diff --git a/Statement.h b/Statement.h index 5caf9644d..049aa118e 100644 --- a/Statement.h +++ b/Statement.h @@ -196,18 +196,6 @@ class PCallTask : public Statement { const pform_name_t& path() const; - unsigned nparms() const { return parms_.size(); } - - PExpr*&parm(unsigned idx) - { assert(idx < parms_.size()); - return parms_[idx]; - } - - PExpr* parm(unsigned idx) const - { assert(idx < parms_.size()); - return parms_[idx]; - } - virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; diff --git a/elaborate.cc b/elaborate.cc index e256a4df8..cd3ef2d73 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2825,12 +2825,12 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const des->errors += 1; } - unsigned parm_count = nparms(); + unsigned parm_count = parms_.size(); /* Catch the special case that the system task has no parameters. The "()" string will be parsed as a single empty parameter, when we really mean no parameters at all. */ - if ((nparms() == 1) && (parm(0) == 0)) + if ((parm_count== 1) && (parms_[0] == 0)) parm_count = 0; svectoreparms (parm_count); @@ -2838,7 +2838,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const perm_string name = peek_tail_name(path_); for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { - PExpr*ex = parm(idx); + PExpr*ex = parms_[idx]; if (ex != 0) { eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex); } else { @@ -2930,9 +2930,20 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const } assert(def); - if (nparms() != def->port_count()) { + + unsigned parm_count = parms_.size(); + + // Handle special case that the definition has no arguments + // but the parser found a simgle nul argument. This is an + // argument of the parser allowing for the possibility of + // default values for argumets: The parser cannot tell the + // difference between "func()" and "func()". + if (def->port_count() == 0 && parm_count == 1 && parms_[0] == 0) + parm_count = 0; + + if (parm_count != def->port_count()) { cerr << get_fileline() << ": error: Port count mismatch in call to ``" - << path_ << "''. Got " << nparms() + << path_ << "''. Got " << parm_count << " ports, expecting " << def->port_count() << " ports." << endl; des->errors += 1; return 0; @@ -2942,7 +2953,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const /* Handle non-automatic tasks with no parameters specially. There is no need to make a sequential block to hold the generated code. */ - if ((nparms() == 0) && !task->is_auto()) { + if ((parm_count == 0) && !task->is_auto()) { cur = new NetUTask(task); cur->set_line(*this); return cur; @@ -2974,7 +2985,23 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const expression the r-value. We know by definition that the port is a reg type, so this elaboration is pretty obvious. */ - for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { + + if (parms_[idx] == 0 && !gn_system_verilog()) { + cerr << get_fileline() << ": error: " + << "Missing argument " << (idx+1) + << " of call to task." << endl; + des->errors += 1; + continue; + } + + if (parms_[idx] == 0) { + cerr << get_fileline() << ": sorry: " + << "Implicit arguments (arg " << (idx+1) + << ") not supported." << endl; + des->errors += 1; + continue; + } NetNet*port = def->port(idx); assert(port->port_type() != NetNet::NOT_A_PORT); @@ -2985,7 +3012,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const unsigned wid = count_lval_width(lv); ivl_variable_type_t lv_type = lv->expr_type(); - NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_[idx]); + NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_ [idx]); if (NetEEvent*evt = dynamic_cast (rv)) { cerr << evt->get_fileline() << ": error: An event '" << evt->event()->name() << "' can not be a user " @@ -3015,7 +3042,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const expression that can be a target to a procedural assignment, including a memory word. */ - for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { NetNet*port = def->port(idx); diff --git a/parse.y b/parse.y index 6bcfffff2..79a1ae6c4 100644 --- a/parse.y +++ b/parse.y @@ -513,8 +513,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type enum_data_type %type task_item task_item_list task_item_list_opt -%type task_port_item tf_port_item tf_port_list tf_port_list_opt -%type function_item function_item_list +%type tf_port_declaration tf_port_item tf_port_list tf_port_list_opt +%type function_item function_item_list function_item_list_opt %type port_name parameter_value_byname %type port_name_list parameter_value_byname_list @@ -719,6 +719,7 @@ class_item /* IEEE1800-2005: A.1.8 */ /* IEEE1800 A.1.8: class_constructor_declaration */ : method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + function_item_list_opt statement_or_null_list_opt K_endfunction endnew_opt { yyerror(@3, "sorry: Class constructors not supported yet."); @@ -730,6 +731,7 @@ class_item /* IEEE1800-2005: A.1.8 */ be K_super ("this.new" makes little sense) but that would cause a conflict. */ | method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + function_item_list_opt implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' statement_or_null_list_opt K_endfunction endnew_opt @@ -1454,6 +1456,45 @@ task_declaration /* IEEE1800-2005: A.2.7 */ ; +tf_port_declaration /* IEEE1800-2005: A.2.7 */ + : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(@1, $1, + $2 ? IVL_VT_LOGIC : + IVL_VT_NO_TYPE, + $3, $4, $5); + $$ = tmp; + } + + /* When the port is an integer, infer a signed vector of the integer + shape. Generate a range ([31:0]) to make it work. */ + + | port_direction K_integer list_of_identifiers ';' + { list*range_stub = make_range_from_width(integer_width); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, + range_stub, $3, true); + $$ = tmp; + } + + /* Ports can be time with a width of [63:0] (unsigned). */ + + | port_direction K_time list_of_identifiers ';' + { list*range_stub = make_range_from_width(64); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, + range_stub, $3); + $$ = tmp; + } + + /* Ports can be real or realtime. */ + + | port_direction real_or_realtime list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false, + 0, $3); + $$ = tmp; + } + + ; + + /* These rules for tf_port_item are slightly expanded from the strict rules in the LRM to help with LALR parsing. @@ -3071,26 +3112,34 @@ expr_primary /* A function_item_list borrows the task_port_item run to match declarations of ports. We check later to make sure there are no - output or inout ports actually used. */ + output or inout ports actually used. + + The function_item is the same as tf_item_declaration. */ +function_item_list_opt + : function_item_list { $$ = $1; } + | { $$ = 0; } + ; + function_item_list - : function_item - { $$ = $1; } - | function_item_list function_item - { if ($1 && $2) { - svector*tmp = new svector(*$1, *$2); - delete $1; - delete $2; - $$ = tmp; - } else if ($1) { - $$ = $1; - } else { - $$ = $2; - } - } - ; + : function_item + { $$ = $1; } + | function_item_list function_item + { /* */ + if ($1 && $2) { + svector*tmp = new svector(*$1, *$2); + delete $1; + delete $2; + $$ = tmp; + } else if ($1) { + $$ = $1; + } else { + $$ = $2; + } + } + ; function_item - : task_port_item + : tf_port_declaration { $$ = $1; } | block_item_decl { $$ = 0; } @@ -5700,7 +5749,7 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - | hierarchy_identifier '(' expression_list_proper ')' ';' + | hierarchy_identifier '(' expression_list_with_nuls ')' ';' { PCallTask*tmp = new PCallTask(*$1, *$3); FILE_NAME(tmp, @1); delete $1; @@ -5708,7 +5757,7 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - | implicit_class_handle '.' hierarchy_identifier '(' expression_list_proper ')' ';' + | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';' { PCallTask*tmp = new PCallTask(*$3, *$5); yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); FILE_NAME(tmp, @1); @@ -5717,11 +5766,7 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - /* NOTE: The standard doesn't really support an empty argument list - between parentheses, but it seems natural, and people commonly - want it. So accept it explicitly. */ - - | hierarchy_identifier '(' ')' ';' + | hierarchy_identifier ';' { listpt; PCallTask*tmp = new PCallTask(*$1, pt); FILE_NAME(tmp, @1); @@ -5729,29 +5774,22 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - - | implicit_class_handle '.' hierarchy_identifier '(' ')' ';' - { listpt; - yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); - PCallTask*tmp = new PCallTask(*$3, pt); - FILE_NAME(tmp, @3); - delete $3; + | hierarchy_identifier '(' error ')' ';' + { yyerror(@3, "error: Syntax error in task arguments."); + listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; $$ = tmp; } - | hierarchy_identifier ';' - { listpt; - PCallTask*tmp = new PCallTask(*$1, pt); - FILE_NAME(tmp, @1); - delete $1; - $$ = tmp; - } - | error ';' - { yyerror(@2, "error: malformed statement"); - yyerrok; - $$ = new PNoop; - } - ; + | error ';' + { yyerror(@2, "error: malformed statement"); + yyerrok; + $$ = new PNoop; + } + + ; compressed_statement : lpvalue K_PLUS_EQ expression @@ -5841,47 +5879,9 @@ analog_statement other block items. */ task_item : block_item_decl { $$ = new svector(0); } - | task_port_item { $$ = $1; } + | tf_port_declaration { $$ = $1; } ; -task_port_item - : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(@1, $1, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5); - $$ = tmp; - } - - /* When the port is an integer, infer a signed vector of the integer - shape. Generate a range ([31:0]) to make it work. */ - - | port_direction K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, - range_stub, $3, true); - $$ = tmp; - } - - /* Ports can be time with a width of [63:0] (unsigned). */ - - | port_direction K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, - range_stub, $3); - $$ = tmp; - } - - /* Ports can be real or realtime. */ - - | port_direction real_or_realtime list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false, - 0, $3); - $$ = tmp; - } - - ; - task_item_list : task_item_list task_item { svector*tmp = new svector(*$1, *$2);