diff --git a/Changes b/Changes index 966ff15b4..6e2cf4ec6 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Support tracing/coverage of underscore signals, bug280. [by Jason McMullan] +**** Fix preprocessor `` of existing base define, bug283. [Usha Priyadharshini] + **** Increase define recursions before error. [Paul Liu] **** On core dump, print debug suggestions. diff --git a/src/V3PreLex.h b/src/V3PreLex.h index d4dd591f7..3c867b8cb 100644 --- a/src/V3PreLex.h +++ b/src/V3PreLex.h @@ -63,6 +63,8 @@ class V3PreProcImp; #define VP_DEFFORM 309 #define VP_STRIFY 310 #define VP_BACKQUOTE 311 +#define VP_SYMBOL_JOIN 312 +#define VP_DEFREF_JOIN 313 #define VP_PSL 350 diff --git a/src/V3PreLex.l b/src/V3PreLex.l index b91bb3a39..552c8133c 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -80,6 +80,7 @@ crnl [\r]*[\n] quote [\"] tickquote [`][\"] backslash [\\] +/* Where we use symb/symbdef, we must also look for a `` join */ symb ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+) symbdef ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n`]+) word [a-zA-Z0-9_]+ @@ -225,6 +226,7 @@ psl [p]sl yy_pop_state(); return (VP_DEFARG); }} "`"{symbdef} { appendDefValue(yytext,yyleng); } /* defref in defref - outer macro expands first */ +"`"{symbdef}`` { appendDefValue(yytext,yyleng); } /* defref in defref - outer macro expands first */ [^\/\*\n\r\\(,){}\[\]\"`]+ | . { appendDefValue(yytext,yyleng); } @@ -267,13 +269,15 @@ psl [p]sl "//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */ /* Define calls */ - /* symbdef prevents normal lex rules from makeing `\`"foo a symbol {`"foo} instead of a BACKQUOTE */ + /* symbdef prevents normal lex rules from making `\`"foo a symbol {`"foo} instead of a BACKQUOTE */ "`"{symbdef} { return (VP_DEFREF); } +"`"{symbdef}`` { yyleng-=2; return (VP_DEFREF_JOIN); } /* Generics */ {crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); } -<> { yyterminate(); } /* A "normal" EOF */ -{symb} { return (VP_SYMBOL); } +<> { yyterminate(); } /* A "normal" EOF */ +{symb} { return (VP_SYMBOL); } +{symb}`` { yyleng-=2; return (VP_SYMBOL_JOIN); } {wsn}+ { return (VP_WHITE); } {drop} { } [\r] { } diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index cbbe91f1b..be6a38696 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -126,14 +126,14 @@ struct V3PreProcImp : public V3PreProc { ps_DEFNAME_UNDEF, ps_DEFNAME_DEFINE, ps_DEFNAME_IFDEF, ps_DEFNAME_IFNDEF, ps_DEFNAME_ELSIF, ps_DEFFORM, ps_DEFVALUE, ps_DEFPAREN, ps_DEFARG, - ps_INCNAME, ps_ERRORNAME, ps_STRIFY }; + ps_INCNAME, ps_ERRORNAME, ps_JOIN, ps_STRIFY }; const char* procStateName(ProcState s) { static const char* states[] = {"ps_TOP", "ps_DEFNAME_UNDEF", "ps_DEFNAME_DEFINE", "ps_DEFNAME_IFDEF", "ps_DEFNAME_IFNDEF", "ps_DEFNAME_ELSIF", "ps_DEFFORM", "ps_DEFVALUE", "ps_DEFPAREN", "ps_DEFARG", - "ps_INCNAME", "ps_ERRORNAME", "ps_STRIFY"}; + "ps_INCNAME", "ps_ERRORNAME", "ps_JOIN", "ps_STRIFY"}; return states[s]; }; @@ -162,6 +162,10 @@ struct V3PreProcImp : public V3PreProc { stack m_defRefs; // Pending definine substitution stack m_ifdefStack; ///< Stack of true/false emitting evaluations unsigned m_defDepth; ///< How many `defines deep + bool m_defPutJoin; ///< Insert `` after substitution + + // For `` join + stack m_joinStack; ///< Text on lhs of join // For getline() string m_lineChars; ///< Characters left for next line @@ -246,6 +250,7 @@ public: m_finAhead = false; m_finAtBol = true; m_defDepth = 0; + m_defPutJoin = false; } void configure(FileLine* filelinep) { // configure() separate from constructor to avoid calling abstract functions @@ -459,6 +464,7 @@ const char* V3PreProcImp::tokenName(int tok) { case VP_DEFFORM : return("DEFFORM"); case VP_DEFINE : return("DEFINE"); case VP_DEFREF : return("DEFREF"); + case VP_DEFREF_JOIN : return("DEFREF_JOIN"); case VP_DEFVALUE : return("DEFVALUE"); case VP_ELSE : return("ELSE"); case VP_ELSIF : return("ELSIF"); @@ -473,6 +479,7 @@ const char* V3PreProcImp::tokenName(int tok) { case VP_STRIFY : return("STRIFY"); case VP_STRING : return("STRING"); case VP_SYMBOL : return("SYMBOL"); + case VP_SYMBOL_JOIN : return("SYMBOL_JOIN"); case VP_TEXT : return("TEXT"); case VP_UNDEF : return("UNDEF"); case VP_UNDEFINEALL : return("UNDEFINEALL"); @@ -640,7 +647,7 @@ string V3PreProcImp::defineSubst(V3DefineRef* refp) { if (!quote) { // Check for `` only after we've detected end-of-argname if (cp[0]=='`' && cp[1]=='`') { - //out += ""; // `` means to suppress the `` + out += "``"; // `` must get removed later, as `FOO```BAR must pre-expand FOO and BAR cp++; continue; } @@ -856,6 +863,40 @@ int V3PreProcImp::getStateToken() { goto next_tok; } + if (tok==VP_DEFREF_JOIN) { + // Here's something fun and unspecified as yet: + // The existance of non-existance of a base define changes `` expansion + // `define QA_b zzz + // `define Q1 `QA``_b + // 1Q1 -> zzz + // `define QA a + // `Q1 -> a_b + // Note parenthesis make this unambiguous + // `define Q1 `QA()``_b // -> a_b + // This may be a side effect of how `UNDEFINED remains as `UNDEFINED, + // but it screws up our method here. So hardcode it. + string name (yyourtext()+1,yyourleng()-1); + if (defExists(name)) { // JOIN(DEFREF) + // Put back the `` and process the defref + UINFO(5,"```: define "< string doesn't include the ``, so can just grab next and continue + string out (yyourtext(),yyourleng()); + UINFO(5,"`` LHS:"< V3PreProc::DEFINE_RECURSION_LEVEL_MAX) { error("Recursive `define substitution: `"+name); goto next_tok; diff --git a/test_regress/t/t_preproc.out b/test_regress/t/t_preproc.out index c305d2feb..8ddb222af 100644 --- a/test_regress/t/t_preproc.out +++ b/test_regress/t/t_preproc.out @@ -654,4 +654,52 @@ Line_Preproc_Check 407 Line_Preproc_Check 410 -`line 413 "t/t_preproc.v" 2 + +`line 414 "t/t_preproc.v" 0 + + + + +`line 418 "t/t_preproc.v" 0 + +abc + + + + +`line 424 "t/t_preproc.v" 0 + + + +EXP: sonet_frame +sonet_frame + +`line 430 "t/t_preproc.v" 0 + + +EXP: sonet_frame +sonet_frame + +`line 435 "t/t_preproc.v" 0 + + +EXP: sonet_frame +sonet_frame + + +`line 441 "t/t_preproc.v" 0 + + +EXP: module zzz ; endmodule +module zzz ; endmodule +module zzz ; endmodule + +`line 447 "t/t_preproc.v" 0 + +EXP: module a_b ; endmodule +module a_b ; endmodule +module a_b ; endmodule + + + +`line 454 "t/t_preproc.v" 2 diff --git a/test_regress/t/t_preproc.v b/test_regress/t/t_preproc.v index cd5de413d..56d14875c 100644 --- a/test_regress/t/t_preproc.v +++ b/test_regress/t/t_preproc.v @@ -409,3 +409,44 @@ Line_Preproc_Check `__LINE__ arg_line2") Line_Preproc_Check `__LINE__ //====================================================================== +// bug283 + +`define A a +`define B b +`define C c +// EXP: abc +`define C5 `A``b```C +`C5 +`undef A +`undef B +`undef C + +`define XTYPE sonet +`define XJOIN(__arg1, __arg2) __arg1``__arg2 +`define XACTION `XJOIN(`XTYPE, _frame) +EXP: sonet_frame +`XACTION +// +`define XFRAME frame +`define XACTION2 `XJOIN(sonet_, `XFRAME) +EXP: sonet_frame +`XACTION2 +// This result varies between simulators +`define sonet_frame other_frame +`define XACTION3 `XTYPE``_frame +EXP: sonet_frame +`XACTION3 + +// The existance of non-existance of a base define can make a difference +`define QA_b zzz +`define Q1 `QA``_b +EXP: module zzz ; endmodule +module `Q1 ; endmodule +module `Q1 ; endmodule + +`define QA a +EXP: module a_b ; endmodule +module `Q1 ; endmodule +module `Q1 ; endmodule + +//======================================================================