%option align interactive
%option stack
%option noc++
%option prefix="VParseLex"
%{
/**************************************************************************
 * DESCRIPTION: Verilog Parser Lexer
 *
 * This file is part of Verilog-Perl.
 *
 * Author: Wilson Snyder <wsnyder@wsnyder.org>
 *
 * Code available from: https://www.veripool.org/verilog-perl
 *
 **************************************************************************
 *
 * Copyright 2000-2020 by Wilson Snyder.  This program is free software;
 * 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.
 *
 * 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.
 *
 **************************************************************************
 * Do not use Flex in C++ mode.  It has bugs with yyunput() which result in
 * lost characters.
 *************************************************************************/

#include "VParseLex.h"
#include <cstdio>
#include <iostream>
#include <cstdarg>
#include <cstring>

#include "VParseGrammar.h"
#include "VParseBison.h"

#define YY_SKIP_YYWRAP

#define STATE_VERILOG_RECENT  S17		// State name for most recent Verilog Version

// Flex 2.5.35 has compile warning in ECHO, so we'll default our own rule
#define ECHO yyerrorf("Missing VParseLex.l rule: ECHO rule invoked in state %d: %s", YY_START, yytext);

VParseLex* VParseLex::s_currentLexp = NULL;	// Current lexing point
VParseBisonYYSType* VParseLex::s_yylvalp = NULL;		// LValue for current bison object

#define LEXP (VParseLex::s_currentLexp)
#define LPARSEP (LEXP->m_parsep)

#define NEXTLINE()  { LPARSEP->inFilelineInc(); }
#define LINECHECKS(textp,len)  { const char* cp=textp; for (int n=len; n; --n) if (cp[n]=='\n') NEXTLINE(); }
#define LINECHECK()  LINECHECKS(yytext,yyleng)

#define FL { VParseLex::s_yylvalp->fl = LPARSEP->inFilelinep(); }

// lval.fileline not used yet; here for Verilator parser compatibility
#define VALTEXTS(strg) VParseLex::s_yylvalp->str = strg
#define VALTEXT   VALTEXTS(string(yytext,yyleng))
#define CALLBACKS(whichCb,strg) {LPARSEP->whichCb(VParseLex::s_yylvalp->fl, strg); }
#define CALLBACK(whichCb) CALLBACKS(whichCb,string(yytext,yyleng))

#define YY_INPUT(buf,result,max_size) \
    result = LPARSEP->inputToLex(buf,max_size);

int yywrap() { return LPARSEP->eofToLex(); }

#define StashPrefix LPARSEP->unreadbackCat(yytext,yyleng)

void yyerror(char* errmsg) {
    LPARSEP->inFilelinep()->error(errmsg);
}

void yyerrorf(const char* format, ...) {
    char msg[1024];

    va_list ap;
    va_start(ap,format);
    vsprintf(msg,format,ap);
    va_end(ap);

    yyerror(msg);
}

/**********************************************************************/
%}

%s V95 V01 V05 S05 S09 S12 S17
%s STRING ATTRMODE
%s CMTMODE PROTMODE
%s DUMMY_TO_AVOID_WARNING

space	[ ]
ws	[ \t\f\r]+
crnl	[\r]*[\n]
	/* identifier */
id	[a-zA-Z_][a-zA-Z0-9_$]*
	/* escaped identifier */
escid	\\[^ \t\f\r\n]+
word	[a-zA-Z0-9_]+
	/* verilog numbers, constructed to not match the ' that begins a '(  or '{ */
vnum1	[0-9]*?[''][sS]?[bcodhBCODH][ \t\n]*[A-Fa-f0-9xXzZ_?]*
vnum2	[0-9]*?[''][sS]?[01xXzZ]
vnum3	[0-9][_0-9]*[ \t\n]*[''][Ss]?[bcodhBCODH]?[ \t\n]*[A-Fa-f0-9xXzZ_?]+
vnum4	[0-9][_0-9]*[ \t\n]*[''][sS]?[bcodhBCODH]
vnum5	[0-9][_0-9]*[ \t\n]*[''][sS]
vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}

%%

<INITIAL>.|\n 		{BEGIN STATE_VERILOG_RECENT; yyless(0); }

  /* Verilog 1995 */
<V95,V01,V05,S05,S09,S12,S17>{
  {ws}			{ StashPrefix; }	/* otherwise ignore white-space */
  {crnl}		{ StashPrefix; NEXTLINE(); }		/* Count line numbers */
  /*     Keywords */
  "always"		{ FL; VALTEXT; CALLBACK(keywordCb); return yALWAYS; }
  "and"			{ FL; VALTEXT; CALLBACK(keywordCb); return yAND; }
  "assign"		{ FL; VALTEXT; CALLBACK(keywordCb); return yASSIGN; }
  "begin"		{ FL; VALTEXT; CALLBACK(keywordCb); return yBEGIN; }
  "buf"			{ FL; VALTEXT; CALLBACK(keywordCb); return yBUF; }
  "case"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCASE; }
  "casex"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCASEX; }
  "casez"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCASEZ; }
  "deassign"		{ FL; VALTEXT; CALLBACK(keywordCb); return yDEASSIGN; }
  "default"		{ FL; VALTEXT; CALLBACK(keywordCb); return yDEFAULT; }
  "defparam"		{ FL; VALTEXT; CALLBACK(keywordCb); return yDEFPARAM; }
  "disable"		{ FL; VALTEXT; CALLBACK(keywordCb); return yDISABLE; }
  "edge"		{ FL; VALTEXT; CALLBACK(keywordCb); return yEDGE; }
  "else"		{ FL; VALTEXT; CALLBACK(keywordCb); return yELSE; }
  "end"			{ FL; VALTEXT; CALLBACK(keywordCb); return yEND; }
  "endcase"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDCASE; }
  "endfunction"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDFUNCTION; }
  "endmodule"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDMODULE; }
  "endprimitive"	{ FL; VALTEXT; CALLBACK(keywordCb); return yENDMODULE; }
  "endspecify"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDSPECIFY; }
  "endtable"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDTABLE; }
  "endtask"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDTASK; }
  "event"		{ FL; VALTEXT; CALLBACK(keywordCb); return yEVENT; }
  "for"			{ FL; VALTEXT; CALLBACK(keywordCb); return yFOR; }
  "force"		{ FL; VALTEXT; CALLBACK(keywordCb); return yFORCE; }
  "forever"		{ FL; VALTEXT; CALLBACK(keywordCb); return yFOREVER; }
  "fork"		{ FL; VALTEXT; CALLBACK(keywordCb); return yFORK; }
  "function"		{ FL; VALTEXT; CALLBACK(keywordCb); return yFUNCTION__LEX; }
  "if"			{ FL; VALTEXT; CALLBACK(keywordCb); return yIF; }
  "initial"		{ FL; VALTEXT; CALLBACK(keywordCb); return yINITIAL; }
  "inout"		{ FL; VALTEXT; CALLBACK(keywordCb); return yINOUT; }
  "input"		{ FL; VALTEXT; CALLBACK(keywordCb); return yINPUT; }
  "integer"		{ FL; VALTEXT; CALLBACK(keywordCb); return yINTEGER; }
  "join"		{ FL; VALTEXT; CALLBACK(keywordCb); return yJOIN; }
  "macromodule"		{ FL; VALTEXT; CALLBACK(keywordCb); return yMODULE; }
  "module"		{ FL; VALTEXT; CALLBACK(keywordCb); return yMODULE; }
  "nand"		{ FL; VALTEXT; CALLBACK(keywordCb); return yNAND; }
  "negedge"		{ FL; VALTEXT; CALLBACK(keywordCb); return yNEGEDGE; }
  "nor"			{ FL; VALTEXT; CALLBACK(keywordCb); return yNOR; }
  "not"			{ FL; VALTEXT; CALLBACK(keywordCb); return yNOT; }
  "or"			{ FL; VALTEXT; CALLBACK(keywordCb); return yOR; }
  "output"		{ FL; VALTEXT; CALLBACK(keywordCb); return yOUTPUT; }
  "parameter"		{ FL; VALTEXT; CALLBACK(keywordCb); return yPARAMETER; }
  "posedge"		{ FL; VALTEXT; CALLBACK(keywordCb); return yPOSEDGE; }
  "primitive"		{ FL; VALTEXT; CALLBACK(keywordCb); return yMODULE; }
  "real"		{ FL; VALTEXT; CALLBACK(keywordCb); return yREAL; }
  "realtime"		{ FL; VALTEXT; CALLBACK(keywordCb); return yREALTIME; }
  "reg"			{ FL; VALTEXT; CALLBACK(keywordCb); return yREG; }
  "release"		{ FL; VALTEXT; CALLBACK(keywordCb); return yRELEASE; }
  "repeat"		{ FL; VALTEXT; CALLBACK(keywordCb); return yREPEAT; }
  "scalared"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySCALARED; }
  "specify"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySPECIFY; }
  "specparam"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySPECPARAM; }
  "supply0"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySUPPLY0; }
  "supply1"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySUPPLY1; }
  "table"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTABLE; }
  "task"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTASK__LEX; }
  "time"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTIME; }
  "tri"			{ FL; VALTEXT; CALLBACK(keywordCb); return yTRI; }
  "tri0"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTRI0; }
  "tri1"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTRI1; }
  "triand"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTRIAND; }
  "trior"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTRIOR; }
  "trireg"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTRIREG; }
  "vectored"		{ FL; VALTEXT; CALLBACK(keywordCb); return yVECTORED; }
  "wait"		{ FL; VALTEXT; CALLBACK(keywordCb); return yWAIT; }
  "wand"		{ FL; VALTEXT; CALLBACK(keywordCb); return yWAND; }
  "while"		{ FL; VALTEXT; CALLBACK(keywordCb); return yWHILE; }
  "wire"		{ FL; VALTEXT; CALLBACK(keywordCb); return yWIRE; }
  "wor"			{ FL; VALTEXT; CALLBACK(keywordCb); return yWOR; }
  "xnor"		{ FL; VALTEXT; CALLBACK(keywordCb); return yXNOR; }
  "xor"			{ FL; VALTEXT; CALLBACK(keywordCb); return yXOR; }
  /*     Types Verilator doesn't support but we do generically here */
  "bufif0"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "bufif1"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "cmos"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "highz0"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "highz1"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "large"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "medium"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "nmos"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "notif0"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "notif1"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "pmos"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "pull0"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "pull1"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "pulldown"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "pullup"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "rcmos"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "rnmos"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "rpmos"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "rtran"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "rtranif0"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "rtranif1"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "small"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "strong0"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "strong1"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "tran"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "tranif0"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "tranif1"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenGATE; }
  "weak0"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  "weak1"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenSTRENGTH; }
  /*     Generic unsupported warnings */
}

  /* Verilog 2001 */
<V01,V05,S05,S09,S12,S17>{
  /*     Keywords*/
  "automatic"		{ FL; VALTEXT; CALLBACK(keywordCb); return yAUTOMATIC; }
  "endgenerate"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDGENERATE; }
  "generate"		{ FL; VALTEXT; CALLBACK(keywordCb); return yGENERATE; }
  "genvar"		{ FL; VALTEXT; CALLBACK(keywordCb); return yGENVAR; }
  "ifnone"		{ FL; VALTEXT; CALLBACK(keywordCb); return yaTIMINGSPEC; }
  "localparam"		{ FL; VALTEXT; CALLBACK(keywordCb); return yLOCALPARAM; }
  "noshowcancelled"	{ FL; VALTEXT; CALLBACK(keywordCb); return yaTIMINGSPEC; }
  "pulsestyle_ondetect"	{ FL; VALTEXT; CALLBACK(keywordCb); return yaTIMINGSPEC; }
  "pulsestyle_onevent"	{ FL; VALTEXT; CALLBACK(keywordCb); return yaTIMINGSPEC; }
  "showcancelled"	{ FL; VALTEXT; CALLBACK(keywordCb); return yaTIMINGSPEC; }
  "signed"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySIGNED; }
  "unsigned"		{ FL; VALTEXT; CALLBACK(keywordCb); return yUNSIGNED; }
  /*     Generic unsupported keywords */
  "cell"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
  "config"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
  "design"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
  "endconfig"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
  "incdir"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
  "include"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
  "instance"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
  "liblist"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
  "library"		{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
  "use"			{ FL; VALTEXT; CALLBACK(keywordCb); return ygenCONFIGKEYWORD; }
}

  /* Verilog 2005 */
<V05,S05,S09,S12,S17>{
  /*     Keywords */
  "uwire"		{ FL; VALTEXT; CALLBACK(keywordCb); return yWIRE; }
}

  /* System Verilog 2005 */
<S05,S09,S12,S17>{
  /*     System Tasks */
  "$error"		{ FL; VALTEXT; CALLBACK(keywordCb); return yD_ERROR; }
  "$fatal"		{ FL; VALTEXT; CALLBACK(keywordCb); return yD_FATAL; }
  "$info"		{ FL; VALTEXT; CALLBACK(keywordCb); return yD_INFO; }
  "$root"		{ FL; VALTEXT; CALLBACK(keywordCb); return yD_ROOT; }
  "$unit"		{ FL; VALTEXT; CALLBACK(keywordCb); return yD_UNIT; }
  "$warning"		{ FL; VALTEXT; CALLBACK(keywordCb); return yD_WARNING; }
  /*     Keywords */
  "alias"		{ FL; VALTEXT; CALLBACK(keywordCb); return yALIAS; }
  "always_comb"		{ FL; VALTEXT; CALLBACK(keywordCb); return yALWAYS; }
  "always_ff"		{ FL; VALTEXT; CALLBACK(keywordCb); return yALWAYS; }
  "always_latch"	{ FL; VALTEXT; CALLBACK(keywordCb); return yALWAYS; }
  "assert"		{ FL; VALTEXT; CALLBACK(keywordCb); return yASSERT; }
  "assume"		{ FL; VALTEXT; CALLBACK(keywordCb); return yASSUME; }
  "before"		{ FL; VALTEXT; CALLBACK(keywordCb); return yBEFORE; }
  "bind"		{ FL; VALTEXT; CALLBACK(keywordCb); return yBIND; }
  "bins"		{ FL; VALTEXT; CALLBACK(keywordCb); return yBINS; }
  "binsof"		{ FL; VALTEXT; CALLBACK(keywordCb); return yBINSOF; }
  "bit"			{ FL; VALTEXT; CALLBACK(keywordCb); return yBIT; }
  "break"		{ FL; VALTEXT; CALLBACK(keywordCb); return yBREAK; }
  "byte"		{ FL; VALTEXT; CALLBACK(keywordCb); return yBYTE; }
  "chandle"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCHANDLE; }
  "class"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCLASS; }
  "clocking"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCLOCKING; }
  "const"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCONST__LEX; }
  "constraint"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCONSTRAINT; }
  "context"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCONTEXT; }
  "continue"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCONTINUE; }
  "cover"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCOVER; }
  "covergroup"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCOVERGROUP; }
  "coverpoint"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCOVERPOINT; }
  "cross"		{ FL; VALTEXT; CALLBACK(keywordCb); return yCROSS; }
  "dist"		{ FL; VALTEXT; CALLBACK(keywordCb); return yDIST; }
  "do"			{ FL; VALTEXT; CALLBACK(keywordCb); return yDO; }
  "endclass"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDCLASS; }
  "endclocking"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDCLOCKING; }
  "endgroup"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDGROUP; }
  "endinterface"	{ FL; VALTEXT; CALLBACK(keywordCb); return yENDINTERFACE; }
  "endpackage"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDPACKAGE; }
  "endprogram"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDPROGRAM; }
  "endproperty"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDPROPERTY; }
  "endsequence"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENDSEQUENCE; }
  "enum"		{ FL; VALTEXT; CALLBACK(keywordCb); return yENUM; }
  "expect"		{ FL; VALTEXT; CALLBACK(keywordCb); return yEXPECT; }
  "export"		{ FL; VALTEXT; CALLBACK(keywordCb); return yEXPORT; }
  "extends"		{ FL; VALTEXT; CALLBACK(keywordCb); return yEXTENDS; }
  "extern"		{ FL; VALTEXT; CALLBACK(keywordCb); return yEXTERN; }
  "final"		{ FL; VALTEXT; CALLBACK(keywordCb); return yFINAL; }
  "first_match"		{ FL; VALTEXT; CALLBACK(keywordCb); return yFIRST_MATCH; }
  "foreach"		{ FL; VALTEXT; CALLBACK(keywordCb); return yFOREACH; }
  "forkjoin"		{ FL; VALTEXT; CALLBACK(keywordCb); return yFORKJOIN; }
  "iff"			{ FL; VALTEXT; CALLBACK(keywordCb); return yIFF; }
  "ignore_bins"		{ FL; VALTEXT; CALLBACK(keywordCb); return yIGNORE_BINS; }
  "illegal_bins"	{ FL; VALTEXT; CALLBACK(keywordCb); return yILLEGAL_BINS; }
  "import"		{ FL; VALTEXT; CALLBACK(keywordCb); return yIMPORT; }
  "inside"		{ FL; VALTEXT; CALLBACK(keywordCb); return yINSIDE; }
  "int"			{ FL; VALTEXT; CALLBACK(keywordCb); return yINT; }
  "interface"		{ FL; VALTEXT; CALLBACK(keywordCb); return yINTERFACE; }
  "intersect"		{ FL; VALTEXT; CALLBACK(keywordCb); return yINTERSECT; }
  "join_any"		{ FL; VALTEXT; CALLBACK(keywordCb); return yJOIN; }
  "join_none"		{ FL; VALTEXT; CALLBACK(keywordCb); return yJOIN; }
  "local"		{ FL; VALTEXT; CALLBACK(keywordCb); return yLOCAL__LEX; }
  "logic"		{ FL; VALTEXT; CALLBACK(keywordCb); return yLOGIC; }
  "longint"		{ FL; VALTEXT; CALLBACK(keywordCb); return yLONGINT; }
  "matches"		{ FL; VALTEXT; CALLBACK(keywordCb); return yMATCHES; }
  "modport"		{ FL; VALTEXT; CALLBACK(keywordCb); return yMODPORT; }
  "new"			{ FL; VALTEXT; CALLBACK(keywordCb); return yNEW__LEX; }
  "null"		{ FL; VALTEXT; CALLBACK(keywordCb); return yNULL; }
  "package"		{ FL; VALTEXT; CALLBACK(keywordCb); return yPACKAGE; }
  "packed"		{ FL; VALTEXT; CALLBACK(keywordCb); return yPACKED; }
  "priority"		{ FL; VALTEXT; CALLBACK(keywordCb); return yPRIORITY; }
  "program"		{ FL; VALTEXT; CALLBACK(keywordCb); return yPROGRAM; }
  "property"		{ FL; VALTEXT; CALLBACK(keywordCb); return yPROPERTY; }
  "protected"		{ FL; VALTEXT; CALLBACK(keywordCb); return yPROTECTED; }
  "pure"		{ FL; VALTEXT; CALLBACK(keywordCb); return yPURE; }
  "rand"		{ FL; VALTEXT; CALLBACK(keywordCb); return yRAND; }
  "randc"		{ FL; VALTEXT; CALLBACK(keywordCb); return yRANDC; }
  "randcase"		{ FL; VALTEXT; CALLBACK(keywordCb); return yRANDCASE; }
  "randsequence"	{ FL; VALTEXT; CALLBACK(keywordCb); return yRANDSEQUENCE; }
  "ref"			{ FL; VALTEXT; CALLBACK(keywordCb); return yREF; }
  "return"		{ FL; VALTEXT; CALLBACK(keywordCb); return yRETURN; }
  "sequence"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySEQUENCE; }
  "shortint"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySHORTINT; }
  "shortreal"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySHORTREAL; }
  "solve"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySOLVE; }
  "static"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySTATIC__LEX; }
  "string"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySTRING; }
  "struct"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySTRUCT; }
  "super"		{ FL; VALTEXT; CALLBACK(keywordCb); return ySUPER; }
  "tagged"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTAGGED; }
  "this"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTHIS; }
  "throughout"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTHROUGHOUT; }
  "timeprecision"	{ FL; VALTEXT; CALLBACK(keywordCb); return yTIMEPRECISION; }
  "timeunit"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTIMEUNIT; }
  "type"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTYPE; }
  "typedef"		{ FL; VALTEXT; CALLBACK(keywordCb); return yTYPEDEF; }
  "union"		{ FL; VALTEXT; CALLBACK(keywordCb); return yUNION; }
  "unique"		{ FL; VALTEXT; CALLBACK(keywordCb); return yUNIQUE; }
  "var"			{ FL; VALTEXT; CALLBACK(keywordCb); return yVAR; }
  "virtual"		{ FL; VALTEXT; CALLBACK(keywordCb); return yVIRTUAL__LEX; }
  "void"		{ FL; VALTEXT; CALLBACK(keywordCb); return yVOID; }
  "wait_order"		{ FL; VALTEXT; CALLBACK(keywordCb); return yWAIT_ORDER; }
  "wildcard"		{ FL; VALTEXT; CALLBACK(keywordCb); return yWILDCARD; }
  "with"		{ FL; VALTEXT; CALLBACK(keywordCb); return yWITH__LEX; }
  "within"		{ FL; VALTEXT; CALLBACK(keywordCb); return yWITHIN; }
}

  /* System Verilog 2009 */
<S09,S12,S17>{
  /*     Keywords */
  "accept_on"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yACCEPT_ON; }
  "checker"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yCHECKER; }
  "endchecker"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yENDCHECKER; }
  "eventually"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yEVENTUALLY; }
  "global"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yGLOBAL__LEX; }
  "implies"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yIMPLIES; }
  "let"		 	{ FL; VALTEXT; CALLBACK(keywordCb); return yLET; }
  "nexttime"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yNEXTTIME; }
  "reject_on"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yREJECT_ON; }
  "restrict"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yRESTRICT; }
  "s_always"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yS_ALWAYS; }
  "s_eventually" 	{ FL; VALTEXT; CALLBACK(keywordCb); return yS_EVENTUALLY; }
  "s_nexttime"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yS_NEXTTIME; }
  "s_until"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yS_UNTIL; }
  "s_until_with" 	{ FL; VALTEXT; CALLBACK(keywordCb); return yS_UNTIL_WITH; }
  "strong"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return ySTRONG; }
  "sync_accept_on" 	{ FL; VALTEXT; CALLBACK(keywordCb); return ySYNC_ACCEPT_ON; }
  "sync_reject_on" 	{ FL; VALTEXT; CALLBACK(keywordCb); return ySYNC_REJECT_ON; }
  "unique0"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yUNIQUE0; }
  "until"		{ FL; VALTEXT; CALLBACK(keywordCb); return yUNTIL; }
  "until_with"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yUNTIL_WITH; }
  "untyped"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yUNTYPED; }
  "weak"            	{ FL; VALTEXT; CALLBACK(keywordCb); return yWEAK; }
}

  /* System Verilog 2012 */
<S12,S17>{
  /*     Keywords */
  "implements"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yIMPLEMENTS; }
  "interconnect" 	{ FL; VALTEXT; CALLBACK(keywordCb); return yINTERCONNECT; }
  "nettype"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return yNETTYPE; }
  "soft"	 	{ FL; VALTEXT; CALLBACK(keywordCb); return ySOFT; }
}

  /* System Verilog 2017 */
  /* No new keywords */

  /* Default PLI rule */
<V95,V01,V05,S05,S09,S12,S17>{
    "$"[a-zA-Z_$][a-zA-Z0-9_$]*	{ FL; VALTEXT; CALLBACK(sysfuncCb); return ygenSYSCALL; }
}

  /************************************************************************/

  /* Single character operator thingies */
<V95,V01,V05,S05,S09,S12,S17>{
  "{"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "}"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
}
<V95,V01,V05,S05,S09,S12,S17>{
  "!"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "#"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "$"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "%"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "&"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "("			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  ")"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "*"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "+"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  ","			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "-"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "."			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "/"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  ":"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  ";"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "<"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "="			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  ">"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "?"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "@"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "["			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "]"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "^"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "|"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
  "~"			{ FL; VALTEXT; CALLBACK(operatorCb); return yytext[0]; }
}

  /************************************************************************/
  /* Operators and multi-character symbols */

  /* Verilog 1995 Operators */
<V95,V01,V05,S05,S09,S12,S17>{
  "&&"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_ANDAND; }
  "||"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_OROR; }
  "<="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_LTE; }
  ">="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_GTE; }
  "<<"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_SLEFT; }
  ">>"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_SRIGHT; }
  "=="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_EQUAL; }
  "!="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_NOTEQUAL; }
  "==="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_CASEEQUAL; }
  "!=="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_CASENOTEQUAL; }
  "^~"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_XNOR; }
  "~^"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_XNOR; }
  "~&"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_NAND; }
  "~|"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_NOR; }
  "->"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_MINUSGT; }
  "=>"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_EQGT; }
  "*>"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_ASTGT; }
  "&&&"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_ANDANDAND; }
}

  /* Verilog 2001 Operators */
<V01,V05,S05,S09,S12,S17>{
  "<<<"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_SLEFT; }
  ">>>"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_SSRIGHT; }
  "**"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_POW; }
  "+:"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_PLUSCOLON; }
  "-:"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_MINUSCOLON; }
  ".*"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_DOTSTAR; }
}

  /* SystemVerilog 2005 Operators */
<S05,S09,S12,S17>{
  "'"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_TICK; }
  "'{"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_TICKBRA; }
  "==?"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_WILDEQUAL; }
  "!=?"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_WILDNOTEQUAL; }
  "++"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_PLUSPLUS; }
  "--"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_MINUSMINUS; }
  "+="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_PLUSEQ; }
  "-="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_MINUSEQ; }
  "*="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_TIMESEQ; }
  "/="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_DIVEQ; }
  "%="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_MODEQ; }
  "&="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_ANDEQ; }
  "|="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_OREQ; }
  "^="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_XOREQ; }
  "<<="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_SLEFTEQ; }
  ">>="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_SRIGHTEQ; }
  "<<<="		{ FL; VALTEXT; CALLBACK(operatorCb); return yP_SLEFTEQ; }
  ">>>="		{ FL; VALTEXT; CALLBACK(operatorCb); return yP_SSRIGHTEQ; }
  "->>"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_MINUSGTGT; }
  "##"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_POUNDPOUND; }
  "@@"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_ATAT; }
  "::"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_COLONCOLON; }
  ":="			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_COLONEQ; }
  ":/"[^\/\*]		{ FL; VALTEXT; CALLBACK(operatorCb); return yP_COLONDIV; }  /* : then comment is not ":/" */
  "|->"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_ORMINUSGT; }
  "|=>"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_OREQGT; }
  /* Some simulators allow whitespace here. Grr */
  "["{ws}*"*"		{ FL; VALTEXT; CALLBACK(operatorCb); return yP_BRASTAR; }
  "["{ws}*"="		{ FL; VALTEXT; CALLBACK(operatorCb); return yP_BRAEQ; }
  "["{ws}*"->"		{ FL; VALTEXT; CALLBACK(operatorCb); return yP_BRAMINUSGT; }
  "["{ws}*"+"{ws}*"]"	{ FL; VALTEXT; CALLBACK(operatorCb); return yP_BRAPLUSKET; }
}

  /* SystemVerilog 2009 Operators */
<S09,S12,S17>{
  "<->"			{ FL; VALTEXT; CALLBACK(operatorCb); return yP_LTMINUSGT; }
}

  /* Identifiers and numbers */
<V95,V01,V05,S05,S09,S12,S17>{
  /* Consume a following space, as we're going to add one to the symbol, we'd like to avoid inserting an extra */
  {escid}{space}	{ if (VParseLex::symEscapeless(yytext+1,yyleng-1-1)) {
			      string sym = string(yytext+1,yyleng-1-1);
			      FL; CALLBACKS(symbolCb, sym); VALTEXTS(sym); unput(' ');
			  } else {
			      string sym = string(yytext,yyleng-1) + ' ';
			      FL; CALLBACKS(symbolCb, sym); VALTEXTS(sym);
			  }
			  return yaID__LEX; }
  {escid}		{ if (VParseLex::symEscapeless(yytext+1,yyleng-1)) {
			      string sym = string(yytext+1,yyleng-1);
			      FL; CALLBACKS(symbolCb, sym); VALTEXTS(sym);
			  } else {
			      string sym = string(yytext,yyleng) + ' ';
			      FL; CALLBACKS(symbolCb, sym); VALTEXTS(sym);
			  }
			  return yaID__LEX; }
  {id}			{ FL; VALTEXT; CALLBACK(symbolCb); return yaID__LEX; }
  \"[^\"\\]*\"		{ FL; VALTEXT; CALLBACK(stringCb); return yaSTRING;
			}
  \" 			{ yy_push_state(STRING); yymore(); }

  {vnum} {
			  /* "# 1'b0" is a delay value so must lex as "#" "1" "'b0" */
			  if (LEXP->prevLexToken()=='#') {
			      int shortlen = 0;
			      while (isdigit(yytext[shortlen])) shortlen++;
			      if (shortlen) {
				  // Return is stuff before '
				  VALTEXTS(string(yytext,shortlen));
				  // Push rest for later parse
				  LEXP->unputString(yytext+shortlen, yyleng-shortlen);
				  FL; LINECHECKS(yytext,shortlen); CALLBACKS(numberCb,string(yytext,shortlen)); return yaINTNUM;
			      }
			  }
			  FL; VALTEXT; LINECHECK(); CALLBACK(numberCb); return yaINTNUM;
			}
  [0-9][_0-9]*		{
			  FL; VALTEXT; CALLBACK(numberCb); return yaINTNUM;
			}
  [0-9][_0-9]*(\.[_0-9]+)([eE][-+]?[_0-9]+)? {
                          FL; VALTEXT; CALLBACK(numberCb); return yaFLOATNUM;
			}
  [0-9][_0-9]*(\.[_0-9]+)?([eE][-+]?[_0-9]+) {
                          FL; VALTEXT; CALLBACK(numberCb); return yaFLOATNUM;
			}
  [0-9][_0-9]*(\.[_0-9]+)?(fs|ps|ns|us|ms|s|step) {
                          FL; VALTEXT; CALLBACK(numberCb); return yaTIMENUM;
			}
}

  /************************************************************************/
  /* STRINGS */
<STRING><<EOF>>		{ yyerrorf("EOF in unterminated string"); yyleng = 0; yy_pop_state(); }
<STRING>{crnl}		{ yyerrorf("Unterminated string"); NEXTLINE(); }
<STRING>\\{crnl}	{ yymore(); NEXTLINE(); }
<STRING>\\.	 	{ yymore(); }
<STRING>\" 		{ yy_pop_state();
			  FL; VALTEXT; CALLBACK(stringCb); return yaSTRING; }
<STRING>{word}		{ yymore(); }
<STRING>.		{ yymore(); }

  /************************************************************************/
  /* Multi-line COMMENTS */
<CMTMODE>"*"+[^*/\n]* 	{ yymore(); }
<CMTMODE>\n		{ yymore(); NEXTLINE(); }
<CMTMODE>"*"+"/"	{ VALTEXT; CALLBACK(commentCb); yy_pop_state(); } /* No FL; it's at comment begin */
<CMTMODE>{word}		{ yymore(); }
<CMTMODE>. 		{ yymore(); }
<CMTMODE><<EOF>>	{ yyerrorf("EOF in '/* ... */' block comment");
			  yyleng = 0; yy_pop_state(); }

  /************************************************************************/
  /* Protected */
<PROTMODE>\n		{ if (LPARSEP->useProtected()) yymore(); NEXTLINE(); }
<PROTMODE>"`endprotected"				{ FL; VALTEXT; CALLBACK(preprocCb); yy_pop_state(); }
<PROTMODE>"`pragma"{ws}+"protect"{ws}+"end_protected"	{ FL; VALTEXT; CALLBACK(preprocCb); yy_pop_state(); }
<PROTMODE>"//"{ws}*"pragma"{ws}+"protect"{ws}+"end_protected"  {
                          FL; VALTEXT; CALLBACK(preprocCb); yy_pop_state(); }
<PROTMODE>. 		{ if (LPARSEP->useProtected()) yymore(); }
<PROTMODE>{word}	{ if (LPARSEP->useProtected()) yymore(); }
<PROTMODE><<EOF>>	{ yyerrorf("EOF in `protected");
			  yyleng = 0; yy_pop_state(); }

  /************************************************************************/
  /* Attributes */
<ATTRMODE>{crnl}	{ yymore(); NEXTLINE(); }
<ATTRMODE>"*)"		{ FL; VALTEXT; CALLBACK(attributeCb); yy_pop_state(); }
<ATTRMODE>{word}	{ yymore(); }
<ATTRMODE>. 		{ yymore(); }
<ATTRMODE><<EOF>>	{ yyerrorf("EOF in (*");
			  yyleng = 0; yy_pop_state(); }

  /************************************************************************/
  /* Attributes */
  /* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */
<V95,V01,V05,S05,S09,S12,S17>{
    "(*"({ws}|{crnl})*({id}|{escid})	{ yymore(); yy_push_state(ATTRMODE); }	/* Doesn't match (*), but (* attr_spec */
}

  /************************************************************************/
  /* Preprocessor */
<V95,V01,V05,S05,S09,S12,S17>{
  "`accelerate"				{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`autoexpand_vectornets"		{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`celldefine"				{ FL; VALTEXT; CALLBACK(preprocCb); LEXP->m_inCellDefine=true; }
  "`default_decay_time"{ws}+[^\n\r]*	{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog spec - delays only
  "`default_nettype"{ws}+[a-zA-Z0-9]*	{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog 2001
  "`default_trireg_strength"{ws}+[^\n\r]*	{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog 2009
  "`delay_mode_distributed"		{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog spec - delays only
  "`delay_mode_path"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog spec - delays only
  "`delay_mode_unit"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog spec - delays only
  "`delay_mode_zero"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog spec - delays only
  "`disable_portfaults"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`enable_portfaults"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`endcelldefine"			{ FL; VALTEXT; CALLBACK(preprocCb); LEXP->m_inCellDefine=false; }
  "`endprotect"				{ FL; VALTEXT; CALLBACK(preprocCb); }
  "`expand_vectornets"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`inline"				{ FL; VALTEXT; CALLBACK(preprocCb); }
  "`line"{ws}+[^\n\r]*{crnl}		{ LPARSEP->inLineDirective(yytext); FL; VALTEXT; CALLBACK(preprocCb); }
  "`noaccelerate"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`noexpand_vectornets"		{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`noremove_gatenames"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`noremove_netnames"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`nosuppress_faults"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`nounconnected_drive"		{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`portcoerce"				{ FL; VALTEXT; CALLBACK(preprocCb); }
  "`pragma"{ws}+"protect"{ws}+"begin_protected"	{ FL; VALTEXT; CALLBACK(preprocCb); yy_push_state(PROTMODE); }
  "`pragma"{ws}+[^\n\r]*		{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog 2005
  "`protect"				{ FL; VALTEXT; CALLBACK(preprocCb); }
  "`protected"				{ FL; VALTEXT; CALLBACK(preprocCb); yy_push_state(PROTMODE); }
  "`remove_gatenames"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`remove_netnames"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`resetall"				{ FL; VALTEXT; CALLBACK(preprocCb); }
  "`suppress_faults"			{ FL; VALTEXT; CALLBACK(preprocCb); } // Verilog-XL compatibility
  "`timescale"{ws}+[^\n\r]*		{ FL; VALTEXT; CALLBACK(preprocCb); }

  /* See also setLanguage below */
  "`begin_keywords"[ \t]*\"1364-1995\"		{ yy_push_state(V95); CALLBACK(preprocCb); }
  "`begin_keywords"[ \t]*\"1364-2001\"		{ yy_push_state(V01); CALLBACK(preprocCb); }
  "`begin_keywords"[ \t]*\"1364-2001-noconfig\"	{ yy_push_state(V01); CALLBACK(preprocCb); }
  "`begin_keywords"[ \t]*\"1364-2005\"		{ yy_push_state(V05); CALLBACK(preprocCb); }
  "`begin_keywords"[ \t]*\"1800-2005\"		{ yy_push_state(S05); CALLBACK(preprocCb); }
  "`begin_keywords"[ \t]*\"1800-2009\"		{ yy_push_state(S09); CALLBACK(preprocCb); }
  "`begin_keywords"[ \t]*\"1800-2012\"		{ yy_push_state(S12); CALLBACK(preprocCb); }
  "`begin_keywords"[ \t]*\"1800-2017\"		{ yy_push_state(S17); CALLBACK(preprocCb); }
  "`end_keywords"				{ yy_pop_state();     CALLBACK(preprocCb); }
}

  /************************************************************************/
  /* Default rules - leave last */

<V95,V01,V05,S05,S09,S12,S17>{
  "`"[a-zA-Z_0-9]+	{ FL; VALTEXT;
			  if (LPARSEP->sigParser()) { yyerrorf("Define or directive not defined: %s",yytext); }
			  else { CALLBACK(preprocCb); } }
  "//"{ws}*"pragma"{ws}+"protect"{ws}+"begin_protected"   {
                          FL; CALLBACK(preprocCb); yy_push_state(PROTMODE); }
  "//"[^\n]*		{ FL; VALTEXT; CALLBACK(commentCb); }  /* throw away single line comments */
  "/*"		       	{ FL; yy_push_state(CMTMODE); yymore(); }  /* FL; marks start for COMMENT callback */
  .			{ FL; VALTEXT; CALLBACK(operatorCb); return ygenOPERATOR; } /* return single char ops. */
}

  /* Catch all - absolutely last */
<*>.|\n     		{ yyerrorf("Missing VParseLex.l rule: Default rule invoked in state %d: %s", YY_START, yytext); }
%%

void VParseLex::unputString(const char* textp) {
    s_currentLexp = this;
    // 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 VParseLex::unputString(const char* textp, size_t length) {
    s_currentLexp = this;
    // Add characters to input stream in back-to-front order
    const char* cp = textp;
    for (cp += length - 1; length--; cp--) {
	unput(*cp);
    }
}

void VParseLex::unused() {
    if (0) {
	// Prevent unused warnings
	yy_top_state();
    }
}

int VParseLex::yylexReadTok() {
    // Call yylex() remembering last non-whitespace token
    int token = yylex();
    m_prevLexToken = token;  // Save so can find '#' to parse following number
    return token;
}

int VParseLex::lexToken(VParseBisonYYSType* yylvalp) {
    // Fetch next token from prefetch or real lexer
    s_currentLexp = this;
    int token;
    if (m_ahead) {
	// We prefetched an extra token, give it back
	m_ahead = false;
	token = m_aheadToken;
	*yylvalp = m_aheadVal;
    } else {
	// Parse new token
	s_yylvalp = yylvalp;  // Read by yylex()
	token = yylexReadTok();
    }
    // If a paren, read another
    if (token == '('
	|| token == yCONST__LEX
	|| token == yGLOBAL__LEX
	|| token == yLOCAL__LEX
	|| token == yNEW__LEX
	|| token == ySTATIC__LEX
	|| token == yVIRTUAL__LEX
	|| token == yWITH__LEX
	// Never put yID_* here; below symbol table resolution would break
	) {
#ifdef FLEX_DEBUG
	if (yy_flex_debug) { cout<<"   lexToken: reading ahead to find possible strength"<<endl; }
#endif
	VParseBisonYYSType curValue = *s_yylvalp;  // Remember value, as about to read ahead
	int nexttok = yylexReadTok();
	m_ahead = true;
	m_aheadToken = nexttok;
	m_aheadVal = *s_yylvalp;
	*s_yylvalp = curValue;
	// Now potentially munge the current token
	if (token == '(' && (nexttok == ygenSTRENGTH
			     || nexttok == ySUPPLY0
			     || nexttok == ySUPPLY1)) {
	    token = yP_PAR__STRENGTH;
	}
	else if (token == yCONST__LEX) {
	    if (nexttok == yREF) token = yCONST__REF;
	    else token = yCONST__ETC;
	}
	else if (token == yGLOBAL__LEX) {
	    if (nexttok == yCLOCKING) token = yGLOBAL__CLOCKING;
	    else { token = yaID__LEX; s_yylvalp->str = "global"; }  // Avoid 2009 "global" conflicting with old code when we can
	}
	else if (token == yLOCAL__LEX) {
	    if (nexttok == yP_COLONCOLON) token = yLOCAL__COLONCOLON;
	    else token = yLOCAL__ETC;
	}
	else if (token == yNEW__LEX) {
	    if (nexttok == '(') token = yNEW__PAREN;
	    else token = yNEW__ETC;
	}
	else if (token == ySTATIC__LEX) {
	    if (nexttok == yCONSTRAINT) token = ySTATIC__CONSTRAINT;
	    else token = ySTATIC__ETC;
	}
	else if (token == yVIRTUAL__LEX) {
	    if (nexttok == yCLASS) token = yVIRTUAL__CLASS;
	    else if (nexttok == yINTERFACE) token = yVIRTUAL__INTERFACE;
	    else if (nexttok == yaID__ETC || nexttok == yaID__LEX)
		     // || nexttok == yaID__aINTERFACE	// but we may not know interfaces yet.
		token = yVIRTUAL__anyID;
	    else token = yVIRTUAL__ETC;
	}
	else if (token == yWITH__LEX) {
	    if (nexttok == '(') token = yWITH__PAREN;
	    else if (nexttok == '[') token = yWITH__BRA;
	    else if (nexttok == '{') token = yWITH__CUR;
	    else token = yWITH__ETC;
	}
	// If add to above "else if", also add to "if (token" further above
    }

    // Non-lookahead conversions
    // If a function/task convert token based on earlier detection of yPURE yVIRTUAL
    switch (token) {
    case yPURE:
	m_pvstate = 1;  // found pure
	break;
    case yVIRTUAL__ETC:
	if (m_pvstate == 1) m_pvstate = 2;  // found pure virtual
	else m_pvstate = 0;
	break;
    case yFUNCTION__LEX:
	token = (m_pvstate==2) ? yFUNCTION__aPUREV : yFUNCTION__ETC;
	m_pvstate = 0;
	break;
    case yTASK__LEX:
	token = (m_pvstate==2) ? yTASK__aPUREV : yTASK__ETC;
	m_pvstate = 0;
	break;
    case ';':  // Just to be safe
	m_pvstate = 0;
	break;
    default:
	if (m_pvstate == 1) m_pvstate = 0;
	break;
    }

    // If an id, change the type based on symbol table
    // Note above sometimes converts yGLOBAL to a yaID__LEX
    s_yylvalp->scp = NULL;
    if (token == yaID__LEX) {
	VAstEnt* scp;
	if (VAstEnt* look_underp = LPARSEP->symTableNextId()) {
	    if (yy_flex_debug) { cout<<"   lexToken: next id lookup forced under "<<look_underp
				     <<" for \""<<s_yylvalp->str<<"\""<<endl; }
	    scp = look_underp->findSym(s_yylvalp->str);
	    // "consume" it.  Must set again if want another token under temp scope
	    LPARSEP->symTableNextId(NULL);
	} else {
	    scp = LPARSEP->syms().findEntUpward(s_yylvalp->str);
	}
	if (scp) {
	    s_yylvalp->scp = scp;
	    switch (scp->type()) {
	    case VAstType::PACKAGE:	token = yaID__aPACKAGE;	    break;
	    case VAstType::CLASS:	token = yaID__aTYPE;	    break;
	    case VAstType::COVERGROUP:	token = yaID__aTYPE;	    break;
	    case VAstType::TYPE:	token = yaID__aTYPE;	    break;
	    default:			token = yaID__ETC;	    break;
	    }
	} else {  // Not found
	    token = yaID__ETC;
	}
    }
    return token;
}

int VParseLex::lexToBison(VParseBisonYYSType* yylvalp) {
    int tok = lexToken(yylvalp);
    if (yy_flex_debug || LPARSEP->debug()>=6) {  // When debugging flex OR bison
	string shortstr = yylvalp->str; if (shortstr.length()>20) shortstr = string(shortstr,20)+"...";
	cout<<"   lexToBison  TOKEN="<<tok<<" "<<VParseGrammar::tokenName(tok)<<" str=\""<<shortstr<<"\"";
	if (yylvalp->scp) cout<<"  scp="<<yylvalp->scp->ascii();
	cout<<endl;
    }
    return tok;
}

void VParseLex::debug(int level) {
#ifdef FLEX_DEBUG
    yy_flex_debug = level;
#endif
}

void VParseLex::language(const char* value) {
    if (0==strcmp(value,"1364-1995"))		{ BEGIN V95; }
    else if (0==strcmp(value,"1364-2001"))	{ BEGIN V01; }
    else if (0==strcmp(value,"1364-2001-noconfig")) { BEGIN V01; }
    else if (0==strcmp(value,"1364-2005"))	{ BEGIN V05; }
    else if (0==strcmp(value,"1800-2005"))	{ BEGIN S05; }
    else if (0==strcmp(value,"1800-2009"))	{ BEGIN S09; }
    else if (0==strcmp(value,"1800-2012"))	{ BEGIN S12; }
    else if (0==strcmp(value,"1800-2017"))	{ BEGIN S17; }
    else yyerrorf("Unknown setLanguage code: %s", value);
}

/*###################################################################
 * Local Variables:
 * mode: C++
 * End:
 */
