Fix preprocessor `` of existing base define, bug283.
This commit is contained in:
parent
7c5318768c
commit
42199bc8e5
2
Changes
2
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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}}
|
||||
<ARGMODE>"`"{symbdef} { appendDefValue(yytext,yyleng); } /* defref in defref - outer macro expands first */
|
||||
<ARGMODE>"`"{symbdef}`` { appendDefValue(yytext,yyleng); } /* defref in defref - outer macro expands first */
|
||||
<ARGMODE>[^\/\*\n\r\\(,){}\[\]\"`]+ |
|
||||
<ARGMODE>. { appendDefValue(yytext,yyleng); }
|
||||
|
||||
|
|
@ -267,13 +269,15 @@ psl [p]sl
|
|||
<PSLMULM>"//"[^\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 */
|
||||
<INITIAL,PSLMULM,PSLONEM>"`"{symbdef} { return (VP_DEFREF); }
|
||||
<INITIAL,PSLMULM,PSLONEM>"`"{symbdef}`` { yyleng-=2; return (VP_DEFREF_JOIN); }
|
||||
|
||||
/* Generics */
|
||||
<INITIAL,PSLMULM>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
|
||||
<INITIAL,PSLMULM,PSLONEM><<EOF>> { yyterminate(); } /* A "normal" EOF */
|
||||
<INITIAL,PSLMULM,PSLONEM>{symb} { return (VP_SYMBOL); }
|
||||
<INITIAL,PSLMULM,PSLONEM><<EOF>> { yyterminate(); } /* A "normal" EOF */
|
||||
<INITIAL,PSLMULM,PSLONEM>{symb} { return (VP_SYMBOL); }
|
||||
<INITIAL,PSLMULM,PSLONEM>{symb}`` { yyleng-=2; return (VP_SYMBOL_JOIN); }
|
||||
<INITIAL,PSLMULM,PSLONEM>{wsn}+ { return (VP_WHITE); }
|
||||
<INITIAL,PSLMULM,PSLONEM>{drop} { }
|
||||
<INITIAL,PSLMULM,PSLONEM>[\r] { }
|
||||
|
|
|
|||
|
|
@ -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<V3DefineRef> m_defRefs; // Pending definine substitution
|
||||
stack<VPreIfEntry> m_ifdefStack; ///< Stack of true/false emitting evaluations
|
||||
unsigned m_defDepth; ///< How many `defines deep
|
||||
bool m_defPutJoin; ///< Insert `` after substitution
|
||||
|
||||
// For `` join
|
||||
stack<string> 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 "<<name<<" exists, expand first\n");
|
||||
m_defPutJoin = true; // After define, unputString("``"). Not now as would loose yyourtext()
|
||||
UINFO(5,"TOKEN now DEFREF\n");
|
||||
tok = VP_DEFREF;
|
||||
} else { // DEFREF(JOIN)
|
||||
UINFO(5,"```: define "<<name<<" doesn't exist, join first\n");
|
||||
// FALLTHRU, handle as with VP_SYMBOL_JOIN
|
||||
}
|
||||
}
|
||||
if (tok==VP_SYMBOL_JOIN || tok==VP_DEFREF_JOIN) { // not else if, can fallthru from above if()
|
||||
// a`` -> string doesn't include the ``, so can just grab next and continue
|
||||
string out (yyourtext(),yyourleng());
|
||||
UINFO(5,"`` LHS:"<<out<<endl);
|
||||
// a``b``c can have multiple joins, so we need a stack
|
||||
m_joinStack.push(out);
|
||||
statePush(ps_JOIN);
|
||||
goto next_tok;
|
||||
}
|
||||
|
||||
// Deal with some special parser states
|
||||
switch (state) {
|
||||
case ps_TOP: {
|
||||
|
|
@ -1089,6 +1130,27 @@ int V3PreProcImp::getStateToken() {
|
|||
goto next_tok;
|
||||
}
|
||||
}
|
||||
case ps_JOIN: {
|
||||
if (tok==VP_SYMBOL || tok==VP_TEXT) {
|
||||
if (m_joinStack.empty()) fatalSrc("`` join stack empty, but in a ``");
|
||||
string lhs = m_joinStack.top(); m_joinStack.pop();
|
||||
UINFO(5,"`` LHS:"<<lhs<<endl);
|
||||
string rhs (yyourtext(),yyourleng());
|
||||
UINFO(5,"`` RHS:"<<rhs<<endl);
|
||||
string out = lhs+rhs;
|
||||
UINFO(5,"`` Out:"<<out<<endl);
|
||||
unputString(out);
|
||||
statePop();
|
||||
goto next_tok;
|
||||
} else if (tok==VP_EOF || tok==VP_WHITE || tok == VP_COMMENT || tok==VP_STRING) {
|
||||
error((string)"Expecting symbol to terminate ``; whitespace etc cannot follow ``. Found: "+tokenName(tok)+"\n");
|
||||
statePop();
|
||||
goto next_tok;
|
||||
} else {
|
||||
// `define, etc, fall through and expand. Pop back here.
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ps_STRIFY: {
|
||||
if (tok==VP_STRIFY) {
|
||||
// Quote what's in the middle of the stringification
|
||||
|
|
@ -1175,8 +1237,9 @@ int V3PreProcImp::getStateToken() {
|
|||
|
||||
case VP_DEFREF: {
|
||||
// m_off not right here, but inside substitution, to make this work: `ifdef NEVER `DEFUN(`endif)
|
||||
string name; name.append(yyourtext()+1,yyourleng()-1);
|
||||
string name (yyourtext()+1,yyourleng()-1);
|
||||
UINFO(4,"DefRef "<<name<<endl);
|
||||
if (m_defPutJoin) { m_defPutJoin = false; unputString("``"); }
|
||||
if (m_defDepth++ > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) {
|
||||
error("Recursive `define substitution: `"+name);
|
||||
goto next_tok;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
//======================================================================
|
||||
|
|
|
|||
Loading…
Reference in New Issue