/* $Id$ -*- C++ -*- */ /************************************************************************** * DESCRIPTION: Verilator: Flex verilog preprocessor * * Code available from: http://www.veripool.com/verilator * ************************************************************************** * * Copyright 2003-2007 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 // Prevent conflicts from perl version static void linenoInc() {V3PreLex::s_currentLexp->incLineno();} static bool optPsl() { return V3PreProc::optPsl(); } static bool pedantic() { return V3PreLex::s_currentLexp->m_pedantic; } static void yyerror(char* msg) { V3PreLex::s_currentLexp->m_curFilelinep->v3error(msg); } static void appendDefValue(char* t,int l) { V3PreLex::s_currentLexp->appendDefValue(t,l); } static int pslParenLevel() { return V3PreLex::s_currentLexp->m_pslParenLevel; } static void pslParenLevelInc() { V3PreLex::s_currentLexp->m_pslParenLevel++; } static void pslParenLevelDec() { if (pslParenLevel()) V3PreLex::s_currentLexp->m_pslParenLevel--; } static bool pslMoreNeeded() { return V3PreLex::s_currentLexp->m_pslMoreNeeded; } static void pslMoreNeeded(bool flag) { V3PreLex::s_currentLexp->m_pslMoreNeeded = flag; } /**********************************************************************/ %} %x PSLONEM %x PSLONEE %x PSLMULM %x PSLMUL1 %x CMTONEM %x CMTBEGM %x CMTMODE %x STRMODE %x DEFMODE %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_$]* drop [\032] psl [p]sl /**************************************************************/ %% ^{ws}*"`line"{ws}+.*{crnl} { V3PreLex::s_currentLexp->lineDirective(yytext); return(VP_LINE); } /* Special directives we recognise */ "`include" { return(VP_INCLUDE); } "`ifdef" { return(VP_IFDEF); } "`ifndef" { return(VP_IFNDEF); } "`else" { return(VP_ELSE); } "`elsif" { return(VP_ELSIF); } "`endif" { return(VP_ENDIF); } "`undef" { return(VP_UNDEF); } "`define" { return(VP_DEFINE); } /* Optional directives we recognise */ "`__FILE__" { if (!pedantic()) { yytext = (char*)V3PreLex::s_currentLexp->m_curFilelinep->cfilename(); yyleng = strlen(yytext); return (VP_TEXT); } else return(VP_DEFREF); } "`__LINE__" { if (!pedantic()) { static char buf[10]; sprintf(buf, "%d",V3PreLex::s_currentLexp->m_curFilelinep->lineno()); yytext = buf; yyleng = strlen(yytext); return (VP_TEXT); } else return(VP_DEFREF); } "`error" { if (!pedantic()) return (VP_ERROR); else return(VP_DEFREF); } /* Pass-through strings */ {quote} { yy_push_state(STRMODE); yymore(); } <> { linenoInc(); yyerror("EOF in unterminated string"); yyleng=0; yyterminate(); } {crnl} { linenoInc(); yyerror("Unterminated string"); BEGIN(INITIAL); } [^\"\\] { yymore(); } {backslash}. { yymore(); } {quote} { yy_pop_state(); if (V3PreLex::s_currentLexp->m_parenLevel) appendDefValue(yytext,yyleng); else return (VP_STRING); } /* Protected blocks */ "`protected" { yy_push_state(PRTMODE); yymore(); } <> { linenoInc(); yyerror("EOF in `protected"); yyleng=0; yyterminate(); } {crnl} { linenoInc(); yymore(); } . { yymore(); } "`endprotected" { yy_pop_state(); return (VP_TEXT); } /* Pass-through include <> filenames */ <> { linenoInc(); yyerror("EOF in unterminated include filename"); yyleng=0; yyterminate(); } {crnl} { linenoInc(); yyerror("Unterminated include filename"); BEGIN(INITIAL); } [^\>\\] { yymore(); } {backslash}. { yymore(); } [\>] { yy_pop_state(); return (VP_STRING); } /* Reading definition */ "/*" { yy_push_state(CMTMODE); yymore(); } "//"[^\n\r]* { return (VP_COMMENT);} {drop} { } <> { linenoInc(); yyerror("EOF (missing return?) in define value"); yyleng=0; yyterminate(); } {crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return (VP_DEFVALUE); } [\\]{crnl} { linenoInc(); appendDefValue("\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} { } <> { yyerror("EOF in define argument list\n"); yyleng = 0; yyterminate(); } {crnl} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); } {quote} { yy_push_state(STRMODE); yymore(); } [(] { V3PreLex::s_currentLexp->m_parenLevel++; appendDefValue(yytext,yyleng); } [,)] { if (V3PreLex::s_currentLexp->m_parenLevel>1) { appendDefValue(yytext,yyleng); if (yytext[0]==')') V3PreLex::s_currentLexp->m_parenLevel--; } else { unput(yytext[0]); yy_pop_state(); return (VP_DEFARG); }} [^\/\*\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="\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); } <> { yyerror("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); } {crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return(VP_WHITE); } /* Completed psl oneline comments */ {crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return(VP_WHITE); } {ws}+ { yymore(); } . { yyerror("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(); } <> { yyerror("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); } . { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */ . { yymore(); } /* Psl C-style comments. */ .|{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) */ <> { yyerror("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); } /* Define calls */ "`"{symb} { return (VP_DEFREF); } /* Generics */ {crnl} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); } {symb} { return (VP_SYMBOL); } {wsn}+ { return (VP_WHITE); } {drop} { } [\r] { } . { return (VP_TEXT); } %% void V3PreLex::setStateDefArg() { // Enter define substitution argument state yy_push_state(ARGMODE); m_parenLevel = 1; m_defValue = ""; } void V3PreLex::setStateDefValue() { // Enter define value state yy_push_state(DEFMODE); m_parenLevel = 0; m_defValue = ""; } void V3PreLex::setStateIncFilename() { // Enter include <> filename state yy_push_state(INCMODE); yymore(); } void V3PreLex::unputString(const char* textp) { // Add characters to input stream in back-to-front order const char* cp; for (cp = textp; *cp; cp++); for (cp--; cp >= textp; cp--) { unput(*cp); } } void V3PreLex::appendDefValue(const char* textp, int len) { // Append given text to current definition value being formed m_defValue.append(textp,len); } 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()); }