2010-07-07 00:29:12 +00:00
%option noyywrap align interactive
%option stack
%option noc++
%option prefix="V3PreLex"
%{
2006-08-26 11:35:28 +00:00
/**************************************************************************
* 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
*
**************************************************************************
*
2018-01-02 23:05:06 +00:00
* Copyright 2003-2018 by Wilson Snyder. This program is free software;
2010-02-07 11:40:48 +00:00
* 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.
2006-08-26 11:35:28 +00:00
*
* 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.
**************************************************************************/
#include "V3PreProc.h"
#include "V3PreLex.h"
V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
2009-12-21 13:54:39 +00:00
#define LEXP V3PreLex::s_currentLexp
2010-04-07 00:20:44 +00:00
#define YY_INPUT(buf,result,max_size) \
result = LEXP->inputToLex(buf,max_size);
2010-03-05 17:02:56 +00:00
// Accessors, because flex keeps changing the type of yyleng
char* yyourtext() { return yytext; }
size_t yyourleng() { return yyleng; }
void yyourtext(const char* textp, size_t size) { yytext=(char*)textp; yyleng=size; }
2006-08-26 11:35:28 +00:00
// Prevent conflicts from perl version
2010-07-09 00:31:41 +00:00
static void linenoInc() {LEXP->linenoInc();}
2009-12-21 13:54:39 +00:00
static bool pedantic() { return LEXP->m_pedantic; }
2010-07-07 00:29:12 +00:00
static void yyerror(char* msg) { LEXP->curFilelinep()->v3error(msg); }
static void yyerrorf(const char* msg) { LEXP->curFilelinep()->v3error(msg); }
2010-04-07 00:20:44 +00:00
static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t,l); }
2006-08-26 11:35:28 +00:00
/**********************************************************************/
%}
%x CMTONEM
%x CMTBEGM
%x CMTMODE
%x STRMODE
2009-05-11 15:57:43 +00:00
%x DEFFPAR
%x DEFFORM
%x DEFVAL
2010-01-28 14:41:24 +00:00
%x DEFCMT
2015-05-08 01:41:54 +00:00
%x STRIFY
2006-08-26 11:35:28 +00:00
%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 [\"]
2010-07-10 22:30:16 +00:00
tickquote [`][\"]
2010-09-20 19:20:16 +00:00
/* Where we use symb/symbdef, we must also look for a `` join */
2012-02-26 02:31:36 +00:00
/* Note in the preprocessor \ESCaped is *not* always special; mantis1537/bug441 */
2009-07-31 16:02:43 +00:00
symb ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+)
2010-07-10 22:30:16 +00:00
symbdef ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n`]+)
2010-04-07 00:20:44 +00:00
word [a-zA-Z0-9_]+
2007-05-17 16:15:24 +00:00
drop [\032]
2018-06-26 11:11:56 +00:00
bom [\357\273\277]
2006-08-26 11:35:28 +00:00
/**************************************************************/
%%
2018-06-26 11:11:56 +00:00
<INITIAL>{bom} { }
2015-05-08 01:41:54 +00:00
<INITIAL,STRIFY>^{ws}*"`line"{ws}+.*{crnl} { LEXP->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 */
2009-12-21 03:26:48 +00:00
<INITIAL>"`define" { return(VP_DEFINE); }
2006-08-26 11:35:28 +00:00
<INITIAL>"`else" { return(VP_ELSE); }
<INITIAL>"`elsif" { return(VP_ELSIF); }
<INITIAL>"`endif" { return(VP_ENDIF); }
2009-12-21 03:26:48 +00:00
<INITIAL>"`ifdef" { return(VP_IFDEF); }
<INITIAL>"`ifndef" { return(VP_IFNDEF); }
<INITIAL>"`include" { return(VP_INCLUDE); }
2006-08-26 11:35:28 +00:00
<INITIAL>"`undef" { return(VP_UNDEF); }
2009-12-21 03:26:48 +00:00
<INITIAL>"`undefineall" { return(VP_UNDEFINEALL); }
2015-05-08 01:41:54 +00:00
<INITIAL>"`error" { if (!pedantic()) return (VP_ERROR); else return(VP_DEFREF); }
<INITIAL,STRIFY>"`__FILE__" { static string rtnfile;
2014-06-09 01:36:18 +00:00
rtnfile = '"'; rtnfile += LEXP->curFilelinep()->filename();
2009-12-24 16:40:56 +00:00
rtnfile += '"'; yytext=(char*)rtnfile.c_str(); yyleng = rtnfile.length();
return (VP_STRING); }
2015-05-08 01:41:54 +00:00
<INITIAL,STRIFY>"`__LINE__" { static char buf[10];
2010-07-07 00:29:12 +00:00
sprintf(buf, "%d",LEXP->curFilelinep()->lineno());
2009-12-24 16:40:56 +00:00
yytext = buf; yyleng = strlen(yytext);
return (VP_TEXT); }
2006-08-26 11:35:28 +00:00
/* Pass-through strings */
2014-11-22 15:14:14 +00:00
<INITIAL>{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); }
2010-04-07 00:20:44 +00:00
<STRMODE>{word} { yymore(); }
2006-08-26 11:35:28 +00:00
<STRMODE>[^\"\\] { yymore(); }
2017-11-16 01:19:12 +00:00
<STRMODE>[\\]{crnl} { linenoInc(); yymore(); }
<STRMODE>[\\]{wsn}+{crnl} { yyless(1); LEXP->curFilelinep()->v3warn(BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?"); }
<STRMODE>[\\]. { yymore(); }
2006-08-26 11:35:28 +00:00
<STRMODE>{quote} { yy_pop_state();
2014-11-12 21:37:51 +00:00
if (LEXP->m_parenLevel || LEXP->m_defQuote) { LEXP->m_defQuote=false; appendDefValue(yytext,yyleng); yyleng=0; }
2006-08-26 11:35:28 +00:00
else return (VP_STRING); }
2010-07-10 22:30:16 +00:00
/* Stringification */
2015-05-08 01:41:54 +00:00
<INITIAL>{tickquote} { yy_push_state(STRIFY); return VP_STRIFY; }
<STRIFY><<EOF>> { linenoInc(); yyerrorf("EOF in unterminated '\""); yyleng=0; yyterminate(); }
<STRIFY>"`\\`\"" { return VP_BACKQUOTE; }
<STRIFY>{quote} { yy_push_state(STRMODE); yymore(); }
<STRIFY>{tickquote} { yy_pop_state(); return VP_STRIFY; }
<STRIFY>{symbdef} { return (VP_SYMBOL); }
<STRIFY>{symbdef}`` { yyleng-=2; return (VP_SYMBOL_JOIN); }
<STRIFY>"`"{symbdef} { return (VP_DEFREF); }
<STRIFY>"`"{symbdef}`` { yyleng-=2; return (VP_DEFREF_JOIN); }
2017-10-10 22:44:10 +00:00
<STRIFY>`` { yyleng-=2; return (VP_JOIN); }
2015-05-08 01:41:54 +00:00
<STRIFY>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
<STRIFY>{wsn}+ { return (VP_WHITE); }
<STRIFY>{drop} { }
<STRIFY>[\r] { }
<STRIFY>. { return (VP_TEXT); }
2010-07-10 22:30:16 +00:00
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(); }
2015-04-05 14:54:56 +00:00
<PRTMODE>{crnl} { linenoInc(); return VP_TEXT; }
2007-05-18 14:03:50 +00:00
<PRTMODE>. { yymore(); }
2015-04-05 14:54:56 +00:00
<PRTMODE>"`endprotected" { yy_pop_state(); return VP_TEXT; }
2007-05-18 14:03:50 +00:00
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(); }
2017-11-16 01:19:12 +00:00
<INCMODE>[\\]. { yymore(); }
2015-04-05 14:54:56 +00:00
<INCMODE>[\>] { yy_pop_state(); return VP_STRING; }
2006-08-26 11:35:28 +00:00
2009-05-11 15:57:43 +00:00
/* Reading definition formal parenthesis (or not) to begin formal arguments */
/* Note '(' must IMMEDIATELY follow definition name */
2009-12-21 13:54:39 +00:00
<DEFFPAR>[(] { appendDefValue("(",1); LEXP->m_formalLevel=1; BEGIN(DEFFORM); }
2009-05-11 15:57:43 +00:00
<DEFFPAR>{crnl} { yy_pop_state(); unput('\n'); yyleng=0; return VP_DEFFORM; } /* DEFVAL will later grab the return */
2009-09-18 02:23:18 +00:00
<DEFFPAR><<EOF>> { yy_pop_state(); return VP_DEFFORM; } /* empty formals */
2009-05-11 15:57:43 +00:00
<DEFFPAR>. { yy_pop_state(); unput(yytext[yyleng-1]); yyleng=0; return VP_DEFFORM; } /* empty formals */
2009-12-21 13:54:39 +00:00
2010-07-09 00:31:41 +00:00
/* Reading definition formals (declaration of a define) */
2009-12-21 13:54:39 +00:00
<DEFFORM>[(] { appendDefValue(yytext,yyleng); yyleng=0; ++LEXP->m_formalLevel; }
<DEFFORM>[)] { appendDefValue(yytext,yyleng); yyleng=0; if ((--LEXP->m_formalLevel)==0) { yy_pop_state(); return VP_DEFFORM; } }
2009-05-11 15:57:43 +00:00
<DEFFORM>"/*" { yy_push_state(CMTMODE); yymore(); }
<DEFFORM>"//"[^\n\r]* { return (VP_COMMENT);}
2009-12-21 13:54:39 +00:00
<DEFFORM>{drop} { }
2009-05-11 15:57:43 +00:00
<DEFFORM><<EOF>> { linenoInc(); yy_pop_state(); yyerrorf("Unterminated ( in define formal arguments."); yyleng=0; return VP_DEFFORM; }
<DEFFORM>{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
2017-11-16 01:19:12 +00:00
<DEFFORM>[\\]{wsn}+{crnl} { yyless(1); LEXP->curFilelinep()->v3warn(BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?"); }
2010-07-10 22:30:16 +00:00
<DEFFORM>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Include return so can maintain output line count */
2014-11-12 21:37:51 +00:00
<DEFFORM>{quote} { LEXP->m_defQuote=true; yy_push_state(STRMODE); yymore(); } /* Legal only in default values */
2010-07-10 22:30:16 +00:00
<DEFFORM>"`\\`\"" { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
<DEFFORM>{tickquote} { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
2009-12-21 13:54:39 +00:00
<DEFFORM>[{\[] { LEXP->m_formalLevel++; appendDefValue(yytext,yyleng); }
<DEFFORM>[}\]] { LEXP->m_formalLevel--; appendDefValue(yytext,yyleng); }
<DEFFORM>[^\/\*\n\r\\(){}\[\]\"]+ |
2009-05-11 15:57:43 +00:00
<DEFFORM>[\\][^\n\r] |
<DEFFORM>. { appendDefValue(yytext,yyleng); }
2010-07-09 00:31:41 +00:00
/* Reading definition value (declaration of a define's text) */
2010-01-28 14:41:24 +00:00
<DEFVAL>"/*" { LEXP->m_defCmtSlash=false; yy_push_state(DEFCMT); yymore(); } /* Special comment parser */
2010-02-19 01:57:46 +00:00
<DEFVAL>"//"[^\n\r]*[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Spec says // not part of define value */
2009-05-11 15:57:43 +00:00
<DEFVAL>"//"[^\n\r]* { return (VP_COMMENT);}
<DEFVAL>{drop} { }
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
<DEFVAL>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
2017-11-16 01:19:12 +00:00
<DEFVAL>[\\]{wsn}+{crnl} { yyless(1); LEXP->curFilelinep()->v3warn(BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?"); }
2010-07-10 22:30:16 +00:00
<DEFVAL>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Return, AND \ is part of define value */
2014-11-12 21:37:51 +00:00
<DEFVAL>{quote} { LEXP->m_defQuote=true; yy_push_state(STRMODE); yymore(); }
<DEFVAL>[^\/\*\n\r\\\"]+ |
2009-05-11 15:57:43 +00:00
<DEFVAL>[\\][^\n\r] |
<DEFVAL>. { appendDefValue(yytext,yyleng); }
2006-08-26 11:35:28 +00:00
2010-01-28 14:41:24 +00:00
/* Comments inside define values - if embedded get added to define value per spec */
/* - if no \{crnl} ending then the comment belongs to the next line, as a non-embedded comment */
/* - if all but (say) 3rd line is missing \ then it's indeterminate */
<DEFCMT>"*/" { yy_pop_state(); appendDefValue(yytext,yyleng); }
2017-11-16 01:19:12 +00:00
<DEFCMT>[\\]{wsn}+{crnl} { yyless(1); LEXP->curFilelinep()->v3warn(BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?"); }
2010-01-28 14:41:24 +00:00
<DEFCMT>[\\]{crnl} { linenoInc(); LEXP->m_defCmtSlash=true;
appendDefValue(yytext,yyleng-2); appendDefValue((char*)"\n",1); } /* Return but not \ */
<DEFCMT>{crnl} { linenoInc(); yymore(); if (LEXP->m_defCmtSlash) yyerrorf("One line of /* ... */ is missing \\ before newline");
BEGIN(CMTMODE); }
2010-04-07 00:20:44 +00:00
<DEFCMT>{word} { yymore(); }
2010-01-28 14:41:24 +00:00
<DEFCMT>. { yymore(); }
<DEFCMT><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
2010-07-10 22:30:16 +00:00
/* Define arguments (use of a define) */
2006-08-26 11:35:28 +00:00
<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(); }
2010-07-10 22:30:16 +00:00
<ARGMODE>"`\\`\"" { appendDefValue(yytext,yyleng); } /* Literal text */
2018-06-21 12:19:59 +00:00
<ARGMODE>{tickquote} { yy_push_state(STRIFY); return(VP_STRIFY); }
2009-12-21 13:54:39 +00:00
<ARGMODE>[{\[] { LEXP->m_parenLevel++; appendDefValue(yytext,yyleng); }
<ARGMODE>[}\]] { LEXP->m_parenLevel--; appendDefValue(yytext,yyleng); }
<ARGMODE>[(] { LEXP->m_parenLevel++;
2008-04-25 14:01:50 +00:00
// Note paren level 0 means before "(" of starting args
// Level 1 means "," between arguments
2016-11-06 13:14:05 +00:00
// Level 2+ means one inside the () of an argument
2009-12-21 13:54:39 +00:00
if (LEXP->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);
2008-06-12 16:03:47 +00:00
}}
2009-12-21 13:54:39 +00:00
<ARGMODE>[)] { LEXP->m_parenLevel--;
if (LEXP->m_parenLevel>0) {
2008-03-27 13:21:49 +00:00
appendDefValue(yytext,yyleng);
} else {
yy_pop_state(); return (VP_DEFARG);
2008-06-12 16:03:47 +00:00
}}
2009-12-21 13:54:39 +00:00
<ARGMODE>[,] { if (LEXP->m_parenLevel>1) {
2008-03-27 13:21:49 +00:00
appendDefValue(yytext,yyleng);
} else {
yy_pop_state(); return (VP_DEFARG);
2008-06-12 16:03:47 +00:00
}}
2010-07-10 22:30:16 +00:00
<ARGMODE>"`"{symbdef} { appendDefValue(yytext,yyleng); } /* defref in defref - outer macro expands first */
2010-09-20 19:20:16 +00:00
<ARGMODE>"`"{symbdef}`` { appendDefValue(yytext,yyleng); } /* defref in defref - outer macro expands first */
2017-10-10 22:44:10 +00:00
<ARGMODE>`` { appendDefValue(yytext,yyleng); } /* defref in defref - outer macro expands first */
2008-06-04 15:39:44 +00:00
<ARGMODE>[^\/\*\n\r\\(,){}\[\]\"`]+ |
2006-08-26 11:35:28 +00:00
<ARGMODE>. { appendDefValue(yytext,yyleng); }
/* One line comments. */
2008-04-29 14:14:20 +00:00
<INITIAL>"//"{ws}*{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return (VP_WHITE); }
2014-11-22 15:14:14 +00:00
<INITIAL>"//" { 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
/* C-style comments. */
2010-01-28 14:41:24 +00:00
/**** See also DEFCMT */
2014-11-22 15:14:14 +00:00
/* We distinguish between the start of a comment, and later, to look for prefix comments (deprecated) */
<INITIAL>"/*" { yy_push_state(CMTMODE); yymore(); }
2006-08-26 11:35:28 +00:00
<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(); }
2010-04-07 00:20:44 +00:00
<CMTMODE>{word} { yymore(); }
2014-11-22 15:14:14 +00:00
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* beginning in comment */
2006-08-26 11:35:28 +00:00
<CMTMODE>. { yymore(); }
/* Define calls */
2010-09-20 19:20:16 +00:00
/* symbdef prevents normal lex rules from making `\`"foo a symbol {`"foo} instead of a BACKQUOTE */
2014-11-22 15:14:14 +00:00
<INITIAL>"`"{symbdef} { return (VP_DEFREF); }
<INITIAL>"`"{symbdef}`` { yyleng-=2; return (VP_DEFREF_JOIN); }
2006-08-26 11:35:28 +00:00
/* Generics */
2014-11-22 15:14:14 +00:00
<INITIAL>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
<INITIAL><<EOF>> { yyterminate(); } /* A "normal" EOF */
<INITIAL>{symb} { return (VP_SYMBOL); }
<INITIAL>{symb}`` { yyleng-=2; return (VP_SYMBOL_JOIN); }
2017-10-10 22:44:10 +00:00
<INITIAL>`` { yyleng-=2; return (VP_JOIN); }
2014-11-22 15:14:14 +00:00
<INITIAL>{wsn}+ { return (VP_WHITE); }
<INITIAL>{drop} { }
<INITIAL>[\r] { }
<INITIAL>. { return (VP_TEXT); }
2006-08-26 11:35:28 +00:00
%%
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 = "";
}
2009-05-11 15:57:43 +00:00
void V3PreLex::pushStateDefForm() {
// Enter define formal arguments state
yy_push_state(DEFFPAR); // First is an optional ( to begin args
m_parenLevel = 0;
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
2009-05-11 15:57:43 +00:00
yy_push_state(DEFVAL);
2006-08-26 11:35:28 +00:00
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();
}
2010-07-10 22:30:16 +00:00
void V3PreLex::debug(int level) { yy_flex_debug=level; }
int V3PreLex::debug() { return yy_flex_debug; }
int V3PreLex::lex() {
V3PreLex::s_currentLexp = this; // Tell parser where to get/put data
m_tokFilelinep = curFilelinep(); // Remember token start location, may be updated by the lexer later
return yylex();
2010-04-07 00:20:44 +00:00
}
size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
// We need a custom YY_INPUT because we can't use flex buffers.
// Flex buffers are limited to 2GB, and we can't chop into 2G pieces
// because buffers can't end in the middle of tokens.
2010-07-10 22:30:16 +00:00
// Note if we switched streams here (which we don't) "buf" would be
// become a stale invalid pointer.
2010-04-07 00:20:44 +00:00
//
2010-07-10 22:30:16 +00:00
VPreStream* streamp = curStreamp();
if (debug()>=10) { cout<<"- pp:inputToLex ITL s="<<max_size<<" bs="<<streamp->m_buffers.size()<<endl; dumpStack(); }
2010-04-07 00:20:44 +00:00
// For testing, use really small chunks
//if (max_size > 13) max_size=13;
2010-07-10 22:30:16 +00:00
again:
2010-04-07 00:20:44 +00:00
size_t got = 0;
2010-07-10 22:30:16 +00:00
// Get from this stream
2010-04-07 00:20:44 +00:00
while (got < max_size // Haven't got enough
2010-07-10 22:30:16 +00:00
&& !streamp->m_buffers.empty()) { // And something buffered
string front = curStreamp()->m_buffers.front(); streamp->m_buffers.pop_front();
2010-04-07 00:20:44 +00:00
size_t len = front.length();
if (len > (max_size-got)) { // Front string too big
len = (max_size-got);
2010-07-10 22:30:16 +00:00
string remainder = front.substr(len);
front = front.substr(0, len);
streamp->m_buffers.push_front(remainder); // Put back remainder for next time
2010-04-07 00:20:44 +00:00
}
strncpy(buf+got, front.c_str(), len);
got += len;
}
2010-07-10 22:30:16 +00:00
if (!got) { // end of stream; try "above" file
bool again=false;
string forceOut = endOfStream(again/*ref*/);
streamp = curStreamp(); // May have been updated
if (forceOut != "") {
if (forceOut.length() > max_size) {
yyerrorf("Output buffer too small for a `line");
} else {
got = forceOut.length();
strncpy(buf, forceOut.c_str(), got);
}
} else {
if (streamp->m_eof) {
if (yy_flex_debug) cout<<"- EOF\n";
}
got = 0; // 0=EOF/EOS - although got was already 0.
if (again) goto again;
}
}
if (debug()>=10) { cout<<"- pp::inputToLex got="<<got<<" '"<<string(buf,got)<<"'"<<endl; }
2010-04-07 00:20:44 +00:00
return got;
}
2010-07-10 22:30:16 +00:00
string V3PreLex::endOfStream(bool& againr) {
// Switch to file or next unputString
againr = false;
if (yy_flex_debug) cout<<"-EOS state="<<curStreamp()->m_termState<<" at "<<curFilelinep()<<endl;
if (curStreamp()->m_eof) return ""; // Don't delete the final "EOF" stream
bool exited_file = curStreamp()->m_file;
if (!exited_file) {
// Midpoint of stream, just change buffers
delete curStreamp();
m_streampStack.pop(); // Must work as size>1; EOF is entry 0
againr = true;
return "";
}
// Multiple steps because we need FLEX to see ending \n and EOS to end
// any illegal states, like an unterminated `protected region
else if (!curStreamp()->m_termState) {
// First shutdown phase for a file
// Terminate all files with a newline. This prevents problems if
// the user had a define without a terminating newline,
// otherwise the resumed file's next line would get tacked on.
// Also makes it likely the `line that changes files comes out
// immediately.
curStreamp()->m_termState = 1;
return "\n"; // Exit old file
}
else if (curStreamp()->m_termState == 1) {
// Now the EOF - can't be sent with other characters
curStreamp()->m_termState = 2;
return ""; // End of file
}
else if (curStreamp()->m_termState == 2) {
// Now ending `line
curStreamp()->m_termState = 3;
return curFilelinep()->lineDirectiveStrg(2); // Exit old file
}
else {
// Final shutdown phase for a stream, we can finally change the
// current fileline to the new stream
curStreamp()->m_termState = 0;
FileLine* filelinep = curFilelinep();
delete curStreamp();
m_streampStack.pop(); // Must work as size>1; EOF is entry 0
if (curStreamp()->m_eof) {
// EOF doesn't have a "real" fileline, but a linenumber of 0 from init time
// Inherit whatever we last parsed so it's more obvious.
curFilelinep(filelinep);
}
// The caller parser remembered the start location for the text we are parsing,
// but we've discovered there was a file switch along the way, so update it.
m_tokFilelinep = curFilelinep();
//
if (curStreamp()->m_eof) {
return "";
} else {
return curFilelinep()->lineDirectiveStrg(0); // Reenter resumed file
}
}
}
void V3PreLex::initFirstBuffer(FileLine* filelinep) {
// Called from constructor to make first buffer
// yy_create_buffer also sets yy_fill_buffer=1 so reads from YY_INPUT
2012-02-24 02:37:49 +00:00
VPreStream* streamp = new VPreStream(filelinep, this);
2010-07-10 22:30:16 +00:00
streamp->m_eof = true;
m_streampStack.push(streamp);
//
m_bufferState = yy_create_buffer(NULL, YY_BUF_SIZE);
yy_switch_to_buffer(m_bufferState);
yyrestart(NULL);
}
void V3PreLex::scanNewFile(FileLine* filelinep) {
// Called on new open file. scanBytesBack will be called next.
2012-02-24 02:37:49 +00:00
if (streamDepth() > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) {
// The recursive `include in VPreProcImp should trigger first
yyerrorf("Recursive `define or other nested inclusion");
curStreamp()->m_eof = true; // Fake it to stop recursion
} else {
VPreStream* streamp = new VPreStream(filelinep, this);
m_tokFilelinep = curFilelinep();
streamp->m_file = true;
scanSwitchStream(streamp);
}
2010-07-10 22:30:16 +00:00
}
void V3PreLex::scanBytes(const string& str) {
2010-04-07 00:20:44 +00:00
// Note buffers also appended in ::scanBytesBack
// Not "m_buffers.push_front(string(strp,len))" as we need a `define
// to take effect immediately, in the middle of the current buffer
2010-07-10 22:30:16 +00:00
// Also we don't use scan_bytes that would set yy_fill_buffer
// which would force Flex to bypass our YY_INPUT routine.
2012-02-24 02:37:49 +00:00
if (streamDepth() > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) {
// More streams if recursive `define with complex insertion
// More buffers mostly if something internal goes funky
yyerrorf("Recursive `define or other nested inclusion");
curStreamp()->m_eof = true; // Fake it to stop recursion
} else {
VPreStream* streamp = new VPreStream(curFilelinep(), this);
streamp->m_buffers.push_front(str);
scanSwitchStream(streamp);
}
2010-07-10 22:30:16 +00:00
}
void V3PreLex::scanSwitchStream(VPreStream* streamp) {
curStreamp()->m_buffers.push_front(currentUnreadChars());
m_streampStack.push(streamp);
yyrestart(NULL);
2006-08-26 11:35:28 +00:00
}
2010-04-07 00:20:44 +00:00
void V3PreLex::scanBytesBack(const string& str) {
// Initial creation, that will pull from YY_INPUT==inputToLex
// Note buffers also appended in ::scanBytes
2010-07-10 22:30:16 +00:00
if (curStreamp()->m_eof) yyerrorf("scanBytesBack without being under scanNewFile");
curStreamp()->m_buffers.push_back(str);
2010-04-07 00:20:44 +00:00
}
2010-07-10 22:30:16 +00:00
string V3PreLex::currentUnreadChars() {
// WARNING - Peeking at internals
ssize_t left = (yy_n_chars - (yy_c_buf_p -currentBuffer()->yy_ch_buf));
if (left > 0) { // left may be -1 at EOS
*(yy_c_buf_p) = (yy_hold_char);
return string(yy_c_buf_p, left);
} else {
return "";
}
2006-08-26 11:35:28 +00:00
}
2009-09-18 02:23:18 +00:00
YY_BUFFER_STATE V3PreLex::currentBuffer() {
return YY_CURRENT_BUFFER;
}
2011-08-05 01:58:45 +00:00
int V3PreLex::currentStartState() const {
2009-05-11 15:57:43 +00:00
return YY_START;
}
2006-08-26 11:35:28 +00:00
void V3PreLex::lineDirective(const char* textp) {
2010-07-07 00:29:12 +00:00
curFilelinep()->lineDirective(textp, m_enterExit/*ref*/);
2006-08-26 11:35:28 +00:00
// Make sure we have a dependency on whatever file was specified
2010-07-07 00:29:12 +00:00
V3File::addSrcDepend(curFilelinep()->filename());
2006-08-26 11:35:28 +00:00
}
2009-09-18 02:23:18 +00:00
2010-04-07 00:20:44 +00:00
void V3PreLex::dumpSummary() {
2010-07-10 22:30:16 +00:00
cout<<"- pp::dumpSummary curBuf="<<(void*)(currentBuffer());
#ifdef FLEX_DEBUG // Else peeking at internals may cause portability issues
ssize_t left = (yy_n_chars
- (yy_c_buf_p
-currentBuffer()->yy_ch_buf));
2018-02-02 02:24:41 +00:00
cout<<" left="<<std::dec<<left;
2010-07-10 22:30:16 +00:00
#endif
cout<<endl;
2010-04-07 00:20:44 +00:00
}
2009-09-18 02:23:18 +00:00
void V3PreLex::dumpStack() {
// For debug use
2010-04-07 00:20:44 +00:00
dumpSummary();
2018-02-02 02:24:41 +00:00
std::stack<VPreStream*> tmpstack = LEXP->m_streampStack;
2009-09-18 02:23:18 +00:00
while (!tmpstack.empty()) {
2010-07-10 22:30:16 +00:00
VPreStream* streamp = tmpstack.top();
cout<<"- bufferStack["<<(void*)(streamp)<<"]: "
<<" at="<<streamp->m_curFilelinep
<<" nBuf="<<streamp->m_buffers.size()
<<" size0="<<(streamp->m_buffers.empty() ? 0 : streamp->m_buffers.front().length())
<<(streamp->m_eof?" [EOF]":"")
<<(streamp->m_file?" [FILE]":"");
cout<<endl;
2009-09-18 02:23:18 +00:00
tmpstack.pop();
}
}
2010-07-10 22:30:16 +00:00
string V3PreLex::cleanDbgStrg(const string& in) {
string out = in;
string::size_type pos;
while ((pos=out.find("\n")) != string::npos) { out.replace(pos, 1, "\\n"); }
while ((pos=out.find("\r")) != string::npos) { out.replace(pos, 1, "\\r"); }
return out;
}
void V3PreLex::unused() {
if (0) {
// Prevent unused warnings
yy_top_state();
2011-08-23 01:02:09 +00:00
yyerror((char*)"");
2010-07-10 22:30:16 +00:00
}
}
2009-09-18 02:23:18 +00:00
/*###################################################################
* Local Variables:
* mode: C++
* End:
*/