⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vpreproc.cpp

📁 Verilog Parser in Perl
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// -*- C++ -*-//*************************************************************************//// Copyright 2000-2009 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 or the Perl Artistic License.//// This program 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.////*************************************************************************/// \file/// \brief Verilog::Preproc: Internal implementation of default preprocessor////// Authors: Wilson Snyder////// Code available from: http://www.veripool.org/verilog-perl/////*************************************************************************#include <cstdio>#include <fstream>#include <cstring>#include <stack>#include <vector>#include <map>#include <cassert>#include "VPreproc.h"#include "VPreprocLex.h"//#undef yyFlexLexer//#define yyFlexLexer xxFlexLexer//#include <FlexLexer.h>//*************************************************************************class VPreDefRef {    // One for each pending define substitution    string	m_name;		// Define last name being defined    string	m_params;	// Define parameter list for next expansion    string	m_nextarg;	// String being built for next argument    int		m_parenLevel;	// Parenthesis counting inside def args    vector<string> m_args;	// List of define argumentspublic:    string name() const { return m_name; }    string params() const { return m_params; }    string nextarg() const { return m_nextarg; }    void nextarg(const string& value) { m_nextarg = value; }    int parenLevel() const { return m_parenLevel; }    vector<string>& args() { return m_args; }    VPreDefRef(const string& name, const string& params, int pl)	: m_name(name), m_params(params), m_parenLevel(pl) {}    ~VPreDefRef() {}};//*************************************************************************/// Data for parsing on/offclass VPreIfEntry {    // One for each pending ifdef/ifndef    bool	m_on;		// Current parse for this ifdef level is "on"    bool	m_everOn;	// Some if term in elsif tree has been onpublic:    bool on() const { return m_on; }    bool everOn() const { return m_everOn; }    VPreIfEntry(bool on, bool everOn)	: m_on(on), m_everOn(everOn || on) {}  // Note everOn includes new state    ~VPreIfEntry() {}};//*************************************************************************/// Data for a preprocessor instantiation.struct VPreprocImp : public VPreprocOpaque {    VPreproc*	m_preprocp;	///< Object we're holding data for    VFileLine*	m_filelinep;	///< Last token's starting point    int		m_debug;	///< Debugging level    VPreprocLex* m_lexp;	///< Current lexer state (NULL = closed)    stack<VPreprocLex*> m_includeStack;	///< Stack of includers above current m_lexp    enum ProcState { ps_TOP, ps_DEFNAME, 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.    // For getRawToken/ `line insertion    string	m_lineCmt;	///< Line comment(s) to be returned    bool	m_lineCmtNl;	///< Newline needed before inserting lineCmt    int		m_lineAdd;	///< Empty lines to return to maintain line count    bool	m_rawAtBol;	///< Last rawToken left us at beginning of line    // For defines    stack<VPreDefRef> m_defRefs; // Pending definine substitution    stack<VPreIfEntry> m_ifdefStack;	///< Stack of true/false emitting evaluations    unsigned	m_defDepth;	///< How many `defines deep    // For getline()    string	m_lineChars;	///< Characters left for next line    VPreprocImp(VFileLine* filelinep) {	m_filelinep = filelinep;	m_debug = 0;	m_lexp = NULL;	 // Closed.	m_state = ps_TOP;	m_off = 0;	m_lineChars = "";	m_lastSym = "";	m_lineAdd = 0;	m_lineCmtNl = false;	m_rawAtBol = true;	m_defDepth = 0;    }    const char* tokenName(int tok);    int getRawToken();    int getToken();    void parseTop();    void parseUndef();    string getline();    bool isEof() const { return (m_lexp==NULL); }    void open(string filename, VFileLine* filelinep);    void insertUnreadback(const string& text) { m_lineCmt += text; }    void insertUnreadbackAtBol(const string& text);private:    void error(string msg) { m_filelinep->error(msg); }    void fatal(string msg) { m_filelinep->fatal(msg); }    int debug() const { return m_debug; }    void eof();    string defineSubst(VPreDefRef* refp);    void addLineComment(int enter_exit_level);    string trimWhitespace(const string& strg);    void parsingOn() { m_off--; assert(m_off>=0); if (!m_off) addLineComment(0); }    void parsingOff() { m_off++; }};//*************************************************************************// CreationVPreproc::VPreproc(VFileLine* filelinep) {    VPreprocImp* idatap = new VPreprocImp(filelinep);    m_opaquep = idatap;    idatap->m_preprocp = this;}//*************************************************************************// VPreproc Methods.  Just call the implementation functions.void VPreproc::comment(string cmt) { }void VPreproc::open(string filename, VFileLine* filelinep) {    VPreprocImp* idatap = static_cast<VPreprocImp*>(m_opaquep);    idatap->open (filename,filelinep);}string VPreproc::getline() {    VPreprocImp* idatap = static_cast<VPreprocImp*>(m_opaquep);    return idatap->getline();}void VPreproc::debug(int level) {    VPreprocImp* idatap = static_cast<VPreprocImp*>(m_opaquep);    idatap->m_debug = level;}bool VPreproc::isEof() {    VPreprocImp* idatap = static_cast<VPreprocImp*>(m_opaquep);    return idatap->isEof();}VFileLine* VPreproc::filelinep() {    VPreprocImp* idatap = static_cast<VPreprocImp*>(m_opaquep);    return idatap->m_filelinep;}void VPreproc::insertUnreadback(string text) {    VPreprocImp* idatap = static_cast<VPreprocImp*>(m_opaquep);    return idatap->insertUnreadback(text);}//*************************************************************************// CALLBACK METHODS// This probably will want to be overridden for given child users of this class.void VPreproc::include(string filename) {    open(filename, filelinep());}void VPreproc::undef(string define) {    cout<<"UNDEF "<<define<<endl;}bool VPreproc::defExists(string define) {    return defParams(define)!="";}string VPreproc::defParams(string define) {    return "";}void VPreproc::define(string define, string value, string params) {    error("Defines not implemented: "+define+"\n");}string VPreproc::defValue(string define) {    error("Define not defined: "+define+"\n");    return define;}//**********************************************************************// Parser Utilitiesconst char* VPreprocImp::tokenName(int tok) {    switch (tok) {    case VP_EOF		: return("EOF");    case VP_INCLUDE	: return("INCLUDE");    case VP_IFDEF	: return("IFDEF");    case VP_IFNDEF	: return("IFNDEF");    case VP_ENDIF	: return("ENDIF");    case VP_UNDEF	: return("UNDEF");    case VP_DEFINE	: return("DEFINE");    case VP_ELSE	: return("ELSE");    case VP_ELSIF	: return("ELSIF");    case VP_LINE	: return("LINE");    case VP_SYMBOL	: return("SYMBOL");    case VP_STRING	: return("STRING");    case VP_DEFVALUE	: return("DEFVALUE");    case VP_COMMENT	: return("COMMENT");    case VP_TEXT	: return("TEXT");    case VP_WHITE	: return("WHITE");    case VP_DEFREF	: return("DEFREF");    case VP_DEFARG	: return("DEFARG");    case VP_ERROR	: return("ERROR");    default: return("?");    }}string VPreprocImp::trimWhitespace(const string& strg) {    string out = strg;    while (out.length()>0 && isspace(out[0])) {	out.erase(0,1);    }    return out;}string VPreprocImp::defineSubst(VPreDefRef* refp) {    // Substitute out defines in a argumented define reference.    // We could push the define text back into the lexer, but that's slow    // and would make recursive definitions and parameter handling nasty.    //    // Note we parse the definition parameters and value here.  If a    // parametrized define is used many, many times, we could cache the    // parsed result.    if (debug()) {	cout<<"defineSubstIn  `"<<refp->name()<<" "<<refp->params()<<endl;	for (unsigned i=0; i<refp->args().size(); i++) {	    cout<<"defineArg["<<i<<"] = "<<refp->args()[i]<<endl;	}    }    // Grab value    string value = m_preprocp->defValue(refp->name());    if (debug()) cout<<"defineValue    '"<<value<<"'"<<endl;    map<string,string> argValueByName;    {   // Parse argument list into map	unsigned numArgs=0;	string argName;	for (const char* cp=refp->params().c_str(); *cp; cp++) {	    if (*cp=='(') {	    } else if (argName=="" && isspace(*cp)) {	    } else if (isspace(*cp) || *cp==')' || *cp==',') {		if (argName!="") {		    if (refp->args().size() > numArgs) {			// A call `def( a ) must be equivelent to `def(a ), so trimWhitespace			// Note other sims don't trim trailing whitespace, so we don't either.			argValueByName[argName] = trimWhitespace(refp->args()[numArgs]);		    }		    numArgs++;		    //cout << "  arg "<<argName<<endl;		}		argName = "";	    } else if ( isalpha(*cp) || *cp=='_'			|| (argName!="" && (isdigit(*cp) || *cp=='$'))) {		argName += *cp;	    }	}	if (refp->args().size() != numArgs) {	    error("Define passed wrong number of arguments: "+refp->name()+"\n");	    return " `"+refp->name()+" ";	}    }    string out = "";    {   // Parse substitution define using arguments	string argName;	string prev;	bool quote = false;	// Note we go through the loop once more at the NULL end-of-string	for (const char* cp=value.c_str(); (*cp) || argName!=""; cp=(*cp?cp+1:cp)) {	    //cout << "CH "<<*cp<<"  an "<<argName<<"\n";	    if (!quote) {		if ( isalpha(*cp) || *cp=='_'		     || (argName!="" && (isdigit(*cp) || *cp=='$'))) {		    argName += *cp;		    continue;		}	    }	    if (argName != "") {		// Found a possible variable substitution		map<string,string>::iterator iter = argValueByName.find(argName);		if (iter != argValueByName.end()) {		    // Substitute		    string subst = iter->second;		    out += subst;		} else {		    out += argName;		}		argName = "";	    }	    if (!quote) {		// Check for `` only after we've detected end-of-argname		if (cp[0]=='`' && cp[1]=='`') {		    //out += "";   // `` means to suppress the ``		    cp++;		    continue;		}		else if (cp[0]=='`' && cp[1]=='"') {		    out += '"';   // `" means to put out a " without enabling quote mode (sort of)		    cp++;		    continue;		}		else if (cp[0]=='`' && cp[1]=='\\') {		    out += '\\';   // `\ means to put out a backslash		    cp++;		    continue;		}	    }	    if (cp[0]=='\\' && cp[1]) {		out += cp[0]; // \{any} Put out literal next character		out += cp[1];		cp++;		continue;	    }	    if (*cp=='"') quote=!quote;	    if (*cp) out += *cp;	}    }    if (debug()) cout<<"defineSubstOut '"<<out<<"'"<<endl;    return out;}//**********************************************************************// Parser routinesvoid VPreprocImp::open(string filename, VFileLine* filelinep) {    // Open a new file, possibly overriding the current one which is active.    if (filelinep) {	m_filelinep = filelinep;    }    FILE* fp = fopen (filename.c_str(), "r");    if (!fp) {	error("File not found: "+filename+"\n");	return;    }    if (m_lexp) {	// We allow the same include file twice, because occasionally it pops	// up, with guards preventing a real recursion.	if (m_includeStack.size()>VPreproc::INCLUDE_DEPTH_MAX) {	    error("Recursive inclusion of file: "+filename);	    return;	}	// There's already a file active.  Push it to work on the new one.	m_includeStack.push(m_lexp);	addLineComment(0);    }    m_lexp = new VPreprocLex (fp);    m_lexp->m_keepComments = m_preprocp->keepComments();    m_lexp->m_keepWhitespace = m_preprocp->keepWhitespace();    m_lexp->m_pedantic = m_preprocp->pedantic();    m_lexp->m_curFilelinep = m_preprocp->filelinep()->create(filename, 1);    m_filelinep = m_lexp->m_curFilelinep;  // Remember token start location    addLineComment(1); // Enter    yy_switch_to_buffer(m_lexp->m_yyState);}void VPreprocImp::insertUnreadbackAtBol(const string& text) {    // Insert insuring we're at the beginning of line, for `line    // We don't always add a leading newline, as it may result in extra unreadback(newlines).    if (m_lineCmt == "") { m_lineCmtNl = true; }    else if (m_lineCmt[m_lineCmt.length()-1]!='\n') {	insertUnreadback("\n");    }    insertUnreadback(text);}void VPreprocImp::addLineComment(int enter_exit_level) {    if (m_preprocp->lineDirectives()) {	char numbuf[20]; sprintf(numbuf, "%d", m_lexp->m_curFilelinep->lineno());	char levelbuf[20]; sprintf(levelbuf, "%d", enter_exit_level);	string cmt = ((string)"`line "+numbuf		      +" \""+m_lexp->m_curFilelinep->filename()+"\" "		      +levelbuf+"\n");	insertUnreadbackAtBol(cmt);    }}void VPreprocImp::eof() {    // Remove current lexer    if (debug()) cout<<m_filelinep<<"EOF!\n";    addLineComment(2);	// Exit    delete m_lexp;  m_lexp=NULL;    // Perhaps there's a parent file including us?    if (!m_includeStack.empty()) {	// Back to parent.	m_lexp = m_includeStack.top(); m_includeStack.pop();	addLineComment(0);	yy_switch_to_buffer(m_lexp->m_yyState);    }}int VPreprocImp::getRawToken() {    // Get a token from the file, whatever it may be.    while (1) {      next_tok:	if (m_lineAdd) {	    m_lineAdd--;	    m_rawAtBol = true;	    yytext=(char*)"\n"; yyleng=1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -