// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Bison grammer file
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
//*************************************************************************
// Original code here by Paul Wasson and Duane Galbi
//*************************************************************************

%{
#include "V3Ast.h"
#include "V3Global.h"
#include "V3Config.h"
#include "V3ParseImp.h"  // Defines YYTYPE; before including bison header

#include <cstdlib>
#include <cstdarg>

#define YYERROR_VERBOSE 1
#define YYINITDEPTH 10000	// Older bisons ignore YYMAXDEPTH
#define YYMAXDEPTH 10000

// Pick up new lexer
#define yylex PARSEP->lexToBison
#define BBUNSUP(fl,msg) { if (!v3Global.opt.bboxUnsup()) { (fl)->v3error(msg); } }
#define GATEUNSUP(fl,tok) { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: "<<(tok)); }

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

//======================================================================
// Statics (for here only)

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

class V3ParseGrammar {
public:
    bool	m_impliedDecl;	// Allow implied wire declarations
    AstVarType	m_varDecl;	// Type for next signal declaration (reg/wire/etc)
    bool        m_varDeclTyped; // Var got reg/wire for dedup check
    VDirection  m_varIO;        // Direction for next signal declaration (reg/wire/etc)
    AstVar*	m_varAttrp;	// Current variable for attribute adding
    AstRange*	m_gateRangep;	// Current range for gate declarations
    AstCase*	m_caseAttrp;	// Current case statement for attribute adding
    AstNodeDType* m_varDTypep;	// Pointer to data type for next signal declaration
    AstNodeDType* m_memDTypep;	// Pointer to data type for next member declaration
    bool        m_pinAnsi;      // In ANSI port list
    int		m_pinNum;	// Pin number currently parsing
    FileLine*   m_instModuleFl; // Fileline of module referenced for instantiations
    string	m_instModule;	// Name of module referenced for instantiations
    AstPin*	m_instParamp;	// Parameters for instantiations
    bool	m_tracingParse;	// Tracing disable for parser

    static int	s_modTypeImpNum; // Implicit type number, incremented each module

    // CONSTRUCTORS
    V3ParseGrammar() {
	m_impliedDecl = false;
	m_varDecl = AstVarType::UNKNOWN;
        m_varDeclTyped = false;
	m_varIO = VDirection::NONE;
	m_varDTypep = NULL;
	m_gateRangep = NULL;
	m_memDTypep = NULL;
	m_pinAnsi = false;
	m_pinNum = -1;
	m_instModuleFl = NULL;
	m_instModule = "";
	m_instParamp = NULL;
	m_varAttrp = NULL;
	m_caseAttrp = NULL;
	m_tracingParse = true;
    }
    static V3ParseGrammar* singletonp() {
	static V3ParseGrammar singleton;
	return &singleton;
    }

    // METHODS
    void argWrapList(AstNodeFTaskRef* nodep);
    bool allTracingOn(FileLine* fl) {
	return v3Global.opt.trace() && m_tracingParse && fl->tracingOn();
    }
    AstRange* scrubRange(AstNodeRange* rangep);
    AstNodeDType* createArray(AstNodeDType* basep, AstNodeRange* rangep, bool isPacked);
    AstVar*  createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp, AstNode* attrsp);
    AstNode* createSupplyExpr(FileLine* fileline, const string& name, int value);
    AstText* createTextQuoted(FileLine* fileline, const string& text) {
	string newtext = deQuote(fileline, text);
	return new AstText(fileline, newtext);
    }
    AstDisplay* createDisplayError(FileLine* fileline) {
	AstDisplay* nodep = new AstDisplay(fileline, AstDisplayType::DT_ERROR, "", NULL, NULL);
	nodep->addNext(new AstStop(fileline, true));
	return nodep;
    }
    AstNode* createGatePin(AstNode* exprp) {
	AstRange* rangep = m_gateRangep;
	if (!rangep) return exprp;
	else return new AstGatePin(rangep->fileline(), exprp, rangep->cloneTree(true));
    }
    void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) { endLabel(fl, nodep->prettyName(), endnamep); }
    void endLabel(FileLine* fl, string name, string* endnamep) {
	if (fl && endnamep && *endnamep != "" && name != *endnamep
	    && name != AstNode::prettyName(*endnamep)) {
	    fl->v3warn(ENDLABEL,"End label '"<<*endnamep<<"' does not match begin label '"<<name<<"'");
	}
    }
    void setVarDecl(AstVarType type) { m_varDecl = type; }
    void setDType(AstNodeDType* dtypep) {
	if (m_varDTypep) { m_varDTypep->deleteTree(); m_varDTypep=NULL; } // It was cloned, so this is safe.
	m_varDTypep = dtypep;
    }
    AstPackage* unitPackage(FileLine* fl) {
	// Find one made earlier?
	VSymEnt* symp = SYMP->symRootp()->findIdFlat(AstPackage::dollarUnitName());
	AstPackage* pkgp;
	if (!symp) {
	    pkgp = PARSEP->rootp()->dollarUnitPkgAddp();
	    SYMP->reinsert(pkgp, SYMP->symRootp());  // Don't push/pop scope as they're global
	} else {
	    pkgp = VN_CAST(symp->nodep(), Package);
	}
	return pkgp;
    }
    AstNodeDType* addRange(AstBasicDType* dtypep, AstNodeRange* rangesp, bool isPacked) {
	// If dtypep isn't basic, don't use this, call createArray() instead
	if (!rangesp) {
	    return dtypep;
	} else {
	    // If rangesp is "wire [3:3][2:2][1:1] foo [5:5][4:4]"
	    // then [1:1] becomes the basicdtype range; everything else is arraying
	    // the final [5:5][4:4] will be passed in another call to createArray
            AstNodeRange* rangearraysp = NULL;
            if (dtypep->isRanged()) {
                rangearraysp = rangesp;  // Already a range; everything is an array
            } else {
                AstNodeRange* finalp = rangesp;
                while (finalp->nextp()) finalp = VN_CAST(finalp->nextp(), Range);
                if (finalp != rangesp) {
                    finalp->unlinkFrBack();
                    rangearraysp = rangesp;
                }
                if (AstRange* finalRangep = VN_CAST(finalp, Range)) {  // not an UnsizedRange
                    if (dtypep->implicit()) {
                        // It's no longer implicit but a wire logic type
                        AstBasicDType* newp = new AstBasicDType(dtypep->fileline(), AstBasicDTypeKwd::LOGIC,
                                                                dtypep->numeric(), dtypep->width(), dtypep->widthMin());
                        dtypep->deleteTree(); VL_DANGLING(dtypep);
                        dtypep = newp;
                    }
                    dtypep->rangep(finalRangep);
                }
	    }
	    return createArray(dtypep, rangearraysp, isPacked);
	}
    }
    string   deQuote(FileLine* fileline, string text);
    void checkDpiVer(FileLine* fileline, const string& str) {
	if (str != "DPI-C" && !v3Global.opt.bboxSys()) {
	    fileline->v3error("Unsupported DPI type '"<<str<<"': Use 'DPI-C'");
	}
    }
};

const AstBasicDTypeKwd LOGIC = AstBasicDTypeKwd::LOGIC;	// Shorthand "LOGIC"
const AstBasicDTypeKwd LOGIC_IMPLICIT = AstBasicDTypeKwd::LOGIC_IMPLICIT;

int V3ParseGrammar::s_modTypeImpNum = 0;

//======================================================================
// Macro functions

#define CRELINE() (PARSEP->copyOrSameFileLine())  // Only use in empty rules, so lines point at beginnings
#define FILELINE_OR_CRE(nodep) ((nodep) ? (nodep)->fileline() : CRELINE())

#define VARRESET_LIST(decl)    { GRAMMARP->m_pinNum=1; GRAMMARP->m_pinAnsi=false; \
                                 VARRESET(); VARDECL(decl); }  // Start of pinlist
#define VARRESET_NONLIST(decl) { GRAMMARP->m_pinNum=0; GRAMMARP->m_pinAnsi=false; \
                                 VARRESET(); VARDECL(decl); }  // Not in a pinlist
#define VARRESET() { VARDECL(UNKNOWN); VARIO(NONE); VARDTYPE_NDECL(NULL); \
                     GRAMMARP->m_varDeclTyped = false; }
#define VARDECL(type) { GRAMMARP->setVarDecl(AstVarType::type); }
#define VARIO(type) { GRAMMARP->m_varIO = VDirection::type; }
#define VARDTYPE(dtypep) { GRAMMARP->setDType(dtypep); GRAMMARP->m_varDeclTyped = true; }
#define VARDTYPE_NDECL(dtypep) { GRAMMARP->setDType(dtypep); }  // Port that is range or signed only (not a decl)

#define VARDONEA(fl,name,array,attrs) GRAMMARP->createVariable((fl),(name),(array),(attrs))
#define VARDONEP(portp,array,attrs) GRAMMARP->createVariable((portp)->fileline(),(portp)->name(),(array),(attrs))
#define PINNUMINC() (GRAMMARP->m_pinNum++)

#define GATERANGE(rangep) { GRAMMARP->m_gateRangep = rangep; }

#define INSTPREP(modfl,modname,paramsp) { \
	GRAMMARP->m_impliedDecl = true; \
	GRAMMARP->m_instModuleFl = modfl; GRAMMARP->m_instModule = modname; \
	GRAMMARP->m_instParamp = paramsp; }

#define DEL(nodep) { if (nodep) nodep->deleteTree(); }

static void ERRSVKWD(FileLine* fileline, const string& tokname) {
    static int toldonce = 0;
    fileline->v3error(string("Unexpected '")+tokname+"': '"+tokname
                      +"' is a SystemVerilog keyword misused as an identifier."
                      +(!toldonce++
                        ? "\n"+V3Error::warnMore()
                          +"... Suggest modify the Verilog-2001 code to avoid SV keywords,"
                          +" or use `begin_keywords or --language."
                        : ""));
}

static void UNSUPREAL(FileLine* fileline) {
    fileline->v3warn(SHORTREAL, "Unsupported: shortreal being promoted to real (suggest use real instead)");
}

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

class AstSenTree;
%}

// When writing Bison patterns we use yTOKEN instead of "token",
// so Bison will error out on unknown "token"s.

// Generic lexer tokens, for example a number
// IEEE: real_number
%token<cdouble>		yaFLOATNUM	"FLOATING-POINT NUMBER"

// IEEE: identifier, class_identifier, class_variable_identifier,
// covergroup_variable_identifier, dynamic_array_variable_identifier,
// enum_identifier, interface_identifier, interface_instance_identifier,
// package_identifier, type_identifier, variable_identifier,
%token<strp>		yaID__ETC	"IDENTIFIER"
%token<strp>		yaID__LEX	"IDENTIFIER-in-lex"
%token<strp>		yaID__aPACKAGE	"PACKAGE-IDENTIFIER"
%token<strp>		yaID__aTYPE	"TYPE-IDENTIFIER"
//			Can't predecode aFUNCTION, can declare after use
//			Can't predecode aINTERFACE, can declare after use
//			Can't predecode aTASK, can declare after use

// IEEE: integral_number
%token<nump>		yaINTNUM	"INTEGER NUMBER"
// IEEE: time_literal + time_unit
%token<cdouble>		yaTIMENUM	"TIME NUMBER"
// IEEE: string_literal
%token<strp>		yaSTRING	"STRING"
%token<strp>		yaSTRING__IGNORE "STRING-ignored"	// Used when expr:string not allowed

%token<fl>		yaTIMINGSPEC	"TIMING SPEC ELEMENT"

%token<fl>		ygenSTRENGTH	"STRENGTH keyword (strong1/etc)"

%token<strp>		yaTABLELINE	"TABLE LINE"

%token<strp>		yaSCHDR		"`systemc_header BLOCK"
%token<strp>		yaSCINT		"`systemc_ctor BLOCK"
%token<strp>		yaSCIMP		"`systemc_dtor BLOCK"
%token<strp>		yaSCIMPH	"`systemc_interface BLOCK"
%token<strp>		yaSCCTOR	"`systemc_implementation BLOCK"
%token<strp>		yaSCDTOR	"`systemc_imp_header BLOCK"

%token<fl>		yVLT_COVERAGE_OFF "coverage_off"
%token<fl>		yVLT_COVERAGE_ON  "coverage_on"
%token<fl>		yVLT_LINT_OFF	  "lint_off"
%token<fl>		yVLT_LINT_ON	  "lint_on"
%token<fl>		yVLT_TRACING_OFF  "tracing_off"
%token<fl>		yVLT_TRACING_ON   "tracing_on"

%token<fl>		yVLT_D_FILE	"--file"
%token<fl>		yVLT_D_LINES	"--lines"
%token<fl>		yVLT_D_MSG	"--msg"
%token<fl>		yVLT_D_RULE	"--rule"

%token<strp>		yaD_IGNORE	"${ignored-bbox-sys}"
%token<strp>		yaD_DPI		"${dpi-sys}"

%token<fl>		yaT_RESETALL	"`resetall"

// <fl> is the fileline, abbreviated to shorten "$<fl>1" references
%token<fl>		'!'
%token<fl>		'#'
%token<fl>		'%'
%token<fl>		'&'
%token<fl>		'('
%token<fl>		')'
%token<fl>		'*'
%token<fl>		'+'
%token<fl>		','
%token<fl>		'-'
%token<fl>		'.'
%token<fl>		'/'
%token<fl>		':'
%token<fl>		';'
%token<fl>		'<'
%token<fl>		'='
%token<fl>		'>'
%token<fl>		'?'
%token<fl>		'@'
%token<fl>		'['
%token<fl>		']'
%token<fl>		'^'
%token<fl>		'{'
%token<fl>		'|'
%token<fl>		'}'
%token<fl>		'~'

// Specific keywords
// yKEYWORD means match "keyword"
// Other cases are yXX_KEYWORD where XX makes it unique,
// for example yP_ for punctuation based operators.
// Double underscores "yX__Y" means token X followed by Y,
// and "yX__ETC" means X folled by everything but Y(s).
%token<fl>		yALIAS		"alias"
%token<fl>		yALWAYS		"always"
%token<fl>		yALWAYS_COMB	"always_comb"
%token<fl>		yALWAYS_FF	"always_ff"
%token<fl>		yALWAYS_LATCH	"always_latch"
%token<fl>		yAND		"and"
%token<fl>		yASSERT		"assert"
%token<fl>		yASSIGN		"assign"
%token<fl>		yASSUME		"assume"
%token<fl>		yAUTOMATIC	"automatic"
%token<fl>		yBEGIN		"begin"
%token<fl>		yBIND		"bind"
%token<fl>		yBIT		"bit"
%token<fl>		yBREAK		"break"
%token<fl>		yBUF		"buf"
%token<fl>		yBUFIF0		"bufif0"
%token<fl>		yBUFIF1		"bufif1"
%token<fl>		yBYTE		"byte"
%token<fl>		yCASE		"case"
%token<fl>		yCASEX		"casex"
%token<fl>		yCASEZ		"casez"
%token<fl>		yCHANDLE	"chandle"
%token<fl>		yCLASS		"class"
%token<fl>		yCLOCKING	"clocking"
%token<fl>		yCMOS		"cmos"
%token<fl>		yCONST__ETC	"const"
%token<fl>		yCONST__LEX	"const-in-lex"
%token<fl>		yCONST__REF	"const-then-ref"
%token<fl>		yCONTEXT	"context"
%token<fl>		yCONTINUE	"continue"
%token<fl>		yCOVER		"cover"
%token<fl>		yDEASSIGN	"deassign"
%token<fl>		yDEFAULT	"default"
%token<fl>		yDEFPARAM	"defparam"
%token<fl>		yDISABLE	"disable"
%token<fl>		yDO		"do"
%token<fl>		yEDGE		"edge"
%token<fl>		yELSE		"else"
%token<fl>		yEND		"end"
%token<fl>		yENDCASE	"endcase"
%token<fl>		yENDCLASS	"endclass"
%token<fl>		yENDCLOCKING	"endclocking"
%token<fl>		yENDFUNCTION	"endfunction"
%token<fl>		yENDGENERATE	"endgenerate"
%token<fl>		yENDINTERFACE	"endinterface"
%token<fl>		yENDMODULE	"endmodule"
%token<fl>		yENDPACKAGE	"endpackage"
%token<fl>		yENDPRIMITIVE	"endprimitive"
%token<fl>		yENDPROGRAM	"endprogram"
%token<fl>		yENDPROPERTY	"endproperty"
%token<fl>		yENDSPECIFY	"endspecify"
%token<fl>		yENDTABLE	"endtable"
%token<fl>		yENDTASK	"endtask"
%token<fl>		yENUM		"enum"
%token<fl>		yEVENT		"event"
%token<fl>		yEXPORT		"export"
%token<fl>		yEXTENDS	"extends"
%token<fl>		yEXTERN		"extern"
%token<fl>		yFINAL		"final"
%token<fl>		yFOR		"for"
%token<fl>		yFORCE		"force"
%token<fl>		yFOREACH	"foreach"
%token<fl>		yFOREVER	"forever"
%token<fl>		yFORK		"fork"
%token<fl>		yFORKJOIN	"forkjoin"
%token<fl>		yFUNCTION	"function"
%token<fl>		yGENERATE	"generate"
%token<fl>		yGENVAR		"genvar"
%token<fl>		yGLOBAL__CLOCKING "global-then-clocking"
%token<fl>		yGLOBAL__ETC	"global"
%token<fl>		yGLOBAL__LEX	"global-in-lex"
%token<fl>		yIF		"if"
%token<fl>		yIFF		"iff"
%token<fl>		yIMPLEMENTS	"implements"
%token<fl>		yIMPORT		"import"
%token<fl>		yINITIAL	"initial"
%token<fl>		yINOUT		"inout"
%token<fl>		yINPUT		"input"
%token<fl>		yINSIDE		"inside"
%token<fl>		yINT		"int"
%token<fl>		yINTEGER	"integer"
%token<fl>		yINTERFACE	"interface"
%token<fl>		yJOIN		"join"
%token<fl>		yJOIN_ANY	"join_any"
%token<fl>		yJOIN_NONE	"join_none"
%token<fl>		yLOCALPARAM	"localparam"
%token<fl>		yLOCAL__COLONCOLON "local-then-::"
%token<fl>		yLOCAL__ETC	"local"
%token<fl>		yLOCAL__LEX	"local-in-lex"
%token<fl>		yLOGIC		"logic"
%token<fl>		yLONGINT	"longint"
%token<fl>		yMODPORT	"modport"
%token<fl>		yMODULE		"module"
%token<fl>		yNAND		"nand"
%token<fl>		yNEGEDGE	"negedge"
%token<fl>		yNEW__ETC	"new"
%token<fl>		yNEW__LEX	"new-in-lex"
%token<fl>		yNEW__PAREN	"new-then-paren"
%token<fl>		yNMOS		"nmos"
%token<fl>		yNOR		"nor"
%token<fl>		yNOT		"not"
%token<fl>		yNOTIF0		"notif0"
%token<fl>		yNOTIF1		"notif1"
%token<fl>		yNULL		"null"
%token<fl>		yOR		"or"
%token<fl>		yOUTPUT		"output"
%token<fl>		yPACKAGE	"package"
%token<fl>		yPACKED		"packed"
%token<fl>		yPARAMETER	"parameter"
%token<fl>		yPMOS		"pmos"
%token<fl>		yPOSEDGE	"posedge"
%token<fl>		yPRIMITIVE	"primitive"
%token<fl>		yPRIORITY	"priority"
%token<fl>		yPROGRAM	"program"
%token<fl>		yPROPERTY	"property"
%token<fl>		yPROTECTED	"protected"
%token<fl>		yPULLDOWN	"pulldown"
%token<fl>		yPULLUP		"pullup"
%token<fl>		yPURE		"pure"
%token<fl>		yRAND		"rand"
%token<fl>		yRANDC		"randc"
%token<fl>		yRANDCASE	"randcase"
%token<fl>		yRCMOS		"rcmos"
%token<fl>		yREAL		"real"
%token<fl>		yREALTIME	"realtime"
%token<fl>		yREF		"ref"
%token<fl>		yREG		"reg"
%token<fl>		yRELEASE	"release"
%token<fl>		yREPEAT		"repeat"
%token<fl>		yRESTRICT	"restrict"
%token<fl>		yRETURN		"return"
%token<fl>		yRNMOS		"rnmos"
%token<fl>		yRPMOS		"rpmos"
%token<fl>		yRTRAN		"rtran"
%token<fl>		yRTRANIF0	"rtranif0"
%token<fl>		yRTRANIF1	"rtranif1"
%token<fl>		ySCALARED	"scalared"
%token<fl>		ySHORTINT	"shortint"
%token<fl>		ySHORTREAL	"shortreal"
%token<fl>		ySIGNED		"signed"
%token<fl>		ySPECIFY	"specify"
%token<fl>		ySPECPARAM	"specparam"
%token<fl>		ySTATIC__ETC	"static"
%token<fl>		ySTRING		"string"
%token<fl>		ySTRUCT		"struct"
%token<fl>		ySUPER		"super"
%token<fl>		ySUPPLY0	"supply0"
%token<fl>		ySUPPLY1	"supply1"
%token<fl>		yTABLE		"table"
%token<fl>		yTASK		"task"
%token<fl>		yTHIS		"this"
%token<fl>		yTIME		"time"
%token<fl>		yTIMEPRECISION	"timeprecision"
%token<fl>		yTIMEUNIT	"timeunit"
%token<fl>		yTRAN		"tran"
%token<fl>		yTRANIF0	"tranif0"
%token<fl>		yTRANIF1	"tranif1"
%token<fl>		yTRI		"tri"
%token<fl>		yTRI0		"tri0"
%token<fl>		yTRI1		"tri1"
%token<fl>		yTRIAND 	"triand"
%token<fl>		yTRIOR 		"trior"
%token<fl>		yTRIREG 	"trireg"
%token<fl>		yTRUE		"true"
%token<fl>		yTYPE		"type"
%token<fl>		yTYPEDEF	"typedef"
%token<fl>		yUNION		"union"
%token<fl>		yUNIQUE		"unique"
%token<fl>		yUNIQUE0	"unique0"
%token<fl>		yUNSIGNED	"unsigned"
%token<fl>		yVAR		"var"
%token<fl>		yVECTORED	"vectored"
%token<fl>		yVIRTUAL__CLASS	"virtual-then-class"
%token<fl>		yVIRTUAL__ETC	"virtual"
%token<fl>		yVIRTUAL__INTERFACE	"virtual-then-interface"
%token<fl>		yVIRTUAL__LEX	"virtual-in-lex"
%token<fl>		yVIRTUAL__anyID	"virtual-then-identifier"
%token<fl>		yVOID		"void"
%token<fl>		yWAIT		"wait"
%token<fl>		yWAND 		"wand"
%token<fl>		yWHILE		"while"
%token<fl>		yWIRE		"wire"
%token<fl>		yWOR 		"wor"
%token<fl>		yWREAL		"wreal"
%token<fl>		yXNOR		"xnor"
%token<fl>		yXOR		"xor"

%token<fl>		yD_ACOS		"$acos"
%token<fl>		yD_ACOSH	"$acosh"
%token<fl>		yD_ASIN		"$asin"
%token<fl>		yD_ASINH	"$asinh"
%token<fl>		yD_ATAN		"$atan"
%token<fl>		yD_ATAN2	"$atan2"
%token<fl>		yD_ATANH	"$atanh"
%token<fl>		yD_BITS		"$bits"
%token<fl>		yD_BITSTOREAL	"$bitstoreal"
%token<fl>		yD_BITSTOSHORTREAL "$bitstoshortreal"
%token<fl>		yD_C		"$c"
%token<fl>		yD_CEIL		"$ceil"
%token<fl>		yD_CLOG2	"$clog2"
%token<fl>		yD_COS		"$cos"
%token<fl>		yD_COSH		"$cosh"
%token<fl>		yD_COUNTONES	"$countones"
%token<fl>		yD_DIMENSIONS	"$dimensions"
%token<fl>		yD_DISPLAY	"$display"
%token<fl>		yD_ERROR	"$error"
%token<fl>		yD_EXP		"$exp"
%token<fl>		yD_FATAL	"$fatal"
%token<fl>		yD_FCLOSE	"$fclose"
%token<fl>		yD_FDISPLAY	"$fdisplay"
%token<fl>		yD_FEOF		"$feof"
%token<fl>		yD_FFLUSH	"$fflush"
%token<fl>		yD_FGETC	"$fgetc"
%token<fl>		yD_FGETS	"$fgets"
%token<fl>		yD_FINISH	"$finish"
%token<fl>		yD_FLOOR	"$floor"
%token<fl>		yD_FOPEN	"$fopen"
%token<fl>		yD_FREAD	"$fread"
%token<fl>		yD_FREWIND	"$frewind"
%token<fl>		yD_FSCANF	"$fscanf"
%token<fl>		yD_FSEEK	"$fseek"
%token<fl>		yD_FTELL	"$ftell"
%token<fl>		yD_FWRITE	"$fwrite"
%token<fl>		yD_HIGH		"$high"
%token<fl>		yD_HYPOT	"$hypot"
%token<fl>		yD_INCREMENT	"$increment"
%token<fl>		yD_INFO		"$info"
%token<fl>		yD_ISUNKNOWN	"$isunknown"
%token<fl>		yD_ITOR		"$itor"
%token<fl>		yD_LEFT		"$left"
%token<fl>		yD_LN		"$ln"
%token<fl>		yD_LOG10	"$log10"
%token<fl>		yD_LOW		"$low"
%token<fl>		yD_ONEHOT	"$onehot"
%token<fl>		yD_ONEHOT0	"$onehot0"
%token<fl>		yD_PAST		"$past"
%token<fl>		yD_POW		"$pow"
%token<fl>		yD_RANDOM	"$random"
%token<fl>		yD_READMEMB	"$readmemb"
%token<fl>		yD_READMEMH	"$readmemh"
%token<fl>		yD_REALTIME	"$realtime"
%token<fl>		yD_REALTOBITS	"$realtobits"
%token<fl>		yD_REWIND	"$rewind"
%token<fl>		yD_RIGHT	"$right"
%token<fl>		yD_RTOI		"$rtoi"
%token<fl>		yD_SFORMAT	"$sformat"
%token<fl>		yD_SFORMATF	"$sformatf"
%token<fl>		yD_SHORTREALTOBITS "$shortrealtobits"
%token<fl>		yD_SIGNED	"$signed"
%token<fl>		yD_SIN		"$sin"
%token<fl>		yD_SINH		"$sinh"
%token<fl>		yD_SIZE		"$size"
%token<fl>		yD_SQRT		"$sqrt"
%token<fl>		yD_SSCANF	"$sscanf"
%token<fl>		yD_STIME	"$stime"
%token<fl>		yD_STOP		"$stop"
%token<fl>		yD_SWRITE	"$swrite"
%token<fl>		yD_SYSTEM	"$system"
%token<fl>		yD_TAN		"$tan"
%token<fl>		yD_TANH		"$tanh"
%token<fl>		yD_TESTPLUSARGS	"$test$plusargs"
%token<fl>		yD_TIME		"$time"
%token<fl>		yD_UNGETC	"$ungetc"
%token<fl>		yD_UNIT		"$unit"
%token<fl>		yD_UNPACKED_DIMENSIONS "$unpacked_dimensions"
%token<fl>		yD_UNSIGNED	"$unsigned"
%token<fl>		yD_VALUEPLUSARGS "$value$plusargs"
%token<fl>		yD_WARNING	"$warning"
%token<fl>		yD_WRITE	"$write"
%token<fl>		yD_WRITEMEMH	"$writememh"

%token<fl>		yVL_CLOCK		"/*verilator sc_clock*/"
%token<fl>		yVL_CLOCKER		"/*verilator clocker*/"
%token<fl>		yVL_NO_CLOCKER		"/*verilator no_clocker*/"
%token<fl>		yVL_CLOCK_ENABLE	"/*verilator clock_enable*/"
%token<fl>		yVL_COVERAGE_BLOCK_OFF	"/*verilator coverage_block_off*/"
%token<fl>		yVL_FULL_CASE		"/*verilator full_case*/"
%token<fl>		yVL_INLINE_MODULE	"/*verilator inline_module*/"
%token<fl>		yVL_ISOLATE_ASSIGNMENTS	"/*verilator isolate_assignments*/"
%token<fl>		yVL_NO_INLINE_MODULE	"/*verilator no_inline_module*/"
%token<fl>		yVL_NO_INLINE_TASK	"/*verilator no_inline_task*/"
%token<fl>		yVL_SC_BV		"/*verilator sc_bv*/"
%token<fl>		yVL_SFORMAT		"/*verilator sformat*/"
%token<fl>		yVL_PARALLEL_CASE	"/*verilator parallel_case*/"
%token<fl>		yVL_PUBLIC		"/*verilator public*/"
%token<fl>		yVL_PUBLIC_FLAT		"/*verilator public_flat*/"
%token<fl>		yVL_PUBLIC_FLAT_RD	"/*verilator public_flat_rd*/"
%token<fl>		yVL_PUBLIC_FLAT_RW	"/*verilator public_flat_rw*/"
%token<fl>		yVL_PUBLIC_MODULE	"/*verilator public_module*/"

%token<fl>		yP_TICK		"'"
%token<fl>		yP_TICKBRA	"'{"
%token<fl>		yP_OROR		"||"
%token<fl>		yP_ANDAND	"&&"
%token<fl>		yP_NOR		"~|"
%token<fl>		yP_XNOR		"^~"
%token<fl>		yP_NAND		"~&"
%token<fl>		yP_EQUAL	"=="
%token<fl>		yP_NOTEQUAL	"!="
%token<fl>		yP_CASEEQUAL	"==="
%token<fl>		yP_CASENOTEQUAL	"!=="
%token<fl>		yP_WILDEQUAL	"==?"
%token<fl>		yP_WILDNOTEQUAL	"!=?"
%token<fl>		yP_GTE		">="
%token<fl>		yP_LTE		"<="
%token<fl>		yP_LTE__IGNORE	"<=-ignored"	// Used when expr:<= means assignment
%token<fl>		yP_SLEFT	"<<"
%token<fl>		yP_SRIGHT	">>"
%token<fl>		yP_SSRIGHT	">>>"
%token<fl>		yP_POW		"**"

%token<fl>		yP_PAR__STRENGTH "(-for-strength"

%token<fl>		yP_LTMINUSGT	"<->"
%token<fl>		yP_PLUSCOLON	"+:"
%token<fl>		yP_MINUSCOLON	"-:"
%token<fl>		yP_MINUSGT	"->"
%token<fl>		yP_MINUSGTGT	"->>"
%token<fl>		yP_EQGT		"=>"
%token<fl>		yP_ASTGT	"*>"
%token<fl>		yP_ANDANDAND	"&&&"
%token<fl>		yP_POUNDPOUND	"##"
%token<fl>		yP_DOTSTAR	".*"

%token<fl>		yP_ATAT		"@@"
%token<fl>		yP_COLONCOLON	"::"
%token<fl>		yP_COLONEQ	":="
%token<fl>		yP_COLONDIV	":/"
%token<fl>		yP_ORMINUSGT	"|->"
%token<fl>		yP_OREQGT	"|=>"
%token<fl>		yP_BRASTAR	"[*"
%token<fl>		yP_BRAEQ	"[="
%token<fl>		yP_BRAMINUSGT	"[->"

%token<fl>		yP_PLUSPLUS	"++"
%token<fl>		yP_MINUSMINUS	"--"
%token<fl>		yP_PLUSEQ	"+="
%token<fl>		yP_MINUSEQ	"-="
%token<fl>		yP_TIMESEQ	"*="
%token<fl>		yP_DIVEQ	"/="
%token<fl>		yP_MODEQ	"%="
%token<fl>		yP_ANDEQ	"&="
%token<fl>		yP_OREQ		"|="
%token<fl>		yP_XOREQ	"^="
%token<fl>		yP_SLEFTEQ	"<<="
%token<fl>		yP_SRIGHTEQ	">>="
%token<fl>		yP_SSRIGHTEQ	">>>="

// [* is not a operator, as "[ * ]" is legal
// [= and [-> could be repitition operators, but to match [* we don't add them.
// '( is not a operator, as "' (" is legal

//********************
// These prevent other conflicts
%left		yP_ANDANDAND

// PSL op precedence
%right		yP_ORMINUSGT yP_OREQGT

// Verilog op precedence
%right		yP_MINUSGT yP_LTMINUSGT
%right		'?' ':'
%left		yP_OROR
%left		yP_ANDAND
%left		'|' yP_NOR
%left		'^' yP_XNOR
%left		'&' yP_NAND
%left		yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL
%left		'>' '<' yP_GTE yP_LTE yP_LTE__IGNORE yINSIDE
%left		yP_SLEFT yP_SRIGHT yP_SSRIGHT
%left		'+' '-'
%left		'*' '/' '%'
%left		yP_POW
%left		prUNARYARITH yP_MINUSMINUS yP_PLUSPLUS prREDUCTION prNEGATION
%left		'.'
// Not in IEEE, but need to avoid conflicts; TICK should bind tightly just lower than COLONCOLON
%left		yP_TICK
//%left		'(' ')' '[' ']' yP_COLONCOLON '.'

%nonassoc prLOWER_THAN_ELSE
%nonassoc yELSE

//BISONPRE_TYPES
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion
//  Blank lines for type insertion

%start source_text

%%
//**********************************************************************
// Files

source_text:			// ==IEEE: source_text
		/* empty */				{ }
	//			// timeunits_declaration moved into description:package_item
	|	descriptionList				{ }
	;

descriptionList:		// IEEE: part of source_text
		description				{ }
	|	descriptionList description		{ }
	;

description:			// ==IEEE: description
		module_declaration			{ }
	//			// udp_declaration moved into module_declaration
	|	interface_declaration			{ }
	|	program_declaration			{ }
	|	package_declaration			{ }
	|	package_item				{ if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
       	|	bind_directive				{ if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
	//	unsupported	// IEEE: config_declaration
	//			// Verilator only
	|	yaT_RESETALL				{ }  // Else, under design, and illegal based on IEEE 22.3
	|	vltItem					{ }
	|	error					{ }
	;

timeunits_declaration<nodep>:	// ==IEEE: timeunits_declaration
		yTIMEUNIT       yaTIMENUM ';'		{ $$ = NULL; }
	|	yTIMEUNIT yaTIMENUM '/' yaTIMENUM ';'	{ $$ = NULL; }
	| 	yTIMEPRECISION  yaTIMENUM ';'		{ $$ = NULL; }
	;

//**********************************************************************
// Packages

package_declaration:		// ==IEEE: package_declaration
		packageFront package_itemListE yENDPACKAGE endLabelE
			{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline()));  // Stash for implicit wires, etc
			  if ($2) $1->addStmtp($2);
			  SYMP->popScope($1);
			  GRAMMARP->endLabel($<fl>4,$1,$4); }
	;

packageFront<modulep>:
		yPACKAGE lifetimeE idAny ';'
			{ $$ = new AstPackage($<fl>3, *$3);
			  $$->inLibrary(true);  // packages are always libraries; don't want to make them a "top"
			  $$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
			  PARSEP->rootp()->addModulep($$);
			  SYMP->pushNew($$); }
	;

package_itemListE<nodep>:	// IEEE: [{ package_item }]
		/* empty */				{ $$ = NULL; }
	|	package_itemList			{ $$ = $1; }
	;

package_itemList<nodep>:	// IEEE: { package_item }
		package_item				{ $$ = $1; }
	|	package_itemList package_item		{ $$ = $1->addNextNull($2); }
	;

package_item<nodep>:		// ==IEEE: package_item
		package_or_generate_item_declaration	{ $$ = $1; }
	|	anonymous_program			{ $$ = $1; }
	|	package_export_declaration		{ $$ = $1; }
	|	timeunits_declaration			{ $$ = $1; }
	;

package_or_generate_item_declaration<nodep>:	// ==IEEE: package_or_generate_item_declaration
		net_declaration				{ $$ = $1; }
	|	data_declaration			{ $$ = $1; }
	|	task_declaration			{ $$ = $1; }
	|	function_declaration			{ $$ = $1; }
	//UNSUP	checker_declaration			{ $$ = $1; }
	|	dpi_import_export			{ $$ = $1; }
	//UNSUP	extern_constraint_declaration		{ $$ = $1; }
	|	class_declaration			{ $$ = $1; }
	//			// class_constructor_declaration is part of function_declaration
	|	local_parameter_declaration ';'		{ $$ = $1; }
	|	parameter_declaration ';'		{ $$ = $1; }
	//UNSUP	covergroup_declaration			{ $$ = $1; }
	//UNSUP	assertion_item_declaration		{ $$ = $1; }
	|	';'					{ $$ = NULL; }
	;

package_import_declarationList<nodep>:
		package_import_declaration		{ $$ = $1; }
	|	package_import_declarationList package_import_declaration { $$ = $1->addNextNull($2); }
	;

package_import_declaration<nodep>:	// ==IEEE: package_import_declaration
		yIMPORT package_import_itemList ';'	{ $$ = $2; }
	;

package_import_itemList<nodep>:
		package_import_item			{ $$ = $1; }
	|	package_import_itemList ',' package_import_item { $$ = $1->addNextNull($3); }
	;

package_import_item<nodep>:	// ==IEEE: package_import_item
		yaID__aPACKAGE yP_COLONCOLON package_import_itemObj
			{ $$ = new AstPackageImport($<fl>2, VN_CAST($<scp>1, Package), *$3);
			  SYMP->importItem($<scp>1,*$3); }
	;

package_import_itemObj<strp>:	// IEEE: part of package_import_item
		idAny					{ $<fl>$=$<fl>1; $$=$1; }
	|	'*'					{ $<fl>$=$<fl>1; static string star="*"; $$=&star; }
	;

package_export_declaration<nodep>: // IEEE: package_export_declaration
		yEXPORT '*' yP_COLONCOLON '*' ';'	{ $$ = new AstPackageExportStarStar($<fl>2); SYMP->exportStarStar($<scp>1); }
	|	yEXPORT package_export_itemList ';'	{ $$ = $2; }
	;

package_export_itemList<nodep>:
		package_export_item			{ $$ = $1; }
	|	package_export_itemList ',' package_export_item { $$ = $1->addNextNull($3); }
	;

package_export_item<nodep>:	// ==IEEE: package_export_item
		yaID__aPACKAGE yP_COLONCOLON package_import_itemObj
			{ $$ = new AstPackageExport($<fl>3, VN_CAST($<scp>1, Package), *$3);
			  SYMP->exportItem($<scp>1,*$3); }
	;

//**********************************************************************
// Module headers

module_declaration:		// ==IEEE: module_declaration
	//			// timeunits_declaration instead in module_item
	//			// IEEE: module_nonansi_header + module_ansi_header
		modFront importsAndParametersE portsStarE ';'
			module_itemListE yENDMODULE endLabelE
			{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline()));  // Stash for implicit wires, etc
			  if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
			  if ($5) $1->addStmtp($5);
			  SYMP->popScope($1);
			  GRAMMARP->endLabel($<fl>7,$1,$7); }
	|	udpFront parameter_port_listE portsStarE ';'
			module_itemListE yENDPRIMITIVE endLabelE
			{ $1->modTrace(false);  // Stash for implicit wires, etc
			  if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
			  if ($5) $1->addStmtp($5);
			  GRAMMARP->m_tracingParse = true;
			  SYMP->popScope($1);
			  GRAMMARP->endLabel($<fl>7,$1,$7); }
	//
	|	yEXTERN modFront parameter_port_listE portsStarE ';'
			{ BBUNSUP($<fl>1, "Unsupported: extern module"); }
	;

modFront<modulep>:
	//			// General note: all *Front functions must call symPushNew before
	//			// any formal arguments, as the arguments must land in the new scope.
		yMODULE lifetimeE idAny
			{ $$ = new AstModule($<fl>3,*$3);
			  $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine());
			  $$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
			  PARSEP->rootp()->addModulep($$);
			  SYMP->pushNew($$); }
	;

importsAndParametersE<nodep>:	// IEEE: common part of module_declaration, interface_declaration, program_declaration
	//			// { package_import_declaration } [ parameter_port_list ]
		parameter_port_listE			{ $$ = $1; }
	|	package_import_declarationList parameter_port_listE	{ $$ = $1->addNextNull($2); }
	;

udpFront<modulep>:
		yPRIMITIVE lifetimeE idAny
			{ $$ = new AstPrimitive($<fl>3, *$3); $$->inLibrary(true);
			  $$->modTrace(false);
			  $$->addStmtp(new AstPragma($<fl>3, AstPragmaType::INLINE_MODULE));
			  GRAMMARP->m_tracingParse = false;
			  PARSEP->rootp()->addModulep($$);
			  SYMP->pushNew($$); }
	;

parameter_value_assignmentE<pinp>:	// IEEE: [ parameter_value_assignment ]
		/* empty */				{ $$ = NULL; }
	|	'#' '(' cellparamList ')'		{ $$ = $3; }
	//			// Parentheses are optional around a single parameter
	|	'#' yaINTNUM				{ $$ = new AstPin($<fl>2, 1, "", new AstConst($<fl>2, *$2)); }
	|	'#' yaFLOATNUM				{ $$ = new AstPin($<fl>2, 1, "",
									  new AstConst($<fl>2, AstConst::Unsized32(),
										       (int)(($2<0)?($2-0.5):($2+0.5)))); }
	//UNSUP	'#' yaTIMENUM				{ UNSUP }
	|	'#' idClassSel				{ $$ = new AstPin($<fl>2, 1, "", $2); }
	//			// Not needed in Verilator:
	//			// Side effect of combining *_instantiations
	//			// '#' delay_value	{ UNSUP }
	;

parameter_value_assignmentClass<pinp>:	// IEEE: [ parameter_value_assignment ] (for classes)
	//			// Like parameter_value_assignment, but for classes only, which always have #()
		'#' '(' cellparamList ')'		{ $$ = $3; }
	;

parameter_port_listE<nodep>:	// IEEE: parameter_port_list + empty == parameter_value_assignment
		/* empty */				{ $$ = NULL; }
	|	'#' '(' ')'				{ $$ = NULL; }
	//			// IEEE: '#' '(' list_of_param_assignments { ',' parameter_port_declaration } ')'
	//			// IEEE: '#' '(' parameter_port_declaration { ',' parameter_port_declaration } ')'
	//			// Can't just do that as "," conflicts with between vars and between stmts, so
	//			// split into pre-comma and post-comma parts
	|	'#' '(' {VARRESET_LIST(GPARAM);} paramPortDeclOrArgList ')'	{ $$ = $4; VARRESET_NONLIST(UNKNOWN); }
	//			// Note legal to start with "a=b" with no parameter statement
	;

paramPortDeclOrArgList<nodep>:	// IEEE: list_of_param_assignments + { parameter_port_declaration }
		paramPortDeclOrArg				{ $$ = $1; }
	|	paramPortDeclOrArgList ',' paramPortDeclOrArg	{ $$ = $1->addNext($3); }
	;

paramPortDeclOrArg<nodep>:	// IEEE: param_assignment + parameter_port_declaration
	//			// We combine the two as we can't tell which follows a comma
		parameter_port_declarationFrontE param_assignment	{ $$ = $2; }
	;

portsStarE<nodep>:		// IEEE: .* + list_of_ports + list_of_port_declarations + empty
		/* empty */					{ $$ = NULL; }
	|	'(' ')'						{ $$ = NULL; }
	//			// .* expanded from module_declaration
	//UNSUP	'(' yP_DOTSTAR ')'				{ UNSUP }
	|	'(' {VARRESET_LIST(PORT);} list_of_ports ')'	{ $$ = $3; VARRESET_NONLIST(UNKNOWN); }
	;

list_of_ports<nodep>:		// IEEE: list_of_ports + list_of_port_declarations
		port					{ $$ = $1; }
	|	list_of_ports ',' port			{ $$ = $1->addNextNull($3); }
	;

port<nodep>:			// ==IEEE: port
	//			// SEE ALSO port_declaration, tf_port_declaration,
	//			// data_declarationVarFront
	//
	//			// Though not type for interfaces, we factor out the port direction and type
	//			// so we can simply handle it in one place
	//
	//			// IEEE: interface_port_header port_identifier { unpacked_dimension }
	//			// Expanded interface_port_header
	//			// We use instantCb here because the non-port form looks just like a module instantiation
		portDirNetE id/*interface*/                      portSig variable_dimensionListE sigAttrListE
			{ $$ = $3; VARDECL(IFACEREF); VARIO(NONE);
			  VARDTYPE(new AstIfaceRefDType($<fl>2,"",*$2));
			  $$->addNextNull(VARDONEP($$,$4,$5)); }
	|	portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig variable_dimensionListE sigAttrListE
			{ $$ = $5; VARDECL(IFACEREF); VARIO(NONE);
			  VARDTYPE(new AstIfaceRefDType($<fl>2, $<fl>4, "", *$2, *$4));
			  $$->addNextNull(VARDONEP($$,$6,$7)); }
	|	portDirNetE yINTERFACE                           portSig rangeListE sigAttrListE
			{ $$ = NULL; BBUNSUP($<fl>2, "Unsupported: virtual or generic interfaces"); }
	|	portDirNetE yINTERFACE      '.' idAny/*modport*/ portSig rangeListE sigAttrListE
			{ $$ = NULL; BBUNSUP($<fl>2, "Unsupported: virtual or generic interfaces"); }
	//
	//			// IEEE: ansi_port_declaration, with [port_direction] removed
	//			//   IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ]
	//			//   IEEE: [ net_port_header | variable_port_header ] '.' port_identifier '(' [ expression ] ')'
	//			//   IEEE: [ variable_port_header ] port_identifier { variable_dimension } [ '=' constant_expression ]
	//			//   Substitute net_port_header = [ port_direction ] net_port_type
	//			//   Substitute variable_port_header = [ port_direction ] variable_port_type
	//			//   Substitute net_port_type = [ net_type ] data_type_or_implicit
	//			//   Substitute variable_port_type = var_data_type
	//			//   Substitute var_data_type = data_type | yVAR data_type_or_implicit
	//			//     [ [ port_direction ] net_port_type | interface_port_header            ] port_identifier { unpacked_dimension }
	//			//     [ [ port_direction ] var_data_type                                    ] port_identifier variable_dimensionListE [ '=' constant_expression ]
	//			//     [ [ port_direction ] net_port_type | [ port_direction ] var_data_type ] '.' port_identifier '(' [ expression ] ')'
	//
	//			// Remove optional '[...] id' is in portAssignment
	//			// Remove optional '[port_direction]' is in port
	//			//     net_port_type | interface_port_header            port_identifier { unpacked_dimension }
	//			//     net_port_type | interface_port_header            port_identifier { unpacked_dimension }
	//			//     var_data_type                                    port_identifier variable_dimensionListE [ '=' constExpr ]
	//			//     net_port_type | [ port_direction ] var_data_type '.' port_identifier '(' [ expr ] ')'
	//			// Expand implicit_type
	//
	//			// variable_dimensionListE instead of rangeListE to avoid conflicts
	//
	//			// Note implicit rules looks just line declaring additional followon port
	//			// No VARDECL("port") for implicit, as we don't want to declare variables for them
	//UNSUP	portDirNetE data_type	       '.' portSig '(' portAssignExprE ')' sigAttrListE
	//UNSUP		{ UNSUP }
	//UNSUP	portDirNetE yVAR data_type     '.' portSig '(' portAssignExprE ')' sigAttrListE
	//UNSUP		{ UNSUP }
	//UNSUP	portDirNetE yVAR implicit_type '.' portSig '(' portAssignExprE ')' sigAttrListE
	//UNSUP		{ UNSUP }
	//UNSUP	portDirNetE signingE rangeList '.' portSig '(' portAssignExprE ')' sigAttrListE
	//UNSUP		{ UNSUP }
	//UNSUP	portDirNetE /*implicit*/       '.' portSig '(' portAssignExprE ')' sigAttrListE
	//UNSUP		{ UNSUP }
	//
	|	portDirNetE data_type           portSig variable_dimensionListE sigAttrListE
			{ $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); }
	|	portDirNetE yVAR data_type      portSig variable_dimensionListE sigAttrListE
			{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
	|	portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
			{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
	|	portDirNetE signing             portSig variable_dimensionListE sigAttrListE
			{ $$=$3; VARDTYPE_NDECL(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2)); $$->addNextNull(VARDONEP($$,$4,$5)); }
	|	portDirNetE signingE rangeList  portSig variable_dimensionListE sigAttrListE
			{ $$=$4; VARDTYPE_NDECL(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3,true)); $$->addNextNull(VARDONEP($$,$5,$6)); }
	|	portDirNetE /*implicit*/        portSig variable_dimensionListE sigAttrListE
			{ $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); }
	//
	|	portDirNetE data_type           portSig variable_dimensionListE sigAttrListE '=' constExpr
			{ $$=$3; VARDTYPE($2); if (AstVar* vp=VARDONEP($$,$4,$5)) { $$->addNextNull(vp); vp->valuep($7); } }
	|	portDirNetE yVAR data_type      portSig variable_dimensionListE sigAttrListE '=' constExpr
			{ $$=$4; VARDTYPE($3); if (AstVar* vp=VARDONEP($$,$5,$6)) { $$->addNextNull(vp); vp->valuep($8); } }
	|	portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE '=' constExpr
			{ $$=$4; VARDTYPE($3); if (AstVar* vp=VARDONEP($$,$5,$6)) { $$->addNextNull(vp); vp->valuep($8); } }
	|	portDirNetE /*implicit*/        portSig variable_dimensionListE sigAttrListE '=' constExpr
			{ $$=$2; /*VARDTYPE-same*/ if (AstVar* vp=VARDONEP($$,$3,$4)) { $$->addNextNull(vp); vp->valuep($6); } }
 	;

portDirNetE:			// IEEE: part of port, optional net type and/or direction
		/* empty */				{ }
	//			// Per spec, if direction given default the nettype.
	//			// The higher level rule may override this VARDTYPE with one later in the parse.
	|	port_direction					{ VARDECL(PORT); VARDTYPE_NDECL(NULL/*default_nettype*/); }
	|	port_direction { VARDECL(PORT); } net_type	{ VARDTYPE_NDECL(NULL/*default_nettype*/); }  // net_type calls VARDECL
	|	net_type					{ } // net_type calls VARDECL
 	;

port_declNetE:			// IEEE: part of port_declaration, optional net type
		/* empty */				{ }
	|	net_type				{ } // net_type calls VARDECL
 	;

portSig<nodep>:
		id/*port*/				{ $$ = new AstPort($<fl>1,PINNUMINC(),*$1); }
	|	idSVKwd					{ $$ = new AstPort($<fl>1,PINNUMINC(),*$1); }
 	;

//**********************************************************************
// Interface headers

interface_declaration:		// IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header:
	//			// timeunits_delcarationE is instead in interface_item
		intFront parameter_port_listE portsStarE ';'
			interface_itemListE yENDINTERFACE endLabelE
			{ if ($2) $1->addStmtp($2);
			  if ($3) $1->addStmtp($3);
			  if ($5) $1->addStmtp($5);
			  SYMP->popScope($1); }
	|	yEXTERN intFront parameter_port_listE portsStarE ';'
			{ BBUNSUP($<fl>1, "Unsupported: extern interface"); }
	;

intFront<modulep>:
		yINTERFACE lifetimeE idAny/*new_interface*/
			{ $$ = new AstIface($<fl>3, *$3);
			  $$->inLibrary(true);
			  PARSEP->rootp()->addModulep($$);
			  SYMP->pushNew($$); }
	;

interface_itemListE<nodep>:
		/* empty */				{ $$ = NULL; }
	|	interface_itemList			{ $$ = $1; }
	;

interface_itemList<nodep>:
		interface_item				{ $$ = $1; }
	|	interface_itemList interface_item	{ $$ = $1->addNextNull($2); }
	;

interface_item<nodep>:		// IEEE: interface_item + non_port_interface_item
		port_declaration ';'			{ $$ = $1; }
	//			// IEEE: non_port_interface_item
	//			// IEEE: generate_region
	|	interface_generate_region		{ $$ = $1; }
	|	interface_or_generate_item		{ $$ = $1; }
	|	program_declaration			{ $$ = NULL; v3error("Unsupported: program decls within interface decls"); }
	//			// IEEE 1800-2017: modport_item
	//			// See instead old 2012 position in interface_or_generate_item
	|	interface_declaration			{ $$ = NULL; v3error("Unsupported: interface decls within interface decls"); }
	|	timeunits_declaration			{ $$ = $1; }
	//			// See note in interface_or_generate item
	|	module_common_item			{ $$ = $1; }
	;

interface_generate_region<nodep>:		// ==IEEE: generate_region
		yGENERATE interface_itemList yENDGENERATE	{ $$ = new AstGenerate($1, $2); }
	|	yGENERATE yENDGENERATE			{ $$ = NULL; }
	;

interface_or_generate_item<nodep>:  // ==IEEE: interface_or_generate_item
	//			    // module_common_item in interface_item, as otherwise duplicated
	//			    // with module_or_generate_item's module_common_item
		modport_declaration			{ $$ = $1; }
	|	extern_tf_declaration			{ $$ = $1; }
	;

//**********************************************************************
// Program headers

anonymous_program<nodep>:	// ==IEEE: anonymous_program
	//			// See the spec - this doesn't change the scope, items still go up "top"
		yPROGRAM ';' anonymous_program_itemListE yENDPROGRAM	{ $<fl>1->v3error("Unsupported: Anonymous programs"); $$ = NULL; }
	;

anonymous_program_itemListE<nodep>:	// IEEE: { anonymous_program_item }
		/* empty */				{ $$ = NULL; }
	|	anonymous_program_itemList		{ $$ = $1; }
	;

anonymous_program_itemList<nodep>:	// IEEE: { anonymous_program_item }
		anonymous_program_item			{ $$ = $1; }
	|	anonymous_program_itemList anonymous_program_item	{ $$ = $1->addNextNull($2); }
	;

anonymous_program_item<nodep>:	// ==IEEE: anonymous_program_item
		task_declaration			{ $$ = $1; }
	|	function_declaration			{ $$ = $1; }
	|	class_declaration			{ $$ = $1; }
	//UNSUP	covergroup_declaration			{ $$ = $1; }
	//			// class_constructor_declaration is part of function_declaration
	|	';'					{ $$ = NULL; }
	;

program_declaration:		// IEEE: program_declaration + program_nonansi_header + program_ansi_header:
	//			// timeunits_delcarationE is instead in program_item
		pgmFront parameter_port_listE portsStarE ';'
			program_itemListE yENDPROGRAM endLabelE
			{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline()));  // Stash for implicit wires, etc
			  if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
			  if ($5) $1->addStmtp($5);
			  SYMP->popScope($1);
			  GRAMMARP->endLabel($<fl>7,$1,$7); }
	|	yEXTERN	pgmFront parameter_port_listE portsStarE ';'
			{ BBUNSUP($<fl>1, "Unsupported: extern program");
			  SYMP->popScope($2); }
	;

pgmFront<modulep>:
		yPROGRAM lifetimeE idAny/*new_program*/
			{ $$ = new AstModule($<fl>3,*$3);
			  $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine());
			  $$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
			  PARSEP->rootp()->addModulep($$);
			  SYMP->pushNew($$); }
	;

program_itemListE<nodep>:	// ==IEEE: [{ program_item }]
		/* empty */				{ $$ = NULL; }
	|	program_itemList			{ $$ = $1; }
	;

program_itemList<nodep>:	// ==IEEE: { program_item }
		program_item				{ $$ = $1; }
	|	program_itemList program_item		{ $$ = $1->addNextNull($2); }
	;

program_item<nodep>:		// ==IEEE: program_item
		port_declaration ';'			{ $$ = $1; }
	|	non_port_program_item			{ $$ = $1; }
	;

non_port_program_item<nodep>:	// ==IEEE: non_port_program_item
		continuous_assign			{ $$ = $1; }
	|	module_or_generate_item_declaration	{ $$ = $1; }
	|	initial_construct			{ $$ = $1; }
	|	final_construct				{ $$ = $1; }
	|	concurrent_assertion_item		{ $$ = $1; }
	|	timeunits_declaration			{ $$ = $1; }
	|	program_generate_item			{ $$ = $1; }
	;

program_generate_item<nodep>:		// ==IEEE: program_generate_item
		loop_generate_construct			{ $$ = $1; }
	|	conditional_generate_construct		{ $$ = $1; }
	|	generate_region				{ $$ = $1; }
	|	elaboration_system_task			{ $$ = $1; }
	;

extern_tf_declaration<nodep>:		// ==IEEE: extern_tf_declaration
		yEXTERN task_prototype ';'		{ $$ = NULL; BBUNSUP($<fl>1, "Unsupported: extern task"); }
	|	yEXTERN function_prototype ';'		{ $$ = NULL; BBUNSUP($<fl>1, "Unsupported: extern function"); }
	|	yEXTERN yFORKJOIN task_prototype ';'	{ $$ = NULL; BBUNSUP($<fl>1, "Unsupported: extern forkjoin"); }
	;

modport_declaration<nodep>:		// ==IEEE: modport_declaration
		yMODPORT modport_itemList ';'		{ $$ = $2; }
	;

modport_itemList<nodep>:		// IEEE: part of modport_declaration
		modport_item				{ $$ = $1; }
	|	modport_itemList ',' modport_item	{ $$ = $1->addNextNull($3); }
	;

modport_item<nodep>:			// ==IEEE: modport_item
		id/*new-modport*/ '(' { VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); }
	/*cont*/	modportPortsDeclList ')'	{ $$ = new AstModport($<fl>1, *$1, $4); }
	;

modportPortsDeclList<nodep>:
		modportPortsDecl			    { $$ = $1; }
	|	modportPortsDeclList ',' modportPortsDecl   { $$ = $1->addNextNull($3); }
	;

// IEEE: modport_ports_declaration  + modport_simple_ports_declaration
//	+ (modport_tf_ports_declaration+import_export) + modport_clocking_declaration
// We've expanded the lists each take to instead just have standalone ID ports.
// We track the type as with the V2k series of defines, then create as each ID is seen.
modportPortsDecl<nodep>:
	//			// IEEE: modport_simple_ports_declaration
		port_direction modportSimplePort	{ $$ = new AstModportVarRef($<fl>2, *$2, GRAMMARP->m_varIO); }
	//			// IEEE: modport_clocking_declaration
	|	yCLOCKING idAny/*clocking_identifier*/	{ $$ = NULL; BBUNSUP($<fl>1, "Unsupported: Modport clocking"); }
	//			// IEEE: yIMPORT modport_tf_port
	//			// IEEE: yEXPORT modport_tf_port
	//			// modport_tf_port expanded here
	|	yIMPORT id/*tf_identifier*/		{ $$ = new AstModportFTaskRef($<fl>2, *$2, false); }
	|	yEXPORT id/*tf_identifier*/		{ $$ = new AstModportFTaskRef($<fl>2, *$2, true); }
	|	yIMPORT method_prototype		{ $$ = NULL; BBUNSUP($<fl>1, "Unsupported: Modport import with prototype"); }
	|	yEXPORT method_prototype		{ $$ = NULL; BBUNSUP($<fl>1, "Unsupported: Modport export with prototype"); }
	// Continuations of above after a comma.
	//			// IEEE: modport_simple_ports_declaration
	|	modportSimplePort			{ $$ = new AstModportVarRef($<fl>1,*$1,GRAMMARP->m_varIO); }
	;

modportSimplePort<strp>:	// IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier
		id					{ $$ = $1; }
	//UNSUP	'.' idAny '(' ')'			{ }
	//UNSUP	'.' idAny '(' expr ')'			{ }
	;

//************************************************
// Variable Declarations

genvar_declaration<nodep>:	// ==IEEE: genvar_declaration
		yGENVAR list_of_genvar_identifiers ';'	{ $$ = $2; }
	;

list_of_genvar_identifiers<nodep>:	// IEEE: list_of_genvar_identifiers (for declaration)
		genvar_identifierDecl			{ $$ = $1; }
	|	list_of_genvar_identifiers ',' genvar_identifierDecl	{ $$ = $1->addNext($3); }
	;

genvar_identifierDecl<varp>:		// IEEE: genvar_identifier (for declaration)
		id/*new-genvar_identifier*/ sigAttrListE
			{ VARRESET_NONLIST(GENVAR); VARDTYPE(new AstBasicDType($<fl>1,AstBasicDTypeKwd::INTEGER));
			  $$ = VARDONEA($<fl>1, *$1, NULL, $2); }
	;

local_parameter_declaration<nodep>:	// IEEE: local_parameter_declaration
	//			// See notes in parameter_declaration
	//			// Front must execute first so VARDTYPE is ready before list of vars
		local_parameter_declarationFront list_of_param_assignments	{ $$ = $2; }
	;

parameter_declaration<nodep>:	// IEEE: parameter_declaration
	//			// IEEE: yPARAMETER yTYPE list_of_type_assignments ';'
	//			// Instead of list_of_type_assignments
	//			// we use list_of_param_assignments because for port handling
	//			// it already must accept types, so simpler to have code only one place
	//			// Front must execute first so VARDTYPE is ready before list of vars
		parameter_declarationFront list_of_param_assignments	{ $$ = $2; }
	;

local_parameter_declarationFront: // IEEE: local_parameter_declaration w/o assignment
	//			// Front must execute first so VARDTYPE is ready before list of vars
		varLParamReset implicit_typeE 		{ /*VARRESET-in-varLParam*/ VARDTYPE($2); }
	|	varLParamReset data_type		{ /*VARRESET-in-varLParam*/ VARDTYPE($2); }
	|	varLParamReset yTYPE			{ /*VARRESET-in-varLParam*/ VARDTYPE(new AstParseTypeDType($2)); }
	;

parameter_declarationFront:	// IEEE: parameter_declaration w/o assignment
	//			// Front must execute first so VARDTYPE is ready before list of vars
		varGParamReset implicit_typeE 		{ /*VARRESET-in-varGParam*/ VARDTYPE($2); }
	|	varGParamReset data_type		{ /*VARRESET-in-varGParam*/ VARDTYPE($2); }
	|	varGParamReset yTYPE			{ /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($2)); }
	;

parameter_port_declarationFrontE: // IEEE: parameter_port_declaration w/o assignment
	//			// IEEE: parameter_declaration (minus assignment)
	//			// IEEE: local_parameter_declaration (minus assignment)
	//			// Front must execute first so VARDTYPE is ready before list of vars
		varGParamReset implicit_typeE 		{ /*VARRESET-in-varGParam*/ VARDTYPE($2); }
	|	varGParamReset data_type		{ /*VARRESET-in-varGParam*/ VARDTYPE($2); }
	|	varGParamReset yTYPE			{ /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($2)); }
	|	varLParamReset implicit_typeE 		{ /*VARRESET-in-varLParam*/ VARDTYPE($2); }
	|	varLParamReset data_type		{ /*VARRESET-in-varLParam*/ VARDTYPE($2); }
	|	varLParamReset yTYPE			{ /*VARRESET-in-varLParam*/ VARDTYPE(new AstParseTypeDType($2)); }
	|	implicit_typeE 				{ /*VARRESET-in-varGParam*/ VARDTYPE($1); }
	|	data_type				{ /*VARRESET-in-varGParam*/ VARDTYPE($1); }
	|	yTYPE					{ /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($1)); }
	;

net_declaration<nodep>:		// IEEE: net_declaration - excluding implict
		net_declarationFront netSigList ';'	{ $$ = $2; }
	;

net_declarationFront:		// IEEE: beginning of net_declaration
		net_declRESET net_type   strengthSpecE net_scalaredE net_dataTypeE { VARDTYPE_NDECL($5); }
	//UNSUP	net_declRESET yINTERCONNECT signingE rangeListE { VARNET($2); VARDTYPE(x); }
	;

net_declRESET:
		/* empty */ 				{ VARRESET_NONLIST(UNKNOWN); }
	;

net_scalaredE:
		/* empty */ 				{ }
	//			//UNSUP: ySCALARED/yVECTORED ignored
	|	ySCALARED			 	{ }
	|	yVECTORED				{ }
	;

net_dataTypeE<dtypep>:
	//			// If there's a SV data type there shouldn't be a delay on this wire
	//			// Otherwise #(...) can't be determined to be a delay or parameters
	//			// Submit this as a footnote to the committee
		var_data_type	 			{ $$ = $1; }
	|	signingE rangeList delayE 		{ $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC, $1),$2,true); }  // not implicit
	|	signing					{ $$ = new AstBasicDType($<fl>1, LOGIC, $1); }  // not implicit
	|	/*implicit*/ delayE 			{ $$ = new AstBasicDType(CRELINE(), LOGIC); }  // not implicit
	;

net_type:			// ==IEEE: net_type
		ySUPPLY0				{ VARDECL(SUPPLY0); }
	|	ySUPPLY1				{ VARDECL(SUPPLY1); }
	|	yTRI 					{ VARDECL(TRIWIRE); }
	|	yTRI0 					{ VARDECL(TRI0); }
	|	yTRI1 					{ VARDECL(TRI1); }
	|	yTRIAND 				{ VARDECL(WIRE); BBUNSUP($1, "Unsupported: triand"); }
	|	yTRIOR 					{ VARDECL(WIRE); BBUNSUP($1, "Unsupported: trior"); }
	|	yTRIREG 				{ VARDECL(WIRE); BBUNSUP($1, "Unsupported: trireg"); }
	|	yWAND 					{ VARDECL(WIRE); BBUNSUP($1, "Unsupported: wand"); }
	|	yWIRE 					{ VARDECL(WIRE); }
	|	yWOR 					{ VARDECL(WIRE); BBUNSUP($1, "Unsupported: wor"); }
	//			// VAMS - somewhat hackish
	|	yWREAL 					{ VARDECL(WREAL); }
	;

varGParamReset:
		yPARAMETER				{ VARRESET_NONLIST(GPARAM); }
	;

varLParamReset:
		yLOCALPARAM				{ VARRESET_NONLIST(LPARAM); }
	;

port_direction:			// ==IEEE: port_direction + tf_port_direction
	//			// IEEE 19.8 just "input" FIRST forces type to wire - we'll ignore that here
	//			// Only used for ANSI declarations
		yINPUT					{ GRAMMARP->m_pinAnsi=true; VARIO(INPUT); }
	|	yOUTPUT					{ GRAMMARP->m_pinAnsi=true; VARIO(OUTPUT); }
	|	yINOUT					{ GRAMMARP->m_pinAnsi=true; VARIO(INOUT); }
	|	yREF					{ GRAMMARP->m_pinAnsi=true; VARIO(REF); }
	|	yCONST__REF yREF			{ GRAMMARP->m_pinAnsi=true; VARIO(CONSTREF); }
	;

port_directionReset:		// IEEE: port_direction that starts a port_declaraiton
	//			// Used only for declarations outside the port list
		yINPUT					{ VARRESET_NONLIST(UNKNOWN); VARIO(INPUT); }
	|	yOUTPUT					{ VARRESET_NONLIST(UNKNOWN); VARIO(OUTPUT); }
	|	yINOUT					{ VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); }
	|	yREF					{ VARRESET_NONLIST(UNKNOWN); VARIO(REF); }
	|	yCONST__REF yREF			{ VARRESET_NONLIST(UNKNOWN); VARIO(CONSTREF); }
	;

port_declaration<nodep>:	// ==IEEE: port_declaration
	//			// Non-ANSI; used inside block followed by ';'
	//			// SEE ALSO port, tf_port_declaration, data_declarationVarFront
	//
	//			// IEEE: inout_declaration
	//			// IEEE: input_declaration
	//			// IEEE: output_declaration
	//			// IEEE: ref_declaration
		port_directionReset port_declNetE data_type          { VARDTYPE($3); }
			list_of_variable_decl_assignments			{ $$ = $5; }
	|	port_directionReset port_declNetE yVAR data_type     { VARDTYPE($4); }
			list_of_variable_decl_assignments			{ $$ = $6; }
	|	port_directionReset port_declNetE yVAR implicit_typeE { VARDTYPE($4); }
			list_of_variable_decl_assignments			{ $$ = $6; }
	|	port_directionReset port_declNetE signingE rangeList { VARDTYPE_NDECL(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3), $4, true)); }
			list_of_variable_decl_assignments			{ $$ = $6; }
	|	port_directionReset port_declNetE signing	     { VARDTYPE_NDECL(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $3)); }
			list_of_variable_decl_assignments			{ $$ = $5; }
	|	port_directionReset port_declNetE /*implicit*/       { VARDTYPE_NDECL(NULL);/*default_nettype*/}
			list_of_variable_decl_assignments			{ $$ = $4; }
	//			// IEEE: interface_declaration
	//			// Looks just like variable declaration unless has a period
	//			// See etcInst
	;

tf_port_declaration<nodep>:	// ==IEEE: tf_port_declaration
	//			// Used inside function; followed by ';'
	//			// SEE ALSO port_declaration, port, data_declarationVarFront
	//
		port_directionReset      data_type      { VARDTYPE($2); }  list_of_tf_variable_identifiers ';'	{ $$ = $4; }
	|	port_directionReset      implicit_typeE { VARDTYPE_NDECL($2); }  list_of_tf_variable_identifiers ';'	{ $$ = $4; }
	|	port_directionReset yVAR data_type      { VARDTYPE($3); }  list_of_tf_variable_identifiers ';'	{ $$ = $5; }
	|	port_directionReset yVAR implicit_typeE { VARDTYPE($3); }  list_of_tf_variable_identifiers ';'	{ $$ = $5; }
	;

integer_atom_type<bdtypep>:	// ==IEEE: integer_atom_type
		yBYTE					{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::BYTE); }
	|	ySHORTINT				{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::SHORTINT); }
	|	yINT					{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::INT); }
	|	yLONGINT				{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::LONGINT); }
	|	yINTEGER				{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::INTEGER); }
	|	yTIME					{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::TIME); }
	;

integer_vector_type<bdtypep>:	// ==IEEE: integer_atom_type
		yBIT					{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::BIT); }
	|	yLOGIC					{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::LOGIC); }
	|	yREG					{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::LOGIC); } // logic==reg
	;

non_integer_type<bdtypep>:	// ==IEEE: non_integer_type
		yREAL					{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::DOUBLE); }
	|	yREALTIME				{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::DOUBLE); }
	|	ySHORTREAL				{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::DOUBLE); UNSUPREAL($1); }
	;

signingE<signstate>:		// IEEE: signing - plus empty
		/*empty*/ 				{ $$ = signedst_NOSIGN; }
	|	signing					{ $$ = $1; }
	;

signing<signstate>:		// ==IEEE: signing
		ySIGNED					{ $<fl>$ = $<fl>1; $$ = signedst_SIGNED; }
	|	yUNSIGNED				{ $<fl>$ = $<fl>1; $$ = signedst_UNSIGNED; }
	;

//************************************************
// Data Types

casting_type<dtypep>:		// IEEE: casting_type
		simple_type				{ $$ = $1; }
	//			// IEEE: constant_primary
	//			// In expr:cast this is expanded to just "expr"
	//
	//			// IEEE: signing
	//See where casting_type used
	//^^	ySIGNED					{ $$ = new AstSigned($1,$3); }
	//^^	yUNSIGNED				{ $$ = new AstUnsigned($1,$3); }
	//UNSUP	ySTRING					{ $$ = $1; }
	//UNSUP	yCONST__ETC/*then `*/			{ $$ = $1; }
	;

simple_type<dtypep>:		// ==IEEE: simple_type
	//			// IEEE: integer_type
		integer_atom_type			{ $$ = $1; }
	|	integer_vector_type			{ $$ = $1; }
	|	non_integer_type			{ $$ = $1; }
	//			// IEEE: ps_type_identifier
	//			// IEEE: ps_parameter_identifier (presumably a PARAMETER TYPE)
	|	ps_type					{ $$ = $1; }
	//			// { generate_block_identifer ... } '.'
	//			// Need to determine if generate_block_identifier can be lex-detected
	;

data_type<dtypep>:		// ==IEEE: data_type
	//			// This expansion also replicated elsewhere, IE data_type__AndID
		data_typeNoRef				{ $$ = $1; }
	//
	//			// REFERENCES
	//
	//			// IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension }
	//			// IEEE: class_type
	//			// IEEE: ps_covergroup_identifier
	//			// Don't distinguish between types and classes so all these combined
	|	package_scopeIdFollowsE idRefDType packed_dimensionListE
			{ $2->packagep($1);
			  $$ = GRAMMARP->createArray($2, $3, true); }
	|	package_scopeIdFollowsE idRefDType parameter_value_assignmentClass packed_dimensionListE
			{ $2->packagep($1);
			  BBUNSUP($3->fileline(), "Unsupported: Parameter classes");
			  $$ = GRAMMARP->createArray($2, $4, true); }
	;

data_typeBasic<dtypep>:		// IEEE: part of data_type
		integer_vector_type signingE rangeListE	{ $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); }
	|	integer_atom_type signingE		{ $1->setSignedState($2); $$ = $1; }
	|	non_integer_type			{ $$ = $1; }
	;

data_typeNoRef<dtypep>:		// ==IEEE: data_type, excluding class_type etc references
		data_typeBasic				{ $$ = $1; }
	|	struct_unionDecl packed_dimensionListE	{ $$ = GRAMMARP->createArray(new AstDefImplicitDType($1->fileline(),"__typeimpsu"+cvtToStr(GRAMMARP->s_modTypeImpNum++),
													     SYMP,VFlagChildDType(),$1),$2,true); }
	|	enumDecl				{ $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->s_modTypeImpNum++),
										       SYMP,VFlagChildDType(),$1); }
	|	ySTRING					{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); }
	|	yCHANDLE				{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::CHANDLE); }
	|	yEVENT					{ $$ = new AstBasicDType($1,AstBasicDTypeKwd::BIT); BBUNSUP($1, "Unsupported: event data types"); }
	//			// Rules overlap virtual_interface_declaration
	//			// Parameters here are SV2009
	//			// IEEE has ['.' modport] but that will conflict with port
	//			// declarations which decode '.' modport themselves, so
	//			// instead see data_typeVar
	|	yVIRTUAL__INTERFACE yINTERFACE id/*interface*/	{ $$ = NULL; BBUNSUP($1, "Unsupported: virtual interface"); }
	|	yVIRTUAL__anyID                id/*interface*/	{ $$ = NULL; BBUNSUP($1, "Unsupported: virtual data type"); }
	//UNSUP	type_reference				{ UNSUP }
	//			// IEEE: class_scope: see data_type above
	//			// IEEE: class_type: see data_type above
	//			// IEEE: ps_covergroup: see data_type above
	;

data_type_or_void<dtypep>:	// ==IEEE: data_type_or_void
		data_type				{ $$ = $1; }
	//UNSUP	yVOID					{ UNSUP }	// No yTAGGED structures
	;

var_data_type<dtypep>:		// ==IEEE: var_data_type
		data_type				{ $$ = $1; }
	|	yVAR data_type				{ $$ = $2; }
	|	yVAR implicit_typeE			{ $$ = $2; }
	;

//UNSUP type_reference<dtypep>:  // ==IEEE: type_reference
//UNSUP		yTYPE '(' exprOrDataType ')'		{ UNSUP }
//UNSUP	;

struct_unionDecl<uorstructp>:	// IEEE: part of data_type
	//			// packedSigningE is NOP for unpacked
		ySTRUCT        packedSigningE '{' 	{ $<uorstructp>$ = new AstStructDType($1, $2); SYMP->pushNew($<uorstructp>$); }
	/*cont*/	struct_union_memberList '}'
			{ $$=$<uorstructp>4; $$->addMembersp($5); SYMP->popScope($$); }
	|	yUNION taggedE packedSigningE '{' 	{ $<uorstructp>$ = new AstUnionDType($1, $3); SYMP->pushNew($<uorstructp>$); }
	/*cont*/	struct_union_memberList '}'
			{ $$=$<uorstructp>5; $$->addMembersp($6); SYMP->popScope($$); }
	;

struct_union_memberList<nodep>:	// IEEE: { struct_union_member }
		struct_union_member				{ $$ = $1; }
	|	struct_union_memberList struct_union_member	{ $$ = $1->addNextNull($2); }
	;

struct_union_member<nodep>:	// ==IEEE: struct_union_member
		random_qualifierE data_type_or_void
			{ GRAMMARP->m_memDTypep = $2; }  // As a list follows, need to attach this dtype to each member.
	/*cont*/	list_of_member_decl_assignments ';'	{ $$ = $4; GRAMMARP->m_memDTypep = NULL; }
	;

list_of_member_decl_assignments<nodep>:	// Derived from IEEE: list_of_variable_decl_assignments
		member_decl_assignment		{ $$ = $1; }
	|	list_of_member_decl_assignments ',' member_decl_assignment	{ $$ = $1->addNextNull($3); }
	;

member_decl_assignment<memberp>:	// Derived from IEEE: variable_decl_assignment
	//			// At present we allow only packed structures/unions.  So this is different from variable_decl_assignment
		id variable_dimensionListE
			{ if ($2) $2->v3error("Unsupported: Unpacked array in packed struct/union");
			  $$ = new AstMemberDType($<fl>1, *$1, VFlagChildDType(),
						  AstNodeDType::cloneTreeNull(GRAMMARP->m_memDTypep, true));
                          PARSEP->tagNodep($$);
                          }
	|	id variable_dimensionListE '=' variable_declExpr
			{ $4->v3error("Unsupported: Initial values in struct/union members.");
			  $$ = NULL; }
	|	idSVKwd					{ $$ = NULL; }
	//
	//			// IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]"
	//			// Matches above with variable_dimensionE = "[]"
	//			// IEEE: "class_variable_identifier [ '=' class_new ]"
	//			// variable_dimensionE must be empty
	//			// Pushed into variable_declExpr:dynamic_array_new
	//
	//			// IEEE: "[ covergroup_variable_identifier ] '=' class_new
	//			// Pushed into variable_declExpr:class_new
	|	'=' class_new				{ NULL; BBUNSUP($1, "Unsupported: member declaration assignment with new()"); }
	;

list_of_variable_decl_assignments<nodep>:	// ==IEEE: list_of_variable_decl_assignments
		variable_decl_assignment		{ $$ = $1; }
	|	list_of_variable_decl_assignments ',' variable_decl_assignment	{ $$ = $1->addNextNull($3); }
	;

variable_decl_assignment<varp>:	// ==IEEE: variable_decl_assignment
		id variable_dimensionListE sigAttrListE
			{ $$ = VARDONEA($<fl>1,*$1,$2,$3); }
	|	id variable_dimensionListE sigAttrListE '=' variable_declExpr
			{ $$ = VARDONEA($<fl>1,*$1,$2,$3); $$->valuep($5); }
	|	idSVKwd					{ $$ = NULL; }
	//
	//			// IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]"
	//			// Matches above with variable_dimensionE = "[]"
	//			// IEEE: "class_variable_identifier [ '=' class_new ]"
	//			// variable_dimensionE must be empty
	//			// Pushed into variable_declExpr:dynamic_array_new
	//
	//			// IEEE: "[ covergroup_variable_identifier ] '=' class_new
	//			// Pushed into variable_declExpr:class_new
	|	'=' class_new				{ NULL; BBUNSUP($1, "Unsupported: declaration assignment with new()"); }
	;

list_of_tf_variable_identifiers<nodep>: // ==IEEE: list_of_tf_variable_identifiers
		tf_variable_identifier			{ $$ = $1; }
	|	list_of_tf_variable_identifiers ',' tf_variable_identifier	{ $$ = $1->addNext($3); }
	;

tf_variable_identifier<varp>:		// IEEE: part of list_of_tf_variable_identifiers
		id variable_dimensionListE sigAttrListE
			{ $$ = VARDONEA($<fl>1,*$1, $2, $3); }
	|	id variable_dimensionListE sigAttrListE '=' expr
			{ $$ = VARDONEA($<fl>1,*$1, $2, $3);
			  $$->addNext(new AstAssign($4, new AstVarRef($<fl>1, *$1, true), $5)); }
	;

variable_declExpr<nodep>:		// IEEE: part of variable_decl_assignment - rhs of expr
		expr					{ $$ = $1; }
	|	dynamic_array_new			{ $$ = $1; }
	|	class_new				{ $$ = $1; }
	;

variable_dimensionListE<rangep>:	// IEEE: variable_dimension + empty
		/*empty*/				{ $$ = NULL; }
	|	variable_dimensionList			{ $$ = $1; }
	;

variable_dimensionList<rangep>:	// IEEE: variable_dimension + empty
		variable_dimension			{ $$ = $1; }
	|	variable_dimensionList variable_dimension	{ $$ = VN_CAST($1->addNext($2), NodeRange); }
	;

variable_dimension<rangep>:	// ==IEEE: variable_dimension
	//			// IEEE: unsized_dimension
		'[' ']'					{ $$ = new AstUnsizedRange($1); }
	//			// IEEE: unpacked_dimension
	|	anyrange				{ $$ = $1; }
	|	'[' constExpr ']'			{ if (VN_IS($2, Unbounded)) { $2->deleteTree(); $$ = new AstQueueRange($1); }
							  else { $$ = new AstRange($1, new AstConst($1, 0),
								 		   new AstSub($1, $2, new AstConst($1, 1))); } }
	//			// IEEE: associative_dimension
	|	'[' data_type ']'			{ $$ = new AstAssocRange($1, $2); }
	|	yP_BRASTAR ']'				{ $$ = NULL; v3error("Unsupported: [*] wildcard associative arrays"); }
	|	'[' '*' ']'				{ $$ = NULL; v3error("Unsupported: [*] wildcard associative arrays"); }
	//			// IEEE: queue_dimension
	//			// '[' '$' ']' -- $ is part of expr, see '[' constExpr ']'
	//			// '[' '$' ':' expr ']' -- anyrange:expr:$
	;

random_qualifierE:		// IEEE: random_qualifier + empty
		/*empty*/				{ }
	|	random_qualifier			{ }
	;

random_qualifier:		// ==IEEE: random_qualifier
		yRAND					{ }  // Ignored until we support randomize()
	|	yRANDC					{ }  // Ignored until we support randomize()
	;

taggedE:
		/*empty*/				{ }
	//UNSUP	yTAGGED					{ UNSUP }
	;

packedSigningE<signstate>:
	//			// AstNumeric::NOSIGN overloaded to indicate not packed
		/*empty*/				{ $$ = signedst_NOSIGN; }
	|	yPACKED signingE			{ $$ = $2; if ($$ == signedst_NOSIGN) $$ = signedst_UNSIGNED; }
	;

//************************************************
// enum

// IEEE: part of data_type
enumDecl<dtypep>:
		yENUM enum_base_typeE '{' enum_nameList '}' { $$ = new AstEnumDType($1,VFlagChildDType(),$2,$4); }
	;

enum_base_typeE<dtypep>:	// IEEE: enum_base_type
		/* empty */				{ $$ = new AstBasicDType(CRELINE(), AstBasicDTypeKwd::INT); }
	//			// Not in spec, but obviously "enum [1:0]" should work
	//			// implicit_type expanded, without empty
	//			// Note enum base types are always packed data types
	|	signingE rangeList			{ $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); }
	|	signing					{ $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
	//
	|	integer_atom_type signingE		{ $1->setSignedState($2); $$ = $1; }
	|	integer_vector_type signingE rangeListE	{ $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); }
	//			// below can be idAny or yaID__aTYPE
	//			// IEEE requires a type, though no shift conflict if idAny
	|	idAny rangeListE			{ $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2, true); }
	;

enum_nameList<nodep>:
		enum_name_declaration			{ $$ = $1; }
	|	enum_nameList ',' enum_name_declaration	{ $$ = $1->addNextNull($3); }
	;

enum_name_declaration<nodep>:	// ==IEEE: enum_name_declaration
		idAny/*enum_identifier*/ enumNameRangeE enumNameStartE	{ $$ = new AstEnumItem($<fl>1, *$1, $2, $3); }
	;

enumNameRangeE<nodep>:		// IEEE: second part of enum_name_declaration
		/* empty */				{ $$ = NULL; }
	|	'[' intnumAsConst ']'			{ $$ = new AstRange($1, new AstConst($1, 0), new AstConst($1, $2->toSInt()-1)); }
	|	'[' intnumAsConst ':' intnumAsConst ']'	{ $$ = new AstRange($1,$2,$4); }
	;

enumNameStartE<nodep>:		// IEEE: third part of enum_name_declaration
		/* empty */				{ $$ = NULL; }
	|	'=' constExpr				{ $$ = $2; }
	;

intnumAsConst<constp>:
		yaINTNUM				{ $$ = new AstConst($<fl>1,*$1); }
	;

//************************************************
// Typedef

data_declaration<nodep>:	// ==IEEE: data_declaration
	//			// VARRESET can't be called here - conflicts
		data_declarationVar			{ $$ = $1; }
	|	type_declaration			{ $$ = $1; }
	|	package_import_declaration		{ $$ = $1; }
	//			// IEEE: virtual_interface_declaration
	//			// "yVIRTUAL yID yID" looks just like a data_declaration
	//			// Therefore the virtual_interface_declaration term isn't used
	//			// 1800-2009:
	//UNSUP	net_type_declaration			{ $$ = $1; }
	;

class_property<nodep>:		// ==IEEE: class_property, which is {property_qualifier} data_declaration
		memberQualResetListE data_declarationVarClass		{ $$ = $2; }
	|	memberQualResetListE type_declaration			{ $$ = $2; }
	|	memberQualResetListE package_import_declaration		{ $$ = $2; }
	//			// IEEE: virtual_interface_declaration
	//			// "yVIRTUAL yID yID" looks just like a data_declaration
	//			// Therefore the virtual_interface_declaration term isn't used
	;

data_declarationVar<nodep>:	// IEEE: part of data_declaration
	//			// The first declaration has complications between assuming what's the type vs ID declaring
		data_declarationVarFront list_of_variable_decl_assignments ';'	{ $$ = $2; }
	;

data_declarationVarClass<nodep>: // IEEE: part of data_declaration (for class_property)
	//			// The first declaration has complications between assuming what's the type vs ID declaring
		data_declarationVarFrontClass list_of_variable_decl_assignments ';'	{ $$ = $2; }
	;

data_declarationVarFront:	// IEEE: part of data_declaration
	//			// Non-ANSI; used inside block followed by ';'
	//			// SEE ALSO port_declaration, tf_port_declaration, port
	//
	//			// Expanded: "constE yVAR lifetimeE data_type"
	//			// implicit_type expanded into /*empty*/ or "signingE rangeList"
		/**/ 	    yVAR lifetimeE data_type	{ VARRESET_NONLIST(VAR); VARDTYPE($3); }
	|	/**/ 	    yVAR lifetimeE		{ VARRESET_NONLIST(VAR); VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT)); }
	|	/**/ 	    yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $3), $4,true)); }
	//
	//			// implicit_type expanded into /*empty*/ or "signingE rangeList"
	|	yCONST__ETC yVAR lifetimeE data_type	{ VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>2, VFlagChildDType(), $4)); }
	|	yCONST__ETC yVAR lifetimeE		{ VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>2, VFlagChildDType(), new AstBasicDType($<fl>2, LOGIC_IMPLICIT))); }
	|	yCONST__ETC yVAR lifetimeE signingE rangeList { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>2, VFlagChildDType(), GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4), $5,true))); }
	//
	//			// Expanded: "constE lifetimeE data_type"
	|	/**/		      data_type		{ VARRESET_NONLIST(VAR); VARDTYPE($1); }
	|	/**/	    lifetime  data_type		{ VARRESET_NONLIST(VAR); VARDTYPE($2); }
	|	yCONST__ETC lifetimeE data_type		{ VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>1, VFlagChildDType(), $3)); }
	//			// = class_new is in variable_decl_assignment
	;

data_declarationVarFrontClass:	// IEEE: part of data_declaration (for class_property)
	//			// VARRESET called before this rule
	//			// yCONST is removed, added to memberQual rules
	//			// implicit_type expanded into /*empty*/ or "signingE rangeList"
		yVAR lifetimeE data_type	{ VARRESET_NONLIST(VAR); VARDTYPE($3); }
	|	yVAR lifetimeE			{ VARRESET_NONLIST(VAR); }
	|	yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $3), $4,true)); }
	//
	//			// Expanded: "constE lifetimeE data_type"
	|	data_type			{ VARRESET_NONLIST(VAR); VARDTYPE($1); }
	//			// lifetime is removed, added to memberQual rules to avoid conflict
	//			// yCONST is removed, added to memberQual rules to avoid conflict
	//			// = class_new is in variable_decl_assignment
	;

//UNSUPnet_type_declaration:		// IEEE: net_type_declaration
//UNSUP		yNETTYPE data_type idAny/*net_type_identifier*/ ';' { }
//UNSUP	//			// package_scope part of data_type
//UNSUP	|	yNETTYPE data_type idAny yWITH__ETC package_scopeIdFollows id/*tf_identifier*/ ';' { }
//UNSUP	|	yNETTYPE package_scopeIdFollows id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';' { }
//UNSUP	;

implicit_typeE<dtypep>:		// IEEE: part of *data_type_or_implicit
	//			// Also expanded in data_declaration
		/* empty */				{ $$ = NULL; }
	|	signingE rangeList			{ $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); }
	|	signing					{ $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
	;

//UNSUPassertion_variable_declaration:  // IEEE: assertion_variable_declaration
//UNSUP	//			// IEEE: var_data_type expanded
//UNSUP		var_data_type list_of_variable_decl_assignments ';'	{ }
//UNSUP	;

type_declaration<nodep>:	// ==IEEE: type_declaration
	//			// Use idAny, as we can redeclare a typedef on an existing typedef
		yTYPEDEF data_type idAny variable_dimensionListE dtypeAttrListE ';'
	/**/	{ $$ = new AstTypedef($<fl>3, *$3, $5, VFlagChildDType(), GRAMMARP->createArray($2,$4,false));
		  SYMP->reinsert($$); PARSEP->tagNodep($$); }
	|	yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';'	{ $$ = NULL; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); }
	//			// Combines into above "data_type id" rule
	//			// Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
	|	yTYPEDEF id ';'				{ $$ = NULL; $$ = new AstTypedefFwd($<fl>2, *$2); SYMP->reinsert($$); PARSEP->tagNodep($$); }
	|	yTYPEDEF yENUM idAny ';'		{ $$ = NULL; $$ = new AstTypedefFwd($<fl>3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); }
	|	yTYPEDEF ySTRUCT idAny ';'		{ $$ = NULL; $$ = new AstTypedefFwd($<fl>3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); }
	|	yTYPEDEF yUNION idAny ';'		{ $$ = NULL; $$ = new AstTypedefFwd($<fl>3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); }
	|	yTYPEDEF yCLASS idAny ';'		{ $$ = NULL; $$ = new AstTypedefFwd($<fl>3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); }
	|	yTYPEDEF yINTERFACE yCLASS idAny ';'	{ $$ = NULL; $$ = new AstTypedefFwd($<fl>4, *$4); SYMP->reinsert($$); PARSEP->tagNodep($$); }
	;

dtypeAttrListE<nodep>:
		/* empty */				{ $$ = NULL; }
	|	dtypeAttrList				{ $$ = $1; }
	;

dtypeAttrList<nodep>:
		dtypeAttr				{ $$ = $1; }
	|	dtypeAttrList dtypeAttr			{ $$ = $1->addNextNull($2); }
	;

dtypeAttr<nodep>:
		yVL_PUBLIC				{ $$ = new AstAttrOf($1,AstAttrType::DT_PUBLIC); }
	;

//************************************************
// Module Items

module_itemListE<nodep>:	// IEEE: Part of module_declaration
		/* empty */				{ $$ = NULL; }
	|	module_itemList				{ $$ = $1; }
	;

module_itemList<nodep>:		// IEEE: Part of module_declaration
		module_item				{ $$ = $1; }
	|	module_itemList module_item		{ $$ = $1->addNextNull($2); }
	;

module_item<nodep>:		// ==IEEE: module_item
		port_declaration ';'			{ $$ = $1; }
	|	non_port_module_item			{ $$ = $1; }
	;

non_port_module_item<nodep>:	// ==IEEE: non_port_module_item
		generate_region				{ $$ = $1; }
	|	module_or_generate_item 		{ $$ = $1; }
	|	specify_block 				{ $$ = $1; }
	|	specparam_declaration			{ $$ = $1; }
	|	program_declaration			{ $$ = NULL; v3error("Unsupported: program decls within module decls"); }
	|	module_declaration			{ $$ = NULL; v3error("Unsupported: module decls within module decls"); }
	|	interface_declaration			{ $$ = NULL; v3error("Unsupported: interface decls within module decls"); }
	|	timeunits_declaration			{ $$ = $1; }
	//			// Verilator specific
	|	yaSCHDR					{ $$ = new AstScHdr($<fl>1,*$1); }
	|	yaSCINT					{ $$ = new AstScInt($<fl>1,*$1); }
	|	yaSCIMP					{ $$ = new AstScImp($<fl>1,*$1); }
	|	yaSCIMPH				{ $$ = new AstScImpHdr($<fl>1,*$1); }
	|	yaSCCTOR				{ $$ = new AstScCtor($<fl>1,*$1); }
	|	yaSCDTOR				{ $$ = new AstScDtor($<fl>1,*$1); }
	|	yVL_INLINE_MODULE			{ $$ = new AstPragma($1,AstPragmaType::INLINE_MODULE); }
	|	yVL_NO_INLINE_MODULE			{ $$ = new AstPragma($1,AstPragmaType::NO_INLINE_MODULE); }
	|	yVL_PUBLIC_MODULE			{ $$ = new AstPragma($1,AstPragmaType::PUBLIC_MODULE); v3Global.dpi(true); }
	;

module_or_generate_item<nodep>:	// ==IEEE: module_or_generate_item
	//			// IEEE: parameter_override
		yDEFPARAM list_of_defparam_assignments ';'	{ $$ = $2; }
	//			// IEEE: gate_instantiation + udp_instantiation + module_instantiation
	//			// not here, see etcInst in module_common_item
	//			// We joined udp & module definitions, so this goes here
	|	combinational_body			{ $$ = $1; }
	//			// This module_common_item shared with interface_or_generate_item:module_common_item
	|	module_common_item			{ $$ = $1; }
	;

module_common_item<nodep>:	// ==IEEE: module_common_item
		module_or_generate_item_declaration	{ $$ = $1; }
	//			// IEEE: interface_instantiation
	//			// + IEEE: program_instantiation
	//			// + module_instantiation from module_or_generate_item
	|	etcInst 				{ $$ = $1; }
	|	assertion_item				{ $$ = $1; }
	|	bind_directive				{ $$ = $1; }
	|	continuous_assign			{ $$ = $1; }
	//			// IEEE: net_alias
	|	yALIAS variable_lvalue aliasEqList ';'	{ $$ = NULL; BBUNSUP($1, "Unsupported: alias statements"); }
	|	initial_construct			{ $$ = $1; }
	|	final_construct				{ $$ = $1; }
	//			// IEEE: always_construct
	//			// Verilator only - event_control attached to always
	|	yALWAYS       event_controlE stmtBlock	{ $$ = new AstAlways($1,VAlwaysKwd::ALWAYS, $2,$3); }
	|	yALWAYS_FF    event_controlE stmtBlock	{ $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_FF, $2,$3); }
	|	yALWAYS_LATCH event_controlE stmtBlock	{ $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, $2,$3); }
	|	yALWAYS_COMB  stmtBlock			{ $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_COMB, NULL, $2); }
	//
	|	loop_generate_construct			{ $$ = $1; }
	|	conditional_generate_construct		{ $$ = $1; }
	|	elaboration_system_task			{ $$ = $1; }
	//
	|	error ';'				{ $$ = NULL; }
	;

continuous_assign<nodep>:	// IEEE: continuous_assign
		yASSIGN strengthSpecE delayE assignList ';'	{ $$ = $4; }
	;

initial_construct<nodep>:	// IEEE: initial_construct
		yINITIAL stmtBlock			{ $$ = new AstInitial($1,$2); }
	;

final_construct<nodep>:		// IEEE: final_construct
		yFINAL stmtBlock			{ $$ = new AstFinal($1,$2); }
	;

module_or_generate_item_declaration<nodep>:	// ==IEEE: module_or_generate_item_declaration
		package_or_generate_item_declaration	{ $$ = $1; }
	| 	genvar_declaration			{ $$ = $1; }
	|	clocking_declaration			{ $$ = $1; }
	|	yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';'	{ $$ = NULL; BBUNSUP($1, "Unsupported: default clocking identifier"); }
	//UNSUP	yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';'	{ }
	;

aliasEqList:			// IEEE: part of net_alias
		'=' variable_lvalue			{ }
	|	aliasEqList '=' variable_lvalue		{ }
	;

bind_directive<nodep>:		// ==IEEE: bind_directive + bind_target_scope
	//			// ';' - Note IEEE grammar is wrong, includes extra ';' - it's already in module_instantiation
	//			// We merged the rules - id may be a bind_target_instance or module_identifier or interface_identifier
		yBIND bind_target_instance bind_instantiation	{ $$ = new AstBind($<fl>2, *$2, $3); }
	|	yBIND bind_target_instance ':' bind_target_instance_list bind_instantiation
			{ $$ = NULL; BBUNSUP($1, "Unsupported: Bind with instance list"); }
	;

bind_target_instance_list:	// ==IEEE: bind_target_instance_list
		bind_target_instance			{ }
	|	bind_target_instance_list ',' bind_target_instance	{ }
	;

bind_target_instance<strp>:	// ==IEEE: bind_target_instance
	//UNSUP	hierarchical_identifierBit		{ }
		idAny					{ $$ = $1; }
	;

bind_instantiation<nodep>:	// ==IEEE: bind_instantiation
	//			// IEEE: program_instantiation
	//			// IEEE: + module_instantiation
	//			// IEEE: + interface_instantiation
	//			// Need to get an AstBind instead of AstCell, so have special rules
		instDecl				{ $$ = $1; }
	;

//************************************************
// Generates
//
// Way down in generate_item is speced a difference between module,
// interface and checker generates.  modules and interfaces are almost
// identical (minus DEFPARAMs) so we overlap them.  Checkers are too
// different, so we copy all rules for checkers.

generate_region<nodep>:		// ==IEEE: generate_region
		yGENERATE ~c~genItemList yENDGENERATE	{ $$ = new AstGenerate($1, $2); }
	|	yGENERATE yENDGENERATE			{ $$ = NULL; }
	;

//UNSUPc_generate_region<nodep>:  // IEEE: generate_region (for checkers)
//UNSUP		BISONPRE_COPY(generate_region,{s/~c~/c_/g})	// {copied}
//UNSUP	;

generate_block_or_null<nodep>:	// IEEE: generate_block_or_null
	//	';'		// is included in
	//			// IEEE: generate_block
	//			// Must always return a BEGIN node, or NULL - see GenFor construction
		generate_item				{ $$ = $1 ? (new AstBegin($1->fileline(),"genblk",$1,true)) : NULL; }
	|	genItemBegin				{ $$ = $1; }
	;

genItemBegin<nodep>:		// IEEE: part of generate_block
		yBEGIN ~c~genItemList yEND		{ $$ = new AstBegin($1,"genblk",$2,true); }
	|	yBEGIN yEND				{ $$ = NULL; }
	|	id ':' yBEGIN ~c~genItemList yEND endLabelE	{ $$ = new AstBegin($<fl>1,*$1,$4,true); GRAMMARP->endLabel($<fl>6,*$1,$6); }
	|	id ':' yBEGIN yEND endLabelE		{ $$ = NULL; GRAMMARP->endLabel($<fl>5,*$1,$5); }
	|	yBEGIN ':' idAny ~c~ genItemList yEND endLabelE	{ $$ = new AstBegin($<fl>3,*$3,$4,true); GRAMMARP->endLabel($<fl>6,*$3,$6); }
	|	yBEGIN ':' idAny yEND endLabelE		{ $$ = NULL; GRAMMARP->endLabel($<fl>5,*$3,$5); }
	;

//UNSUPc_genItemBegin<nodep>:  // IEEE: part of generate_block (for checkers)
//UNSUP		BISONPRE_COPY(genItemBegin,{s/~c~/c_/g})		// {copied}
//UNSUP	;

genItemOrBegin<nodep>:		// Not in IEEE, but our begin isn't under generate_item
		~c~generate_item			{ $$ = $1; }
	|	~c~genItemBegin				{ $$ = $1; }
	;

//UNSUPc_genItemOrBegin<nodep>:  // (for checkers)
//UNSUP		BISONPRE_COPY(genItemOrBegin,{s/~c~/c_/g})	// {copied}
//UNSUP	;

genItemList<nodep>:
		~c~genItemOrBegin			{ $$ = $1; }
	|	~c~genItemList ~c~genItemOrBegin	{ $$ = $1->addNextNull($2); }
	;

//UNSUPc_genItemList<nodep>:  // (for checkers)
//UNSUP		BISONPRE_COPY(genItemList,{s/~c~/c_/g})		// {copied}
//UNSUP	;

generate_item<nodep>:		// IEEE: module_or_interface_or_generate_item
	//			// Only legal when in a generate under a module (or interface under a module)
		module_or_generate_item			{ $$ = $1; }
	//			// Only legal when in a generate under an interface
	//UNSUP	interface_or_generate_item		{ $$ = $1; }
	//			// IEEE: checker_or_generate_item
	//			// Only legal when in a generate under a checker
	//			// so below in c_generate_item
	;

//UNSUPc_generate_item<nodep>:  // IEEE: generate_item (for checkers)
//UNSUP		checker_or_generate_item		{ $$ = $1; }
//UNSUP	;

conditional_generate_construct<nodep>:	// ==IEEE: conditional_generate_construct
		yCASE  '(' expr ')' ~c~case_generate_itemListE yENDCASE
			{ $$ = new AstGenCase($1, $3, $5); }
	|	yIF '(' expr ')' ~c~generate_block_or_null	%prec prLOWER_THAN_ELSE
			{ $$ = new AstGenIf($1, $3, $5, NULL); }
	|	yIF '(' expr ')' ~c~generate_block_or_null yELSE ~c~generate_block_or_null
			{ $$ = new AstGenIf($1, $3, $5, $7); }
	;

//UNSUPc_conditional_generate_construct<nodep>:  // IEEE: conditional_generate_construct (for checkers)
//UNSUP		BISONPRE_COPY(conditional_generate_construct,{s/~c~/c_/g})	// {copied}
//UNSUP	;

loop_generate_construct<nodep>:	// ==IEEE: loop_generate_construct
		yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' ~c~generate_block_or_null
			{ // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar
			  AstBegin* lowerBegp = VN_CAST($9, Begin);
			  UASSERT_OBJ(!($9 && !lowerBegp), $9, "Child of GENFOR should have been begin");
			  if (!lowerBegp) lowerBegp = new AstBegin($1,"genblk",NULL,true);  // Empty body
			  AstNode* lowerNoBegp = lowerBegp->stmtsp();
			  if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext();
			  //
			  AstBegin* blkp = new AstBegin($1,lowerBegp->name(),NULL,true);
			  // V3LinkDot detects BEGIN(GENFOR(...)) as a special case
			  AstNode* initp = $3;  AstNode* varp = $3;
			  if (VN_IS(varp, Var)) {  // Genvar
				initp = varp->nextp();
				initp->unlinkFrBackWithNext();  // Detach 2nd from varp, make 1st init
				blkp->addStmtsp(varp);
			  }
			  // Statements are under 'genforp' as cells under this
			  // for loop won't get an extra layer of hierarchy tacked on
			  blkp->addGenforp(new AstGenFor($1,initp,$5,$7,lowerNoBegp));
			  $$ = blkp;
			  lowerBegp->deleteTree(); VL_DANGLING(lowerBegp);
			}
	;

//UNSUPc_loop_generate_construct<nodep>:  // IEEE: loop_generate_construct (for checkers)
//UNSUP		BISONPRE_COPY(loop_generate_construct,{s/~c~/c_/g})	// {copied}
//UNSUP	;

genvar_initialization<nodep>:	// ==IEEE: genvar_initialization
		varRefBase '=' expr			{ $$ = new AstAssign($2,$1,$3); }
	|	yGENVAR genvar_identifierDecl '=' constExpr	{ $$ = $2; $2->addNext(new AstAssign($3,new AstVarRef($2->fileline(),$2,true), $4)); }
	;

genvar_iteration<nodep>:	// ==IEEE: genvar_iteration
		varRefBase '=' 		expr		{ $$ = new AstAssign($2,$1,$3); }
	|	varRefBase yP_PLUSEQ	expr		{ $$ = new AstAssign($2,$1,new AstAdd    ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_MINUSEQ	expr		{ $$ = new AstAssign($2,$1,new AstSub    ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_TIMESEQ	expr		{ $$ = new AstAssign($2,$1,new AstMul    ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_DIVEQ	expr		{ $$ = new AstAssign($2,$1,new AstDiv    ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_MODEQ	expr		{ $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_ANDEQ	expr		{ $$ = new AstAssign($2,$1,new AstAnd    ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_OREQ	expr		{ $$ = new AstAssign($2,$1,new AstOr     ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_XOREQ	expr		{ $$ = new AstAssign($2,$1,new AstXor    ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_SLEFTEQ	expr		{ $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_SRIGHTEQ	expr		{ $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
	|	varRefBase yP_SSRIGHTEQ	expr		{ $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
	//			// inc_or_dec_operator
	// When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeMathStmt?
	|	yP_PLUSPLUS   varRefBase		{ $$ = new AstAssign($1,$2,new AstAdd    ($1,$2->cloneTree(true), new AstConst($1, AstConst::StringToParse(), "'b1"))); }
	|	yP_MINUSMINUS varRefBase		{ $$ = new AstAssign($1,$2,new AstSub    ($1,$2->cloneTree(true), new AstConst($1, AstConst::StringToParse(), "'b1"))); }
	|	varRefBase yP_PLUSPLUS			{ $$ = new AstAssign($2,$1,new AstAdd    ($2,$1->cloneTree(true), new AstConst($2, AstConst::StringToParse(), "'b1"))); }
	|	varRefBase yP_MINUSMINUS		{ $$ = new AstAssign($2,$1,new AstSub    ($2,$1->cloneTree(true), new AstConst($2, AstConst::StringToParse(), "'b1"))); }
	;

case_generate_itemListE<nodep>:	// IEEE: [{ case_generate_itemList }]
		/* empty */				{ $$ = NULL; }
	|	case_generate_itemList			{ $$ = $1; }
	;

case_generate_itemList<nodep>:	// IEEE: { case_generate_itemList }
		~c~case_generate_item			{ $$=$1; }
	|	~c~case_generate_itemList ~c~case_generate_item	{ $$=$1; $1->addNext($2); }
	;

//UNSUPc_case_generate_itemList<nodep>:  // IEEE: { case_generate_item } (for checkers)
//UNSUP		BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g})	// {copied}
//UNSUP	;

case_generate_item<nodep>:	// ==IEEE: case_generate_item
		caseCondList ':' generate_block_or_null		{ $$ = new AstCaseItem($2,$1,$3); }
	|	yDEFAULT ':' generate_block_or_null		{ $$ = new AstCaseItem($1,NULL,$3); }
	|	yDEFAULT generate_block_or_null			{ $$ = new AstCaseItem($1,NULL,$2); }
	;

//UNSUPc_case_generate_item<nodep>:  // IEEE: case_generate_item (for checkers)
//UNSUP		BISONPRE_COPY(case_generate_item,{s/~c~/c_/g})	// {copied}
//UNSUP	;

//************************************************
// Assignments and register declarations

assignList<nodep>:
		assignOne				{ $$ = $1; }
	|	assignList ',' assignOne		{ $$ = $1->addNext($3); }
	;

assignOne<nodep>:
		variable_lvalue '=' expr		{ $$ = new AstAssignW($2,$1,$3); }
	;

//UNSUPdelay_or_event_controlE<nodep>:  // IEEE: delay_or_event_control plus empty
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	delay_control				{ $$ = $1; }
//UNSUP	|	event_control				{ $$ = $1; }
//UNSUP	|	yREPEAT '(' expr ')' event_control	{ }
//UNSUP	;

delayE:
		/* empty */				{ }
	|	delay_control				{ $1->v3warn(ASSIGNDLY,"Unsupported: Ignoring delay on this assignment/primitive."); } /* ignored */
	;

delay_control<fl>:	//== IEEE: delay_control
		'#' delay_value				{ $$ = $1; } /* ignored */
	|	'#' '(' minTypMax ')'			{ $$ = $1; } /* ignored */
	|	'#' '(' minTypMax ',' minTypMax ')'			{ $$ = $1; } /* ignored */
	|	'#' '(' minTypMax ',' minTypMax ',' minTypMax ')'	{ $$ = $1; } /* ignored */
	;

delay_value:			// ==IEEE:delay_value
	//			// IEEE: ps_identifier
		ps_id_etc				{ }
	|	yaINTNUM 				{ }
	|	yaFLOATNUM 				{ }
	|	yaTIMENUM 				{ }
	;

delayExpr:
		expr					{ DEL($1); }
	//			// Verilator doesn't support yaTIMENUM, so not in expr
	//UNSUP below doesn't belong here:
	|	yaTIMENUM 				{ }
	;

minTypMax:			// IEEE: mintypmax_expression and constant_mintypmax_expression
		delayExpr				{ }
	|	delayExpr ':' delayExpr ':' delayExpr	{ }
	;

netSigList<varp>:		// IEEE: list_of_port_identifiers
		netSig  				{ $$ = $1; }
	|	netSigList ',' netSig		       	{ $$ = $1; $1->addNext($3); }
	;

netSig<varp>:			// IEEE: net_decl_assignment -  one element from list_of_port_identifiers
		netId sigAttrListE			{ $$ = VARDONEA($<fl>1,*$1, NULL, $2); }
	|	netId sigAttrListE '=' expr		{ $$ = VARDONEA($<fl>1,*$1, NULL, $2);
							  $$->addNext(new AstAssignW($3, new AstVarRef($<fl>1, *$1, true), $4)); }
	|	netId variable_dimensionList sigAttrListE	{ $$ = VARDONEA($<fl>1,*$1, $2, $3); }
	;

netId<strp>:
		id/*new-net*/				{ $$ = $1; $<fl>$=$<fl>1; }
	|	idSVKwd					{ $$ = $1; $<fl>$=$<fl>1; }
	;

sigAttrListE<nodep>:
		/* empty */				{ $$ = NULL; }
	|	sigAttrList				{ $$ = $1; }
	;

sigAttrList<nodep>:
		sigAttr					{ $$ = $1; }
	|	sigAttrList sigAttr			{ $$ = $1->addNextNull($2); }
	;

sigAttr<nodep>:
		yVL_CLOCK				{ $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK); }
	|	yVL_CLOCKER				{ $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCKER); }
	|	yVL_NO_CLOCKER				{ $$ = new AstAttrOf($1,AstAttrType::VAR_NO_CLOCKER); }
	|	yVL_CLOCK_ENABLE			{ $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); }
	|	yVL_PUBLIC				{ $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); v3Global.dpi(true); }
	|	yVL_PUBLIC_FLAT				{ $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); v3Global.dpi(true); }
	|	yVL_PUBLIC_FLAT_RD			{ $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RD); v3Global.dpi(true); }
	|	yVL_PUBLIC_FLAT_RW			{ $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); }
	|	yVL_PUBLIC_FLAT_RW attr_event_control	{ $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true);
							  $$ = $$->addNext(new AstAlwaysPublic($1,$2,NULL)); }
	|	yVL_ISOLATE_ASSIGNMENTS			{ $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
	|	yVL_SC_BV				{ $$ = new AstAttrOf($1,AstAttrType::VAR_SC_BV); }
	|	yVL_SFORMAT				{ $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
	;

rangeListE<rangep>:		// IEEE: [{packed_dimension}]
		/* empty */    		               	{ $$ = NULL; }
	|	rangeList 				{ $$ = $1; }
	;

rangeList<rangep>:		// IEEE: {packed_dimension}
		anyrange				{ $$ = $1; }
        |	rangeList anyrange			{ $$ = $1; $1->addNext($2); }
	;

//UNSUPbit_selectE<fl>:  // IEEE: constant_bit_select (IEEE included empty)
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	'[' constExpr ']'			{ $<fl>$=$<fl>1; $$ = "["+$2+"]"; }
//UNSUP	;

// IEEE: select
// Merged into more general idArray

anyrange<rangep>:
		'[' constExpr ':' constExpr ']'		{ $$ = new AstRange($1,$2,$4); }
	;

packed_dimensionListE<rangep>:	// IEEE: [{ packed_dimension }]
		/* empty */				{ $$ = NULL; }
	|	packed_dimensionList			{ $$ = $1; }
	;

packed_dimensionList<rangep>:	// IEEE: { packed_dimension }
		packed_dimension			{ $$ = $1; }
	|	packed_dimensionList packed_dimension	{ $$ = VN_CAST($1->addNext($2), NodeRange); }
	;

packed_dimension<rangep>:	// ==IEEE: packed_dimension
		anyrange				{ $$ = $1; }
	|	'[' ']'					{ $$ = NULL; $<fl>1->v3error("Unsupported: [] dimensions"); }
	;

//************************************************
// Parameters

param_assignment<varp>:		// ==IEEE: param_assignment
	//			// IEEE: constant_param_expression
	//			// constant_param_expression: '$' is in expr
	//			// note exptOrDataType being a data_type is only for yPARAMETER yTYPE
		id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' exprOrDataType
	/**/		{ $$ = VARDONEA($<fl>1,*$1, $2, $3); $$->valuep($5); }
	|	id/*new-parameter*/ variable_dimensionListE sigAttrListE
	/**/		{ $$ = VARDONEA($<fl>1,*$1, $2, $3);
		          if ($<fl>1->language() < V3LangCode::L1800_2009) {
			     $<fl>1->v3error("Parameter requires default value, or use IEEE 1800-2009 or later."); } }
	;

list_of_param_assignments<varp>:	// ==IEEE: list_of_param_assignments
		param_assignment			{ $$ = $1; }
	|	list_of_param_assignments ',' param_assignment	{ $$ = $1; $1->addNext($3); }
	;

list_of_defparam_assignments<nodep>:	//== IEEE: list_of_defparam_assignments
		defparam_assignment			{ $$ = $1; }
	|	list_of_defparam_assignments ',' defparam_assignment	{ $$ = $1->addNext($3); }
	;

defparam_assignment<nodep>:	// ==IEEE: defparam_assignment
		id '.' id '=' expr 			{ $$ = new AstDefParam($4,*$1,*$3,$5); }
	//UNSUP	More general dotted identifiers
	;

//************************************************
// Instances
// We don't know identifier types, so this matches all module,udp,etc instantiation
//   module_id      [#(params)]   name  (pins) [, name ...] ;	// module_instantiation
//   gate (strong0) [#(delay)]   [name] (pins) [, (pins)...] ;	// gate_instantiation
//   program_id     [#(params}]   name ;			// program_instantiation
//   interface_id   [#(params}]   name ;			// interface_instantiation
//   checker_id			  name  (pins) ;		// checker_instantiation

etcInst<nodep>:			// IEEE: module_instantiation + gate_instantiation + udp_instantiation
		instDecl				{ $$ = $1; }
	|	gateDecl 				{ $$ = $1; }
	;

instDecl<nodep>:
		id parameter_value_assignmentE {INSTPREP($<fl>1,*$1,$2);} instnameList ';'
			{ $$ = $4; GRAMMARP->m_impliedDecl=false;
			  if (GRAMMARP->m_instParamp) { GRAMMARP->m_instParamp->deleteTree(); GRAMMARP->m_instParamp = NULL; } }
	//			// IEEE: interface_identifier' .' modport_identifier list_of_interface_identifiers
	|	id/*interface*/ '.' id/*modport*/
			{ VARRESET_NONLIST(AstVarType::IFACEREF);
			  VARDTYPE(new AstIfaceRefDType($<fl>1, $<fl>3, "", *$1, *$3)); }
		mpInstnameList ';'
			{ $$ = VARDONEP($5,NULL,NULL); }
	//UNSUP: strengthSpecE for udp_instantiations
	;

mpInstnameList<nodep>:		// Similar to instnameList, but for modport instantiations which have no parenthesis
		mpInstnameParen				{ $$ = $1; }
	|	mpInstnameList ',' mpInstnameParen	{ $$ = $1->addNext($3); }
	;

mpInstnameParen<nodep>:		// Similar to instnameParen, but for modport instantiations which have no parenthesis
		id instRangeListE sigAttrListE		{ $$ = VARDONEA($<fl>1,*$1,$2,$3); }
	;

instnameList<nodep>:
		instnameParen				{ $$ = $1; }
	|	instnameList ',' instnameParen		{ $$ = $1->addNext($3); }
	;

instnameParen<cellp>:
	//			// Must clone m_instParamp as may be comma'ed list of instances
		id instRangeListE '(' cellpinList ')'	{ $$ = new AstCell($<fl>1, GRAMMARP->m_instModuleFl,
									   *$1, GRAMMARP->m_instModule, $4,
									   AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true),
                                                                           GRAMMARP->scrubRange($2));
						          $$->trace(GRAMMARP->allTracingOn($<fl>1)); }
	|	id instRangeListE 			{ $$ = new AstCell($<fl>1, GRAMMARP->m_instModuleFl,
									   *$1, GRAMMARP->m_instModule, NULL,
									   AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true),
                                                                           GRAMMARP->scrubRange($2));
						          $$->trace(GRAMMARP->allTracingOn($<fl>1)); }
	//UNSUP	instRangeListE '(' cellpinList ')'	{ UNSUP } // UDP
	//			// Adding above and switching to the Verilog-Perl syntax
	//			// causes a shift conflict due to use of idClassSel inside exprScope.
	//			// It also breaks allowing "id foo;" instantiation syntax.
	;

instRangeListE<rangep>:
		/* empty */				{ $$ = NULL; }
	|	instRangeList				{ $$ = $1; }
	;

instRangeList<rangep>:
		instRange				{ $$ = $1; }
	|	instRangeList instRange			{ $$ = VN_CAST($1->addNextNull($2), Range); }
	;

instRange<rangep>:
		'[' constExpr ']'			{ $$ = new AstRange($1, new AstConst($1, 0), new AstSub($1, $2, new AstConst($1, 1))); }
	|	'[' constExpr ':' constExpr ']'		{ $$ = new AstRange($1,$2,$4); }
	;

cellparamList<pinp>:
		{VARRESET_LIST(UNKNOWN);} cellparamItList	{ $$ = $2; VARRESET_NONLIST(UNKNOWN); }
	;

cellpinList<pinp>:
		{VARRESET_LIST(UNKNOWN);} cellpinItList	{ $$ = $2; VARRESET_NONLIST(UNKNOWN); }
	;

cellparamItList<pinp>:		// IEEE: list_of_parameter_assignmente
		cellparamItemE				{ $$ = $1; }
	|	cellparamItList ',' cellparamItemE	{ $$ = VN_CAST($1->addNextNull($3), Pin); }
	;

cellpinItList<pinp>:		// IEEE: list_of_port_connections
		cellpinItemE				{ $$ = $1; }
	|	cellpinItList ',' cellpinItemE		{ $$ = VN_CAST($1->addNextNull($3), Pin); }
	;

cellparamItemE<pinp>:		// IEEE: named_parameter_assignment + empty
				// Note empty can match either () or (,); V3LinkCells cleans up ()
		/* empty: ',,' is legal */		{ $$ = new AstPin(CRELINE(), PINNUMINC(), "", NULL); }
	|	yP_DOTSTAR				{ $$ = new AstPin($1,PINNUMINC(),".*",NULL); }
	|	'.' idSVKwd				{ $$ = new AstPin($<fl>2,PINNUMINC(), *$2,
									  new AstParseRef($<fl>2,VParseRefExp::PX_TEXT,*$2,NULL,NULL));
									  $$->svImplicit(true);}
	|	'.' idAny				{ $$ = new AstPin($<fl>2,PINNUMINC(), *$2,
									  new AstParseRef($<fl>2,VParseRefExp::PX_TEXT,*$2,NULL,NULL));
									  $$->svImplicit(true);}
	|	'.' idAny '(' ')'			{ $$ = new AstPin($<fl>2,PINNUMINC(),*$2,NULL); }
	//			// mintypmax is expanded here, as it might be a UDP or gate primitive
	|	'.' idAny '(' expr ')'			{ $$ = new AstPin($<fl>2,PINNUMINC(),*$2,$4); }
	//UNSUP	'.' idAny '(' expr ':' expr ')'		{ }
	//UNSUP	'.' idAny '(' expr ':' expr ':' expr ')' { }
	//			// For parameters
	|	'.' idAny '(' data_type ')'		{ $$ = new AstPin($<fl>2, PINNUMINC(), *$2, $4); }
	//			// For parameters
	|	data_type				{ $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); }
	//
	|	expr					{ $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); }
	//UNSUP	expr ':' expr				{ }
	//UNSUP	expr ':' expr ':' expr			{ }
	;

cellpinItemE<pinp>:		// IEEE: named_port_connection + empty
				// Note empty can match either () or (,); V3LinkCells cleans up ()
		/* empty: ',,' is legal */		{ $$ = new AstPin(CRELINE(), PINNUMINC(), "", NULL); }
	|	yP_DOTSTAR				{ $$ = new AstPin($1,PINNUMINC(),".*",NULL); }
	|	'.' idSVKwd				{ $$ = new AstPin($<fl>2,PINNUMINC(),*$2,new AstParseRef($<fl>2,VParseRefExp::PX_TEXT,*$2,NULL,NULL)); $$->svImplicit(true);}
	|	'.' idAny				{ $$ = new AstPin($<fl>2,PINNUMINC(),*$2,new AstParseRef($<fl>2,VParseRefExp::PX_TEXT,*$2,NULL,NULL)); $$->svImplicit(true);}
	|	'.' idAny '(' ')'			{ $$ = new AstPin($<fl>2,PINNUMINC(),*$2,NULL); }
	//			// mintypmax is expanded here, as it might be a UDP or gate primitive
	//UNSUP               pev_expr below
	|	'.' idAny '(' expr ')'			{ $$ = new AstPin($<fl>2,PINNUMINC(),*$2,$4); }
	//UNSUP	'.' idAny '(' pev_expr ':' expr ')'	{ }
	//UNSUP	'.' idAny '(' pev_expr ':' expr ':' expr ')' { }
	//
	|	expr					{ $$ = new AstPin(FILELINE_OR_CRE($1),PINNUMINC(),"",$1); }
	//UNSUP	expr ':' expr				{ }
	//UNSUP	expr ':' expr ':' expr			{ }
	;

//************************************************
// EventControl lists

attr_event_control<sentreep>:	// ==IEEE: event_control
		'@' '(' event_expression ')'		{ $$ = new AstSenTree($1,$3); }
	|	'@' '(' '*' ')'				{ $$ = NULL; }
	|	'@' '*'					{ $$ = NULL; }
	;

event_controlE<sentreep>:
		/* empty */				{ $$ = NULL; }
	|	event_control				{ $$ = $1; }
	;

event_control<sentreep>:	// ==IEEE: event_control
		'@' '(' event_expression ')'		{ $$ = new AstSenTree($1,$3); }
	|	'@' '(' '*' ')'				{ $$ = NULL; }
	|	'@' '*'					{ $$ = NULL; }
	//			// IEEE: hierarchical_event_identifier
	//			// UNSUP below should be idClassSel
	|	'@' senitemVar				{ $$ = new AstSenTree($1,$2); }	/* For events only */
	//			// IEEE: sequence_instance
	//			// sequence_instance without parens matches idClassSel above.
	//			// Ambiguity: "'@' sequence (-for-sequence" versus expr:delay_or_event_controlE "'@' id (-for-expr
	//			// For now we avoid this, as it's very unlikely someone would mix
	//			// 1995 delay with a sequence with parameters.
	//			// Alternatively split this out of event_control, and delay_or_event_controlE
	//			// and anywhere delay_or_event_controlE is called allow two expressions
	//|	'@' idClassSel '(' list_of_argumentsE ')'	{ }
	;

event_expression<senitemp>:	// IEEE: event_expression - split over several
	//UNSUP			// Below are all removed
		senitem					{ $$ = $1; }
	|	event_expression yOR senitem		{ $$ = VN_CAST($1->addNextNull($3), NodeSenItem); }
	|	event_expression ',' senitem		{ $$ = VN_CAST($1->addNextNull($3), NodeSenItem); }	/* Verilog 2001 */
	//UNSUP			// Above are all removed, replace with:
	//UNSUP	ev_expr					{ $$ = $1; }
	//UNSUP	event_expression ',' ev_expr %prec yOR	{ $$ = VN_CAST($1->addNextNull($3), NodeSenItem); }
	;

senitem<senitemp>:		// IEEE: part of event_expression, non-'OR' ',' terms
		senitemEdge				{ $$ = $1; }
	|	senitemVar				{ $$ = $1; }
	|	'(' senitem ')'				{ $$ = $2; }
	//UNSUP	expr					{ UNSUP }
	|	'{' event_expression '}'		{ $$ = $2; }
	|	senitem yP_ANDAND senitem		{ $$ = new AstSenItem($2, AstSenItem::Illegal()); }
	//UNSUP	expr yIFF expr				{ UNSUP }
	// Since expr is unsupported we allow and ignore constants (removed in V3Const)
	|	yaINTNUM				{ $$ = NULL; }
	|	yaFLOATNUM				{ $$ = NULL; }
	;

senitemVar<senitemp>:
		idClassSel				{ $$ = new AstSenItem($1->fileline(), VEdgeType::ET_ANYEDGE, $1); }
	;

senitemEdge<senitemp>:		// IEEE: part of event_expression
	//UNSUP			// Below are all removed
		yPOSEDGE idClassSel			{ $$ = new AstSenItem($1, VEdgeType::ET_POSEDGE, $2); }
	|	yNEGEDGE idClassSel			{ $$ = new AstSenItem($1, VEdgeType::ET_NEGEDGE, $2); }
	|	yEDGE idClassSel			{ $$ = new AstSenItem($1, VEdgeType::ET_BOTHEDGE, $2); }
	|	yPOSEDGE '(' idClassSel ')'		{ $$ = new AstSenItem($1, VEdgeType::ET_POSEDGE, $3); }
	|	yNEGEDGE '(' idClassSel ')'		{ $$ = new AstSenItem($1, VEdgeType::ET_NEGEDGE, $3); }
	|	yEDGE '(' idClassSel ')'		{ $$ = new AstSenItem($1, VEdgeType::ET_BOTHEDGE, $3); }
	//UNSUP			// Above are all removed, replace with:
	//UNSUP	yPOSEDGE expr				{ UNSUP }
	//UNSUP	yPOSEDGE expr yIFF expr			{ UNSUP }
	//UNSUP	yNEGEDGE expr				{ UNSUP }
	//UNSUP	yNEGEDGE expr yIFF expr			{ UNSUP }
	//UNSUP	yEDGE expr				{ UNSUP }
	//UNSUP	yEDGE expr yIFF expr			{ UNSUP }
	;

//************************************************
// Statements

stmtBlock<nodep>:		// IEEE: statement + seq_block + par_block
		stmt					{ $$ = $1; }
	;

seq_block<nodep>:		// ==IEEE: seq_block
	//			// IEEE doesn't allow declarations in unnamed blocks, but several simulators do.
	//			// So need AstBegin's even if unnamed to scope variables down
		seq_blockFront blockDeclStmtList yEND endLabelE	{ $$=$1; $1->addStmtsp($2); SYMP->popScope($1); GRAMMARP->endLabel($<fl>4,$1,$4); }
	|	seq_blockFront /**/		 yEND endLabelE	{ $$=$1; SYMP->popScope($1); GRAMMARP->endLabel($<fl>3,$1,$3); }
	;

par_block<nodep>:		// ==IEEE: par_block
		par_blockFront blockDeclStmtList yJOIN endLabelE
			{ $$ = $1; $1->addStmtsp($2);
			  SYMP->popScope($1); GRAMMARP->endLabel($<fl>4, $1, $4); }
	|	par_blockFront /**/		 yJOIN endLabelE
			{ $$ = $1;
			  SYMP->popScope($1); GRAMMARP->endLabel($<fl>3, $1, $3); }
	|	par_blockFront blockDeclStmtList yJOIN_ANY endLabelE
			{ $$ = $1; $1->addStmtsp($2);
			  SYMP->popScope($1); GRAMMARP->endLabel($<fl>4, $1, $4); }
	|	par_blockFront /**/		 yJOIN_ANY endLabelE
			{ $$ = $1;
			  SYMP->popScope($1); GRAMMARP->endLabel($<fl>3, $1, $3); }
	|	par_blockFront blockDeclStmtList yJOIN_NONE endLabelE
			{ $$ = $1; $1->addStmtsp($2);
			  SYMP->popScope($1); GRAMMARP->endLabel($<fl>4, $1, $4); }
	|	par_blockFront /**/		 yJOIN_NONE endLabelE
			{ $$ = $1;
			  SYMP->popScope($1); GRAMMARP->endLabel($<fl>3, $1, $3); }
	;

seq_blockFront<beginp>:		// IEEE: part of seq_block
		yBEGIN					 { $$ = new AstBegin($1,"",NULL);  SYMP->pushNew($$); }
	|	yBEGIN ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($<fl>3, *$3, NULL); SYMP->pushNew($$); }
	;

par_blockFront<beginp>:		// IEEE: part of par_block
		yFORK					{ $$ = new AstBegin($1, "", NULL);  SYMP->pushNew($$);
							  BBUNSUP($1, "Unsupported: fork statements");
							  // When support, record or BBUNSUP yJOIN_ANY/yJOIN_NONE
							  }
	|	yFORK ':' idAny/*new-block_identifier*/	{ $$ = new AstBegin($<fl>3, *$3, NULL); SYMP->pushNew($$);
							  BBUNSUP($1, "Unsupported: fork statements"); }
	;

blockDeclStmtList<nodep>:	// IEEE: { block_item_declaration } { statement or null }
	//			// The spec seems to suggest a empty declaration isn't ok, but most simulators take it
		block_item_declarationList		{ $$ = $1; }
	|	block_item_declarationList stmtList	{ $$ = $1->addNextNull($2); }
	|	stmtList				{ $$ = $1; }
	;

block_item_declarationList<nodep>:	// IEEE: [ block_item_declaration ]
		block_item_declaration			{ $$ = $1; }
	|	block_item_declarationList block_item_declaration	{ $$ = $1->addNextNull($2); }
	;

block_item_declaration<nodep>:	// ==IEEE: block_item_declaration
		data_declaration 			{ $$ = $1; }
	|	local_parameter_declaration ';'		{ $$ = $1; }
	|	parameter_declaration ';' 		{ $$ = $1; }
	//UNSUP	let_declaration 			{ $$ = $1; }
	;

stmtList<nodep>:
		stmtBlock				{ $$ = $1; }
	|	stmtList stmtBlock			{ $$ = ($2==NULL)?($1):($1->addNext($2)); }
	;

stmt<nodep>:			// IEEE: statement_or_null == function_statement_or_null
		statement_item				{ $$ = $1; }
	//			// S05 block creation rule
	|	id/*block_identifier*/ ':' statement_item	{ $$ = new AstBegin($<fl>1, *$1, $3); }
	//			// from _or_null
	|	';'					{ $$ = NULL; }
	;

statement_item<nodep>:		// IEEE: statement_item
	//			// IEEE: operator_assignment
		foperator_assignment ';'		{ $$ = $1; }
	//
	//		 	// IEEE: blocking_assignment
	//			// 1800-2009 restricts LHS of assignment to new to not have a range
	//			// This is ignored to avoid conflicts
	|	fexprLvalue '=' class_new ';'		{ $$ = new AstAssign($2, $1, $3); }
	|	fexprLvalue '=' dynamic_array_new ';'	{ $$ = new AstAssign($2, $1, $3); }
	//
	//			// IEEE: nonblocking_assignment
	|	fexprLvalue yP_LTE delayE expr ';'	{ $$ = new AstAssignDly($2,$1,$4); }
	//UNSUP	fexprLvalue yP_LTE delay_or_event_controlE expr ';'	{ UNSUP }
	//
	//			// IEEE: procedural_continuous_assignment
	|	yASSIGN idClassSel '=' delayE expr ';'	{ $$ = new AstAssign($1,$2,$5); }
	//UNSUP:			delay_or_event_controlE above
	|	yDEASSIGN variable_lvalue ';'		{ $$ = NULL; BBUNSUP($1, "Unsupported: Verilog 1995 deassign"); }
	|	yFORCE expr '=' expr ';'		{ $$ = NULL; BBUNSUP($1, "Unsupported: Verilog 1995 force"); }
	|	yRELEASE variable_lvalue ';'		{ $$ = NULL; BBUNSUP($1, "Unsupported: Verilog 1995 release"); }
	//
	//			// IEEE: case_statement
	|	unique_priorityE caseStart caseAttrE case_itemListE yENDCASE	{ $$ = $2; if ($4) $2->addItemsp($4);
							  if ($1 == uniq_UNIQUE) $2->uniquePragma(true);
							  if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true);
							  if ($1 == uniq_PRIORITY) $2->priorityPragma(true); }
	//UNSUP	caseStart caseAttrE yMATCHES case_patternListE yENDCASE	{ }
	|	unique_priorityE caseStart caseAttrE yINSIDE case_insideListE yENDCASE	{ $$ = $2; if ($5) $2->addItemsp($5);
							  if (!$2->caseSimple()) $2->v3error("Illegal to have inside on a casex/casez");
							  $2->caseInsideSet();
							  if ($1 == uniq_UNIQUE) $2->uniquePragma(true);
							  if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true);
							  if ($1 == uniq_PRIORITY) $2->priorityPragma(true); }
	//
	//			// IEEE: conditional_statement
	|	unique_priorityE yIF '(' expr ')' stmtBlock	%prec prLOWER_THAN_ELSE
							{ AstIf* newp = new AstIf($2,$4,$6,NULL);
							  $$ = newp;
							  if ($1 == uniq_UNIQUE) newp->uniquePragma(true);
							  if ($1 == uniq_UNIQUE0) newp->unique0Pragma(true);
							  if ($1 == uniq_PRIORITY) newp->priorityPragma(true); }
	|	unique_priorityE yIF '(' expr ')' stmtBlock yELSE stmtBlock
							{ AstIf* newp = new AstIf($2,$4,$6,$8);
							  $$ = newp;
							  if ($1 == uniq_UNIQUE) newp->uniquePragma(true);
							  if ($1 == uniq_UNIQUE0) newp->unique0Pragma(true);
							  if ($1 == uniq_PRIORITY) newp->priorityPragma(true); }
	//
	|	finc_or_dec_expression ';'		{ $$ = $1; }
	//			// IEEE: inc_or_dec_expression
	//			// Below under expr
	//
	//			// IEEE: subroutine_call_statement
	//			// IEEE says we then expect a function call
	//			// (function_subroutine_callNoMethod), but rest of
	//			// the code expects an AstTask when used as a statement,
	//			// so parse as if task
	//			// Alternative would be shim with new AstVoidStmt.
	|	yVOID yP_TICK '(' task_subroutine_callNoMethod ')' ';'
							{ $$ = $4;
							  FileLine* newfl = new FileLine($$->fileline());
							  newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true);
							  $$->fileline(newfl); }
	|	yVOID yP_TICK '(' expr '.' task_subroutine_callNoMethod ')' ';'
							{ $$ = new AstDot($5, $4, $6);
							  FileLine* newfl = new FileLine($6->fileline());
							  newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true);
							  $6->fileline(newfl); }
	//			// Expr included here to resolve our not knowing what is a method call
	//			// Expr here must result in a subroutine_call
	|	task_subroutine_callNoMethod ';'	{ $$ = $1; }
	//UNSUP	fexpr '.' array_methodNoRoot ';'	{ UNSUP }
	|	fexpr '.' task_subroutine_callNoMethod ';'	{ $$ = new AstDot($<fl>2,$1,$3); }
	//UNSUP	fexprScope ';'				{ UNSUP }
	//			// Not here in IEEE; from class_constructor_declaration
	//			// Because we've joined class_constructor_declaration into generic functions
	//			// Way over-permissive;
	//			// IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ]
	|	fexpr '.' class_new ';'			{ $$ = NULL; BBUNSUP($1, "Unsupported: dotted new"); }
	//
	|	statementVerilatorPragmas		{ $$ = $1; }
	//
	//			// IEEE: disable_statement
	|	yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';'	{ $$ = new AstDisable($1,*$2); }
	|	yDISABLE yFORK ';'			{ $$ = NULL; BBUNSUP($1, "Unsupported: disable fork statements"); }
	//			// IEEE: event_trigger
	//UNSUP	yP_MINUSGT hierarchical_identifier/*event*/ ';'	{ UNSUP }
	//UNSUP	yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';'	{ UNSUP }
	//			// IEEE: loop_statement
	|	yFOREVER stmtBlock			{ $$ = new AstWhile($1,new AstConst($1,AstConst::LogicTrue()),$2); }
	|	yREPEAT '(' expr ')' stmtBlock		{ $$ = new AstRepeat($1,$3,$5);}
	|	yWHILE '(' expr ')' stmtBlock		{ $$ = new AstWhile($1,$3,$5);}
	//			// for's first ';' is in for_initialization
	|	statementFor				{ $$ = $1; }
	|	yDO stmtBlock yWHILE '(' expr ')' ';'	{ if ($2) {
							     $$ = $2->cloneTree(true);
							     $$->addNext(new AstWhile($1,$5,$2));
							  }
							  else $$ = new AstWhile($1,$5,NULL); }
	//			// IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009
	|	yFOREACH '(' idClassForeach '[' loop_variables ']' ')' stmtBlock	{ $$ = new AstForeach($1,$3,$5,$8); }
	//
	//			// IEEE: jump_statement
	|	yRETURN ';'				{ $$ = new AstReturn($1); }
	|	yRETURN expr ';'			{ $$ = new AstReturn($1,$2); }
	|	yBREAK ';'				{ $$ = new AstBreak($1); }
	|	yCONTINUE ';'				{ $$ = new AstContinue($1); }
	//
	|	par_block				{ $$ = $1; }
	//			// IEEE: procedural_timing_control_statement + procedural_timing_control
	|	delay_control stmtBlock			{ $$ = $2; $1->v3warn(STMTDLY,"Unsupported: Ignoring delay on this delayed statement."); }
	//UNSUP	event_control stmtBlock			{ UNSUP }
	//UNSUP	cycle_delay stmtBlock			{ UNSUP }
	//
	|	seq_block				{ $$ = $1; }
	//
	//			// IEEE: wait_statement
	|	yWAIT '(' expr ')' stmtBlock		{ $$ = NULL; BBUNSUP($1, "Unsupported: wait statements"); }
	|	yWAIT yFORK ';'				{ $$ = NULL; BBUNSUP($1, "Unsupported: wait fork statements"); }
	//UNSUP	yWAIT_ORDER '(' hierarchical_identifierList ')' action_block	{ UNSUP }
	//
	//			// IEEE: procedural_assertion_statement
	|	procedural_assertion_statement		{ $$ = $1; }
	//
	//			// IEEE: clocking_drive ';'
	//			// Pattern w/o cycle_delay handled by nonblocking_assign above
	//			// clockvar_expression made to fexprLvalue to prevent reduce conflict
	//			// Note LTE in this context is highest precedence, so first on left wins
	//UNSUP	cycle_delay fexprLvalue yP_LTE ';'	{ UNSUP }
	//UNSUP	fexprLvalue yP_LTE cycle_delay expr ';'	{ UNSUP }
	//
	//UNSUP	randsequence_statement			{ $$ = $1; }
	//
	//			// IEEE: randcase_statement
	|	yRANDCASE case_itemList yENDCASE	{ $$ = NULL; BBUNSUP($1, "Unsupported: SystemVerilog 2005 randcase statements"); }
	//
	//UNSUP	expect_property_statement		{ $$ = $1; }
	//
	|	error ';'				{ $$ = NULL; }
	;

statementFor<beginp>:		// IEEE: part of statement
		yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock
							{ $$ = new AstBegin($1,"",$3);
							  $$->addStmtsp(new AstWhile($1, $4,$8,$6)); }
	|	yFOR '(' for_initialization ';' for_stepE ')' stmtBlock
							{ $$ = new AstBegin($1,"",$3);
							  $$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::LogicTrue()),$7,$5)); }
	;

statementVerilatorPragmas<nodep>:
		yVL_COVERAGE_BLOCK_OFF			{ $$ = new AstPragma($1,AstPragmaType::COVERAGE_BLOCK_OFF); }
	;

//UNSUPoperator_assignment<nodep>:  // IEEE: operator_assignment
//UNSUP		~f~exprLvalue '=' delay_or_event_controlE expr { }
//UNSUP	|	~f~exprLvalue yP_PLUSEQ    expr		{ }
//UNSUP	|	~f~exprLvalue yP_MINUSEQ   expr		{ }
//UNSUP	|	~f~exprLvalue yP_TIMESEQ   expr		{ }
//UNSUP	|	~f~exprLvalue yP_DIVEQ     expr		{ }
//UNSUP	|	~f~exprLvalue yP_MODEQ     expr		{ }
//UNSUP	|	~f~exprLvalue yP_ANDEQ     expr		{ }
//UNSUP	|	~f~exprLvalue yP_OREQ      expr		{ }
//UNSUP	|	~f~exprLvalue yP_XOREQ     expr		{ }
//UNSUP	|	~f~exprLvalue yP_SLEFTEQ   expr		{ }
//UNSUP	|	~f~exprLvalue yP_SRIGHTEQ  expr		{ }
//UNSUP	|	~f~exprLvalue yP_SSRIGHTEQ expr		{ }
//UNSUP	;

foperator_assignment<nodep>:	// IEEE: operator_assignment (for first part of expression)
		fexprLvalue '=' delayE expr	{ $$ = new AstAssign($2,$1,$4); }
	|	fexprLvalue '=' yD_FOPEN '(' expr ')'		{ $$ = NULL; BBUNSUP($3, "Unsupported: $fopen with multichannel descriptor.  Add ,\"w\" as second argument to open a file descriptor."); }
	|	fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')'	{ $$ = new AstFOpen($3,$1,$5,$7); }
	//
	//UNSUP	~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP }
	//UNSUP	~f~exprLvalue yP_PLUS(etc) expr		{ UNSUP }
	|	fexprLvalue yP_PLUSEQ    expr		{ $$ = new AstAssign($2,$1,new AstAdd    ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_MINUSEQ   expr		{ $$ = new AstAssign($2,$1,new AstSub    ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_TIMESEQ   expr		{ $$ = new AstAssign($2,$1,new AstMul    ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_DIVEQ     expr		{ $$ = new AstAssign($2,$1,new AstDiv    ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_MODEQ     expr		{ $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_ANDEQ     expr		{ $$ = new AstAssign($2,$1,new AstAnd    ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_OREQ      expr		{ $$ = new AstAssign($2,$1,new AstOr     ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_XOREQ     expr		{ $$ = new AstAssign($2,$1,new AstXor    ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_SLEFTEQ   expr		{ $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_SRIGHTEQ  expr		{ $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
	|	fexprLvalue yP_SSRIGHTEQ expr		{ $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
	//UNSUP replace above with:
	//UNSUP	BISONPRE_COPY(operator_assignment,{s/~f~/f/g})	// {copied}
	;

//UNSUPinc_or_dec_expression<nodep>:  // ==IEEE: inc_or_dec_expression
//UNSUP	//			// Need fexprScope instead of variable_lvalue to prevent conflict
//UNSUP		~l~exprScope yP_PLUSPLUS		{ $<fl>$=$<fl>1; $$ = $1+$2; }
//UNSUP	|	~l~exprScope yP_MINUSMINUS		{ $<fl>$=$<fl>1; $$ = $1+$2; }
//UNSUP	//			// Need expr instead of variable_lvalue to prevent conflict
//UNSUP	|	yP_PLUSPLUS	expr			{ $<fl>$=$<fl>1; $$ = $1+$2; }
//UNSUP	|	yP_MINUSMINUS	expr			{ $<fl>$=$<fl>1; $$ = $1+$2; }
//UNSUP	;

finc_or_dec_expression<nodep>:	// ==IEEE: inc_or_dec_expression
	//UNSUP: Generic scopes in incrementes, remove below
		fexprLvalue yP_PLUSPLUS			{ $$ = new AstAssign($2,$1,new AstAdd    ($2,$1->cloneTree(true),new AstConst($2, AstConst::StringToParse(), "'b1"))); }
	|	fexprLvalue yP_MINUSMINUS		{ $$ = new AstAssign($2,$1,new AstSub    ($2,$1->cloneTree(true),new AstConst($2, AstConst::StringToParse(), "'b1"))); }
	|	yP_PLUSPLUS   fexprLvalue		{ $$ = new AstAssign($1,$2,new AstAdd    ($1,$2->cloneTree(true),new AstConst($1, AstConst::StringToParse(), "'b1"))); }
	|	yP_MINUSMINUS fexprLvalue		{ $$ = new AstAssign($1,$2,new AstSub    ($1,$2->cloneTree(true),new AstConst($1, AstConst::StringToParse(), "'b1"))); }
	//UNSUP: Generic scopes in incrementes, remove above
	//UNSUP	BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g})	// {copied}
	;

//UNSUPsinc_or_dec_expression<nodep>:  // IEEE: inc_or_dec_expression (for sequence_expression)
//UNSUP		BISONPRE_COPY(inc_or_dec_expression,{s/~l~/s/g})	// {copied}
//UNSUP	;

//UNSUPpinc_or_dec_expression<nodep>:  // IEEE: inc_or_dec_expression (for property_expression)
//UNSUP		BISONPRE_COPY(inc_or_dec_expression,{s/~l~/p/g})	// {copied}
//UNSUP	;

//UNSUPev_inc_or_dec_expression<nodep>:  // IEEE: inc_or_dec_expression (for ev_expr)
//UNSUP		BISONPRE_COPY(inc_or_dec_expression,{s/~l~/ev_/g})	// {copied}
//UNSUP	;

//UNSUPpev_inc_or_dec_expression<nodep>:  // IEEE: inc_or_dec_expression (for pev_expr)
//UNSUP		BISONPRE_COPY(inc_or_dec_expression,{s/~l~/pev_/g})	// {copied}
//UNSUP	;

class_new<nodep>:		// ==IEEE: class_new
	//			// Special precence so (...) doesn't match expr
		yNEW__ETC				{ $$ = new AstNew($1); }
	|	yNEW__ETC expr				{ $$ = new AstNew($1); BBUNSUP($1, "Unsupported: new with expression"); }
	//			// Grammer abiguity; we assume "new (x)" the () are a argument, not expr
	|	yNEW__PAREN '(' list_of_argumentsE ')'	{ $$ = new AstNew($1); BBUNSUP($1, "Unsupported: new with arguments"); }
	;

dynamic_array_new<nodep>:	// ==IEEE: dynamic_array_new
		yNEW__ETC '[' expr ']'			{ $$ = new AstNew($1); BBUNSUP($1, "Unsupported: Dynamic array new"); }
	|	yNEW__ETC '[' expr ']' '(' expr ')'	{ $$ = new AstNew($1); BBUNSUP($1, "Unsupported: Dynamic array new"); }
	;

//************************************************
// Case/If

unique_priorityE<uniqstate>:	// IEEE: unique_priority + empty
		/*empty*/				{ $$ = uniq_NONE; }
	|	yPRIORITY				{ $$ = uniq_PRIORITY; }
	|	yUNIQUE					{ $$ = uniq_UNIQUE; }
	|	yUNIQUE0				{ $$ = uniq_UNIQUE0; }
	;

caseStart<casep>:		// IEEE: part of case_statement
	 	yCASE  '(' expr ')' 			{ $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASE,$3,NULL); }
	|	yCASEX '(' expr ')' 			{ $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASEX,$3,NULL); }
	|	yCASEZ '(' expr ')'			{ $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASEZ,$3,NULL); }
	;

caseAttrE:
	 	/*empty*/				{ }
	|	caseAttrE yVL_FULL_CASE			{ GRAMMARP->m_caseAttrp->fullPragma(true); }
	|	caseAttrE yVL_PARALLEL_CASE		{ GRAMMARP->m_caseAttrp->parallelPragma(true); }
	;

//UNSUPcase_patternListE<nodep>:  // IEEE: case_pattern_item
//UNSUP	//	&&& is part of expr so aliases to case_itemList
//UNSUP		case_itemListE				{ $$ = $1; }
//UNSUP	;

case_itemListE<caseitemp>:	// IEEE: [ { case_item } ]
		/* empty */				{ $$ = NULL; }
	|	case_itemList				{ $$ = $1; }
	;

case_insideListE<caseitemp>:	// IEEE: [ { case_inside_item } ]
		/* empty */				{ $$ = NULL; }
	|	case_inside_itemList			{ $$ = $1; }
	;

case_itemList<caseitemp>:	// IEEE: { case_item + ... }
		caseCondList ':' stmtBlock		{ $$ = new AstCaseItem($2,$1,$3); }
	|	yDEFAULT ':' stmtBlock			{ $$ = new AstCaseItem($1,NULL,$3); }
	|	yDEFAULT stmtBlock			{ $$ = new AstCaseItem($1,NULL,$2); }
	|	case_itemList caseCondList ':' stmtBlock	{ $$ = $1;$1->addNext(new AstCaseItem($3,$2,$4)); }
	|       case_itemList yDEFAULT stmtBlock		{ $$ = $1;$1->addNext(new AstCaseItem($2,NULL,$3)); }
	|	case_itemList yDEFAULT ':' stmtBlock		{ $$ = $1;$1->addNext(new AstCaseItem($2,NULL,$4)); }
	;

case_inside_itemList<caseitemp>:	// IEEE: { case_inside_item + open_range_list ... }
		open_range_list ':' stmtBlock		{ $$ = new AstCaseItem($2,$1,$3); }
	|	yDEFAULT ':' stmtBlock			{ $$ = new AstCaseItem($1,NULL,$3); }
	|	yDEFAULT stmtBlock			{ $$ = new AstCaseItem($1,NULL,$2); }
	|	case_inside_itemList open_range_list ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,$2,$4)); }
	|       case_inside_itemList yDEFAULT stmtBlock		{ $$ = $1;$1->addNext(new AstCaseItem($2,NULL,$3)); }
	|	case_inside_itemList yDEFAULT ':' stmtBlock	{ $$ = $1;$1->addNext(new AstCaseItem($2,NULL,$4)); }
	;

open_range_list<nodep>:		// ==IEEE: open_range_list + open_value_range
		open_value_range			{ $$ = $1; }
	|	open_range_list ',' open_value_range	{ $$ = $1;$1->addNext($3); }
	;

open_value_range<nodep>:	// ==IEEE: open_value_range
		value_range				{ $$ = $1; }
	;

value_range<nodep>:		// ==IEEE: value_range
		expr					{ $$ = $1; }
	|	'[' expr ':' expr ']'			{ $$ = new AstInsideRange($1, $2, $4); }
	;

//UNSUPcovergroup_value_range<nodep>:  // ==IEEE-2012: covergroup_value_range
//UNSUP		cgexpr					{ $$ = $1; }
//UNSUP	|	'[' cgexpr ':' cgexpr ']'		{ }
//UNSUP	;

caseCondList<nodep>:		// IEEE: part of case_item
		expr 					{ $$ = $1; }
	|	caseCondList ',' expr			{ $$ = $1;$1->addNext($3); }
	;

patternNoExpr<nodep>:		// IEEE: pattern **Excluding Expr*
		'.' id/*variable*/			{ $$ = NULL; $1->v3error("Unsupported: '{} tagged patterns"); }
	|	yP_DOTSTAR				{ $$ = NULL; $1->v3error("Unsupported: '{} tagged patterns"); }
	//			// IEEE: "expr" excluded; expand in callers
	//			// "yTAGGED id [expr]" Already part of expr
	//UNSUP	yTAGGED id/*member_identifier*/ patternNoExpr		{ $$ = NULL; $1->v3error("Unsupported: '{} tagged patterns"); }
	//			// "yP_TICKBRA patternList '}'" part of expr under assignment_pattern
	;

patternList<nodep>:		// IEEE: part of pattern
		patternOne				{ $$ = $1; }
	|	patternList ',' patternOne		{ $$ = $1->addNextNull($3); }
	;

patternOne<nodep>:		// IEEE: part of pattern
		expr					{ if ($1) { $$ = new AstPatMember($1->fileline(),$1,NULL,NULL); } else { $$=NULL; } }
	|	expr '{' argsExprList '}'		{ $$ = new AstPatMember($2,$3,NULL,$1); }
	|	patternNoExpr				{ $$ = $1; }
	;

patternMemberList<nodep>:	// IEEE: part of pattern and assignment_pattern
		patternMemberOne			{ $$ = $1; }
	|	patternMemberList ',' patternMemberOne	{ $$ = $1->addNextNull($3); }
	;

patternMemberOne<patmemberp>:	// IEEE: part of pattern and assignment_pattern
		patternKey ':' expr			{ $$ = new AstPatMember($1->fileline(),$3,$1,NULL); }
	|	patternKey ':' patternNoExpr		{ $$ = NULL; $2->v3error("Unsupported: '{} .* patterns"); }
	//			// From assignment_pattern_key
	|	yDEFAULT ':' expr			{ $$ = new AstPatMember($1,$3,NULL,NULL); $$->isDefault(true); }
	|	yDEFAULT ':' patternNoExpr		{ $$ = NULL; $2->v3error("Unsupported: '{} .* patterns"); }
	;

patternKey<nodep>:		// IEEE: merge structure_pattern_key, array_pattern_key, assignment_pattern_key
	//			// IEEE: structure_pattern_key
	//			// id/*member*/ is part of constExpr below
	//UNSUP	constExpr				{ $$ = $1; }
	//			// IEEE: assignment_pattern_key
	//UNSUP	simple_type				{ $1->v3error("Unsupported: '{} with data type as key"); $$=$1; }
	//			// simple_type reference looks like constExpr
	//			// Verilator:
	//			//   The above expressions cause problems because "foo" may be a constant identifier
	//			//   (if array) or a reference to the "foo"member (if structure)
	//			//   So for now we only allow a true constant number, or a identifier which we treat as a structure member name
		yaINTNUM				{ $$ = new AstConst($<fl>1,*$1); }
	|	yaFLOATNUM				{ $$ = new AstConst($<fl>1,AstConst::RealDouble(),$1); }
	|	yaID__ETC				{ $$ = new AstText($<fl>1,*$1); }
	|	strAsInt				{ $$ = $1; }
	;

assignment_pattern<patternp>:	// ==IEEE: assignment_pattern
	// This doesn't match the text of the spec.  I think a : is missing, or example code needed
	// yP_TICKBRA constExpr exprList '}'	{ $$="'{"+$2+" "+$3"}"; }
	//			// "'{ const_expression }" is same as patternList with one entry
	//			// From patternNoExpr
	//			// also IEEE: "''{' expression { ',' expression } '}'"
	//			//      matches since patternList includes expr
		yP_TICKBRA patternList '}'		{ $$ = new AstPattern($1,$2); }
	//			// From patternNoExpr
	//			// also IEEE "''{' structure_pattern_key ':' ...
	//			// also IEEE "''{' array_pattern_key ':' ...
	|	yP_TICKBRA patternMemberList '}'	{ $$ = new AstPattern($1,$2); }
	//			// IEEE: Not in grammar, but in VMM
	|	yP_TICKBRA '}'				{ $$ = new AstPattern($1, NULL); $1->v3error("Unsupported: Empty '{}"); }
	;

// "datatype id = x {, id = x }"  |  "yaId = x {, id=x}" is legal
for_initialization<nodep>:	// ==IEEE: for_initialization + for_variable_declaration + extra terminating ";"
	//			// IEEE: for_variable_declaration
		for_initializationItemList ';'		{ $$ = $1; }
	//			// IEEE: 1800-2017 empty initialization
	|	';'					{ $$ = NULL; }
	;

for_initializationItemList<nodep>:	// IEEE: [for_variable_declaration...]
		for_initializationItem			{ $$ = $1; }
	|	for_initializationItemList ',' for_initializationItem	{ $$ = $1; $<fl>2->v3error("Unsupported: for loop initialization after the first comma"); }
	;

for_initializationItem<nodep>:		// IEEE: variable_assignment + for_variable_declaration
	//			// IEEE: for_variable_declaration
		data_type idAny/*new*/ '=' expr
			{ VARRESET_NONLIST(VAR); VARDTYPE($1);
			  $$ = VARDONEA($<fl>2,*$2,NULL,NULL);
			  $$->addNext(new AstAssign($3, new AstVarRef($<fl>2, *$2, true), $4));}
	//			// IEEE-2012:
	|	yVAR data_type idAny/*new*/ '=' expr
			{ VARRESET_NONLIST(VAR); VARDTYPE($2);
			  $$ = VARDONEA($<fl>3,*$3,NULL,NULL);
			  $$->addNext(new AstAssign($4, new AstVarRef($<fl>3, *$3, true), $5));}
	//			// IEEE: variable_assignment
	//			// UNSUP variable_lvalue below
	|	varRefBase '=' expr			{ $$ = new AstAssign($2, $1, $3); }
	;

for_stepE<nodep>:		// IEEE: for_step + empty
		/* empty */				{ $$ = NULL; }
	|	for_step				{ $$ = $1; }
	;

for_step<nodep>:		// IEEE: for_step
		for_step_assignment			{ $$ = $1; }
	|	for_step ',' for_step_assignment	{ $$ = $1; $<fl>1->v3error("Unsupported: for loop step after the first comma"); }
	;

for_step_assignment<nodep>:  // ==IEEE: for_step_assignment
	//UNSUP	operator_assignment			{ $$ = $1; }
	//
	//UNSUP	inc_or_dec_expression			{ $$ = $1; }
	//			// IEEE: subroutine_call
	//UNSUP	function_subroutine_callNoMethod	{ $$ = $1; }
	//			// method_call:array_method requires a '.'
	//UNSUP	expr '.' array_methodNoRoot		{ }
	//UNSUP	exprScope				{ $$ = $1; }
	//UNSUP remove below
		genvar_iteration			{ $$ = $1; }
	//UNSUP remove above
	;

loop_variables<nodep>:		// IEEE: loop_variables
		varRefBase				{ $$ = $1; }
	|	loop_variables ',' varRefBase		{ $$ = $1;$1->addNext($3); }
	;

//************************************************
// Functions/tasks

taskRef<nodep>:			// IEEE: part of tf_call
		id		 		{ $$ = new AstTaskRef($<fl>1,*$1,NULL); }
	|	id '(' list_of_argumentsE ')'	{ $$ = new AstTaskRef($<fl>1,*$1,$3); }
	|	package_scopeIdFollows id '(' list_of_argumentsE ')'	{ $$ = AstDot::newIfPkg($<fl>2, $1, new AstTaskRef($<fl>2,*$2,$4)); }
	;

funcRef<nodep>:			// IEEE: part of tf_call
	//			// package_scope/hierarchical_... is part of expr, so just need ID
	//			//	making-a		id-is-a
	//			//	-----------------	------------------
	//			//      tf_call			tf_identifier		expr (list_of_arguments)
	//			//      method_call(post .)	function_identifier	expr (list_of_arguments)
	//			//	property_instance	property_identifier	property_actual_arg
	//			//	sequence_instance	sequence_identifier	sequence_actual_arg
	//			//      let_expression		let_identifier		let_actual_arg
	//
		id '(' list_of_argumentsE ')'		{ $$ = new AstFuncRef($<fl>1, *$1, $3); }
	|	package_scopeIdFollows id '(' list_of_argumentsE ')'	{ $$ = AstDot::newIfPkg($<fl>2, $1, new AstFuncRef($<fl>2,*$2,$4)); }
	//UNSUP list_of_argumentE should be pev_list_of_argumentE
	//UNSUP: idDotted is really just id to allow dotted method calls
	;

task_subroutine_callNoMethod<nodep>:	// function_subroutine_callNoMethod (as task)
	//			// IEEE: tf_call
		taskRef					{ $$ = $1; }
	//UNSUP	funcRef yWITH__PAREN '(' expr ')'	{ /*UNSUP*/ }
	|	system_t_call				{ $$ = $1; }
	//			// IEEE: method_call requires a "." so is in expr
	//			// IEEE: ['std::'] not needed, as normal std package resolution will find it
	//			// IEEE: randomize_call
	//			// We implement randomize as a normal funcRef, since randomize isn't a keyword
	//			// Note yNULL is already part of expressions, so they come for free
	//UNSUP	funcRef yWITH__CUR constraint_block	{ }
	;

function_subroutine_callNoMethod<nodep>:	// IEEE: function_subroutine_call (as function)
	//			// IEEE: tf_call
		funcRef					{ $$ = $1; }
	//UNSUP	funcRef yWITH__PAREN '(' expr ')'	{ /*UNSUP*/ }
	|	system_f_call				{ $$ = $1; }
	//			// IEEE: method_call requires a "." so is in expr
	//			// IEEE: ['std::'] not needed, as normal std package resolution will find it
	//			// IEEE: randomize_call
	//			// We implement randomize as a normal funcRef, since randomize isn't a keyword
	//			// Note yNULL is already part of expressions, so they come for free
	//UNSUP	funcRef yWITH__CUR constraint_block	{ }
	;

system_t_call<nodep>:		// IEEE: system_tf_call (as task)
	//
		yaD_IGNORE  parenE			{ $$ = new AstSysIgnore($<fl>1,NULL); }
	|	yaD_IGNORE  '(' exprList ')'		{ $$ = new AstSysIgnore($<fl>1,$3); }
	//
	|	yaD_DPI parenE				{ $$ = new AstTaskRef($<fl>1,*$1,NULL); }
	|	yaD_DPI '(' exprList ')'		{ $$ = new AstTaskRef($<fl>1, *$1, $3);
							  GRAMMARP->argWrapList(VN_CAST($$, TaskRef)); }
	//
	|	yD_C '(' cStrList ')'			{ $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); }
	|	yD_SYSTEM  '(' expr ')'			{ $$ = new AstSystemT($1, $3); }
	//
	|	yD_FCLOSE '(' idClassSel ')'		{ $$ = new AstFClose($1, $3); }
	|	yD_FFLUSH parenE			{ $$ = NULL; BBUNSUP($1, "Unsupported: $fflush of all handles does not map to C++."); }
	|	yD_FFLUSH '(' expr ')'			{ $$ = new AstFFlush($1, $3); }
	|	yD_FINISH parenE			{ $$ = new AstFinish($1); }
	|	yD_FINISH '(' expr ')'			{ $$ = new AstFinish($1); DEL($3); }
	|	yD_STOP parenE				{ $$ = new AstStop($1, false); }
	|	yD_STOP '(' expr ')'			{ $$ = new AstStop($1, false); DEL($3); }
	//
	|	yD_SFORMAT '(' expr ',' str commaEListE ')'	{ $$ = new AstSFormat($1,$3,*$5,$6); }
	|	yD_SWRITE  '(' expr ',' str commaEListE ')'	{ $$ = new AstSFormat($1,$3,*$5,$6); }
	//
	|	yD_DISPLAY  parenE			{ $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL); }
	|	yD_DISPLAY  '(' exprList ')'		{ $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3); }
	|	yD_WRITE    parenE			{ $$ = NULL; }  // NOP
	|	yD_WRITE    '(' exprList ')'		{ $$ = new AstDisplay($1,AstDisplayType::DT_WRITE,   NULL, $3); }
	|	yD_FDISPLAY '(' expr ')'		{ $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, NULL); }
	|	yD_FDISPLAY '(' expr ',' exprListE ')' 	{ $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5); }
	|	yD_FWRITE   '(' expr ',' exprListE ')'	{ $$ = new AstDisplay($1,AstDisplayType::DT_WRITE,   $3, $5); }
	|	yD_INFO	    parenE			{ $$ = new AstDisplay($1,AstDisplayType::DT_INFO,    NULL, NULL); }
	|	yD_INFO	    '(' exprList ')'		{ $$ = new AstDisplay($1,AstDisplayType::DT_INFO,    NULL, $3); }
	|	yD_WARNING  parenE			{ $$ = new AstDisplay($1,AstDisplayType::DT_WARNING, NULL, NULL); }
	|	yD_WARNING  '(' exprList ')'		{ $$ = new AstDisplay($1,AstDisplayType::DT_WARNING, NULL, $3); }
	|	yD_ERROR    parenE			{ $$ = GRAMMARP->createDisplayError($1); }
	|	yD_ERROR    '(' exprList ')'		{ $$ = new AstDisplay($1,AstDisplayType::DT_ERROR,   NULL, $3);   $$->addNext(new AstStop($1, true)); }
	|	yD_FATAL    parenE			{ $$ = new AstDisplay($1,AstDisplayType::DT_FATAL,   NULL, NULL); $$->addNext(new AstStop($1, false)); }
	|	yD_FATAL    '(' expr ')'		{ $$ = new AstDisplay($1,AstDisplayType::DT_FATAL,   NULL, NULL); $$->addNext(new AstStop($1, false)); DEL($3); }
	|	yD_FATAL    '(' expr ',' exprListE ')'	{ $$ = new AstDisplay($1,AstDisplayType::DT_FATAL,   NULL, $5);   $$->addNext(new AstStop($1, false)); DEL($3); }
	//
	|	yD_READMEMB '(' expr ',' idClassSel ')'				{ $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); }
	|	yD_READMEMB '(' expr ',' idClassSel ',' expr ')'		{ $$ = new AstReadMem($1,false,$3,$5,$7,NULL); }
	|	yD_READMEMB '(' expr ',' idClassSel ',' expr ',' expr ')'	{ $$ = new AstReadMem($1,false,$3,$5,$7,$9); }
	|	yD_READMEMH '(' expr ',' idClassSel ')'				{ $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); }
	|	yD_READMEMH '(' expr ',' idClassSel ',' expr ')'		{ $$ = new AstReadMem($1,true, $3,$5,$7,NULL); }
	|	yD_READMEMH '(' expr ',' idClassSel ',' expr ',' expr ')'	{ $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
	//
	|	yD_WRITEMEMH '(' expr ',' idClassSel ')'			{ $$ = new AstWriteMem($1,$3,$5,NULL,NULL); }
	|	yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ')'		{ $$ = new AstWriteMem($1,$3,$5,$7,NULL); }
	|	yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ',' expr ')'	{ $$ = new AstWriteMem($1,$3,$5,$7,$9); }
	//
	// Any system function as a task
	|	system_f_call_or_t			{ $$ = new AstSysFuncAsTask($<fl>1, $1); }
	;

system_f_call<nodep>:		// IEEE: system_tf_call (as func)
		yaD_IGNORE parenE			{ $$ = new AstConst($<fl>1, AstConst::StringToParse(), "'b0"); }  // Unsized 0
	|	yaD_IGNORE '(' exprList ')'		{ $$ = new AstConst($<fl>1, AstConst::StringToParse(), "'b0"); }  // Unsized 0
	//
	|	yaD_DPI parenE				{ $$ = new AstFuncRef($<fl>1,*$1,NULL); }
	|	yaD_DPI '(' exprList ')'		{ $$ = new AstFuncRef($<fl>1,*$1,$3); GRAMMARP->argWrapList(VN_CAST($$, FuncRef)); }
	//
	|	yD_C '(' cStrList ')'			{ $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); }
	|	yD_SYSTEM  '(' expr ')'			{ $$ = new AstSystemF($1,$3); }
	//
	|	system_f_call_or_t			{ $$ = $1; }
	;

system_f_call_or_t<nodep>:	// IEEE: part of system_tf_call (can be task or func)
		yD_ACOS '(' expr ')'			{ $$ = new AstAcosD($1,$3); }
	|	yD_ACOSH '(' expr ')'			{ $$ = new AstAcoshD($1,$3); }
	|	yD_ASIN '(' expr ')'			{ $$ = new AstAsinD($1,$3); }
	|	yD_ASINH '(' expr ')'			{ $$ = new AstAsinhD($1,$3); }
	|	yD_ATAN '(' expr ')'			{ $$ = new AstAtanD($1,$3); }
	|	yD_ATAN2 '(' expr ',' expr ')'  	{ $$ = new AstAtan2D($1,$3,$5); }
	|	yD_ATANH '(' expr ')'			{ $$ = new AstAtanhD($1,$3); }
	|	yD_BITS '(' exprOrDataType ')'		{ $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3); }
	|	yD_BITS '(' exprOrDataType ',' expr ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3,$5); }
	|	yD_BITSTOREAL '(' expr ')'		{ $$ = new AstBitsToRealD($1,$3); }
	|	yD_BITSTOSHORTREAL '(' expr ')'		{ $$ = new AstBitsToRealD($1,$3); UNSUPREAL($1); }
	|	yD_CEIL '(' expr ')'			{ $$ = new AstCeilD($1,$3); }
	|	yD_CLOG2 '(' expr ')'			{ $$ = new AstCLog2($1,$3); }
	|	yD_COS '(' expr ')'			{ $$ = new AstCosD($1,$3); }
	|	yD_COSH '(' expr ')'			{ $$ = new AstCoshD($1,$3); }
	|	yD_COUNTONES '(' expr ')'		{ $$ = new AstCountOnes($1,$3); }
	|	yD_DIMENSIONS '(' exprOrDataType ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_DIMENSIONS,$3); }
	|	yD_EXP '(' expr ')'			{ $$ = new AstExpD($1,$3); }
	|	yD_FEOF '(' expr ')'			{ $$ = new AstFEof($1,$3); }
	|	yD_FGETC '(' expr ')'			{ $$ = new AstFGetC($1,$3); }
	|	yD_FGETS '(' idClassSel ',' expr ')'	{ $$ = new AstFGetS($1,$3,$5); }
	|	yD_FREAD '(' idClassSel ',' expr ')'	{ $$ = new AstFRead($1,$3,$5,NULL,NULL); }
	|	yD_FREAD '(' idClassSel ',' expr ',' expr ')'	{ $$ = new AstFRead($1,$3,$5,$7,NULL); }
	|	yD_FREAD '(' idClassSel ',' expr ',' expr ',' expr ')'	{ $$ = new AstFRead($1,$3,$5,$7,$9); }
	|	yD_FREWIND '(' idClassSel ')'		{ $$ = new AstFRewind($1, $3); }
	|	yD_FLOOR '(' expr ')'			{ $$ = new AstFloorD($1,$3); }
	|	yD_FSCANF '(' expr ',' str commaVRDListE ')'	{ $$ = new AstFScanF($1,*$5,$3,$6); }
	|	yD_FSEEK '(' idClassSel ',' expr ',' expr ')'	{ $$ = new AstFSeek($1,$3,$5,$7); }
	|	yD_FTELL '(' idClassSel ')'		{ $$ = new AstFTell($1, $3); }
	|	yD_HIGH '(' exprOrDataType ')'		{ $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,NULL); }
	|	yD_HIGH '(' exprOrDataType ',' expr ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,$5); }
	|	yD_HYPOT '(' expr ',' expr ')'		{ $$ = new AstHypotD($1,$3,$5); }
	|	yD_INCREMENT '(' exprOrDataType ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_INCREMENT,$3,NULL); }
	|	yD_INCREMENT '(' exprOrDataType ',' expr ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_INCREMENT,$3,$5); }
	|	yD_ISUNKNOWN '(' expr ')'		{ $$ = new AstIsUnknown($1,$3); }
	|	yD_ITOR '(' expr ')'			{ $$ = new AstIToRD($1,$3); }
	|	yD_LEFT '(' exprOrDataType ')'		{ $$ = new AstAttrOf($1,AstAttrType::DIM_LEFT,$3,NULL); }
	|	yD_LEFT '(' exprOrDataType ',' expr ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_LEFT,$3,$5); }
	|	yD_LN '(' expr ')'			{ $$ = new AstLogD($1,$3); }
	|	yD_LOG10 '(' expr ')'			{ $$ = new AstLog10D($1,$3); }
	|	yD_LOW '(' exprOrDataType ')'		{ $$ = new AstAttrOf($1,AstAttrType::DIM_LOW,$3,NULL); }
	|	yD_LOW '(' exprOrDataType ',' expr ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_LOW,$3,$5); }
	|	yD_ONEHOT '(' expr ')'			{ $$ = new AstOneHot($1,$3); }
	|	yD_ONEHOT0 '(' expr ')'			{ $$ = new AstOneHot0($1,$3); }
	|	yD_PAST '(' expr ')'			{ $$ = new AstPast($1,$3, NULL); }
	|	yD_PAST '(' expr ',' expr ')'		{ $$ = new AstPast($1,$3, $5); }
	|	yD_PAST '(' expr ',' expr ',' expr ')'		{ $1->v3error("Unsupported: $past expr2 and clock arguments"); $$ = $3; }
	|	yD_PAST '(' expr ',' expr ',' expr ',' expr')'	{ $1->v3error("Unsupported: $past expr2 and clock arguments"); $$ = $3; }
	|	yD_POW '(' expr ',' expr ')'		{ $$ = new AstPowD($1,$3,$5); }
	|	yD_RANDOM '(' expr ')'			{ $$ = NULL; $1->v3error("Unsupported: Seeding $random doesn't map to C++, use $c(\"srand\")"); }
	|	yD_RANDOM parenE			{ $$ = new AstRand($1); }
	|	yD_REALTIME parenE			{ $$ = new AstTimeD($1); }
	|	yD_REALTOBITS '(' expr ')'		{ $$ = new AstRealToBits($1,$3); }
	|	yD_REWIND '(' idClassSel ')'		{ $$ = new AstFSeek($1, $3, new AstConst($1, 0), new AstConst($1, 0)); }
	|	yD_RIGHT '(' exprOrDataType ')'		{ $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,NULL); }
	|	yD_RIGHT '(' exprOrDataType ',' expr ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,$5); }
	|	yD_RTOI '(' expr ')'			{ $$ = new AstRToIS($1,$3); }
	|	yD_SFORMATF '(' str commaEListE ')'	{ $$ = new AstSFormatF($1,*$3,false,$4); }
	|	yD_SHORTREALTOBITS '(' expr ')'		{ $$ = new AstRealToBits($1,$3); UNSUPREAL($1); }
	|	yD_SIGNED '(' expr ')'			{ $$ = new AstSigned($1,$3); }
	|	yD_SIN '(' expr ')'			{ $$ = new AstSinD($1,$3); }
	|	yD_SINH '(' expr ')'			{ $$ = new AstSinhD($1,$3); }
	|	yD_SIZE '(' exprOrDataType ')'		{ $$ = new AstAttrOf($1,AstAttrType::DIM_SIZE,$3,NULL); }
	|	yD_SIZE '(' exprOrDataType ',' expr ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_SIZE,$3,$5); }
	|	yD_SQRT '(' expr ')'			{ $$ = new AstSqrtD($1,$3); }
	|	yD_SSCANF '(' expr ',' str commaVRDListE ')'	{ $$ = new AstSScanF($1,*$5,$3,$6); }
	|	yD_STIME parenE				{ $$ = new AstSel($1,new AstTime($1),0,32); }
	|	yD_TAN '(' expr ')'			{ $$ = new AstTanD($1,$3); }
	|	yD_TANH '(' expr ')'			{ $$ = new AstTanhD($1,$3); }
	|	yD_TESTPLUSARGS '(' str ')'		{ $$ = new AstTestPlusArgs($1,*$3); }
	|	yD_TIME	parenE				{ $$ = new AstTime($1); }
	|	yD_UNGETC '(' expr ',' expr ')'		{ $$ = new AstFUngetC($1, $5, $3); }  // Arg swap to file first
	|	yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')'	{ $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); }
	|	yD_UNSIGNED '(' expr ')'		{ $$ = new AstUnsigned($1,$3); }
	|	yD_VALUEPLUSARGS '(' expr ',' expr ')'	{ $$ = new AstValuePlusArgs($1,$3,$5); }
	;

elaboration_system_task<nodep>:	// IEEE: elaboration_system_task (1800-2009)
	//			// TODO: These currently just make initial statements, should instead give runtime error
		elaboration_system_task_guts ';'	{ $$ = new AstInitial($<fl>1, $1); }
	;

elaboration_system_task_guts<nodep>:	// IEEE: part of elaboration_system_task (1800-2009)
	//			// $fatal first argument is exit number, must be constant
		yD_INFO	   parenE			{ $$ = new AstElabDisplay($1, AstDisplayType::DT_INFO, NULL); }
	|	yD_INFO	   '(' exprList ')'		{ $$ = new AstElabDisplay($1, AstDisplayType::DT_INFO, $3); }
	|	yD_WARNING parenE			{ $$ = new AstElabDisplay($1, AstDisplayType::DT_WARNING, NULL); }
	|	yD_WARNING '(' exprList ')'		{ $$ = new AstElabDisplay($1, AstDisplayType::DT_WARNING, $3); }
	|	yD_ERROR   parenE			{ $$ = new AstElabDisplay($1, AstDisplayType::DT_ERROR, NULL); }
	|	yD_ERROR   '(' exprList ')'		{ $$ = new AstElabDisplay($1, AstDisplayType::DT_ERROR, $3); }
	|	yD_FATAL   parenE			{ $$ = new AstElabDisplay($1, AstDisplayType::DT_FATAL, NULL); }
	|	yD_FATAL   '(' expr ')'			{ $$ = new AstElabDisplay($1, AstDisplayType::DT_FATAL, NULL); DEL($3); }
	|	yD_FATAL   '(' expr ',' exprListE ')'	{ $$ = new AstElabDisplay($1, AstDisplayType::DT_FATAL, $5); DEL($3); }
	;

//UNSUPproperty_actual_arg<nodep>:  // ==IEEE: property_actual_arg
//UNSUP	//			// IEEE: property_expr
//UNSUP	//			// IEEE: sequence_actual_arg
//UNSUP		pev_expr				{ $$ = $1; }
//UNSUP	//			// IEEE: sequence_expr
//UNSUP	//			// property_expr already includes sequence_expr
//UNSUP	;

exprOrDataType<nodep>:		// expr | data_type: combined to prevent conflicts
		expr					{ $$ = $1; }
	//			// data_type includes id that overlaps expr, so special flavor
	|	data_type				{ $$ = $1; }
	//			// not in spec, but needed for $past(sig,1,,@(posedge clk))
	//UNSUP	event_control				{ }
	;

//UNSUPexprOrDataTypeOrMinTypMax<nodep>:  // exprOrDataType or mintypmax_expression
//UNSUP		expr					{ $$ = $1; }
//UNSUP	|	expr ':' expr ':' expr			{ $$ = $3; }
//UNSUP	//			// data_type includes id that overlaps expr, so special flavor
//UNSUP	|	data_type				{ $$ = $1; }
//UNSUP	//			// not in spec, but needed for $past(sig,1,,@(posedge clk))
//UNSUP	|	event_control				{ $$ = $1; }
//UNSUP	;

//UNSUPexprOrDataTypeList<nodep>:
//UNSUP		exprOrDataType				{ $$ = $1; }
//UNSUP	|	exprOrDataTypeList ',' exprOrDataType	{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

list_of_argumentsE<nodep>:	// IEEE: [list_of_arguments]
		argsDottedList				{ $$ = $1; }
	|	argsExprListE				{ if (VN_IS($1, Arg) && VN_CAST($1, Arg)->emptyConnectNoNext()) { $1->deleteTree(); $$ = NULL; }  // Mis-created when have 'func()'
	/*cont*/					  else $$ = $1; }
	|	argsExprListE ',' argsDottedList	{ $$ = $1->addNextNull($3); }
	;

task_declaration<ftaskp>:	// ==IEEE: task_declaration
		yTASK lifetimeE taskId tfGuts yENDTASK endLabelE
			{ $$ = $3; $$->addStmtsp($4); SYMP->popScope($$);
			  GRAMMARP->endLabel($<fl>6,$$,$6); }
	;

task_prototype<ftaskp>:		// ==IEEE: task_prototype
		yTASK taskId '(' tf_port_listE ')'	{ $$=$2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); }
	|	yTASK taskId				{ $$=$2; $$->prototype(true); SYMP->popScope($$); }
	;

function_declaration<ftaskp>:	// IEEE: function_declaration + function_body_declaration
	 	yFUNCTION lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE
			{ $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5);
			  SYMP->popScope($$);
			  GRAMMARP->endLabel($<fl>7,$$,$7); }
	| 	yFUNCTION lifetimeE funcIdNew funcIsolateE tfGuts yENDFUNCTION endLabelE
			{ $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5);
			  SYMP->popScope($$);
			  GRAMMARP->endLabel($<fl>7,$$,$7); }
	;

function_prototype<ftaskp>:	// IEEE: function_prototype
		yFUNCTION funcId '(' tf_port_listE ')'	{ $$=$2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); }
	|	yFUNCTION funcId			{ $$=$2; $$->prototype(true); SYMP->popScope($$); }
	;

class_constructor_prototype<ftaskp>:	// ==IEEE: class_constructor_prototype
		yFUNCTION funcIdNew '(' tf_port_listE ')' ';'	{ $$ = $2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); }
	|	yFUNCTION funcIdNew ';'				{ $$ = $2; $$->prototype(true); SYMP->popScope($$); }
	;

funcIsolateE<cint>:
		/* empty */		 		{ $$ = 0; }
	|	yVL_ISOLATE_ASSIGNMENTS			{ $$ = 1; }
	;

method_prototype:
		task_prototype				{ }
	|	function_prototype			{ }
	;

lifetimeE:			// IEEE: [lifetime]
		/* empty */		 		{ }
	|	lifetime		 		{ }
	;

lifetime:			// ==IEEE: lifetime
	//			// Note lifetime used by members is instead under memberQual
		ySTATIC__ETC		 		{ BBUNSUP($1, "Unsupported: Static in this context"); }
	|	yAUTOMATIC		 		{ }
	;

taskId<ftaskp>:
		tfIdScoped
			{ $$ = new AstTask($<fl>1, *$<strp>1, NULL);
			  SYMP->pushNewUnder($$, NULL); }
	;

funcId<ftaskp>:			// IEEE: function_data_type_or_implicit + part of function_body_declaration
	//			// IEEE: function_data_type_or_implicit must be expanded here to prevent conflict
	//			// function_data_type expanded here to prevent conflicts with implicit_type:empty vs data_type:ID
		/**/			tfIdScoped
			{ $$ = new AstFunc($<fl>1,*$<strp>1,NULL,
					   new AstBasicDType($<fl>1, LOGIC_IMPLICIT));
			  SYMP->pushNewUnder($$, NULL); }
	|	signingE rangeList	tfIdScoped
			{ $$ = new AstFunc($<fl>3,*$<strp>3,NULL,
					   GRAMMARP->addRange(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $1), $2,true));
			  SYMP->pushNewUnder($$, NULL); }
	|	signing			tfIdScoped
			{ $$ = new AstFunc($<fl>2,*$<strp>2,NULL,
					   new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $1));
			  SYMP->pushNewUnder($$, NULL); }
	|	data_type		tfIdScoped
			{ $$ = new AstFunc($<fl>2,*$<strp>2,NULL,$1);
			  SYMP->pushNewUnder($$, NULL); }
	//			// To verilator tasks are the same as void functions (we separately detect time passing)
	|	yVOID			tfIdScoped
			{ $$ = new AstTask($<fl>2,*$<strp>2,NULL);
			  SYMP->pushNewUnder($$, NULL); }
	;

funcIdNew<ftaskp>:		// IEEE: from class_constructor_declaration
		yNEW__ETC
			{ $$ = new AstFunc($<fl>1, "new", NULL, NULL);
			  BBUNSUP($<fl>1, "Unsupported: new constructor");
			  SYMP->pushNewUnder($$, NULL); }
	| 	yNEW__PAREN
			{ $$ = new AstFunc($<fl>1, "new", NULL, NULL);
			  BBUNSUP($<fl>1, "Unsupported: new constructor");
			  SYMP->pushNewUnder($$, NULL); }
	|	class_scopeWithoutId yNEW__PAREN
			{ $$ = new AstFunc($<fl>2, "new", NULL, NULL);
			  BBUNSUP($<fl>2, "Unsupported: scoped new constructor");
			  SYMP->pushNewUnder($$, NULL); }
	;

tfIdScoped<strp>:		// IEEE: part of function_body_declaration/task_body_declaration
 	//			// IEEE: [ interface_identifier '.' | class_scope ] function_identifier
		id					{ $<fl>$=$<fl>1; $<strp>$ = $1; }
	|	id/*interface_identifier*/ '.' id	{ $<fl>$=$<fl>3; $<strp>$ = $3; BBUNSUP($2, "Unsupported: Out of block function declaration"); }
	|	class_scopeIdFollows id			{ $<fl>$=$<fl>2; $<scp>$=$<scp>1; $<strp>$=$<strp>2;
							  BBUNSUP($<fl>1, "Unsupported: Out of class block function declaration"); }
	;

tfGuts<nodep>:
		'(' tf_port_listE ')' ';' tfBodyE	{ $$ = $2->addNextNull($5); }
	|	';' tfBodyE				{ $$ = $2; }
	;

tfBodyE<nodep>:			// IEEE: part of function_body_declaration/task_body_declaration
		/* empty */				{ $$ = NULL; }
	|	tf_item_declarationList			{ $$ = $1; }
	|	tf_item_declarationList stmtList	{ $$ = $1->addNextNull($2); }
	|	stmtList				{ $$ = $1; }
	;

tf_item_declarationList<nodep>:
		tf_item_declaration			{ $$ = $1; }
	|	tf_item_declarationList tf_item_declaration	{ $$ = $1->addNextNull($2); }
	;

tf_item_declaration<nodep>:	// ==IEEE: tf_item_declaration
		block_item_declaration			{ $$ = $1; }
	|	tf_port_declaration			{ $$ = $1; }
	|	tf_item_declarationVerilator		{ $$ = $1; }
	;

tf_item_declarationVerilator<nodep>:	// Verilator extensions
		yVL_PUBLIC				{ $$ = new AstPragma($1,AstPragmaType::PUBLIC_TASK); v3Global.dpi(true); }
	|	yVL_NO_INLINE_TASK			{ $$ = new AstPragma($1,AstPragmaType::NO_INLINE_TASK); }
	;

tf_port_listE<nodep>:		// IEEE: tf_port_list + empty
	//			// Empty covered by tf_port_item
		{VARRESET_LIST(UNKNOWN); VARIO(INPUT); }
			tf_port_listList		{ $$ = $2; VARRESET_NONLIST(UNKNOWN); }
	;

tf_port_listList<nodep>:	// IEEE: part of tf_port_list
		tf_port_item				{ $$ = $1; }
	|	tf_port_listList ',' tf_port_item	{ $$ = $1->addNextNull($3); }
	;

tf_port_item<nodep>:		// ==IEEE: tf_port_item
	//			// We split tf_port_item into the type and assignment as don't know what follows a comma
		/* empty */				{ $$ = NULL; PINNUMINC(); }	// For example a ",," port
	|	tf_port_itemFront tf_port_itemAssignment { $$ = $2; }
	|	tf_port_itemAssignment 			{ $$ = $1; }
	;

tf_port_itemFront:		// IEEE: part of tf_port_item, which has the data type
		data_type				{ VARDTYPE($1); }
	|	signingE rangeList			{ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2, true)); }
	|	signing					{ VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1)); }
	|	yVAR data_type				{ VARDTYPE($2); }
	|	yVAR implicit_typeE			{ VARDTYPE($2); }
	//
	|	tf_port_itemDir /*implicit*/		{ VARDTYPE(NULL); /*default_nettype-see spec*/ }
	|	tf_port_itemDir data_type		{ VARDTYPE($2); }
	|	tf_port_itemDir signingE rangeList	{ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3,true)); }
	|	tf_port_itemDir signing			{ VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $2)); }
	|	tf_port_itemDir yVAR data_type		{ VARDTYPE($3); }
	|	tf_port_itemDir yVAR implicit_typeE	{ VARDTYPE($3); }
	;

tf_port_itemDir:		// IEEE: part of tf_port_item, direction
		port_direction				{ }  // port_direction sets VARIO
	;

tf_port_itemAssignment<varp>:	// IEEE: part of tf_port_item, which has assignment
		id variable_dimensionListE sigAttrListE
			{ $$ = VARDONEA($<fl>1, *$1, $2, $3); }
	|	id variable_dimensionListE sigAttrListE '=' expr
			{ $$ = VARDONEA($<fl>1, *$1, $2, $3); $$->valuep($5); }
	;

parenE:
		/* empty */				{ }
	|	'(' ')'					{ }
	;

//	method_call:		// ==IEEE: method_call + method_call_body
//				// IEEE: method_call_root '.' method_identifier [ '(' list_of_arguments ')' ]
//				//   "method_call_root '.' method_identifier" looks just like "expr '.' id"
//				//   "method_call_root '.' method_identifier (...)" looks just like "expr '.' tf_call"
//				// IEEE: built_in_method_call
//				//   method_call_root not needed, part of expr resolution
//				// What's left is below array_methodNoRoot
array_methodNoRoot<nodep>:
		yOR					{ $$ = new AstFuncRef($1, "or", NULL); }
	|	yAND					{ $$ = new AstFuncRef($1, "and", NULL); }
	|	yXOR					{ $$ = new AstFuncRef($1, "xor", NULL); }
	//UNSUP	yUNIQUE					{ $$ = new AstFuncRef($1, "unique", NULL); }
	;

dpi_import_export<nodep>:	// ==IEEE: dpi_import_export
		yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE function_prototype ';'
			{ $$ = $5; if (*$4!="") $5->cname(*$4); $5->dpiContext($3==iprop_CONTEXT); $5->pure($3==iprop_PURE);
			  $5->dpiImport(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true);
			  if ($$->prettyName()[0]=='$') SYMP->reinsert($$,NULL,$$->prettyName());  // For $SysTF overriding
			  SYMP->reinsert($$); }
	|	yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE task_prototype ';'
			{ $$ = $5; if (*$4!="") $5->cname(*$4); $5->dpiContext($3==iprop_CONTEXT); $5->pure($3==iprop_PURE);
			  $5->dpiImport(true); $5->dpiTask(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true);
			  if ($$->prettyName()[0]=='$') SYMP->reinsert($$,NULL,$$->prettyName());  // For $SysTF overriding
			  SYMP->reinsert($$); }
	|	yEXPORT yaSTRING dpi_importLabelE yFUNCTION idAny ';'	{ $$ = new AstDpiExport($<fl>5, *$5, *$3);
			  GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true); }
	|	yEXPORT yaSTRING dpi_importLabelE yTASK     idAny ';'	{ $$ = new AstDpiExport($<fl>5, *$5, *$3);
			  GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true); }
	;

dpi_importLabelE<strp>:		// IEEE: part of dpi_import_export
		/* empty */				{ static string s; $$ = &s; }
	|	idAny/*c_identifier*/ '='		{ $$ = $1; $<fl>$=$<fl>1; }
	;

dpi_tf_import_propertyE<iprop>:	// IEEE: [ dpi_function_import_property + dpi_task_import_property ]
		/* empty */				{ $$ = iprop_NONE; }
	|	yCONTEXT				{ $$ = iprop_CONTEXT; }
	|	yPURE					{ $$ = iprop_PURE; }
	;

//************************************************
// Expressions
//
// ~l~ means this is the (l)eft hand side of any operator
//     it will get replaced by "", "f" or "s"equence
// ~r~ means this is a (r)ight hand later expansion in the same statement,
//     not under parenthesis for <= disambiguation
//     it will get replaced by "", or "f"
// ~p~ means this is a (p)arenthetized expression
//     it will get replaced by "", or "s"equence

constExpr<nodep>:
		expr					{ $$ = $1; }
	;

expr<nodep>:			// IEEE: part of expression/constant_expression/primary
	// *SEE BELOW*		// IEEE: primary/constant_primary
	//
	//			// IEEE: unary_operator primary
		'+' ~r~expr	%prec prUNARYARITH	{ $$ = $2; }
	|	'-' ~r~expr	%prec prUNARYARITH	{ $$ = new AstNegate	($1,$2); }
	|	'!' ~r~expr	%prec prNEGATION	{ $$ = new AstLogNot	($1,$2); }
	|	'&' ~r~expr	%prec prREDUCTION	{ $$ = new AstRedAnd	($1,$2); }
	|	'~' ~r~expr	%prec prNEGATION	{ $$ = new AstNot	($1,$2); }
	|	'|' ~r~expr	%prec prREDUCTION	{ $$ = new AstRedOr	($1,$2); }
	|	'^' ~r~expr	%prec prREDUCTION	{ $$ = new AstRedXor	($1,$2); }
	|	yP_NAND ~r~expr	%prec prREDUCTION	{ $$ = new AstLogNot($1, new AstRedAnd($1, $2)); }
	|	yP_NOR  ~r~expr	%prec prREDUCTION	{ $$ = new AstLogNot($1, new AstRedOr($1, $2)); }
	|	yP_XNOR ~r~expr	%prec prREDUCTION	{ $$ = new AstRedXnor	($1,$2); }
	//
	//			// IEEE: inc_or_dec_expression
	//UNSUP	~l~inc_or_dec_expression		{ UNSUP }
	//
	//			// IEEE: '(' operator_assignment ')'
	//			// Need exprScope of variable_lvalue to prevent conflict
	//UNSUP	'(' ~p~exprScope '=' 	      expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_PLUSEQ    expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_MINUSEQ   expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_TIMESEQ   expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_DIVEQ     expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_MODEQ     expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_ANDEQ     expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_OREQ      expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_XOREQ     expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_SLEFTEQ   expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_SRIGHTEQ  expr ')'	{ UNSUP }
	//UNSUP	'(' ~p~exprScope yP_SSRIGHTEQ expr ')'	{ UNSUP }
	//
	//			// IEEE: expression binary_operator expression
	|	~l~expr '+' ~r~expr			{ $$ = new AstAdd	($2,$1,$3); }
	|	~l~expr '-' ~r~expr			{ $$ = new AstSub	($2,$1,$3); }
	|	~l~expr '*' ~r~expr			{ $$ = new AstMul	($2,$1,$3); }
	|	~l~expr '/' ~r~expr			{ $$ = new AstDiv	($2,$1,$3); }
	|	~l~expr '%' ~r~expr			{ $$ = new AstModDiv	($2,$1,$3); }
	|	~l~expr yP_EQUAL ~r~expr		{ $$ = new AstEq	($2,$1,$3); }
	|	~l~expr yP_NOTEQUAL ~r~expr		{ $$ = new AstNeq	($2,$1,$3); }
	|	~l~expr yP_CASEEQUAL ~r~expr		{ $$ = new AstEqCase	($2,$1,$3); }
	|	~l~expr yP_CASENOTEQUAL ~r~expr		{ $$ = new AstNeqCase	($2,$1,$3); }
	|	~l~expr yP_WILDEQUAL ~r~expr		{ $$ = new AstEqWild	($2,$1,$3); }
	|	~l~expr yP_WILDNOTEQUAL ~r~expr		{ $$ = new AstNeqWild	($2,$1,$3); }
	|	~l~expr yP_ANDAND ~r~expr		{ $$ = new AstLogAnd	($2,$1,$3); }
	|	~l~expr yP_OROR ~r~expr			{ $$ = new AstLogOr	($2,$1,$3); }
	|	~l~expr yP_POW ~r~expr			{ $$ = new AstPow	($2,$1,$3); }
	|	~l~expr '<' ~r~expr			{ $$ = new AstLt	($2,$1,$3); }
	|	~l~expr '>' ~r~expr			{ $$ = new AstGt	($2,$1,$3); }
	|	~l~expr yP_GTE ~r~expr			{ $$ = new AstGte	($2,$1,$3); }
	|	~l~expr '&' ~r~expr			{ $$ = new AstAnd	($2,$1,$3); }
	|	~l~expr '|' ~r~expr			{ $$ = new AstOr	($2,$1,$3); }
	|	~l~expr '^' ~r~expr			{ $$ = new AstXor	($2,$1,$3); }
	|	~l~expr yP_XNOR ~r~expr			{ $$ = new AstXnor	($2,$1,$3); }
	|	~l~expr yP_NOR ~r~expr			{ $$ = new AstNot($2,new AstOr	($2,$1,$3)); }
	|	~l~expr yP_NAND ~r~expr			{ $$ = new AstNot($2,new AstAnd	($2,$1,$3)); }
	|	~l~expr yP_SLEFT ~r~expr		{ $$ = new AstShiftL	($2,$1,$3); }
	|	~l~expr yP_SRIGHT ~r~expr		{ $$ = new AstShiftR	($2,$1,$3); }
	|	~l~expr yP_SSRIGHT ~r~expr		{ $$ = new AstShiftRS	($2,$1,$3); }
	|	~l~expr yP_LTMINUSGT ~r~expr		{ $$ = new AstLogEq     ($2,$1,$3); }
	//
	//			// IEEE: expr yP_MINUSGT expr  (1800-2009)
	//			// Conflicts with constraint_expression:"expr yP_MINUSGT constraint_set"
	//			// To duplicating expr for constraints, just allow the more general form
	//			// Later Ast processing must ignore constraint terms where inappropriate
	//UNSUP	~l~expr yP_MINUSGT constraint_set		{ $<fl>$=$<fl>1; $$ = $1+$2+$3; }
	//UNSUP remove line below
	|	~l~expr yP_MINUSGT ~r~expr		{ $$ = new AstLogIf($2, $1, $3); }
	//
	//			// <= is special, as we need to disambiguate it with <= assignment
	//			// We copy all of expr to fexpr and rename this token to a fake one.
	|	~l~expr yP_LTE~f__IGNORE~ ~r~expr	{ $$ = new AstLte($2, $1, $3); }
	//
	//			// IEEE: conditional_expression
	|	~l~expr '?' ~r~expr ':' ~r~expr		{ $$ = new AstCond($2,$1,$3,$5); }
	//
	//			// IEEE: inside_expression
	|	~l~expr yINSIDE '{' open_range_list '}'	{ $$ = new AstInside($2,$1,$4); }
	//
	//			// IEEE: tagged_union_expression
	//UNSUP	yTAGGED id/*member*/ %prec prTAGGED		{ UNSUP }
	//UNSUP	yTAGGED id/*member*/ %prec prTAGGED expr	{ UNSUP }
	//
	//======================// IEEE: primary/constant_primary
	//
	//			// IEEE: primary_literal (minus string, which is handled specially)
	|	yaINTNUM				{ $$ = new AstConst($<fl>1,*$1); }
	|	yaFLOATNUM				{ $$ = new AstConst($<fl>1,AstConst::RealDouble(),$1); }
	//UNSUP	yaTIMENUM				{ UNSUP }
	|	strAsInt~noStr__IGNORE~			{ $$ = $1; }
	//
	//			// IEEE: "... hierarchical_identifier select"  see below
	//
	//			// IEEE: empty_queue (IEEE 1800-2017 empty_unpacked_array_concatenation)
	|	'{' '}'					{ $$ = new AstConst($1, AstConst::LogicFalse());
							  $<fl>1->v3error("Unsupported: empty queues (\"{ }\")"); }
	//
	//			// IEEE: concatenation/constant_concatenation
	//			// Part of exprOkLvalue below
	//
	//			// IEEE: multiple_concatenation/constant_multiple_concatenation
	|	'{' constExpr '{' cateList '}' '}'	{ $$ = new AstReplicate($3, $4, $2); }
	//			// UNSUP some other rules above
	//
	|	function_subroutine_callNoMethod	{ $$ = $1; }
	//			// method_call
	|	~l~expr '.' function_subroutine_callNoMethod	{ $$ = new AstDot($2,$1,$3); }
	//			// method_call:array_method requires a '.'
	|	~l~expr '.' array_methodNoRoot		{ $$ = new AstDot($2,$1,$3); }
	//
	//			// IEEE: let_expression
	//			// see funcRef
	//
	//			// IEEE: '(' mintypmax_expression ')'
	|	~noPar__IGNORE~'(' expr ')'		{ $$ = $2; }
	|	~noPar__IGNORE~'(' expr ':' expr ':' expr ')'	{ $$ = $2; BBUNSUP($1, "Unsupported: min typ max expressions"); }
	//			// PSL rule
	|	'_' '(' expr ')'			{ $$ = $3; }	// Arbitrary Verilog inside PSL
	//
	//			// IEEE: cast/constant_cast
	|	casting_type yP_TICK '(' expr ')'	{ $$ = new AstCast($1->fileline(), $4, $1); }
	//			// expanded from casting_type
	|	ySIGNED	     yP_TICK '(' expr ')'	{ $$ = new AstSigned($1,$4); }
	|	yUNSIGNED    yP_TICK '(' expr ')'	{ $$ = new AstUnsigned($1,$4); }
	//			// Spec only allows primary with addition of a type reference
	//			// We'll be more general, and later assert LHS was a type.
	|	~l~expr      yP_TICK '(' expr ')'	{ $$ = new AstCastParse($2,$4,$1); }
	//
	//			// IEEE: assignment_pattern_expression
	//			// IEEE: streaming_concatenation
	//			// See exprOkLvalue
	//
	//			// IEEE: sequence_method_call
	//			// Indistinguishable from function_subroutine_call:method_call
	//
	|	'$'					{ $$ = new AstUnbounded($<fl>1); }
	|	yNULL					{ $$ = new AstConst($1, AstConst::LogicFalse()); }
	//			// IEEE: yTHIS
	//			// See exprScope
	//
	//----------------------
	//
	//			// Part of expr that may also be used as lvalue
	|	~l~exprOkLvalue				{ $$ = $1; }
	//
	//----------------------
	//
	//			// IEEE: cond_predicate - here to avoid reduce problems
	//			// Note expr includes cond_pattern
	|	~l~expr yP_ANDANDAND ~r~expr		{ $$ = new AstConst($2, AstConst::LogicFalse());
							  BBUNSUP($<fl>2, "Unsupported: &&& expression"); }
	//
	//			// IEEE: cond_pattern - here to avoid reduce problems
	//			// "expr yMATCHES pattern"
	//			// IEEE: pattern - expanded here to avoid conflicts
	//UNSUP	~l~expr yMATCHES patternNoExpr		{ UNSUP }
	//UNSUP	~l~expr yMATCHES ~r~expr		{ UNSUP }
	//
	//			// IEEE: expression_or_dist - here to avoid reduce problems
	//			// "expr yDIST '{' dist_list '}'"
	//UNSUP	~l~expr yDIST '{' dist_list '}'		{ UNSUP }
	;

fexpr<nodep>:			// For use as first part of statement (disambiguates <=)
		BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;})	// {copied}
	;

//UNSUPev_expr<nodep>:  // IEEE: event_expression
//UNSUP	//			// for yOR/, see event_expression
//UNSUP	//
//UNSUP	//			// IEEE: [ edge_identifier ] expression [ yIFF expression ]
//UNSUP	//			// expr alone see below
//UNSUP		senitemEdge				{ $$ = $1; }
//UNSUP	|	ev_expr yIFF expr			{ }
//UNSUP	//
//UNSUP	//			// IEEE: sequence_instance [ yIFF expression ]
//UNSUP	//			// seq_inst is in expr, so matches senitem rule above
//UNSUP	//
//UNSUP	//			// IEEE: event_expression yOR event_expression
//UNSUP	|	ev_expr yOR ev_expr			{ }
//UNSUP	//			// IEEE: event_expression ',' event_expression
//UNSUP	//			// See real event_expression rule
//UNSUP	//
//UNSUP	//---------------------
//UNSUP	//			// IEEE: expr
//UNSUP	|	BISONPRE_COPY(expr,{s/~l~/ev_/g; s/~r~/ev_/g; s/~p~/ev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g;})	// {copied}
//UNSUP	//
//UNSUP	//			// IEEE: '(' event_expression ')'
//UNSUP	//			// expr:'(' x ')' conflicts with event_expression:'(' event_expression ')'
//UNSUP	//			// so we use a special expression class
//UNSUP	|	'(' event_expression ')'		{ $<fl>$=$<fl>1; $$ = "(...)"; }
//UNSUP	//			// IEEE: From normal expr: '(' expr ':' expr ':' expr ')'
//UNSUP	//			// But must avoid conflict
//UNSUP	|	'(' event_expression ':' expr ':' expr ')'	{ $<fl>$=$<fl>1; $$ = "(...)"; }
//UNSUP	;

exprNoStr<nodep>:		// expression with string removed
		BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;})	// {copied}
	;

exprOkLvalue<nodep>:		// expression that's also OK to use as a variable_lvalue
		~l~exprScope				{ $$ = $1; }
	//			// IEEE: concatenation/constant_concatenation
	//			// Replicate(1) required as otherwise "{a}" would not be self-determined
	|	'{' cateList '}'			{ $$ = new AstReplicate($1,$2,1); }
	|	'{' cateList '}' '[' expr ']'		{ $$ = new AstSelBit($4, new AstReplicate($1,$2,1), $5); }
	|	'{' cateList '}' '[' constExpr ':' constExpr ']'
							{ $$ = new AstSelExtract($4, new AstReplicate($1,$2,1), $5, $7); }
	|	'{' cateList '}' '[' expr yP_PLUSCOLON constExpr ']'
							{ $$ = new AstSelPlus($4, new AstReplicate($1,$2,1), $5, $7); }
	|	'{' cateList '}' '[' expr yP_MINUSCOLON constExpr ']'
							{ $$ = new AstSelMinus($4, new AstReplicate($1,$2,1), $5, $7); }
	//			// IEEE: assignment_pattern_expression
	//			// IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type]
	//			// We allow more here than the spec requires
	//UNSUP	~l~exprScope assignment_pattern		{ UNSUP }
	|	data_type assignment_pattern		{ $$ = $2; if ($2) $2->childDTypep($1); }
	|	assignment_pattern			{ $$ = $1; }
	//
	|	streaming_concatenation			{ $$ = $1; }
	;

fexprOkLvalue<nodep>:		// exprOkLValue, For use as first part of statement (disambiguates <=)
		BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g})	// {copied}
	;

//UNSUPsexprOkLvalue<nodep>:  // exprOkLValue, For use by sequence_expr
//UNSUP		BISONPRE_COPY(exprOkLvalue,{s/~l~/s/g})	// {copied}
//UNSUP	;

//UNSUPpexprOkLvalue<nodep>:  // exprOkLValue, For use by property_expr
//UNSUP		BISONPRE_COPY(exprOkLvalue,{s/~l~/p/g})	// {copied}
//UNSUP	;

//UNSUPev_exprOkLvalue<nodep>:  // exprOkLValue, For use by ev_expr
//UNSUP		BISONPRE_COPY(exprOkLvalue,{s/~l~/ev_/g})	// {copied}
//UNSUP	;

//UNSUPpev_exprOkLvalue<nodep>:  // exprOkLValue, For use by ev_expr
//UNSUP		BISONPRE_COPY(exprOkLvalue,{s/~l~/pev_/g})	// {copied}
//UNSUP	;

fexprLvalue<nodep>:		// For use as first part of statement (disambiguates <=)
		fexprOkLvalue				{ $<fl>$=$<fl>1; $$ = $1; }
	;

exprScope<nodep>:		// scope and variable for use to inside an expression
	// 			// Here we've split method_call_root | implicit_class_handle | class_scope | package_scope
	//			// from the object being called and let expr's "." deal with resolving it.
	//			// (note method_call_root was simplified to require a primary in 1800-2009)
	//
	//			// IEEE: [ implicit_class_handle . | class_scope | package_scope ] hierarchical_identifier select
	//			// Or method_call_body without parenthesis
	//			// See also varRefClassBit, which is the non-expr version of most of this
		yTHIS					{ $$ = new AstConst($1, AstConst::LogicFalse());
							  BBUNSUP($1, "Unsupported: this"); }
	|	idArrayed				{ $$ = $1; }
	|	package_scopeIdFollows idArrayed	{ $$ = AstDot::newIfPkg($2->fileline(), $1, $2); }
	|	class_scopeIdFollows idArrayed		{ $$ = $2; BBUNSUP($<fl>1, "Unsupported: scoped class reference"); }
	|	~l~expr '.' idArrayed			{ $$ = new AstDot($<fl>2,$1,$3); }
	//			// expr below must be a "yTHIS"
	|	~l~expr '.' ySUPER			{ $$ = $1; BBUNSUP($3, "Unsupported: super"); }
	//			// Part of implicit_class_handle
	|	ySUPER					{ $$ = new AstConst($1, AstConst::LogicFalse());
							  BBUNSUP($1, "Unsupported: super"); }
	;

fexprScope<nodep>:		// exprScope, For use as first part of statement (disambiguates <=)
		BISONPRE_COPY(exprScope,{s/~l~/f/g})	// {copied}
	;

//UNSUPsexprScope<nodep>:  // exprScope, For use by sequence_expr
//UNSUP		BISONPRE_COPY(exprScope,{s/~l~/s/g})	// {copied}
//UNSUP	;

//UNSUPpexprScope<nodep>:  // exprScope, For use by property_expr
//UNSUP		BISONPRE_COPY(exprScope,{s/~l~/p/g})	// {copied}
//UNSUP	;

//UNSUPev_exprScope<nodep>:  // exprScope, For use by ev_expr
//UNSUP		BISONPRE_COPY(exprScope,{s/~l~/ev_/g})	// {copied}
//UNSUP	;

//UNSUPpev_exprScope<nodep>:  // exprScope, For use by ev_expr
//UNSUP		BISONPRE_COPY(exprScope,{s/~l~/pev_/g})	// {copied}
//UNSUP	;

// PLI calls exclude "" as integers, they're strings
// For $c("foo","bar") we want "bar" as a string, not a Verilog integer.
exprStrText<nodep>:
		exprNoStr				{ $$ = $1; }
	|	strAsText				{ $$ = $1; }
	;

cStrList<nodep>:
		exprStrText				{ $$ = $1; }
	|	exprStrText ',' cStrList		{ $$ = $1;$1->addNext($3); }
	;

cateList<nodep>:
	//			// Not just 'expr' to prevent conflict via stream_concOrExprOrType
		stream_expression			{ $$ = $1; }
	|	cateList ',' stream_expression		{ $$ = new AstConcat($2,$1,$3); }
	;

exprListE<nodep>:
		/* empty */				{ $$ = NULL; }
	|	exprList				{ $$ = $1; }
	;

exprList<nodep>:
		expr					{ $$ = $1; }
	|	exprList ',' expr			{ $$ = $1;$1->addNext($3); }
	;

commaEListE<nodep>:
		/* empty */				{ $$ = NULL; }
	|	',' exprList				{ $$ = $2; }
	;

vrdList<nodep>:
		idClassSel				{ $$ = $1; }
	|	vrdList ',' idClassSel			{ $$ = $1;$1->addNext($3); }
	;

commaVRDListE<nodep>:
		/* empty */				{ $$ = NULL; }
	|	',' vrdList				{ $$ = $2; }
	;

argsExprList<nodep>:		// IEEE: part of list_of_arguments (used where ,, isn't legal)
		expr					{ $$ = $1; }
	|	argsExprList ',' expr			{ $$ = $1->addNext($3); }
	;

argsExprListE<nodep>:		// IEEE: part of list_of_arguments
		argsExprOneE				{ $$ = $1; }
	|	argsExprListE ',' argsExprOneE		{ $$ = $1->addNext($3); }
	;

//UNSUPpev_argsExprListE<nodep>:  // IEEE: part of list_of_arguments - pev_expr at bottom
//UNSUP		pev_argsExprOneE			{ $$ = $1; }
//UNSUP	|	pev_argsExprListE ',' pev_argsExprOneE	{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

argsExprOneE<nodep>:		// IEEE: part of list_of_arguments
		/*empty*/				{ $$ = new AstArg(CRELINE(), "", NULL); }
	|	expr					{ $$ = new AstArg($1->fileline(), "", $1); }
	;

//UNSUPpev_argsExprOneE<nodep>:  // IEEE: part of list_of_arguments - pev_expr at bottom
//UNSUP		/*empty*/				{ $$ = NULL; }	// ,, is legal in list_of_arguments
//UNSUP	|	pev_expr				{ $$ = $1; }
//UNSUP	;

argsDottedList<nodep>:		// IEEE: part of list_of_arguments
		argsDotted				{ $$ = $1; }
	|	argsDottedList ',' argsDotted		{ $$ = $1->addNextNull($3); }
	;

//UNSUPpev_argsDottedList<nodep>:  // IEEE: part of list_of_arguments - pev_expr at bottom
//UNSUP		pev_argsDotted				{ $$ = $1; }
//UNSUP	|	pev_argsDottedList ',' pev_argsDotted	{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

argsDotted<nodep>:		// IEEE: part of list_of_arguments
		'.' idAny '(' ')'			{ $$ = new AstArg($<fl>2, *$2, NULL); }
	|	'.' idAny '(' expr ')'			{ $$ = new AstArg($<fl>2, *$2, $4); }
	;

//UNSUPpev_argsDotted<nodep>:  // IEEE: part of list_of_arguments - pev_expr at bottom
//UNSUP		'.' idAny '(' ')'			{ $$ = new AstArg($<fl>2, *$2, NULL); }
//UNSUP	|	'.' idAny '(' pev_expr ')'		{ $$ = new AstArg($<fl>2, *$2, $4); }
//UNSUP	;

streaming_concatenation<nodep>:	// ==IEEE: streaming_concatenation
	//	 		// Need to disambiguate {<< expr-{ ... expr-} stream_concat }
	//			// From                 {<< stream-{ ... stream-} }
	//			// Likewise simple_type's idScoped from constExpr's idScope
	//			// Thus we allow always any two operations.  Sorry
	//			// IEEE: "'{' yP_SL/R             stream_concatenation '}'"
	//			// IEEE: "'{' yP_SL/R simple_type stream_concatenation '}'"
	//			// IEEE: "'{' yP_SL/R constExpr	  stream_concatenation '}'"
		'{' yP_SLEFT              stream_concOrExprOrType '}'	{ $$ = new AstStreamL($2, $3, new AstConst($2,1)); }
	|	'{' yP_SRIGHT             stream_concOrExprOrType '}'	{ $$ = new AstStreamR($2, $3, new AstConst($2,1)); }
	|	'{' yP_SLEFT  stream_concOrExprOrType stream_concatenation '}'	{ $$ = new AstStreamL($2, $4, $3); }
	|	'{' yP_SRIGHT stream_concOrExprOrType stream_concatenation '}'	{ $$ = new AstStreamR($2, $4, $3); }
	;

stream_concOrExprOrType<nodep>:	// IEEE: stream_concatenation | slice_size:simple_type | slice_size:constExpr
		cateList				{ $$ = $1; }
	|	simple_type				{ $$ = $1; }
	//			// stream_concatenation found via cateList:stream_expr:'{-normal-concat'
	//			// simple_typeRef found via cateList:stream_expr:expr:id
	//			// constant_expression found via cateList:stream_expr:expr
	;

stream_concatenation<nodep>:	// ==IEEE: stream_concatenation
		'{' cateList '}'			{ $$ = $2; }
	;

stream_expression<nodep>:	// ==IEEE: stream_expression
	//			// IEEE: array_range_expression expanded below
		expr					{ $$ = $1; }
	//UNSUP	expr yWITH__BRA '[' expr ']'		{ UNSUP }
	//UNSUP	expr yWITH__BRA '[' expr ':' expr ']'	{ UNSUP }
	//UNSUP	expr yWITH__BRA '[' expr yP_PLUSCOLON  expr ']'	{ UNSUP }
	//UNSUP	expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']'	{ UNSUP }
	;

//************************************************
// Gate declarations

gateDecl<nodep>:
		yBUF    delayE gateBufList ';'		{ $$ = $3; }
	|	yBUFIF0 delayE gateBufif0List ';'	{ $$ = $3; }
	|	yBUFIF1 delayE gateBufif1List ';'	{ $$ = $3; }
	|	yNOT    delayE gateNotList ';'		{ $$ = $3; }
	|	yNOTIF0 delayE gateNotif0List ';'	{ $$ = $3; }
	|	yNOTIF1 delayE gateNotif1List ';'	{ $$ = $3; }
	|	yAND  delayE gateAndList ';'		{ $$ = $3; }
	|	yNAND delayE gateNandList ';'		{ $$ = $3; }
	|	yOR   delayE gateOrList ';'		{ $$ = $3; }
	|	yNOR  delayE gateNorList ';'		{ $$ = $3; }
	|	yXOR  delayE gateXorList ';'		{ $$ = $3; }
	|	yXNOR delayE gateXnorList ';'		{ $$ = $3; }
	|	yPULLUP delayE gatePullupList ';'	{ $$ = $3; }
	|	yPULLDOWN delayE gatePulldownList ';'	{ $$ = $3; }
	|	yNMOS delayE gateBufif1List ';'		{ $$ = $3; }  // ~=bufif1, as don't have strengths yet
	|	yPMOS delayE gateBufif0List ';'		{ $$ = $3; }  // ~=bufif0, as don't have strengths yet
	//
	|	yTRAN delayE gateUnsupList ';'		{ $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported
	|	yRCMOS delayE gateUnsupList ';'		{ $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported
	|	yCMOS delayE gateUnsupList ';'		{ $$ = $3; GATEUNSUP($3,"cmos"); } // Unsupported
	|	yRNMOS delayE gateUnsupList ';'		{ $$ = $3; GATEUNSUP($3,"rmos"); } // Unsupported
	|	yRPMOS delayE gateUnsupList ';'		{ $$ = $3; GATEUNSUP($3,"pmos"); } // Unsupported
	|	yRTRAN delayE gateUnsupList ';'		{ $$ = $3; GATEUNSUP($3,"rtran"); } // Unsupported
	|	yRTRANIF0 delayE gateUnsupList ';'	{ $$ = $3; GATEUNSUP($3,"rtranif0"); } // Unsupported
	|	yRTRANIF1 delayE gateUnsupList ';'	{ $$ = $3; GATEUNSUP($3,"rtranif1"); } // Unsupported
	|	yTRANIF0 delayE gateUnsupList ';'	{ $$ = $3; GATEUNSUP($3,"tranif0"); } // Unsupported
	|	yTRANIF1 delayE gateUnsupList ';'	{ $$ = $3; GATEUNSUP($3,"tranif1"); } // Unsupported
	;

gateBufList<nodep>:
		gateBuf 				{ $$ = $1; }
	|	gateBufList ',' gateBuf			{ $$ = $1->addNext($3); }
	;
gateBufif0List<nodep>:
		gateBufif0 				{ $$ = $1; }
	|	gateBufif0List ',' gateBufif0		{ $$ = $1->addNext($3); }
	;
gateBufif1List<nodep>:
		gateBufif1 				{ $$ = $1; }
	|	gateBufif1List ',' gateBufif1		{ $$ = $1->addNext($3); }
	;
gateNotList<nodep>:
		gateNot 				{ $$ = $1; }
	|	gateNotList ',' gateNot			{ $$ = $1->addNext($3); }
	;
gateNotif0List<nodep>:
		gateNotif0 				{ $$ = $1; }
	|	gateNotif0List ',' gateNotif0		{ $$ = $1->addNext($3); }
	;
gateNotif1List<nodep>:
		gateNotif1 				{ $$ = $1; }
	|	gateNotif1List ',' gateNotif1		{ $$ = $1->addNext($3); }
	;
gateAndList<nodep>:
		gateAnd 				{ $$ = $1; }
	|	gateAndList ',' gateAnd			{ $$ = $1->addNext($3); }
	;
gateNandList<nodep>:
		gateNand 				{ $$ = $1; }
	|	gateNandList ',' gateNand		{ $$ = $1->addNext($3); }
	;
gateOrList<nodep>:
		gateOr 					{ $$ = $1; }
	|	gateOrList ',' gateOr			{ $$ = $1->addNext($3); }
	;
gateNorList<nodep>:
		gateNor 				{ $$ = $1; }
	|	gateNorList ',' gateNor			{ $$ = $1->addNext($3); }
	;
gateXorList<nodep>:
		gateXor 				{ $$ = $1; }
	|	gateXorList ',' gateXor			{ $$ = $1->addNext($3); }
	;
gateXnorList<nodep>:
		gateXnor 				{ $$ = $1; }
	|	gateXnorList ',' gateXnor		{ $$ = $1->addNext($3); }
	;
gatePullupList<nodep>:
		gatePullup 				{ $$ = $1; }
	|	gatePullupList ',' gatePullup		{ $$ = $1->addNext($3); }
	;
gatePulldownList<nodep>:
		gatePulldown 				{ $$ = $1; }
	|	gatePulldownList ',' gatePulldown	{ $$ = $1->addNext($3); }
	;
gateUnsupList<nodep>:
		gateUnsup 				{ $$ = $1; }
	|	gateUnsupList ',' gateUnsup		{ $$ = $1->addNext($3); }
	;

gateRangeE<nodep>:
		instRangeListE 				{ $$ = $1; GATERANGE(GRAMMARP->scrubRange($1)); }
	;

gateBuf<nodep>:
		gateFront variable_lvalue ',' gatePinExpr ')'
			{ $$ = new AstAssignW($<fl>1, $2, $4); DEL($1); }
	;
gateBufif0<nodep>:
		gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')'
			{ $$ = new AstAssignW($<fl>1, $2, new AstBufIf1($<fl>1, new AstNot($<fl>1, $6), $4)); DEL($1); }
	;
gateBufif1<nodep>:
		gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')'
			{ $$ = new AstAssignW($<fl>1, $2, new AstBufIf1($<fl>1, $6, $4)); DEL($1); }
	;
gateNot<nodep>:
		gateFront variable_lvalue ',' gatePinExpr ')'
			{ $$ = new AstAssignW($<fl>1, $2, new AstNot($<fl>1, $4)); DEL($1); }
	;
gateNotif0<nodep>:
		gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')'
			{ $$ = new AstAssignW($<fl>1, $2, new AstBufIf1($<fl>1, new AstNot($<fl>1, $6),
									new AstNot($<fl>1, $4))); DEL($1); }
	;
gateNotif1<nodep>:
		gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')'
			{ $$ = new AstAssignW($<fl>1, $2, new AstBufIf1($<fl>1, $6, new AstNot($<fl>1, $4))); DEL($1); }
	;
gateAnd<nodep>:
		gateFront variable_lvalue ',' gateAndPinList ')'
			{ $$ = new AstAssignW($<fl>1, $2, $4); DEL($1); }
	;
gateNand<nodep>:
		gateFront variable_lvalue ',' gateAndPinList ')'
			{ $$ = new AstAssignW($<fl>1, $2, new AstNot($<fl>1, $4)); DEL($1); }
	;
gateOr<nodep>:
		gateFront variable_lvalue ',' gateOrPinList ')'
			{ $$ = new AstAssignW($<fl>1, $2, $4); DEL($1); }
	;
gateNor<nodep>:
		gateFront variable_lvalue ',' gateOrPinList ')'
			{ $$ = new AstAssignW($<fl>1, $2, new AstNot($<fl>1, $4)); DEL($1); }
	;
gateXor<nodep>:
		gateFront variable_lvalue ',' gateXorPinList ')'
			{ $$ = new AstAssignW($<fl>1, $2, $4); DEL($1); }
	;
gateXnor<nodep>:
		gateFront variable_lvalue ',' gateXorPinList ')'
			{ $$ = new AstAssignW($<fl>1, $2, new AstNot($<fl>1, $4)); DEL($1); }
	;
gatePullup<nodep>:
		gateFront variable_lvalue ')'		{ $$ = new AstPull($<fl>1, $2, true); DEL($1); }
	;
gatePulldown<nodep>:
		gateFront variable_lvalue ')'		{ $$ = new AstPull($<fl>1, $2, false); DEL($1); }
	;
gateUnsup<nodep>:
		gateFront gateUnsupPinList ')'		{ $$ = new AstImplicit($<fl>1, $2); DEL($1); }
	;

gateFront<nodep>:
		id/*gate*/ gateRangeE '('		{ $$ = $2; $<fl>$ = $<fl>1; }
	|	gateRangeE '('				{ $$ = $1; $<fl>$ = $<fl>2; }
	;

gateAndPinList<nodep>:
		gatePinExpr 				{ $$ = $1; }
	|	gateAndPinList ',' gatePinExpr		{ $$ = new AstAnd($2,$1,$3); }
	;
gateOrPinList<nodep>:
		gatePinExpr 				{ $$ = $1; }
	|	gateOrPinList ',' gatePinExpr		{ $$ = new AstOr($2,$1,$3); }
	;
gateXorPinList<nodep>:
		gatePinExpr 				{ $$ = $1; }
	|	gateXorPinList ',' gatePinExpr		{ $$ = new AstXor($2,$1,$3); }
	;
gateUnsupPinList<nodep>:
		gatePinExpr 				{ $$ = $1; }
	|	gateUnsupPinList ',' gatePinExpr	{ $$ = $1->addNext($3); }
	;

gatePinExpr<nodep>:
		expr					{ $$ = GRAMMARP ->createGatePin($1); }
	;

// This list is also hardcoded in VParseLex.l
strength:			// IEEE: strength0+strength1 - plus HIGHZ/SMALL/MEDIUM/LARGE
		ygenSTRENGTH				{ BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); }
	|	ySUPPLY0				{ BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); }
	|	ySUPPLY1				{ BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); }
	;

strengthSpecE:			// IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty
		/* empty */				{ }
	|	strengthSpec				{ }
	;

strengthSpec:			// IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty
		yP_PAR__STRENGTH strength ')'			{ }
	|	yP_PAR__STRENGTH strength ',' strength ')'	{ }
	;

//************************************************
// Tables

combinational_body<nodep>:	// IEEE: combinational_body + sequential_body
		yTABLE tableEntryList yENDTABLE		{ $$ = new AstUdpTable($1,$2); }
	;

tableEntryList<nodep>:	// IEEE: { combinational_entry | sequential_entry }
		tableEntry 				{ $$ = $1; }
	|	tableEntryList tableEntry		{ $$ = $1->addNextNull($2); }
	;

tableEntry<nodep>:	// IEEE: combinational_entry + sequential_entry
		yaTABLELINE				{ $$ = new AstUdpTableLine($<fl>1,*$1); }
	|	error					{ $$ = NULL; }
	;

//************************************************
// Specify

specify_block<nodep>:		// ==IEEE: specify_block
		ySPECIFY specifyJunkList yENDSPECIFY	{ $$ = NULL; }
	|	ySPECIFY yENDSPECIFY			{ $$ = NULL; }
	;

specifyJunkList:
		specifyJunk 				{ } /* ignored */
	|	specifyJunkList specifyJunk		{ } /* ignored */
	;

specifyJunk:
		BISONPRE_NOT(ySPECIFY,yENDSPECIFY)	{ }
	|	ySPECIFY specifyJunk yENDSPECIFY	{ }
	|	error {}
	;

specparam_declaration<nodep>:		// ==IEEE: specparam_declaration
		ySPECPARAM junkToSemiList ';'		{ $$ = NULL; }
	;

junkToSemiList:
		junkToSemi 				{ } /* ignored */
	|	junkToSemiList junkToSemi		{ } /* ignored */
 	;

junkToSemi:
		BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE)	{ }
	|	error {}
	;

//************************************************
// IDs

id<strp>:
		yaID__ETC				{ $$ = $1; $<fl>$=$<fl>1; }
	;

idAny<strp>:			// Any kind of identifier
		yaID__aPACKAGE				{ $$ = $1; $<fl>$=$<fl>1; }
	|	yaID__aTYPE				{ $$ = $1; $<fl>$=$<fl>1; }
	|	yaID__ETC				{ $$ = $1; $<fl>$=$<fl>1; }
	;

idRefDType<refdtypep>:		// IEEE: class_identifier or other type identifier
				// Used where reference is needed
		yaID__aTYPE				{ $$ = new AstRefDType($<fl>1, *$1); }
	;

idSVKwd<strp>:			// Warn about non-forward compatible Verilog 2001 code
	//			// yBIT, yBYTE won't work here as causes conflicts
		yDO					{ static string s = "do"   ; $$ = &s; ERRSVKWD($1,*$$); $<fl>$=$<fl>1; }
	|	yFINAL					{ static string s = "final"; $$ = &s; ERRSVKWD($1,*$$); $<fl>$=$<fl>1; }
	;

variable_lvalue<nodep>:		// IEEE: variable_lvalue or net_lvalue
	//			// Note many variable_lvalue's must use exprOkLvalue when arbitrary expressions may also exist
		idClassSel				{ $$ = $1; }
	|	'{' variable_lvalueConcList '}'		{ $$ = $2; }
	//			// IEEE: [ assignment_pattern_expression_type ] assignment_pattern_variable_lvalue
	//			// We allow more assignment_pattern_expression_types then strictly required
	//UNSUP	data_type  yP_TICKBRA variable_lvalueList '}'	{ UNSUP }
	//UNSUP	idClassSel yP_TICKBRA variable_lvalueList '}'	{ UNSUP }
	//UNSUP	/**/       yP_TICKBRA variable_lvalueList '}'	{ UNSUP }
	|	streaming_concatenation			{ $$ = $1; }
	;

variable_lvalueConcList<nodep>:	// IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}'
		variable_lvalue					{ $$ = $1; }
	|	variable_lvalueConcList ',' variable_lvalue	{ $$ = new AstConcat($2,$1,$3); }
	;

//UNSUPvariable_lvalueList<nodep>:  // IEEE: part of variable_lvalue: variable_lvalue { ',' variable_lvalue }
//UNSUP		variable_lvalue				{ $$ = $1; }
//UNSUP	|	variable_lvalueList ',' variable_lvalue	{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

// VarRef to dotted, and/or arrayed, and/or bit-ranged variable
idClassSel<nodep>:			// Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable
		idDotted				{ $$ = $1; }
	//			// IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
	|	yTHIS '.' idDotted			{ $$ = $3; BBUNSUP($1, "Unsupported: this"); }
	|	ySUPER '.' idDotted			{ $$ = $3; BBUNSUP($1, "Unsupported: super"); }
	|	yTHIS '.' ySUPER '.' idDotted		{ $$ = $5; BBUNSUP($1, "Unsupported: this.super"); }
	//			// Expanded: package_scope idDotted
	|	class_scopeIdFollows idDotted		{ $$ = $2; BBUNSUP($2, "Unsupported: package scoped id"); }
	|	package_scopeIdFollows idDotted		{ $$ = $2; BBUNSUP($2, "Unsupported: class scoped id"); }
	;

idDotted<nodep>:
	//UNSUP	yD_ROOT '.' idDottedMore		{ UNSUP }
		idDottedMore		 		{ $$ = $1; }
	;

idDottedMore<nodep>:
		idArrayed 				{ $$ = $1; }
	|	idDottedMore '.' idArrayed	 	{ $$ = new AstDot($2,$1,$3); }
	;

// Single component of dotted path, maybe [#].
// Due to lookahead constraints, we can't know if [:] or [+:] are valid (last dotted part),
// we'll assume so and cleanup later.
// id below includes:
//	 enum_identifier
idArrayed<nodep>:		// IEEE: id + select
		id						{ $$ = new AstParseRef($<fl>1,VParseRefExp::PX_TEXT,*$1,NULL,NULL); }
	//			// IEEE: id + part_select_range/constant_part_select_range
	|	idArrayed '[' expr ']'				{ $$ = new AstSelBit($2,$1,$3); }  // Or AstArraySel, don't know yet.
	|	idArrayed '[' constExpr ':' constExpr ']'	{ $$ = new AstSelExtract($2,$1,$3,$5); }
	//			// IEEE: id + indexed_range/constant_indexed_range
	|	idArrayed '[' expr yP_PLUSCOLON  constExpr ']'	{ $$ = new AstSelPlus($2,$1,$3,$5); }
	|	idArrayed '[' expr yP_MINUSCOLON constExpr ']'	{ $$ = new AstSelMinus($2,$1,$3,$5); }
	;

idClassForeach<nodep>:
		idForeach				{ $$ = $1; }
	|	package_scopeIdFollows idForeach	{ $$ = AstDot::newIfPkg($2->fileline(), $1, $2); }
	;

idForeach<nodep>:
		varRefBase				{ $$ = $1; }
	|	idForeach '.' varRefBase	 	{ $$ = new AstDot($2,$1,$3); }
	;


// VarRef without any dots or vectorizaion
varRefBase<varrefp>:
		id					{ $$ = new AstVarRef($<fl>1,*$1,false);}
	;

// yaSTRING shouldn't be used directly, instead via an abstraction below
str<strp>:			// yaSTRING but with \{escapes} need decoded
		yaSTRING				{ $$ = PARSEP->newString(GRAMMARP->deQuote($<fl>1,*$1)); }
	;

strAsInt<nodep>:
		yaSTRING				{ $$ = new AstConst($<fl>1, AstConst::VerilogStringLiteral(), GRAMMARP->deQuote($<fl>1, *$1));}
	;

strAsIntIgnore<nodep>:		// strAsInt, but never matches for when expr shouldn't parse strings
		yaSTRING__IGNORE			{ $$ = NULL; yyerror("Impossible token"); }
	;

strAsText<nodep>:
		yaSTRING				{ $$ = GRAMMARP->createTextQuoted($<fl>1,*$1);}
	;

endLabelE<strp>:
		/* empty */				{ $$ = NULL; $<fl>$=NULL; }
	|	':' idAny				{ $$ = $2; $<fl>$=$<fl>2; }
	|	':' yNEW__ETC				{ static string n = "new"; $$ = &n; $<fl>$=$<fl>2; }
	;

//************************************************
// Clocking

clocking_declaration<nodep>:		// IEEE: clocking_declaration  (INCOMPLETE)
	//UNSUP: vvv remove this -- vastly simplified grammar:
		yDEFAULT yCLOCKING '@' '(' senitemEdge ')' ';' yENDCLOCKING
			{ $$ = new AstClocking($2, $5, NULL); }
	//UNSUP: ^^^ remove this -- vastly simplified grammar:
	//UNSUP	clockingFront clocking_event ';'
	//UNSUP	 clocking_itemListE yENDCLOCKING endLabelE { SYMP->popScope($$); }
	;

//UNSUPclockingFront:  // IEEE: part of class_declaration
//UNSUP		yCLOCKING				{ PARSEP->symPushNewAnon(VAstType::CLOCKING); }
//UNSUP	|	yCLOCKING idAny/*clocking_identifier*/	{ SYMP->pushNew($$); }
//UNSUP	|	yDEFAULT yCLOCKING			{ PARSEP->symPushNewAnon(VAstType::CLOCKING); }
//UNSUP	|	yDEFAULT yCLOCKING idAny/*clocking_identifier*/	{ SYMP->pushNew($$); }
//UNSUP	|	yGLOBAL__CLOCKING yCLOCKING			{ PARSEP->symPushNewAnon(VAstType::CLOCKING); }
//UNSUP	|	yGLOBAL__CLOCKING yCLOCKING idAny/*clocking_identifier*/	{ SYMP->pushNew($$); }
//UNSUP	;

//UNSUPclocking_event:  // ==IEEE: clocking_event
//UNSUP		'@' id					{ }
//UNSUP	|	'@' '(' event_expression ')'		{ }
//UNSUP	;

//UNSUPclocking_itemListE:
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	clocking_itemList			{ $$ = $1; }
//UNSUP	;

//UNSUPclocking_itemList:  // IEEE: [ clocking_item ]
//UNSUP		clocking_item				{ $$ = $1; }
//UNSUP	|	clocking_itemList clocking_item		{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPclocking_item:  // ==IEEE: clocking_item
//UNSUP		yDEFAULT default_skew ';'		{ }
//UNSUP	|	clocking_direction list_of_clocking_decl_assign ';'	{ }
//UNSUP	|	assertion_item_declaration		{ }
//UNSUP	;

//UNSUPdefault_skew:  // ==IEEE: default_skew
//UNSUP		yINPUT clocking_skew			{ }
//UNSUP	|	yOUTPUT clocking_skew			{ }
//UNSUP	|	yINPUT clocking_skew yOUTPUT clocking_skew	{ }
//UNSUP	;

//UNSUPclocking_direction:  // ==IEEE: clocking_direction
//UNSUP		yINPUT clocking_skewE			{ }
//UNSUP	|	yOUTPUT clocking_skewE			{ }
//UNSUP	|	yINPUT clocking_skewE yOUTPUT clocking_skewE	{ }
//UNSUP	|	yINOUT					{ }
//UNSUP	;

//UNSUPlist_of_clocking_decl_assign:  // ==IEEE: list_of_clocking_decl_assign
//UNSUP		clocking_decl_assign			{ $$ = $1; }
//UNSUP	|	list_of_clocking_decl_assign ',' clocking_decl_assign	{ }
//UNSUP	;

//UNSUPclocking_decl_assign:  // ==IEEE: clocking_decl_assign
//UNSUP		idAny/*new-signal_identifier*/		{ $$ = $1; }
//UNSUP	|	idAny/*new-signal_identifier*/ '=' expr	{ }
//UNSUP	;

//UNSUPclocking_skewE:  // IEEE: [clocking_skew]
//UNSUP		/* empty */				{ $$ = NULL;}
//UNSUP	|	clocking_skew				{ $$ = $1; }
//UNSUP	;

//UNSUPclocking_skew:  // ==IEEE: clocking_skew
//UNSUP		yPOSEDGE				{ }
//UNSUP	|	yPOSEDGE delay_control			{ }
//UNSUP	|	yNEGEDGE				{ }
//UNSUP	|	yNEGEDGE delay_control			{ }
//UNSUP	|	yEDGE					{ NEED_S09($<fl>1,"edge"); }
//UNSUP	|	yEDGE delay_control			{ NEED_S09($<fl>1,"edge"); }
//UNSUP	|	delay_control				{ $$ = $1; }
//UNSUP	;

//UNSUPcycle_delay:  // ==IEEE: cycle_delay
//UNSUP		yP_POUNDPOUND yaINTNUM			{ }
//UNSUP	|	yP_POUNDPOUND id			{ }
//UNSUP	|	yP_POUNDPOUND '(' expr ')'		{ }
//UNSUP	;

//************************************************
// Asserts

//UNSUPassertion_item_declaration:  // ==IEEE: assertion_item_declaration
//UNSUP		property_declaration			{ $$ = $1; }
//UNSUP	|	sequence_declaration			{ $$ = $1; }
//UNSUP	|	let_declaration				{ $$ = $1; }
//UNSUP	;

assertion_item<nodep>:		// ==IEEE: assertion_item
		concurrent_assertion_item		{ $$ = $1; }
	|	deferred_immediate_assertion_item
			{ $$ = $1 ? new AstAlways($1->fileline(), VAlwaysKwd::ALWAYS_COMB, NULL, $1) : NULL; }
	;

deferred_immediate_assertion_item<nodep>:	// ==IEEE: deferred_immediate_assertion_item
		deferred_immediate_assertion_statement	{ $$ = $1; }
	|	id/*block_identifier*/ ':' deferred_immediate_assertion_statement
			{ $$ = new AstBegin($<fl>1, *$1, $3); }
	;

procedural_assertion_statement<nodep>:	// ==IEEE: procedural_assertion_statement
		concurrent_assertion_statement		{ $$ = $1; }
	|	immediate_assertion_statement		{ $$ = $1; }
	//			// IEEE: checker_instantiation
	//			// Unlike modules, checkers are the only "id id (...)" form in statements.
	//UNSUP	checker_instantiation			{ $$ = $1; }
	;

immediate_assertion_statement<nodep>:	// ==IEEE: immediate_assertion_statement
		simple_immediate_assertion_statement	{ $$ = $1; }
	|	deferred_immediate_assertion_statement	{ $$ = $1; }
	;

simple_immediate_assertion_statement<nodep>:	// ==IEEE: simple_immediate_assertion_statement
	//				// action_block expanded here, for compatibility with AstAssert
		yASSERT '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE	{ $$ = new AstAssert($1, $3, $5, NULL, true); }
	|	yASSERT '(' expr ')'           yELSE stmtBlock		{ $$ = new AstAssert($1, $3, NULL, $6, true); }
	|	yASSERT '(' expr ')' stmtBlock yELSE stmtBlock		{ $$ = new AstAssert($1, $3, $5, $7, true); }
	//				// action_block expanded here, for compatibility with AstAssert
	|	yASSUME '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE	{ $$ = new AstAssert($1, $3, $5, NULL, true); }
	|	yASSUME '(' expr ')'           yELSE stmtBlock		{ $$ = new AstAssert($1, $3, NULL, $6, true); }
	|	yASSUME '(' expr ')' stmtBlock yELSE stmtBlock		{ $$ = new AstAssert($1, $3, $5, $7, true);   }
	//			// IEEE: simple_immediate_cover_statement
	|	yCOVER '(' expr ')' stmt 		{ $$ = new AstCover($1, $3, $5, true); }
	;

final_zero:			// IEEE: part of deferred_immediate_assertion_statement
		'#' yaINTNUM
			{ if ($2->isNeqZero()) { $<fl>2->v3error("Deferred assertions must use '#0' (IEEE 2017 16.4)"); } }
	//			// 1800-2012:
	|	yFINAL							{ }
	;

deferred_immediate_assertion_statement<nodep>:	// ==IEEE: deferred_immediate_assertion_statement
	//			// IEEE: deferred_immediate_assert_statement
		yASSERT final_zero '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE	{ $$ = new AstAssert($1, $4, $6, NULL, true); }
	|	yASSERT final_zero '(' expr ')'           yELSE stmtBlock		{ $$ = new AstAssert($1, $4, NULL, $7, true); }
	|	yASSERT final_zero '(' expr ')' stmtBlock yELSE stmtBlock		{ $$ = new AstAssert($1, $4, $6, $8, true);   }
	//			// IEEE: deferred_immediate_assume_statement
	|	yASSUME final_zero '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE	{ $$ = new AstAssert($1, $4, $6, NULL, true); }
	|	yASSUME final_zero '(' expr ')'           yELSE stmtBlock		{ $$ = new AstAssert($1, $4, NULL, $7, true); }
	|	yASSUME final_zero '(' expr ')' stmtBlock yELSE stmtBlock		{ $$ = new AstAssert($1, $4, $6, $8, true); }
	//			// IEEE: deferred_immediate_cover_statement
	|	yCOVER final_zero '(' expr ')' stmt	{ $$ = new AstCover($1, $4, $6, true); }
	;

//UNSUPexpect_property_statement<nodep>:  // ==IEEE: expect_property_statement
//UNSUP		yEXPECT '(' property_spec ')' action_block	{ }
//UNSUP	;

concurrent_assertion_item<nodep>:	// IEEE: concurrent_assertion_item
		concurrent_assertion_statement		{ $$ = $1; }
	|	id/*block_identifier*/ ':' concurrent_assertion_statement	{ $$ = new AstBegin($<fl>1, *$1, $3); }
	//			// IEEE: checker_instantiation
	//			// identical to module_instantiation; see etcInst
	;

concurrent_assertion_statement<nodep>:	// ==IEEE: concurrent_assertion_statement
	//			// IEEE: assert_property_statement
	//UNSUP remove below:
		yASSERT yPROPERTY '(' property_spec ')' elseStmtBlock	{ $$ = new AstAssert($1, $4, NULL, $6, false); }
	//UNSUP	yASSERT yPROPERTY '(' property_spec ')' action_block	{ }
	//			// IEEE: assume_property_statement
	//UNSUP	yASSUME yPROPERTY '(' property_spec ')' action_block	{ }
	//			// IEEE: cover_property_statement
	|	yCOVER yPROPERTY '(' property_spec ')' stmtBlock	{ $$ = new AstCover($1, $4, $6, false); }
	//			// IEEE: cover_sequence_statement
	//UNSUP	yCOVER ySEQUENCE '(' sexpr ')' stmt			{ }
	//			// IEEE: yCOVER ySEQUENCE '(' clocking_event sexpr ')' stmt
	//			// sexpr already includes "clocking_event sexpr"
	//UNSUP	yCOVER ySEQUENCE '(' clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt	{ }
	//UNSUP	yCOVER ySEQUENCE '(' yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt	{ }
	//			// IEEE: restrict_property_statement
	|	yRESTRICT yPROPERTY '(' property_spec ')' ';'		{ $$ = new AstRestrict($1, $4); }
	;

elseStmtBlock<nodep>:	// Part of concurrent_assertion_statement
		';'					{ $$ = NULL; }
	|	yELSE stmtBlock				{ $$ = $2; }
	;

//UNSUPproperty_declaration<nodep>:  // ==IEEE: property_declaration
//UNSUP		property_declarationFront property_port_listE ';' property_declarationBody
//UNSUP			yENDPROPERTY endLabelE
//UNSUP			{ SYMP->popScope($$); }
//UNSUP	;

//UNSUPproperty_declarationFront<nodep>:  // IEEE: part of property_declaration
//UNSUP		yPROPERTY idAny/*property_identifier*/
//UNSUP			{ SYMP->pushNew($$); }
//UNSUP	;

//UNSUPproperty_port_listE<nodep>:  // IEEE: [ ( [ property_port_list ] ) ]
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	'(' {VARRESET_LIST(""); VARIO("input"); } property_port_list ')'
//UNSUP			{ VARRESET_NONLIST(""); }
//UNSUP	;

//UNSUPproperty_port_list<nodep>:  // ==IEEE: property_port_list
//UNSUP		property_port_item			{ $$ = $1; }
//UNSUP	|	property_port_list ',' property_port_item	{ }
//UNSUP	;

//UNSUPproperty_port_item<nodep>:  // IEEE: property_port_item/sequence_port_item
//UNSUP	//			// Merged in sequence_port_item
//UNSUP	//			// IEEE: property_lvar_port_direction ::= yINPUT
//UNSUP	//			// prop IEEE: [ yLOCAL [ yINPUT ] ] property_formal_type
//UNSUP	//			//	     id {variable_dimension} [ '=' property_actual_arg ]
//UNSUP	//			// seq IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type
//UNSUP	//			//           id {variable_dimension} [ '=' sequence_actual_arg ]
//UNSUP		property_port_itemFront property_port_itemAssignment { }
//UNSUP	;

//UNSUPproperty_port_itemFront:	// IEEE: part of property_port_item/sequence_port_item
//UNSUP		property_port_itemDirE property_formal_typeNoDt		{ VARDTYPE($2); }
//UNSUP	//			// data_type_or_implicit
//UNSUP	|	property_port_itemDirE data_type           	{ VARDTYPE($2); }
//UNSUP	|	property_port_itemDirE yVAR data_type      	{ VARDTYPE($3); }
//UNSUP	|	property_port_itemDirE yVAR implicit_typeE 	{ VARDTYPE($3); }
//UNSUP	|	property_port_itemDirE signingE rangeList  	{ VARDTYPE(SPACED($2,$3)); }
//UNSUP	|	property_port_itemDirE /*implicit*/        	{ /*VARDTYPE-same*/ }
//UNSUP	;

//UNSUPproperty_port_itemAssignment<nodep>:  // IEEE: part of property_port_item/sequence_port_item/checker_port_direction
//UNSUP		portSig variable_dimensionListE		{ VARDONE($<fl>1, $1, $2, ""); PINNUMINC(); }
//UNSUP	|	portSig variable_dimensionListE '=' property_actual_arg
//UNSUP			{ VARDONE($<fl>1, $1, $2, $4); PINNUMINC(); }
//UNSUP	;

//UNSUPproperty_port_itemDirE:
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	yLOCAL__ETC				{ }
//UNSUP	|	yLOCAL__ETC port_direction		{ }
//UNSUP	;

//UNSUPproperty_declarationBody<nodep>:  // IEEE: part of property_declaration
//UNSUP		assertion_variable_declarationList property_statement_spec	{ }
//UNSUP	//			// IEEE-2012: Incorectly hasyCOVER ySEQUENCE then property_spec here.
//UNSUP	//			// Fixed in IEEE 1800-2017
//UNSUP	|	property_statement_spec			{ $$ = $1; }
//UNSUP	;

//UNSUPassertion_variable_declarationList: // IEEE: part of assertion_variable_declaration
//UNSUP		assertion_variable_declaration		{ $$ = $1; }
//UNSUP	|	assertion_variable_declarationList assertion_variable_declaration	{ }
//UNSUP	;

//UNSUPsequence_declaration<nodep>:  // ==IEEE: sequence_declaration
//UNSUP		sequence_declarationFront sequence_port_listE ';' sequence_declarationBody
//UNSUP			yENDSEQUENCE endLabelE
//UNSUP			{ SYMP->popScope($$); }
//UNSUP	;

//UNSUPsequence_declarationFront<nodep>:  // IEEE: part of sequence_declaration
//UNSUP		ySEQUENCE idAny/*new_sequence*/
//UNSUP			{ SYMP->pushNew($$); }
//UNSUP	;

//UNSUPsequence_port_listE<nodep>:  // IEEE: [ ( [ sequence_port_list ] ) ]
//UNSUP	//			// IEEE: sequence_lvar_port_direction ::= yINPUT | yINOUT | yOUTPUT
//UNSUP	//			// IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type
//UNSUP	//			//           id {variable_dimension} [ '=' sequence_actual_arg ]
//UNSUP	//			// All this is almost identically the same as a property.
//UNSUP	//			// Difference is only yINOUT/yOUTPUT (which might be added to 1800-2012)
//UNSUP	//			// and yPROPERTY.  So save some work.
//UNSUP		property_port_listE			{ $$ = $1; }
//UNSUP	;

//UNSUPproperty_formal_typeNoDt<nodep>:  // IEEE: property_formal_type (w/o implicit)
//UNSUP		sequence_formal_typeNoDt		{ $$ = $1; }
//UNSUP	|	yPROPERTY				{ }
//UNSUP	;

//UNSUPsequence_formal_typeNoDt<nodep>:  // ==IEEE: sequence_formal_type (w/o data_type_or_implicit)
//UNSUP	//			// IEEE: data_type_or_implicit
//UNSUP	//			// implicit expanded where used
//UNSUP		ySEQUENCE				{ }
//UNSUP	//			// IEEE-2009: yEVENT
//UNSUP	//			// already part of data_type.  Removed in 1800-2012.
//UNSUP	|	yUNTYPED				{ }
//UNSUP	;

//UNSUPsequence_declarationBody<nodep>:  // IEEE: part of sequence_declaration
//UNSUP	//			// 1800-2012 makes ';' optional
//UNSUP		assertion_variable_declarationList sexpr	{ }
//UNSUP	|	assertion_variable_declarationList sexpr ';'	{ }
//UNSUP	|	sexpr					{ $$ = $1; }
//UNSUP	|	sexpr ';'				{ $$ = $1; }
//UNSUP	;

property_spec<nodep>:			// IEEE: property_spec
	//UNSUP: This rule has been super-specialized to what is supported now
	//UNSUP remove below
		'@' '(' senitemEdge ')' yDISABLE yIFF '(' expr ')' pexpr
			{ $$ = new AstPropClocked($1, $3, $8, $10); }
	|	'@' '(' senitemEdge ')' pexpr	 	{ $$ = new AstPropClocked($1, $3, NULL, $5); }
	//UNSUP remove above
	|	yDISABLE yIFF '(' expr ')' pexpr 	{ $$ = new AstPropClocked($4->fileline(), NULL, $4, $6); }
	|	pexpr	 				{ $$ = new AstPropClocked($1->fileline(), NULL, NULL, $1); }
	;

//UNSUPproperty_statement_spec<nodep>:  // ==IEEE: property_statement_spec
//UNSUP	//			// IEEE: [ clocking_event ] [ yDISABLE yIFF '(' expression_or_dist ')' ] property_statement
//UNSUP		property_statement			{ $$ = $1; }
//UNSUP	|	yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statement	{ }
//UNSUP	//			// IEEE: clocking_event property_statement
//UNSUP	//			// IEEE: clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statement
//UNSUP	//			// Both overlap pexpr:"clocking_event pexpr"  the difference is
//UNSUP	//			// property_statement:property_statementCaseIf so replicate it
//UNSUP	|	clocking_event property_statementCaseIf	{ }
//UNSUP	|	clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statementCaseIf	{ }
//UNSUP	;

//UNSUPproperty_statement<nodep>:  // ==IEEE: property_statement
//UNSUP	//			// Doesn't make sense to have "pexpr ;" in pexpr rule itself, so we split out case/if
//UNSUP		pexpr ';'				{ $$ = $1; }
//UNSUP	//			// Note this term replicated in property_statement_spec
//UNSUP	//			// If committee adds terms, they may need to be there too.
//UNSUP	|	property_statementCaseIf		{ $$ = $1; }
//UNSUP	;

//UNSUPproperty_statementCaseIf<nodep>:  // IEEE: property_statement - minus pexpr
//UNSUP		yCASE '(' expr/*expression_or_dist*/ ')' property_case_itemList yENDCASE	{ }
//UNSUP	|	yCASE '(' expr/*expression_or_dist*/ ')' yENDCASE		{ }
//UNSUP	|	yIF '(' expr/*expression_or_dist*/ ')' pexpr  %prec prLOWER_THAN_ELSE	{ }
//UNSUP	|	yIF '(' expr/*expression_or_dist*/ ')' pexpr yELSE pexpr	{ }
//UNSUP	;

//UNSUPproperty_case_itemList<nodep>:  // IEEE: {property_case_item}
//UNSUP		property_case_item			{ $$ = $1; }
//UNSUP	|	property_case_itemList ',' property_case_item	{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

//UNSUPproperty_case_item<nodep>:  // ==IEEE: property_case_item
//UNSUP	//			// IEEE: expression_or_dist { ',' expression_or_dist } ':' property_statement
//UNSUP	//			// IEEE 1800-2012 changed from property_statement to property_expr
//UNSUP	//			// IEEE 1800-2017 changed to require the semicolon
//UNSUP		caseCondList ':' pexpr			{ }
//UNSUP	|	caseCondList ':' pexpr ';'		{ }
//UNSUP	|	yDEFAULT pexpr				{ }
//UNSUP	|	yDEFAULT ':' pexpr ';'			{ }
//UNSUP	;

//UNSUPpev_expr<nodep>:  // IEEE: property_actual_arg | expr
//UNSUP	//			//       which expands to pexpr | event_expression
//UNSUP	//			// Used in port and function calls, when we can't know yet if something
//UNSUP	//			// is a function/sequence/property or instance/checker pin.
//UNSUP	//
//UNSUP	//			// '(' pev_expr ')'
//UNSUP	//			// Already in pexpr
//UNSUP	//			// IEEE: event_expression ',' event_expression
//UNSUP	//			// ','s are legal in event_expressions, but parens required to avoid conflict with port-sep-,
//UNSUP	//			// IEEE: event_expression yOR event_expression
//UNSUP	//			// Already in pexpr - needs removal there
//UNSUP	//			// IEEE: event_expression yIFF expr
//UNSUP	//			// Already in pexpr - needs removal there
//UNSUP	//
//UNSUP		senitemEdge				{ $$ = $1; }
//UNSUP	//
//UNSUP	//============= pexpr rules copied for pev_expr
//UNSUP	|	BISONPRE_COPY_ONCE(pexpr,{s/~o~p/pev_/g; })	// {copied}
//UNSUP	//
//UNSUP	//============= sexpr rules copied for pev_expr
//UNSUP	|	BISONPRE_COPY_ONCE(sexpr,{s/~p~s/pev_/g; })	// {copied}
//UNSUP	//
//UNSUP	//============= expr rules copied for pev_expr
//UNSUP	|	BISONPRE_COPY_ONCE(expr,{s/~l~/pev_/g; s/~p~/pev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; })	// {copied}
//UNSUP	;

pexpr<nodep>:  // IEEE: property_expr  (The name pexpr is important as regexps just add an "p" to expr.)
	//UNSUP: This rule has been super-specialized to what is supported now
	//UNSUP remove below
		expr yP_ORMINUSGT pexpr			{ $$ = new AstLogOr($2, new AstLogNot($2, $1), $3); }
	//UNSUP	expr yP_OREQGT pexpr			{ $$ = new AstLogOr($2, new AstLogNot($2, new AstPast($2, $1, NULL)), $3); } // This handles disable iff in the past time step incorrectly
	|	expr					{ $$ = $1; }
	//UNSUP remove above, use below:
	//
	//			// IEEE: sequence_expr
	//			// Expanded below
	//
	//			// IEEE: '(' pexpr ')'
	//			// Expanded below
	//
	//UNSUP	yNOT pexpr %prec prNEGATION		{ }
	//UNSUP	ySTRONG '(' sexpr ')'			{ }
	//UNSUP	yWEAK '(' sexpr ')'			{ }
	//			// IEEE: pexpr yOR pexpr
	//			// IEEE: pexpr yAND pexpr
	//			// Under ~p~sexpr and/or ~p~sexpr
	//
	//			// IEEE: "sequence_expr yP_ORMINUSGT pexpr"
	//			// Instead we use pexpr to prevent conflicts
	//UNSUP	~o~pexpr yP_ORMINUSGT pexpr		{ }
	//UNSUP	~o~pexpr yP_OREQGT pexpr		{ }
	//
	//			// IEEE-2009: property_statement
	//			// IEEE-2012: yIF and yCASE
	//UNSUP	property_statementCaseIf		{ }
	//
	//UNSUP	~o~pexpr/*sexpr*/ yP_POUNDMINUSPD pexpr	{ }
	//UNSUP	~o~pexpr/*sexpr*/ yP_POUNDEQPD pexpr	{ }
	//UNSUP	yNEXTTIME pexpr				{ }
	//UNSUP	yS_NEXTTIME pexpr			{ }
	//UNSUP	yNEXTTIME '[' expr/*const*/ ']' pexpr %prec yNEXTTIME		{ }
	//UNSUP	yS_NEXTTIME '[' expr/*const*/ ']' pexpr	%prec yS_NEXTTIME	{ }
	//UNSUP	yALWAYS pexpr				{ }
	//UNSUP	yALWAYS '[' cycle_delay_const_range_expression ']' pexpr  %prec yALWAYS	{ }
	//UNSUP	yS_ALWAYS '[' constant_range ']' pexpr  %prec yS_ALWAYS		{ }
	//UNSUP	yS_EVENTUALLY pexpr			{ }
	//UNSUP	yEVENTUALLY '[' constant_range ']' pexpr  %prec yEVENTUALLY	{ }
	//UNSUP	yS_EVENTUALLY '[' cycle_delay_const_range_expression ']' pexpr  %prec yS_EVENTUALLY	{ }
	//UNSUP	~o~pexpr yUNTIL pexpr			{ }
	//UNSUP	~o~pexpr yS_UNTIL pexpr			{ }
	//UNSUP	~o~pexpr yUNTIL_WITH pexpr		{ }
	//UNSUP	~o~pexpr yS_UNTIL_WITH pexpr		{ }
	//UNSUP	~o~pexpr yIMPLIES pexpr			{ }
	//			// yIFF also used by event_expression
	//UNSUP	~o~pexpr yIFF ~o~pexpr			{ }
	//UNSUP	yACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr  %prec yACCEPT_ON	{ }
	//UNSUP	yREJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr  %prec yREJECT_ON	{ }
	//UNSUP	ySYNC_ACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_ACCEPT_ON	{ }
	//UNSUP	ySYNC_REJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_REJECT_ON	{ }
	//
	//			// IEEE: "property_instance"
	//			// Looks just like a function/method call
	//
	//			// Note "clocking_event pexpr" overlaps property_statement_spec: clocking_event property_statement
	//
	//			// Include property_specDisable to match property_spec rule
	//UNSUP	clocking_event yDISABLE yIFF '(' expr ')' pexpr	%prec prSEQ_CLOCKING	{ }
	//
	//============= sexpr rules copied for property_expr
	//UNSUP	BISONPRE_COPY_ONCE(sexpr,{s/~p~s/p/g; })	// {copied}
	//
	//============= expr rules copied for property_expr
	//UNSUP	BISONPRE_COPY_ONCE(expr,{s/~l~/p/g; s/~p~/p/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; })	// {copied}
	;

//UNSUPsexpr<nodep>:  // ==IEEE: sequence_expr  (The name sexpr is important as regexps just add an "s" to expr.)
//UNSUP	//			// ********* RULES COPIED IN sequence_exprProp
//UNSUP	//			// For precedence, see IEEE 17.7.1
//UNSUP	//
//UNSUP	// 			// IEEE: "cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }"
//UNSUP	//			// IEEE: "sequence_expr cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }"
//UNSUP	//			// Both rules basically mean we can repeat sequences, so make it simpler:
//UNSUP		cycle_delay_range sexpr	 %prec yP_POUNDPOUND	{ }
//UNSUP	|	~p~sexpr cycle_delay_range sexpr %prec prPOUNDPOUND_MULTI	{ }
//UNSUP	//
//UNSUP	//			// IEEE: expression_or_dist [ boolean_abbrev ]
//UNSUP	//			// Note expression_or_dist includes "expr"!
//UNSUP	//			// sexpr/*sexpression_or_dist*/	 --- Hardcoded below
//UNSUP	|	~p~sexpr/*sexpression_or_dist*/ boolean_abbrev	{ }
//UNSUP	//
//UNSUP	//			// IEEE: "sequence_instance [ sequence_abbrev ]"
//UNSUP	//			// version without sequence_abbrev looks just like normal function call
//UNSUP	//			// version w/sequence_abbrev matches above; expression_or_dist:expr:func boolean_abbrev:sequence_abbrev
//UNSUP	//
//UNSUP	//			// IEEE: '(' expression_or_dist {',' sequence_match_item } ')' [ boolean_abbrev ]
//UNSUP	//			// IEEE: '(' sexpr {',' sequence_match_item } ')' [ sequence_abbrev ]
//UNSUP	//			// As sequence_expr includes expression_or_dist, and boolean_abbrev includes sequence_abbrev:
//UNSUP	//			// '(' sequence_expr {',' sequence_match_item } ')' [ boolean_abbrev ]
//UNSUP	//			// "'(' sexpr ')' boolean_abbrev" matches "[sexpr:'(' expr ')'] boolean_abbrev" so we can simply drop it
//UNSUP	|	'(' ~p~sexpr ')'			{ $<fl>$=$<fl>1; $$=$1+$2+$3; }
//UNSUP	|	'(' ~p~sexpr ',' sequence_match_itemList ')'	{ }
//UNSUP	//
//UNSUP	//			// AND/OR are between pexprs OR sexprs
//UNSUP	|	~p~sexpr yAND ~p~sexpr			{ $<fl>$=$<fl>1; $$=$1+$2+$3; }
//UNSUP	|	~p~sexpr yOR ~p~sexpr			{ $<fl>$=$<fl>1; $$=$1+$2+$3; }
//UNSUP	//			// Intersect always has an sexpr rhs
//UNSUP	|	~p~sexpr yINTERSECT sexpr		{ $<fl>$=$<fl>1; $$=$1+$2+$3; }
//UNSUP	//
//UNSUP	|	yFIRST_MATCH '(' sexpr ')'		{ }
//UNSUP	|	yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')'	{ }
//UNSUP	|	~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr		{ }
//UNSUP	//			// Below pexpr's are really sequence_expr, but avoid conflict
//UNSUP	//			// IEEE: sexpr yWITHIN sexpr
//UNSUP	|	~p~sexpr yWITHIN sexpr			{ $<fl>$=$<fl>1; $$=$1+$2+$3; }
//UNSUP	//			// Note concurrent_assertion had duplicate rule for below
//UNSUP	|	clocking_event ~p~sexpr %prec prSEQ_CLOCKING	{ }
//UNSUP	//
//UNSUP	//============= expr rules copied for sequence_expr
//UNSUP	|	BISONPRE_COPY_ONCE(expr,{s/~l~/s/g; s/~p~/s/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; })	// {copied}
//UNSUP	;

//UNSUPcycle_delay_range<nodep>:  // IEEE: ==cycle_delay_range
//UNSUP	//			// These three terms in 1800-2005 ONLY
//UNSUP		yP_POUNDPOUND yaINTNUM			{ }
//UNSUP	|	yP_POUNDPOUND id			{ }
//UNSUP	|	yP_POUNDPOUND '(' constExpr ')'		{ }
//UNSUP	//			// In 1800-2009 ONLY:
//UNSUP	//			// IEEE: yP_POUNDPOUND constant_primary
//UNSUP	//			// UNSUP: This causes a big grammer ambiguity
//UNSUP	//			// as ()'s mismatch between primary and the following statement
//UNSUP	//			// the sv-ac committee has been asked to clarify  (Mantis 1901)
//UNSUP	|	yP_POUNDPOUND '[' cycle_delay_const_range_expression ']'	{ }
//UNSUP	|	yP_POUNDPOUND yP_BRASTAR ']'		{ }
//UNSUP	|	yP_POUNDPOUND yP_BRAPLUSKET		{ }
//UNSUP	;

//UNSUPsequence_match_itemList<nodep>:  // IEEE: [sequence_match_item] part of sequence_expr
//UNSUP		sequence_match_item			{ $$ = $1; }
//UNSUP	|	sequence_match_itemList ',' sequence_match_item	{ }
//UNSUP	;

//UNSUPsequence_match_item<nodep>:  // ==IEEE: sequence_match_item
//UNSUP	//			// IEEE says: operator_assignment
//UNSUP	//			// IEEE says: inc_or_dec_expression
//UNSUP	//			// IEEE says: subroutine_call
//UNSUP	//			// This is the same list as...
//UNSUP		for_step_assignment			{ $$ = $1; }
//UNSUP	;

//UNSUPboolean_abbrev<nodep>:  // ==IEEE: boolean_abbrev
//UNSUP	//			// IEEE: consecutive_repetition
//UNSUP		yP_BRASTAR const_or_range_expression ']'	{ }
//UNSUP	|	yP_BRASTAR ']'				{ }
//UNSUP	|	yP_BRAPLUSKET				{ $$ = $1; }
//UNSUP	//			// IEEE: non_consecutive_repetition
//UNSUP	|	yP_BRAEQ const_or_range_expression ']'		{ }
//UNSUP	//			// IEEE: goto_repetition
//UNSUP	|	yP_BRAMINUSGT const_or_range_expression ']'	{ }
//UNSUP	;

//UNSUPconst_or_range_expression<nodep>:  // ==IEEE: const_or_range_expression
//UNSUP		constExpr				{ $$ = $1; }
//UNSUP	|	cycle_delay_const_range_expression	{ }
//UNSUP	;

//UNSUPconstant_range<nodep>:  // ==IEEE: constant_range
//UNSUP		constExpr ':' constExpr			{ }
//UNSUP	;

//UNSUPcycle_delay_const_range_expression<nodep>:  // ==IEEE: cycle_delay_const_range_expression
//UNSUP	//				// Note '$' is part of constExpr
//UNSUP		constExpr ':' constExpr			{ }
//UNSUP	;

//************************************************
// Let

//************************************************
// Covergroup

//UNSUPcovergroup_declaration<nodep>:  // ==IEEE: covergroup_declaration
//UNSUP		covergroup_declarationFront coverage_eventE ';' coverage_spec_or_optionListE
//UNSUP			yENDGROUP endLabelE
//UNSUP			{ PARSEP->endgroupCb($<fl>5,$5);
//UNSUP			  SYMP->popScope($$); }
//UNSUP	|	covergroup_declarationFront '(' tf_port_listE ')' coverage_eventE ';' coverage_spec_or_optionListE
//UNSUP			yENDGROUP endLabelE
//UNSUP			{ PARSEP->endgroupCb($<fl>8,$8);
//UNSUP			  SYMP->popScope($$); }
//UNSUP	;

//UNSUPcovergroup_declarationFront:  // IEEE: part of covergroup_declaration
//UNSUP		yCOVERGROUP idAny
//UNSUP 			{ SYMP->pushNew($$);
//UNSUP			  PARSEP->covergroupCb($<fl>1,$1,$2); }
//UNSUP	;

//UNSUPcgexpr<nodep>:  // IEEE-2012: covergroup_expression, before that just expression
//UNSUP		expr					{ $$ = $1; }
//UNSUP	;

//UNSUPcoverage_spec_or_optionListE<nodep>:  // IEEE: [{coverage_spec_or_option}]
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	coverage_spec_or_optionList		{ $$ = $1; }
//UNSUP	;

//UNSUPcoverage_spec_or_optionList<nodep>:  // IEEE: {coverage_spec_or_option}
//UNSUP		coverage_spec_or_option			{ $$ = $1; }
//UNSUP	|	coverage_spec_or_optionList coverage_spec_or_option	{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPcoverage_spec_or_option<nodep>:  // ==IEEE: coverage_spec_or_option
//UNSUP	//			// IEEE: coverage_spec
//UNSUP		cover_point				{ $$ = $1; }
//UNSUP	|	cover_cross				{ $$ = $1; }
//UNSUP	|	coverage_option ';'			{ $$ = $1; }
//UNSUP	|	error					{ $$ = NULL; }
//UNSUP	;

//UNSUPcoverage_option:  // ==IEEE: coverage_option
//UNSUP	//			// option/type_option aren't really keywords
//UNSUP		id/*yOPTION | yTYPE_OPTION*/ '.' idAny/*member_identifier*/ '=' expr	{ }
//UNSUP	;

//UNSUPcover_point:  // ==IEEE: cover_point
//UNSUP		/**/               yCOVERPOINT expr iffE bins_or_empty	{ }
//UNSUP	//			// IEEE-2012: class_scope before an ID
//UNSUP	|	/**/           /**/ /**/    id ':' yCOVERPOINT expr iffE bins_or_empty	{ }
//UNSUP	|	class_scope_id ':' yCOVERPOINT expr iffE bins_or_empty	{ }
//UNSUP	|	class_scope_id id data_type id ':' yCOVERPOINT expr iffE bins_or_empty	{ }
//UNSUP	|	class_scope_id id /**/      id ':' yCOVERPOINT expr iffE bins_or_empty	{ }
//UNSUP	|	/**/           id /**/      id ':' yCOVERPOINT expr iffE bins_or_empty	{ }
//UNSUP	//			// IEEE-2012:
//UNSUP	|	bins_or_empty				{ $$ = $1; }
//UNSUP	;

//UNSUPiffE<nodep>:  // IEEE: part of cover_point, others
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	yIFF '(' expr ')'			{ }
//UNSUP	;

//UNSUPbins_or_empty<nodep>:  // ==IEEE: bins_or_empty
//UNSUP		'{' bins_or_optionsList '}'		{ $$ = $2; }
//UNSUP	|	'{' '}'					{ $$ = NULL; }
//UNSUP	|	';'					{ $$ = NULL; }
//UNSUP	;

//UNSUPbins_or_optionsList<nodep>:  // IEEE: { bins_or_options ';' }
//UNSUP		bins_or_options ';'			{ $$ = $1; }
//UNSUP	|	bins_or_optionsList bins_or_options ';'	{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPbins_or_options<nodep>:  // ==IEEE: bins_or_options
//UNSUP	//			// Superset of IEEE - we allow []'s in more places
//UNSUP		coverage_option				{ $$ = $1; }
//UNSUP	//			// Can't use wildcardE as results in conflicts
//UNSUP	|	/**/      bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE	{ }
//UNSUP	|	yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE	{ }
//UNSUP	|	/**/      bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE	{ }
//UNSUP	|	yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE	{ }
//UNSUP	//
//UNSUP	//			// cgexpr part of trans_list
//UNSUP	//
//UNSUP	|	/**/      bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE	{ }
//UNSUP	|	yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE	{ }
//UNSUP	//
//UNSUP	|	bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE	{ }
//UNSUP	//
//UNSUP	|	bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE { }
//UNSUP	;

//UNSUPbins_orBraE<nodep>:  // IEEE: part of bins_or_options:
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	'[' ']'					{ }
//UNSUP	|	'[' cgexpr ']'				{ }
//UNSUP	;

//UNSUPbins_keyword:  // ==IEEE: bins_keyword
//UNSUP		yBINS					{ }
//UNSUP	|	yILLEGAL_BINS				{ }
//UNSUP	|	yIGNORE_BINS				{ }
//UNSUP	;

//UNSUPcovergroup_range_list:  // ==IEEE: covergroup_range_list
//UNSUP	 	covergroup_value_range			{ $$ = $1; }
//UNSUP	|	covergroup_range_list ',' covergroup_value_range	{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

//UNSUPtrans_list:  // ==IEEE: trans_list
//UNSUP		'(' trans_set ')'			{ $$ = $2; }
//UNSUP	|	trans_list ',' '(' trans_set ')'	{ }
//UNSUP	;

//UNSUPtrans_set:  // ==IEEE: trans_set
//UNSUP		trans_range_list			{ $$ = $1; }
//UNSUP	//			// Note the { => } in the grammer, this is really a list
//UNSUP	|	trans_set yP_EQGT trans_range_list	{ }
//UNSUP	;

//UNSUPtrans_range_list:  // ==IEEE: trans_range_list
//UNSUP		trans_item				{ $$ = $1; }
//UNSUP	|	trans_item yP_BRASTAR repeat_range ']'	{ }
//UNSUP	|	trans_item yP_BRAMINUSGT repeat_range ']' { }
//UNSUP	|	trans_item yP_BRAEQ repeat_range ']'	{ }
//UNSUP	;

//UNSUPtrans_item:  // ==IEEE: range_list
//UNSUP		covergroup_range_list			{ $$ = $1; }
//UNSUP	;

//UNSUPrepeat_range:  // ==IEEE: repeat_range
//UNSUP		cgexpr					{ $$ = $1; }
//UNSUP	|	cgexpr ':' cgexpr			{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

//UNSUPcover_cross:  // ==IEEE: cover_cross
//UNSUP	 	id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body	{ }
//UNSUP	|	/**/				 yCROSS list_of_cross_items iffE cross_body	{ }
//UNSUP	;

//UNSUPlist_of_cross_items<nodep>:  // ==IEEE: list_of_cross_items
//UNSUP		cross_item ',' cross_item		{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	|	cross_item ',' cross_item ',' cross_itemList	{ }
//UNSUP	;

//UNSUPcross_itemList<nodep>:  // IEEE: part of list_of_cross_items
//UNSUP		cross_item				{ $$ = NULL; }
//UNSUP	|	cross_itemList ',' cross_item		{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

//UNSUPcross_item<nodep>:  // ==IEEE: cross_item
//UNSUP		idAny/*cover_point_identifier or variable_identifier*/		{ $$ = $1; }
//UNSUP	;

//UNSUPcross_body:  // ==IEEE: cross_body
//UNSUP		'{' '}'					{ $$ = NULL; }
//UNSUP	//			// IEEE-2012: No semicolon here, mistake in spec
//UNSUP	|	'{' cross_body_itemSemiList '}'		{ $$ = $1; }
//UNSUP	|	';'					{ $$ = NULL; }
//UNSUP	;

//UNSUPcross_body_itemSemiList:  // IEEE: part of cross_body
//UNSUP		cross_body_item ';'			{ $$ = $1; }
//UNSUP	|	cross_body_itemSemiList cross_body_item ';' { $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPcross_body_item<nodep>:  // ==IEEE: cross_body_item
//UNSUP	//			// IEEE: our semicolon is in the list
//UNSUP		bins_selection_or_option		{ $$ = $1; }
//UNSUP	|	function_declaration			{ $$ = $1; }
//UNSUP	;

//UNSUPbins_selection_or_option<nodep>:  // ==IEEE: bins_selection_or_option
//UNSUP		coverage_option				{ $$ = $1; }
//UNSUP	|	bins_selection				{ $$ = $1; }
//UNSUP	;

//UNSUPbins_selection:  // ==IEEE: bins_selection
//UNSUP		bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE	{ }
//UNSUP	;

//UNSUPselect_expression:  // ==IEEE: select_expression
//UNSUP	//			// IEEE: select_condition expanded here
//UNSUP		yBINSOF '(' bins_expression ')'		{ }
//UNSUP	|	yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}'	{ }
//UNSUP	|	yWITH__PAREN '(' cgexpr ')'		{ }
//UNSUP	//			// IEEE-2012: Need clarification as to precedence
//UNSUP	//UNSUP	yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr	{ }
//UNSUP	|	'!' yBINSOF '(' bins_expression ')'		{ }
//UNSUP	|	'!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}'	{ }
//UNSUP	|	'!' yWITH__PAREN '(' cgexpr ')'		{ }
//UNSUP	//			// IEEE-2012: Need clarification as to precedence
//UNSUP	//UNSUP	'!' yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr	{ }
//UNSUP	|	select_expression yP_ANDAND select_expression	{ }
//UNSUP	|	select_expression yP_OROR   select_expression	{ }
//UNSUP	|	'(' select_expression ')'			{ $$ = $2; }
//UNSUP	//			// IEEE-2012: cross_identifier
//UNSUP	//			// Part of covergroup_expression - generic identifier
//UNSUP	//			// IEEE-2012: Need clarification as to precedence
//UNSUP	//UNSUP	covergroup_expression [ yMATCHES covergroup_expression ]
//UNSUP	;

//UNSUPbins_expression:  // ==IEEE: bins_expression
//UNSUP	//			// "cover_point_identifier" and "variable_identifier" look identical
//UNSUP		id/*variable_identifier or cover_point_identifier*/	{ $$ = $1; }
//UNSUP	|	id/*cover_point_identifier*/ '.' idAny/*bins_identifier*/	{ }
//UNSUP	;

//UNSUPcoverage_eventE:  // IEEE: [ coverage_event ]
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	clocking_event				{ $$ = $1; }
//UNSUP	|	yWITH__ETC function idAny/*"sample"*/ '(' tf_port_listE ')'	{ }
//UNSUP	|	yP_ATAT '(' block_event_expression ')'	{ }
//UNSUP	;

//UNSUPblock_event_expression:  // ==IEEE: block_event_expression
//UNSUP		block_event_expressionTerm		{ $$ = $1; }
//UNSUP	|	block_event_expression yOR block_event_expressionTerm	{ }
//UNSUP	;

//UNSUPblock_event_expressionTerm:  // IEEE: part of block_event_expression
//UNSUP		yBEGIN hierarchical_btf_identifier	{ }
//UNSUP	|	yEND   hierarchical_btf_identifier	{ }
//UNSUP	;

//UNSUPhierarchical_btf_identifier:  // ==IEEE: hierarchical_btf_identifier
//UNSUP	//			// hierarchical_tf_identifier + hierarchical_block_identifier
//UNSUP		hierarchical_identifier/*tf_or_block*/	{ $$ = $1; }
//UNSUP	//			// method_identifier
//UNSUP	|	hierarchical_identifier class_scope_id	{ }
//UNSUP	|	hierarchical_identifier id		{ }
//UNSUP	;

//**********************************************************************
// Randsequence

//UNSUPrandsequence_statement<nodep>:  // ==IEEE: randsequence_statement
//UNSUP		yRANDSEQUENCE '('    ')' productionList yENDSEQUENCE	{ }
//UNSUP	|	yRANDSEQUENCE '(' id/*production_identifier*/ ')' productionList yENDSEQUENCE	{ }
//UNSUP	;

//UNSUPproductionList<nodep>:  // IEEE: production+
//UNSUP		production				{ $$ = $1; }
//UNSUP	|	productionList production		{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPproduction<nodep>:  // ==IEEE: production
//UNSUP		productionFront ':' rs_ruleList ';'	{ }
//UNSUP	;

//UNSUPproductionFront<nodep>:  // IEEE: part of production
//UNSUP		function_data_type id/*production_identifier*/	{ }
//UNSUP	|	/**/		   id/*production_identifier*/	{ $$ = $1; }
//UNSUP	|	function_data_type id/*production_identifier*/ '(' tf_port_listE ')'	{ }
//UNSUP	|	/**/		   id/*production_identifier*/ '(' tf_port_listE ')'	{ }
//UNSUP	;

//UNSUPrs_ruleList<nodep>:  // IEEE: rs_rule+ part of production
//UNSUP		rs_rule					{ $$ = $1; }
//UNSUP	|	rs_ruleList '|' rs_rule			{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

//UNSUPrs_rule<nodep>:  // ==IEEE: rs_rule
//UNSUP		rs_production_list			{ $$ = $1; }
//UNSUP	|	rs_production_list yP_COLONEQ weight_specification	{ }
//UNSUP	|	rs_production_list yP_COLONEQ weight_specification rs_code_block	{ }
//UNSUP	;

//UNSUPrs_production_list<nodep>:  // ==IEEE: rs_production_list
//UNSUP		rs_prodList				{ $$ = $1; }
//UNSUP	|	yRAND yJOIN /**/         production_item production_itemList	{ }
//UNSUP	|	yRAND yJOIN '(' expr ')' production_item production_itemList	{ }
//UNSUP	;

//UNSUPweight_specification<nodep>:  // ==IEEE: weight_specification
//UNSUP		yaINTNUM				{ $$ = $1; }
//UNSUP	|	idClassSel/*ps_identifier*/		{ $$ = $1; }
//UNSUP	|	'(' expr ')'				{ $$ = $2; }
//UNSUP	;

//UNSUPrs_code_block<nodep>:  // ==IEEE: rs_code_block
//UNSUP		'{' '}'					{ $$ = NULL; }
//UNSUP	|	'{' rs_code_blockItemList '}'		{ $$ = $2; }
//UNSUP	;

//UNSUPrs_code_blockItemList<nodep>:  // IEEE: part of rs_code_block
//UNSUP		rs_code_blockItem			{ $$ = $1; }
//UNSUP	|	rs_code_blockItemList rs_code_blockItem		{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPrs_code_blockItem<nodep>:  // IEEE: part of rs_code_block
//UNSUP		data_declaration			{ $$ = $1; }
//UNSUP	|	stmt					{ $$ = $1; }
//UNSUP	;

//UNSUPrs_prodList<nodep>:  // IEEE: rs_prod+
//UNSUP		rs_prod					{ $$ = $1; }
//UNSUP	|	rs_prodList rs_prod			{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPrs_prod<nodep>:  // ==IEEE: rs_prod
//UNSUP		production_item				{ $$ = $1; }
//UNSUP	|	rs_code_block				{ $$ = $1; }
//UNSUP	//			// IEEE: rs_if_else
//UNSUP	|	yIF '(' expr ')' production_item %prec prLOWER_THAN_ELSE	{ }
//UNSUP	|	yIF '(' expr ')' production_item yELSE production_item		{ }
//UNSUP	//			// IEEE: rs_repeat
//UNSUP	|	yREPEAT '(' expr ')' production_item	{ }
//UNSUP	//			// IEEE: rs_case
//UNSUP	|	yCASE '(' expr ')' rs_case_itemList yENDCASE	{ }
//UNSUP	;

//UNSUPproduction_itemList<nodep>:  // IEEE: production_item+
//UNSUP		production_item				{ $$ = $1; }
//UNSUP	|	production_itemList production_item	{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPproduction_item<nodep>:  // ==IEEE: production_item
//UNSUP		id/*production_identifier*/ 		{ $$ = $1; }
//UNSUP	|	id/*production_identifier*/ '(' list_of_argumentsE ')'	{ }
//UNSUP	;

//UNSUPrs_case_itemList<nodep>:  // IEEE: rs_case_item+
//UNSUP		rs_case_item				{ $$ = $1; }
//UNSUP	|	rs_case_itemList rs_case_item		{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPrs_case_item<nodep>:  // ==IEEE: rs_case_item
//UNSUP		caseCondList ':' production_item ';'	{ }
//UNSUP	|	yDEFAULT production_item ';'		{ }
//UNSUP	|	yDEFAULT ':' production_item ';'	{ }
//UNSUP	;

//**********************************************************************
// Checker

//UNSUPchecker_declaration<nodep>:  // ==IEEE: part of checker_declaration
//UNSUP		checkerFront checker_port_listE ';'
//UNSUP			checker_or_generate_itemListE yENDCHECKER endLabelE
//UNSUP			{ SYMP->popScope($$); }
//UNSUP	;

//UNSUPcheckerFront<nodep>:  // IEEE: part of checker_declaration
//UNSUP		yCHECKER idAny/*checker_identifier*/
//UNSUP			{ SYMP->pushNew($$); }
//UNSUP	;

//UNSUPchecker_port_listE<nodep>:  // IEEE: [ ( [ checker_port_list ] ) ]
//UNSUP	//			// checker_port_item is basically the same as property_port_item, minus yLOCAL::
//UNSUP	//			// Want to bet 1800-2012 adds local to checkers?
//UNSUP		property_port_listE			{ $$ = $1; }
//UNSUP	;

//UNSUPchecker_or_generate_itemListE<nodep>:  // IEEE: [{ checker_or_generate_itemList }]
//UNSUP		/* empty */				{ $$ = NULL; }
//UNSUP	|	checker_or_generate_itemList		{ $$ = $1; }
//UNSUP	;

//UNSUPchecker_or_generate_itemList<nodep>:  // IEEE: { checker_or_generate_itemList }
//UNSUP		checker_or_generate_item		{ $$ = $1; }
//UNSUP	|	checker_or_generate_itemList checker_or_generate_item	{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPchecker_or_generate_item<nodep>:  // ==IEEE: checker_or_generate_item
//UNSUP		checker_or_generate_item_declaration	{ $$ = $1; }
//UNSUP	|	initial_construct			{ $$ = $1; }
//UNSUP	//			// IEEE: checker_construct
//UNSUP	|	yALWAYS stmtBlock			{ }
//UNSUP	|	final_construct				{ $$ = $1; }
//UNSUP	|	assertion_item				{ $$ = $1; }
//UNSUP	|	continuous_assign			{ $$ = $1; }
//UNSUP	|	checker_generate_item			{ $$ = $1; }
//UNSUP	;

//UNSUPchecker_or_generate_item_declaration<nodep>:  // ==IEEE: checker_or_generate_item_declaration
//UNSUP		data_declaration			{ $$ = $1; }
//UNSUP	|	yRAND data_declaration			{ }
//UNSUP	|	function_declaration			{ $$ = $1; }
//UNSUP	|	checker_declaration			{ $$ = $1; }
//UNSUP	|	assertion_item_declaration		{ $$ = $1; }
//UNSUP	|	covergroup_declaration			{ $$ = $1; }
//UNSUP	//	// IEEE deprecated: overload_declaration
//UNSUP	|	genvar_declaration			{ $$ = $1; }
//UNSUP	|	clocking_declaration			{ $$ = $1; }
//UNSUP	|	yDEFAULT yCLOCKING id/*clocking_identifier*/ ';'	{ }
//UNSUP	|	yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';'	{ }
//UNSUP	|	';'					{ $$ = NULL; }
//UNSUP	;

//UNSUPchecker_generate_item<nodep>:  // ==IEEE: checker_generate_item
//UNSUP	//			// Specialized for checker so need "c_" prefixes here
//UNSUP		c_loop_generate_construct		{ $$ = $1; }
//UNSUP	|	c_conditional_generate_construct	{ $$ = $1; }
//UNSUP	|	c_generate_region			{ $$ = $1; }
//UNSUP	//
//UNSUP	|	elaboration_system_task			{ $$ = $1; }
//UNSUP	;

//UNSUPchecker_instantiation<nodep>:
//UNSUP	//			// Only used for procedural_assertion_item's
//UNSUP	//			// Version in concurrent_assertion_item looks like etcInst
//UNSUP	//			// Thus instead of *_checker_port_connection we can use etcInst's cellpinList
//UNSUP		id/*checker_identifier*/ id '(' cellpinList ')' ';'	{ }
//UNSUP	;

//**********************************************************************
// Class

class_declaration<nodep>:	// ==IEEE: part of class_declaration
	//			// IEEE-2012: using this also for interface_class_declaration
	//			// The classExtendsE rule relys on classFront having the
	//			// new class scope correct via classFront
		classFront parameter_port_listE classExtendsE classImplementsE ';'
			class_itemListE yENDCLASS endLabelE
			{ $$ = $1; $1->addMembersp($2);
			  $1->addMembersp($4); $1->addMembersp($6);
			  SYMP->popScope($$);
			  GRAMMARP->endLabel($<fl>7, $1, $8); }
	;

classFront<classp>:		// IEEE: part of class_declaration
		classVirtualE yCLASS lifetimeE idAny/*class_identifier*/
			{ $$ = new AstClass($2, *$4);
			  SYMP->pushNew($<classp>$);
			  BBUNSUP($2, "Unsupported: classes");  }
	//			// IEEE: part of interface_class_declaration
	|	yINTERFACE yCLASS lifetimeE idAny/*class_identifier*/
			{ $$ = new AstClass($2, *$4);
			  SYMP->pushNew($<classp>$);
			  BBUNSUP($2, "Unsupported: interface classes");  }
	;

classVirtualE:
		/* empty */				{ }
	|	yVIRTUAL__CLASS				{ BBUNSUP($1, "Unsupported: virtual classes"); }
	;

classExtendsE<nodep>:		// IEEE: part of class_declaration
	//			// The classExtendsE rule relys on classFront having the
	//			// new class scope correct via classFront
		/* empty */				{ $$ = NULL; }
	|	yEXTENDS classExtendsList		{ $$ = $2; }
	;

classExtendsList<nodep>:	// IEEE: part of class_declaration
		classExtendsOne				{ $$ = $1; }
	|	classExtendsList ',' classExtendsOne	{ $$ = AstNode::addNextNull($1, $3); }
	;

classExtendsOne<nodep>:		// IEEE: part of class_declaration
		class_typeWithoutId			{ $$ = NULL; BBUNSUP($1, "Unsupported: extends"); }
	//			// IEEE: Might not be legal to have more than one set of parameters in an extends
	|	class_typeWithoutId '(' list_of_argumentsE ')'	{ $$ = NULL; BBUNSUP($1, "Unsupported: extends"); }
	;

classImplementsE<nodep>:	// IEEE: part of class_declaration
	//			// All 1800-2012
		/* empty */				{ $$ = NULL; }
	|	yIMPLEMENTS classImplementsList		{ $$ = $2; }
	;

classImplementsList<nodep>:	// IEEE: part of class_declaration
	//			// All 1800-2012
		class_typeWithoutId				{ $$ = NULL; BBUNSUP($1, "Unsupported: implements class"); }
	|	classImplementsList ',' class_typeWithoutId	{ $$ = AstNode::addNextNull($1, $3); }
	;

//=========
// Package scoping - to traverse the symbol table properly, the final identifer
// must be included in the rules below.
// Each of these must end with {symsPackageDone | symsClassDone}

ps_id_etc:		// package_scope + general id
		package_scopeIdFollowsE id		{ }
	;

ps_type<dtypep>:		// IEEE: ps_parameter_identifier | ps_type_identifier
				// Even though we looked up the type and have a AstNode* to it,
				// we can't fully resolve it because it may have been just a forward definition.
		package_scopeIdFollowsE idRefDType	{ $$ = $2; $2->packagep($1); }
	//			// Simplify typing - from ps_covergroup_identifier
	;

//=== Below rules assume special scoping per above

class_typeWithoutId<nodep>:	// as with class_typeWithoutId but allow yaID__aTYPE
	//			// and we thus don't need to resolve it in specified package
		package_scopeIdFollowsE class_typeOneList	{ $$ = $2; $2->packagep($1); }
	;

class_scopeWithoutId<nodep>:	// class_type standalone without following id
	//			// and we thus don't need to resolve it in specified package
		class_scopeIdFollows			{ $$ = $1; }
	;

class_scopeIdFollows<nodep>:	// IEEE: class_scope + type
	//			// IEEE: "class_type yP_COLONCOLON"
	//			// IMPORTANT: The lexer will parse the following ID to be in the found package
	//			// But class_type:'::' conflicts with class_scope:'::' so expand here
		package_scopeIdFollowsE class_typeOneListColonIdFollows
			{ $$ = NULL; BBUNSUP(CRELINE(), "Unsupported: scoped class reference"); }
	;

class_typeOneListColonIdFollows: // IEEE: class_type :: but allow yaID__aTYPE
		class_typeOneList yP_COLONCOLON 	{ BBUNSUP($2, "Unsupported: Hierarchical class references"); }
	;

class_typeOneList<refdtypep>:	// IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE
	//			// If you follow the rules down, class_type is really a list via ps_class_identifier
	//			// Must propagate scp up for next id
		class_typeOne					{ $$ = $1; }
	|	class_typeOneListColonIdFollows class_typeOne	{ $$ = $2; /*UNSUP*/ }
	;

class_typeOne<refdtypep>:	// IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE
	//			// If you follow the rules down, class_type is really a list via ps_class_identifier
	//			// Not listed in IEEE, but see bug627 any parameter type maybe a class
		idRefDType parameter_value_assignmentE
			{ $$ = $1; if ($2) BBUNSUP($2->fileline(), "Unsupported: Parameterized classes"); }
	;

package_scopeIdFollowsE<packagep>:	// IEEE: [package_scope]
	//			// IMPORTANT: The lexer will parse the following ID to be in the found package
	//			// class_qualifier := [ yLOCAL '::'  ] [ implicit_class_handle '.'  class_scope ]
		/* empty */				{ $$ = NULL; }
	|	package_scopeIdFollows			{ $$ = $1; }
	;

package_scopeIdFollows<packagep>:	// IEEE: package_scope
	//			// IMPORTANT: The lexer will parse the following ID to be in the found package
	//			//vv mid rule action needed otherwise we might not have NextId in time to parse the id token
		yD_UNIT        { SYMP->nextId(PARSEP->rootp()); }
	/*cont*/	yP_COLONCOLON	{ $$ = GRAMMARP->unitPackage($<fl>1); }
	|	yaID__aPACKAGE { SYMP->nextId($<scp>1); }
	/*cont*/	yP_COLONCOLON	{ $$ = VN_CAST($<scp>1, Package); }
	//UNSUP	yLOCAL__COLONCOLON { PARSEP->symTableNextId($<scp>1); }
	//UNSUP	/*cont*/	yP_COLONCOLON	{ UNSUP }
	;

//^^^=========

class_itemListE<nodep>:
		/* empty */				{ $$ = NULL; }
	|	class_itemList				{ $$ = $1; }
	;

class_itemList<nodep>:
		class_item				{ $$ = $1; }
	|	class_itemList class_item  		{ $$ = AstNode::addNextNull($1, $2); }
	;

class_item<nodep>:			// ==IEEE: class_item
		class_property				{ $$ = $1; }
	|	class_method				{ $$ = $1; }
	//UNSUP	class_constraint			{ $$ = $1; }
	//
	|	class_declaration			{ $$ = NULL; BBUNSUP($1, "Unsupported: class within class"); }
	|	timeunits_declaration			{ $$ = $1; }
	//UNSUP	covergroup_declaration			{ $$ = $1; }
	|	local_parameter_declaration ';'		{ $$ = $1; BBUNSUP($2, "Unsupported: class parameters"); }  // 1800-2009
	|	parameter_declaration ';'		{ $$ = $1; BBUNSUP($2, "Unsupported: class parameters"); }  // 1800-2009
	|	';'					{ $$ = NULL; }
	//
	|	error ';'				{ $$ = NULL; }
	;

class_method<nodep>:		// ==IEEE: class_method
		memberQualResetListE task_declaration		{ $$ = $2; }
	|	memberQualResetListE function_declaration	{ $$ = $2; }
	|	yPURE yVIRTUAL__ETC memberQualResetListE method_prototype ';'
			{ $$ = NULL; BBUNSUP($1, "Unsupported: pure virtual class method"); }
	|	yEXTERN memberQualResetListE method_prototype ';'
			{ $$ = NULL; BBUNSUP($1, "Unsupported: extern class method prototype"); }
	//			// IEEE: "method_qualifierE class_constructor_declaration"
	//			// part of function_declaration
	|	yEXTERN memberQualResetListE class_constructor_prototype
			{ $$ = NULL; BBUNSUP($1, "Unsupported: extern class"); }
	;

// IEEE: class_constructor_prototype
// See function_declaration

class_item_qualifier<nodep>:	// IEEE: class_item_qualifier minus ySTATIC
	//			// IMPORTANT: yPROTECTED | yLOCAL is in a lex rule
		yPROTECTED				{ $$ = NULL; }  // Ignoring protected until implemented
	|	yLOCAL__ETC				{ $$ = NULL; BBUNSUP($1, "Unsupported: 'local' class item"); }
	|	ySTATIC__ETC				{ $$ = NULL; BBUNSUP($1, "Unsupported: 'static' class item"); }
	;

memberQualResetListE<nodep>:	// Called from class_property for all qualifiers before yVAR
	//			// Also before method declarations, to prevent grammar conflict
	//			// Thus both types of qualifiers (method/property) are here
		/*empty*/				{ $$ = NULL; }
	|	memberQualList				{ $$ = $1; }
	;

memberQualList<nodep>:
		memberQualOne				{ $$ = $1; }
	|	memberQualList memberQualOne		{ $$ = AstNode::addNextNull($1, $2); }
	;

memberQualOne<nodep>:			// IEEE: property_qualifier + method_qualifier
	//			// Part of method_qualifier and property_qualifier
		class_item_qualifier			{ $$ = $1; }
	//			// Part of method_qualifier only
	|	yVIRTUAL__ETC				{ $$ = NULL; BBUNSUP($1, "Unsupported: virtual class member qualifier"); }
	//			// Part of property_qualifier only
	|	random_qualifier			{ $$ = NULL; }
	//			// Part of lifetime, but here as ySTATIC can be in different positions
	|	yAUTOMATIC		 		{ $$ = NULL; BBUNSUP($1, "Unsupported: automatic class member qualifier"); }
	//			// Part of data_declaration, but not in data_declarationVarFrontClass
	|	yCONST__ETC				{ $$ = NULL; BBUNSUP($1, "Unsupported: const class member qualifier"); }
	;

//**********************************************************************
// Constraints

//UNSUPclass_constraint<nodep>:  // ==IEEE: class_constraint
//UNSUP	//			// IEEE: constraint_declaration
//UNSUP		constraintStaticE yCONSTRAINT idAny constraint_block	{ }
//UNSUP	//			// IEEE: constraint_prototype + constraint_prototype_qualifier
//UNSUP	|	constraintStaticE yCONSTRAINT idAny ';'		{ }
//UNSUP	|	yEXTERN constraintStaticE yCONSTRAINT idAny ';'	{ }
//UNSUP	|	yPURE constraintStaticE yCONSTRAINT idAny ';'	{ }
//UNSUP	;

//UNSUPconstraint_block<nodep>:  // ==IEEE: constraint_block
//UNSUP		'{' constraint_block_itemList '}'	{ $$ = $1; }
//UNSUP	;

//UNSUPconstraint_block_itemList<nodep>:  // IEEE: { constraint_block_item }
//UNSUP		constraint_block_item			{ $$ = $1; }
//UNSUP	|	constraint_block_itemList constraint_block_item	{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPconstraint_block_item:  // ==IEEE: constraint_block_item
//UNSUP		ySOLVE solve_before_list yBEFORE solve_before_list ';'	{ }
//UNSUP	|	constraint_expression			{ $$ = $1; }
//UNSUP	;

//UNSUPsolve_before_list:  // ==IEEE: solve_before_list
//UNSUP		constraint_primary			{ $$ = $1; }
//UNSUP	|	solve_before_list ',' constraint_primary	{ }
//UNSUP	;

//UNSUPconstraint_primary:  // ==IEEE: constraint_primary
//UNSUP	//			// exprScope more general than: [ implicit_class_handle '.' | class_scope ] hierarchical_identifier select
//UNSUP		exprScope				{ $$ = $1; }
//UNSUP	;

//UNSUPconstraint_expressionList<nodep>:  // ==IEEE: { constraint_expression }
//UNSUP		constraint_expression				{ $$ = $1; }
//UNSUP	|	constraint_expressionList constraint_expression	{ $$ = AstNode::addNextNull($1, $2); }
//UNSUP	;

//UNSUPconstraint_expression<nodep>:  // ==IEEE: constraint_expression
//UNSUP		expr/*expression_or_dist*/ ';'		{ $$ = $1; }
//UNSUP	//			// 1800-2012:
//UNSUP	|	ySOFT expr/*expression_or_dist*/ ';'	{ }
//UNSUP	//			// 1800-2012:
//UNSUP	//			// IEEE: uniqueness_constraint ';'
//UNSUP	|	yUNIQUE '{' open_range_list '}'		{ }
//UNSUP	//			// IEEE: expr yP_MINUSGT constraint_set
//UNSUP	//			// Conflicts with expr:"expr yP_MINUSGT expr"; rule moved there
//UNSUP	//
//UNSUP	|	yIF '(' expr ')' constraint_set	%prec prLOWER_THAN_ELSE	{ }
//UNSUP	|	yIF '(' expr ')' constraint_set	yELSE constraint_set	{ }
//UNSUP	//			// IEEE says array_identifier here, but dotted accepted in VMM + 1800-2009
//UNSUP	|	yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' constraint_set	{ }
//UNSUP	//			// soft is 1800-2012
//UNSUP	|	yDISABLE ySOFT expr/*constraint_primary*/ ';'	{ }
//UNSUP	;

//UNSUPconstraint_set<nodep>:  // ==IEEE: constraint_set
//UNSUP		constraint_expression			{ $$ = $1; }
//UNSUP	|	'{' constraint_expressionList '}'	{ $$ = $2; }
//UNSUP	;

//UNSUPdist_list<nodep>:  // ==IEEE: dist_list
//UNSUP		dist_item				{ $$ = $1; }
//UNSUP	|	dist_list ',' dist_item			{ $$ = AstNode::addNextNull($1, $3); }
//UNSUP	;

//UNSUPdist_item:  // ==IEEE: dist_item + dist_weight
//UNSUP		value_range				{ $$ = $1; }
//UNSUP	|	value_range yP_COLONEQ  expr		{ }
//UNSUP	|	value_range yP_COLONDIV expr		{ }
//UNSUP	;

//UNSUPextern_constraint_declaration:  // ==IEEE: extern_constraint_declaration
//UNSUP		constraintStaticE yCONSTRAINT class_scope_id constraint_block	{ }
//UNSUP	;

//UNSUPconstraintStaticE<bool>:  // IEEE: part of extern_constraint_declaration
//UNSUP		/* empty */				{ $$ = false; }
//UNSUP	|	ySTATIC__CONSTRAINT			{ $$ = true; }
//UNSUP	;

//**********************************************************************
// VLT Files

vltItem:
		vltOffFront				{ V3Config::addIgnore($1,false,"*",0,0); }
	|	vltOffFront yVLT_D_FILE yaSTRING	{ V3Config::addIgnore($1,false,*$3,0,0); }
	|	vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM			{ V3Config::addIgnore($1,false,*$3,$5->toUInt(),$5->toUInt()+1); }
	|	vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM	{ V3Config::addIgnore($1,false,*$3,$5->toUInt(),$7->toUInt()+1); }
	|	vltOnFront				{ V3Config::addIgnore($1,true,"*",0,0); }
	|	vltOnFront yVLT_D_FILE yaSTRING		{ V3Config::addIgnore($1,true,*$3,0,0); }
	|	vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM			{ V3Config::addIgnore($1,true,*$3,$5->toUInt(),$5->toUInt()+1); }
	|	vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM	{ V3Config::addIgnore($1,true,*$3,$5->toUInt(),$7->toUInt()+1); }
	;

vltOffFront<errcodeen>:
		yVLT_COVERAGE_OFF			{ $$ = V3ErrorCode::I_COVERAGE; }
	|	yVLT_TRACING_OFF			{ $$ = V3ErrorCode::I_TRACING; }
	|	yVLT_LINT_OFF				{ $$ = V3ErrorCode::I_LINT; }
	|	yVLT_LINT_OFF yVLT_D_MSG yaID__ETC
			{ $$ = V3ErrorCode((*$3).c_str());
			  if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: "<<*$3<<endl); }
			  $2->v3warn(DEPRECATED, "Deprecated -msg in configuration files, use -rule instead."<<endl); }
	|	yVLT_LINT_OFF yVLT_D_RULE yaID__ETC
			{ $$ = V3ErrorCode((*$3).c_str());
			  if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: "<<*$3<<endl);  } }
	;

vltOnFront<errcodeen>:
		yVLT_COVERAGE_ON			{ $$ = V3ErrorCode::I_COVERAGE; }
	|	yVLT_TRACING_ON				{ $$ = V3ErrorCode::I_TRACING; }
	|	yVLT_LINT_ON				{ $$ = V3ErrorCode::I_LINT; }
	|	yVLT_LINT_ON yVLT_D_MSG yaID__ETC
			{ $$ = V3ErrorCode((*$3).c_str());
			  if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: "<<*$3<<endl);  }
			  $2->v3warn(DEPRECATED, "Deprecated -msg in configuration files, use -rule instead."<<endl); }
	|	yVLT_LINT_ON yVLT_D_RULE yaID__ETC
			{ $$ = V3ErrorCode((*$3).c_str());
			  if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: "<<*$3<<endl);  } }
	;

//**********************************************************************
%%
// For implementation functions see V3ParseGrammar.cpp

//YACC = /kits/sources/bison-2.4.1/src/bison --report=lookahead
// --report=lookahead
// --report=itemset
// --graph
