diff --git a/src/init.cpp b/src/init.cpp index dea807e..5346d01 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -6,9 +6,14 @@ #include "arifmetic.h" #include "parser/parser.h" #include "parser/grammatical.h" +// definitions for bison-bridge +#define YYSTYPE CONFSTYPE +#define YYLTYPE CONFLTYPE #include "parser/lexical.h" +#undef YYSTYPE +#undef YYLTYPE -int ParseConfigFile(char* config) +int ParseConfigFile(const char* config) { yyscan_t scanner; struct lexical_extra extra; @@ -21,18 +26,24 @@ int ParseConfigFile(char* config) COUT(ERROR)<<"Can't open file "<0);} ret=confparse(scanner); conflex_destroy(scanner); fclose(conffd); - return ret; + return ret+extra.retcode; } diff --git a/src/init.h b/src/init.h index d2578ae..98c73d8 100644 --- a/src/init.h +++ b/src/init.h @@ -6,7 +6,7 @@ typedef void* yyscan_t; #endif #include "deptree.h" -int ParseConfigFile(char* config); +int ParseConfigFile(const char* config); int RegisterArifmeticFunctions(); int BuildDepTree(DepTree* deptree, UsedType& used); int CheckFunctions(); diff --git a/src/parser/grammatical.y b/src/parser/grammatical.y index d98dd86..a48f188 100644 --- a/src/parser/grammatical.y +++ b/src/parser/grammatical.y @@ -1,10 +1,13 @@ -%name-prefix "conf" %language "c" %output "grammatical.cpp" %defines "grammatical.h" %param {yyscan_t scanner} +%define api.prefix {conf} %define api.pure full +%define lr.type ielr %define parse.lac full +%define parse.error verbose +//%define parse.trace %locations //%no-lines @@ -23,7 +26,7 @@ typedef void* yyscan_t; #include "grammatical.h" inline void conferror(YYLTYPE *locp, yyscan_t sc, const char * str) { - COUT(ERROR)< 199711L #define register // Deprecated in C++11. #endif // #if __cplusplus > 199711L #include -#include #include "../debug.h" #include "../object.h" #include "parser.h" #include "grammatical.h" -// Get rid of warning on unneeded function +// Get rid of warning on unused function #define YY_NO_INPUT -static std::string str; +// definitions for bison-bridge +#define YYSTYPE CONFSTYPE +#define YYLTYPE CONFLTYPE +std::string str; +#define yyterminate(ret) { while(YY_CURRENT_BUFFER) yypop_buffer_state(yyscanner); str.erase(); yyextra->retcode=-(ret); return (ret); } +#define yyerrormessage(message,ret) {COUT(ERROR)<state.curdir<state.filename<<" at line "<state.curline<<": "<<(message)<state.curline++; yyextra->state.curpos=0; yyextra->state.curoffset++;} +#define yynextsym {yyextra->state.curpos+=yyleng; yyextra->state.curoffset+=yyleng;} %} %% -\n yyextra->curline++; yyextra->curpos=0; yyextra->curoffset++; REJECT; -. yyextra->curpos++; yyextra->curoffset++; REJECT; -include\(\".+\"\); {/* - if(yyextra->inclevel>=yyextra->maxinclevel) { COUT(ERROR)<<"Max include level reached in file "<filename<<" at line "<inclevel+1; - extra.maxinclevel=yyextra->maxinclevel; - yylex_init_extra(&extra,&scanner); - yyset_in(fd,scanner); - yylex(scanner); - yylex_destroy(scanner); - fclose(fd); +@include[ \t]*\" yy_push_state(INCLUDE,yyscanner); str.erase(); yynextsym; +\" { + if(yyextra->state.inclevel>=yyextra->maxinclevel) yyerrormessage("maximal include level reached",-1); + FILE* fd; + + // yyextra->curdir is directory with currently scanned file + // !!!NONPORTABLE!!! + if('/'==str[0]) fd=fopen(str.c_str(),"r"); // absolute path + else + { + // first, try to search file in working directory + fd=fopen(str.c_str(),"r"); + // if fail, try to search in directory with currently scanned file + if(fd==0) fd=fopen((yyextra->state.curdir+str).c_str(),"r"); + } + + if(fd==0) yyerrormessage("can't open file "+str,-1); + yynextsym; + yyextra->fds.push(fd); + yyextra->states.push(yyextra->state); + COUT(DEBUG)<state.inclevel++; + yyextra->ParsePath(str); + yyextra->state.curline=1; + yyextra->state.curpos=yyextra->state.curoffset=0; - */} -[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<"NAME("<str=new std::string(yytext); return NAME; -[+\-*/^] COUT(MOREDEBUG)<<" OPERATION("<[0-9]+ COUT(MOREDEBUG)<<" INTEGER("<i=atoll(yytext); return INTEGER; -[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)? COUT(MOREDEBUG)<<" REAL("<r=atof(yytext); return REAL; -[TF] COUT(MOREDEBUG)<<" BOOL("<b=(yytext[0]=='T')?true:false; return BOOL; -\( COUT(MOREDEBUG)<<" OBRACE()"; return OBRACE; -\) COUT(MOREDEBUG)<<" CBRACE()"; return CBRACE; -\; COUT(MOREDEBUG)<<" ENDL()"<= COUT(MOREDEBUG)<<" ASSIGN()"; return ASSIGN; -, COUT(MOREDEBUG)<<" DELIM()"; return DELIM; -[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<" IDENTIFIER("<str=new std::string(yytext); return IDENTIFIER; -\. COUT(MOREDEBUG)<<" DOT()"; return yytext[0]; -[ \n\t] -\#.* -\" BEGIN(PSTRING); str.erase(); -. COUT(ERROR)<<"Unknown symbol "<filename<<" at line "<\\\\ str+='\\'; -\\\" str+='\"'; -\" BEGIN(PARSE); COUT(MOREDEBUG)<<" STRING("<str=&str; return STRING; -. str+=yytext[0]; -<> COUT(ERROR)<<"Unclosed quote!"<> str.erase(); yyterminate(); return 0; + yypush_buffer_state(yy_create_buffer(fd,YY_BUF_SIZE,yyscanner),yyscanner); + // Get rid of warning on unused function + if(__builtin_expect(yy_top_state(yyscanner)==PSTRING,0)) yyerrormessage("misterious error",-1); + yy_pop_state(yyscanner); + } +[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<"NAME("<str=new std::string(yytext); yynextsym; return NAME; +[+\-*/^] COUT(MOREDEBUG)<<" OPERATION("<[0-9]+ COUT(MOREDEBUG)<<" INTEGER("<i=atoll(yytext); yynextsym; return INTEGER; +[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)? COUT(MOREDEBUG)<<" REAL("<r=atof(yytext); yynextsym; return REAL; +[TF] COUT(MOREDEBUG)<<" BOOL("<b=(yytext[0]=='T')?true:false; yynextsym; return BOOL; +\( COUT(MOREDEBUG)<<" OBRACE()"; yynextsym; return OBRACE; +\) COUT(MOREDEBUG)<<" CBRACE()"; yynextsym; return CBRACE; +\; COUT(MOREDEBUG)<<" ENDL()"<= COUT(MOREDEBUG)<<" ASSIGN()"; yynextsym; return ASSIGN; +, COUT(MOREDEBUG)<<" DELIM()"; yynextsym; return DELIM; +[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<" IDENTIFIER("<str=new std::string(yytext); yynextsym; return IDENTIFIER; +\. COUT(MOREDEBUG)<<" DOT()"; yynextsym; return yytext[0]; +[ \t]+ yynextsym; +\n yynextline; +\#.* yynextsym; +\" BEGIN(PSTRING); str.erase(); yynextsym; +. yyerrormessage(std::string("unknown symbol ")+yytext+" at position "+std::to_string(yyextra->state.curpos),-1); +\\\\ str+='\\'; yynextsym; +\\\" str+='\"'; yynextsym; +\n str+=yytext[0]; yynextline; +\" BEGIN(PARSE); COUT(MOREDEBUG)<<" STRING("<str=new std::string(str); yynextsym; return STRING; +. str+=yytext[0]; yynextsym; +<> yyerrormessage("unclosed quote",-1); +<> yypop_buffer_state(yyscanner); if(YY_CURRENT_BUFFER) {yyextra->state=yyextra->states.top(); yyextra->states.pop(); fclose(yyextra->fds.top()); yyextra->fds.pop();} else yyterminate(0); %% diff --git a/src/parser/parser.h b/src/parser/parser.h index 088032d..dd745c5 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -1,11 +1,34 @@ #ifndef PARSER_PARSER_H #define PARSER_PARSER_H +#include +#include +#include -struct lexical_extra +struct lexical_state { - const char* filename; - unsigned int inclevel,maxinclevel; + std::string filename,curdir; + unsigned int inclevel; unsigned int curline,curpos,curoffset; }; +struct lexical_extra +{ + struct lexical_state state; + unsigned int maxinclevel; + int retcode; + std::stack fds; + std::stack states; + ~lexical_extra() + { + while(fds.size()!=0) {fclose(fds.top()); fds.pop();} while(states.size()!=0) states.pop(); + } + void ParsePath(const std::string& path) + { + // !!!NONPORTABLE!!! + if('/'==path[0]) state.curdir=path.substr(0,path.rfind('/')+1); // absolute path + else if(std::string::npos!=path.rfind('/')) state.curdir+=path.substr(0,path.rfind('/')+1); // relative path + state.filename=path.substr((path.rfind('/')!=std::string::npos)?(path.rfind('/')+1):0,std::string::npos); + } +}; + #endif