2009-10-31 14:08:38 +00:00
|
|
|
|
// -*- C++ -*-
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Common header between parser and lex
|
|
|
|
|
//
|
|
|
|
|
// Code available from: http://www.veripool.org/verilator
|
|
|
|
|
//
|
|
|
|
|
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2011-01-01 23:21:19 +00:00
|
|
|
|
// Copyright 2009-2011 by Wilson Snyder. This program is free software; you can
|
2009-10-31 14:08:38 +00:00
|
|
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
|
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
|
|
|
|
//
|
|
|
|
|
// Verilator is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#ifndef _V3PARSEIMP_H_
|
|
|
|
|
#define _V3PARSEIMP_H_ 1
|
|
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
#include "V3Error.h"
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3Parse.h"
|
|
|
|
|
#include "V3SymTable.h"
|
|
|
|
|
#include <deque>
|
|
|
|
|
|
|
|
|
|
class V3Lexer;
|
|
|
|
|
|
|
|
|
|
// IMPORTANT: Don't include this file other than in the bison and flex,
|
|
|
|
|
// as it's definitions will confuse other parsers
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
// Types (between parser & lexer)
|
|
|
|
|
|
2010-12-26 02:58:28 +00:00
|
|
|
|
typedef enum { uniq_NONE, uniq_UNIQUE, uniq_UNIQUE0, uniq_PRIORITY } V3UniqState;
|
2009-10-31 14:08:38 +00:00
|
|
|
|
|
2009-12-03 11:55:29 +00:00
|
|
|
|
typedef enum { iprop_NONE, iprop_CONTEXT, iprop_PURE } V3ImportProperty;
|
|
|
|
|
|
2009-10-31 14:08:38 +00:00
|
|
|
|
//============================================================================
|
|
|
|
|
// We can't use bison's %union as we want to pass the fileline with all tokens
|
|
|
|
|
|
|
|
|
|
struct V3ParseBisonYYSType {
|
|
|
|
|
FileLine* fl;
|
2009-11-08 02:05:02 +00:00
|
|
|
|
AstNode* scp; // Symbol table scope for future lookups
|
2009-10-31 14:08:38 +00:00
|
|
|
|
union {
|
|
|
|
|
V3Number* nump;
|
|
|
|
|
string* strp;
|
|
|
|
|
int cint;
|
|
|
|
|
double cdouble;
|
|
|
|
|
V3UniqState uniqstate;
|
2009-11-02 13:06:04 +00:00
|
|
|
|
AstSignedState signstate;
|
2009-12-03 11:55:29 +00:00
|
|
|
|
V3ImportProperty iprop;
|
2010-01-21 11:11:30 +00:00
|
|
|
|
V3ErrorCode::en errcodeen;
|
2009-10-31 14:08:38 +00:00
|
|
|
|
|
|
|
|
|
AstNode* nodep;
|
|
|
|
|
|
2009-11-02 13:06:04 +00:00
|
|
|
|
AstBasicDType* bdtypep;
|
2009-10-31 14:08:38 +00:00
|
|
|
|
AstBegin* beginp;
|
|
|
|
|
AstCase* casep;
|
|
|
|
|
AstCaseItem* caseitemp;
|
|
|
|
|
AstConst* constp;
|
2009-11-07 11:20:20 +00:00
|
|
|
|
AstNodeModule* modulep;
|
2009-11-05 14:57:23 +00:00
|
|
|
|
AstNodeDType* dtypep;
|
2009-11-03 03:50:31 +00:00
|
|
|
|
AstNodeFTask* ftaskp;
|
2009-11-08 02:05:02 +00:00
|
|
|
|
AstNodeFTaskRef* ftaskrefp;
|
2009-11-03 03:50:31 +00:00
|
|
|
|
AstNodeSenItem* senitemp;
|
2009-10-31 14:08:38 +00:00
|
|
|
|
AstNodeVarRef* varnodep;
|
2009-11-08 02:05:02 +00:00
|
|
|
|
AstPackage* packagep;
|
2009-10-31 14:08:38 +00:00
|
|
|
|
AstParseRef* parserefp;
|
|
|
|
|
AstPin* pinp;
|
|
|
|
|
AstRange* rangep;
|
|
|
|
|
AstSenTree* sentreep;
|
|
|
|
|
AstVar* varp;
|
2010-01-08 03:08:48 +00:00
|
|
|
|
AstVarRef* varrefp;
|
2009-10-31 14:08:38 +00:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define YYSTYPE V3ParseBisonYYSType
|
|
|
|
|
|
2009-10-31 14:14:04 +00:00
|
|
|
|
//######################################################################
|
|
|
|
|
// Symbol table for parsing
|
|
|
|
|
|
|
|
|
|
class V3ParseSym {
|
|
|
|
|
// TYPES
|
|
|
|
|
typedef vector<V3SymTable*> SymStack;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// MEMBERS
|
|
|
|
|
static int s_anonNum; // Number of next anonymous object
|
|
|
|
|
V3SymTable* m_symTableNextId; // Symbol table for next lexer lookup
|
2009-11-08 02:05:02 +00:00
|
|
|
|
V3SymTable* m_symCurrentp; // Active symbol table for additions/lookups
|
|
|
|
|
V3SymTable* m_symRootp; // Root symbol table
|
2009-10-31 14:14:04 +00:00
|
|
|
|
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; }
|
2009-11-08 02:05:02 +00:00
|
|
|
|
V3SymTable* symRootp() const { return m_symRootp; }
|
2009-10-31 14:14:04 +00:00
|
|
|
|
|
|
|
|
|
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) {
|
2009-11-08 02:05:02 +00:00
|
|
|
|
if (entp) {
|
|
|
|
|
UINFO(9,"symTableNextId under "<<entp<<"-"<<entp->type().ascii()<<endl);
|
|
|
|
|
m_symTableNextId = getTable(entp);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
UINFO(9,"symTableNextId under NULL"<<endl);
|
|
|
|
|
m_symTableNextId = NULL;
|
|
|
|
|
}
|
2009-10-31 14:14:04 +00:00
|
|
|
|
}
|
|
|
|
|
void reinsert(AstNode* nodep, V3SymTable* parentp=NULL) {
|
2009-12-04 12:05:44 +00:00
|
|
|
|
reinsert(nodep, parentp, nodep->name());
|
|
|
|
|
}
|
|
|
|
|
void reinsert(AstNode* nodep, V3SymTable* parentp, string name) {
|
2009-10-31 14:14:04 +00:00
|
|
|
|
if (!parentp) parentp = symCurrentp();
|
|
|
|
|
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 "<<symCurrentp()->ownerp()->prettyTypeName()
|
|
|
|
|
<<" but parser thinks ending "<<nodep->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"<<symp->ownerp()<<endl);
|
|
|
|
|
}
|
|
|
|
|
UINFO(1,"ParseSym Current: "<<symCurrentp()->ownerp()<<endl);
|
|
|
|
|
}
|
|
|
|
|
void dump(ostream& os, const string& indent="") {
|
|
|
|
|
os<<"ParseSym Dump:\n";
|
|
|
|
|
m_sympStack[0]->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);
|
|
|
|
|
}
|
2009-11-10 00:07:59 +00:00
|
|
|
|
void import(AstNode* packagep, const string& id_or_star) {
|
2009-10-31 14:14:04 +00:00
|
|
|
|
// Import from package::id_or_star to this
|
2009-11-10 00:07:59 +00:00
|
|
|
|
V3SymTable* symp = getTable(packagep);
|
|
|
|
|
if (!symp) { // Internal problem, because we earlier found pkg to label it an ID__aPACKAGE
|
|
|
|
|
packagep->v3fatalSrc("Import package not found");
|
2009-10-31 14:14:04 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Walk old sym table and reinsert into current table
|
2009-11-10 00:07:59 +00:00
|
|
|
|
// We let V3Link report the error instead of us
|
|
|
|
|
symCurrentp()->import(symp, id_or_star);
|
2009-10-31 14:14:04 +00:00
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
// CREATORS
|
|
|
|
|
V3ParseSym(AstNetlist* rootp) {
|
|
|
|
|
s_anonNum = 0; // Number of next anonymous object
|
|
|
|
|
pushScope(findNewTable(rootp, NULL));
|
2009-11-07 04:16:06 +00:00
|
|
|
|
m_symTableNextId = NULL;
|
|
|
|
|
m_symCurrentp = symCurrentp();
|
2009-11-08 02:05:02 +00:00
|
|
|
|
m_symRootp = symCurrentp();
|
2009-10-31 14:14:04 +00:00
|
|
|
|
}
|
|
|
|
|
~V3ParseSym() {
|
|
|
|
|
for (SymStack::iterator it = m_symsp.begin(); it != m_symsp.end(); ++it) {
|
|
|
|
|
delete (*it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2009-10-31 14:08:38 +00:00
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class V3ParseImp {
|
|
|
|
|
// MEMBERS
|
2010-01-20 12:15:51 +00:00
|
|
|
|
AstNetlist* m_rootp; // Root of the design
|
|
|
|
|
V3InFilter* m_filterp; // Reading filter
|
|
|
|
|
V3Lexer* m_lexerp; // Current FlexLexer
|
2009-10-31 14:08:38 +00:00
|
|
|
|
static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based
|
2010-01-20 12:15:51 +00:00
|
|
|
|
FileLine* m_fileline; // Filename/linenumber currently active
|
2009-10-31 14:08:38 +00:00
|
|
|
|
|
2009-10-31 14:14:04 +00:00
|
|
|
|
V3ParseSym m_sym; // Symbol table
|
2009-10-31 14:08:38 +00:00
|
|
|
|
bool m_inCellDefine; // Inside a `celldefine
|
|
|
|
|
bool m_inLibrary; // Currently reading a library vs. regular file
|
|
|
|
|
int m_inBeginKwd; // Inside a `begin_keywords
|
|
|
|
|
int m_lastVerilogState; // Last LEX state in `begin_keywords
|
|
|
|
|
|
2010-01-23 00:08:20 +00:00
|
|
|
|
bool m_ahead; // aheadToken is valid
|
|
|
|
|
int m_aheadToken; // Token we read ahead
|
|
|
|
|
V3ParseBisonYYSType m_aheadVal; // aheadToken's value
|
|
|
|
|
|
2009-10-31 14:08:38 +00:00
|
|
|
|
deque<string*> m_stringps; // Created strings for later cleanup
|
|
|
|
|
deque<V3Number*> m_numberps; // Created numbers for later cleanup
|
|
|
|
|
deque<FileLine> m_lintState; // Current lint state for save/restore
|
|
|
|
|
deque<string> m_ppBuffers; // Preprocessor->lex buffer of characters to process
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// Note these are an exception to using the filename as the debug type
|
|
|
|
|
static int debugBison() {
|
|
|
|
|
static int level = -1;
|
|
|
|
|
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel("bison");
|
|
|
|
|
return level;
|
|
|
|
|
}
|
|
|
|
|
static int debugFlex() {
|
|
|
|
|
static int level = -1;
|
|
|
|
|
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel("flex");
|
|
|
|
|
return level;
|
|
|
|
|
}
|
|
|
|
|
static int debug() { return debugBison() ? debugFlex() : 0; }
|
|
|
|
|
|
|
|
|
|
// Functions called by lex rules:
|
|
|
|
|
int yylexThis();
|
|
|
|
|
static bool optPsl() { return v3Global.opt.psl(); }
|
|
|
|
|
static bool optFuture(const string& flag) { return v3Global.opt.isFuture(flag); }
|
|
|
|
|
|
|
|
|
|
void ppline (const char* text);
|
2010-07-09 00:31:41 +00:00
|
|
|
|
void linenoInc() { fileline()->linenoInc(); }
|
2009-10-31 14:08:38 +00:00
|
|
|
|
void verilatorCmtLint(const char* text, bool on);
|
|
|
|
|
void verilatorCmtLintSave();
|
|
|
|
|
void verilatorCmtLintRestore();
|
|
|
|
|
void verilatorCmtBad(const char* text);
|
|
|
|
|
void pushBeginKeywords(int state) { m_inBeginKwd++; m_lastVerilogState=state; }
|
|
|
|
|
bool popBeginKeywords() { if (m_inBeginKwd) { m_inBeginKwd--; return true; } else return false; }
|
|
|
|
|
int lastVerilogState() { return m_lastVerilogState; }
|
|
|
|
|
static const char* tokenName(int tok);
|
|
|
|
|
|
|
|
|
|
void ppPushText(const string& text) { m_ppBuffers.push_back(text); }
|
2010-04-07 00:20:44 +00:00
|
|
|
|
size_t ppInputToLex(char* buf, size_t max_size);
|
2009-10-31 14:08:38 +00:00
|
|
|
|
|
|
|
|
|
static V3ParseImp* parsep() { return s_parsep; }
|
|
|
|
|
|
|
|
|
|
// TODO: Many of these functions are the old interface; they'd be better as non-static
|
|
|
|
|
// and called as READP->newString(...) etc.
|
|
|
|
|
string* newString(const string& text) {
|
|
|
|
|
// Allocate a string, remembering it so we can reclaim storage at lex end
|
|
|
|
|
string* strp = new string (text);
|
|
|
|
|
m_stringps.push_back(strp);
|
|
|
|
|
return strp;
|
|
|
|
|
}
|
|
|
|
|
string* newString(const char* text) {
|
|
|
|
|
// Allocate a string, remembering it so we can reclaim storage at lex end
|
|
|
|
|
string* strp = new string (text);
|
|
|
|
|
m_stringps.push_back(strp);
|
|
|
|
|
return strp;
|
|
|
|
|
}
|
2010-04-07 00:20:44 +00:00
|
|
|
|
string* newString(const char* text, size_t length) {
|
2009-10-31 14:08:38 +00:00
|
|
|
|
string* strp = new string (text, length);
|
|
|
|
|
m_stringps.push_back(strp);
|
|
|
|
|
return strp;
|
|
|
|
|
}
|
|
|
|
|
V3Number* newNumber(FileLine* fl, const char* text) {
|
|
|
|
|
V3Number* nump = new V3Number (fl, text);
|
|
|
|
|
m_numberps.push_back(nump);
|
|
|
|
|
return nump;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return next token, for bison, since bison isn't class based, use a global THIS
|
|
|
|
|
FileLine* fileline() { return m_fileline; }
|
|
|
|
|
AstNetlist* rootp() { return m_rootp; }
|
|
|
|
|
FileLine* copyOrSameFileLine() { return fileline()->copyOrSameFileLine(); }
|
|
|
|
|
bool inCellDefine() { return m_inCellDefine; }
|
|
|
|
|
void inCellDefine(bool flag) { m_inCellDefine = flag; }
|
|
|
|
|
bool inLibrary() { return m_inLibrary; }
|
|
|
|
|
|
|
|
|
|
// Interactions with parser
|
|
|
|
|
int bisonParse();
|
|
|
|
|
|
|
|
|
|
// Interactions with lexer
|
|
|
|
|
void lexNew(int debug);
|
|
|
|
|
void lexDestroy();
|
|
|
|
|
void stateExitPsl(); // Parser -> lexer communication
|
|
|
|
|
void statePushVlg(); // Parser -> lexer communication
|
|
|
|
|
void statePop(); // Parser -> lexer communication
|
|
|
|
|
int stateVerilogRecent(); // Parser -> lexer communication
|
2010-04-07 00:20:44 +00:00
|
|
|
|
size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf,max_size); }
|
2009-10-31 14:08:38 +00:00
|
|
|
|
|
2009-10-31 14:14:04 +00:00
|
|
|
|
//==== Symbol tables
|
|
|
|
|
V3ParseSym* symp() { return &m_sym; }
|
|
|
|
|
|
2009-10-31 14:08:38 +00:00
|
|
|
|
public:
|
|
|
|
|
// CREATORS
|
2010-01-20 12:15:51 +00:00
|
|
|
|
V3ParseImp(AstNetlist* rootp, V3InFilter* filterp)
|
|
|
|
|
: m_sym(rootp), m_filterp(filterp) {
|
2009-10-31 14:08:38 +00:00
|
|
|
|
m_rootp = rootp; m_lexerp = NULL;
|
|
|
|
|
m_inCellDefine = false;
|
|
|
|
|
m_inLibrary = false;
|
|
|
|
|
m_inBeginKwd = 0;
|
|
|
|
|
m_lastVerilogState = stateVerilogRecent();
|
2010-01-23 00:08:20 +00:00
|
|
|
|
m_ahead = false;
|
|
|
|
|
m_aheadToken = 0;
|
2009-10-31 14:08:38 +00:00
|
|
|
|
}
|
|
|
|
|
~V3ParseImp();
|
|
|
|
|
void parserClear();
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
// Preprocess and read the Verilog file specified into the netlist database
|
|
|
|
|
int lexToBison(); // Pass token to bison
|
|
|
|
|
|
|
|
|
|
void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void lexFile(const string& modname);
|
|
|
|
|
int lexToken(); // Internal; called from lexToBison
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif // Guard
|