/************************************************************************** * DESCRIPTION: Verilator: Flex verilog preprocessor * * Code available from: http://www.veripool.org/verilator * ************************************************************************** * * Copyright 2003-2010 by Wilson Snyder. This program is free software; you can * redistribute it and/or modify it under the terms of either the GNU * General Public License or the Perl Artistic License. * * 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. * ************************************************************************** * Do not use Flex in C++ mode. It has bugs with yyunput() which result in * lost characters. **************************************************************************/ %option noyywrap align interactive %option stack %option noc++ %option prefix="V3PreLex" %{ #include "V3PreProc.h" #include "V3PreLex.h" V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point #define LEXP V3PreLex::s_currentLexp // Prevent conflicts from perl version static void linenoInc() {LEXP->incLineno();} static bool optPsl() { return V3PreProc::optPsl(); } static bool pedantic() { return LEXP->m_pedantic; } static void yyerror(char* msg) { LEXP->m_curFilelinep->v3error(msg); } static void yyerrorf(const char* msg) { LEXP->m_curFilelinep->v3error(msg); } static void appendDefValue(const char* t,int l) { LEXP->appendDefValue(t,l); } static int pslParenLevel() { return LEXP->m_pslParenLevel; } static void pslParenLevelInc() { LEXP->m_pslParenLevel++; } static void pslParenLevelDec() { if (pslParenLevel()) LEXP->m_pslParenLevel--; } static bool pslMoreNeeded() { return LEXP->m_pslMoreNeeded; } static void pslMoreNeeded(bool flag) { LEXP->m_pslMoreNeeded = flag; } /**********************************************************************/ %} %x PSLONEM %x PSLONEE %x PSLMULM %x PSLMUL1 %x CMTONEM %x CMTBEGM %x CMTMODE %x STRMODE %x DEFFPAR %x DEFFORM %x DEFVAL %x ARGMODE %x INCMODE %x PRTMODE /* drop: Drop Ctrl-Z - can't pass thru or may EOF the output too soon */ ws [ \t\f\r] wsn [ \t\f] crnl [\r]*[\n] quote [\"] backslash [\\] symb ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+) drop [\032] psl [p]sl /**************************************************************/ %% ^{ws}*"`line"{ws}+.*{crnl} { LEXP->lineDirective(yytext); return(VP_LINE); } /* Special directives we recognize */ "`define" { return(VP_DEFINE); } "`else" { return(VP_ELSE); } "`elsif" { return(VP_ELSIF); } "`endif" { return(VP_ENDIF); } "`ifdef" { return(VP_IFDEF); } "`ifndef" { return(VP_IFNDEF); } "`include" { return(VP_INCLUDE); } "`undef" { return(VP_UNDEF); } "`undefineall" { return(VP_UNDEFINEALL); } /* Optional directives we recognize */ "`__FILE__" { static string rtnfile; rtnfile = '"'; rtnfile += LEXP->m_curFilelinep->cfilename(); rtnfile += '"'; yytext=(char*)rtnfile.c_str(); yyleng = rtnfile.length(); return (VP_STRING); } "`__LINE__" { static char buf[10]; sprintf(buf, "%d",LEXP->m_curFilelinep->lineno()); yytext = buf; yyleng = strlen(yytext); return (VP_TEXT); } "`error" { if (!pedantic()) return (VP_ERROR); else return(VP_DEFREF); } /* Pass-through strings */ {quote} { yy_push_state(STRMODE); yymore(); } <> { linenoInc(); yyerrorf("EOF in unterminated string"); yyleng=0; yyterminate(); } {crnl} { linenoInc(); yyerrorf("Unterminated string"); BEGIN(INITIAL); } [^\"\\] { yymore(); } {backslash}{crnl} { linenoInc(); yymore(); } {backslash}. { yymore(); } {quote} { yy_pop_state(); if (LEXP->m_parenLevel || LEXP->m_formalLevel) { appendDefValue(yytext,yyleng); yyleng=0; } else return (VP_STRING); } /* Protected blocks */ "`protected" { yy_push_state(PRTMODE); yymore(); } <> { linenoInc(); yyerrorf("EOF in `protected"); yyleng=0; yyterminate(); } {crnl} { linenoInc(); yymore(); } . { yymore(); } "`endprotected" { yy_pop_state(); return (VP_TEXT); } /* Pass-through include <> filenames */ <> { linenoInc(); yyerrorf("EOF in unterminated include filename"); yyleng=0; yyterminate(); } {crnl} { linenoInc(); yyerrorf("Unterminated include filename"); BEGIN(INITIAL); } [^\>\\] { yymore(); } {backslash}. { yymore(); } [\>] { yy_pop_state(); return (VP_STRING); } /* Reading definition formal parenthesis (or not) to begin formal arguments */ /* Note '(' must IMMEDIATELY follow definition name */ [(] { appendDefValue("(",1); LEXP->m_formalLevel=1; BEGIN(DEFFORM); } {crnl} { yy_pop_state(); unput('\n'); yyleng=0; return VP_DEFFORM; } /* DEFVAL will later grab the return */ <> { yy_pop_state(); return VP_DEFFORM; } /* empty formals */ . { yy_pop_state(); unput(yytext[yyleng-1]); yyleng=0; return VP_DEFFORM; } /* empty formals */ /* Reading definition formals */ [(] { appendDefValue(yytext,yyleng); yyleng=0; ++LEXP->m_formalLevel; } [)] { appendDefValue(yytext,yyleng); yyleng=0; if ((--LEXP->m_formalLevel)==0) { yy_pop_state(); return VP_DEFFORM; } } "/*" { yy_push_state(CMTMODE); yymore(); } "//"[^\n\r]* { return (VP_COMMENT);} {drop} { } <> { linenoInc(); yy_pop_state(); yyerrorf("Unterminated ( in define formal arguments."); yyleng=0; return VP_DEFFORM; } {crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */ [\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */ {quote} { yy_push_state(STRMODE); yymore(); } [{\[] { LEXP->m_formalLevel++; appendDefValue(yytext,yyleng); } [}\]] { LEXP->m_formalLevel--; appendDefValue(yytext,yyleng); } [^\/\*\n\r\\(){}\[\]\"]+ | [\\][^\n\r] | . { appendDefValue(yytext,yyleng); } /* Reading definition value */ "/*" { yy_push_state(CMTMODE); yymore(); } "//"[^\n\r]* { return (VP_COMMENT);} {drop} { } <> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */ {crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } [\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */ [^\/\*\n\r\\]+ | [\\][^\n\r] | . { appendDefValue(yytext,yyleng); } /* Define arguments */ "/*" { yy_push_state(CMTMODE); yymore(); } "//"[^\n\r]* { return (VP_COMMENT);} {drop} { } <> { yyerrorf("EOF in define argument list\n"); yyleng = 0; yyterminate(); } {crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); } {quote} { yy_push_state(STRMODE); yymore(); } [{\[] { LEXP->m_parenLevel++; appendDefValue(yytext,yyleng); } [}\]] { LEXP->m_parenLevel--; appendDefValue(yytext,yyleng); } [(] { LEXP->m_parenLevel++; // Note paren level 0 means before "(" of starting args // Level 1 means "," between arguments // Level 2+ means one argument's internal () if (LEXP->m_parenLevel>1) { appendDefValue(yytext,yyleng); } else { return (VP_TEXT); }} [)] { LEXP->m_parenLevel--; if (LEXP->m_parenLevel>0) { appendDefValue(yytext,yyleng); } else { yy_pop_state(); return (VP_DEFARG); }} [,] { if (LEXP->m_parenLevel>1) { appendDefValue(yytext,yyleng); } else { yy_pop_state(); return (VP_DEFARG); }} "`"{symb} { return (VP_DEFREF); } /* defref in defref */ [^\/\*\n\r\\(,){}\[\]\"`]+ | . { appendDefValue(yytext,yyleng); } /* One line comments. */ "//"{ws}*{psl} { if (optPsl()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); } else { yy_push_state(CMTONEM); yymore(); } } "//"{ws}*{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return (VP_WHITE); } "//" { if (pslMoreNeeded()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); } else { yy_push_state(CMTONEM); yymore(); } } [^\n\r]* { yy_pop_state(); return (VP_COMMENT); } /* Psl oneline comments */ [{(] { pslParenLevelInc(); return (VP_TEXT); } [})] { pslParenLevelDec(); return (VP_TEXT); } [;] { if (!pslParenLevel()) {BEGIN PSLONEE; pslMoreNeeded(false);} return (VP_TEXT); } {crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); } /* Completed psl oneline comments */ {crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); } {ws}+ { yymore(); } . { yyerrorf("Unexpected text following psl assertion\n"); } /* C-style comments. */ /* We distinguish between the start of a comment, and later, so we may find a "psl" prefix */ "/*" { yy_push_state(optPsl() ? CMTBEGM : CMTMODE); yymore(); } {psl} { yyleng -= 3; BEGIN PSLMUL1; return (VP_COMMENT); } {ws}+ { yymore(); } "*/" { yy_pop_state(); return(VP_COMMENT); } {crnl} { linenoInc(); yymore(); } <> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); } . { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */ . { yymore(); } /* Psl C-style comments. */ /* EOFs are normal because / * `foo(..) * / hits a unputString EOF */ .|{crnl} { yyless(0); BEGIN PSLMULM; return(VP_PSL); } "*/" { yy_pop_state(); return(VP_COMMENT); } "//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */ /* Define calls */ "`"{symb} { return (VP_DEFREF); } /* Generics */ {crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); } <> { yyterminate(); } /* A "normal" EOF */ {symb} { return (VP_SYMBOL); } {wsn}+ { return (VP_WHITE); } {drop} { } [\r] { } . { return (VP_TEXT); } %% void V3PreLex::pushStateDefArg(int level) { // Enter define substitution argument state yy_push_state(ARGMODE); m_parenLevel = level; m_defValue = ""; } void V3PreLex::pushStateDefForm() { // Enter define formal arguments state yy_push_state(DEFFPAR); // First is an optional ( to begin args m_parenLevel = 0; m_defValue = ""; } void V3PreLex::pushStateDefValue() { // Enter define value state yy_push_state(DEFVAL); m_parenLevel = 0; m_defValue = ""; } void V3PreLex::pushStateIncFilename() { // Enter include <> filename state yy_push_state(INCMODE); yymore(); } void V3PreLex::scanBytes(const string& strg) { yy_scan_bytes(strg.c_str(), strg.length()); m_bufferStack.push(currentBuffer()); // yy_scan_bytes makes new buffer } void V3PreLex::appendDefValue(const char* textp, int len) { // Append given text to current definition value being formed m_defValue.append(textp,len); } YY_BUFFER_STATE V3PreLex::currentBuffer() { return YY_CURRENT_BUFFER; } int V3PreLex::currentStartState() { return YY_START; } void V3PreLex::lineDirective(const char* textp) { m_curFilelinep->lineDirective(textp); // Make sure we have a dependency on whatever file was specified V3File::addSrcDepend(m_curFilelinep->filename()); } void V3PreLex::dumpStack() { // For debug use stack tmpstack = m_bufferStack; printf(" bufferStack[%p]:",this); while (!tmpstack.empty()) { printf(" %p",tmpstack.top()); tmpstack.pop(); } printf("\n"); } /*################################################################### * Local Variables: * mode: C++ * End: */