Fix expansion of back-slashed escaped macros, bug441.

This commit is contained in:
Wilson Snyder 2012-02-25 21:31:36 -05:00
parent 2be6699a6a
commit f540362e36
5 changed files with 181 additions and 16 deletions

View File

@ -12,7 +12,9 @@ indicates the contributor was also the author of the fix; Thanks!
*** Support arrayed SystemC I/O pins. [Christophe Joly]
**** Fix core dump with over 100 deep UNOPTFLAT, bug432. [Joe Eiler]
**** Fix expansion of back-slashed escaped macros, bug441. [Alberto Del Rio]
**** Fix core dump with over 100 deep UNOPTFLAT, bug432. [Joe Eiler]
**** Fix false command not found warning in makefiles. [Ruben Diez]

View File

@ -81,6 +81,7 @@ quote [\"]
tickquote [`][\"]
backslash [\\]
/* Where we use symb/symbdef, we must also look for a `` join */
/* Note in the preprocessor \ESCaped is *not* always special; mantis1537/bug441 */
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_]+

View File

@ -628,16 +628,18 @@ string V3PreProcImp::defineSubst(V3DefineRef* refp) {
string argName;
string prev;
bool quote = false;
bool backslashesc = false; // In \.....{space} block
// Note we go through the loop once more at the NULL end-of-string
for (const char* cp=value.c_str(); (*cp) || argName!=""; cp=(*cp?cp+1:cp)) {
//cout << "CH "<<*cp<<" an "<<argName<<"\n";
if (!quote) {
if ( isalpha(*cp) || *cp=='_'
|| *cp=='$' // Won't replace system functions, since no $ in argValueByName
|| (argName!="" && (isdigit(*cp) || *cp=='$'))) {
argName += *cp;
continue;
}
//UINFO(4, "CH "<<*cp<<" an "<<argName<<endl);
if (!quote && *cp == '\\') { backslashesc = true; }
else if (isspace(*cp)) { backslashesc = false; }
// We don't check for quotes; some simulators expand even inside quotes
if ( isalpha(*cp) || *cp=='_'
|| *cp=='$' // Won't replace system functions, since no $ in argValueByName
|| (argName!="" && (isdigit(*cp) || *cp=='$'))) {
argName += *cp;
continue;
}
if (argName != "") {
// Found a possible variable substitution
@ -654,7 +656,11 @@ string V3PreProcImp::defineSubst(V3DefineRef* refp) {
if (!quote) {
// Check for `` only after we've detected end-of-argname
if (cp[0]=='`' && cp[1]=='`') {
out += "``"; // `` must get removed later, as `FOO```BAR must pre-expand FOO and BAR
if (backslashesc) {
// Don't put out the ``, we're forming an escape which will not expand further later
} else {
out += "``"; // `` must get removed later, as `FOO```BAR must pre-expand FOO and BAR
}
cp++;
continue;
}
@ -685,12 +691,18 @@ string V3PreProcImp::defineSubst(V3DefineRef* refp) {
continue;
}
}
if (cp[0]=='\\' && cp[1]) {
if (cp[0]=='\\' && cp[1]=='\"') {
out += cp[0]; // \{any} Put out literal next character
out += cp[1];
cp++;
continue;
}
else if (cp[0]=='\\') {
// Normally \{any} would put out literal next character
// Instead we allow "`define A(nm) \nm" to expand, per proposed mantis1537
out += cp[0];
continue;
}
if (*cp=='"') quote=!quote;
if (*cp) out += *cp;
}

View File

@ -137,7 +137,7 @@ firstline comma","line LLZZ firstline comma","line
`line 71 "t/t_preproc.v" 0
x y LLZZ "a" y
x y LLZZ "x" y
`line 74 "t/t_preproc.v" 0
@ -398,7 +398,7 @@ x,y)--bee submacro has comma paren
$display("bits %d %d", $bits(foo), `10);
$display("10 %d %d", $bits(foo), 10);
`line 260 "t/t_preproc.v" 0
@ -709,5 +709,86 @@ module a_b ; endmodule
integer foo;
module t;
`line 457 "t/t_preproc.v" 2
initial begin : \`LEX_CAT(a[0],_assignment)
`line 464 "t/t_preproc.v" 0
$write("GOT%%m='%m' EXP='%s'\n", "t.\\`LEX_CAT(a[0],_assignment) "); end
initial begin : \a[0]_assignment_a[1]
`line 471 "t/t_preproc.v" 0
$write("GOT%%m='%m' EXP='%s'\n", "t.\\a[0]_assignment_a[1] "); end
initial begin : \`CAT(pp,suffix) $write("GOT%%m='%m' EXP='%s'\n", "t.\\`CAT(pp,suffix) "); end
initial begin : \`CAT(ff,bb)
`line 485 "t/t_preproc.v" 0
$write("GOT%%m='%m' EXP='%s'\n", "t.\\`CAT(ff,bb) "); end
initial begin : \`zzz
`line 491 "t/t_preproc.v" 0
$write("GOT%%m='%m' EXP='%s'\n", "t.\\`zzz "); end
initial begin : \`FOO
`line 498 "t/t_preproc.v" 0
$write("GOT%%m='%m' OTHER_EXP='%s'\n OUR_EXP='%s'", "t.bar ","t.\\`FOO "); end
initial begin : \xx`FOO
`line 500 "t/t_preproc.v" 0
$write("GOT%%m='%m' EXP='%s'\n", "t.\\xx`FOO "); end
initial begin : \`UNKNOWN $write("GOT%%m='%m' EXP='%s'\n", "t.\\`UNKNOWN "); end
initial begin : \`DEF_NO_EXPAND $write("GOT%%m='%m' EXP='%s'\n", "t.\\`DEF_NO_EXPAND "); end
initial $write("GOT='%s' EXP='%s'\n", "foo bar baz", "foo bar baz");
initial $write("GOT='%s' EXP='%s'\n", "foo `A(bar) baz", "foo `A(bar) baz");
endmodule
`line 526 "t/t_preproc.v" 2

View File

@ -69,7 +69,7 @@ Line_Preproc_Check `__LINE__
comma","line)
`define withquote(a, bar) a bar LLZZ "a" bar
`withquote( x , y)
`withquote( x , y) // Simulators disagree here; some substitute "a" others do not
`define noparam (a,b)
`noparam(a,b)
@ -254,7 +254,7 @@ Not a \`define
//======================================================================
// bug191
`define bug191(bits) $display("bits %d %d", $bits(foo), `bits);
`define bug191(bits) $display("bits %d %d", $bits(foo), bits);
`bug191(10)
//======================================================================
@ -453,3 +453,72 @@ module `Q1 ; endmodule
// bug311
integer/*NEED_SPACE*/foo;
//======================================================================
// bug441
module t;
//-----
// case provided
// note this does NOT escape as suggested in the mail
`define LEX_CAT(lexem1, lexem2) lexem1``lexem2
`define LEX_ESC(name) \name \
initial begin : `LEX_ESC( `LEX_CAT(a[0],_assignment) ) $write("GOT%%m='%m' EXP='%s'\n", "t.\\`LEX_CAT(a[0],_assignment) "); end
//-----
// SHOULD(simulator-dependant): Backslash doesn't prevent arguments from
// substituting and the \ staying in the expansion
// Note space after name is important so when substitute it has ending whitespace
`define ESC_CAT(name,name2) \name``_assignment_``name2 \
initial begin : `ESC_CAT( a[0],a[1] ) $write("GOT%%m='%m' EXP='%s'\n", "t.\\a[0]_assignment_a[1] "); end
`undef ESC_CAT
//-----
`define CAT(a,b) a``b
`define ESC(name) \`CAT(name,suffix)
// RULE: Ignoring backslash does NOT allow an additional expansion level
// (Because ESC gets expanded then the \ has it's normal escape meaning)
initial begin : `ESC(pp) $write("GOT%%m='%m' EXP='%s'\n", "t.\\`CAT(pp,suffix) "); end
`undef CAT `undef ESC
//-----
`define CAT(a,b) a``b
`define ESC(name) \name \
// Similar to above; \ does not allow expansion after substitution
initial begin : `ESC( `CAT(ff,bb) ) $write("GOT%%m='%m' EXP='%s'\n", "t.\\`CAT(ff,bb) "); end
`undef CAT `undef ESC
//-----
`define ESC(name) \name \
// MUST: Unknown macro with backslash escape stays as escaped symbol name
initial begin : `ESC( `zzz ) $write("GOT%%m='%m' EXP='%s'\n", "t.\\`zzz "); end
`undef ESC
//-----
`define FOO bar
`define ESC(name) \name \
// SHOULD(simulator-dependant): Known macro with backslash escape expands
initial begin : `ESC( `FOO ) $write("GOT%%m='%m' OTHER_EXP='%s'\n OUR_EXP='%s'", "t.bar ","t.\\`FOO "); end
// SHOULD(simulator-dependant): Prefix breaks the above
initial begin : `ESC( xx`FOO ) $write("GOT%%m='%m' EXP='%s'\n", "t.\\xx`FOO "); end
`undef FOO `undef ESC
//-----
// MUST: Unknown macro not under call with backslash escape doesn't expand
`undef UNKNOWN
initial begin : \`UNKNOWN $write("GOT%%m='%m' EXP='%s'\n", "t.\\`UNKNOWN "); end
//-----
// MUST: Unknown macro not under call doesn't expand
`define DEF_NO_EXPAND error_dont_expand
initial begin : \`DEF_NO_EXPAND $write("GOT%%m='%m' EXP='%s'\n", "t.\\`DEF_NO_EXPAND "); end
`undef DEF_NO_EXPAND
//-----
// bug441 derivative
// SHOULD(simulator-dependant): Quotes doesn't prevent arguments from expanding (like backslashes above)
`define STR(name) "foo name baz"
initial $write("GOT='%s' EXP='%s'\n", `STR(bar), "foo bar baz");
`undef STR
//-----
// RULE: Because there are quotes after substituting STR, the `A does NOT expand
`define STR(name) "foo name baz"
`define A(name) boo name hiss
initial $write("GOT='%s' EXP='%s'\n", `STR(`A(bar)), "foo `A(bar) baz");
`undef A `undef STR
endmodule
//======================================================================