From 85c5765c005837a4ec0d2bee651de302613d2a06 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 11 Mar 2014 19:07:58 -0400 Subject: [PATCH] Fix parsing "#0 'b0", bug256. --- Changes | 2 ++ src/V3ParseImp.h | 5 ++++ src/V3ParseLex.cpp | 17 +++++++++++- src/verilog.l | 49 ++++++++++++++++++--------------- test_regress/t/t_parse_delay.pl | 18 ++++++++++++ test_regress/t/t_parse_delay.v | 20 ++++++++++++++ 6 files changed, 88 insertions(+), 23 deletions(-) create mode 100755 test_regress/t/t_parse_delay.pl create mode 100644 test_regress/t/t_parse_delay.v diff --git a/Changes b/Changes index 10968aabc..6d510e4b2 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Add parameters into trace files, bug706. [Alex Solomatnikov] +**** Fix parsing "#0 'b0", bug256. + **** Fix array bound checks on real variables. **** Fix --skip-identical mis-detecting on OS-X, bug707. diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 648435d8f..84b9085d4 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -105,6 +105,7 @@ class V3ParseImp { int m_inBeginKwd; // Inside a `begin_keywords int m_lastVerilogState; // Last LEX state in `begin_keywords + int m_prevLexToken; // previous parsed token (for lexer) bool m_ahead; // aheadToken is valid int m_aheadToken; // Token we read ahead V3ParseBisonYYSType m_aheadVal; // aheadToken's value @@ -193,6 +194,7 @@ public: void statePushVlg(); // Parser -> lexer communication void statePop(); // Parser -> lexer communication static int stateVerilogRecent(); // Parser -> lexer communication + int prevLexToken() { return m_prevLexToken; } // Parser -> lexer communication size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf,max_size); } //==== Symbol tables @@ -208,11 +210,13 @@ public: m_inLibrary = false; m_inBeginKwd = 0; m_lastVerilogState = stateVerilogRecent(); + m_prevLexToken = 0; m_ahead = false; m_aheadToken = 0; } ~V3ParseImp(); void parserClear(); + void unputString(const char* textp, size_t length); // METHODS // Preprocess and read the Verilog file specified into the netlist database @@ -223,6 +227,7 @@ public: private: void lexFile(const string& modname); + int yylexReadTok(); int lexToken(); // Internal; called from lexToBison }; diff --git a/src/V3ParseLex.cpp b/src/V3ParseLex.cpp index 75ff5a80e..137973494 100644 --- a/src/V3ParseLex.cpp +++ b/src/V3ParseLex.cpp @@ -57,11 +57,26 @@ public: void statePop() { yy_pop_state(); } + void unputString(const char* textp, size_t length) { + // Add characters to input stream in back-to-front order + const char* cp = textp; + for (cp += length - 1; length--; cp--) { + unput(*cp); + } + } }; void V3ParseImp::stateExitPsl() { parsep()->m_lexerp->stateExitPsl(); } void V3ParseImp::statePushVlg() { parsep()->m_lexerp->stateExitPsl(); } void V3ParseImp::statePop() { parsep()->m_lexerp->statePop(); } -int V3ParseImp::yylexThis() { return parsep()->m_lexerp->yylex(); } + +void V3ParseImp::unputString(const char* textp, size_t length) { parsep()->m_lexerp->unputString(textp, length); } + +int V3ParseImp::yylexReadTok() { + // Call yylex() remembering last non-whitespace token + int token = parsep()->m_lexerp->yylex(); + m_prevLexToken = token; // Save so can find '#' to parse following number + return token; +} //###################################################################### // Read class functions diff --git a/src/verilog.l b/src/verilog.l index 035b384c2..1dcdc34d2 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -43,7 +43,8 @@ extern void yyerrorf(const char* format, ...); //====================================================================== #define NEXTLINE() {PARSEP->linenoInc();} -#define LINECHECK() { const char* cp=yytext; for (int n=yyleng; n; --n) if (cp[n]=='\n') NEXTLINE(); } +#define LINECHECKS(textp,len) { const char* cp=textp; for (int n=len; n; --n) if (cp[n]=='\n') NEXTLINE(); } +#define LINECHECK() LINECHECKS(yytext,yyleng) #define CRELINE() (PARSEP->copyOrSameFileLine()) #define FL { yylval.fl = CRELINE(); } @@ -149,6 +150,13 @@ id [a-zA-Z_][a-zA-Z0-9_$]* /* escaped identifier */ escid \\[^ \t\f\r\n]+ word [a-zA-Z0-9_]+ + /* verilog numbers, constructed to not match the ' that begins a '( or '{ */ +vnum1 [0-9]*?['']s?[bcodhBCODH][ \t\n]*[A-Fa-f0-9xXzZ_?]* +vnum2 [0-9]*?['']s?[01xXzZ] +vnum3 [0-9][_0-9]*[ \t\n]*['']s?[bcodhBCODH]?[ \t]*[A-Fa-f0-9xXzZ_?]+ +vnum4 [0-9][_0-9]*[ \t\n]*['']s?[bcodhBCODH] +vnum5 [0-9][_0-9]*[ \t\n]*['']s +vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} %% @@ -912,24 +920,21 @@ word [a-zA-Z0-9_]+ } \" { yy_push_state(STRING); yymore(); } - [0-9]*?['']s?[bcodhBCODH][ \t\n]*[A-Fa-f0-9xXzZ_?]* { - FL; LINECHECK(); yylval.nump = PARSEP->newNumber(yylval.fl,(char*)yytext); - return yaINTNUM; - } - [0-9]*?['']s?[01xXzZ] { /* SystemVerilog */ - FL; yylval.nump = PARSEP->newNumber(yylval.fl,(char*)yytext); - return yaINTNUM; - } - /* Note below is constructed to not match the ' that begins a '( or '{ */ - [0-9][_0-9]*[ \t\n]*['']s?[bcodhBCODH]?[ \t]*[A-Fa-f0-9xXzZ_?]+ { - FL; LINECHECK(); yylval.nump = PARSEP->newNumber(yylval.fl,(char*)yytext); - return yaINTNUM; - } - [0-9][_0-9]*[ \t\n]*['']s?[bcodhBCODH] { - FL; LINECHECK(); yylval.nump = PARSEP->newNumber(yylval.fl,(char*)yytext); - return yaINTNUM; - } - [0-9][_0-9]*[ \t\n]*['']s { + {vnum} { + /* "# 1'b0" is a delay value so must lex as "#" "1" "'b0" */ + if (PARSEP->prevLexToken()=='#') { + int shortlen = 0; + while (isdigit(yytext[shortlen])) shortlen++; + if (shortlen) { + // Push rest for later parse + PARSEP->unputString(yytext+shortlen, yyleng-shortlen); + FL; LINECHECKS(yytext,shortlen); + // Return is stuff before ' + yytext[shortlen] = '\0'; + yylval.nump = PARSEP->newNumber(yylval.fl, (char*)yytext); + return yaINTNUM; + } + } FL; LINECHECK(); yylval.nump = PARSEP->newNumber(yylval.fl,(char*)yytext); return yaINTNUM; } @@ -1106,8 +1111,8 @@ int V3ParseImp::lexToken() { yylval = m_aheadVal; } else { // Parse new token - token = yylexThis(); - //yylval // Set by yylexThis() + token = yylexReadTok(); + //yylval // Set by yylexReadTok() } // If a paren, read another if (token == yCONST__LEX @@ -1116,7 +1121,7 @@ int V3ParseImp::lexToken() { ) { if (debugFlex()) { cout<<" lexToken: reading ahead to find possible strength"<1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_parse_delay.v b/test_regress/t/t_parse_delay.v new file mode 100644 index 000000000..ba51cbaa4 --- /dev/null +++ b/test_regress/t/t_parse_delay.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2014 by Wilson Snyder. + +module t (/*AUTOARG*/); + + // verilator lint_off WIDTH + reg [6:0] myreg1; + + initial begin + myreg1 = # 100 7'd0; + myreg1 = # 100 'b0; // [#] [100] ['b0] + myreg1 = #100'b0; // [#] [100] ['b0] + myreg1 = 100'b0; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule