Browse Source

Tracking bison locations, so grammatical error messages are informative now.

Also, some cosmetic cleanups.
test
Michael Uleysky 9 years ago
parent
commit
92e9368e56
  1. 23
      src/parser/grammatical.y
  2. 56
      src/parser/lexical.l
  3. 17
      src/parser/parser.h
  4. 19
      src/parser/yyloc.h

23
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 <inttypes.h>
#include <algorithm>
@ -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)<<std::endl<<" Grammatical parser: "<<str<<std::endl;
COUT(ERROR)<<std::endl<<" Grammatical parser: "<<str<<std::endl<<" in file "<<locp->filename;
if(locp->first_line==locp->last_line) COUT(ERROR)<<" at line "<<locp->last_line<<", from position "<<locp->first_column<<" to "<<locp->last_column<<std::endl;
else COUT(ERROR)<<" from line "<<locp->first_line<<", position "<<locp->first_column<<" to line "<<locp->last_line<<", position "<<locp->last_column<<std::endl;
}
inline void conferror(const YYLTYPE& locp, yyscan_t sc, const std::string& str)
{
conferror(&locp,sc,str.c_str());
}
#include "lexical.h"
%}
%union
@ -84,7 +95,7 @@ line:
else if(*$1=="print") G_toprint.push_back(ol);
else
{
COUT(ERROR)<<std::endl<<"Unknown statement "<<(*$1)<<std::endl;
conferror(@1,scanner,"unknown statement "+(*$1));
delete ol;
delete $1;
YYABORT;
@ -97,7 +108,7 @@ line:
else if(*$1=="print") G_toprint.push_back(ol);
else
{
COUT(ERROR)<<std::endl<<"Unknown statement "<<(*$1)<<std::endl;
conferror(@1,scanner,"unknown statement "+(*$1));
delete ol;
delete $1;
YYABORT;

56
src/parser/lexical.l

@ -15,24 +15,29 @@
%x INCLUDE
%{
#if __cplusplus > 199711L
#define register // Deprecated in C++11.
#endif // #if __cplusplus > 199711L
#include <stdlib.h>
#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)<<std::endl<<" Lexical error in file "<<yyextra->state.curdir<<yyextra->state.filename<<" at line "<<yyextra->state.curline<<": "<<(message)<<std::endl; yyterminate(ret);}
// Trace position
#define yynextline {yyextra->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("<<yytext<<")"; BEGIN(PARSE); yylval_param->str=new std::string(yytext); yynextsym; return NAME;
<PARSE>[+\-*/^] COUT(MOREDEBUG)<<" OPERATION("<<yytext<<")"; return yytext[0]; yynextsym;
<PARSE>[0-9]+ COUT(MOREDEBUG)<<" INTEGER("<<yytext<<")"; yylval_param->i=atoll(yytext); yynextsym; return INTEGER;
<PARSE>[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)? COUT(MOREDEBUG)<<" REAL("<<yytext<<")"; yylval_param->r=atof(yytext); yynextsym; return REAL;
<PARSE>[TF] COUT(MOREDEBUG)<<" BOOL("<<yytext<<")"; yylval_param->b=(yytext[0]=='T')?true:false; yynextsym; return BOOL;
<PARSE>\( COUT(MOREDEBUG)<<" OBRACE()"; yynextsym; return OBRACE;
<PARSE>\) COUT(MOREDEBUG)<<" CBRACE()"; yynextsym; return CBRACE;
<PARSE>\; COUT(MOREDEBUG)<<" ENDL()"<<std::endl; BEGIN(0); yynextsym; return ENDL;
<PARSE>= COUT(MOREDEBUG)<<" ASSIGN()"; yynextsym; return ASSIGN;
<PARSE>, COUT(MOREDEBUG)<<" DELIM()"; yynextsym; return DELIM;
<PARSE>[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<" IDENTIFIER("<<yytext<<")"; yylval_param->str=new std::string(yytext); yynextsym; return IDENTIFIER;
<PARSE>\. COUT(MOREDEBUG)<<" DOT()"; yynextsym; return yytext[0];
[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<"NAME("<<yytext<<")"; BEGIN(PARSE); yylval_param->str=new std::string(yytext); setyyllocp; yynextsym; return NAME;
<PARSE>[+\-*/^] COUT(MOREDEBUG)<<" OPERATION("<<yytext<<")"; setyyllocp; yynextsym; return yytext[0];
<PARSE>[0-9]+ COUT(MOREDEBUG)<<" INTEGER("<<yytext<<")"; yylval_param->i=atoll(yytext); setyyllocp; yynextsym; return INTEGER;
<PARSE>[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)? COUT(MOREDEBUG)<<" REAL("<<yytext<<")"; yylval_param->r=atof(yytext); setyyllocp; yynextsym; return REAL;
<PARSE>[TF] COUT(MOREDEBUG)<<" BOOL("<<yytext<<")"; yylval_param->b=(yytext[0]=='T')?true:false; setyyllocp; yynextsym; return BOOL;
<PARSE>\( COUT(MOREDEBUG)<<" OBRACE()"; setyyllocp; yynextsym; return OBRACE;
<PARSE>\) COUT(MOREDEBUG)<<" CBRACE()"; setyyllocp; yynextsym; return CBRACE;
<PARSE>\; COUT(MOREDEBUG)<<" ENDL()"<<std::endl; BEGIN(0); setyyllocp; yynextsym; return ENDL;
<PARSE>= COUT(MOREDEBUG)<<" ASSIGN()"; setyyllocp; yynextsym; return ASSIGN;
<PARSE>, COUT(MOREDEBUG)<<" DELIM()"; setyyllocp; yynextsym; return DELIM;
<PARSE>[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<" IDENTIFIER("<<yytext<<")"; yylval_param->str=new std::string(yytext); setyyllocp; yynextsym; return IDENTIFIER;
<PARSE>\. COUT(MOREDEBUG)<<" DOT()"; setyyllocp; yynextsym; return yytext[0];
<PARSE,INITIAL>[ \t]+ yynextsym;
<PARSE,INITIAL>\n yynextline;
<PARSE,INITIAL>\#.* yynextsym;
<PARSE>\" BEGIN(PSTRING); str.erase(); yynextsym;
<PARSE>\" BEGIN(PSTRING); str.erase(); yyextra->states.push(yyextra->state); yynextsym;
<PARSE,INITIAL>. yyerrormessage(std::string("unknown symbol ")+yytext+" at position "+std::to_string(yyextra->state.curpos),-1);
<PSTRING,INCLUDE>\\\\ str+='\\'; yynextsym;
<PSTRING,INCLUDE>\\\" str+='\"'; yynextsym;
<PSTRING>\n str+=yytext[0]; yynextline;
<PSTRING>\" BEGIN(PARSE); COUT(MOREDEBUG)<<" STRING("<<str<<")"; yylval_param->str=new std::string(str); yynextsym; return STRING;
<PSTRING>\" BEGIN(PARSE); COUT(MOREDEBUG)<<" STRING("<<str<<")"; yylval_param->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;
<PSTRING,INCLUDE>. str+=yytext[0]; yynextsym;
<PSTRING,INCLUDE><<EOF>> yyerrormessage("unclosed quote",-1);
<<EOF>> 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);
<PSTRING,INCLUDE><<EOF>> yyextra->states.pop(); yyerrormessage("unclosed quote",-1);
<<EOF>> 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);
%%

17
src/parser/parser.h

@ -4,6 +4,7 @@
#include <stack>
#include <stdio.h>
// 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

19
src/parser/yyloc.h

@ -1,19 +0,0 @@
#ifndef PARSER_YYLOC_H
#define PARSER_YYLOC_H
#include <string.h>
#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
Loading…
Cancel
Save