diff --git a/lexor.lex b/lexor.lex index 7c62f92eb..e55675919 100644 --- a/lexor.lex +++ b/lexor.lex @@ -120,8 +120,6 @@ static list keyword_mask_stack; static int comment_enter; static bool in_module = false; static bool in_UDP = false; -static bool in_module_port_list = false; -static bool module_port_list_start = false; bool in_celldefine = false; UCDriveType uc_drive = UCD_NONE; static int ts_state = 0; @@ -141,12 +139,6 @@ void lex_in_package_scope(PPackage*pkg) in_package_scope = pkg; } -void lex_in_module_port_list(bool flag) -{ - in_module_port_list = flag; - module_port_list_start = flag; -} - %} %x CCOMMENT @@ -426,13 +418,6 @@ TU [munpf] } } - /* If this identifier names a previously declared interface, then - return this as an INTERFACE_IDENTIFIER instead. */ - if (rc == IDENTIFIER && gn_system_verilog()) { - if (pform_test_interface_identifier(yylval.text)) - rc = INTERFACE_IDENTIFIER; - } - /* If this identifier names a previously declared type, then return this as a TYPE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { @@ -443,22 +428,6 @@ TU [munpf] } } - if (rc == IDENTIFIER && gn_system_verilog() && - in_module_port_list && module_port_list_start) { - char save_ch = *yy_c_buf_p; - *yy_c_buf_p = yy_hold_char; - const char*cp = yy_c_buf_p; - while (*cp == ' ' || *cp == '\t' || *cp == '\b' || - *cp == '\f' || *cp == '\r' || *cp == '\n') - cp += 1; - if (*cp == '.' || isalpha(static_cast(*cp)) || - *cp == '_' || *cp == '\\') - rc = INTERFACE_IDENTIFIER; - *yy_c_buf_p = save_ch; - } - - if (in_module_port_list) - module_port_list_start = false; return rc; } @@ -474,10 +443,6 @@ TU [munpf] return PACKAGE_IDENTIFIER; } } - if (gn_system_verilog()) { - if (pform_test_interface_identifier(yylval.text)) - return INTERFACE_IDENTIFIER; - } if (gn_system_verilog()) { if (typedef_t*type = pform_test_type_identifier(yylloc, yylval.text)) { yylval.type_identifier.text = yylval.text; @@ -933,16 +898,7 @@ TU [munpf] `{W} { VLerror(yylloc, "error: Stray tic (`) here. Perhaps you put white " "space between the tic and preprocessor directive?"); } -. { - if (in_module_port_list) { - if (yytext[0] == '(' || yytext[0] == ',') - module_port_list_start = true; - else if (yytext[0] != ')' && yytext[0] != '[' && - yytext[0] != ']' && yytext[0] != ':') - module_port_list_start = false; - } - return yytext[0]; -} +. { return yytext[0]; } /* Final catchall. something got lost or mishandled. */ /* XXX Should we tell the user something about the lexical state? */ diff --git a/parse.y b/parse.y index 20b9bd6a4..83d149b30 100644 --- a/parse.y +++ b/parse.y @@ -761,7 +761,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, enum type_restrict_t::type_t type_restrict; }; -%token IDENTIFIER INTERFACE_IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL +%token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL %token TYPE_IDENTIFIER %token PACKAGE_IDENTIFIER %token DISCIPLINE_IDENTIFIER @@ -879,7 +879,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type udp_port_decl udp_port_decls %type udp_initial udp_init_opt -%type event_variable label_opt +%type event_variable label_opt interface_port_modport_opt %type block_identifier_opt %type identifier_name %type event_variable_list @@ -5000,6 +5000,18 @@ list_of_port_declarations (*tmp)[0] = $1; $$ = tmp; } + // Keep interface ports as list base cases so the leading identifier is + // shifted before choosing between an interface port and an old-style port + // reference. The attributed form is separate because attribute_list_opt + // can be empty. + | IDENTIFIER interface_port_modport_opt identifier_name dimensions_opt + { Module::port_t*port = module_declare_interface_port(@3, $1, $2, $3, $4, 0); + $$ = new std::vector(1, port); + } + | attribute_instance_list IDENTIFIER interface_port_modport_opt identifier_name dimensions_opt + { Module::port_t*port = module_declare_interface_port(@4, $2, $3, $4, $5, $1); + $$ = new std::vector(1, port); + } | list_of_port_declarations ',' port_declaration { std::vector*tmp = $1; tmp->push_back($3); @@ -5044,12 +5056,28 @@ list_of_port_declarations ports->push_back(port); $$ = ports; } + // Once an ANSI port declaration list has been established, an identifier + // can unambiguously start an interface port. Keeping this case out of + // port_declaration avoids ambiguity with an old-style port reference at + // the start of the list. + | list_of_port_declarations ',' attribute_list_opt IDENTIFIER interface_port_modport_opt identifier_name dimensions_opt + { std::vector *ports = $1; + ports->push_back(module_declare_interface_port(@6, $4, $5, $6, $7, $3)); + $$ = ports; + } | list_of_port_declarations ',' { yyerror(@2, "error: Superfluous comma in port declaration list."); } | list_of_port_declarations ';' { yyerror(@2, "error: ';' is an invalid port declaration separator."); } ; +interface_port_modport_opt + : '.' identifier_name + { $$ = $2; } + | + { $$ = 0; } + ; + // All of port direction, port kind and data type are optional, but at least // one has to be specified, so we need multiple rules. port_declaration @@ -5057,12 +5085,6 @@ port_declaration { $$ = module_declare_port(@4, $4.id, $4.lexical_pos, $2, $3, $4.type, $4.ranges, $5, $1); } - | attribute_list_opt INTERFACE_IDENTIFIER '.' identifier_name identifier_name dimensions_opt - { $$ = module_declare_interface_port(@5, $2, $4, $5, $6, $1); - } - | attribute_list_opt INTERFACE_IDENTIFIER identifier_name dimensions_opt - { $$ = module_declare_interface_port(@3, $2, 0, $3, $4, $1); - } | attribute_list_opt net_type_or_var data_type_or_implicit_plus_id_dim initializer_opt { pform_requires_sv(@3, "Partial ANSI port declaration"); $$ = module_declare_port(@3, $3.id, $3.lexical_pos, @@ -5182,11 +5204,9 @@ module port_declaration_context_init(); } module_package_import_list_opt module_parameter_port_list_opt - { lex_in_module_port_list(true); } module_port_list_opt - { lex_in_module_port_list(false); } module_attribute_foreign ';' - { pform_module_set_ports($9); } + { pform_module_set_ports($8); } timeunits_declaration_opt { pform_set_scope_timescale(@2); } module_item_list_opt @@ -5209,16 +5229,16 @@ module } // Check that program/endprogram and module/endmodule // keywords match. - if ($2 != $17) { + if ($2 != $15) { switch ($2) { case K_module: - yyerror(@17, "error: module not closed by endmodule."); + yyerror(@15, "error: module not closed by endmodule."); break; case K_program: - yyerror(@17, "error: program not closed by endprogram."); + yyerror(@15, "error: program not closed by endprogram."); break; case K_interface: - yyerror(@17, "error: interface not closed by endinterface."); + yyerror(@15, "error: interface not closed by endinterface."); break; default: break; @@ -5234,13 +5254,13 @@ module // module. switch ($2) { case K_module: - check_end_label(@19, "module", $4, $19); + check_end_label(@17, "module", $4, $17); break; case K_program: - check_end_label(@19, "program", $4, $19); + check_end_label(@17, "program", $4, $17); break; case K_interface: - check_end_label(@19, "interface", $4, $19); + check_end_label(@17, "interface", $4, $17); break; default: break; @@ -5583,13 +5603,6 @@ module_item delete[]$2; } - | attribute_list_opt - INTERFACE_IDENTIFIER parameter_value_opt gate_instance_list ';' - { perm_string tmp1 = lex_strings.make($2); - pform_make_modgates(@2, tmp1, $3, $4, $1); - delete[]$2; - } - | attribute_list_opt IDENTIFIER parameter_value_opt error ';' { yyerror(@2, "error: Invalid module instantiation"); @@ -5597,13 +5610,6 @@ module_item if ($1) delete $1; } - | attribute_list_opt - INTERFACE_IDENTIFIER parameter_value_opt error ';' - { yyerror(@2, "error: Invalid module instantiation"); - delete[]$2; - if ($1) delete $1; - } - /* Continuous assignment can have an optional drive strength, then an optional delay3 that applies to all the assignments in the cont_assign_list. */ diff --git a/parse_misc.h b/parse_misc.h index 62adbe9e6..e82751eb6 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -83,13 +83,6 @@ extern UCDriveType uc_drive; */ extern void lex_in_package_scope(PPackage*pkg); -/* - * The parser signals when the lexor is scanning a module/interface/program - * port list so that ambiguous SystemVerilog interface formals can be - * tokenized without depending on declaration order. - */ -extern void lex_in_module_port_list(bool flag); - /* * Test if this identifier is a type identifier in the current * context. The pform code needs to help the lexor here because the @@ -99,11 +92,6 @@ extern void lex_in_module_port_list(bool flag); extern typedef_t* pform_test_type_identifier(const YYLTYPE&loc, const char*txt); extern typedef_t* pform_test_type_identifier(PPackage*pkg, const char*txt); -/* - * Test if this identifier is a previously declared interface name. - */ -extern bool pform_test_interface_identifier(const char*txt); - /* * Test if this identifier is a package name. The pform needs to help * the lexor here because the parser detects packages and saves them. diff --git a/pform.cc b/pform.cc index 0f5b3578f..41f093c06 100644 --- a/pform.cc +++ b/pform.cc @@ -955,14 +955,6 @@ typedef_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt) return 0; } -bool pform_test_interface_identifier(const char*txt) -{ - perm_string name = lex_strings.make(txt); - map::const_iterator cur = pform_modules.find(name); - - return cur != pform_modules.end() && cur->second->is_interface; -} - PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, const list &parms)