Fix carriage-returns embedded in display formats

Internals: Store all AstDisplay etc strings in un-backslashed raw format.
This commit is contained in:
Wilson Snyder 2009-10-22 21:16:52 -04:00
parent 996afe7d95
commit b4d3806f10
9 changed files with 70 additions and 35 deletions

View File

@ -196,6 +196,31 @@ string AstNode::prettyTypeName() const {
return string(typeName())+" '"+prettyName()+"'";
}
string AstNode::quoteName(const string& namein) {
// Encode control chars into C style escapes
// Reverse is V3Parse::deQuote
const char* start = namein.c_str();
string out;
for (const char* pos = start; *pos; pos++) {
if (pos[0]=='\\' || pos[0]=='"') {
out += string("\\")+pos[0];
} else if (pos[0]=='\n') {
out += "\\n";
} else if (pos[0]=='\r') {
out += "\\r";
} else if (pos[0]=='\t') {
out += "\\t";
} else if (isprint(pos[0])) {
out += pos[0];
} else {
// This will also cover \a etc
char octal[10]; sprintf(octal,"\\%03o",pos[0]);
out += octal;
}
}
return out;
}
int AstNode::widthPow2() const {
// I.e. width 30 returns 32, width 32 returns 32.
uint32_t width = this->width();

View File

@ -675,6 +675,7 @@ public:
virtual string verilogKwd() const { return ""; }
string shortName() const; // Name with __PVT__ removed for concatenating scopes
static string dedotName(const string& namein); // Name with dots removed
static string quoteName(const string& namein); // Name with control chars quoted
static string prettyName(const string& namein); // Name for printing out to the user
static string encodeName(const string& namein); // Encode user name into internal C representation
static string encodeNumber(vlsint64_t numin); // Encode number into internal C representation

View File

@ -273,7 +273,7 @@ void AstNode::dump(ostream& os) {
<<" "<<(isSigned()?"s":"")
<<"w"<<(widthSized()?"":"u")<<width();
if (!widthSized()) os<<"/"<<widthMin();
if (name()!="") os<<" "<<name();
if (name()!="") os<<" "<<AstNode::quoteName(name());
}
void AstAttrOf::dump(ostream& str) {

View File

@ -227,7 +227,7 @@ public:
}
virtual void visit(AstDisplay* nodep, AstNUser*) {
string text = nodep->text();
if (nodep->addNewline()) text += "\\n";
if (nodep->addNewline()) text += "\n";
displayNode(nodep, text, nodep->exprsp(), false);
}
virtual void visit(AstFScanF* nodep, AstNUser*) {
@ -994,9 +994,7 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
isStmt = true;
nodep->v3fatalSrc("Unknown displayEmit node type");
}
puts("\"");
ofp()->putsNoTracking(emitDispState.m_format); // Not putsQuoted - already contains \s
puts("\"");
ofp()->putsQuoted(emitDispState.m_format);
// Arguments
for (unsigned i=0; i < emitDispState.m_argsp.size(); i++) {
puts(",");

View File

@ -31,6 +31,7 @@
#include "V3Global.h"
#include "V3File.h"
#include "V3PreShell.h"
#include "V3Ast.h"
//######################################################################
// V3File Internal state
@ -435,16 +436,9 @@ void V3OutFile::putsQuoted(const char* strg) {
// Quote \ and " for use inside C programs
// Don't use to quote a filename for #include - #include doesn't \ escape.
putcNoTracking('"');
for (const char* cp=strg; *cp; cp++) {
if (*cp == '\\') {
putcNoTracking('\\');
putcNoTracking('\\');
} else if (*cp == '"') {
putcNoTracking('\\');
putcNoTracking('"');
} else {
putcNoTracking (*cp);
}
string quoted = AstNode::quoteName(strg);
for (const char* cp=quoted.c_str(); *cp; cp++) {
putcNoTracking (*cp);
}
putcNoTracking('"');
}

View File

@ -1677,20 +1677,20 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
| yD_STOP parenE { $$ = new AstStop($1); }
| yD_STOP '(' expr ')' { $$ = new AstStop($1); }
//
| yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,"", NULL,NULL); }
| yD_DISPLAY '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$3,NULL,$4); }
| yD_WRITE '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$3,NULL,$4); }
| yD_FDISPLAY '(' idClassSel ',' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$5,$3,$6); }
| yD_FWRITE '(' idClassSel ',' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$5,$3,$6); }
| yD_INFO parenE { $$ = new AstDisplay($1,AstDisplayType::INFO, "", NULL,NULL); }
| yD_INFO '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::INFO, *$3,NULL,$4); }
| yD_WARNING parenE { $$ = new AstDisplay($1,AstDisplayType::WARNING,"", NULL,NULL); }
| yD_WARNING '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WARNING,*$3,NULL,$4); }
| yD_ERROR parenE { $$ = V3Parse::createDisplayError($1); }
| yD_ERROR '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::ERROR, *$3,NULL,$4); $$->addNext(new AstStop($1)); }
| yD_FATAL parenE { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); }
| yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); }
| yD_FATAL '(' expr ',' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, *$5,NULL,$6); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); }
| yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,"", NULL,NULL); }
| yD_DISPLAY '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$3,NULL,$4); }
| yD_WRITE '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$3,NULL,$4); }
| yD_FDISPLAY '(' idClassSel ',' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$5,$3,$6); }
| yD_FWRITE '(' idClassSel ',' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$5,$3,$6); }
| yD_INFO parenE { $$ = new AstDisplay($1,AstDisplayType::INFO, "", NULL,NULL); }
| yD_INFO '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::INFO, *$3,NULL,$4); }
| yD_WARNING parenE { $$ = new AstDisplay($1,AstDisplayType::WARNING,"", NULL,NULL); }
| yD_WARNING '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WARNING,*$3,NULL,$4); }
| yD_ERROR parenE { $$ = V3Parse::createDisplayError($1); }
| yD_ERROR '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::ERROR, *$3,NULL,$4); $$->addNext(new AstStop($1)); }
| yD_FATAL parenE { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); }
| yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); }
| yD_FATAL '(' expr ',' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, *$5,NULL,$6); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); }
//
| yD_READMEMB '(' expr ',' varRefMem ')' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); }
| yD_READMEMB '(' expr ',' varRefMem ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); }
@ -1711,8 +1711,8 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
| yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); }
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
| yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); }
| yD_FSCANF '(' expr ',' yaSTRING commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
| yD_SSCANF '(' expr ',' yaSTRING commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); }
| yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }
@ -2372,6 +2372,11 @@ varRefBase<varrefp>:
id { $$ = new AstVarRef(CRELINE(),*$1,false);}
;
// yaSTRING shouldn't be used directly, instead via an abstraction below
str<strp>: // yaSTRING but with \{escapes} need decoded
yaSTRING { $$ = V3Read::newString(V3Parse::deQuote(CRELINE(),*$1)); }
;
strAsInt<nodep>:
yaSTRING { $$ = new AstConst(CRELINE(),V3Number(V3Number::VerilogString(),CRELINE(),V3Parse::deQuote(CRELINE(),*$1)));}
;
@ -2593,6 +2598,7 @@ AstVar* V3Parse::createVariable(FileLine* fileline, string name, AstRange* array
string V3Parse::deQuote(FileLine* fileline, string text) {
// Fix up the quoted strings the user put in, for example "\"" becomes "
// Reverse is AstNode::quoteName(...)
bool quoted = false;
string newtext;
unsigned char octal_val = 0;

View File

@ -12,7 +12,7 @@ compile (
execute (
check_finished=>1,
expect=>quotemeta(
expect=>quotemeta(dequote(
'[0] In TOP.v: Hi
[0] In TOP.v.sub
[0] In TOP.v.sub.subblock
@ -26,9 +26,14 @@ execute (
[0] %s=! %s= what! %s= hmmm!1234
[0] hello, from a very long string. Percent %s are literally substituted in.
[0] Embedded <#013> return
*-* All Finished *-*
'),
')),
);
ok(1);
# Don't put control chars into our source repository, pre-compress instead
sub dequote { my $s = shift; $s =~ s/<#013>/\r/g; $s; }
1;

View File

@ -37,6 +37,7 @@ module t;
$display("[%0t] %s%s%s", $time,
"hel", "lo, fr", "om a very long string. Percent %s are literally substituted in.");
$write("[%0t] Embedded \r return\n", $time);
// Str check
`ifndef nc // NC-Verilog 5.3 chokes on this test

View File

@ -15,7 +15,7 @@ compile (
execute (
check_finished=>1,
expect=>quotemeta(
expect=>quotemeta(dequote(
'[0] In TOP.v: Hi
[0] In TOP.v.sub
[0] In TOP.v.sub.subblock
@ -29,9 +29,14 @@ execute (
[0] %s=! %s= what! %s= hmmm!1234
[0] hello, from a very long string. Percent %s are literally substituted in.
[0] Embedded <#013> return
*-* All Finished *-*
'),
')),
);
ok(1);
# Don't put control chars into our source repository, pre-compress instead
sub dequote { my $s = shift; $s =~ s/<#013>/\r/g; $s; }
1;