From 18bebaf5c310b39f1e1702419b1e43f8c1374a9d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 31 Oct 2009 10:14:04 -0400 Subject: [PATCH] Internals: Add parse-time symbol table for eventual typedef detection --- src/V3Link.cpp | 2 +- src/V3LinkCells.cpp | 5 ++ src/V3ParseImp.cpp | 4 ++ src/V3ParseImp.h | 116 +++++++++++++++++++++++++++++++++++++++++++- src/V3SymTable.h | 36 +++++++++++--- src/Verilator.cpp | 4 ++ src/verilog.y | 38 +++++++++------ 7 files changed, 182 insertions(+), 23 deletions(-) diff --git a/src/V3Link.cpp b/src/V3Link.cpp index 733d8495d..f0fb3da64 100644 --- a/src/V3Link.cpp +++ b/src/V3Link.cpp @@ -88,7 +88,7 @@ private: if (V3SymTable* symsp = nodep->user1p()->castSymTable()) { return symsp; } else { - V3SymTable* symsp = new V3SymTable(upperVarsp); + V3SymTable* symsp = new V3SymTable(nodep, upperVarsp); m_delSymps.push_back(symsp); nodep->user1p(symsp); return symsp; diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index c7a2274c7..e9fca5bb3 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -18,6 +18,9 @@ // GNU General Public License for more details. // //************************************************************************* +// NO EDITS: Don't replace or delete nodes, as the parser symbol table +// has pointers into the ast tree. +// // LINK TRANSFORMATIONS: // Top-down traversal // Cells: @@ -88,6 +91,8 @@ private: // NODE STATE // Entire netlist: // AstModule::user1p() // V3GraphVertex* Vertex describing this module + // Allocated across all readFiles in V3Global::readFiles: + // AstNode::user4p() // V3SymTable* Package and typedef symbol names AstUser1InUse m_inuser1; // STATE diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index a0bcbe93b..598e8d069 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -46,6 +46,8 @@ V3ParseImp* V3ParseImp::s_parsep = NULL; +int V3ParseSym::s_anonNum = 0; + //###################################################################### // Read class functions @@ -60,6 +62,8 @@ V3ParseImp::~V3ParseImp() { m_numberps.clear(); lexDestroy(); parserClear(); + + if (debug()>=9) { UINFO(0,"~V3ParseImp\n"); symp()->dump(cout, "-vpi: "); } } int V3ParseImp::ppInputToLex(char* buf, int max_size) { diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 32598df8d..a2dc2ea94 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -45,6 +45,7 @@ typedef enum { uniq_NONE, uniq_UNIQUE, uniq_PRIORITY } V3UniqState; struct V3ParseBisonYYSType { FileLine* fl; + //V3SymTable* scp; // Symbol table scope for future lookups union { V3Number* nump; string* strp; @@ -73,6 +74,115 @@ struct V3ParseBisonYYSType { #define YYSTYPE V3ParseBisonYYSType +//###################################################################### +// Symbol table for parsing + +class V3ParseSym { + // TYPES + typedef vector SymStack; + +private: + // MEMBERS + static int s_anonNum; // Number of next anonymous object + V3SymTable* m_symTableNextId; // Symbol table for next lexer lookup + V3SymTable* m_symCurrentp; // Node with active symbol table for additions/lookups + SymStack m_sympStack; // Stack of nodes with symbol tables + SymStack m_symsp; // All symbol tables, to cleanup + +private: + // METHODS + static V3SymTable* getTable(AstNode* nodep) { + if (!nodep->user4p()) nodep->v3fatalSrc("Current symtable not found"); + return nodep->user4p()->castSymTable(); + } + +public: + V3SymTable* nextId() const { return m_symTableNextId; } + V3SymTable* symCurrentp() const { return m_symCurrentp; } + + V3SymTable* findNewTable(AstNode* nodep, V3SymTable* parentp) { + if (!nodep->user4p()) { + V3SymTable* symsp = new V3SymTable(nodep, parentp); + nodep->user4p(symsp); + m_symsp.push_back(symsp); + } + return getTable(nodep); + } + void nextId(AstNode* entp) { + if (entp) { UINFO(9,"symTableNextId under "<type().ascii()<name(); + if (name == "") { // New name with space in name so can't collide with users + name = string(" anon") + nodep->type().ascii() + cvtToStr(++s_anonNum); + } + parentp->reinsert(name,nodep); + } + void pushNew(AstNode* nodep) { pushNewUnder(nodep, NULL); } + void pushNewUnder(AstNode* nodep, V3SymTable* parentp) { + if (!parentp) parentp = symCurrentp(); + V3SymTable* symp = findNewTable(nodep, parentp); // Will set user4p, which is how we connect table to node + reinsert(nodep, parentp); + pushScope(symp); + } + void pushScope(V3SymTable* symp) { + m_sympStack.push_back(symp); + m_symCurrentp = symp; + } + void popScope(AstNode* nodep) { + if (symCurrentp()->ownerp() != nodep) { + if (debug()) { showUpward(); dump(cout,"-mism: "); } + nodep->v3fatalSrc("Symbols suggest ending "<ownerp()->prettyTypeName() + <<" but parser thinks ending "<prettyTypeName()); + return; + } + m_sympStack.pop_back(); + if (m_sympStack.empty()) { nodep->v3fatalSrc("symbol stack underflow"); return; } + m_symCurrentp = m_sympStack.back(); + } + void showUpward () { + UINFO(1,"ParseSym Stack:\n"); + for (SymStack::reverse_iterator it=m_sympStack.rbegin(); it!=m_sympStack.rend(); ++it) { + V3SymTable* symp = *it; + UINFO(1,"\t"<ownerp()<ownerp()<dump(os, indent, true); + } + AstNode* findEntUpward (const string& name) { + // Lookup the given string as an identifier, return type of the id, scanning upward + return symCurrentp()->findIdUpward(name); + } + void import(AstNode* nodep, const string& pkg, const string& id_or_star) { + // Import from package::id_or_star to this + AstNode* entp = findEntUpward(pkg); + if (!entp) { // Internal problem, because we earlier found pkg to label it an ID__aPACKAGE + nodep->v3fatalSrc("Import package not found: "+pkg); + return; + } + // Walk old sym table and reinsert into current table + nodep->v3fatalSrc("Unimplemented: import"); + } +public: + // CREATORS + V3ParseSym(AstNetlist* rootp) { + s_anonNum = 0; // Number of next anonymous object + pushScope(findNewTable(rootp, NULL)); + m_symTableNextId = symCurrentp(); + } + ~V3ParseSym() { + for (SymStack::iterator it = m_symsp.begin(); it != m_symsp.end(); ++it) { + delete (*it); + } + } +}; + //###################################################################### class V3ParseImp { @@ -82,6 +192,7 @@ class V3ParseImp { static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based FileLine* m_fileline; // Filename/linenumber currently active + V3ParseSym m_sym; // Symbol table bool m_inCellDefine; // Inside a `celldefine bool m_inLibrary; // Currently reading a library vs. regular file int m_inBeginKwd; // Inside a `begin_keywords @@ -172,9 +283,12 @@ public: int stateVerilogRecent(); // Parser -> lexer communication int flexPpInputToLex(char* buf, int max_size) { return ppInputToLex(buf,max_size); } + //==== Symbol tables + V3ParseSym* symp() { return &m_sym; } + public: // CREATORS - V3ParseImp(AstNetlist* rootp) { + V3ParseImp(AstNetlist* rootp) : m_sym(rootp) { m_rootp = rootp; m_lexerp = NULL; m_inCellDefine = false; m_inLibrary = false; diff --git a/src/V3SymTable.h b/src/V3SymTable.h index 2d04910d6..aa18805b2 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -40,13 +40,17 @@ class V3SymTable : public AstNUser { private: // MEMBERS typedef std::map IdNameMap; - IdNameMap m_idNameMap; // Hash of variables by name + IdNameMap m_idNameMap; // Hash of variables by name + AstNode* m_ownerp; // Node that table belongs to V3SymTable* m_upperp; // Table "above" this one in name scope public: // METHODS - V3SymTable(V3SymTable* upperTablep) { m_upperp = upperTablep; } - V3SymTable() { m_upperp = NULL; } + V3SymTable(AstNode* ownerp, V3SymTable* upperTablep) { + m_ownerp = ownerp; m_upperp = upperTablep; } + V3SymTable() { + m_ownerp = NULL; m_upperp = NULL; } ~V3SymTable() {} + AstNode* ownerp() const { return m_ownerp; } void insert(const string& name, AstNode* nodep) { //UINFO(9, " SymInsert "<second = nodep; // Replace + } else { + insert(name,nodep); + } + } + AstNode* findIdFlat(const string& name) const { // Find identifier without looking upward through symbol hierarchy //UINFO(9, " SymFind "<second); return NULL; } - AstNode* findIdUpward(const string& name) { + AstNode* findIdUpward(const string& name) const { // Find identifier looking upward through symbol hierarchy // First, scan this begin/end block or module for the name if (AstNode* nodep = findIdFlat(name)) return nodep; @@ -73,6 +86,17 @@ class V3SymTable : public AstNUser { if (m_upperp) return m_upperp->findIdUpward(name); return NULL; } + void dump(ostream& os, const string& indent="", bool user4p_is_table=false) const { + for (IdNameMap::const_iterator it=m_idNameMap.begin(); it!=m_idNameMap.end(); ++it) { + os<first; + for (int i=it->first.length(); i<30; ++i) os<<" "; + os<second<second)->user4p()->castSymTable(); + belowp->dump(os, indent+" ", user4p_is_table); + } + } + } }; #endif // guard diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 2aa8c7657..c34f30c1d 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -92,6 +92,10 @@ V3Global v3Global; // V3 Class -- top level void V3Global::readFiles() { + // NODE STATE + // AstNode::user4p() // V3SymTable* Package and typedef symbol names + AstUser4InUse inuser4; + V3Parse parser (v3Global.rootp()); // Read top module for (V3StringList::const_iterator it = v3Global.opt.vFiles().begin(); diff --git a/src/verilog.y b/src/verilog.y index 53c63e700..0347f46b4 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -101,6 +101,7 @@ public: }; #define PARSEP V3ParseImp::parsep() +#define SYMP PARSEP->symp() #define GRAMMARP V3ParseGrammar::singletonp() //====================================================================== @@ -521,7 +522,7 @@ module_declaration: // ==IEEE: module_declaration { $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3); if ($5) $1->addStmtp($5); - } + SYMP->popScope($1); } // //UNSUP yEXTERN modFront parameter_port_listE portsStarE ';' //UNSUP { UNSUP } @@ -534,7 +535,7 @@ modFront: { $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine()); $$->modTrace(v3Global.opt.trace()); PARSEP->rootp()->addModulep($$); - } + SYMP->pushNew($$); } ; parameter_value_assignmentE: // IEEE: [ parameter_value_assignment ] @@ -1383,13 +1384,13 @@ stmtBlock: // IEEE: statement + seq_block + par_block seq_block: // ==IEEE: seq_block // // IEEE doesn't allow declarations in unnamed blocks, but several simulators do. // // So need begin's even if unnamed to scope variables down - seq_blockFront blockDeclStmtList yEND endLabelE { $$=$1; $1->addStmtp($2); } - | seq_blockFront /**/ yEND endLabelE { $$=$1; } + seq_blockFront blockDeclStmtList yEND endLabelE { $$=$1; $1->addStmtp($2); SYMP->popScope($1); } + | seq_blockFront /**/ yEND endLabelE { $$=$1; SYMP->popScope($1); } ; seq_blockFront: // IEEE: part of par_block - yBEGIN { $$ = new AstBegin($1,"",NULL); } - | yBEGIN ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($1,*$3,NULL); } + yBEGIN { $$ = new AstBegin($1,"",NULL); SYMP->pushNew($$); } + | yBEGIN ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($1,*$3,NULL); SYMP->pushNew($$); } ; blockDeclStmtList: // IEEE: { block_item_declaration } { statement or null } @@ -1719,16 +1720,16 @@ list_of_argumentsE: // IEEE: [list_of_arguments] task_declaration: // ==IEEE: task_declaration yTASK lifetimeE taskId tfGuts yENDTASK endLabelE - { $$ = $3; $$->addStmtsp($4); } + { $$ = $3; $$->addStmtsp($4); SYMP->popScope($$); } ; function_declaration: // IEEE: function_declaration + function_body_declaration yFUNCTION lifetimeE funcTypeE funcId tfGuts yENDFUNCTION endLabelE { $$ = $4; $$->addFvarp($3); $$->addStmtsp($5); if ($3) $$->isSigned($3->isSigned()); - } + SYMP->popScope($$); } | yFUNCTION lifetimeE funcTypeE funcId yVL_ISOLATE_ASSIGNMENTS tfGuts yENDFUNCTION endLabelE { $$ = $4; $$->addFvarp($3); $$->addStmtsp($6); $$->attrIsolateAssign(true); if ($3) $$->isSigned($3->isSigned()); - } + SYMP->popScope($$); } //UNSUP: Generic function return types ; @@ -1744,17 +1745,24 @@ lifetime: // ==IEEE: lifetime ; taskId: - id - { $$ = new AstTask($1, *$1, NULL); - } + tfIdScoped + { $$ = new AstTask($1, *$1, NULL); + SYMP->pushNewUnder($$, NULL); } ; funcId: // IEEE: function_data_type_or_implicit + part of function_body_declaration // // IEEE: function_data_type_or_implicit must be expanded here to prevent conflict // // function_data_type expanded here to prevent conflicts with implicit_type:empty vs data_type:ID - id - { $$ = new AstFunc ($1,*$1,NULL,NULL); - } + tfIdScoped + { $$ = new AstFunc ($1,*$1,NULL,NULL); + SYMP->pushNewUnder($$, NULL); } + //UNSUP id/*interface_identifier*/ '.' id { UNSUP } + //UNSUP class_scope_id { UNSUP } + ; + +tfIdScoped: // IEEE: part of function_body_declaration/task_body_declaration + // // IEEE: [ interface_identifier '.' | class_scope ] function_identifier + id { $$=$1; $$ = $1; } //UNSUP id/*interface_identifier*/ '.' id { UNSUP } //UNSUP class_scope_id { UNSUP } ;