2012-04-13 01:08:20 +00:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 11:35:28 +00:00
|
|
|
//*************************************************************************
|
|
|
|
// DESCRIPTION: Verilator: Parse syntax tree
|
|
|
|
//
|
2019-11-08 03:33:59 +00:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
//
|
2022-01-01 13:26:40 +00:00
|
|
|
// Copyright 2003-2022 by Wilson Snyder. This program is free software; you
|
2020-03-21 15:24:24 +00:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 21:07:57 +00:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
// Version 2.0.
|
2020-03-21 15:24:24 +00:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
//*************************************************************************
|
2019-10-05 00:17:11 +00:00
|
|
|
|
2020-11-14 15:20:27 +00:00
|
|
|
#define YYDEBUG 1 // Nicer errors
|
|
|
|
|
2018-10-27 14:03:28 +00:00
|
|
|
#include "V3Ast.h" // This must be before V3ParseBison.cpp, as we don't want #defines to conflict
|
2006-08-26 11:35:28 +00:00
|
|
|
|
2022-09-18 19:53:42 +00:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
//======================================================================
|
2019-06-12 01:19:44 +00:00
|
|
|
// The guts come from bison output
|
|
|
|
|
2009-05-05 01:54:44 +00:00
|
|
|
#include "V3ParseBison.c"
|
2019-06-12 01:19:44 +00:00
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// V3ParseImp functions requiring bison state
|
|
|
|
|
|
|
|
int V3ParseImp::bisonParse() {
|
|
|
|
// Use --debugi-bison 9 to enable this
|
2020-04-15 11:58:34 +00:00
|
|
|
if (PARSEP->debugBison() >= 9) yydebug = 1;
|
2019-06-12 01:19:44 +00:00
|
|
|
return yyparse();
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* V3ParseImp::tokenName(int token) {
|
|
|
|
#if YYDEBUG || YYERROR_VERBOSE
|
2020-08-15 14:12:55 +00:00
|
|
|
static const char** nameTablep = nullptr;
|
2019-06-12 01:19:44 +00:00
|
|
|
if (!nameTablep) {
|
|
|
|
int size;
|
2020-04-15 11:58:34 +00:00
|
|
|
for (size = 0; yytname[size]; ++size) {}
|
|
|
|
nameTablep = new const char*[size];
|
2019-06-12 01:19:44 +00: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 11:58:34 +00:00
|
|
|
return nameTablep[token - 255];
|
2019-06-12 01:19:44 +00:00
|
|
|
} else {
|
2020-04-15 11:58:34 +00:00
|
|
|
static char ch[2];
|
|
|
|
ch[0] = token;
|
|
|
|
ch[1] = '\0';
|
2019-06-12 01:19:44 +00:00
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
return "";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void V3ParseImp::parserClear() {
|
|
|
|
// Clear up any dynamic memory V3Parser required
|
2020-08-15 14:12:55 +00:00
|
|
|
VARDTYPE(nullptr);
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// V3ParseGrammar functions requiring bison state
|
|
|
|
|
2022-08-29 13:26:00 +00:00
|
|
|
AstArg* V3ParseGrammar::argWrapList(AstNode* nodep) {
|
2019-06-12 01:19:44 +00:00
|
|
|
// Convert list of expressions to list of arguments
|
2020-08-15 14:12:55 +00:00
|
|
|
if (!nodep) return nullptr;
|
2022-08-29 13:26:00 +00:00
|
|
|
AstArg* outp = nullptr;
|
2021-11-13 18:50:44 +00:00
|
|
|
AstBegin* const tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
|
2020-05-23 15:55:34 +00:00
|
|
|
while (nodep) {
|
2021-11-13 18:50:44 +00:00
|
|
|
AstNode* const nextp = nodep->nextp();
|
|
|
|
AstNode* const exprp = nodep->unlinkFrBack();
|
2020-05-23 15:55:34 +00:00
|
|
|
nodep = nextp;
|
2019-06-12 01:19:44 +00:00
|
|
|
outp = AstNode::addNext(outp, new AstArg(exprp->fileline(), "", exprp));
|
|
|
|
}
|
2020-05-23 15:55:34 +00:00
|
|
|
VL_DO_DANGLING(tempp->deleteTree(), tempp);
|
|
|
|
return outp;
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
|
|
|
|
2019-10-06 12:20:02 +00:00
|
|
|
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) {
|
2022-09-14 11:39:27 +00:00
|
|
|
AstAssignW* assignp
|
|
|
|
= new AstAssignW{fileline, new AstVarRef{fileline, name, VAccess::WRITE},
|
|
|
|
new AstConst{fileline, AstConst::StringToParse{}, (value ? "'1" : "'0")}};
|
|
|
|
AstStrengthSpec* strengthSpecp
|
|
|
|
= new AstStrengthSpec{fileline, VStrength::SUPPLY, VStrength::SUPPLY};
|
|
|
|
assignp->strengthSpecp(strengthSpecp);
|
|
|
|
return assignp;
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
|
|
|
|
// Remove any UnsizedRange's from list
|
2020-04-15 11:58:34 +00:00
|
|
|
for (AstNodeRange *nodep = nrangep, *nextp; nodep; nodep = nextp) {
|
2021-10-22 12:56:48 +00:00
|
|
|
nextp = VN_AS(nodep->nextp(), NodeRange);
|
2019-06-12 01:19:44 +00:00
|
|
|
if (!VN_IS(nodep, Range)) {
|
2020-04-15 11:58:34 +00:00
|
|
|
nodep->v3error(
|
2020-12-13 03:43:55 +00:00
|
|
|
"Unsupported or syntax error: Unsized range in instance or other declaration");
|
2020-04-15 11:58:34 +00:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-12 23:06:26 +00:00
|
|
|
if (nrangep && nrangep->nextp()) {
|
|
|
|
// Not supported by at least 2 of big 3
|
2020-12-13 03:43:55 +00:00
|
|
|
nrangep->nextp()->v3warn(E_UNSUPPORTED,
|
|
|
|
"Unsupported: Multidimensional instances/interfaces.");
|
2019-09-12 23:06:26 +00:00
|
|
|
nrangep->nextp()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
}
|
2019-06-12 01:19:44 +00:00
|
|
|
return VN_CAST(nrangep, Range);
|
|
|
|
}
|
|
|
|
|
2020-04-15 11:58:34 +00:00
|
|
|
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nrangep,
|
|
|
|
bool isPacked) {
|
2019-06-12 01:19:44 +00: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 12:56:48 +00:00
|
|
|
while (nrangep->nextp()) nrangep = VN_AS(nrangep->nextp(), NodeRange);
|
2019-06-12 01:19:44 +00:00
|
|
|
while (nrangep) {
|
2021-11-13 18:50:44 +00:00
|
|
|
AstNodeRange* const prevp = VN_AS(nrangep->backp(), NodeRange);
|
2019-06-12 01:19:44 +00:00
|
|
|
if (prevp) nrangep->unlinkFrBack();
|
2021-11-13 18:50:44 +00:00
|
|
|
AstRange* const rangep = VN_CAST(nrangep, Range);
|
2019-12-01 11:09:58 +00:00
|
|
|
if (rangep && isPacked) {
|
2020-04-15 11:58:34 +00:00
|
|
|
arrayp
|
|
|
|
= new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
|
|
|
|
} else if (rangep
|
|
|
|
&& (VN_IS(rangep->leftp(), Unbounded)
|
|
|
|
|| VN_IS(rangep->rightp(), Unbounded))) {
|
2019-12-15 02:39:47 +00:00
|
|
|
arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp,
|
|
|
|
rangep->rightp()->cloneTree(true));
|
2019-12-08 20:56:49 +00:00
|
|
|
} else if (rangep) {
|
2020-04-15 11:58:34 +00:00
|
|
|
arrayp = new AstUnpackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp,
|
|
|
|
rangep);
|
2019-12-01 11:09:58 +00:00
|
|
|
} else if (VN_IS(nrangep, UnsizedRange)) {
|
2020-04-15 11:58:34 +00:00
|
|
|
arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp);
|
2020-06-09 11:13:40 +00:00
|
|
|
} else if (VN_IS(nrangep, BracketRange)) {
|
2021-11-13 18:50:44 +00:00
|
|
|
const AstBracketRange* const arangep = VN_AS(nrangep, BracketRange);
|
|
|
|
AstNode* const keyp = arangep->elementsp()->unlinkFrBack();
|
2020-06-09 11:13:40 +00:00
|
|
|
arrayp = new AstBracketArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp,
|
|
|
|
keyp);
|
2022-07-20 13:01:36 +00:00
|
|
|
} else if (VN_IS(nrangep, WildcardRange)) {
|
|
|
|
arrayp = new AstWildcardArrayDType{nrangep->fileline(), VFlagChildDType{}, arrayp};
|
2019-12-01 11:09:58 +00:00
|
|
|
} else {
|
|
|
|
UASSERT_OBJ(0, nrangep, "Expected range or unsized range");
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
|
|
|
nrangep = prevp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return arrayp;
|
|
|
|
}
|
|
|
|
|
2019-10-06 12:20:02 +00:00
|
|
|
AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
|
2019-06-12 01:19:44 +00:00
|
|
|
AstNodeRange* arrayp, AstNode* attrsp) {
|
|
|
|
AstNodeDType* dtypep = GRAMMARP->m_varDTypep;
|
2020-04-15 11:58:34 +00:00
|
|
|
UINFO(5, " creVar " << name << " decl=" << GRAMMARP->m_varDecl << " io="
|
|
|
|
<< GRAMMARP->m_varIO << " dt=" << (dtypep ? "set" : "") << endl);
|
2022-01-02 18:56:40 +00:00
|
|
|
if (GRAMMARP->m_varIO == VDirection::NONE && GRAMMARP->m_varDecl == VVarType::PORT) {
|
2019-06-12 01:19:44 +00:00
|
|
|
// Just a port list with variable name (not v2k format); AstPort already created
|
2020-06-09 23:20:16 +00:00
|
|
|
if (dtypep) fileline->v3warn(E_UNSUPPORTED, "Unsupported: Ranges ignored in port-lists");
|
2020-08-15 14:12:55 +00:00
|
|
|
return nullptr;
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
2022-01-02 18:56:40 +00:00
|
|
|
if (GRAMMARP->m_varDecl == VVarType::WREAL) {
|
2019-06-12 01:19:44 +00:00
|
|
|
// dtypep might not be null, might be implicit LOGIC before we knew better
|
2022-01-02 18:56:40 +00:00
|
|
|
dtypep = new AstBasicDType(fileline, VBasicDTypeKwd::DOUBLE);
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
|
|
|
if (!dtypep) { // Created implicitly
|
|
|
|
dtypep = new AstBasicDType(fileline, LOGIC_IMPLICIT);
|
|
|
|
} else { // May make new variables with same type, so clone
|
|
|
|
dtypep = dtypep->cloneTree(false);
|
|
|
|
}
|
2020-04-15 11:58:34 +00:00
|
|
|
// UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<"
|
|
|
|
// io="<<GRAMMARP->m_varIO.ascii()<<endl);
|
2022-01-02 18:56:40 +00:00
|
|
|
VVarType type = GRAMMARP->m_varDecl;
|
|
|
|
if (type == VVarType::UNKNOWN) {
|
2019-06-12 01:19:44 +00:00
|
|
|
if (GRAMMARP->m_varIO.isAny()) {
|
2022-01-02 18:56:40 +00:00
|
|
|
type = VVarType::PORT;
|
2019-06-12 01:19:44 +00:00
|
|
|
} else {
|
2020-06-06 12:50:47 +00:00
|
|
|
fileline->v3fatalSrc("Unknown signal type declared: " << type.ascii());
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-02 18:56:40 +00:00
|
|
|
if (type == VVarType::GENVAR) {
|
2022-10-22 20:03:42 +00:00
|
|
|
// Should be impossible as the grammer blocks this, but...
|
|
|
|
if (arrayp) fileline->v3error("Genvars may not be arrayed: " << name); // LCOV_EXCL_LINE
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Split RANGE0-RANGE1-RANGE2 into
|
|
|
|
// ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3), RANGE), RANGE)
|
2021-11-13 18:50:44 +00:00
|
|
|
AstNodeDType* const arrayDTypep = createArray(dtypep, arrayp, false);
|
2019-06-12 01:19:44 +00:00
|
|
|
|
2021-11-13 18:50:44 +00:00
|
|
|
AstVar* const nodep = new AstVar(fileline, type, name, VFlagChildDType(), arrayDTypep);
|
2019-06-12 01:19:44 +00:00
|
|
|
nodep->addAttrsp(attrsp);
|
2019-06-22 16:43:48 +00:00
|
|
|
nodep->ansi(m_pinAnsi);
|
|
|
|
nodep->declTyped(m_varDeclTyped);
|
2020-04-26 16:45:06 +00:00
|
|
|
nodep->lifetime(m_varLifetime);
|
2022-05-17 18:19:44 +00:00
|
|
|
nodep->delayp(m_netDelayp);
|
|
|
|
m_netDelayp = nullptr;
|
2022-01-02 18:56:40 +00:00
|
|
|
if (GRAMMARP->m_varDecl != VVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl);
|
2019-06-12 01:19:44 +00:00
|
|
|
if (GRAMMARP->m_varIO != VDirection::NONE) {
|
|
|
|
nodep->declDirection(GRAMMARP->m_varIO);
|
|
|
|
nodep->direction(GRAMMARP->m_varIO);
|
|
|
|
}
|
|
|
|
|
2022-01-02 18:56:40 +00:00
|
|
|
if (GRAMMARP->m_varDecl == VVarType::SUPPLY0) {
|
2022-09-17 12:48:51 +00:00
|
|
|
AstNode::addNext<AstNode, AstNode>(
|
|
|
|
nodep, V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 0));
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
2022-01-02 18:56:40 +00:00
|
|
|
if (GRAMMARP->m_varDecl == VVarType::SUPPLY1) {
|
2022-09-17 12:48:51 +00:00
|
|
|
AstNode::addNext<AstNode, AstNode>(
|
|
|
|
nodep, V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 1));
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
|
|
|
if (VN_IS(dtypep, ParseTypeDType)) {
|
|
|
|
// Parser needs to know what is a type
|
2021-11-13 18:50:44 +00:00
|
|
|
AstNode* const newp = new AstTypedefFwd(fileline, name);
|
2022-09-17 12:48:51 +00:00
|
|
|
AstNode::addNext<AstNode, AstNode>(nodep, newp);
|
2019-06-12 01:19:44 +00:00
|
|
|
SYMP->reinsert(newp);
|
|
|
|
}
|
|
|
|
// Don't set dtypep in the ranging;
|
|
|
|
// We need to autosize parameters and integers separately
|
|
|
|
//
|
|
|
|
// Propagate from current module tracing state
|
2020-04-15 11:58:34 +00:00
|
|
|
if (nodep->isGenVar()) {
|
|
|
|
nodep->trace(false);
|
|
|
|
} else if (nodep->isParam() && !v3Global.opt.traceParams()) {
|
|
|
|
nodep->trace(false);
|
|
|
|
} else {
|
|
|
|
nodep->trace(allTracingOn(nodep->fileline()));
|
|
|
|
}
|
2019-06-12 01:19:44 +00: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;
|
|
|
|
}
|
|
|
|
|
|
|
|
string V3ParseGrammar::deQuote(FileLine* fileline, string text) {
|
|
|
|
// Fix up the quoted strings the user put in, for example "\"" becomes "
|
|
|
|
// Reverse is V3OutFormatter::quoteNameControls(...)
|
|
|
|
bool quoted = false;
|
|
|
|
string newtext;
|
|
|
|
unsigned char octal_val = 0;
|
|
|
|
int octal_digits = 0;
|
|
|
|
for (string::const_iterator cp = text.begin(); cp != text.end(); ++cp) {
|
|
|
|
if (quoted) {
|
|
|
|
if (isdigit(*cp)) {
|
2020-04-15 11:58:34 +00:00
|
|
|
octal_val = octal_val * 8 + (*cp - '0');
|
2019-06-12 01:19:44 +00:00
|
|
|
if (++octal_digits == 3) {
|
|
|
|
octal_digits = 0;
|
|
|
|
quoted = false;
|
|
|
|
newtext += octal_val;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (octal_digits) {
|
|
|
|
// Spec allows 1-3 digits
|
|
|
|
octal_digits = 0;
|
|
|
|
quoted = false;
|
|
|
|
newtext += octal_val;
|
|
|
|
--cp; // Backup to reprocess terminating character as non-escaped
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
quoted = false;
|
2020-04-15 11:58:34 +00:00
|
|
|
if (*cp == 'n') {
|
|
|
|
newtext += '\n';
|
|
|
|
} else if (*cp == 'a') {
|
|
|
|
newtext += '\a'; // SystemVerilog 3.1
|
|
|
|
} else if (*cp == 'f') {
|
|
|
|
newtext += '\f'; // SystemVerilog 3.1
|
|
|
|
} else if (*cp == 'r') {
|
|
|
|
newtext += '\r';
|
|
|
|
} else if (*cp == 't') {
|
|
|
|
newtext += '\t';
|
|
|
|
} else if (*cp == 'v') {
|
|
|
|
newtext += '\v'; // SystemVerilog 3.1
|
|
|
|
} else if (*cp == 'x' && isxdigit(cp[1])
|
|
|
|
&& isxdigit(cp[2])) { // SystemVerilog 3.1
|
|
|
|
#define vl_decodexdigit(c) ((isdigit(c) ? ((c) - '0') : (tolower((c)) - 'a' + 10)))
|
2022-07-30 15:52:35 +00:00
|
|
|
newtext
|
|
|
|
+= static_cast<char>(16 * vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2]));
|
2019-06-12 01:19:44 +00:00
|
|
|
cp += 2;
|
2020-04-15 11:58:34 +00:00
|
|
|
} else if (isalnum(*cp)) {
|
|
|
|
fileline->v3error("Unknown escape sequence: \\" << *cp);
|
2019-06-12 01:19:44 +00:00
|
|
|
break;
|
2022-01-08 17:01:39 +00:00
|
|
|
} else {
|
2020-04-15 11:58:34 +00:00
|
|
|
newtext += *cp;
|
2022-01-08 17:01:39 +00:00
|
|
|
}
|
2019-06-12 01:19:44 +00:00
|
|
|
}
|
2020-04-15 11:58:34 +00:00
|
|
|
} else if (*cp == '\\') {
|
2019-06-12 01:19:44 +00:00
|
|
|
quoted = true;
|
|
|
|
octal_digits = 0;
|
2020-04-15 11:58:34 +00:00
|
|
|
} else if (*cp != '"') {
|
2019-06-12 01:19:44 +00:00
|
|
|
newtext += *cp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newtext;
|
|
|
|
}
|