Added $display %m support, fixed mem leak in $display, fixes #128

This commit is contained in:
Clifford Wolf 2016-03-19 11:51:13 +01:00
parent ff5c61b120
commit e5d42ebb4d
1 changed files with 44 additions and 20 deletions

View File

@ -193,13 +193,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// but should be good enough for most uses // but should be good enough for most uses
if ((type == AST_TCALL) && ((str == "$display") || (str == "$write"))) if ((type == AST_TCALL) && ((str == "$display") || (str == "$write")))
{ {
size_t nargs = GetSize(children); int nargs = GetSize(children);
if(nargs < 1) if (nargs < 1)
log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n", log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n",
str.c_str(), int(children.size()), filename.c_str(), linenum); str.c_str(), int(children.size()), filename.c_str(), linenum);
// First argument is the format string // First argument is the format string
AstNode *node_string = children[0]->clone(); AstNode *node_string = children[0];
while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_string->type != AST_CONSTANT) if (node_string->type != AST_CONSTANT)
log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
@ -207,37 +207,57 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// Other arguments are placeholders. Process the string as we go through it // Other arguments are placeholders. Process the string as we go through it
std::string sout; std::string sout;
size_t next_arg = 1; int next_arg = 1;
for(size_t i=0; i<sformat.length(); i++) for (size_t i = 0; i < sformat.length(); i++)
{ {
// format specifier // format specifier
if(sformat[i] == '%') if (sformat[i] == '%')
{ {
// If there's no next character, that's a problem // If there's no next character, that's a problem
if(i+1 >= sformat.length()) if (i+1 >= sformat.length())
log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum); log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
char cformat = sformat[++i]; char cformat = sformat[++i];
// %% is special, does not need a matching argument // %% is special, does not need a matching argument
if(cformat == '%') if (cformat == '%')
{ {
sout += '%'; sout += '%';
continue; continue;
} }
// If we're out of arguments, that's a problem!
if(next_arg >= nargs)
log_error("System task `%s' called with more format specifiers than arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
// Simplify the argument // Simplify the argument
AstNode *node_arg = children[next_arg ++]->clone(); AstNode *node_arg = nullptr;
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_arg->type != AST_CONSTANT)
log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
// Everything from here on depends on the format specifier // Everything from here on depends on the format specifier
switch(cformat) switch (cformat)
{
case 's':
case 'S':
case 'd':
case 'D':
case 'x':
case 'X':
if (next_arg >= GetSize(children))
log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n",
cformat, str.c_str(), filename.c_str(), linenum);
node_arg = children[next_arg++];
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_arg->type != AST_CONSTANT)
log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
break;
case 'm':
case 'M':
break;
default:
log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
break;
}
switch (cformat)
{ {
case 's': case 's':
case 'S': case 'S':
@ -262,9 +282,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
} }
break; break;
default: case 'm':
log_error("System task `%s' called with invalid format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); case 'M':
sout += log_id(current_module->name);
break; break;
default:
log_abort();
} }
} }
@ -275,7 +299,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// Finally, print the message (only include a \n for $display, not for $write) // Finally, print the message (only include a \n for $display, not for $write)
log("%s", sout.c_str()); log("%s", sout.c_str());
if(str == "$display") if (str == "$display")
log("\n"); log("\n");
delete_children(); delete_children();
str = std::string(); str = std::string();