mirror of
https://github.com/verilator/verilator.git
synced 2025-04-25 10:06:54 +00:00
Fix define formal arguments that contain newlines, bug84.
This commit is contained in:
parent
96d150e92d
commit
4e522ab7f5
2
Changes
2
Changes
@ -14,6 +14,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
**** Fix escaped identifiers with '.' causing conflicts, bug83. [J Baxter]
|
||||
|
||||
**** Fix define formal arguments that contain newlines, bug84. [David A]
|
||||
|
||||
* Verilator 3.703 2009/05/02
|
||||
|
||||
*** Fix $clog2 calculation error with powers-of-2, bug81. [Patricio Kaplan]
|
||||
|
@ -51,7 +51,9 @@
|
||||
#define VP_DEFREF 306
|
||||
#define VP_DEFARG 307
|
||||
#define VP_ERROR 308
|
||||
#define VP_PSL 309
|
||||
#define VP_DEFFORM 309
|
||||
|
||||
#define VP_PSL 350
|
||||
|
||||
|
||||
//======================================================================
|
||||
@ -134,9 +136,12 @@ class V3PreLex {
|
||||
void incLineno() { m_curFilelinep->incLineno(); }
|
||||
// Called by V3PreProc.cpp to inform lexer
|
||||
void pushStateDefArg(int level);
|
||||
void pushStateDefForm();
|
||||
void pushStateDefValue();
|
||||
void pushStateIncFilename();
|
||||
void unputString(const char* textp);
|
||||
/// Called by VPreproc.cpp to get data from lexer
|
||||
int currentStartState();
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
@ -37,7 +37,7 @@ static bool optPsl() { return V3PreProc::optPsl(); }
|
||||
static bool pedantic() { return V3PreLex::s_currentLexp->m_pedantic; }
|
||||
static void yyerror(char* msg) { V3PreLex::s_currentLexp->m_curFilelinep->v3error(msg); }
|
||||
static void yyerrorf(const char* msg) { V3PreLex::s_currentLexp->m_curFilelinep->v3error(msg); }
|
||||
static void appendDefValue(char* t,int l) { V3PreLex::s_currentLexp->appendDefValue(t,l); }
|
||||
static void appendDefValue(const char* t,int l) { V3PreLex::s_currentLexp->appendDefValue(t,l); }
|
||||
static int pslParenLevel() { return V3PreLex::s_currentLexp->m_pslParenLevel; }
|
||||
static void pslParenLevelInc() { V3PreLex::s_currentLexp->m_pslParenLevel++; }
|
||||
static void pslParenLevelDec() { if (pslParenLevel()) V3PreLex::s_currentLexp->m_pslParenLevel--; }
|
||||
@ -55,7 +55,9 @@ static void pslMoreNeeded(bool flag) { V3PreLex::s_currentLexp->m_pslMoreNeeded
|
||||
%x CMTBEGM
|
||||
%x CMTMODE
|
||||
%x STRMODE
|
||||
%x DEFMODE
|
||||
%x DEFFPAR
|
||||
%x DEFFORM
|
||||
%x DEFVAL
|
||||
%x ARGMODE
|
||||
%x INCMODE
|
||||
%x PRTMODE
|
||||
@ -123,16 +125,35 @@ psl [p]sl
|
||||
<INCMODE>{backslash}. { yymore(); }
|
||||
<INCMODE>[\>] { yy_pop_state(); return (VP_STRING); }
|
||||
|
||||
/* Reading definition */
|
||||
<DEFMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
|
||||
<DEFMODE>"//"[^\n\r]* { return (VP_COMMENT);}
|
||||
<DEFMODE>{drop} { }
|
||||
<DEFMODE><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
|
||||
<DEFMODE>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
|
||||
<DEFMODE>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
|
||||
<DEFMODE>[^\/\*\n\r\\]+ |
|
||||
<DEFMODE>[\\][^\n\r] |
|
||||
<DEFMODE>. { appendDefValue(yytext,yyleng); }
|
||||
/* Reading definition formal parenthesis (or not) to begin formal arguments */
|
||||
/* Note '(' must IMMEDIATELY follow definition name */
|
||||
<DEFFPAR>[(] { appendDefValue("(",1); BEGIN(DEFFORM); }
|
||||
<DEFFPAR>{crnl} { yy_pop_state(); unput('\n'); yyleng=0; return VP_DEFFORM; } /* DEFVAL will later grab the return */
|
||||
<DEFFPAR>. { yy_pop_state(); unput(yytext[yyleng-1]); yyleng=0; return VP_DEFFORM; } /* empty formals */
|
||||
|
||||
/* Reading definition formals */
|
||||
<DEFFORM>[(] { yy_pop_state(); yyerrorf("Extra ( in define formal arguments.\n"); yyleng=0; return VP_DEFFORM; }
|
||||
<DEFFORM>[)] { yy_pop_state(); appendDefValue(yytext,yyleng); yyleng=0; return VP_DEFFORM; }
|
||||
<DEFFORM>"/*" { yy_push_state(CMTMODE); yymore(); }
|
||||
<DEFFORM>"//"[^\n\r]* { return (VP_COMMENT);}
|
||||
<DEFFORM>{drop} { }
|
||||
<DEFFORM><<EOF>> { linenoInc(); yy_pop_state(); yyerrorf("Unterminated ( in define formal arguments."); yyleng=0; return VP_DEFFORM; }
|
||||
<DEFFORM>{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
|
||||
<DEFFORM>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
|
||||
<DEFFORM>[^\/\*\n\r\\()]+ |
|
||||
<DEFFORM>[\\][^\n\r] |
|
||||
<DEFFORM>. { appendDefValue(yytext,yyleng); }
|
||||
|
||||
/* Reading definition value */
|
||||
<DEFVAL>"/*" { yy_push_state(CMTMODE); yymore(); }
|
||||
<DEFVAL>"//"[^\n\r]* { return (VP_COMMENT);}
|
||||
<DEFVAL>{drop} { }
|
||||
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
|
||||
<DEFVAL>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
|
||||
<DEFVAL>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
|
||||
<DEFVAL>[^\/\*\n\r\\]+ |
|
||||
<DEFVAL>[\\][^\n\r] |
|
||||
<DEFVAL>. { appendDefValue(yytext,yyleng); }
|
||||
|
||||
/* Define arguments */
|
||||
<ARGMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
|
||||
@ -225,9 +246,16 @@ void V3PreLex::pushStateDefArg(int level) {
|
||||
m_defValue = "";
|
||||
}
|
||||
|
||||
void V3PreLex::pushStateDefForm() {
|
||||
// Enter define formal arguments state
|
||||
yy_push_state(DEFFPAR); // First is an optional ( to begin args
|
||||
m_parenLevel = 0;
|
||||
m_defValue = "";
|
||||
}
|
||||
|
||||
void V3PreLex::pushStateDefValue() {
|
||||
// Enter define value state
|
||||
yy_push_state(DEFMODE);
|
||||
yy_push_state(DEFVAL);
|
||||
m_parenLevel = 0;
|
||||
m_defValue = "";
|
||||
}
|
||||
@ -252,6 +280,10 @@ void V3PreLex::appendDefValue(const char* textp, int len) {
|
||||
m_defValue.append(textp,len);
|
||||
}
|
||||
|
||||
int V3PreLex::currentStartState() {
|
||||
return YY_START;
|
||||
}
|
||||
|
||||
void V3PreLex::lineDirective(const char* textp) {
|
||||
m_curFilelinep->lineDirective(textp);
|
||||
// Make sure we have a dependency on whatever file was specified
|
||||
|
@ -111,12 +111,14 @@ struct V3PreProcImp : public V3PreProc {
|
||||
V3PreLex* m_lexp; // Current lexer state (NULL = closed)
|
||||
stack<V3PreLex*> m_includeStack; // Stack of includers above current m_lexp
|
||||
|
||||
enum ProcState { ps_TOP, ps_DEFNAME, ps_DEFVALUE, ps_DEFPAREN, ps_DEFARG,
|
||||
enum ProcState { ps_TOP,
|
||||
ps_DEFNAME, ps_DEFFORM, ps_DEFVALUE, ps_DEFPAREN, ps_DEFARG,
|
||||
ps_INCNAME, ps_ERRORNAME };
|
||||
ProcState m_state; // Current state of parser
|
||||
int m_stateFor; // Token state is parsing for
|
||||
int m_off; // If non-zero, ifdef level is turned off, don't dump text
|
||||
string m_lastSym; // Last symbol name found.
|
||||
string m_formals; ///< Last formals found
|
||||
|
||||
// For getRawToken/ `line insertion
|
||||
string m_lineCmt; // Line comment(s) to be returned
|
||||
@ -371,6 +373,7 @@ const char* V3PreProcImp::tokenName(int tok) {
|
||||
case VP_LINE : return("LINE");
|
||||
case VP_SYMBOL : return("SYMBOL");
|
||||
case VP_STRING : return("STRING");
|
||||
case VP_DEFFORM : return("DEFFORM");
|
||||
case VP_DEFVALUE : return("DEFVALUE");
|
||||
case VP_COMMENT : return("COMMENT");
|
||||
case VP_TEXT : return("TEXT");
|
||||
@ -581,7 +584,7 @@ int V3PreProcImp::getRawToken() {
|
||||
return (VP_TEXT);
|
||||
}
|
||||
if (m_lineCmt!="") {
|
||||
// We have some `line directive to return to the user. Do it.
|
||||
// We have some `line directive or other processed data to return to the user.
|
||||
static string rtncmt; // Keep the c string till next call
|
||||
rtncmt = m_lineCmt;
|
||||
if (m_lineCmtNl) {
|
||||
@ -591,10 +594,11 @@ int V3PreProcImp::getRawToken() {
|
||||
yytext=(char*)rtncmt.c_str(); yyleng=rtncmt.length();
|
||||
m_lineCmt = "";
|
||||
if (yyleng) m_rawAtBol = (yytext[yyleng-1]=='\n');
|
||||
if (m_state!=ps_DEFVALUE) return (VP_TEXT);
|
||||
else {
|
||||
if (m_state==ps_DEFVALUE) {
|
||||
V3PreLex::s_currentLexp->appendDefValue(yytext,yyleng);
|
||||
goto next_tok;
|
||||
} else {
|
||||
return (VP_TEXT);
|
||||
}
|
||||
}
|
||||
if (isEof()) return (VP_EOF);
|
||||
@ -609,9 +613,9 @@ int V3PreProcImp::getRawToken() {
|
||||
string::size_type pos;
|
||||
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
|
||||
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
|
||||
fprintf (stderr, "%d: RAW %s s%d dr%d: %-10s: %s\n",
|
||||
fprintf (stderr, "%d: RAW %s s%d dr%d: <%d>%-10s: %s\n",
|
||||
fileline()->lineno(), m_off?"of":"on", m_state, (int)m_defRefs.size(),
|
||||
tokenName(tok), buf.c_str());
|
||||
m_lexp->currentStartState(), tokenName(tok), buf.c_str());
|
||||
}
|
||||
|
||||
// On EOF, try to pop to upper level includes, as needed.
|
||||
@ -695,8 +699,8 @@ int V3PreProcImp::getToken() {
|
||||
}
|
||||
else if (m_stateFor==VP_DEFINE) {
|
||||
// m_lastSym already set.
|
||||
m_state = ps_DEFVALUE;
|
||||
m_lexp->pushStateDefValue();
|
||||
m_state = ps_DEFFORM;
|
||||
m_lexp->pushStateDefForm();
|
||||
}
|
||||
else fileline()->v3fatalSrc("Bad case\n");
|
||||
goto next_tok;
|
||||
@ -706,45 +710,64 @@ int V3PreProcImp::getToken() {
|
||||
goto next_tok;
|
||||
}
|
||||
}
|
||||
case ps_DEFFORM: {
|
||||
if (tok==VP_DEFFORM) {
|
||||
m_formals = m_lexp->m_defValue;
|
||||
m_state = ps_DEFVALUE;
|
||||
if (debug()) cout<<"DefFormals='"<<m_formals<<"'\n";
|
||||
m_lexp->pushStateDefValue();
|
||||
goto next_tok;
|
||||
} else if (tok==VP_TEXT) {
|
||||
// IE, something like comment in formals
|
||||
if (!m_off) return tok;
|
||||
else goto next_tok;
|
||||
} else {
|
||||
fileline()->v3error("Expecting define formal arguments. Found: "<<tokenName(tok));
|
||||
goto next_tok;
|
||||
}
|
||||
}
|
||||
case ps_DEFVALUE: {
|
||||
static string newlines;
|
||||
newlines = "\n"; // Always start with trailing return
|
||||
if (tok == VP_DEFVALUE) {
|
||||
if (debug()) cout<<"DefValue='"<<m_lexp->m_defValue<<"' formals='"<<m_formals<<"'\n";
|
||||
// Add any formals
|
||||
string formAndValue = m_formals + m_lexp->m_defValue;
|
||||
// Remove returns
|
||||
for (unsigned i=0; i<m_lexp->m_defValue.length(); i++) {
|
||||
if (m_lexp->m_defValue[i] == '\n') {
|
||||
m_lexp->m_defValue[i] = ' ';
|
||||
for (unsigned i=0; i<formAndValue.length(); i++) {
|
||||
if (formAndValue[i] == '\n') {
|
||||
formAndValue[i] = ' ';
|
||||
newlines += "\n";
|
||||
}
|
||||
}
|
||||
if (!m_off) {
|
||||
string params;
|
||||
if (m_lexp->m_defValue=="" || isspace(m_lexp->m_defValue[0])) {
|
||||
if (formAndValue=="" || isspace(formAndValue[0])) {
|
||||
// Define without parameters
|
||||
} else if (m_lexp->m_defValue[0] == '(') {
|
||||
string::size_type paren = m_lexp->m_defValue.find(")");
|
||||
} else if (formAndValue[0] == '(') {
|
||||
string::size_type paren = formAndValue.find(")");
|
||||
if (paren == string::npos) {
|
||||
fileline()->v3error("Missing ) to end define arguments.");
|
||||
} else {
|
||||
params = m_lexp->m_defValue.substr(0, paren+1);
|
||||
m_lexp->m_defValue.replace(0, paren+1, "");
|
||||
params = formAndValue.substr(0, paren+1);
|
||||
formAndValue.replace(0, paren+1, "");
|
||||
}
|
||||
} else {
|
||||
fileline()->v3error("Missing space or paren to start define value.");
|
||||
}
|
||||
// Remove leading whitespace
|
||||
unsigned leadspace = 0;
|
||||
while (m_lexp->m_defValue.length() > leadspace
|
||||
&& isspace(m_lexp->m_defValue[leadspace])) leadspace++;
|
||||
if (leadspace) m_lexp->m_defValue.erase(0,leadspace);
|
||||
while (formAndValue.length() > leadspace
|
||||
&& isspace(formAndValue[leadspace])) leadspace++;
|
||||
if (leadspace) formAndValue.erase(0,leadspace);
|
||||
// Remove trailing whitespace
|
||||
unsigned trailspace = 0;
|
||||
while (m_lexp->m_defValue.length() > trailspace
|
||||
&& isspace(m_lexp->m_defValue[m_lexp->m_defValue.length()-1-trailspace])) trailspace++;
|
||||
if (trailspace) m_lexp->m_defValue.erase(m_lexp->m_defValue.length()-trailspace,trailspace);
|
||||
while (formAndValue.length() > trailspace
|
||||
&& isspace(formAndValue[formAndValue.length()-1-trailspace])) trailspace++;
|
||||
if (trailspace) formAndValue.erase(formAndValue.length()-trailspace,trailspace);
|
||||
// Define it
|
||||
UINFO(4,"Define "<<m_lastSym<<" = '"<<m_lexp->m_defValue<<"'"<<endl);
|
||||
define(fileline(), m_lastSym, m_lexp->m_defValue, params);
|
||||
UINFO(4,"Define "<<m_lastSym<<" = '"<<formAndValue<<"'"<<endl);
|
||||
define(fileline(), m_lastSym, formAndValue, params);
|
||||
}
|
||||
} else {
|
||||
fileline()->v3fatalSrc("Bad define text\n");
|
||||
@ -954,6 +977,7 @@ int V3PreProcImp::getToken() {
|
||||
}
|
||||
case VP_WHITE: // Handled at top of loop
|
||||
case VP_COMMENT: // Handled at top of loop
|
||||
case VP_DEFFORM: // Handled by m_state=ps_DEFFORM;
|
||||
case VP_DEFVALUE: // Handled by m_state=ps_DEFVALUE;
|
||||
default:
|
||||
fileline()->v3fatalSrc("Internal error: Unexpected token.\n");
|
||||
|
@ -177,4 +177,18 @@ begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end
|
||||
`line 130 "t/t_preproc.v" 0
|
||||
|
||||
Line_Preproc_Check 131
|
||||
`line 132 "t/t_preproc.v" 2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(p,q)
|
||||
|
||||
|
||||
|
||||
(x,y )
|
||||
Line_Preproc_Check 144
|
||||
|
||||
`line 146 "t/t_preproc.v" 2
|
||||
|
@ -129,3 +129,17 @@ assign c = tmp_``c ;
|
||||
`error "Empty is still true"
|
||||
`endif
|
||||
Line_Preproc_Check `__LINE__
|
||||
|
||||
//======================================================================
|
||||
// bug84
|
||||
|
||||
`define ARGPAR(a, // Hello, comments MIGHT not be legal
|
||||
/*more,,)cmts*/ b // But newlines ARE legal... who speced THAT?
|
||||
) (a,b)
|
||||
`ARGPAR(p,q)
|
||||
`ARGPAR( //Here
|
||||
x,
|
||||
y //Too
|
||||
)
|
||||
Line_Preproc_Check `__LINE__
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user