2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Parse syntax tree
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2025-01-01 14:30:25 +01:00
|
|
|
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2020-11-14 16:20:27 +01:00
|
|
|
#define YYDEBUG 1 // Nicer errors
|
|
|
|
|
|
2023-09-25 04:12:23 +02:00
|
|
|
#define VL_MT_DISABLED_CODE_UNIT 1
|
|
|
|
|
|
2018-10-27 16:03:28 +02:00
|
|
|
#include "V3Ast.h" // This must be before V3ParseBison.cpp, as we don't want #defines to conflict
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//======================================================================
|
2019-06-12 03:19:44 +02:00
|
|
|
// The guts come from bison output
|
|
|
|
|
|
2009-05-05 03:54:44 +02:00
|
|
|
#include "V3ParseBison.c"
|
2019-06-12 03:19:44 +02:00
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
// V3ParseImp functions requiring bison state
|
|
|
|
|
|
|
|
|
|
int V3ParseImp::bisonParse() {
|
|
|
|
|
// Use --debugi-bison 9 to enable this
|
2020-04-15 13:58:34 +02:00
|
|
|
if (PARSEP->debugBison() >= 9) yydebug = 1;
|
2019-06-12 03:19:44 +02:00
|
|
|
return yyparse();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* V3ParseImp::tokenName(int token) {
|
|
|
|
|
#if YYDEBUG || YYERROR_VERBOSE
|
2020-08-15 16:12:55 +02:00
|
|
|
static const char** nameTablep = nullptr;
|
2019-06-12 03:19:44 +02:00
|
|
|
if (!nameTablep) {
|
|
|
|
|
int size;
|
2020-04-15 13:58:34 +02:00
|
|
|
for (size = 0; yytname[size]; ++size) {}
|
|
|
|
|
nameTablep = new const char*[size];
|
2019-06-12 03:19:44 +02:00
|
|
|
// Workaround bug in bison's which have '!' in yytname but not token values
|
|
|
|
|
int iout = 0;
|
|
|
|
|
for (int i = 0; yytname[i]; ++i) {
|
|
|
|
|
if (yytname[i][0] == '\'') continue;
|
|
|
|
|
nameTablep[iout++] = yytname[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (token >= 255) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return nameTablep[token - 255];
|
2019-06-12 03:19:44 +02:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
static char ch[2];
|
|
|
|
|
ch[0] = token;
|
|
|
|
|
ch[1] = '\0';
|
2019-06-12 03:19:44 +02:00
|
|
|
return ch;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
return "";
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-20 13:20:10 +02:00
|
|
|
void V3ParseImp::candidatePli(VSpellCheck* spellerp) {
|
|
|
|
|
#if !YYERROR_VERBOSE
|
|
|
|
|
#error "Need lex token names"
|
|
|
|
|
#endif
|
|
|
|
|
for (int i = 0; yytname[i]; ++i) {
|
|
|
|
|
if (yytname[i][0] != '\"') continue;
|
|
|
|
|
if (yytname[i][1] != '$') continue;
|
|
|
|
|
spellerp->pushCandidate(string{yytname[i]}.substr(1, strlen(yytname[i]) - 2));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-12 03:19:44 +02:00
|
|
|
void V3ParseImp::parserClear() {
|
|
|
|
|
// Clear up any dynamic memory V3Parser required
|
2020-08-15 16:12:55 +02:00
|
|
|
VARDTYPE(nullptr);
|
2025-09-10 23:42:45 +02:00
|
|
|
GRAMMARP->setNetDelay(nullptr);
|
2025-09-11 13:01:36 +02:00
|
|
|
GRAMMARP->setScopedSigAttr(nullptr);
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
// V3ParseGrammar functions requiring bison state
|
|
|
|
|
|
2022-11-13 21:33:11 +01:00
|
|
|
AstArg* V3ParseGrammar::argWrapList(AstNodeExpr* nodep) {
|
2019-06-12 03:19:44 +02:00
|
|
|
// Convert list of expressions to list of arguments
|
2022-08-29 15:26:00 +02:00
|
|
|
AstArg* outp = nullptr;
|
2020-05-23 17:55:34 +02:00
|
|
|
while (nodep) {
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const nextp = VN_AS(nodep->nextp(), NodeExpr);
|
2025-09-20 19:16:03 +02:00
|
|
|
if (nextp) nextp->unlinkFrBackWithNext();
|
|
|
|
|
outp = AstNode::addNext(outp, new AstArg{nodep->fileline(), "", nodep});
|
2020-05-23 17:55:34 +02:00
|
|
|
nodep = nextp;
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
2020-05-23 17:55:34 +02:00
|
|
|
return outp;
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
|
|
|
|
|
Internals: Make AstAssignW a procedural statement (#6280) (#6556)
Initial idea was to remodel AssignW as Assign under Alway. Trying that
uncovered some issues, the most difficult of them was that a delay
attached to a continuous assignment behaves differently from a delay
attached to a blocking assignment statement, so we need to keep the
knowledge of which flavour an assignment was until V3Timing.
So instead of removing AstAssignW, we always wrap it in an AstAlways,
with a special `keyword()` type. This makes it into a proper procedural
statement, which is almost equivalent to AstAssign, except for the case
when they contain a delay. We still gain the benefits of #6280 and can
simplify some code. Every AstNodeStmt should now be under an
AstNodeProcedure - which we should rename to AstProcess, or an
AstNodeFTask). As a result, V3Table can now handle AssignW for free.
Also uncovered and fixed a bug in handling intra-assignment delays if
a function is present on the RHS of an AssignW.
There is more work to be done towards #6280, and potentially simplifying
AssignW handing, but this is the minimal change required to tick it off
the TODO list for #6280.
2025-10-14 10:05:19 +02:00
|
|
|
AstAssignW* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) {
|
2025-10-03 12:49:13 +02:00
|
|
|
AstAssignW* assignp = new AstAssignW{fileline, new AstParseRef{fileline, name},
|
|
|
|
|
value ? new AstConst{fileline, AstConst::All1{}}
|
|
|
|
|
: new AstConst{fileline, AstConst::All0{}}};
|
2022-09-14 13:39:27 +02:00
|
|
|
AstStrengthSpec* strengthSpecp
|
|
|
|
|
= new AstStrengthSpec{fileline, VStrength::SUPPLY, VStrength::SUPPLY};
|
|
|
|
|
assignp->strengthSpecp(strengthSpecp);
|
|
|
|
|
return assignp;
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
|
|
|
|
|
// Remove any UnsizedRange's from list
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNodeRange *nodep = nrangep, *nextp; nodep; nodep = nextp) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nextp = VN_AS(nodep->nextp(), NodeRange);
|
2019-06-12 03:19:44 +02:00
|
|
|
if (!VN_IS(nodep, Range)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error(
|
2020-12-13 04:43:55 +01:00
|
|
|
"Unsupported or syntax error: Unsized range in instance or other declaration");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-13 01:06:26 +02:00
|
|
|
if (nrangep && nrangep->nextp()) {
|
|
|
|
|
// Not supported by at least 2 of big 3
|
2020-12-13 04:43:55 +01:00
|
|
|
nrangep->nextp()->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"Unsupported: Multidimensional instances/interfaces.");
|
2019-09-13 01:06:26 +02:00
|
|
|
nrangep->nextp()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
|
}
|
2019-06-12 03:19:44 +02:00
|
|
|
return VN_CAST(nrangep, Range);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-10 01:56:09 +02:00
|
|
|
AstNodePreSel* V3ParseGrammar::scrubSel(AstNodeExpr* fromp, AstNodePreSel* selp) VL_MT_DISABLED {
|
|
|
|
|
// SEL(PARSELVALUE, ...) -> SEL(fromp, ...)
|
|
|
|
|
AstNodePreSel* subSelp = selp;
|
|
|
|
|
while (true) {
|
|
|
|
|
if (VN_IS(subSelp->fromp(), ParseHolder)) break;
|
|
|
|
|
if (AstNodePreSel* const lowerSelp = VN_CAST(subSelp->fromp(), NodePreSel)) {
|
|
|
|
|
subSelp = lowerSelp;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
subSelp->v3fatalSrc("Couldn't find where to insert expression into select");
|
|
|
|
|
}
|
|
|
|
|
AstNode* subSelFromp = subSelp->fromp();
|
|
|
|
|
subSelFromp->replaceWith(fromp);
|
|
|
|
|
VL_DO_DANGLING(subSelFromp->deleteTree(), subSelFromp);
|
|
|
|
|
return selp;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nrangep,
|
|
|
|
|
bool isPacked) {
|
2019-06-12 03:19:44 +02:00
|
|
|
// Split RANGE0-RANGE1-RANGE2
|
|
|
|
|
// into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3), RANGE), RANGE)
|
|
|
|
|
AstNodeDType* arrayp = basep;
|
|
|
|
|
if (nrangep) { // Maybe no range - return unmodified base type
|
2021-10-22 14:56:48 +02:00
|
|
|
while (nrangep->nextp()) nrangep = VN_AS(nrangep->nextp(), NodeRange);
|
2019-06-12 03:19:44 +02:00
|
|
|
while (nrangep) {
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeRange* const prevp = VN_AS(nrangep->backp(), NodeRange);
|
2019-06-12 03:19:44 +02:00
|
|
|
if (prevp) nrangep->unlinkFrBack();
|
2021-11-13 19:50:44 +01:00
|
|
|
AstRange* const rangep = VN_CAST(nrangep, Range);
|
2019-12-01 12:09:58 +01:00
|
|
|
if (rangep && isPacked) {
|
2020-04-15 13:58:34 +02:00
|
|
|
arrayp
|
2022-11-20 21:06:49 +01:00
|
|
|
= new AstPackArrayDType{rangep->fileline(), VFlagChildDType{}, arrayp, rangep};
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (rangep
|
|
|
|
|
&& (VN_IS(rangep->leftp(), Unbounded)
|
|
|
|
|
|| VN_IS(rangep->rightp(), Unbounded))) {
|
2022-11-20 21:06:49 +01:00
|
|
|
arrayp = new AstQueueDType{nrangep->fileline(), VFlagChildDType{}, arrayp,
|
2022-11-19 20:45:33 +01:00
|
|
|
rangep->rightp()->cloneTree(true)};
|
2025-09-10 23:42:45 +02:00
|
|
|
VL_DO_DANGLING(nrangep->deleteTree(), nrangep);
|
2019-12-08 21:56:49 +01:00
|
|
|
} else if (rangep) {
|
2022-11-19 20:45:33 +01:00
|
|
|
arrayp = new AstUnpackArrayDType{rangep->fileline(), VFlagChildDType{}, arrayp,
|
|
|
|
|
rangep};
|
2019-12-01 12:09:58 +01:00
|
|
|
} else if (VN_IS(nrangep, UnsizedRange)) {
|
2024-06-09 04:44:45 +02:00
|
|
|
arrayp = new AstDynArrayDType{nrangep->fileline(), VFlagChildDType{}, arrayp};
|
2022-12-29 19:59:24 +01:00
|
|
|
VL_DO_DANGLING(nrangep->deleteTree(), nrangep);
|
2020-06-09 13:13:40 +02:00
|
|
|
} else if (VN_IS(nrangep, BracketRange)) {
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstBracketRange* const arangep = VN_AS(nrangep, BracketRange);
|
|
|
|
|
AstNode* const keyp = arangep->elementsp()->unlinkFrBack();
|
2022-11-19 20:45:33 +01:00
|
|
|
arrayp = new AstBracketArrayDType{nrangep->fileline(), VFlagChildDType{}, arrayp,
|
|
|
|
|
keyp};
|
2022-12-29 19:59:24 +01:00
|
|
|
VL_DO_DANGLING(nrangep->deleteTree(), nrangep);
|
2022-07-20 15:01:36 +02:00
|
|
|
} else if (VN_IS(nrangep, WildcardRange)) {
|
|
|
|
|
arrayp = new AstWildcardArrayDType{nrangep->fileline(), VFlagChildDType{}, arrayp};
|
2022-12-29 19:59:24 +01:00
|
|
|
VL_DO_DANGLING(nrangep->deleteTree(), nrangep);
|
2019-12-01 12:09:58 +01:00
|
|
|
} else {
|
|
|
|
|
UASSERT_OBJ(0, nrangep, "Expected range or unsized range");
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
|
|
|
|
nrangep = prevp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return arrayp;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-06 14:20:02 +02:00
|
|
|
AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
|
2019-06-12 03:19:44 +02:00
|
|
|
AstNodeRange* arrayp, AstNode* attrsp) {
|
2025-09-10 23:42:45 +02:00
|
|
|
UINFO(5, " creVar " << name << " decl=" << GRAMMARP->m_varDecl << " io="
|
|
|
|
|
<< GRAMMARP->m_varIO << " dt=" << (GRAMMARP->m_varDTypep ? "set" : ""));
|
2024-12-02 13:21:24 +01:00
|
|
|
if (GRAMMARP->m_varIO == VDirection::NONE // In non-ANSI port list
|
|
|
|
|
&& GRAMMARP->m_varDecl == VVarType::PORT) {
|
2019-06-12 03:19:44 +02:00
|
|
|
// Just a port list with variable name (not v2k format); AstPort already created
|
2024-03-23 23:12:43 +01:00
|
|
|
if (arrayp) VL_DO_DANGLING(arrayp->deleteTree(), arrayp);
|
|
|
|
|
if (attrsp) {
|
|
|
|
|
// TODO: Merge attributes across list? Or warn attribute is ignored
|
|
|
|
|
VL_DO_DANGLING(attrsp->deleteTree(), attrsp);
|
|
|
|
|
}
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
2025-09-10 23:42:45 +02:00
|
|
|
|
|
|
|
|
AstNodeDType* const dtypep = [&]() -> AstNodeDType* {
|
|
|
|
|
if (GRAMMARP->m_varDecl == VVarType::WREAL) {
|
|
|
|
|
// dtypep might not be null, might be implicit LOGIC before we knew better
|
|
|
|
|
return new AstBasicDType{fileline, VBasicDTypeKwd::DOUBLE};
|
|
|
|
|
}
|
|
|
|
|
if (GRAMMARP->m_varDTypep) {
|
|
|
|
|
// May make new variables with same type, so clone
|
|
|
|
|
return GRAMMARP->m_varDTypep->cloneTree(false);
|
|
|
|
|
}
|
|
|
|
|
// Created implicitly
|
2022-11-01 23:53:47 +01:00
|
|
|
if (m_insideProperty) {
|
|
|
|
|
if (m_typedPropertyPort) {
|
|
|
|
|
fileline->v3warn(E_UNSUPPORTED, "Untyped property port following a typed port");
|
|
|
|
|
}
|
2025-09-10 23:42:45 +02:00
|
|
|
return new AstBasicDType{fileline, VBasicDTypeKwd::UNTYPED};
|
2022-11-01 23:53:47 +01:00
|
|
|
}
|
2025-09-10 23:42:45 +02:00
|
|
|
return new AstBasicDType{fileline, LOGIC_IMPLICIT};
|
|
|
|
|
}();
|
|
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
// UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<"
|
|
|
|
|
// io="<<GRAMMARP->m_varIO.ascii()<<endl);
|
2022-01-02 19:56:40 +01:00
|
|
|
VVarType type = GRAMMARP->m_varDecl;
|
2024-12-02 13:21:24 +01:00
|
|
|
if (type == VVarType::UNKNOWN) { // e.g. "output" non-ANSI standalone direction (vs "reg")
|
2019-06-12 03:19:44 +02:00
|
|
|
if (GRAMMARP->m_varIO.isAny()) {
|
2022-01-02 19:56:40 +01:00
|
|
|
type = VVarType::PORT;
|
2019-06-12 03:19:44 +02:00
|
|
|
} else {
|
2020-06-06 14:50:47 +02:00
|
|
|
fileline->v3fatalSrc("Unknown signal type declared: " << type.ascii());
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-01-02 19:56:40 +01:00
|
|
|
if (type == VVarType::GENVAR) {
|
2022-12-03 00:46:38 +01:00
|
|
|
// Should be impossible as the grammar blocks this, but...
|
2022-10-22 22:03:42 +02:00
|
|
|
if (arrayp) fileline->v3error("Genvars may not be arrayed: " << name); // LCOV_EXCL_LINE
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Split RANGE0-RANGE1-RANGE2 into
|
|
|
|
|
// ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3), RANGE), RANGE)
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeDType* const arrayDTypep = createArray(dtypep, arrayp, false);
|
2019-06-12 03:19:44 +02:00
|
|
|
|
2022-11-19 20:45:33 +01:00
|
|
|
AstVar* const nodep = new AstVar{fileline, type, name, VFlagChildDType(), arrayDTypep};
|
2019-06-12 03:19:44 +02:00
|
|
|
nodep->addAttrsp(attrsp);
|
2019-06-22 18:43:48 +02:00
|
|
|
nodep->ansi(m_pinAnsi);
|
|
|
|
|
nodep->declTyped(m_varDeclTyped);
|
2020-04-26 18:45:06 +02:00
|
|
|
nodep->lifetime(m_varLifetime);
|
2025-09-10 23:42:45 +02:00
|
|
|
if (m_netDelayp) nodep->delayp(m_netDelayp->cloneTree(false));
|
2022-01-02 19:56:40 +01:00
|
|
|
if (GRAMMARP->m_varDecl != VVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl);
|
2019-06-12 03:19:44 +02:00
|
|
|
if (GRAMMARP->m_varIO != VDirection::NONE) {
|
|
|
|
|
nodep->declDirection(GRAMMARP->m_varIO);
|
|
|
|
|
nodep->direction(GRAMMARP->m_varIO);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
if (GRAMMARP->m_varDecl == VVarType::SUPPLY0) {
|
Internals: Make AstAssignW a procedural statement (#6280) (#6556)
Initial idea was to remodel AssignW as Assign under Alway. Trying that
uncovered some issues, the most difficult of them was that a delay
attached to a continuous assignment behaves differently from a delay
attached to a blocking assignment statement, so we need to keep the
knowledge of which flavour an assignment was until V3Timing.
So instead of removing AstAssignW, we always wrap it in an AstAlways,
with a special `keyword()` type. This makes it into a proper procedural
statement, which is almost equivalent to AstAssign, except for the case
when they contain a delay. We still gain the benefits of #6280 and can
simplify some code. Every AstNodeStmt should now be under an
AstNodeProcedure - which we should rename to AstProcess, or an
AstNodeFTask). As a result, V3Table can now handle AssignW for free.
Also uncovered and fixed a bug in handling intra-assignment delays if
a function is present on the RHS of an AssignW.
There is more work to be done towards #6280, and potentially simplifying
AssignW handing, but this is the minimal change required to tick it off
the TODO list for #6280.
2025-10-14 10:05:19 +02:00
|
|
|
AstAssignW* const ap = V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 0);
|
|
|
|
|
AstNode::addNext<AstNode, AstNode>(nodep, new AstAlways{ap});
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
2022-01-02 19:56:40 +01:00
|
|
|
if (GRAMMARP->m_varDecl == VVarType::SUPPLY1) {
|
Internals: Make AstAssignW a procedural statement (#6280) (#6556)
Initial idea was to remodel AssignW as Assign under Alway. Trying that
uncovered some issues, the most difficult of them was that a delay
attached to a continuous assignment behaves differently from a delay
attached to a blocking assignment statement, so we need to keep the
knowledge of which flavour an assignment was until V3Timing.
So instead of removing AstAssignW, we always wrap it in an AstAlways,
with a special `keyword()` type. This makes it into a proper procedural
statement, which is almost equivalent to AstAssign, except for the case
when they contain a delay. We still gain the benefits of #6280 and can
simplify some code. Every AstNodeStmt should now be under an
AstNodeProcedure - which we should rename to AstProcess, or an
AstNodeFTask). As a result, V3Table can now handle AssignW for free.
Also uncovered and fixed a bug in handling intra-assignment delays if
a function is present on the RHS of an AssignW.
There is more work to be done towards #6280, and potentially simplifying
AssignW handing, but this is the minimal change required to tick it off
the TODO list for #6280.
2025-10-14 10:05:19 +02:00
|
|
|
AstAssignW* const ap = V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 1);
|
|
|
|
|
AstNode::addNext<AstNode, AstNode>(nodep, new AstAlways{ap});
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
|
|
|
|
if (VN_IS(dtypep, ParseTypeDType)) {
|
|
|
|
|
// Parser needs to know what is a type
|
2025-07-26 23:11:35 +02:00
|
|
|
AstNode* const newp = new AstTypedefFwd{fileline, name, VFwdType::NONE};
|
2022-09-17 14:48:51 +02:00
|
|
|
AstNode::addNext<AstNode, AstNode>(nodep, newp);
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
|
|
|
|
// Don't set dtypep in the ranging;
|
|
|
|
|
// We need to autosize parameters and integers separately
|
|
|
|
|
//
|
|
|
|
|
// Propagate from current module tracing state
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->isGenVar()) {
|
|
|
|
|
nodep->trace(false);
|
|
|
|
|
} else if (nodep->isParam() && !v3Global.opt.traceParams()) {
|
|
|
|
|
nodep->trace(false);
|
|
|
|
|
} else {
|
|
|
|
|
nodep->trace(allTracingOn(nodep->fileline()));
|
|
|
|
|
}
|
2024-03-27 22:57:49 +01:00
|
|
|
if (nodep->varType().isVPIAccessible()) nodep->addAttrsp(GRAMMARP->cloneScopedSigAttr());
|
2019-06-12 03:19:44 +02:00
|
|
|
|
|
|
|
|
// Remember the last variable created, so we can attach attributes to it in later parsing
|
|
|
|
|
GRAMMARP->m_varAttrp = nodep;
|
|
|
|
|
PARSEP->tagNodep(GRAMMARP->m_varAttrp);
|
|
|
|
|
return nodep;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 10:43:37 +02:00
|
|
|
string V3ParseGrammar::unquoteString(FileLine* fileline, const std::string& text) {
|
2023-09-26 21:42:15 +02:00
|
|
|
string errMsg;
|
|
|
|
|
string res = VString::unquoteSVString(text, errMsg);
|
|
|
|
|
if (!errMsg.empty()) fileline->v3error(errMsg.c_str());
|
|
|
|
|
return res;
|
2019-06-12 03:19:44 +02:00
|
|
|
}
|
2025-09-09 16:47:45 +02:00
|
|
|
|
|
|
|
|
int V3ParseGrammar::s_typeImpNum = 0;
|