/* -*- C++ -*- */
/**************************************************************************
 * DESCRIPTION: Verilator: Flex input file
 *
 * Code available from: https://verilator.org
 *
 **************************************************************************
 *
 * Copyright 2003-2020 by Wilson Snyder.  Verilator 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.
 *
 *************************************************************************/

%option interactive c++ stack noyywrap
%{
/* %option nodefault */

#include "V3Number.h"
#include "V3ParseImp.h"  // Defines YYTYPE; before including bison header
#include "V3ParseBison.h"  // Generated by bison

#include <cstdlib>

extern void yyerror(const char*);
extern void yyerrorf(const char* format, ...);

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

#define PARSEP V3ParseImp::parsep()
#define SYMP PARSEP->symp()

#define YY_INPUT(buf,result,max_size) \
    result = PARSEP->flexPpInputToLex(buf, max_size);

//======================================================================

#define FL_FWD { PARSEP->fileline()->forwardToken(yytext, yyleng, true); }
// Use this to break between tokens whereever not return'ing a token (e.g. skipping inside lexer)
#define FL_BRK { PARSEP->fileline()->startToken(); }

#define CRELINE() (PARSEP->copyOrSameFileLine())

#define FL { FL_FWD; yylval.fl = CRELINE(); }

#define RETURN_BBOX_SYS_OR_MSG(msg,yytext) {    \
        if (!v3Global.opt.bboxSys()) { yyerrorf(msg, yytext); FL_BRK; }  \
        return yaD_IGNORE; }

#define ERROR_RSVD_WORD(language) \
        do { FL_FWD; \
             yyerrorf("Unsupported: " language " reserved word not implemented: '%s'", yytext); \
             FL_BRK; } while(0)

// See V3Read.cpp
//void V3ParseImp::statePop() { yy_pop_state(); }

//======================================================================

void yyerror(const char* errmsg) {
    PARSEP->fileline()->v3error(errmsg);
    static const char* const colonmsg = "syntax error, unexpected ::, ";
    //tokens;
    if (0==strncmp(errmsg, colonmsg, strlen(colonmsg))
        && PARSEP->prevBisonVal().token == yaID__ETC
        && PARSEP->curBisonVal().token == yP_COLONCOLON) {
        static int warned = false;
        if (!warned++) {
            std::cerr<<PARSEP->fileline()->warnMore()
                     <<("... Perhaps '"+*PARSEP->prevBisonVal().strp
                        +"' is a package which needs to be predeclared? (IEEE 2017 26.3)")
                     <<std::endl;
        }
    }
}

void yyerrorf(const char* format, ...) {
    const int maxlen = 2000;
    char msg[maxlen];

    va_list ap;
    va_start(ap, format);
    VL_VSNPRINTF(msg, maxlen, format, ap);
    msg[maxlen-1] = '\0';
    va_end(ap);

    yyerror(msg);
}

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

%e 2000
%p 5000
%n 2500
%k 1000
%a 15000
%o 25000

%s V95 V01 V05 S05 S09 S12 S17
%s STRING ATTRMODE TABLE
%s VA5 SAX VLT
%s SYSCHDR SYSCINT SYSCIMP SYSCIMPH SYSCCTOR SYSCDTOR
%s IGNORE

ws      [ \t\f\r]+
wsnr    [ \t\f]+
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); }

  /************************************************************************/
  /* Verilator control files */
<VLT>{
  {ws}                  { FL_FWD; FL_BRK; }  /* otherwise ignore white-space */
  {crnl}                { FL_FWD; FL_BRK; }  /* Count line numbers */

  "clock_enable"        { FL; return yVLT_CLOCK_ENABLE; }
  "clocker"             { FL; return yVLT_CLOCKER; }
  "coverage_block_off"  { FL; return yVLT_COVERAGE_BLOCK_OFF; }
  "coverage_off"        { FL; return yVLT_COVERAGE_OFF; }
  "coverage_on"         { FL; return yVLT_COVERAGE_ON; }
  "full_case"           { FL; return yVLT_FULL_CASE; }
  "inline"              { FL; return yVLT_INLINE; }
  "isolate_assignments" { FL; return yVLT_ISOLATE_ASSIGNMENTS; }
  "lint_off"            { FL; return yVLT_LINT_OFF; }
  "lint_on"             { FL; return yVLT_LINT_ON; }
  "no_clocker"          { FL; return yVLT_NO_CLOCKER; }
  "no_inline"           { FL; return yVLT_NO_INLINE; }
  "parallel_case"       { FL; return yVLT_PARALLEL_CASE; }
  "public"              { FL; return yVLT_PUBLIC; }
  "public_flat"         { FL; return yVLT_PUBLIC_FLAT; }
  "public_flat_rd"      { FL; return yVLT_PUBLIC_FLAT_RD; }
  "public_flat_rw"      { FL; return yVLT_PUBLIC_FLAT_RW; }
  "public_module"       { FL; return yVLT_PUBLIC_MODULE; }
  "sc_bv"               { FL; return yVLT_SC_BV; }
  "sformat"             { FL; return yVLT_SFORMAT; }
  "tracing_off"         { FL; return yVLT_TRACING_OFF; }
  "tracing_on"          { FL; return yVLT_TRACING_ON; }

  -?"-block"            { FL; return yVLT_D_BLOCK; }
  -?"-file"             { FL; return yVLT_D_FILE; }
  -?"-function"         { FL; return yVLT_D_FUNCTION; }
  -?"-lines"            { FL; return yVLT_D_LINES; }
  -?"-match"            { FL; return yVLT_D_MATCH; }
  -?"-module"           { FL; return yVLT_D_MODULE; }
  -?"-msg"              { FL; return yVLT_D_MSG; }
  -?"-rule"             { FL; return yVLT_D_RULE; }
  -?"-task"             { FL; return yVLT_D_TASK; }
  -?"-var"              { FL; return yVLT_D_VAR; }

  /* Reachable by attr_event_control */
  "edge"                { FL; return yEDGE; }
  "negedge"             { FL; return yNEGEDGE; }
  "or"                  { FL; return yOR; }
  "posedge"             { FL; return yPOSEDGE; }
}

  /************************************************************************/
  /* Verilog 1995 */
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX>{
  {ws}                  { FL_FWD; FL_BRK; }  /* otherwise ignore white-space */
  {crnl}                { FL_FWD; FL_BRK; }  /* Count line numbers */
  /*     Extensions to Verilog set, some specified by PSL */
  "$c"[0-9]*            { FL; return yD_C; }  /*Verilator only*/
  /*     System Tasks */
  "$acos"               { FL; return yD_ACOS; }
  "$acosh"              { FL; return yD_ACOSH; }
  "$asin"               { FL; return yD_ASIN; }
  "$asinh"              { FL; return yD_ASINH; }
  "$atan"               { FL; return yD_ATAN; }
  "$atan2"              { FL; return yD_ATAN2; }
  "$atanh"              { FL; return yD_ATANH; }
  "$bitstoreal"         { FL; return yD_BITSTOREAL; }
  "$bitstoshortreal"    { FL; return yD_BITSTOSHORTREAL; }
  "$ceil"               { FL; return yD_CEIL; }
  "$cos"                { FL; return yD_COS; }
  "$cosh"               { FL; return yD_COSH; }
  "$display"            { FL; return yD_DISPLAY; }
  "$exp"                { FL; return yD_EXP; }
  "$fclose"             { FL; return yD_FCLOSE; }
  "$fdisplay"           { FL; return yD_FDISPLAY; }
  "$feof"               { FL; return yD_FEOF; }
  "$fflush"             { FL; return yD_FFLUSH; }
  "$fgetc"              { FL; return yD_FGETC; }
  "$fgets"              { FL; return yD_FGETS; }
  "$finish"             { FL; return yD_FINISH; }
  "$floor"              { FL; return yD_FLOOR; }
  "$fopen"              { FL; return yD_FOPEN; }
  "$fread"              { FL; return yD_FREAD; }
  "$fscanf"             { FL; return yD_FSCANF; }
  "$fseek"              { FL; return yD_FSEEK; }
  "$ftell"              { FL; return yD_FTELL; }
  "$frewind"            { FL; return yD_FREWIND; }
  "$fullskew"           { FL; return yaTIMINGSPEC; }
  "$fwrite"             { FL; return yD_FWRITE; }
  "$hold"               { FL; return yaTIMINGSPEC; }
  "$hypot"              { FL; return yD_HYPOT; }
  "$itor"               { FL; return yD_ITOR; }
  "$ln"                 { FL; return yD_LN; }
  "$log10"              { FL; return yD_LOG10; }
  "$nochange"           { FL; return yaTIMINGSPEC; }
  "$period"             { FL; return yaTIMINGSPEC; }
  "$pow"                { FL; return yD_POW; }
  "$random"             { FL; return yD_RANDOM; }
  "$readmemb"           { FL; return yD_READMEMB; }
  "$readmemh"           { FL; return yD_READMEMH; }
  "$realtime"           { FL; return yD_REALTIME; }
  "$realtobits"         { FL; return yD_REALTOBITS; }
  "$recovery"           { FL; return yaTIMINGSPEC; }
  "$recrem"             { FL; return yaTIMINGSPEC; }
  "$removal"            { FL; return yaTIMINGSPEC; }
  "$rewind"             { FL; return yD_REWIND; }
  "$rtoi"               { FL; return yD_RTOI; }
  "$setup"              { FL; return yaTIMINGSPEC; }
  "$setuphold"          { FL; return yaTIMINGSPEC; }
  "$sampled"            { FL; return yD_SAMPLED; }
  "$sformat"            { FL; return yD_SFORMAT; }
  "$sformatf"           { FL; return yD_SFORMATF; }
  "$shortrealtobits"    { FL; return yD_SHORTREALTOBITS; }
  "$sin"                { FL; return yD_SIN; }
  "$sinh"               { FL; return yD_SINH; }
  "$skew"               { FL; return yaTIMINGSPEC; }
  "$sqrt"               { FL; return yD_SQRT; }
  "$sscanf"             { FL; return yD_SSCANF; }
  "$stime"              { FL; return yD_STIME; }
  "$stop"               { FL; return yD_STOP; }
  "$swrite"             { FL; return yD_SWRITE; }
  "$system"             { FL; return yD_SYSTEM; }
  "$tan"                { FL; return yD_TAN; }
  "$tanh"               { FL; return yD_TANH; }
  "$test$plusargs"      { FL; return yD_TESTPLUSARGS; }
  "$time"               { FL; return yD_TIME; }
  "$timeskew"           { FL; return yaTIMINGSPEC; }
  "$typename"           { FL; return yD_TYPENAME; }
  "$ungetc"             { FL; return yD_UNGETC; }
  "$value$plusargs"     { FL; return yD_VALUEPLUSARGS; }
  "$width"              { FL; return yaTIMINGSPEC; }
  "$write"              { FL; return yD_WRITE; }
  "$writememh"          { FL; return yD_WRITEMEMH; }
  /*     Keywords */
  "always"              { FL; return yALWAYS; }
  "and"                 { FL; return yAND; }
  "assign"              { FL; return yASSIGN; }
  "begin"               { FL; return yBEGIN; }
  "buf"                 { FL; return yBUF; }
  "bufif0"              { FL; return yBUFIF0; }
  "bufif1"              { FL; return yBUFIF1; }
  "case"                { FL; return yCASE; }
  "casex"               { FL; return yCASEX; }
  "casez"               { FL; return yCASEZ; }
  "cmos"                { FL; return yCMOS; }
  "deassign"            { FL; return yDEASSIGN; }
  "default"             { FL; return yDEFAULT; }
  "defparam"            { FL; return yDEFPARAM; }
  "disable"             { FL; return yDISABLE; }
  "edge"                { FL; return yEDGE; }
  "else"                { FL; return yELSE; }
  "end"                 { FL; return yEND; }
  "endcase"             { FL; return yENDCASE; }
  "endfunction"         { FL; return yENDFUNCTION; }
  "endmodule"           { FL; return yENDMODULE; }
  "endprimitive"        { FL; return yENDPRIMITIVE; }
  "endspecify"          { FL; return yENDSPECIFY; }
  "endtable"            { FL_FWD; yyerrorf("Syntax error: ENDTABLE outside of TABLE"); FL_BRK; }
  "endtask"             { FL; return yENDTASK; }
  "event"               { FL; return yEVENT; }
  "for"                 { FL; return yFOR; }
  "force"               { FL; return yFORCE; }
  "foreach"             { FL; return yFOREACH; }
  "forever"             { FL; return yFOREVER; }
  "fork"                { FL; return yFORK; }
  "function"            { FL; return yFUNCTION; }
  "highz0"              { FL; return ygenSTRENGTH; }
  "highz1"              { FL; return ygenSTRENGTH; }
  "if"                  { FL; return yIF; }
  "initial"             { FL; return yINITIAL; }
  "inout"               { FL; return yINOUT; }
  "input"               { FL; return yINPUT; }
  "integer"             { FL; return yINTEGER; }
  "join"                { FL; return yJOIN; }
  "large"               { FL; return ygenSTRENGTH; }
  "macromodule"         { FL; return yMODULE; }
  "medium"              { FL; return ygenSTRENGTH; }
  "module"              { FL; return yMODULE; }
  "nand"                { FL; return yNAND; }
  "negedge"             { FL; return yNEGEDGE; }
  "nmos"                { FL; return yNMOS; }
  "nor"                 { FL; return yNOR; }
  "not"                 { FL; return yNOT; }
  "notif0"              { FL; return yNOTIF0; }
  "notif1"              { FL; return yNOTIF1; }
  "or"                  { FL; return yOR; }
  "output"              { FL; return yOUTPUT; }
  "parameter"           { FL; return yPARAMETER; }
  "pmos"                { FL; return yPMOS; }
  "posedge"             { FL; return yPOSEDGE; }
  "primitive"           { FL; return yPRIMITIVE; }
  "pull0"               { FL; return ygenSTRENGTH; }
  "pull1"               { FL; return ygenSTRENGTH; }
  "pulldown"            { FL; return yPULLDOWN; }
  "pullup"              { FL; return yPULLUP; }
  "rcmos"               { FL; return yRCMOS; }
  "real"                { FL; return yREAL; }
  "realtime"            { FL; return yREALTIME; }
  "reg"                 { FL; return yREG; }
  "release"             { FL; return yRELEASE; }
  "repeat"              { FL; return yREPEAT; }
  "rnmos"               { FL; return yRNMOS; }
  "rpmos"               { FL; return yRPMOS; }
  "rtran"               { FL; return yRTRAN; }
  "rtranif0"            { FL; return yRTRANIF0; }
  "rtranif1"            { FL; return yRTRANIF1; }
  "scalared"            { FL; return ySCALARED; }
  "small"               { FL; return ygenSTRENGTH; }
  "specify"             { FL; return ySPECIFY; }
  "specparam"           { FL; return ySPECPARAM; }
  "strong0"             { FL; return ygenSTRENGTH; }
  "strong1"             { FL; return ygenSTRENGTH; }
  "supply0"             { FL; return ySUPPLY0; }
  "supply1"             { FL; return ySUPPLY1; }
  "table"               { FL; yy_push_state(TABLE); return yTABLE; }
  "task"                { FL; return yTASK; }
  "time"                { FL; return yTIME; }
  "tran"                { FL; return yTRAN; }
  "tranif0"             { FL; return yTRANIF0; }
  "tranif1"             { FL; return yTRANIF1; }
  "tri"                 { FL; return yTRI; }
  "tri0"                { FL; return yTRI0; }
  "tri1"                { FL; return yTRI1; }
  "triand"              { FL; return yTRIAND; }
  "trior"               { FL; return yTRIOR; }
  "trireg"              { FL; return yTRIREG; }
  "vectored"            { FL; return yVECTORED; }
  "wait"                { FL; return yWAIT; }
  "wand"                { FL; return yWAND; }
  "weak0"               { FL; return ygenSTRENGTH; }
  "weak1"               { FL; return ygenSTRENGTH; }
  "while"               { FL; return yWHILE; }
  "wire"                { FL; return yWIRE; }
  "wor"                 { FL; return yWOR; }
  "xnor"                { FL; return yXNOR; }
  "xor"                 { FL; return yXOR; }
  /*     Special errors */
  "$displayb"           { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%b format instead: %s", yytext); }
  "$displayh"           { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%x format instead: %s", yytext); }
  "$displayo"           { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%o format instead: %s", yytext); }
  "$fdisplayb"          { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%b format instead: %s", yytext); }
  "$fdisplayh"          { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%x format instead: %s", yytext); }
  "$fdisplayo"          { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%o format instead: %s", yytext); }
  "$fwriteb"            { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%b format instead: %s", yytext); }
  "$fwriteh"            { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%x format instead: %s", yytext); }
  "$fwriteo"            { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%o format instead: %s", yytext); }
  "$writeb"             { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%b format instead: %s", yytext); }
  "$writeh"             { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%x format instead: %s", yytext); }
  "$writeo"             { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%o format instead: %s", yytext); }
}

  /* Verilog 2001 */
<V01,V05,VA5,S05,S09,S12,S17,SAX>{
  /*     System Tasks */
  "$signed"             { FL; return yD_SIGNED; }
  "$unsigned"           { FL; return yD_UNSIGNED; }
  /*     Keywords */
  "automatic"           { FL; return yAUTOMATIC; }
  "endgenerate"         { FL; return yENDGENERATE; }
  "generate"            { FL; return yGENERATE; }
  "genvar"              { FL; return yGENVAR; }
  "ifnone"              { FL; return yaTIMINGSPEC; }
  "localparam"          { FL; return yLOCALPARAM; }
  "noshowcancelled"     { FL; return yaTIMINGSPEC; }
  "pulsestyle_ondetect" { FL; return yaTIMINGSPEC; }
  "pulsestyle_onevent"  { FL; return yaTIMINGSPEC; }
  "showcancelled"       { FL; return yaTIMINGSPEC; }
  "signed"              { FL; return ySIGNED; }
  "unsigned"            { FL; return yUNSIGNED; }
  /*     Generic unsupported keywords */
  "cell"                { ERROR_RSVD_WORD("Verilog 2001-config"); }
  "config"              { ERROR_RSVD_WORD("Verilog 2001-config"); }
  "design"              { ERROR_RSVD_WORD("Verilog 2001-config"); }
  "endconfig"           { ERROR_RSVD_WORD("Verilog 2001-config"); }
  "incdir"              { ERROR_RSVD_WORD("Verilog 2001-config"); }
  "include"             { FL_FWD; yyerrorf("Unsupported: Verilog 2001-config reserved word not implemented; suggest you want `include instead: %s", yytext); FL_BRK; }
  "instance"            { ERROR_RSVD_WORD("Verilog 2001-config"); }
  "liblist"             { ERROR_RSVD_WORD("Verilog 2001-config"); }
  "library"             { ERROR_RSVD_WORD("Verilog 2001-config"); }
  "use"                 { ERROR_RSVD_WORD("Verilog 2001-config"); }
}

  /* Verilog 2005 */
<V05,S05,S09,S12,S17,SAX>{
  /*     System Tasks */
  "$clog2"              { FL; return yD_CLOG2; }
  /*     Keywords */
  "uwire"               { FL; return yWIRE; }
}

  /* System Verilog 2005 */
<S05,S09,S12,S17,SAX>{
  /*     System Tasks */
  "$bits"               { FL; return yD_BITS; }
  "$countones"          { FL; return yD_COUNTONES; }
  "$dimensions"         { FL; return yD_DIMENSIONS; }
  "$error"              { FL; return yD_ERROR; }
  "$fatal"              { FL; return yD_FATAL; }
  "$high"               { FL; return yD_HIGH; }
  "$increment"          { FL; return yD_INCREMENT; }
  "$info"               { FL; return yD_INFO; }
  "$isunknown"          { FL; return yD_ISUNKNOWN; }
  "$left"               { FL; return yD_LEFT; }
  "$low"                { FL; return yD_LOW; }
  "$onehot"             { FL; return yD_ONEHOT; }
  "$onehot0"            { FL; return yD_ONEHOT0; }
  "$past"               { FL; return yD_PAST; }
  "$right"              { FL; return yD_RIGHT; }
  "$size"               { FL; return yD_SIZE; }
  "$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; }
  "$warning"            { FL; return yD_WARNING; }
  /*     SV2005 Keywords */
  "$unit"               { FL; return yD_UNIT; }  /* Yes, a keyword, not task */
  "alias"               { FL; return yALIAS; }
  "always_comb"         { FL; return yALWAYS_COMB; }
  "always_ff"           { FL; return yALWAYS_FF; }
  "always_latch"        { FL; return yALWAYS_LATCH; }
  "assert"              { FL; return yASSERT; }
  "assume"              { FL; return yASSUME; }
  "bind"                { FL; return yBIND; }
  "bit"                 { FL; return yBIT; }
  "break"               { FL; return yBREAK; }
  "byte"                { FL; return yBYTE; }
  "chandle"             { FL; return yCHANDLE; }
  "class"               { FL; return yCLASS; }
  "clocking"            { FL; return yCLOCKING; }
  "const"               { FL; return yCONST__LEX; }
  "context"             { FL; return yCONTEXT; }
  "continue"            { FL; return yCONTINUE; }
  "cover"               { FL; return yCOVER; }
  "do"                  { FL; return yDO; }
  "endclass"            { FL; return yENDCLASS; }
  "endclocking"         { FL; return yENDCLOCKING; }
  "endinterface"        { FL; return yENDINTERFACE; }
  "endpackage"          { FL; return yENDPACKAGE; }
  "endprogram"          { FL; return yENDPROGRAM; }
  "endproperty"         { FL; return yENDPROPERTY; }
  "enum"                { FL; return yENUM; }
  "export"              { FL; return yEXPORT; }
  "extends"             { FL; return yEXTENDS; }
  "extern"              { FL; return yEXTERN; }
  "final"               { FL; return yFINAL; }
  "forkjoin"            { FL; return yFORKJOIN; }
  "iff"                 { FL; return yIFF; }
  "import"              { FL; return yIMPORT; }
  "inside"              { FL; return yINSIDE; }
  "int"                 { FL; return yINT; }
  "interface"           { FL; return yINTERFACE; }
  "join_any"            { FL; return yJOIN_ANY; }
  "join_none"           { FL; return yJOIN_NONE; }
  "local"               { FL; return yLOCAL__LEX; }
  "logic"               { FL; return yLOGIC; }
  "longint"             { FL; return yLONGINT; }
  "modport"             { FL; return yMODPORT; }
  "new"                 { FL; return yNEW__LEX; }
  "null"                { FL; return yNULL; }
  "package"             { FL; return yPACKAGE; }
  "packed"              { FL; return yPACKED; }
  "priority"            { FL; return yPRIORITY; }
  "program"             { FL; return yPROGRAM; }
  "property"            { FL; return yPROPERTY; }
  "protected"           { FL; return yPROTECTED; }
  "pure"                { FL; return yPURE; }
  "rand"                { FL; return yRAND; }
  "randc"               { FL; return yRANDC; }
  "randcase"            { FL; return yRANDCASE; }
  "ref"                 { FL; return yREF; }
  "restrict"            { FL; return yRESTRICT; }
  "return"              { FL; return yRETURN; }
  "shortint"            { FL; return ySHORTINT; }
  "shortreal"           { FL; return ySHORTREAL; }
  "static"              { FL; return ySTATIC__ETC; }
  "string"              { FL; return ySTRING; }
  "struct"              { FL; return ySTRUCT; }
  "super"               { FL; return ySUPER; }
  "this"                { FL; return yTHIS; }
  "timeprecision"       { FL; return yTIMEPRECISION; }
  "timeunit"            { FL; return yTIMEUNIT; }
  "type"                { FL; return yTYPE; }
  "typedef"             { FL; return yTYPEDEF; }
  "union"               { FL; return yUNION; }
  "unique"              { FL; return yUNIQUE; }
  "var"                 { FL; return yVAR; }
  "virtual"             { FL; return yVIRTUAL__LEX; }
  "void"                { FL; return yVOID; }
  /*     Generic unsupported warnings */
  /* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */
  "$root"               { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "before"              { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "bins"                { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "binsof"              { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "constraint"          { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "covergroup"          { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "coverpoint"          { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "cross"               { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "dist"                { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "endgroup"            { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "endsequence"         { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "expect"              { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "first_match"         { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "ignore_bins"         { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "illegal_bins"        { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "intersect"           { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "matches"             { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "randomize"           { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "randsequence"        { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "sequence"            { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "solve"               { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "tagged"              { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "throughout"          { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "wait_order"          { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "wildcard"            { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "with"                { ERROR_RSVD_WORD("SystemVerilog 2005"); }
  "within"              { ERROR_RSVD_WORD("SystemVerilog 2005"); }
}

  /* SystemVerilog 2009 */
<S09,S12,S17,SAX>{
  /*     Keywords */
  "global"              { FL; return yGLOBAL__LEX; }
  "unique0"             { FL; return yUNIQUE0; }
  /*     Generic unsupported warnings */
  "accept_on"           { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "checker"             { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "endchecker"          { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "eventually"          { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "implies"             { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "let"                 { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "nexttime"            { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "reject_on"           { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "s_always"            { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "s_eventually"        { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "s_nexttime"          { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "s_until"             { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "s_until_with"        { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "strong"              { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "sync_accept_on"      { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "sync_reject_on"      { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "until"               { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "until_with"          { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "untyped"             { ERROR_RSVD_WORD("SystemVerilog 2009"); }
  "weak"                { ERROR_RSVD_WORD("SystemVerilog 2009"); }
}

  /* System Verilog 2012 */
<S12,S17,SAX>{
  /*     Keywords */
  "implements"          { FL; return yIMPLEMENTS; }
  "interconnect"        { ERROR_RSVD_WORD("SystemVerilog 2012"); }
  "nettype"             { ERROR_RSVD_WORD("SystemVerilog 2012"); }
  "soft"                { ERROR_RSVD_WORD("SystemVerilog 2012"); }
}

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

  /* Default PLI rule */
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX>{
  "$"[a-zA-Z_$][a-zA-Z0-9_$]*   { string str (yytext, yyleng);
                                  yylval.strp = PARSEP->newString(AstNode::encodeName(str));
                                  // Lookup unencoded name including the $, to avoid hitting normal signals
                                  if (SYMP->symCurrentp()->findIdFallback(str)) {
                                      FL; return yaD_DPI;
                                  } else { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported or unknown PLI call: %s", yytext); }
                                }
}

  /************************************************************************/
  /* AMS */

<VA5,SAX>{
  /*     Generic unsupported warnings */
   "above"              { ERROR_RSVD_WORD("AMS"); }
   "abs"                { ERROR_RSVD_WORD("AMS"); }
   "absdelay"           { ERROR_RSVD_WORD("AMS"); }
   "abstol"             { ERROR_RSVD_WORD("AMS"); }
   "ac_stim"            { ERROR_RSVD_WORD("AMS"); }
   "access"             { ERROR_RSVD_WORD("AMS"); }
   "acos"               { ERROR_RSVD_WORD("AMS"); }
   "acosh"              { ERROR_RSVD_WORD("AMS"); }
   "aliasparam"         { ERROR_RSVD_WORD("AMS"); }
   "analog"             { ERROR_RSVD_WORD("AMS"); }
   "analysis"           { ERROR_RSVD_WORD("AMS"); }
   "asin"               { FL; return yD_ASIN; }
   "asinh"              { FL; return yD_ASINH; }
   "assert"             { ERROR_RSVD_WORD("AMS"); }
   "atan"               { FL; return yD_ATAN; }
   "atan2"              { FL; return yD_ATAN2; }
   "atanh"              { FL; return yD_ATANH; }
   "branch"             { ERROR_RSVD_WORD("AMS"); }
   "ceil"               { FL; return yD_CEIL; }
   "connect"            { ERROR_RSVD_WORD("AMS"); }
   "connectmodule"      { ERROR_RSVD_WORD("AMS"); }
   "connectrules"       { ERROR_RSVD_WORD("AMS"); }
   "continuous"         { ERROR_RSVD_WORD("AMS"); }
   "cos"                { FL; return yD_COS; }
   "cosh"               { FL; return yD_COSH; }
   "cross"              { ERROR_RSVD_WORD("AMS"); }
   "ddt"                { ERROR_RSVD_WORD("AMS"); }
   "ddt_nature"         { ERROR_RSVD_WORD("AMS"); }
   "ddx"                { ERROR_RSVD_WORD("AMS"); }
   "discipline"         { ERROR_RSVD_WORD("AMS"); }
   "discrete"           { ERROR_RSVD_WORD("AMS"); }
   "domain"             { ERROR_RSVD_WORD("AMS"); }
   "driver_update"      { ERROR_RSVD_WORD("AMS"); }
   "endconnectrules"    { ERROR_RSVD_WORD("AMS"); }
   "enddiscipline"      { ERROR_RSVD_WORD("AMS"); }
   "endnature"          { ERROR_RSVD_WORD("AMS"); }
   "endparamset"        { ERROR_RSVD_WORD("AMS"); }
   "exclude"            { ERROR_RSVD_WORD("AMS"); }
   "exp"                { FL; return yD_EXP; }
   "final_step"         { ERROR_RSVD_WORD("AMS"); }
   "flicker_noise"      { ERROR_RSVD_WORD("AMS"); }
   "floor"              { FL; return yD_FLOOR; }
   "flow"               { ERROR_RSVD_WORD("AMS"); }
   "from"               { ERROR_RSVD_WORD("AMS"); }
   "ground"             { ERROR_RSVD_WORD("AMS"); }
   "hypot"              { FL; return yD_HYPOT; }
   "idt"                { ERROR_RSVD_WORD("AMS"); }
   "idt_nature"         { ERROR_RSVD_WORD("AMS"); }
   "idtmod"             { ERROR_RSVD_WORD("AMS"); }
   "inf"                { ERROR_RSVD_WORD("AMS"); }
   "initial_step"       { ERROR_RSVD_WORD("AMS"); }
   "laplace_nd"         { ERROR_RSVD_WORD("AMS"); }
   "laplace_np"         { ERROR_RSVD_WORD("AMS"); }
   "laplace_zd"         { ERROR_RSVD_WORD("AMS"); }
   "laplace_zp"         { ERROR_RSVD_WORD("AMS"); }
   "last_crossing"      { ERROR_RSVD_WORD("AMS"); }
   "limexp"             { ERROR_RSVD_WORD("AMS"); }
   "ln"                 { FL; return yD_LN; }
   "log"                { FL; return yD_LOG10; }
   "max"                { ERROR_RSVD_WORD("AMS"); }
   "merged"             { ERROR_RSVD_WORD("AMS"); }
   "min"                { ERROR_RSVD_WORD("AMS"); }
   "nature"             { ERROR_RSVD_WORD("AMS"); }
   "net_resolution"     { ERROR_RSVD_WORD("AMS"); }
   "noise_table"        { ERROR_RSVD_WORD("AMS"); }
   "paramset"           { ERROR_RSVD_WORD("AMS"); }
   "potential"          { ERROR_RSVD_WORD("AMS"); }
   "pow"                { FL; return yD_POW; }
   "resolveto"          { ERROR_RSVD_WORD("AMS"); }
   "sin"                { FL; return yD_SIN; }
   "sinh"               { FL; return yD_SINH; }
   "slew"               { ERROR_RSVD_WORD("AMS"); }
   "split"              { ERROR_RSVD_WORD("AMS"); }
   "sqrt"               { FL; return yD_SQRT; }
   "string"             { FL; return ySTRING; }
   "tan"                { FL; return yD_TAN; }
   "tanh"               { FL; return yD_TANH; }
   "timer"              { ERROR_RSVD_WORD("AMS"); }
   "transition"         { ERROR_RSVD_WORD("AMS"); }
   "units"              { ERROR_RSVD_WORD("AMS"); }
   "white_noise"        { ERROR_RSVD_WORD("AMS"); }
   "wreal"              { FL; return yWREAL; }
   "zi_nd"              { ERROR_RSVD_WORD("AMS"); }
   "zi_np"              { ERROR_RSVD_WORD("AMS"); }
   "zi_zd"              { ERROR_RSVD_WORD("AMS"); }
   "zi_zp"              { ERROR_RSVD_WORD("AMS"); }
}

  /************************************************************************/
  /* Meta comments */

  /* Converted from //{cmt}verilator ...{cmt} by preprocessor */
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX>{
  "/*verilator"{ws}*"*/"                { FL_FWD; FL_BRK; }  /* Ignore empty comments, may be `endif // verilator */
  "/*verilator clock_enable*/"          { FL; return yVL_CLOCK_ENABLE; }
  "/*verilator coverage_block_off*/"    { FL; return yVL_COVERAGE_BLOCK_OFF; }
  "/*verilator full_case*/"             { FL; return yVL_FULL_CASE; }
  "/*verilator inline_module*/"         { FL; return yVL_INLINE_MODULE; }
  "/*verilator isolate_assignments*/"   { FL; return yVL_ISOLATE_ASSIGNMENTS; }
  "/*verilator no_inline_module*/"      { FL; return yVL_NO_INLINE_MODULE; }
  "/*verilator no_inline_task*/"        { FL; return yVL_NO_INLINE_TASK; }
  "/*verilator parallel_case*/"         { FL; return yVL_PARALLEL_CASE; }
  "/*verilator public*/"                { FL; return yVL_PUBLIC; }
  "/*verilator public_flat*/"           { FL; return yVL_PUBLIC_FLAT; }
  "/*verilator public_flat_rd*/"        { FL; return yVL_PUBLIC_FLAT_RD; }
  "/*verilator public_flat_rw*/"        { FL; return yVL_PUBLIC_FLAT_RW; }  // The @(edge) is converted by the preproc
  "/*verilator public_module*/"         { FL; return yVL_PUBLIC_MODULE; }
  "/*verilator sc_clock*/"              { FL; return yVL_CLOCK; }
  "/*verilator clocker*/"               { FL; return yVL_CLOCKER; }
  "/*verilator no_clocker*/"            { FL; return yVL_NO_CLOCKER; }
  "/*verilator sc_bv*/"                 { FL; return yVL_SC_BV; }
  "/*verilator sformat*/"               { FL; return yVL_SFORMAT; }
  "/*verilator systemc_clock*/"         { FL; return yVL_CLOCK; }
  "/*verilator tracing_off*/"           { FL_FWD; PARSEP->fileline()->tracingOn(false); FL_BRK; }
  "/*verilator tracing_on*/"            { FL_FWD; PARSEP->fileline()->tracingOn(true); FL_BRK; }
  "/*verilator coverage_off*/"          { FL_FWD; PARSEP->fileline()->coverageOn(false); FL_BRK; }
  "/*verilator coverage_on*/"           { FL_FWD; PARSEP->fileline()->coverageOn(true); FL_BRK; }
  "/*verilator lint_off"[^*]*"*/"       { FL_FWD; PARSEP->verilatorCmtLint(yytext, true); FL_BRK; }
  "/*verilator lint_on"[^*]*"*/"        { FL_FWD; PARSEP->verilatorCmtLint(yytext, false); FL_BRK; }
  "/*verilator lint_restore*/"          { FL_FWD; PARSEP->verilatorCmtLintRestore(); FL_BRK; }
  "/*verilator lint_save*/"             { FL_FWD; PARSEP->verilatorCmtLintSave(); FL_BRK; }
  "/*verilator tag"[^*]*"*/"            { FL_FWD; PARSEP->tag(yytext); FL_BRK; }

  "/**/"                                { FL_FWD; FL_BRK; }
  "/*"[^*]+"*/"                         { FL_FWD; PARSEP->verilatorCmtBad(yytext); FL_BRK; }
}

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

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

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

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

  /* Verilog 2001 Operators */
<V01,V05,VA5,S05,S09,S12,S17,SAX>{
  "<<<"                 { FL; return yP_SLEFT; }
  ">>>"                 { FL; return yP_SSRIGHT; }
  "**"                  { FL; return yP_POW; }
  "+:"                  { FL; return yP_PLUSCOLON; }
  "-:"                  { FL; return yP_MINUSCOLON; }
  ".*"                  { FL; return yP_DOTSTAR; }
  ":+"                  { FL; yyless(1);
                          PARSEP->fileline()->v3warn(COLONPLUS, "Perhaps instead of ':+' the intent was '+:'?");
                          return ':'; }
}

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

  /* SystemVerilog 2009 Operators */
<S09,S12,S17,SAX,VLT>{
  "<->"                 { FL; return yP_LTMINUSGT; }
}

  /* Identifiers and numbers */
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX,VLT>{
  {escid}               { FL; yylval.strp = PARSEP->newString
                                (AstNode::encodeName(string(yytext+1)));  // +1 to skip the backslash
                          return yaID__LEX;
                        }
  {id}                  { FL; yylval.strp = PARSEP->newString(AstNode::encodeName(string(yytext)));
                          return yaID__LEX;
                        }
  \"[^\"\\]*\"          { FL; yylval.strp = PARSEP->newString(yytext+1, yyleng-2);
                          return yaSTRING;
                        }
  \"                    { yy_push_state(STRING); yymore(); }
  {vnum}                {
                          /* "# 1'b0" is a delay value so must lex as "#" "1" "'b0" */
                          if (PARSEP->prevLexToken()=='#') {
                              int shortlen = 0;
                              while (isdigit(yytext[shortlen])) shortlen++;
                              if (shortlen) {
                                  // Push rest past numbers for later parse
                                  PARSEP->unputString(yytext+shortlen, yyleng-shortlen);
                                  // Return is stuff before the tick
                                  yyleng = shortlen;
                                  yytext[yyleng] = '\0';
                                  FL; yylval.nump = PARSEP->newNumber(yylval.fl, (char*)yytext);
                                  return yaINTNUM;
                              }
                          }
                          FL; yylval.nump = PARSEP->newNumber(yylval. fl, (char*)yytext);
                          return yaINTNUM;
                        }
  [0-9][_0-9]*          {
                          FL; yylval.nump = PARSEP->newNumber(yylval.fl, (char*)yytext);
                          return yaINTNUM;
                        }
  [0-9][_0-9]*(\.[_0-9]+)([eE][-+]?[_0-9]+)? {
                          FL; yylval.cdouble = PARSEP->parseDouble(yytext, yyleng);
                          return yaFLOATNUM;
                        }
  [0-9][_0-9]*(\.[_0-9]+)?([eE][-+]?[_0-9]+) {
                          FL; yylval.cdouble = PARSEP->parseDouble(yytext, yyleng);
                          return yaFLOATNUM;
                        }
  [0-9][_0-9]*(\.[_0-9]+)?(fs|ps|ns|us|ms|s|step) {
                          FL; yylval.cdouble = 0;  /* Only for times, not used yet */
                          return yaTIMENUM;
                        }
}

  /************************************************************************/
  /* STRINGS */
<STRING><<EOF>>         { FL_FWD; yyerrorf("EOF in unterminated string");
                          yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); }
<STRING>{crnl}          { FL_FWD; yyerrorf("Unterminated string"); FL_BRK; }
<STRING>\\{crnl}        { yymore(); }
<STRING>\\.             { yymore(); }
<STRING>\"              { yy_pop_state();
                          FL; yylval.strp = PARSEP->newString(yytext+1, yyleng-2);
                          return yaSTRING; }
<STRING>{word}          { yymore(); }
<STRING>.               { yymore(); }

  /************************************************************************/
  /* Attributes */
<ATTRMODE>{crnl}        { yymore(); }
<ATTRMODE>"*)"          { FL_FWD; yy_pop_state(); FL_BRK; }
<ATTRMODE>{word}        { yymore(); }
<ATTRMODE>.             { yymore(); }
<ATTRMODE><<EOF>>       { FL_FWD; yyerrorf("EOF in (*");
                          yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); }

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

  /************************************************************************/
  /* Tables */
<TABLE>\\{crnl}         { yymore(); }
<TABLE>{crnl}           { yymore(); }
<TABLE>";"              { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLELINE; }
<TABLE>"endtable"       { yy_pop_state(); FL; return yENDTABLE; }
<TABLE>.                { yymore(); }
<TABLE><<EOF>>          { FL_FWD; yyerrorf("EOF in TABLE");
                          yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); }

  /************************************************************************/
  /* Preprocessor */
  /* Common for all SYSC header states */
  /* OPTIMIZE: we return one per line, make it one for the entire block */
  /* If add to this list also add to V3LanguageWords.h */
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
  "`accelerate"                         { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`autoexpand_vectornets"              { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`celldefine"                         { FL_FWD; PARSEP->inCellDefine(true); FL_BRK; }
  "`default_decay_time"{ws}+[^\n\r]*    { FL_FWD; FL_BRK; }  // Verilog spec - delays only
  "`default_nettype"{ws}+"wire"         { FL_FWD; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); FL_BRK; }
  "`default_nettype"{ws}+"none"         { FL_FWD; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, false); FL_BRK; }
  "`default_nettype"{ws}+[a-zA-Z0-9]*   { FL_FWD; yyerrorf("Unsupported: `default_nettype of other than none or wire: %s", yytext); FL_BRK; }
  "`default_trireg_strength"{ws}+[^\n\r]*       { FL_FWD; yyerrorf("Unsupported: Verilog optional directive not implemented: %s", yytext); FL_BRK; }
  "`delay_mode_distributed"             { FL_FWD; FL_BRK; }  // Verilog spec - delays only
  "`delay_mode_path"                    { FL_FWD; FL_BRK; }  // Verilog spec - delays only
  "`delay_mode_unit"                    { FL_FWD; FL_BRK; }  // Verilog spec - delays only
  "`delay_mode_zero"                    { FL_FWD; FL_BRK; }  // Verilog spec - delays only
  "`disable_portfaults"                 { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`enable_portfaults"                  { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`endcelldefine"                      { FL_FWD; PARSEP->inCellDefine(false); FL_BRK; }
  "`endprotect"                         { FL_FWD; FL_BRK; }
  "`expand_vectornets"                  { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`inline"                             { FL_FWD; FL_BRK; }
  "`line"{ws}+[^\n\r]*{crnl}            { FL_FWD; PARSEP->ppline(yytext); FL_BRK; }
  "`noaccelerate"                       { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`noexpand_vectornets"                { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`noremove_gatenames"                 { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`noremove_netnames"                  { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`nosuppress_faults"                  { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`nounconnected_drive"                { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`portcoerce"                         { FL_FWD; FL_BRK; }
  "`pragma"{ws}*[^\n\r]*                { FL_FWD; PARSEP->pragma(yytext); FL_BRK; }  // Verilog 2005
  "`protect"                            { FL_FWD; FL_BRK; }
  "`remove_gatenames"                   { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`remove_netnames"                    { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`resetall"                           { FL; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true);
                                          return yaT_RESETALL; }  // Rest handled by preproc
  "`suppress_faults"                    { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
  "`timescale"{ws}+[^\n\r]*             { FL_FWD; FL_BRK; }  // Verilog spec - not supported
  "`uselib"{ws}+[^\n\r]*                { FL_FWD; FL_BRK; }  // Verilog-XL compatibility

  /* See also setLanguage below */
  "`begin_keywords"[ \t]*\"1364-1995\"          { FL_FWD; yy_push_state(V95); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
  "`begin_keywords"[ \t]*\"1364-2001\"          { FL_FWD; yy_push_state(V01); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
  "`begin_keywords"[ \t]*\"1364-2001-noconfig\" { FL_FWD; yy_push_state(V01); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
  "`begin_keywords"[ \t]*\"1364-2005\"          { FL_FWD; yy_push_state(V05); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
  "`begin_keywords"[ \t]*\"VAMS[-0-9.]*\"       { FL_FWD; yy_push_state(VA5); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
  "`begin_keywords"[ \t]*\"1800-2005\"          { FL_FWD; yy_push_state(S05); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
  "`begin_keywords"[ \t]*\"1800-2009\"          { FL_FWD; yy_push_state(S09); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
  "`begin_keywords"[ \t]*\"1800-2012\"          { FL_FWD; yy_push_state(S12); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
  "`begin_keywords"[ \t]*\"1800-2017\"          { FL_FWD; yy_push_state(S17); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
  "`begin_keywords"[ \t]*\"1800[+]VAMS\"        { FL_FWD; yy_push_state(SAX); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }  /*Latest SV*/
  "`end_keywords"                               { FL_FWD; yy_pop_state();
                                                  if (!PARSEP->popBeginKeywords()) yyerrorf("`end_keywords when not inside `begin_keywords block");
                                                  FL_BRK; }

  /* Verilator */
  "`systemc_ctor"                       { FL_FWD; BEGIN SYSCCTOR; FL_BRK; }
  "`systemc_dtor"                       { FL_FWD; BEGIN SYSCDTOR; FL_BRK; }
  "`systemc_header"                     { FL_FWD; BEGIN SYSCHDR; FL_BRK; }
  "`systemc_imp_header"                 { FL_FWD; BEGIN SYSCIMPH; FL_BRK; }
  "`systemc_implementation"             { FL_FWD; BEGIN SYSCIMP; FL_BRK; }
  "`systemc_interface"                  { FL_FWD; BEGIN SYSCINT; FL_BRK; }
  "`verilator_config"                   { FL_FWD; BEGIN VLT; FL_BRK; }
  "`verilog"                            { FL_FWD; BEGIN PARSEP->lastVerilogState(); FL_BRK; }

  /* Errors */
  "<<<<<<<"[^\n\r]*                     { FL_FWD; yyerrorf("version control conflict marker in file"); FL_BRK; }
  "======="[^\n\r]*                     { FL_FWD; yyerrorf("version control conflict marker in file"); FL_BRK; }
  ">>>>>>>"[^\n\r]*                     { FL_FWD; yyerrorf("version control conflict marker in file"); FL_BRK; }

  /* If add to this list also add to V3LanguageWords.h */
}

<SYSCHDR>[ \t]*[^` \t\n\r][^\n\r]*{crnl}        { FL; yylval.strp = PARSEP->newString(yytext); return yaSCHDR; }
<SYSCINT>[ \t]*[^` \t\n\r][^\n\r]*{crnl}        { FL; yylval.strp = PARSEP->newString(yytext); return yaSCINT; }
<SYSCIMP>[ \t]*[^` \t\n\r][^\n\r]*{crnl}        { FL; yylval.strp = PARSEP->newString(yytext); return yaSCIMP; }
<SYSCIMPH>[ \t]*[^` \t\n\r][^\n\r]*{crnl}       { FL; yylval.strp = PARSEP->newString(yytext); return yaSCIMPH; }
<SYSCCTOR>[ \t]*[^` \t\n\r][^\n\r]*{crnl}       { FL; yylval.strp = PARSEP->newString(yytext); return yaSCCTOR; }
<SYSCDTOR>[ \t]*[^` \t\n\r][^\n\r]*{crnl}       { FL; yylval.strp = PARSEP->newString(yytext); return yaSCDTOR; }
<IGNORE>[ \t]*[^` \t\n\r][^\n\r]*{crnl}         { FL_FWD; FL_BRK; }

  /* Pick up text-type data */
<SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
  {wsnr}*               { yymore(); }
  {crnl}                { yymore(); }
}

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

<V95,V01,V05,VA5,S05,S09,S12,S17,SAX,VLT>{
  "`"[a-zA-Z_0-9]+      { FL_FWD; PARSEP->errorPreprocDirective(yytext); FL_BRK; }
  "//"[^\n]*            { FL_FWD; FL_BRK; }  /* throw away single line comments */
  .                     { FL; return yytext[0]; }       /* return single char ops. */
}

  /* Catch all - absolutely last */
<*>.|\n                 { FL_FWD; yyerrorf("Missing verilog.l rule: Default rule invoked in state %d: %s", YY_START, yytext); FL_BRK; }
%%
int V3ParseImp::stateVerilogRecent() { return STATE_VERILOG_RECENT; }

void V3ParseImp::lexToken() {
    // called from lexToBison, has a "this"
    // Fetch next token from prefetch or real lexer
    int token;
    if (m_ahead) {
        // We prefetched an extra token, give it back
        m_ahead = false;
        token = m_aheadVal.token;
        yylval = m_aheadVal;
    } else {
        // Parse new token
        token = yylexReadTok();
        //yylval // Set by yylexReadTok()
    }
    // If a paren, read another
    if (token == '('
        || token == yCONST__LEX
        || token == yGLOBAL__LEX
        || token == yLOCAL__LEX
        || token == yNEW__LEX
        || token == yVIRTUAL__LEX
        // Never put yID_* here; below symbol table resolution would break
        ) {
        if (debugFlex()>=6) { cout<<"   lexToken: reading ahead to find possible strength"<<endl; }
        V3ParseBisonYYSType curValue = yylval;  // Remember value, as about to read ahead
        int nexttok = yylexReadTok();
        m_ahead = true;
        m_aheadVal = yylval;
        m_aheadVal.token = nexttok;
        yylval = 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 if (v3Global.opt.pedantic()) token = yGLOBAL__ETC;
            // Avoid 2009 "global" conflicting with old code when we can
            else { token = yaID__LEX; yylval.strp = PARSEP->newString("global"); }
        }
        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 == 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;
        }
        // If add to above "else if", also add to "if (token" further above
    }
    // If an id, change the type based on symbol table
    // Note above sometimes converts yGLOBAL to a yaID__LEX
    if (token == yaID__LEX) {
        VSymEnt* foundp;
        if (VSymEnt* look_underp = SYMP->nextId()) {
            UINFO(7,"   lexToken: next id lookup forced under "<<look_underp<<endl);
            foundp = look_underp->findIdFallback(*(yylval.strp));
            // "consume" it.  Must set again if want another token under temp scope
            SYMP->nextId(NULL);
        } else {
            UINFO(7,"   lexToken: find upward "<<SYMP->symCurrentp()
                  <<" for '"<<*(yylval.strp)<<"'"<<endl);
            //if (debug()>=9) SYMP->symCurrentp()->dump(cout,"     -findtree: ", true);
            foundp = SYMP->symCurrentp()->findIdFallback(*(yylval.strp));
        }
        if (foundp) {
            AstNode* scp = foundp->nodep();
            yylval.scp = scp;
            UINFO(7,"   lexToken: Found "<<scp<<endl);
            if (VN_IS(scp, Typedef)) token = yaID__aTYPE;
            else if (VN_IS(scp, TypedefFwd)) token = yaID__aTYPE;
            else if (VN_IS(scp, Package)) token = yaID__aPACKAGE;
            else if (VN_IS(scp, Class)) token = yaID__aTYPE;
            //UNSUP else if (VN_IS(scp, CoverGroup)) token = yaID__aCOVERGROUP;
            else token = yaID__ETC;
        } else {  // Not found
            yylval.scp = NULL;
            token = yaID__ETC;
        }
    }
    yylval.token = token;
    // effectively returns yylval
}

int V3ParseImp::lexToBison() {
    // Called as global since bison doesn't have our pointer
    lexToken();  // sets yylval
    m_prevBisonVal = m_curBisonVal;
    m_curBisonVal = yylval;

    //yylval.scp = NULL;   // Symbol table not yet needed - no packages
    if (debugFlex()>=6 || debugBison()>=6) {  // --debugi-flex and --debugi-bison
        cout<<"   {"<<yylval.fl->filenameLetters()<<yylval.fl->asciiLineCol()
            <<"} lexToBison  TOKEN="<<yylval.token<<" "<<tokenName(yylval.token);
        if (yylval.token == yaID__ETC
            || yylval.token == yaID__LEX
            || yylval.token == yaID__aTYPE) {
            cout<<"   strp='"<<*(yylval.strp)<<"'";
        }
        cout<<endl;
    }
    return yylval.token;
}
