Parser clean-up

Signed-off-by: Matthew Ballance <matt.ballance@gmail.com>
This commit is contained in:
Matthew Ballance 2026-03-01 15:46:20 +00:00
parent 42debebb07
commit 8860ad4b3e
5 changed files with 241 additions and 265 deletions

View File

@ -129,10 +129,10 @@ verilator_coverage Arguments
.. option:: --filter-type <regex>
Skips records of coverage types that matches with <regex>
Possible values are `toggle`, `line`, `branch`, `expr`, `funccov`, `user` and
Possible values are `toggle`, `line`, `branch`, `expr`, `covergroup`, `user` and
a wildcard with `\*` or `?`. The default value is `\*`.
The `funccov` type represents SystemVerilog functional coverage including
The `covergroup` type represents SystemVerilog functional coverage including
covergroups, coverpoints, bins, and cross coverage as defined in IEEE
1800-2023 Section 19.

View File

@ -1157,13 +1157,17 @@ class AstCovergroup final : public AstNode {
// @astgen op1 := argsp : List[AstVar]
// @astgen op2 := membersp : List[AstNode]
// @astgen op3 := eventp : Optional[AstSenTree]
// @astgen op4 := sampleArgsp : List[AstVar]
string m_name;
bool m_isClass = false;
public:
AstCovergroup(FileLine* fl, const string& name, AstNode* membersp, AstSenTree* eventp)
AstCovergroup(FileLine* fl, const string& name, AstVar* argsp, AstVar* sampleArgsp,
AstNode* membersp, AstSenTree* eventp)
: ASTGEN_SUPER_Covergroup(fl)
, m_name{name} {
if (argsp) addArgsp(argsp);
if (sampleArgsp) addSampleArgsp(sampleArgsp);
if (membersp) addMembersp(membersp);
this->eventp(eventp);
}

View File

@ -1006,6 +1006,213 @@ class LinkParseVisitor final : public VNVisitor {
iterateChildren(nodep);
}
// Create boilerplate covergroup methods on the given AstClass.
// argsp/sampleArgsp are the raw arg lists still owned by the caller; they are iterated
// (cloned) but not deleted here.
static void createCovergroupMethods(AstClass* nodep, AstNode* argsp, AstNode* sampleArgsp) {
// Hidden static to take unspecified reference argument results
AstVar* const defaultVarp
= new AstVar{nodep->fileline(), VVarType::MEMBER, "__Vint", nodep->findIntDType()};
defaultVarp->lifetime(VLifetime::STATIC_EXPLICIT);
nodep->addStmtsp(defaultVarp);
// Handle constructor arguments - add function parameters and assignments
if (argsp) {
// Find the 'new' function to add parameters to
AstFunc* newFuncp = nullptr;
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
if (AstFunc* const funcp = VN_CAST(memberp, Func)) {
if (funcp->name() == "new") {
newFuncp = funcp;
break;
}
}
}
if (newFuncp) {
// Save the existing body statements and unlink them
AstNode* const existingBodyp = newFuncp->stmtsp();
if (existingBodyp) existingBodyp->unlinkFrBackWithNext();
// Add function parameters and assignments
for (AstNode* argp = argsp; argp; argp = argp->nextp()) {
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
AstVar* const paramp = origVarp->cloneTree(false);
paramp->funcLocal(true);
paramp->direction(VDirection::INPUT);
newFuncp->addStmtsp(paramp);
AstNodeExpr* const lhsp
= new AstParseRef{origVarp->fileline(), origVarp->name()};
AstNodeExpr* const rhsp
= new AstParseRef{paramp->fileline(), paramp->name()};
newFuncp->addStmtsp(new AstAssign{origVarp->fileline(), lhsp, rhsp});
}
}
if (existingBodyp) newFuncp->addStmtsp(existingBodyp);
}
}
// IEEE: option
{
v3Global.setUsesStdPackage();
AstVar* const varp
= new AstVar{nodep->fileline(), VVarType::MEMBER, "option", VFlagChildDType{},
new AstRefDType{nodep->fileline(), "vl_covergroup_options_t",
new AstClassOrPackageRef{nodep->fileline(), "std",
nullptr, nullptr},
nullptr}};
nodep->addMembersp(varp);
}
// IEEE: type_option
{
v3Global.setUsesStdPackage();
AstVar* const varp
= new AstVar{nodep->fileline(), VVarType::MEMBER, "type_option", VFlagChildDType{},
new AstRefDType{nodep->fileline(), "vl_covergroup_type_options_t",
new AstClassOrPackageRef{nodep->fileline(), "std",
nullptr, nullptr},
nullptr}};
nodep->addMembersp(varp);
}
// IEEE: function void sample([arguments])
{
AstFunc* const funcp = new AstFunc{nodep->fileline(), "sample", nullptr, nullptr};
if (sampleArgsp) {
for (AstNode* argp = sampleArgsp; argp; argp = argp->nextp()) {
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
AstVar* const paramp = origVarp->cloneTree(false);
paramp->funcLocal(true);
paramp->direction(VDirection::INPUT);
funcp->addStmtsp(paramp);
AstNodeExpr* const lhsp
= new AstParseRef{origVarp->fileline(), origVarp->name()};
AstNodeExpr* const rhsp
= new AstParseRef{paramp->fileline(), paramp->name()};
funcp->addStmtsp(new AstAssign{origVarp->fileline(), lhsp, rhsp});
}
}
}
funcp->classMethod(true);
funcp->dtypep(funcp->findVoidDType());
nodep->addMembersp(funcp);
}
// IEEE: function void start(), void stop()
for (const string& name : {"start"s, "stop"s}) {
AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr};
funcp->classMethod(true);
funcp->dtypep(funcp->findVoidDType());
nodep->addMembersp(funcp);
}
// IEEE: static function real get_coverage(optional ref int, optional ref int)
// IEEE: function real get_inst_coverage(optional ref int, optional ref int)
for (const string& name : {"get_coverage"s, "get_inst_coverage"s}) {
AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr};
funcp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
funcp->isStatic(name == "get_coverage");
funcp->classMethod(true);
funcp->dtypep(funcp->findVoidDType());
nodep->addMembersp(funcp);
{
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, name,
nodep->findDoubleDType()};
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
varp->funcLocal(true);
varp->direction(VDirection::OUTPUT);
varp->funcReturn(true);
funcp->fvarp(varp);
}
for (const string& varname : {"covered_bins"s, "total_bins"s}) {
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, varname,
nodep->findStringDType()};
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
varp->funcLocal(true);
varp->direction(VDirection::INPUT);
varp->valuep(new AstVarRef{nodep->fileline(), defaultVarp, VAccess::READ});
funcp->addStmtsp(varp);
}
}
// IEEE: function void set_inst_name(string)
{
AstFunc* const funcp
= new AstFunc{nodep->fileline(), "set_inst_name", nullptr, nullptr};
funcp->classMethod(true);
funcp->dtypep(funcp->findVoidDType());
nodep->addMembersp(funcp);
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, "name",
nodep->findStringDType()};
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
varp->funcLocal(true);
varp->direction(VDirection::INPUT);
funcp->addStmtsp(varp);
}
}
void visit(AstCovergroup* nodep) override {
// Transform raw parse-time AstCovergroup into a fully-formed AstClass
cleanFileline(nodep);
const string libname = m_modp ? m_modp->libname() : "";
AstClass* const cgClassp = new AstClass{nodep->fileline(), nodep->name(), libname};
cgClassp->isCovergroup(true);
v3Global.useCovergroup(true);
// Clocking event: unlink before deleteTree, attach as AstCovergroup child on class
if (AstSenTree* const eventp = nodep->eventp()) {
eventp->unlinkFrBack();
AstCovergroup* const cgNodep
= new AstCovergroup{nodep->fileline(), nodep->name(),
nullptr, nullptr, nullptr, eventp};
cgClassp->addMembersp(cgNodep);
}
// Convert constructor args to member variables
for (AstNode* argp = nodep->argsp(); argp; argp = argp->nextp()) {
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
AstVar* const memberp = origVarp->cloneTree(false);
memberp->varType(VVarType::MEMBER);
memberp->funcLocal(false);
memberp->direction(VDirection::NONE);
cgClassp->addMembersp(memberp);
}
}
// Convert sample args to member variables
for (AstNode* argp = nodep->sampleArgsp(); argp; argp = argp->nextp()) {
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
AstVar* const memberp = origVarp->cloneTree(false);
memberp->varType(VVarType::MEMBER);
memberp->funcLocal(false);
memberp->direction(VDirection::NONE);
cgClassp->addMembersp(memberp);
}
}
// Create the constructor; detach membersp (coverage body) and use as its body
{
AstFunc* const newp = new AstFunc{nodep->fileline(), "new", nullptr, nullptr};
newp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
newp->classMethod(true);
newp->isConstructor(true);
newp->dtypep(cgClassp->dtypep());
if (AstNode* const bodyp = nodep->membersp()) {
bodyp->unlinkFrBackWithNext();
newp->addStmtsp(bodyp);
}
cgClassp->addMembersp(newp);
}
// Add all boilerplate covergroup methods (reads argsp/sampleArgsp from nodep)
createCovergroupMethods(cgClassp, nodep->argsp(), nodep->sampleArgsp());
// Replace AstCovergroup with AstClass and process the new class normally
nodep->replaceWith(cgClassp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
iterate(cgClassp);
}
void visit(AstNode* nodep) override {
// Default: Just iterate
cleanFileline(nodep);

View File

@ -94,169 +94,6 @@ public:
nodep->trace(singletonp()->allTracingOn(fileline));
return nodep;
}
void createCoverGroupMethods(AstClass* nodep, AstNode* constructorArgs, AstNode* sampleArgs) {
// Hidden static to take unspecified reference argument results
AstVar* const defaultVarp
= new AstVar{nodep->fileline(), VVarType::MEMBER, "__Vint", nodep->findIntDType()};
defaultVarp->lifetime(VLifetime::STATIC_EXPLICIT);
nodep->addStmtsp(defaultVarp);
// Handle constructor arguments - add function parameters and assignments
// Member variables have already been created in verilog.y
if (constructorArgs) {
// Find the 'new' function to add parameters to
AstFunc* newFuncp = nullptr;
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
if (AstFunc* funcp = VN_CAST(memberp, Func)) {
if (funcp->name() == "new") {
newFuncp = funcp;
break;
}
}
}
if (newFuncp) {
// Save the existing body statements and unlink them
AstNode* const existingBodyp = newFuncp->stmtsp();
if (existingBodyp) existingBodyp->unlinkFrBackWithNext();
// Add function parameters and assignments
AstNode* nextArgp = nullptr;
for (AstNode* argp = constructorArgs; argp; argp = nextArgp) {
nextArgp = argp->nextp(); // Save next before any modifications
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
// Create a constructor parameter
AstVar* const paramp = origVarp->cloneTree(false);
paramp->funcLocal(true);
paramp->direction(VDirection::INPUT);
newFuncp->addStmtsp(paramp);
// Create assignment: member = parameter
AstNodeExpr* const lhsp
= new AstParseRef{origVarp->fileline(), origVarp->name()};
AstNodeExpr* const rhsp
= new AstParseRef{paramp->fileline(), paramp->name()};
newFuncp->addStmtsp(new AstAssign{origVarp->fileline(), lhsp, rhsp});
}
}
// Finally, add back the existing body
if (existingBodyp) newFuncp->addStmtsp(existingBodyp);
}
}
// IEEE: option
{
v3Global.setUsesStdPackage();
AstVar* const varp
= new AstVar{nodep->fileline(), VVarType::MEMBER, "option", VFlagChildDType{},
new AstRefDType{nodep->fileline(), "vl_covergroup_options_t",
new AstClassOrPackageRef{nodep->fileline(), "std",
nullptr, nullptr},
nullptr}};
nodep->addMembersp(varp);
}
// IEEE: type_option
{
v3Global.setUsesStdPackage();
AstVar* const varp
= new AstVar{nodep->fileline(), VVarType::MEMBER, "type_option", VFlagChildDType{},
new AstRefDType{nodep->fileline(), "vl_covergroup_type_options_t",
new AstClassOrPackageRef{nodep->fileline(), "std",
nullptr, nullptr},
nullptr}};
nodep->addMembersp(varp);
}
// IEEE: function void sample([arguments])
{
AstFunc* const funcp = new AstFunc{nodep->fileline(), "sample", nullptr, nullptr};
// Add sample arguments as function parameters and assignments
// Member variables have already been created in verilog.y
if (sampleArgs) {
// Add function parameters and assignments
AstNode* nextArgp = nullptr;
for (AstNode* argp = sampleArgs; argp; argp = nextArgp) {
nextArgp = argp->nextp(); // Save next before any modifications
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
// Create a function parameter
AstVar* const paramp = origVarp->cloneTree(false);
paramp->funcLocal(true);
paramp->direction(VDirection::INPUT);
funcp->addStmtsp(paramp);
// Create assignment: member = parameter
AstNodeExpr* const lhsp
= new AstParseRef{origVarp->fileline(), origVarp->name()};
AstNodeExpr* const rhsp
= new AstParseRef{paramp->fileline(), paramp->name()};
funcp->addStmtsp(new AstAssign{origVarp->fileline(), lhsp, rhsp});
}
}
}
funcp->classMethod(true);
funcp->dtypep(funcp->findVoidDType());
nodep->addMembersp(funcp);
}
// IEEE: function void start(), void stop()
for (const string& name : {"start"s, "stop"s}) {
AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr};
funcp->classMethod(true);
funcp->dtypep(funcp->findVoidDType());
nodep->addMembersp(funcp);
}
// IEEE: static function real get_coverage(optional ref int, optional ref int)
// IEEE: function real get_inst_coverage(optional ref int, optional ref int)
for (const string& name : {"get_coverage"s, "get_inst_coverage"s}) {
AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr};
funcp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
funcp->isStatic(name == "get_coverage");
funcp->classMethod(true);
funcp->dtypep(funcp->findVoidDType());
nodep->addMembersp(funcp);
{
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, name,
nodep->findDoubleDType()};
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
varp->funcLocal(true);
varp->direction(VDirection::OUTPUT);
varp->funcReturn(true);
funcp->fvarp(varp);
}
for (const string& varname : {"covered_bins"s, "total_bins"s}) {
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, varname,
nodep->findStringDType()};
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
varp->funcLocal(true);
varp->direction(VDirection::INPUT);
varp->valuep(new AstVarRef{nodep->fileline(), defaultVarp, VAccess::READ});
funcp->addStmtsp(varp);
}
}
// IEEE: function void set_inst_name(string)
{
AstFunc* const funcp
= new AstFunc{nodep->fileline(), "set_inst_name", nullptr, nullptr};
funcp->classMethod(true);
funcp->dtypep(funcp->findVoidDType());
nodep->addMembersp(funcp);
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, "name",
nodep->findStringDType()};
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
varp->funcLocal(true);
varp->direction(VDirection::INPUT);
funcp->addStmtsp(varp);
}
// The original arg lists were cloned above; delete the orphaned originals
if (constructorArgs) VL_DO_DANGLING(constructorArgs->deleteTree(), constructorArgs);
if (sampleArgs) VL_DO_DANGLING(sampleArgs->deleteTree(), sampleArgs);
}
// Helper to move bins from parser list to coverpoint
void addCoverpointBins(AstCoverpoint* cp, AstNode* binsList) {
if (!binsList) return;

View File

@ -6905,89 +6905,23 @@ covergroup_declaration<nodep>: // ==IEEE: covergroup_declaration
yCOVERGROUP idAny cgPortListE coverage_eventE ';'
/*cont*/ coverage_spec_or_optionListE
/*cont*/ yENDGROUP endLabelE
{ AstClass *cgClassp = new AstClass{$<fl>2, *$2, PARSEP->libname()};
cgClassp->isCovergroup(true);
v3Global.useCovergroup(true);
AstNode* sampleArgs = nullptr;
// coverage_eventE can be either a clocking event or sample arguments
{ AstSenTree* clockp = nullptr;
AstNode* sampleArgsp = nullptr;
if ($4) {
if (VN_IS($4, SenItem)) {
// Clocking event: @(posedge clk)
// Create an AstCovergroup node to hold the clocking event
AstSenTree* senTreep = new AstSenTree{$<fl>1, VN_AS($4, SenItem)};
AstCovergroup* const cgNodep = new AstCovergroup{$<fl>1, *$2, nullptr, senTreep};
cgClassp->addMembersp(cgNodep);
} else {
// Sample arguments: with function sample(...)
sampleArgs = $4;
}
if (VN_IS($4, SenItem))
clockp = new AstSenTree{$<fl>1, VN_AS($4, SenItem)};
else
sampleArgsp = $4;
}
// Convert constructor parameters to member variables
// This must happen BEFORE the covergroup body is added,
// so coverpoints can reference these members
// We iterate carefully to avoid issues with modified AST
if ($3) {
AstNode* nextArgp = nullptr;
for (AstNode* argp = $3; argp; argp = nextArgp) {
nextArgp = argp->nextp(); // Save next before any modifications
if (AstVar* origVarp = VN_CAST(argp, Var)) {
AstVar* memberp = origVarp->cloneTree(false);
memberp->varType(VVarType::MEMBER);
memberp->funcLocal(false);
memberp->direction(VDirection::NONE);
cgClassp->addMembersp(memberp);
}
}
}
// Convert sample parameters to member variables
if (sampleArgs) {
AstNode* nextArgp = nullptr;
for (AstNode* argp = sampleArgs; argp; argp = nextArgp) {
nextArgp = argp->nextp(); // Save next before any modifications
if (AstVar* origVarp = VN_CAST(argp, Var)) {
AstVar* memberp = origVarp->cloneTree(false);
memberp->varType(VVarType::MEMBER);
memberp->funcLocal(false);
memberp->direction(VDirection::NONE);
cgClassp->addMembersp(memberp);
}
}
}
AstFunc* const newp = new AstFunc{$<fl>1, "new", nullptr, nullptr};
newp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
newp->classMethod(true);
newp->isConstructor(true);
newp->dtypep(cgClassp->dtypep());
newp->addStmtsp($6);
cgClassp->addMembersp(newp);
GRAMMARP->createCoverGroupMethods(cgClassp, $3, sampleArgs);
$$ = cgClassp;
GRAMMARP->endLabel($<fl>8, $$, $8);
}
$$ = new AstCovergroup{$<fl>2, *$2, static_cast<AstVar*>($3),
static_cast<AstVar*>(sampleArgsp), $6, clockp};
GRAMMARP->endLabel($<fl>8, $$, $8); }
| yCOVERGROUP yEXTENDS idAny ';'
/*cont*/ coverage_spec_or_optionListE
/*cont*/ yENDGROUP endLabelE
{ BBCOVERIGN($1, "Ignoring unsupported: covergroup inheritance (extends)");
AstClass *cgClassp = new AstClass{$<fl>3, *$3, PARSEP->libname()};
cgClassp->isCovergroup(true);
AstFunc* const newp = new AstFunc{$<fl>1, "new", nullptr, nullptr};
newp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
newp->classMethod(true);
newp->isConstructor(true);
newp->dtypep(cgClassp->dtypep());
newp->addStmtsp($5);
cgClassp->addMembersp(newp);
GRAMMARP->createCoverGroupMethods(cgClassp, nullptr, nullptr);
$$ = cgClassp;
GRAMMARP->endLabel($<fl>7, $$, $7);
}
$$ = new AstCovergroup{$<fl>3, *$3, nullptr, nullptr, $5, nullptr};
GRAMMARP->endLabel($<fl>7, $$, $7); }
;
cgPortListE<nodep>:
@ -7034,43 +6968,43 @@ coverage_option<nodep>: // ==IEEE: coverage_option
cover_point<nodep>: // ==IEEE: cover_point
// // [ [ data_type_or_implicit ] cover_point_identifier ':' ] yCOVERPOINT
yCOVERPOINT expr iffE bins_or_empty
{ auto* cp = new AstCoverpoint{$<fl>1, "", $2};
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>1, "", $2};
if ($3) cp->iffp(VN_AS($3, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $4);
$$ = cp; }
// // IEEE-2012: class_scope before an ID
| id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ auto* cp = new AstCoverpoint{$<fl>3, *$1, $4};
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>3, *$1, $4};
if ($5) cp->iffp(VN_AS($5, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $6);
$$ = cp; }
// // data_type_or_implicit expansion
| data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ auto* cp = new AstCoverpoint{$<fl>4, *$2, $5};
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>4, *$2, $5};
if ($6) cp->iffp(VN_AS($6, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $7);
$$ = cp;
DEL($1); }
| yVAR data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ auto* cp = new AstCoverpoint{$<fl>5, *$3, $6};
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>5, *$3, $6};
if ($7) cp->iffp(VN_AS($7, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $8);
$$ = cp;
DEL($2); }
| yVAR implicit_typeE id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ auto* cp = new AstCoverpoint{$<fl>5, *$3, $6};
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>5, *$3, $6};
if ($7) cp->iffp(VN_AS($7, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $8);
$$ = cp;
DEL($2); }
| signingE rangeList id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ auto* cp = new AstCoverpoint{$<fl>5, *$3, $6};
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>5, *$3, $6};
if ($7) cp->iffp(VN_AS($7, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $8);
$$ = cp;
DEL($2); }
| signing id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ auto* cp = new AstCoverpoint{$<fl>4, *$2, $5};
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>4, *$2, $5};
if ($6) cp->iffp(VN_AS($6, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $7);
$$ = cp; }
@ -7161,23 +7095,17 @@ bins_or_options<nodep>: // ==IEEE: bins_or_options
//
// // cgexpr part of trans_list
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
{
FileLine* isArray = $<fl>3;
$$ = new AstCoverBin{$<fl>2, *$2, static_cast<AstCoverTransSet*>($5), false, false, isArray != nullptr};
DEL($6);
}
{ FileLine* isArray = $<fl>3;
$$ = new AstCoverBin{$<fl>2, *$2, static_cast<AstCoverTransSet*>($5), false, false, isArray != nullptr};
DEL($6); }
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
{
FileLine* isArray = $<fl>3;
$$ = new AstCoverBin{$<fl>2, *$2, static_cast<AstCoverTransSet*>($5), true, false, isArray != nullptr};
DEL($6);
}
{ FileLine* isArray = $<fl>3;
$$ = new AstCoverBin{$<fl>2, *$2, static_cast<AstCoverTransSet*>($5), true, false, isArray != nullptr};
DEL($6); }
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
{
FileLine* isArray = $<fl>3;
$$ = new AstCoverBin{$<fl>2, *$2, static_cast<AstCoverTransSet*>($5), false, true, isArray != nullptr};
DEL($6);
}
{ FileLine* isArray = $<fl>3;
$$ = new AstCoverBin{$<fl>2, *$2, static_cast<AstCoverTransSet*>($5), false, true, isArray != nullptr};
DEL($6); }
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover bin 'wildcard' trans list"); DEL($6, $7);}
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE