From b469feb44bc4d0b44d185687e5cecbd86974e87f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 7 Jun 2020 13:45:50 -0400 Subject: [PATCH] Fix some syntax error context by splitting internal parse and lex filelines --- src/V3ParseImp.cpp | 22 ++++++++++--------- src/V3ParseImp.h | 18 ++++++++++------ src/V3ParseLex.cpp | 2 +- src/verilog.l | 28 ++++++++++++------------- src/verilog.y | 4 ++-- test_regress/t/t_flag_wpedantic_bad.out | 4 ++-- test_regress/t/t_lint_mod_paren_bad.out | 6 +++--- test_regress/t/t_pp_circdef_bad.out | 2 +- test_regress/t/t_pp_defparen_bad.out | 4 ++-- test_regress/t/t_udp_noname.out | 4 ++-- test_regress/t/t_var_bad_sv.out | 4 ++-- 11 files changed, 53 insertions(+), 45 deletions(-) diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index fca88f8fc..ddede422c 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -73,13 +73,13 @@ void V3ParseImp::lexPpline(const char* textp) { // Handle lexer `line directive FileLine* prevFl = copyOrSameFileLine(); int enterExit; - fileline()->lineDirective(textp, enterExit /*ref*/); + lexFileline()->lineDirective(textp, enterExit /*ref*/); if (enterExit == 1) { // Enter - fileline()->parent(prevFl); + lexFileline()->parent(prevFl); } else if (enterExit == 2) { // Exit - FileLine* upFl = fileline()->parent(); + FileLine* upFl = lexFileline()->parent(); if (upFl) upFl = upFl->parent(); - if (upFl) fileline()->parent(upFl); + if (upFl) lexFileline()->parent(upFl); } } @@ -141,8 +141,8 @@ void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnO string msg = sp; string::size_type pos; if ((pos = msg.find('*')) != string::npos) msg.erase(pos); - // Use parsep()->fileline() as want to affect later FileLine's warnings - if (!(parsep()->fileline()->warnOff(msg, warnOff))) { + // Use parsep()->lexFileline() as want to affect later FileLine's warnings + if (!(parsep()->lexFileline()->warnOff(msg, warnOff))) { if (!v3Global.opt.isFuture(msg)) { fl->v3error("Unknown verilator lint message code: '" << msg << "', in '" << textp << "'"); @@ -274,8 +274,9 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i string modname = V3Os::filenameNonExt(modfilename); UINFO(2, __FUNCTION__ << ": " << modname << (inLibrary ? " [LIB]" : "") << endl); - m_fileline = new FileLine(fileline); - m_fileline->newContent(); + m_lexFileline = new FileLine(fileline); + m_lexFileline->newContent(); + m_bisonLastFileline = m_lexFileline; m_inLibrary = inLibrary; // Preprocess into m_ppBuffer @@ -323,7 +324,7 @@ void V3ParseImp::lexFile(const string& modname) { // Prepare for lexing UINFO(3, "Lexing " << modname << endl); s_parsep = this; - fileline()->warnResetDefault(); // Reenable warnings on each file + lexFileline()->warnResetDefault(); // Reenable warnings on each file lexDestroy(); // Restart from clean slate. lexNew(); @@ -483,6 +484,7 @@ int V3ParseImp::lexToBison() { lexToken(); // sets yylval m_bisonValPrev = m_bisonValCur; m_bisonValCur = yylval; + m_bisonLastFileline = yylval.fl; // yylval.scp = NULL; // Symbol table not yet needed - no packages if (debugFlex() >= 6 || debugBison() >= 6) { // --debugi-flex and --debugi-bison @@ -490,7 +492,7 @@ int V3ParseImp::lexToBison() { << "} lexToBison TOKEN=" << yylval.token << " " << tokenName(yylval.token); if (yylval.token == yaID__ETC // || yylval.token == yaID__LEX // - || yylval.token == yaID__aTYPE) { + || yylval.token == yaID__aPACKAGE || yylval.token == yaID__aTYPE) { cout << " strp='" << *(yylval.strp) << "'"; } cout << endl; diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index c2017dcba..d84787162 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -105,7 +105,9 @@ class V3ParseImp { V3Lexer* m_lexerp; // Current FlexLexer static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based - FileLine* m_fileline; // Filename/linenumber currently active + FileLine* m_lexFileline; // Filename/linenumber currently active for lexing + + FileLine* m_bisonLastFileline; // Filename/linenumber of last token bool m_inLibrary; // Currently reading a library vs. regular file int m_lexKwdDepth; // Inside a `begin_keywords @@ -144,7 +146,6 @@ public: int yylexThis(); static bool optFuture(const string& flag) { return v3Global.opt.isFuture(flag); } - void linenoInc() { fileline()->linenoInc(); } void tagNodep(AstNode* nodep) { m_tagNodep = nodep; } AstNode* tagNodep() const { return m_tagNodep; } void lexTimescaleParse(FileLine* fl, const char* textp); @@ -152,6 +153,8 @@ public: bool precSet, double precVal); VTimescale timeLastUnit() const { return m_timeLastUnit; } + FileLine* lexFileline() const { return m_lexFileline; } + FileLine* lexCopyOrSameFileLine() { return lexFileline()->copyOrSameFileLine(); } static void lexErrorPreprocDirective(FileLine* fl, const char* textp); static string lexParseTag(const char* textp); static double lexParseTimenum(const char* text); @@ -178,7 +181,7 @@ public: void ppPushText(const string& text) { m_ppBuffers.push_back(text); - if (fileline()->contentp()) fileline()->contentp()->pushText(text); + if (lexFileline()->contentp()) lexFileline()->contentp()->pushText(text); } size_t ppInputToLex(char* buf, size_t max_size); @@ -209,10 +212,13 @@ public: return nump; } + // Bison sometimes needs error context without a token, so remember last token's line + // Only use this if do not have and cannot get a token-relevent fileline + FileLine* bisonLastFileline() const { return m_bisonLastFileline; } + // Return next token, for bison, since bison isn't class based, use a global THIS - FileLine* fileline() const { return m_fileline; } AstNetlist* rootp() const { return m_rootp; } - FileLine* copyOrSameFileLine() { return fileline()->copyOrSameFileLine(); } + FileLine* copyOrSameFileLine() { return bisonLastFileline()->copyOrSameFileLine(); } bool inLibrary() const { return m_inLibrary; } VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } @@ -239,7 +245,7 @@ public: : m_rootp(rootp) , m_filterp(filterp) , m_symp(parserSymp) { - m_fileline = NULL; + m_lexFileline = NULL; m_lexerp = NULL; m_inLibrary = false; m_lexKwdDepth = 0; diff --git a/src/V3ParseLex.cpp b/src/V3ParseLex.cpp index 33225d9ab..4a24b51b9 100644 --- a/src/V3ParseLex.cpp +++ b/src/V3ParseLex.cpp @@ -52,7 +52,7 @@ void V3ParseImp::lexUnputString(const char* textp, size_t length) { int V3ParseImp::yylexReadTok() { // Call yylex() remembering last non-whitespace token - parsep()->fileline()->startToken(); + parsep()->lexFileline()->startToken(); int token = parsep()->m_lexerp->yylex(); m_lexPrevToken = token; // Save so can find '#' to parse following number return token; diff --git a/src/verilog.l b/src/verilog.l index 533ee67ba..0f1925707 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -36,11 +36,11 @@ //====================================================================== -#define FL_FWD (PARSEP->fileline()->forwardToken(yytext, yyleng, true)) +#define FL_FWD (PARSEP->lexFileline()->forwardToken(yytext, yyleng, true)) // Use this to break between tokens whereever not return'ing a token (e.g. skipping inside lexer) -#define FL_BRK (PARSEP->fileline()->startToken()) +#define FL_BRK (PARSEP->lexFileline()->startToken()) -#define CRELINE() (PARSEP->copyOrSameFileLine()) +#define CRELINE() (PARSEP->lexCopyOrSameFileLine()) #define FL \ do { \ @@ -686,15 +686,15 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "/*verilator clock_enable*/" { FL; return yVL_CLOCK_ENABLE; } "/*verilator clocker*/" { FL; return yVL_CLOCKER; } "/*verilator coverage_block_off*/" { FL; return yVL_COVERAGE_BLOCK_OFF; } - "/*verilator coverage_off*/" { FL_FWD; PARSEP->fileline()->coverageOn(false); FL_BRK; } - "/*verilator coverage_on*/" { FL_FWD; PARSEP->fileline()->coverageOn(true); FL_BRK; } + "/*verilator coverage_off*/" { FL_FWD; PARSEP->lexFileline()->coverageOn(false); FL_BRK; } + "/*verilator coverage_on*/" { FL_FWD; PARSEP->lexFileline()->coverageOn(true); FL_BRK; } "/*verilator full_case*/" { FL; return yVL_FULL_CASE; } "/*verilator inline_module*/" { FL; return yVL_INLINE_MODULE; } "/*verilator isolate_assignments*/" { FL; return yVL_ISOLATE_ASSIGNMENTS; } "/*verilator lint_off"[^*]*"*/" { FL; PARSEP->lexVerilatorCmtLint(yylval.fl, yytext, true); FL_BRK; } "/*verilator lint_on"[^*]*"*/" { FL; PARSEP->lexVerilatorCmtLint(yylval.fl, yytext, false); FL_BRK; } - "/*verilator lint_restore*/" { FL; PARSEP->lexVerilatorCmtLintRestore(PARSEP->fileline()); FL_BRK; } - "/*verilator lint_save*/" { FL; PARSEP->lexVerilatorCmtLintSave(PARSEP->fileline()); FL_BRK; } + "/*verilator lint_restore*/" { FL; PARSEP->lexVerilatorCmtLintRestore(PARSEP->lexFileline()); FL_BRK; } + "/*verilator lint_save*/" { FL; PARSEP->lexVerilatorCmtLintSave(PARSEP->lexFileline()); FL_BRK; } "/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; } "/*verilator no_inline_module*/" { FL; return yVL_NO_INLINE_MODULE; } "/*verilator no_inline_task*/" { FL; return yVL_NO_INLINE_TASK; } @@ -711,8 +711,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "/*verilator systemc_clock*/" { FL; return yVL_CLOCK; } "/*verilator tag"[^*]*"*/" { FL; yylval.strp = PARSEP->newString(V3ParseImp::lexParseTag(yytext)); return yVL_TAG; } - "/*verilator tracing_off*/" { FL_FWD; PARSEP->fileline()->tracingOn(false); FL_BRK; } - "/*verilator tracing_on*/" { FL_FWD; PARSEP->fileline()->tracingOn(true); FL_BRK; } + "/*verilator tracing_off*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(false); FL_BRK; } + "/*verilator tracing_on*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(true); FL_BRK; } "/**/" { FL_FWD; FL_BRK; } "/*"[^*]+"*/" { FL; V3ParseImp::lexVerilatorCmtBad(yylval.fl, yytext); FL_BRK; } @@ -930,10 +930,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} { "`accelerate" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`autoexpand_vectornets" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`celldefine" { FL_FWD; PARSEP->fileline()->celldefineOn(true); FL_BRK; } + "`celldefine" { FL_FWD; PARSEP->lexFileline()->celldefineOn(true); FL_BRK; } "`default_decay_time"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog spec - delays only - "`default_nettype"{ws}+"wire" { FL_FWD; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); FL_BRK; } - "`default_nettype"{ws}+"none" { FL_FWD; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, false); FL_BRK; } + "`default_nettype"{ws}+"wire" { FL_FWD; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); FL_BRK; } + "`default_nettype"{ws}+"none" { FL_FWD; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, false); FL_BRK; } "`default_nettype"{ws}+[a-zA-Z0-9]* { FL; yylval.fl->v3error("Unsupported: `default_nettype of other than none or wire: '" << yytext << "'"); FL_BRK; } "`default_trireg_strength"{ws}+[^\n\r]* { FL; yylval.fl->v3error("Unsupported: Verilog optional directive not implemented: '" << yytext << "'"); @@ -944,7 +944,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "`delay_mode_zero" { FL_FWD; FL_BRK; } // Verilog spec - delays only "`disable_portfaults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`enable_portfaults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`endcelldefine" { FL_FWD; PARSEP->fileline()->celldefineOn(false); FL_BRK; } + "`endcelldefine" { FL_FWD; PARSEP->lexFileline()->celldefineOn(false); FL_BRK; } "`endprotect" { FL_FWD; FL_BRK; } "`expand_vectornets" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`inline" { FL_FWD; FL_BRK; } @@ -960,7 +960,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "`protect" { FL_FWD; FL_BRK; } "`remove_gatenames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`remove_netnames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`resetall" { FL; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); + "`resetall" { FL; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); return yaT_RESETALL; } // Rest handled by preproc "`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`timescale"{ws}+[^\n\r]* { FL; PARSEP->lexTimescaleParse(yylval.fl, diff --git a/src/verilog.y b/src/verilog.y index 80faa1b9c..8d07359d3 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -291,13 +291,13 @@ static void UNSUPREAL(FileLine* fileline) { //====================================================================== void yyerror(const char* errmsg) { - PARSEP->fileline()->v3error(errmsg); + PARSEP->bisonLastFileline()->v3error(errmsg); static const char* const colonmsg = "syntax error, unexpected ::, "; // tokens; if (0 == strncmp(errmsg, colonmsg, strlen(colonmsg)) && PARSEP->bisonValIdThenColon()) { static int warned = false; if (!warned++) { - std::cerr << PARSEP->fileline()->warnMore() + std::cerr << PARSEP->bisonLastFileline()->warnMore() << ("... Perhaps '" + *PARSEP->bisonValPrev().strp + "' is a package which needs to be predeclared? (IEEE 1800-2017 26.3)") << std::endl; diff --git a/test_regress/t/t_flag_wpedantic_bad.out b/test_regress/t/t_flag_wpedantic_bad.out index 85f687f33..707d92b51 100644 --- a/test_regress/t/t_flag_wpedantic_bad.out +++ b/test_regress/t/t_flag_wpedantic_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_flag_wpedantic_bad.v:8:14: syntax error, unexpected global +%Error: t/t_flag_wpedantic_bad.v:8:8: syntax error, unexpected global 8 | reg global; - | ^ + | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_mod_paren_bad.out b/test_regress/t/t_lint_mod_paren_bad.out index 682bb8951..177aa7c8d 100644 --- a/test_regress/t/t_lint_mod_paren_bad.out +++ b/test_regress/t/t_lint_mod_paren_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_lint_mod_paren_bad.v:14:7: syntax error, unexpected '(', expecting ';' - 14 | output bar - | ^~~~~~ +%Error: t/t_lint_mod_paren_bad.v:13:6: syntax error, unexpected '(', expecting ';' + 13 | ) ( + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_pp_circdef_bad.out b/test_regress/t/t_pp_circdef_bad.out index 68de58b97..867858a16 100644 --- a/test_regress/t/t_pp_circdef_bad.out +++ b/test_regress/t/t_pp_circdef_bad.out @@ -1,3 +1,3 @@ %Error: t/t_pp_circdef_bad.v:14:21985: Recursive `define or other nested inclusion -%Error: t/t_pp_circdef_bad.v:15:1: syntax error, unexpected $end, expecting TYPE-IDENTIFIER +%Error: t/t_pp_circdef_bad.v:14:3009: syntax error, unexpected $end, expecting TYPE-IDENTIFIER %Error: Exiting due to diff --git a/test_regress/t/t_pp_defparen_bad.out b/test_regress/t/t_pp_defparen_bad.out index c6c16d023..bf1efdb68 100644 --- a/test_regress/t/t_pp_defparen_bad.out +++ b/test_regress/t/t_pp_defparen_bad.out @@ -1,7 +1,7 @@ %Error: t/t_pp_defparen_bad.v:10:2: Illegal text before '(' that starts define arguments 10 | ( 1,2) | ^ -%Error: t/t_pp_defparen_bad.v:10:2: syntax error, unexpected '(' +%Error: t/t_pp_defparen_bad.v:10:1: syntax error, unexpected '(' 10 | ((val 1) + (2)) - | ^ + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_udp_noname.out b/test_regress/t/t_udp_noname.out index e92964be4..14eb3efdb 100644 --- a/test_regress/t/t_udp_noname.out +++ b/test_regress/t/t_udp_noname.out @@ -1,4 +1,4 @@ -%Error: t/t_udp_noname.v:15:9: syntax error, unexpected '(', expecting IDENTIFIER or randomize +%Error: t/t_udp_noname.v:15:8: syntax error, unexpected '(', expecting IDENTIFIER or randomize 15 | udp (o, a); - | ^ + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_var_bad_sv.out b/test_regress/t/t_var_bad_sv.out index c27c1e81c..7a5ff2358 100644 --- a/test_regress/t/t_var_bad_sv.out +++ b/test_regress/t/t_var_bad_sv.out @@ -5,7 +5,7 @@ %Error: t/t_var_bad_sv.v:9:14: Unexpected 'do': 'do' is a SystemVerilog keyword misused as an identifier. 9 | mod mod (.do(bar)); | ^~ -%Error: t/t_var_bad_sv.v:9:17: syntax error, unexpected '(', expecting ')' +%Error: t/t_var_bad_sv.v:9:16: syntax error, unexpected '(', expecting ')' 9 | mod mod (.do(bar)); - | ^~~ + | ^ %Error: Exiting due to