Fix preprocessor `` of existing base define, bug283.

This commit is contained in:
Wilson Snyder 2010-09-20 15:20:16 -04:00
parent 7c5318768c
commit 42199bc8e5
6 changed files with 168 additions and 8 deletions

View File

@ -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.

View File

@ -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

View File

@ -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] { }

View File

@ -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;

View File

@ -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

View File

@ -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
//======================================================================