Internals: Reindent and move parser code. No functional change.

This commit is contained in:
Wilson Snyder 2020-06-06 08:44:44 -04:00
parent aae2bf872c
commit d15e3d93c4
5 changed files with 856 additions and 775 deletions

View File

@ -425,6 +425,9 @@ CPPCHECK_CPP = $(wildcard \
CPPCHECK_H = $(wildcard \ CPPCHECK_H = $(wildcard \
$(srcdir)/include/*.h \ $(srcdir)/include/*.h \
$(srcdir)/src/*.h ) $(srcdir)/src/*.h )
CPPCHECK_YL = $(wildcard \
$(srcdir)/src/*.y \
$(srcdir)/src/*.l )
CPPCHECK = src/cppcheck_filtered CPPCHECK = src/cppcheck_filtered
CPPCHECK_FLAGS = --enable=all --inline-suppr \ CPPCHECK_FLAGS = --enable=all --inline-suppr \
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \ --suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
@ -462,7 +465,7 @@ CLANGFORMAT_FLAGS = -i
clang-format: clang-format:
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \ @$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***" || echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL)
ftp: info ftp: info

View File

@ -34,6 +34,8 @@
#include "V3PreShell.h" #include "V3PreShell.h"
#include "V3LanguageWords.h" #include "V3LanguageWords.h"
#include "V3ParseBison.h" // Generated by bison
#include <sstream> #include <sstream>
//====================================================================== //======================================================================
@ -352,6 +354,151 @@ void V3ParseImp::lexFile(const string& modname) {
if (bisonParse()) v3fatal("Cannot continue\n"); if (bisonParse()) v3fatal("Cannot continue\n");
} }
void V3ParseImp::lexToken() {
// called from lexToBison, has a "this"
// Fetch next token from prefetch or real lexer
int token;
if (m_ahead) {
// We prefetched an extra token, give it back
m_ahead = false;
token = m_aheadVal.token;
yylval = m_aheadVal;
} else {
// Parse new token
token = yylexReadTok();
// yylval // Set by yylexReadTok()
}
// If a paren, read another
if (token == '(' //
|| token == yCONST__LEX //
|| token == yGLOBAL__LEX //
|| token == yLOCAL__LEX //
|| token == yNEW__LEX //
|| token == yVIRTUAL__LEX
// Never put yID_* here; below symbol table resolution would break
) {
if (debugFlex() >= 6) {
cout << " lexToken: reading ahead to find possible strength" << endl;
}
V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead
int nexttok = yylexReadTok();
m_ahead = true;
m_aheadVal = yylval;
m_aheadVal.token = nexttok;
yylval = curValue;
// Now potentially munge the current token
if (token == '('
&& (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) {
token = yP_PAR__STRENGTH;
} else if (token == yCONST__LEX) {
if (nexttok == yREF) {
token = yCONST__REF;
} else {
token = yCONST__ETC;
}
} else if (token == yGLOBAL__LEX) {
if (nexttok == yCLOCKING) {
token = yGLOBAL__CLOCKING;
} else if (v3Global.opt.pedantic()) {
token = yGLOBAL__ETC;
}
// Avoid 2009 "global" conflicting with old code when we can
else {
token = yaID__LEX;
yylval.strp = V3ParseImp::parsep()->newString("global");
}
} else if (token == yLOCAL__LEX) {
if (nexttok == yP_COLONCOLON) {
token = yLOCAL__COLONCOLON;
} else {
token = yLOCAL__ETC;
}
} else if (token == yNEW__LEX) {
if (nexttok == '(') {
token = yNEW__PAREN;
} else {
token = yNEW__ETC;
}
} else if (token == yVIRTUAL__LEX) {
if (nexttok == yCLASS) {
token = yVIRTUAL__CLASS;
} else if (nexttok == yINTERFACE) {
token = yVIRTUAL__INTERFACE;
} else if (nexttok == yaID__ETC //
|| nexttok == yaID__LEX) {
// || nexttok == yaID__aINTERFACE // but we may not know interfaces yet.
token = yVIRTUAL__anyID;
} else {
token = yVIRTUAL__ETC;
}
}
// If add to above "else if", also add to "if (token" further above
}
// If an id, change the type based on symbol table
// Note above sometimes converts yGLOBAL to a yaID__LEX
if (token == yaID__LEX) {
VSymEnt* foundp;
if (VSymEnt* look_underp = V3ParseImp::parsep()->symp()->nextId()) {
UINFO(7, " lexToken: next id lookup forced under " << look_underp << endl);
foundp = look_underp->findIdFallback(*(yylval.strp));
// "consume" it. Must set again if want another token under temp scope
V3ParseImp::parsep()->symp()->nextId(NULL);
} else {
UINFO(7, " lexToken: find upward " << V3ParseImp::parsep()->symp()->symCurrentp()
<< " for '" << *(yylval.strp) << "'" << endl);
// if (debug()>=9) V3ParseImp::parsep()->symp()->symCurrentp()->dump(cout," -findtree:
// ", true);
foundp = V3ParseImp::parsep()->symp()->symCurrentp()->findIdFallback(*(yylval.strp));
}
if (foundp) {
AstNode* scp = foundp->nodep();
yylval.scp = scp;
UINFO(7, " lexToken: Found " << scp << endl);
if (VN_IS(scp, Typedef)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, TypedefFwd)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, Class)) {
token = yaID__aTYPE;
}
// Packages (and class static references) we could
// alternatively determine by looking for an yaID__LEX followed
// by yP_COLONCOLON (but we can't lookahead after an yaID__LEX
// as described above.)
else if (VN_IS(scp, Package)) {
token = yaID__aPACKAGE;
} else {
token = yaID__ETC;
}
} else { // Not found
yylval.scp = NULL;
token = yaID__ETC;
}
}
yylval.token = token;
// effectively returns yylval
}
int V3ParseImp::lexToBison() {
// Called as global since bison doesn't have our pointer
lexToken(); // sets yylval
m_prevBisonVal = m_curBisonVal;
m_curBisonVal = yylval;
// yylval.scp = NULL; // Symbol table not yet needed - no packages
if (debugFlex() >= 6 || debugBison() >= 6) { // --debugi-flex and --debugi-bison
cout << " {" << yylval.fl->filenameLetters() << yylval.fl->asciiLineCol()
<< "} lexToBison TOKEN=" << yylval.token << " " << tokenName(yylval.token);
if (yylval.token == yaID__ETC //
|| yylval.token == yaID__LEX //
|| yylval.token == yaID__aTYPE) {
cout << " strp='" << *(yylval.strp) << "'";
}
cout << endl;
}
return yylval.token;
}
//====================================================================== //======================================================================
// V3Parse functions // V3Parse functions

View File

@ -1,8 +1,3 @@
%option noyywrap align interactive
%option stack
%option noc++
%option prefix="V3PreLex"
%{
/************************************************************************** /**************************************************************************
* DESCRIPTION: Verilator: Flex verilog preprocessor * DESCRIPTION: Verilator: Flex verilog preprocessor
* *
@ -20,6 +15,16 @@
* Do not use Flex in C++ mode. It has bugs with yyunput() which result in * Do not use Flex in C++ mode. It has bugs with yyunput() which result in
* lost characters. * lost characters.
**************************************************************************/ **************************************************************************/
/* clang-format off */
%option noyywrap align interactive
%option stack
%option noc++
%option prefix="V3PreLex"
%{
#ifdef NEVER_JUST_FOR_CLANG_FORMAT
}
#endif
#include "V3PreProc.h" #include "V3PreProc.h"
#include "V3PreLex.h" #include "V3PreLex.h"
@ -27,6 +32,8 @@
# include <io.h> // for isatty # include <io.h> // for isatty
#endif #endif
/* clang-format on */
V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
#define LEXP V3PreLex::s_currentLexp #define LEXP V3PreLex::s_currentLexp
@ -37,7 +44,10 @@ V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
// Accessors, because flex keeps changing the type of yyleng // Accessors, because flex keeps changing the type of yyleng
char* yyourtext() { return yytext; } char* yyourtext() { return yytext; }
size_t yyourleng() { return yyleng; } size_t yyourleng() { return yyleng; }
void yyourtext(const char* textp, size_t size) { yytext=(char*)textp; yyleng=size; } void yyourtext(const char* textp, size_t size) {
yytext = (char*)textp;
yyleng = size;
}
// FL_FWD only tracks columns; preproc uses linenoInc() to track lines, so // FL_FWD only tracks columns; preproc uses linenoInc() to track lines, so
// insertion of a \n does not mess up line count // insertion of a \n does not mess up line count
@ -52,6 +62,7 @@ static void yyerror(char* msg) { LEXP->curFilelinep()->v3error(msg); }
static void yyerrorf(const char* msg) { LEXP->curFilelinep()->v3error(msg); } static void yyerrorf(const char* msg) { LEXP->curFilelinep()->v3error(msg); }
static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t, l); } static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t, l); }
/* clang-format off */
/**********************************************************************/ /**********************************************************************/
%} %}
@ -308,6 +319,7 @@ bom [\357\273\277]
<INITIAL>[\r] { FL_FWDC; FL_BRK; } <INITIAL>[\r] { FL_FWDC; FL_BRK; }
<INITIAL>. { FL_FWDC; return VP_TEXT; } <INITIAL>. { FL_FWDC; return VP_TEXT; }
%% %%
// clang-format on
void V3PreLex::pushStateDefArg(int level) { void V3PreLex::pushStateDefArg(int level) {
// Enter define substitution argument state // Enter define substitution argument state
@ -336,12 +348,15 @@ void V3PreLex::pushStateIncFilename() {
yymore(); yymore();
} }
void V3PreLex::debug(int level) { yy_flex_debug = level; } void V3PreLex::debug(int level) {
int V3PreLex::debug() { return yy_flex_debug; } yy_flex_debug = level; }
int V3PreLex::debug() {
return yy_flex_debug; }
int V3PreLex::lex() { int V3PreLex::lex() {
V3PreLex::s_currentLexp = this; // Tell parser where to get/put data V3PreLex::s_currentLexp = this; // Tell parser where to get/put data
m_tokFilelinep = curFilelinep(); // Remember token start location, may be updated by the lexer later // Remember token start location, may be updated by the lexer later
m_tokFilelinep = curFilelinep();
return yylex(); return yylex();
} }
@ -354,7 +369,8 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
// //
VPreStream* streamp = curStreamp(); VPreStream* streamp = curStreamp();
if (debug() >= 10) { if (debug() >= 10) {
cout<<"- pp:inputToLex ITL s="<<max_size<<" bs="<<streamp->m_buffers.size()<<endl; cout << "- pp:inputToLex ITL s=" << max_size << " bs=" << streamp->m_buffers.size()
<< endl;
dumpStack(); dumpStack();
} }
// For testing, use really small chunks // For testing, use really small chunks
@ -364,7 +380,8 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
// Get from this stream // Get from this stream
while (got < max_size // Haven't got enough while (got < max_size // Haven't got enough
&& !streamp->m_buffers.empty()) { // And something buffered && !streamp->m_buffers.empty()) { // And something buffered
string front = curStreamp()->m_buffers.front(); streamp->m_buffers.pop_front(); string front = curStreamp()->m_buffers.front();
streamp->m_buffers.pop_front();
size_t len = front.length(); size_t len = front.length();
if (len > (max_size - got)) { // Front string too big if (len > (max_size - got)) { // Front string too big
len = (max_size - got); len = (max_size - got);
@ -394,7 +411,9 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
if (again) goto again; if (again) goto again;
} }
} }
if (debug() >= 10) { cout<<"- pp::inputToLex got="<<got<<" '"<<string(buf, got)<<"'"<<endl; } if (debug() >= 10) {
cout << "- pp::inputToLex got=" << got << " '" << string(buf, got) << "'" << endl;
}
return got; return got;
} }
@ -424,18 +443,15 @@ string V3PreLex::endOfStream(bool& againr) {
// immediately. // immediately.
curStreamp()->m_termState = 1; curStreamp()->m_termState = 1;
return "\n"; // Exit old file return "\n"; // Exit old file
} } else if (curStreamp()->m_termState == 1) {
else if (curStreamp()->m_termState == 1) {
// Now the EOF - can't be sent with other characters // Now the EOF - can't be sent with other characters
curStreamp()->m_termState = 2; curStreamp()->m_termState = 2;
return ""; // End of file return ""; // End of file
} } else if (curStreamp()->m_termState == 2) {
else if (curStreamp()->m_termState == 2) {
// Now ending `line // Now ending `line
curStreamp()->m_termState = 3; curStreamp()->m_termState = 3;
return curFilelinep()->lineDirectiveStrg(2); // Exit old file return curFilelinep()->lineDirectiveStrg(2); // Exit old file
} } else {
else {
// Final shutdown phase for a stream, we can finally change the // Final shutdown phase for a stream, we can finally change the
// current fileline to the new stream // current fileline to the new stream
curStreamp()->m_termState = 0; curStreamp()->m_termState = 0;
@ -543,15 +559,14 @@ void V3PreLex::lineDirective(const char* textp) {
void V3PreLex::warnBackslashSpace() { void V3PreLex::warnBackslashSpace() {
// Make fileline highlight the specific backslash and space // Make fileline highlight the specific backslash and space
curFilelinep()->v3warn(BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?"); curFilelinep()->v3warn(
BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?");
} }
void V3PreLex::dumpSummary() { void V3PreLex::dumpSummary() {
cout << "- pp::dumpSummary curBuf=" << cvtToHex(currentBuffer()); cout << "- pp::dumpSummary curBuf=" << cvtToHex(currentBuffer());
#ifdef FLEX_DEBUG // Else peeking at internals may cause portability issues #ifdef FLEX_DEBUG // Else peeking at internals may cause portability issues
ssize_t left = (yy_n_chars ssize_t left = (yy_n_chars - (yy_c_buf_p - currentBuffer()->yy_ch_buf));
- (yy_c_buf_p
-currentBuffer()->yy_ch_buf));
cout << " left=" << std::dec << left; cout << " left=" << std::dec << left;
#endif #endif
cout << endl; cout << endl;
@ -564,12 +579,9 @@ void V3PreLex::dumpStack() {
while (!tmpstack.empty()) { while (!tmpstack.empty()) {
VPreStream* streamp = tmpstack.top(); VPreStream* streamp = tmpstack.top();
cout << "- bufferStack[" << cvtToHex(streamp) << "]: " cout << "- bufferStack[" << cvtToHex(streamp) << "]: "
<<" at="<<streamp->m_curFilelinep << " at=" << streamp->m_curFilelinep << " nBuf=" << streamp->m_buffers.size()
<<" nBuf="<<streamp->m_buffers.size()
<< " size0=" << (streamp->m_buffers.empty() ? 0 : streamp->m_buffers.front().length()) << " size0=" << (streamp->m_buffers.empty() ? 0 : streamp->m_buffers.front().length())
<<(streamp->m_eof?" [EOF]":"") << (streamp->m_eof ? " [EOF]" : "") << (streamp->m_file ? " [FILE]" : "") << endl;
<<(streamp->m_file?" [FILE]":"");
cout<<endl;
tmpstack.pop(); tmpstack.pop();
} }
} }

View File

@ -13,10 +13,15 @@
* SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 * SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
* *
*************************************************************************/ *************************************************************************/
/* clang-format off */
%option interactive c++ stack noyywrap %option interactive c++ stack noyywrap
%{ %{
/* %option nodefault */ /* %option nodefault */
#ifdef NEVER_JUST_FOR_CLANG_FORMAT
}
#endif
// clang-format on
#include "V3Number.h" #include "V3Number.h"
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header #include "V3ParseImp.h" // Defines YYTYPE; before including bison header
@ -41,12 +46,18 @@ extern void yyerrorf(const char* format, ...);
#define CRELINE() (PARSEP->copyOrSameFileLine()) #define CRELINE() (PARSEP->copyOrSameFileLine())
#define FL do { FL_FWD; yylval.fl = CRELINE(); } while (false) #define FL \
do { \
FL_FWD; \
yylval.fl = CRELINE(); \
} while (false)
#define ERROR_RSVD_WORD(language) \ #define ERROR_RSVD_WORD(language) \
do { FL_FWD; \ do { \
FL_FWD; \
yyerrorf("Unsupported: " language " reserved word not implemented: '%s'", yytext); \ yyerrorf("Unsupported: " language " reserved word not implemented: '%s'", yytext); \
FL_BRK; } while(0) FL_BRK; \
} while (0)
//====================================================================== //======================================================================
@ -80,6 +91,7 @@ void yyerrorf(const char* format, ...) {
yyerror(msg); yyerror(msg);
} }
// clang-format off
/**********************************************************************/ /**********************************************************************/
%} %}
@ -1039,149 +1051,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* Catch all - absolutely last */ /* Catch all - absolutely last */
<*>.|\n { FL_FWD; yyerrorf("Missing verilog.l rule: Default rule invoked in state %d: %s", YY_START, yytext); FL_BRK; } <*>.|\n { FL_FWD; yyerrorf("Missing verilog.l rule: Default rule invoked in state %d: %s", YY_START, yytext); FL_BRK; }
%% %%
// Avoid code here as cl format misindents
// For implementation functions see V3ParseImp.cpp
int V3ParseImp::stateVerilogRecent() { return STATE_VERILOG_RECENT; } int V3ParseImp::stateVerilogRecent() { return STATE_VERILOG_RECENT; }
void V3ParseImp::lexToken() {
// called from lexToBison, has a "this"
// Fetch next token from prefetch or real lexer
int token;
if (m_ahead) {
// We prefetched an extra token, give it back
m_ahead = false;
token = m_aheadVal.token;
yylval = m_aheadVal;
} else {
// Parse new token
token = yylexReadTok();
// yylval // Set by yylexReadTok()
}
// If a paren, read another
if (token == '(' //
|| token == yCONST__LEX //
|| token == yGLOBAL__LEX //
|| token == yLOCAL__LEX //
|| token == yNEW__LEX //
|| token == yVIRTUAL__LEX
// Never put yID_* here; below symbol table resolution would break
) {
if (debugFlex() >= 6) {
cout << " lexToken: reading ahead to find possible strength" << endl;
}
V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead
int nexttok = yylexReadTok();
m_ahead = true;
m_aheadVal = yylval;
m_aheadVal.token = nexttok;
yylval = curValue;
// Now potentially munge the current token
if (token == '('
&& (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) {
token = yP_PAR__STRENGTH;
} else if (token == yCONST__LEX) {
if (nexttok == yREF) {
token = yCONST__REF;
} else {
token = yCONST__ETC;
}
} else if (token == yGLOBAL__LEX) {
if (nexttok == yCLOCKING) {
token = yGLOBAL__CLOCKING;
} else if (v3Global.opt.pedantic()) {
token = yGLOBAL__ETC;
}
// Avoid 2009 "global" conflicting with old code when we can
else {
token = yaID__LEX;
yylval.strp = PARSEP->newString("global");
}
} else if (token == yLOCAL__LEX) {
if (nexttok == yP_COLONCOLON) {
token = yLOCAL__COLONCOLON;
} else {
token = yLOCAL__ETC;
}
} else if (token == yNEW__LEX) {
if (nexttok == '(') {
token = yNEW__PAREN;
} else {
token = yNEW__ETC;
}
} else if (token == yVIRTUAL__LEX) {
if (nexttok == yCLASS) {
token = yVIRTUAL__CLASS;
} else if (nexttok == yINTERFACE) {
token = yVIRTUAL__INTERFACE;
} else if (nexttok == yaID__ETC //
|| nexttok == yaID__LEX) {
// || nexttok == yaID__aINTERFACE // but we may not know interfaces yet.
token = yVIRTUAL__anyID;
} else {
token = yVIRTUAL__ETC;
}
}
// If add to above "else if", also add to "if (token" further above
}
// If an id, change the type based on symbol table
// Note above sometimes converts yGLOBAL to a yaID__LEX
if (token == yaID__LEX) {
VSymEnt* foundp;
if (VSymEnt* look_underp = SYMP->nextId()) {
UINFO(7, " lexToken: next id lookup forced under " << look_underp << endl);
foundp = look_underp->findIdFallback(*(yylval.strp));
// "consume" it. Must set again if want another token under temp scope
SYMP->nextId(NULL);
} else {
UINFO(7, " lexToken: find upward " << SYMP->symCurrentp() << " for '"
<< *(yylval.strp) << "'" << endl);
// if (debug()>=9) SYMP->symCurrentp()->dump(cout," -findtree: ", true);
foundp = SYMP->symCurrentp()->findIdFallback(*(yylval.strp));
}
if (foundp) {
AstNode* scp = foundp->nodep();
yylval.scp = scp;
UINFO(7, " lexToken: Found " << scp << endl);
if (VN_IS(scp, Typedef)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, TypedefFwd)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, Class)) {
token = yaID__aTYPE;
}
// Packages (and class static references) we could
// alternatively determine by looking for an yaID__LEX followed
// by yP_COLONCOLON (but we can't lookahead after an yaID__LEX
// as described above.)
else if (VN_IS(scp, Package)) {
token = yaID__aPACKAGE;
} else {
token = yaID__ETC;
}
} else { // Not found
yylval.scp = NULL;
token = yaID__ETC;
}
}
yylval.token = token;
// effectively returns yylval
}
int V3ParseImp::lexToBison() {
// Called as global since bison doesn't have our pointer
lexToken(); // sets yylval
m_prevBisonVal = m_curBisonVal;
m_curBisonVal = yylval;
// yylval.scp = NULL; // Symbol table not yet needed - no packages
if (debugFlex() >= 6 || debugBison() >= 6) { // --debugi-flex and --debugi-bison
cout << " {" << yylval.fl->filenameLetters() << yylval.fl->asciiLineCol()
<< "} lexToBison TOKEN=" << yylval.token << " " << tokenName(yylval.token);
if (yylval.token == yaID__ETC //
|| yylval.token == yaID__LEX //
|| yylval.token == yaID__aTYPE) {
cout << " strp='" << *(yylval.strp) << "'";
}
cout << endl;
}
return yylval.token;
}

View File

@ -15,8 +15,13 @@
//************************************************************************* //*************************************************************************
// Original code here by Paul Wasson and Duane Galbi // Original code here by Paul Wasson and Duane Galbi
//************************************************************************* //*************************************************************************
// clang-format off
%{ %{
#ifdef NEVER_JUST_FOR_CLANG_FORMAT
}
#endif
// clang-format on
#include "V3Ast.h" #include "V3Ast.h"
#include "V3Global.h" #include "V3Global.h"
#include "V3Config.h" #include "V3Config.h"
@ -31,8 +36,12 @@
// Pick up new lexer // Pick up new lexer
#define yylex PARSEP->lexToBison #define yylex PARSEP->lexToBison
#define BBUNSUP(fl,msg) { if (!v3Global.opt.bboxUnsup()) { (fl)->v3error(msg); } } #define BBUNSUP(fl, msg) \
#define GATEUNSUP(fl,tok) { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: "<<(tok)); } { \
if (!v3Global.opt.bboxUnsup()) { (fl)->v3error(msg); } \
}
#define GATEUNSUP(fl, tok) \
{ BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); }
extern void yyerror(const char* errmsg); extern void yyerror(const char* errmsg);
extern void yyerrorf(const char* format, ...); extern void yyerrorf(const char* format, ...);
@ -97,7 +106,8 @@ public:
} }
AstRange* scrubRange(AstNodeRange* rangep); AstRange* scrubRange(AstNodeRange* rangep);
AstNodeDType* createArray(AstNodeDType* basep, AstNodeRange* rangep, bool isPacked); AstNodeDType* createArray(AstNodeDType* basep, AstNodeRange* rangep, bool isPacked);
AstVar* createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp, AstNode* attrsp); AstVar* createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp,
AstNode* attrsp);
AstNode* createSupplyExpr(FileLine* fileline, const string& name, int value); AstNode* createSupplyExpr(FileLine* fileline, const string& name, int value);
AstText* createTextQuoted(FileLine* fileline, const string& text) { AstText* createTextQuoted(FileLine* fileline, const string& text) {
string newtext = deQuote(fileline, text); string newtext = deQuote(fileline, text);
@ -110,8 +120,11 @@ public:
} }
AstNode* createGatePin(AstNode* exprp) { AstNode* createGatePin(AstNode* exprp) {
AstRange* rangep = m_gateRangep; AstRange* rangep = m_gateRangep;
if (!rangep) return exprp; if (!rangep) {
else return new AstGatePin(rangep->fileline(), exprp, rangep->cloneTree(true)); return exprp;
} else {
return new AstGatePin(rangep->fileline(), exprp, rangep->cloneTree(true));
}
} }
void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) { void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) {
endLabel(fl, nodep->prettyName(), endnamep); endLabel(fl, nodep->prettyName(), endnamep);
@ -119,12 +132,13 @@ public:
void endLabel(FileLine* fl, const string& name, string* endnamep) { void endLabel(FileLine* fl, const string& name, string* endnamep) {
if (fl && endnamep && *endnamep != "" && name != *endnamep if (fl && endnamep && *endnamep != "" && name != *endnamep
&& name != AstNode::prettyName(*endnamep)) { && name != AstNode::prettyName(*endnamep)) {
fl->v3warn(ENDLABEL,"End label '"<<*endnamep<<"' does not match begin label '"<<name<<"'"); fl->v3warn(ENDLABEL, "End label '" << *endnamep << "' does not match begin label '"
<< name << "'");
} }
} }
void setVarDecl(AstVarType type) { m_varDecl = type; } void setVarDecl(AstVarType type) { m_varDecl = type; }
void setDType(AstNodeDType* dtypep) { void setDType(AstNodeDType* dtypep) {
if (m_varDTypep) VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep=NULL); // It was cloned, so this is safe. if (m_varDTypep) VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep = NULL);
m_varDTypep = dtypep; m_varDTypep = dtypep;
} }
AstPackage* unitPackage(FileLine* fl) { AstPackage* unitPackage(FileLine* fl) {
@ -160,8 +174,9 @@ public:
if (AstRange* finalRangep = VN_CAST(finalp, Range)) { // not an UnsizedRange if (AstRange* finalRangep = VN_CAST(finalp, Range)) { // not an UnsizedRange
if (dtypep->implicit()) { if (dtypep->implicit()) {
// It's no longer implicit but a wire logic type // It's no longer implicit but a wire logic type
AstBasicDType* newp = new AstBasicDType(dtypep->fileline(), AstBasicDTypeKwd::LOGIC, AstBasicDType* newp = new AstBasicDType(
dtypep->numeric(), dtypep->width(), dtypep->widthMin()); dtypep->fileline(), AstBasicDTypeKwd::LOGIC, dtypep->numeric(),
dtypep->width(), dtypep->widthMin());
VL_DO_DANGLING(dtypep->deleteTree(), dtypep); VL_DO_DANGLING(dtypep->deleteTree(), dtypep);
dtypep = newp; dtypep = newp;
} }
@ -187,53 +202,87 @@ int V3ParseGrammar::s_modTypeImpNum = 0;
//====================================================================== //======================================================================
// Macro functions // Macro functions
#define CRELINE() (PARSEP->copyOrSameFileLine()) // Only use in empty rules, so lines point at beginnings #define CRELINE() \
(PARSEP->copyOrSameFileLine()) // Only use in empty rules, so lines point at beginnings
#define FILELINE_OR_CRE(nodep) ((nodep) ? (nodep)->fileline() : CRELINE()) #define FILELINE_OR_CRE(nodep) ((nodep) ? (nodep)->fileline() : CRELINE())
#define VARRESET_LIST(decl) { GRAMMARP->m_pinNum=1; GRAMMARP->m_pinAnsi=false; \ #define VARRESET_LIST(decl) \
VARRESET(); VARDECL(decl); } // Start of pinlist { \
#define VARRESET_NONLIST(decl) { GRAMMARP->m_pinNum=0; GRAMMARP->m_pinAnsi=false; \ GRAMMARP->m_pinNum = 1; \
VARRESET(); VARDECL(decl); } // Not in a pinlist GRAMMARP->m_pinAnsi = false; \
#define VARRESET() { VARDECL(UNKNOWN); VARIO(NONE); VARDTYPE_NDECL(NULL); \ VARRESET(); \
VARDECL(decl); \
} // Start of pinlist
#define VARRESET_NONLIST(decl) \
{ \
GRAMMARP->m_pinNum = 0; \
GRAMMARP->m_pinAnsi = false; \
VARRESET(); \
VARDECL(decl); \
} // Not in a pinlist
#define VARRESET() \
{ \
VARDECL(UNKNOWN); \
VARIO(NONE); \
VARDTYPE_NDECL(NULL); \
GRAMMARP->m_varLifetime = VLifetime::NONE; \ GRAMMARP->m_varLifetime = VLifetime::NONE; \
GRAMMARP->m_varDeclTyped = false; } GRAMMARP->m_varDeclTyped = false; \
#define VARDECL(type) { GRAMMARP->setVarDecl(AstVarType::type); } }
#define VARIO(type) { GRAMMARP->m_varIO = VDirection::type; } #define VARDECL(type) \
#define VARLIFE(flag) { GRAMMARP->m_varLifetime = flag; } { GRAMMARP->setVarDecl(AstVarType::type); }
#define VARDTYPE(dtypep) { GRAMMARP->setDType(dtypep); GRAMMARP->m_varDeclTyped = true; } #define VARIO(type) \
#define VARDTYPE_NDECL(dtypep) { GRAMMARP->setDType(dtypep); } // Port that is range or signed only (not a decl) { GRAMMARP->m_varIO = VDirection::type; }
#define VARLIFE(flag) \
{ GRAMMARP->m_varLifetime = flag; }
#define VARDTYPE(dtypep) \
{ \
GRAMMARP->setDType(dtypep); \
GRAMMARP->m_varDeclTyped = true; \
}
#define VARDTYPE_NDECL(dtypep) \
{ GRAMMARP->setDType(dtypep); } // Port that is range or signed only (not a decl)
#define VARDONEA(fl, name, array, attrs) GRAMMARP->createVariable((fl), (name), (array), (attrs)) #define VARDONEA(fl, name, array, attrs) GRAMMARP->createVariable((fl), (name), (array), (attrs))
#define VARDONEP(portp,array,attrs) GRAMMARP->createVariable((portp)->fileline(),(portp)->name(),(array),(attrs)) #define VARDONEP(portp, array, attrs) \
GRAMMARP->createVariable((portp)->fileline(), (portp)->name(), (array), (attrs))
#define PINNUMINC() (GRAMMARP->m_pinNum++) #define PINNUMINC() (GRAMMARP->m_pinNum++)
#define GATERANGE(rangep) { GRAMMARP->m_gateRangep = rangep; } #define GATERANGE(rangep) \
{ GRAMMARP->m_gateRangep = rangep; }
#define INSTPREP(modfl,modname,paramsp) { \ #define INSTPREP(modfl, modname, paramsp) \
{ \
GRAMMARP->m_impliedDecl = true; \ GRAMMARP->m_impliedDecl = true; \
GRAMMARP->m_instModuleFl = modfl; GRAMMARP->m_instModule = modname; \ GRAMMARP->m_instModuleFl = modfl; \
GRAMMARP->m_instParamp = paramsp; } GRAMMARP->m_instModule = modname; \
GRAMMARP->m_instParamp = paramsp; \
}
#define DEL(nodep) { if (nodep) nodep->deleteTree(); } #define DEL(nodep) \
{ \
if (nodep) nodep->deleteTree(); \
}
static void ERRSVKWD(FileLine* fileline, const string& tokname) { static void ERRSVKWD(FileLine* fileline, const string& tokname) {
static int toldonce = 0; static int toldonce = 0;
fileline->v3error(string("Unexpected '")+tokname+"': '"+tokname fileline->v3error(
string("Unexpected '") + tokname + "': '" + tokname
+ "' is a SystemVerilog keyword misused as an identifier." + "' is a SystemVerilog keyword misused as an identifier."
+(!toldonce++ + (!toldonce++ ? "\n" + V3Error::warnMore()
? "\n"+V3Error::warnMore()
+ "... Suggest modify the Verilog-2001 code to avoid SV keywords," + "... Suggest modify the Verilog-2001 code to avoid SV keywords,"
+ " or use `begin_keywords or --language." + " or use `begin_keywords or --language."
: "")); : ""));
} }
static void UNSUPREAL(FileLine* fileline) { static void UNSUPREAL(FileLine* fileline) {
fileline->v3warn(SHORTREAL, "Unsupported: shortreal being promoted to real (suggest use real instead)"); fileline->v3warn(SHORTREAL,
"Unsupported: shortreal being promoted to real (suggest use real instead)");
} }
//====================================================================== //======================================================================
class AstSenTree; class AstSenTree;
// clang-format off
%} %}
// When writing Bison patterns we use yTOKEN instead of "token", // When writing Bison patterns we use yTOKEN instead of "token",