diff --git a/PScope.h b/PScope.h index f7eb73f96..081d9fb58 100644 --- a/PScope.h +++ b/PScope.h @@ -57,6 +57,9 @@ class LexicalScope { // A virtual destructor is so that dynamic_cast can work. virtual ~LexicalScope() { } + enum lifetime_t { INHERITED, STATIC, AUTOMATIC }; + lifetime_t default_lifetime; + struct range_t { // True if this is an exclude bool exclude_flag; diff --git a/parse.y b/parse.y index a901a63de..1b0fec636 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -452,6 +452,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector PSpecPath* specpath; list *dimensions; + + LexicalScope::lifetime_t lifetime; }; %token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL @@ -560,7 +562,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type number pos_neg_number %type signing unsigned_signed_opt signed_unsigned_opt %type import_export -%type K_automatic_opt K_packed_opt K_reg_opt K_static_opt K_virtual_opt +%type K_packed_opt K_reg_opt K_static_opt K_virtual_opt %type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym @@ -665,6 +667,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type atom2_type %type module_start module_end +%type lifetime_opt + %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ %right K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ @@ -724,17 +728,17 @@ block_identifier_opt /* */ ; class_declaration /* IEEE1800-2005: A.1.2 */ - : K_virtual_opt K_class class_identifier class_declaration_extends_opt ';' - { pform_start_class_declaration(@2, $3, $4.type, $4.exprs); } + : K_virtual_opt K_class lifetime_opt class_identifier class_declaration_extends_opt ';' + { pform_start_class_declaration(@2, $4, $5.type, $5.exprs, $3); } class_items_opt K_endclass { // Process a class. - pform_end_class_declaration(@8); + pform_end_class_declaration(@9); } class_declaration_endlabel_opt { // Wrap up the class. - if ($10 && $3 && $3->name != $10) { - yyerror(@10, "error: Class end label doesn't match class name."); - delete[]$10; + if ($11 && $4 && $4->name != $11) { + yyerror(@11, "error: Class end label doesn't match class name."); + delete[]$11; } } ; @@ -1194,7 +1198,7 @@ for_step /* IEEE1800-2005: A.6.8 */ definitions in the func_body to take on the scope of the function instead of the module. */ function_declaration /* IEEE1800-2005: A.2.6 */ - : K_function K_automatic_opt data_type_or_implicit_or_void IDENTIFIER ';' + : K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER ';' { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -1215,7 +1219,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ "function name"); } if (! gn_system_verilog()) { - yyerror(@11, "error: Function end label require " + yyerror(@11, "error: Function end labels require " "SystemVerilog."); } delete[]$11; @@ -1223,7 +1227,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ delete[]$4; } - | K_function K_automatic_opt data_type_or_implicit_or_void IDENTIFIER + | K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -1259,7 +1263,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ /* Detect and recover from some errors. */ - | K_function K_automatic_opt data_type_or_implicit_or_void IDENTIFIER error K_endfunction + | K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER error K_endfunction { /* */ if (current_function) { pform_pop_scope(); @@ -1365,6 +1369,12 @@ jump_statement /* IEEE1800-2005: A.6.5 */ } ; +lifetime_opt /* IEEE1800-2005: A.2.1.3 */ + : K_automatic { $$ = LexicalScope::AUTOMATIC; } + | K_static { $$ = LexicalScope::STATIC; } + | { $$ = LexicalScope::INHERITED; } + ; + /* Loop statements are kinds of statements. */ loop_statement /* IEEE1800-2005: A.6.8 */ @@ -1704,20 +1714,20 @@ open_range_list /* IEEE1800-2005 A.2.11 */ ; package_declaration /* IEEE1800-2005 A.1.2 */ - : K_package IDENTIFIER ';' - { pform_start_package_declaration(@1, $2); + : K_package lifetime_opt IDENTIFIER ';' + { pform_start_package_declaration(@1, $3, $2); } package_item_list_opt K_endpackage endlabel_opt { pform_end_package_declaration(@1); // If an end label is present make sure it match the package name. - if ($7) { - if (strcmp($2,$7) != 0) { - yyerror(@7, "error: End label doesn't match package name"); + if ($8) { + if (strcmp($3,$8) != 0) { + yyerror(@8, "error: End label doesn't match package name"); } - delete[]$7; + delete[]$8; } - delete[]$2; + delete[]$3; } ; @@ -1896,7 +1906,7 @@ streaming_concatenation /* IEEE1800-2005: A.8.1 */ task_declaration /* IEEE1800-2005: A.2.7 */ - : K_task K_automatic_opt IDENTIFIER ';' + : K_task lifetime_opt IDENTIFIER ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -1909,7 +1919,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ pform_pop_scope(); current_task = 0; if ($7 && $7->size() > 1 && !gn_system_verilog()) { - yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); + yyerror(@7, "error: Task body with multiple statements requires SystemVerilog."); } delete $7; } @@ -1932,7 +1942,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task K_automatic_opt IDENTIFIER '(' + | K_task lifetime_opt IDENTIFIER '(' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -1966,7 +1976,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task K_automatic_opt IDENTIFIER '(' ')' ';' + | K_task lifetime_opt IDENTIFIER '(' ')' ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -1983,7 +1993,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ pform_pop_scope(); current_task = 0; if ($9->size() > 1 && !gn_system_verilog()) { - yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); + yyerror(@9, "error: Task body with multiple statements requires SystemVerilog."); } delete $9; } @@ -2006,7 +2016,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task K_automatic_opt IDENTIFIER error K_endtask + | K_task lifetime_opt IDENTIFIER error K_endtask { assert(current_task == 0); } @@ -4377,13 +4387,13 @@ local_timeunit_prec_decl2 items, and finally an end marker. */ module - : attribute_list_opt module_start IDENTIFIER - { pform_startmodule(@2, $3, $2==K_program, $2==K_interface, $1); } + : attribute_list_opt module_start lifetime_opt IDENTIFIER + { pform_startmodule(@2, $4, $2==K_program, $2==K_interface, $3, $1); } module_package_import_list_opt module_parameter_port_list_opt module_port_list_opt module_attribute_foreign ';' - { pform_module_set_ports($7); } + { pform_module_set_ports($8); } local_timeunit_prec_decl_opt { have_timeunit_decl = true; // Every thing past here is have_timeprec_decl = true; // a check! @@ -4409,22 +4419,22 @@ module } // Check that program/endprogram and module/endmodule // keywords match. - if ($2 != $14) { + if ($2 != $15) { switch ($2) { case K_module: - yyerror(@14, "error: module not closed by endmodule."); + yyerror(@15, "error: module not closed by endmodule."); break; case K_program: - yyerror(@14, "error: program not closed by endprogram."); + yyerror(@15, "error: program not closed by endprogram."); break; case K_interface: - yyerror(@14, "error: interface not closed by endinterface."); + yyerror(@15, "error: interface not closed by endinterface."); break; default: break; } } - pform_endmodule($3, in_celldefine, ucd); + pform_endmodule($4, in_celldefine, ucd); have_timeunit_decl = false; // We will allow decls again. have_timeprec_decl = false; } @@ -4434,19 +4444,19 @@ module // endlabel_opt but still have the pform_endmodule() called // early enough that the lexor can know we are outside the // module. - if ($16) { - if (strcmp($3,$16) != 0) { + if ($17) { + if (strcmp($4,$17) != 0) { switch ($2) { case K_module: - yyerror(@16, "error: End label doesn't match " + yyerror(@17, "error: End label doesn't match " "module name."); break; case K_program: - yyerror(@16, "error: End label doesn't match " + yyerror(@17, "error: End label doesn't match " "program name."); break; case K_interface: - yyerror(@16, "error: End label doesn't match " + yyerror(@17, "error: End label doesn't match " "interface name."); break; default: @@ -4457,9 +4467,9 @@ module yyerror(@8, "error: Module end labels require " "SystemVerilog."); } - delete[]$16; + delete[]$17; } - delete[]$3; + delete[]$4; } ; @@ -6782,7 +6792,6 @@ udp_primitive presence is significant. This is a fairly common pattern so collect those rules here. */ -K_automatic_opt: K_automatic { $$ = true; } | { $$ = false; } ; K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; K_static_opt : K_static { $$ = true; } | { $$ = false; } ; diff --git a/pform.cc b/pform.cc index bc1211907..34a5eb638 100644 --- a/pform.cc +++ b/pform.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -312,12 +312,29 @@ static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno) */ static LexicalScope* lexical_scope = 0; +LexicalScope* pform_peek_scope(void) +{ + assert(lexical_scope); + return lexical_scope; +} + void pform_pop_scope() { assert(lexical_scope); lexical_scope = lexical_scope->parent_scope(); } +static LexicalScope::lifetime_t find_lifetime(LexicalScope::lifetime_t lifetime) +{ + if (lifetime != LexicalScope::INHERITED) + return lifetime; + + if (lexical_scope != 0) + return lexical_scope->default_lifetime; + + return LexicalScope::STATIC; +} + static PScopeExtra* find_nearest_scopex(LexicalScope*scope) { PScopeExtra*scopex = dynamic_cast (scope); @@ -328,15 +345,11 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope) return scopex; } -LexicalScope* pform_peek_scope(void) -{ - assert(lexical_scope); - return lexical_scope; -} - -PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name) +PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, + LexicalScope::lifetime_t lifetime) { PClass*class_scope = new PClass(name, lexical_scope); + class_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(class_scope, loc); PScopeExtra*scopex = find_nearest_scopex(lexical_scope); @@ -364,20 +377,27 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name) return class_scope; } -PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name) +PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name, + LexicalScope::lifetime_t lifetime) { PPackage*pkg_scope = new PPackage(name, lexical_scope); + pkg_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(pkg_scope, loc); lexical_scope = pkg_scope; return pkg_scope; } -PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) +PTask* pform_push_task_scope(const struct vlltype&loc, char*name, + LexicalScope::lifetime_t lifetime) { perm_string task_name = lex_strings.make(name); + LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime); + bool is_auto = default_lifetime == LexicalScope::AUTOMATIC; + PTask*task = new PTask(task_name, lexical_scope, is_auto); + task->default_lifetime = default_lifetime; FILE_NAME(task, loc); PScopeExtra*scopex = find_nearest_scopex(lexical_scope); @@ -424,11 +444,15 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) } PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, - bool is_auto) + LexicalScope::lifetime_t lifetime) { perm_string func_name = lex_strings.make(name); + LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime); + bool is_auto = default_lifetime == LexicalScope::AUTOMATIC; + PFunction*func = new PFunction(func_name, lexical_scope, is_auto); + func->default_lifetime = default_lifetime; FILE_NAME(func, loc); PScopeExtra*scopex = find_nearest_scopex(lexical_scope); @@ -1131,6 +1155,7 @@ verinum* pform_verinum_with_size(verinum*siz, verinum*val, void pform_startmodule(const struct vlltype&loc, const char*name, bool program_block, bool is_interface, + LexicalScope::lifetime_t lifetime, list*attr) { if (! pform_cur_module.empty() && !gn_system_verilog()) { @@ -1139,6 +1164,12 @@ void pform_startmodule(const struct vlltype&loc, const char*name, error_count += 1; } + if (lifetime != LexicalScope::INHERITED && !gn_system_verilog()) { + cerr << loc << ": error: Default subroutine lifetimes " + "require SystemVerilog." << endl; + error_count += 1; + } + if (gn_system_verilog() && ! pform_cur_module.empty()) { if (pform_cur_module.front()->program_block) { cerr << loc << ": error: module, program, or interface " @@ -1158,6 +1189,8 @@ void pform_startmodule(const struct vlltype&loc, const char*name, Module*cur_module = new Module(lexical_scope, lex_name); cur_module->program_block = program_block; cur_module->is_interface = is_interface; + cur_module->default_lifetime = find_lifetime(lifetime); + /* Set the local time unit/precision to the global value. */ cur_module->time_unit = pform_time_unit; cur_module->time_precision = pform_time_prec; diff --git a/pform.h b/pform.h index e1ce49065..21d5c3e75 100644 --- a/pform.h +++ b/pform.h @@ -1,7 +1,7 @@ #ifndef IVL_pform_H #define IVL_pform_H /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -163,6 +163,7 @@ extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_ty */ extern void pform_startmodule(const struct vlltype&loc, const char*name, bool program_block, bool is_interface, + LexicalScope::lifetime_t lifetime, list*attr); extern void pform_check_timeunit_prec(); extern void pform_module_set_ports(vector*); @@ -186,7 +187,8 @@ extern void pform_endmodule(const char*, bool inside_celldefine, extern void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type, data_type_t*base_type, - std::list*base_exprs); + std::list*base_exprs, + LexicalScope::lifetime_t lifetime); extern void pform_class_property(const struct vlltype&loc, property_qualifier_t pq, data_type_t*data_type, @@ -211,7 +213,8 @@ extern void pform_make_udp(perm_string name, * Package related functions. */ extern void pform_start_package_declaration(const struct vlltype&loc, - const char*type); + const char*type, + LexicalScope::lifetime_t lifetime); extern void pform_end_package_declaration(const struct vlltype&loc); extern void pform_package_import(const struct vlltype&loc, PPackage*pkg, const char*ident); @@ -246,13 +249,20 @@ extern void pform_pop_scope(); */ extern LexicalScope* pform_peek_scope(); -extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name); +extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, + LexicalScope::lifetime_t lifetime); + extern PFunction*pform_push_constructor_scope(const struct vlltype&loc); -extern PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name); + +extern PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name, + LexicalScope::lifetime_t lifetime); + extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name, - bool is_auto); + LexicalScope::lifetime_t lifetime); + extern PFunction*pform_push_function_scope(const struct vlltype&loc, const char*name, - bool is_auto); + LexicalScope::lifetime_t lifetime); + extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt); extern void pform_put_behavior_in_scope(AProcess*proc); diff --git a/pform_package.cc b/pform_package.cc index a4ed9c832..4c4b38440 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -35,12 +35,13 @@ map pform_packages; static PPackage*pform_cur_package = 0; -void pform_start_package_declaration(const struct vlltype&loc, const char*name) +void pform_start_package_declaration(const struct vlltype&loc, const char*name, + LexicalScope::lifetime_t lifetime) { ivl_assert(loc, pform_cur_package == 0); perm_string use_name = lex_strings.make(name); - PPackage*pkg_scope = pform_push_package_scope(loc, use_name); + PPackage*pkg_scope = pform_push_package_scope(loc, use_name, lifetime); FILE_NAME(pkg_scope, loc); pform_cur_package = pkg_scope; } diff --git a/pform_pclass.cc b/pform_pclass.cc index 0636126f4..bd2a7a21a 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -36,9 +36,13 @@ static PClass*pform_cur_class = 0; * if present, are the "exprs" that would be passed to a chained * constructor. */ -void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type, data_type_t*base_type, list*base_exprs) +void pform_start_class_declaration(const struct vlltype&loc, + class_type_t*type, + data_type_t*base_type, + list*base_exprs, + LexicalScope::lifetime_t lifetime) { - PClass*class_scope = pform_push_class_scope(loc, type->name); + PClass*class_scope = pform_push_class_scope(loc, type->name, lifetime); class_scope->type = type; assert(pform_cur_class == 0); pform_cur_class = class_scope; @@ -127,7 +131,7 @@ void pform_set_constructor_return(PFunction*net) PFunction*pform_push_constructor_scope(const struct vlltype&loc) { assert(pform_cur_class); - PFunction*func = pform_push_function_scope(loc, "new", true); + PFunction*func = pform_push_function_scope(loc, "new", LexicalScope::AUTOMATIC); return func; } @@ -138,7 +142,7 @@ void pform_end_class_declaration(const struct vlltype&loc) // If there were initializer statements, then collect them // into an implicit constructor function. if (! pform_cur_class->type->initialize.empty()) { - PFunction*func = pform_push_function_scope(loc, "new@", true); + PFunction*func = pform_push_function_scope(loc, "new@", LexicalScope::AUTOMATIC); func->set_ports(0); pform_set_constructor_return(func); pform_set_this_class(loc, func);