From 113fc467a7170a8a564049c64d1036dd10e6abac Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 30 Jul 2006 09:07:20 +0000 Subject: It's starting to look pretty good, just trying to figure out how to get through everything that needs to be made modular and general. --- congo | 77 ++++++++++++++++++++++++++++++++++++++++++++++---- pymake.conf | 13 +++++++++ src/action.cpp | 38 +++++++++++++++++++++++++ src/action.h | 35 +++++++++++++++++++++++ src/build.l | 26 +++++++++++++---- src/build.y | 87 ++++++++++++++++++++++++++++++++++++--------------------- src/builder.cpp | 45 +++++++++++++++++++++++------ src/builder.h | 41 +++++++++++++++++++++------ src/command.cpp | 19 +++++++++++++ src/command.h | 38 +++++++++++++++++++++++++ src/main.cpp | 2 ++ 11 files changed, 361 insertions(+), 60 deletions(-) create mode 100644 src/action.cpp create mode 100644 src/action.h create mode 100644 src/command.cpp create mode 100644 src/command.h diff --git a/congo b/congo index ddf7e7b..3031f4e 100644 --- a/congo +++ b/congo @@ -1,16 +1,83 @@ +# +# Simple build.conf test file +# +# you can have as many actions as you'd like, the one that's run by default is +# called "default action", you need a default action. +# +# Actions are filled with a comma-seperated list of commands, like "check xxx" +# to check to see if a target needs to be rebuilt +# +default action: check congo, check congod -default action: create congo, congod +# +# This action will only build the server program +# +server action: check congod -create file congod from files in src/congod using rule exe -create file congo from files in src/congo using rule exe +# +# After that, it helps to define some targets, things that commands usually +# refer to and interact with. +# +# +# "create file" will do just what it says, create a file based on some +# information and a rule. +# +# "from files in" tells us that a list of directories follows, and the input +# list for the rule should be built from these files. +# +# "using rule" tells us which rule to use to actuall create the file +# +create file congod from files in src/congod, src/shared using rule exe +create file congo from files in src/congo, src/shared using rule exe + +# +# After all of that, some targets or list items may have their own additional +# dependancies, depending on the rule that built them. You can define these +# extra dependancies using "xxx requires yyy" which will force the system to +# attempt to create yyy before xxx. +# congod requires libcongo.a congo requires libcongo.a +# +# There are a number of variables that the rules can use, including any in the +# environment. Sometimes you want to modify these, to do that you can use "set" +# and the name of the variable, along with what to do to it. +# +# You can use '=' to set the value, destroying what was there, or '+=' to add +# the new text to the variable, this will assume that the text you provide is +# made up of space-delimited tokens, and will ensure spaces surround them when +# they are added. +# set CXXFLAGS += "-Ilibbu++/src" set LDFLAGS += "-Llibbu++ -lbu++" +# +# Sometimes individual targets or list items require special settings, this is +# easy since build maintians a seperate set of variables for any items that need +# special support. +# +# Currently you can only set, for an item, later you may be able to do more. +# for congo set LDFLAGS += "-lreadline" -rule exe matches all /(.*)\.o/ perform command "g++ {matches} {LDFLAGS} -o {target}" -rule cpp matches one /(.*)\.cpp/ produces {1}.o perform command "g++ {CXXFLAGS} -o {target} {match}" +# +# Finally, no file is complete without some rules. Rules determine how to +# fulfill target checking based on some input data. Generally this is going to +# be creating an executable from a list of source files. +# +# +# First specify the rule name, then you can filter the input list, if desired, +# in two ways. You can use items that match a regular expression, and execute +# the rule once for the whole list collectively, or once for each element that +# made it through the filter. +# +# Within the perform, there are several things that could go there, for now, +# just command, which takes a string, you can use {} for variable substitution. +# +rule exe matches all /(.*)\.o/ perform command ... + "g++ {matches} {LDFLAGS} -o {target}" + +rule cpp matches one /(.*)\.cpp/ produces {1}.o perform command ... + "g++ {CXXFLAGS} -o {target} {match}" diff --git a/pymake.conf b/pymake.conf index 83d9885..2340fd5 100644 --- a/pymake.conf +++ b/pymake.conf @@ -5,6 +5,16 @@ CXXFLAGS: -Ilibbu++/src LDFLAGS: -Llibbu++ -lbu++ +[BUILD] +FILE: src/build.y +COMMAND: stupid +OUTPUT: parser + +[BUILD] +FILE: src/build.l +COMMAND: stupid +OUTPUT: lexer + ## A simple command to build everything in this directory, and output ## an executable with the name 'main' [BUILD] @@ -79,6 +89,9 @@ COMMAND: g++ {INPUT} {LDFLAGS} -o {OUTPUT} NAME: lib COMMAND: ar cr{ARFLAGS} {OUTPUT} {INPUT} +[COMMAND] +NAME: stupid + ### Strange example ### ## The following trigger will take all *.q files, strip all '&'s from them ## and generate a .cpp file, which will then be compiled using the cpp trigger. diff --git a/src/action.cpp b/src/action.cpp new file mode 100644 index 0000000..7a7bbb8 --- /dev/null +++ b/src/action.cpp @@ -0,0 +1,38 @@ +#include "action.h" +#include "command.h" + +Action::Action() : + bDefault( true ), + sName("") +{ +} + +Action::Action( const char *sName ) : + bDefault( false ), + sName( sName ) +{ +} + +Action::~Action() +{ +} + +void Action::add( Command *pCmd ) +{ + lCommand.push_back( pCmd ); +} + +void Action::debug() +{ + if( bDefault ) + printf("action default:\n"); + else + printf("action \"%s\":\n", sName.getString() ); + + for( std::list::iterator i = lCommand.begin(); + i != lCommand.end(); i++ ) + { + (*i)->debug(); + } +} + diff --git a/src/action.h b/src/action.h new file mode 100644 index 0000000..12c2cc4 --- /dev/null +++ b/src/action.h @@ -0,0 +1,35 @@ +#ifndef ACTION_H +#define ACTION_H + +#include +#include "staticstring.h" + +class Command; + +class Action +{ +public: + Action(); + Action( const char *sName ); + virtual ~Action(); + + void add( Command *pCmd ); + + const char *getName() + { + return sName; + } + bool isDefault() + { + return bDefault; + } + + void debug(); + +private: + bool bDefault; + StaticString sName; + std::list lCommand; +}; + +#endif diff --git a/src/build.l b/src/build.l index 6a80f45..3a457b1 100644 --- a/src/build.l +++ b/src/build.l @@ -7,13 +7,14 @@ std::string strbuf; %} +%x regexp %x strsq %x strdq %x comment %option noyywrap nounput batch debug %{ -# define YY_USER_ACTION yylloc->columns (yyleng); +//# define YY_USER_ACTION yylloc->columns (yyleng); %} %% @@ -38,16 +39,27 @@ std::string strbuf; "perform" return TOK_PERFORM; "produces" return TOK_PRODUCES; "command" return TOK_COMMAND; +"check" return TOK_CHECK; "..."\n /* elipsis line continuation */ -\n+ return TOX_EOL; +\n+ return TOK_EOL; [ \t\r]* /* whitespace */ -\/\/.* /* single line comment */ +"/" { + BEGIN( regexp ); + strbuf = ""; +} +[^\n/]* strbuf += yytext; +"/" { + BEGIN( INITIAL ); + yylval->strval = stringdup( strbuf.c_str() ); + return REGEXP; +} + "#".* /* single line comment */ -[^ \t\r\n\'\"]+ { - yylval.strval = stringdup( yytext ); +[^ \t\r\n\'\":=,.]+ { + yylval->strval = stringdup( yytext ); return STRING; } @@ -86,11 +98,13 @@ std::string strbuf; return STRING; } +%% void Builder::scanBegin() { + yy_flex_debug = false; if( !(yyin = fopen( file.c_str(), "r" )) ) - error( std::string("cannot open ") + file ); + fprintf( stderr, "cannot open %s\n", file.c_str() ); } void Builder::scanEnd() diff --git a/src/build.y b/src/build.y index 600b923..45a84f1 100644 --- a/src/build.y +++ b/src/build.y @@ -1,19 +1,21 @@ -%skeleton "lalr1.cc" -%define "parser_class_name" "BuildParser" %defines %{ # include # include "builder.h" +# include "action.h" +# include "command.h" # include "build.tab.h" +void yyerror( YYLTYPE *locp, Builder &bld, char const *msg ); %} %parse-param { Builder &bld } %lex-param { Builder &bld } +%pure-parser %locations %initial-action { - @$.begin.filename = @$.end.filename = &bld.file; + //@$.begin.filename = @$.end.filename = &bld.file; } %debug @@ -23,6 +25,7 @@ } %token STRING "string literal" +%token REGEXP "regular expression" %token TOK_ADDSET "+=" %token TOK_DEFAULT "keyword 'default'" @@ -43,49 +46,69 @@ %token TOK_PERFORM "keyword 'perform'" %token TOK_PRODUCES "keyword 'produces'" %token TOK_COMMAND "keyword 'command'" +%token TOK_CHECK "keyword 'check'" %token TOK_EOL "end of line" +%token ',' ':' '=' %destructor { delete[] $$; } STRING %% input: - | input line + | input fullline ; -line: stuff TOK_EOL { printf("\n"); } +fullline: TOK_EOL + | line TOK_EOL + ; + +line: TOK_DEFAULT TOK_ACTION ':' + { + bld.add( new Action() ); + } + actionlst + | STRING TOK_ACTION ':' + { + bld.add( new Action( $1 ) ); + } + actionlst + | TOK_CREATE createwhat TOK_FROM createfrom TOK_USING createusing ; -stuff: - | stuff token - ; +createwhat: TOK_FILE STRING { printf("target: %s\n", $2 ); } + ; -token: TOK_ADDSET { printf("+= "); } - | TOK_DEFAULT { printf("default "); } - | TOK_ACTION { printf("action "); } - | TOK_CREATE { printf("create "); } - | TOK_FILE { printf("file "); } - | TOK_FROM { printf("from "); } - | TOK_FILES { printf("files "); } - | TOK_IN { printf("in "); } - | TOK_USING { printf("using "); } - | TOK_RULE { printf("rule "); } - | TOK_REQUIRES { printf("requires "); } - | TOK_FOR { printf("for "); } - | TOK_SET { printf("set "); } - | TOK_MATCHES { printf("matches "); } - | TOK_ALL { printf("all "); } - | TOK_ONE { printf("one "); } - | TOK_PERFORM { printf("perform "); } - | TOK_PRODUCES { printf("produces "); } - | TOK_COMMAND { printf("command "); } - ; +createfrom: TOK_FILES TOK_IN createfromdirlst + ; + +createfromdirlst: createfromdir + | createfromdirlst ',' createfromdir + ; + +createfromdir: STRING { printf(" srcdir: %s\n", $1 ); } + ; + +createusing: TOK_RULE STRING { printf(" rule: %s\n", $2 ); } + ; + +actionlst: action + | actionlst ',' action + ; + +action: TOK_CHECK STRING + { + bld.add( new Command( Command::cmdCheck, $2 ) ); + } + ; %% -void yy::BuildParser::error( const yy::BuildParser::location_type &l, - const std::string &m ) +void yyerror( YYLTYPE *locp, Builder &bld, char const *msg ) { - bld.error( l, m ); + fprintf( stderr, "%s:%d-%d:%d-%d: %s\n", + bld.file.c_str(), + locp->first_line, locp->last_line, + locp->first_column, locp->last_column, + msg + ); } - diff --git a/src/builder.cpp b/src/builder.cpp index 8c72fef..2de6f5c 100644 --- a/src/builder.cpp +++ b/src/builder.cpp @@ -1,9 +1,15 @@ #include #include "builder.h" +#include "action.h" +#include "command.h" #include "build.tab.h" -Builder::Builder() +subExceptionDef( BuildException ) + +Builder::Builder() : + pDefaultAction( NULL ), + pLastAddedAction( NULL ) { } @@ -11,24 +17,47 @@ Builder::~Builder() { } +void yyparse( Builder &bld ); + void Builder::load( const char *sFN ) { file = sFN; scanBegin(); - yy::BuildParser parser( *this ); - parser.set_debug_level( false ); - parser.parse(); + yyparse( *this ); scanEnd(); } -void Builder::error( const yy::location &l, const std::string &m ) +void Builder::add( Action *pAct ) +{ + if( pAct->isDefault() ) + { + if( pDefaultAction ) + throw BuildException("There's already a default exception"); + pDefaultAction = pAct; + } + else + { + mAction[pAct->getName()] = pAct; + } + pLastAddedAction = pAct; +} + +void Builder::add( Command *pCmd ) { - std::cerr << l << ": " << m << std::endl; + if( pLastAddedAction ) + { + pLastAddedAction->add( pCmd ); + } } -void Builder::error( const std::string &m ) +void Builder::debug() { - std::cerr << m << std::endl; + pDefaultAction->debug(); + for( std::map::iterator i = mAction.begin(); + i != mAction.end(); i++ ) + { + (*i).second->debug(); + } } diff --git a/src/builder.h b/src/builder.h index e379608..58afaf5 100644 --- a/src/builder.h +++ b/src/builder.h @@ -2,35 +2,58 @@ #define BUILDER_H #include +#include +#include +#include "build.tab.h" +#include "exceptionbase.h" -union YYSTYPE; +subExceptionDecl( BuildException ) -namespace yy -{ - class location; - class BuildParser; -} class Builder; +class Action; +class Command; -#define YY_DECL int yylex( YYSTYPE *yylval_param, yy::location *yylloc, Builder &bld ) +#define YY_DECL int yylex( YYSTYPE *yylval_param, YYLTYPE *yylloc_param, Builder &bld ) YY_DECL; class Builder { + struct ltstr + { + bool operator()(const char* s1, const char* s2) const + { + return strcmp(s1, s2) < 0; + } + }; + public: Builder(); virtual ~Builder(); void load( const char *sFN ); - void error( const yy::location &l, const std::string &m ); - void error( const std::string &m ); + //void error( const yy::location &l, const std::string &m ); + //void error( const std::string &m ); std::string file; + void add( Action *pAct ); + void add( Command *pCmd ); + + bool hasDefaultAction() + { + return pDefaultAction != NULL; + } + + void debug(); + private: void scanBegin(); void scanEnd(); + + Action *pDefaultAction; + Action *pLastAddedAction; + std::map mAction; }; #endif diff --git a/src/command.cpp b/src/command.cpp new file mode 100644 index 0000000..4a1fa6c --- /dev/null +++ b/src/command.cpp @@ -0,0 +1,19 @@ +#include "command.h" + +Command::Command( CmdType cmd, const char *sTarget ) : + nType( cmd ), + sTarget( sTarget ) +{ +} + +Command::~Command() +{ +} + +void Command::debug() +{ + static const char *cmdt[]={"Check", "Clean"}; + printf(" command: %s %s\n", cmdt[ nType ], sTarget.getString() ); + +} + diff --git a/src/command.h b/src/command.h new file mode 100644 index 0000000..aa00eae --- /dev/null +++ b/src/command.h @@ -0,0 +1,38 @@ +#ifndef COMMAND_H +#define COMMAND_H + +#include +#include "staticstring.h" + +class Command +{ +public: + enum CmdType + { + cmdCheck = 0, + cmdClean + }; + +public: + Command( CmdType cmd, const char *sTarget ); + virtual ~Command(); + + CmdType getType() + { + return nType; + } + + const char *getTarget() + { + return sTarget; + } + + void debug(); + +private: + CmdType nType; + StaticString sTarget; + +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index 7e130bc..598a97f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,5 +5,7 @@ int main() Builder bld; bld.load("congo"); + + bld.debug(); } -- cgit v1.2.3