2006-08-26 11:35:28 +00:00
|
|
|
|
/* $Id$ -*- C++ -*- */
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
* DESCRIPTION: Verilator: Flex verilog preprocessor
|
|
|
|
|
*
|
2008-04-25 12:14:27 +00:00
|
|
|
|
* Code available from: http://www.veripool.org/verilator
|
2006-08-26 11:35:28 +00:00
|
|
|
|
*
|
|
|
|
|
**************************************************************************
|
|
|
|
|
*
|
2008-01-15 14:29:08 +00:00
|
|
|
|
* Copyright 2003-2008 by Wilson Snyder. This program is free software; you can
|
2006-08-26 11:35:28 +00:00
|
|
|
|
* 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); }
|
2008-04-29 14:14:20 +00:00
|
|
|
|
static void yyerrorf(const char* msg) { V3PreLex::s_currentLexp->m_curFilelinep->v3error(msg); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
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
|
2007-05-18 14:03:50 +00:00
|
|
|
|
%x PRTMODE
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
2007-05-17 16:15:24 +00:00
|
|
|
|
/* drop: Drop Ctrl-Z - can't pass thru or may EOF the output too soon */
|
|
|
|
|
|
2006-09-13 14:38:48 +00:00
|
|
|
|
ws [ \t\f\r]
|
|
|
|
|
wsn [ \t\f]
|
|
|
|
|
crnl [\r]*[\n]
|
2006-08-26 11:35:28 +00:00
|
|
|
|
quote [\"]
|
|
|
|
|
backslash [\\]
|
|
|
|
|
symb [a-zA-Z_][a-zA-Z0-9_$]*
|
2007-05-17 16:15:24 +00:00
|
|
|
|
drop [\032]
|
2006-08-26 11:35:28 +00:00
|
|
|
|
psl [p]sl
|
|
|
|
|
|
|
|
|
|
/**************************************************************/
|
|
|
|
|
%%
|
|
|
|
|
|
2007-06-13 17:34:09 +00:00
|
|
|
|
<INITIAL>^{ws}*"`line"{ws}+.*{crnl} { V3PreLex::s_currentLexp->lineDirective(yytext);
|
|
|
|
|
return(VP_LINE); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
2007-12-13 13:54:04 +00:00
|
|
|
|
/* Special directives we recognize */
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<INITIAL>"`include" { return(VP_INCLUDE); }
|
|
|
|
|
<INITIAL>"`ifdef" { return(VP_IFDEF); }
|
|
|
|
|
<INITIAL>"`ifndef" { return(VP_IFNDEF); }
|
|
|
|
|
<INITIAL>"`else" { return(VP_ELSE); }
|
|
|
|
|
<INITIAL>"`elsif" { return(VP_ELSIF); }
|
|
|
|
|
<INITIAL>"`endif" { return(VP_ENDIF); }
|
|
|
|
|
<INITIAL>"`undef" { return(VP_UNDEF); }
|
|
|
|
|
<INITIAL>"`define" { return(VP_DEFINE); }
|
|
|
|
|
|
2007-12-13 13:54:04 +00:00
|
|
|
|
/* Optional directives we recognize */
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<INITIAL>"`__FILE__" { if (!pedantic()) {
|
|
|
|
|
yytext = (char*)V3PreLex::s_currentLexp->m_curFilelinep->cfilename();
|
|
|
|
|
yyleng = strlen(yytext); return (VP_TEXT);
|
|
|
|
|
} else return(VP_DEFREF); }
|
|
|
|
|
<INITIAL>"`__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); }
|
|
|
|
|
<INITIAL>"`error" { if (!pedantic()) return (VP_ERROR); else return(VP_DEFREF); }
|
|
|
|
|
|
|
|
|
|
/* Pass-through strings */
|
|
|
|
|
<INITIAL,PSLMULM,PSLONEM>{quote} { yy_push_state(STRMODE); yymore(); }
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<STRMODE><<EOF>> { linenoInc(); yyerrorf("EOF in unterminated string"); yyleng=0; yyterminate(); }
|
|
|
|
|
<STRMODE>{crnl} { linenoInc(); yyerrorf("Unterminated string"); BEGIN(INITIAL); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<STRMODE>[^\"\\] { yymore(); }
|
|
|
|
|
<STRMODE>{backslash}. { yymore(); }
|
|
|
|
|
<STRMODE>{quote} { yy_pop_state();
|
|
|
|
|
if (V3PreLex::s_currentLexp->m_parenLevel) appendDefValue(yytext,yyleng);
|
|
|
|
|
else return (VP_STRING); }
|
|
|
|
|
|
2007-05-18 14:03:50 +00:00
|
|
|
|
/* Protected blocks */
|
|
|
|
|
<INITIAL>"`protected" { yy_push_state(PRTMODE); yymore(); }
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<PRTMODE><<EOF>> { linenoInc(); yyerrorf("EOF in `protected"); yyleng=0; yyterminate(); }
|
2007-05-18 14:03:50 +00:00
|
|
|
|
<PRTMODE>{crnl} { linenoInc(); yymore(); }
|
|
|
|
|
<PRTMODE>. { yymore(); }
|
|
|
|
|
<PRTMODE>"`endprotected" { yy_pop_state(); return (VP_TEXT); }
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
/* Pass-through include <> filenames */
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<INCMODE><<EOF>> { linenoInc(); yyerrorf("EOF in unterminated include filename"); yyleng=0; yyterminate(); }
|
|
|
|
|
<INCMODE>{crnl} { linenoInc(); yyerrorf("Unterminated include filename"); BEGIN(INITIAL); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<INCMODE>[^\>\\] { yymore(); }
|
|
|
|
|
<INCMODE>{backslash}. { yymore(); }
|
|
|
|
|
<INCMODE>[\>] { yy_pop_state(); return (VP_STRING); }
|
|
|
|
|
|
|
|
|
|
/* Reading definition */
|
|
|
|
|
<DEFMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
|
2006-09-13 14:38:48 +00:00
|
|
|
|
<DEFMODE>"//"[^\n\r]* { return (VP_COMMENT);}
|
2007-05-17 16:15:24 +00:00
|
|
|
|
<DEFMODE>{drop} { }
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<DEFMODE><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
|
|
|
|
|
<DEFMODE>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
|
|
|
|
|
<DEFMODE>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
|
2006-09-13 14:38:48 +00:00
|
|
|
|
<DEFMODE>[^\/\*\n\r\\]+ |
|
|
|
|
|
<DEFMODE>[\\][^\n\r] |
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<DEFMODE>. { appendDefValue(yytext,yyleng); }
|
|
|
|
|
|
|
|
|
|
/* Define arguments */
|
|
|
|
|
<ARGMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
|
2006-09-13 14:38:48 +00:00
|
|
|
|
<ARGMODE>"//"[^\n\r]* { return (VP_COMMENT);}
|
2007-05-17 16:15:24 +00:00
|
|
|
|
<ARGMODE>{drop} { }
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<ARGMODE><<EOF>> { yyerrorf("EOF in define argument list\n"); yyleng = 0; yyterminate(); }
|
|
|
|
|
<ARGMODE>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<ARGMODE>{quote} { yy_push_state(STRMODE); yymore(); }
|
2008-03-27 13:21:49 +00:00
|
|
|
|
<ARGMODE>[(] { V3PreLex::s_currentLexp->m_parenLevel++;
|
2008-04-25 14:01:50 +00:00
|
|
|
|
// Note paren level 0 means before "(" of starting args
|
|
|
|
|
// Level 1 means "," between arguments
|
|
|
|
|
// Level 2+ means one argument's internal ()
|
2008-03-27 13:21:49 +00:00
|
|
|
|
if (V3PreLex::s_currentLexp->m_parenLevel>1) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
appendDefValue(yytext,yyleng);
|
|
|
|
|
} else {
|
2008-03-27 13:21:49 +00:00
|
|
|
|
return (VP_TEXT);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}}
|
2008-03-27 13:21:49 +00:00
|
|
|
|
<ARGMODE>[)] { V3PreLex::s_currentLexp->m_parenLevel--;
|
|
|
|
|
if (V3PreLex::s_currentLexp->m_parenLevel>0) {
|
|
|
|
|
appendDefValue(yytext,yyleng);
|
|
|
|
|
} else {
|
|
|
|
|
yy_pop_state(); return (VP_DEFARG);
|
|
|
|
|
}}
|
|
|
|
|
<ARGMODE>[,] { if (V3PreLex::s_currentLexp->m_parenLevel>1) {
|
|
|
|
|
appendDefValue(yytext,yyleng);
|
|
|
|
|
} else {
|
|
|
|
|
yy_pop_state(); return (VP_DEFARG);
|
|
|
|
|
}}
|
|
|
|
|
<ARGMODE>"`"{symb} { return (VP_DEFREF); } /* defref in defref */
|
|
|
|
|
<ARGMODE>[^\/\*\n\r\\(,)\"`]+ |
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<ARGMODE>. { appendDefValue(yytext,yyleng); }
|
|
|
|
|
|
|
|
|
|
/* One line comments. */
|
|
|
|
|
<INITIAL>"//"{ws}*{psl} { if (optPsl()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
|
|
|
|
|
else { yy_push_state(CMTONEM); yymore(); } }
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<INITIAL>"//"{ws}*{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return (VP_WHITE); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<INITIAL>"//" { if (pslMoreNeeded()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
|
|
|
|
|
else { yy_push_state(CMTONEM); yymore(); } }
|
2006-09-13 14:38:48 +00:00
|
|
|
|
<CMTONEM>[^\n\r]* { yy_pop_state(); return (VP_COMMENT); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
/* Psl oneline comments */
|
|
|
|
|
<PSLONEM>[{(] { pslParenLevelInc(); return (VP_TEXT); }
|
|
|
|
|
<PSLONEM>[})] { pslParenLevelDec(); return (VP_TEXT); }
|
|
|
|
|
<PSLONEM>[;] { if (!pslParenLevel()) {BEGIN PSLONEE; pslMoreNeeded(false);} return (VP_TEXT); }
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<PSLONEM><<EOF>> { yyerrorf("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); }
|
|
|
|
|
<PSLONEM>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
/* Completed psl oneline comments */
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<PSLONEE>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<PSLONEE>{ws}+ { yymore(); }
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<PSLONEE>. { yyerrorf("Unexpected text following psl assertion\n"); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
/* C-style comments. */
|
|
|
|
|
/* We distinguish between the start of a comment, and later, so we may find a "psl" prefix */
|
|
|
|
|
<INITIAL>"/*" { yy_push_state(optPsl() ? CMTBEGM : CMTMODE); yymore(); }
|
|
|
|
|
<CMTBEGM>{psl} { yyleng -= 3; BEGIN PSLMUL1; return (VP_COMMENT); }
|
|
|
|
|
<CMTBEGM>{ws}+ { yymore(); }
|
|
|
|
|
<CMTBEGM,CMTMODE>"*/" { yy_pop_state(); return(VP_COMMENT); }
|
2006-09-13 14:38:48 +00:00
|
|
|
|
<CMTBEGM,CMTMODE>{crnl} { linenoInc(); yymore(); }
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<CMTBEGM,CMTMODE><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */
|
|
|
|
|
<CMTMODE>. { yymore(); }
|
|
|
|
|
|
|
|
|
|
/* Psl C-style comments. */
|
2006-09-13 14:38:48 +00:00
|
|
|
|
<PSLMUL1>.|{crnl} { yyless(0); BEGIN PSLMULM; return(VP_PSL); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<PSLMULM>"*/" { yy_pop_state(); return(VP_COMMENT); }
|
2006-09-13 14:38:48 +00:00
|
|
|
|
<PSLMULM>"//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<PSLMULM><<EOF>> { yyerrorf("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
/* Define calls */
|
|
|
|
|
<INITIAL,PSLMULM,PSLONEM>"`"{symb} { return (VP_DEFREF); }
|
|
|
|
|
|
|
|
|
|
/* Generics */
|
2008-04-29 14:14:20 +00:00
|
|
|
|
<INITIAL,PSLMULM>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<INITIAL,PSLMULM,PSLONEM>{symb} { return (VP_SYMBOL); }
|
2006-09-13 14:38:48 +00:00
|
|
|
|
<INITIAL,PSLMULM,PSLONEM>{wsn}+ { return (VP_WHITE); }
|
2007-05-17 16:15:24 +00:00
|
|
|
|
<INITIAL,PSLMULM,PSLONEM>{drop} { }
|
|
|
|
|
<INITIAL,PSLMULM,PSLONEM>[\r] { }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<INITIAL,PSLMULM,PSLONEM>. { return (VP_TEXT); }
|
|
|
|
|
%%
|
|
|
|
|
|
2008-04-25 14:01:50 +00:00
|
|
|
|
void V3PreLex::pushStateDefArg(int level) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Enter define substitution argument state
|
|
|
|
|
yy_push_state(ARGMODE);
|
2008-04-25 14:01:50 +00:00
|
|
|
|
m_parenLevel = level;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
m_defValue = "";
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-27 13:21:49 +00:00
|
|
|
|
void V3PreLex::pushStateDefValue() {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Enter define value state
|
|
|
|
|
yy_push_state(DEFMODE);
|
|
|
|
|
m_parenLevel = 0;
|
|
|
|
|
m_defValue = "";
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-27 13:21:49 +00:00
|
|
|
|
void V3PreLex::pushStateIncFilename() {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// 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());
|
|
|
|
|
}
|