// -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* // DESCRIPTION: Verilator: Common header between parser and lex // // Code available from: https://verilator.org // //************************************************************************* // // Copyright 2009-2020 by Wilson Snyder. This program is free software; you // can 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. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // //************************************************************************* #ifndef _V3PARSEIMP_H_ #define _V3PARSEIMP_H_ 1 #include "config_build.h" #include "verilatedos.h" #include "V3Error.h" #include "V3FileLine.h" #include "V3Global.h" #include "V3Parse.h" #include "V3ParseSym.h" #include 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) typedef enum { uniq_NONE, uniq_UNIQUE, uniq_UNIQUE0, uniq_PRIORITY } V3UniqState; typedef enum { iprop_NONE, iprop_CONTEXT, iprop_PURE } V3ImportProperty; //============================================================================ // Parser YYSType, e.g. for parser's yylval // We can't use bison's %union as we want to pass the fileline with all tokens struct V3ParseBisonYYSType { FileLine* fl; AstNode* scp; // Symbol table scope for future lookups int token; // Read token, aka tok union { V3Number* nump; string* strp; int cint; double cdouble; bool cbool; V3UniqState uniqstate; V3ImportProperty iprop; VSigning::en signstate; V3ErrorCode::en errcodeen; AstAttrType::en attrtypeen; VLifetime::en lifetime; AstNode* nodep; AstBasicDType* bdtypep; AstBegin* beginp; AstCase* casep; AstCaseItem* caseitemp; AstCell* cellp; AstClass* classp; AstConst* constp; AstFork* forkp; AstMemberDType* memberp; AstNodeModule* modulep; AstNodeUOrStructDType* uorstructp; AstNodeDType* dtypep; AstNodeFTask* ftaskp; AstNodeFTaskRef* ftaskrefp; AstNodeRange* rangep; AstNodeSenItem* senitemp; AstNodeVarRef* varnodep; AstPackage* packagep; AstPackageRef* packagerefp; AstParseRef* parserefp; AstPatMember* patmemberp; AstPattern* patternp; AstPin* pinp; AstRefDType* refdtypep; AstSenTree* sentreep; AstVar* varp; AstVarRef* varrefp; }; }; #define YYSTYPE V3ParseBisonYYSType //###################################################################### class V3ParseImp { // MEMBERS AstNetlist* m_rootp; // Root of the design VInFilter* m_filterp; // Reading filter V3ParseSym* m_symp; // Symbol table V3Lexer* m_lexerp; // Current FlexLexer static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based FileLine* m_fileline; // Filename/linenumber currently active 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 VOptionBool m_unconnectedDrive; // Last unconnected drive int m_prevLexToken; // previous parsed token (for lexer) bool m_ahead; // aheadval is valid V3ParseBisonYYSType m_aheadVal; // ahead token value V3ParseBisonYYSType m_bisonValCur; // current token for error reporting V3ParseBisonYYSType m_bisonValPrev; // previous token for error reporting std::deque m_stringps; // Created strings for later cleanup std::deque m_numberps; // Created numbers for later cleanup std::deque m_lintState; // Current lint state for save/restore std::deque m_ppBuffers; // Preprocessor->lex buffer of characters to process string m_tag; // Contents (if any) of current verilator tag AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set. VTimescale m_timeLastUnit; // Last `timescale's unit 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 optFuture(const string& flag) { return v3Global.opt.isFuture(flag); } void ppline(const char* textp); void linenoInc() { fileline()->linenoInc(); } void verilatorCmtLint(FileLine* fl, const char* textp, bool warnOff); void verilatorCmtLintSave(); void verilatorCmtLintRestore(FileLine* fl); void verilatorCmtBad(FileLine* fl, const char* textp); void errorPreprocDirective(const char* textp); void tag(const char* text); void tagNodep(AstNode* nodep) { m_tagNodep = nodep; } AstNode* tagNodep() const { return m_tagNodep; } void timescalePreproc(FileLine* fl, const char* textp); void timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, double unitVal, bool precSet, double precVal); VTimescale timeLastUnit() const { return m_timeLastUnit; } static double parseTimenum(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() const { return m_lastVerilogState; } static const char* tokenName(int tok); void ppPushText(const string& text) { m_ppBuffers.push_back(text); if (fileline()->contentp()) fileline()->contentp()->pushText(text); } size_t ppInputToLex(char* buf, size_t max_size); 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; } string* newString(const char* text, size_t length) { string* strp = new string(text, length); m_stringps.push_back(strp); return strp; } V3Number* newNumber(FileLine* fl, const char* text) { V3Number* nump = new V3Number(V3Number::FileLined(), 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() const { return m_fileline; } AstNetlist* rootp() const { return m_rootp; } FileLine* copyOrSameFileLine() { return fileline()->copyOrSameFileLine(); } bool inCellDefine() const { return m_inCellDefine; } void inCellDefine(bool flag) { m_inCellDefine = flag; } bool inLibrary() const { return m_inLibrary; } VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } // Interactions with parser int bisonParse(); // Interactions with lexer void lexNew(); void lexDestroy(); static int stateVerilogRecent(); // Parser -> lexer communication int prevLexToken() const { return m_prevLexToken; } // Parser -> lexer communication size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf, max_size); } V3ParseBisonYYSType bisonValCur() const { return m_bisonValCur; } V3ParseBisonYYSType bisonValPrev() const { return m_bisonValPrev; } bool bisonValIdThenColon() const; //==== Symbol tables V3ParseSym* symp() { return m_symp; } public: // CONSTRUCTORS V3ParseImp(AstNetlist* rootp, VInFilter* filterp, V3ParseSym* parserSymp) : m_rootp(rootp) , m_filterp(filterp) , m_symp(parserSymp) { m_fileline = NULL; m_lexerp = NULL; m_inCellDefine = false; m_inLibrary = false; m_inBeginKwd = 0; m_lastVerilogState = stateVerilogRecent(); m_prevLexToken = 0; m_ahead = false; m_bisonValCur.token = 0; m_bisonValPrev.token = 0; // m_aheadVal not used as m_ahead = false, and not all compilers support initing it m_tagNodep = NULL; m_timeLastUnit = v3Global.opt.timeDefaultUnit(); } ~V3ParseImp(); void parserClear(); void unputString(const char* textp, size_t length); // 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, const string& errmsg); private: void lexFile(const string& modname); int yylexReadTok(); void lexToken(); // Internal; called from lexToBison void preprocDumps(std::ostream& os); }; #endif // Guard