Fix '' with multiple format strings
This commit is contained in:
parent
b99b3d7b9c
commit
9dfc050fb5
|
|
@ -308,106 +308,75 @@ class LinkResolveVisitor final : public VNVisitor {
|
|||
bool inPct = false;
|
||||
bool inIgnore = false;
|
||||
string fmt;
|
||||
for (const char ch : format) {
|
||||
if (!inPct && ch == '%') {
|
||||
inPct = true;
|
||||
inIgnore = false;
|
||||
fmt = ch;
|
||||
} else if (inPct && (std::isdigit(ch) || ch == '.' || ch == '-')) {
|
||||
fmt += ch;
|
||||
} else if (inPct) {
|
||||
inPct = false;
|
||||
fmt += ch;
|
||||
switch (std::tolower(ch)) {
|
||||
case '%': // %% - just output a %
|
||||
break;
|
||||
case '*':
|
||||
string parseFormat = format;
|
||||
while (!parseFormat.empty() || argp) {
|
||||
for (const char ch : parseFormat) {
|
||||
if (!inPct && ch == '%') {
|
||||
inPct = true;
|
||||
inIgnore = true;
|
||||
break;
|
||||
case 'm': // %m - auto insert "name"
|
||||
if (isScan) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: %m in $fscanf");
|
||||
fmt = "";
|
||||
}
|
||||
break;
|
||||
case 'l': // %l - auto insert "library"
|
||||
if (isScan) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: %l in $fscanf");
|
||||
fmt = "";
|
||||
}
|
||||
if (m_modp)
|
||||
fmt = AstNode::prettyName(m_modp->libname()) + "." + m_modp->prettyName();
|
||||
break;
|
||||
default: // Most operators, just move to next argument
|
||||
if (!V3Number::displayedFmtLegal(ch, isScan)) {
|
||||
nodep->v3error("Unknown $display-like format code: '%" << ch << "'");
|
||||
} else if (!inIgnore) {
|
||||
if (!argp) {
|
||||
nodep->v3error("Missing arguments for $display-like format");
|
||||
} else {
|
||||
argp = argp->nextp();
|
||||
inIgnore = false;
|
||||
fmt = ch;
|
||||
} else if (inPct && (std::isdigit(ch) || ch == '.' || ch == '-')) {
|
||||
fmt += ch;
|
||||
} else if (inPct) {
|
||||
inPct = false;
|
||||
fmt += ch;
|
||||
switch (std::tolower(ch)) {
|
||||
case '%': // %% - just output a %
|
||||
break;
|
||||
case '*':
|
||||
inPct = true;
|
||||
inIgnore = true;
|
||||
break;
|
||||
case 'm': // %m - auto insert "name"
|
||||
if (isScan) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: %m in $fscanf");
|
||||
fmt = "";
|
||||
}
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
newFormat += fmt;
|
||||
} else {
|
||||
newFormat += ch;
|
||||
}
|
||||
}
|
||||
|
||||
if (argp && !isScan) {
|
||||
int skipCount = 0; // number of args consume by any additional format strings
|
||||
while (argp) {
|
||||
if (skipCount) {
|
||||
argp = argp->nextp();
|
||||
--skipCount;
|
||||
continue;
|
||||
}
|
||||
const AstConst* const constp = VN_CAST(argp, Const);
|
||||
const bool isFromString = (constp) ? constp->num().isFromString() : false;
|
||||
if (isFromString) {
|
||||
const int numchars = argp->dtypep()->width() / 8;
|
||||
if (!constp->num().toString().empty()) {
|
||||
string str(numchars, ' ');
|
||||
// now scan for % operators
|
||||
bool inpercent = false;
|
||||
for (int i = 0; i < numchars; i++) {
|
||||
const int ii = numchars - i - 1;
|
||||
const char c = constp->num().dataByte(ii);
|
||||
str[i] = c;
|
||||
if (!inpercent && c == '%') {
|
||||
inpercent = true;
|
||||
} else if (inpercent) {
|
||||
inpercent = false;
|
||||
switch (c) {
|
||||
case '0': // FALLTHRU
|
||||
case '1': // FALLTHRU
|
||||
case '2': // FALLTHRU
|
||||
case '3': // FALLTHRU
|
||||
case '4': // FALLTHRU
|
||||
case '5': // FALLTHRU
|
||||
case '6': // FALLTHRU
|
||||
case '7': // FALLTHRU
|
||||
case '8': // FALLTHRU
|
||||
case '9': // FALLTHRU
|
||||
case '.': inpercent = true; break;
|
||||
case '%': break;
|
||||
default:
|
||||
if (V3Number::displayedFmtLegal(c, isScan)) ++skipCount;
|
||||
}
|
||||
break;
|
||||
case 'l': // %l - auto insert "library"
|
||||
if (isScan) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: %l in $fscanf");
|
||||
fmt = "";
|
||||
}
|
||||
if (m_modp)
|
||||
fmt = AstNode::prettyName(m_modp->libname()) + "."
|
||||
+ m_modp->prettyName();
|
||||
break;
|
||||
default: // Most operators, just move to next argument
|
||||
if (!V3Number::displayedFmtLegal(ch, isScan)) {
|
||||
nodep->v3error("Unknown $display-like format code: '%" << ch << "'");
|
||||
} else if (!inIgnore) {
|
||||
if (!argp) {
|
||||
nodep->v3error("Missing arguments for $display-like format");
|
||||
} else {
|
||||
argp = argp->nextp();
|
||||
}
|
||||
}
|
||||
newFormat.append(str);
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
newFormat += fmt;
|
||||
} else {
|
||||
newFormat += ch;
|
||||
}
|
||||
}
|
||||
|
||||
// Find additional arguments (without format) or additional format strings
|
||||
parseFormat = "";
|
||||
|
||||
if (isScan) break;
|
||||
while (argp) {
|
||||
const AstConst* const constp = VN_CAST(argp, Const);
|
||||
const bool isFromString = (constp) ? constp->num().isFromString() : false;
|
||||
if (!isFromString) {
|
||||
newFormat.append("%?"); // V3Width to figure it out
|
||||
argp = argp->nextp();
|
||||
} else { // New format string
|
||||
parseFormat += constp->num().toString();
|
||||
AstNode* const nextp = argp->nextp();
|
||||
argp->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(argp), argp);
|
||||
argp = nextp;
|
||||
} else {
|
||||
newFormat.append("%?"); // V3Width to figure it out
|
||||
argp = argp->nextp();
|
||||
break; // And continue at top of parsing the new parseFormat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,4 +101,9 @@ ZzX
|
|||
ZzXx
|
||||
XXXx
|
||||
10
|
||||
[50] FIFTY 50
|
||||
[0] FIFTY 50
|
||||
[0] not-fmt %-d 60
|
||||
[0] fmt-as-string-not-%0x 70
|
||||
s=[0] fmt-string-not-%s
|
||||
*-* All Finished *-*
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ module t;
|
|||
|
||||
reg [5:0] assoc_c[int];
|
||||
|
||||
string s;
|
||||
string not_fmt;
|
||||
|
||||
sub sub ();
|
||||
sub2 sub2 ();
|
||||
sub3 sub3 ();
|
||||
|
|
@ -215,6 +218,18 @@ multiline", $time);
|
|||
|
||||
$display(,, 10); // Strange but legal
|
||||
|
||||
// $sformat allows only single format while $display/write allow multiple
|
||||
$display("[50] FIFTY 50");
|
||||
$display("[%0t]", $time, " FIFTY %-d", 50);
|
||||
// This prints as %s, the %-d is not a format, as not_fmt is not literal
|
||||
not_fmt = " not-fmt %-d";
|
||||
$display("[%0t]", $time, not_fmt, 60);
|
||||
// This prints as %s as forces the literal to a string
|
||||
$display("[%0t] %s", $time, " fmt-as-string-not-%0x", 70);
|
||||
// Sformat takes only single format per IEEE
|
||||
s = $sformatf("[%0t] %s", $time, " fmt-string-not-%s");
|
||||
$display("s=%s", s);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue