From 92e9368e56de45e2e3adbd4ed1dae967dafd7a72 Mon Sep 17 00:00:00 2001 From: Michael Uleysky Date: Fri, 11 Sep 2015 00:04:12 +1000 Subject: [PATCH] Tracking bison locations, so grammatical error messages are informative now. Also, some cosmetic cleanups. --- src/parser/grammatical.y | 23 ++++++++++++----- src/parser/lexical.l | 56 ++++++++++++++++++++++------------------ src/parser/parser.h | 17 ++++++++++++ src/parser/yyloc.h | 19 -------------- 4 files changed, 65 insertions(+), 50 deletions(-) delete mode 100644 src/parser/yyloc.h diff --git a/src/parser/grammatical.y b/src/parser/grammatical.y index 0c933bf..fbad0c3 100644 --- a/src/parser/grammatical.y +++ b/src/parser/grammatical.y @@ -11,6 +11,9 @@ %locations //%no-lines +// Get name of initial parsed file +%initial-action {@$.filename=confget_extra(scanner)->state.curdir+confget_extra(scanner)->state.filename;} + %{ #include #include @@ -18,17 +21,25 @@ #include "../debug.h" #include "../object.h" #include "../globals.h" +// We can't include lexical.h before grammatical.h, because of strange errors, but grammatical.h only needs definition of yyscan_t #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif -#include "yyloc.h" + #include "grammatical.h" -inline void conferror(YYLTYPE *locp, yyscan_t sc, const char * str) +#include "lexical.h" + +inline void conferror(const YYLTYPE* locp, yyscan_t sc, const char* str) { - COUT(ERROR)<filename; + if(locp->first_line==locp->last_line) COUT(ERROR)<<" at line "<last_line<<", from position "<first_column<<" to "<last_column<first_line<<", position "<first_column<<" to line "<last_line<<", position "<last_column< 199711L -#define register // Deprecated in C++11. -#endif // #if __cplusplus > 199711L -#include #include "../debug.h" -#include "../object.h" #include "parser.h" +// flex use register keyword, but it deprecated in C++11. +#define register +// Flex always think what bison types prefixed as YY, so we mast define right macroses +#define YYSTYPE CONFSTYPE +#define YYLTYPE CONFLTYPE +// Some declarations in grammatical.h use ObjectBase +class ObjectBase; #include "grammatical.h" // Get rid of warning on unused function #define YY_NO_INPUT -// definitions for bison-bridge -#define YYSTYPE CONFSTYPE -#define YYLTYPE CONFLTYPE -std::string str; +// Termination (mostly. in case of errors) #define yyterminate(ret) { while(YY_CURRENT_BUFFER) yypop_buffer_state(yyscanner); str.erase(); yyextra->retcode=-(ret); return (ret); } +// Abnormal termination with description of error #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;} +// and set bison location accordingly +#define setyyllocp {yylloc_param->first_line=yylloc_param->last_line=yyextra->state.curline; yylloc_param->first_column=yyextra->state.curpos; yylloc_param->last_column=yylloc_param->first_column+yyleng;} + +std::string str; %} %% @@ -62,34 +67,35 @@ std::string str; yyextra->ParsePath(str); yyextra->state.curline=1; yyextra->state.curpos=yyextra->state.curoffset=0; + yylloc_param->filename=yyextra->state.curdir+yyextra->state.filename; 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]; +[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<"NAME("<str=new std::string(yytext); setyyllocp; yynextsym; return NAME; +[+\-*/^] COUT(MOREDEBUG)<<" OPERATION("<[0-9]+ COUT(MOREDEBUG)<<" INTEGER("<i=atoll(yytext); setyyllocp; yynextsym; return INTEGER; +[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)? COUT(MOREDEBUG)<<" REAL("<r=atof(yytext); setyyllocp; yynextsym; return REAL; +[TF] COUT(MOREDEBUG)<<" BOOL("<b=(yytext[0]=='T')?true:false; setyyllocp; yynextsym; return BOOL; +\( COUT(MOREDEBUG)<<" OBRACE()"; setyyllocp; yynextsym; return OBRACE; +\) COUT(MOREDEBUG)<<" CBRACE()"; setyyllocp; yynextsym; return CBRACE; +\; COUT(MOREDEBUG)<<" ENDL()"<= COUT(MOREDEBUG)<<" ASSIGN()"; setyyllocp; yynextsym; return ASSIGN; +, COUT(MOREDEBUG)<<" DELIM()"; setyyllocp; yynextsym; return DELIM; +[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<" IDENTIFIER("<str=new std::string(yytext); setyyllocp; yynextsym; return IDENTIFIER; +\. COUT(MOREDEBUG)<<" DOT()"; setyyllocp; yynextsym; return yytext[0]; [ \t]+ yynextsym; \n yynextline; \#.* yynextsym; -\" BEGIN(PSTRING); str.erase(); yynextsym; +\" BEGIN(PSTRING); str.erase(); yyextra->states.push(yyextra->state); 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; +\" BEGIN(PARSE); COUT(MOREDEBUG)<<" STRING("<str=new std::string(str); {struct lexical_state prstate=yyextra->states.top(); yyextra->states.pop(); yylloc_param->first_line=prstate.curline; yylloc_param->last_line=yyextra->state.curline; yylloc_param->first_column=prstate.curpos; yylloc_param->last_column=yyextra->state.curpos+yyleng;}; 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); +<> yyextra->states.pop(); 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(); yylloc_param->filename=yyextra->state.curdir+yyextra->state.filename;} else yyterminate(0); %% diff --git a/src/parser/parser.h b/src/parser/parser.h index dd745c5..720fab0 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -4,6 +4,7 @@ #include #include +// State of lexical parser (filename and position in file) struct lexical_state { std::string filename,curdir; @@ -11,6 +12,7 @@ struct lexical_state unsigned int curline,curpos,curoffset; }; +// Container for "static" parameters of lexical parser struct lexical_extra { struct lexical_state state; @@ -31,4 +33,19 @@ struct lexical_extra } }; +// Bison location +struct grammatic_location +{ + int first_line; + int first_column; + int last_line; + int last_column; + std::string filename; +}; + +#if !defined CONFLTYPE && !defined CONFLTYPE_IS_DECLARED +typedef struct grammatic_location CONFLTYPE; +#define CONFLTYPE_IS_DECLARED 1 +#endif + #endif diff --git a/src/parser/yyloc.h b/src/parser/yyloc.h deleted file mode 100644 index fc61489..0000000 --- a/src/parser/yyloc.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef PARSER_YYLOC_H -#define PARSER_YYLOC_H -#include - -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; - std::string filename; - std::string token_type; - std::string token_value; -} YYLTYPE; -#define YYLTYPE_IS_DECLARED 1 -#endif - -#endif