%option noyywrap align interactive
%option stack
%option noc++
%option prefix="VPreprocLex"
%{
/* $Revision: #8 $$Date: 2002/08/07 $$Author: wsnyder $
******************************************************************************
* DESCRIPTION: Verilog Preprocessor Lexer
*
* This file is part of Verilog-Perl.
*
* Author: Wilson Snyder <wsnyder@wsnyder.org>
*
* Code available from: http://veripool.com/systemperl
*
******************************************************************************
*
* This program is Copyright 2001 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.
*
* 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.
*
* If you do not have a copy of the GNU General Public License write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
* MA 02139, USA.
*
*****************************************************************************
* Do not use Flex in C++ mode. It has bugs with yyunput() which result in
* lost characters.
*****************************************************************************/
#include "VPreprocLex.h"
#include <stdio.h>
#include <iostream>
VPreprocLex* VPreprocLex::s_currentLexp = NULL; // Current lexing point
#define linenoInc() { VPreprocLex::s_currentLexp->linenoInc(); }
int keepComments() { return VPreprocLex::s_currentLexp->m_keepComments; }
bool pedantic() { return VPreprocLex::s_currentLexp->m_pedantic; }
void yyerror(char* msg) { VPreprocLex::s_currentLexp->m_curFilelinep->error(msg); }
/**********************************************************************/
%}
%x CMTMODE
%x STRMODE
%x DEFMODE
WHITESPACE [ \t\r\f]
NEWLINE [\n]
QUOTE [\"]
BACKSLASH [\\]
SYMBOL [a-zA-Z_][a-zA-Z0-9_$]*
/**************************************************************/
%%
^{WHITESPACE}*"`line"{WHITESPACE}+.*{NEWLINE} { VPreprocLex::s_currentLexp->lineDirective(yytext); }
/* 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*)VPreprocLex::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",VPreprocLex::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); }
/* One line comments. */
"//"[^\n]* { if (keepComments()) return (VP_COMMENT); }
/* C-style comments. */
"/*" { yy_push_state(CMTMODE); yymore(); }
<CMTMODE>"*/" { yy_pop_state(); if (keepComments()) return(VP_COMMENT); }
<CMTMODE>{NEWLINE} { linenoInc(); if (keepComments()) yymore(); else { yytext="\n"; yyleng=1; return(VP_WHITE); } }
<CMTMODE>. { yymore(); }
<CMTMODE><<EOF>> { yyerror("EOF in '/* ... */' block comment\n");
yyleng = 0; yyterminate(); }
/* Pass-through strings */
{QUOTE} { yy_push_state(STRMODE); yymore(); }
<STRMODE>{NEWLINE} { linenoInc();
yyerror("Unterminated string");
BEGIN(INITIAL); }
<STRMODE>[^\"\\] { yymore(); }
<STRMODE>{BACKSLASH}. { yymore(); }
<STRMODE>{QUOTE} { yy_pop_state(); return (VP_STRING); }
/* Reading definition */
<DEFMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
<DEFMODE>"//"[^\n]* { if (keepComments()) return (VP_COMMENT);}
<DEFMODE>{NEWLINE} { linenoInc();
yy_pop_state();
return (VP_DEFVALUE); } /* Note contains a return */
<DEFMODE>[^\/\*\n\m\\]+ |
<DEFMODE>[\\][^\n] |
<DEFMODE>. { VPreprocLex::s_currentLexp->appendDefValue(yytext,yyleng); }
<DEFMODE>[\\]\n { linenoInc(); VPreprocLex::s_currentLexp->appendDefValue(" ",1); }
/* Define calls */
"`"{SYMBOL} { return (VP_DEFREF); }
/* Generics */
{SYMBOL} { return (VP_SYMBOL); }
/* [\m] { } */
[\n] { linenoInc(); return(VP_WHITE); } /* Not {NEWLINE}, too long */
{WHITESPACE}+ { return (VP_WHITE); }
. { return (VP_TEXT); }
%%
void VPreprocLex::setStateDefValue() {
// Enter define value state
yy_push_state(DEFMODE);
m_defValue = "";
}
void VPreprocLex::appendDefValue(const char* textp, int len) {
// Append given text to current definition value being formed
m_defValue.append(textp,len);
}
void VPreprocLex::lineDirective(const char* textp) {
while (*textp && isspace(*textp)) textp++;
if (0==strncmp(textp,"`line",strlen("`line"))) textp+=strlen("`line");
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
// Grab linenumber
const char *ln = textp;
while (*textp && !isspace(*textp)) textp++;
if (isdigit(*ln)) {
m_curFilelinep = m_curFilelinep->create(atoi(ln));
}
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
// Grab filename
const char *fn = textp;
while (*textp && !(isspace(*textp) || *textp=='"')) textp++;
if (textp != fn) {
string newfilename; newfilename.append(fn, (textp-fn));
m_curFilelinep = m_curFilelinep->create(newfilename, m_curFilelinep->lineno());
}
}
/*###################################################################
* Local Variables:
* mode: C
* End:
*/