From 31d4aa9a77636c80f9617b2e73ba996eea3432ba Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 2 Mar 2012 21:16:53 -0800 Subject: [PATCH] Handle complexities of class name pre-declarations Class names can be declared early, before definitions, so that the name can be used as a type name. This thus allows class definitions to be separate from the declaration. This creates some complexity in the parser, since the lexor knows about the class names. --- lexor.lex | 2 +- parse.y | 118 +++++++++++++++++++++++++++++++++----------------- parse_misc.h | 2 + pform_types.h | 7 +++ 4 files changed, 88 insertions(+), 41 deletions(-) diff --git a/lexor.lex b/lexor.lex index b44d47166..64d6f2e3c 100644 --- a/lexor.lex +++ b/lexor.lex @@ -51,7 +51,7 @@ */ extern YYLTYPE yylloc; -static char* strdupnew(char const *str) +char* strdupnew(char const *str) { return str ? strcpy(new char [strlen(str)+1], str) : 0; } diff --git a/parse.y b/parse.y index 411875217..6874ba872 100644 --- a/parse.y +++ b/parse.y @@ -118,33 +118,6 @@ list* make_range_from_width(uint64_t wid) return range; } -#if 0 -/* - * Make a range vector from an existing pair of expressions. - */ -static vector* make_range_vector(list*that) -{ - assert(that->size() == 2); - vector*tmp = new vector (2); - tmp->at(0) = that->front(); - tmp->at(1) = that->back(); - delete that; - return tmp; -} -#endif -#if 0 -/* - * Make a range vector from a width. Generate the msb and lsb - * expressions to get the canonical range for the given width. - */ -static vector* make_range_vector(uint64_t wid) -{ - vector*tmp = new vector (2); - tmp->at(0) = new PENumber(new verinum(wid-1, integer_width)); - tmp->at(1) = new PENumber(new verinum((uint64_t)0, integer_width)); - return tmp; -} -#endif static list* list_from_identifier(char*id) { list*tmp = new list; @@ -342,6 +315,7 @@ static void current_task_set_statement(vector*s) struct_type_t*struct_type; data_type_t*data_type; + class_type_t*class_type; verinum* number; @@ -464,8 +438,7 @@ static void current_task_set_statement(vector*s) %type udp_initial udp_init_opt %type udp_initial_expr_opt -%type register_variable net_variable endname_opt -%type class_declaration_extends_opt +%type register_variable net_variable endname_opt class_declaration_endname_opt %type register_variable_list net_variable_list %type list_of_identifiers loop_variables %type list_of_port_identifiers @@ -511,6 +484,8 @@ static void current_task_set_statement(vector*s) %type list_of_variable_decl_assignments %type data_type data_type_or_implicit +%type class_declaration_extends_opt +%type class_identifier %type struct_union_member %type struct_union_member_list %type struct_data_type @@ -596,30 +571,71 @@ assignment_pattern /* IEEE1800-2005: A.6.7.1 */ ; class_declaration /* IEEE1800-2005: A.1.2 */ - : K_virtual_opt K_class IDENTIFIER class_declaration_extends_opt ';' + : K_virtual_opt K_class class_identifier class_declaration_extends_opt ';' class_items_opt K_endclass - { // Process a class + { // Process a class. if ($4) { yyerror(@4, "sorry: Class extends not supported yet."); - delete[]$4; } yyerror(@2, "sorry: Class declarations not supported yet."); } - endname_opt - { - if ($9 && strcmp($3,$9)!=0) { + class_declaration_endname_opt + { // Wrap up the class. + if ($9 && $3 && $3->name != $9) { yyerror(@9, "error: Class end name doesn't match class name."); delete[]$9; } - delete[]$3; } ; +class_identifier + : IDENTIFIER + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($1); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$1; + $$ = tmp; + } + | TYPE_IDENTIFIER + { class_type_t*tmp = dynamic_cast($1); + if (tmp == 0) { + yyerror(@1, "Type name is not a predeclared class name."); + } + $$ = tmp; + } + ; + + /* The endname after a class declaration is a little tricky because + the class name is detected by the lexor as a TYPE_IDENTIFER if it + does indeed match a name. */ +class_declaration_endname_opt + : ':' TYPE_IDENTIFIER + { class_type_t*tmp = dynamic_cast ($2); + if (tmp == 0) { + yyerror(@2, "error: class declaration endname is not a class name\n"); + $$ = 0; + } else { + $$ = strdupnew(tmp->name.str()); + } + } + | ':' IDENTIFIER + { $$ = $2; } + | + { $$ = 0; } + ; + /* This rule implements [ extends class_type ] in the - class_declaration. It is not a rule of its own in the LRM. */ + class_declaration. It is not a rule of its own in the LRM. + + Note that for this to be correct, the identifier after the + extends keyword must be a class name. Therefore, match + TYPE_IDENTIFIER instead of IDENTIFIER, and this rule will return + a data_type. */ class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ - : K_extends IDENTIFIER + : K_extends TYPE_IDENTIFIER { $$ = $2; } | { $$ = 0; } @@ -662,6 +678,16 @@ class_item /* IEEE1800-2005: A.1.8 */ /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ + | property_qualifier_opt data_type error ';' + { yyerror(@3, "error: Errors in variable names after data type."); + yyerrok; + } + + | property_qualifier_opt IDENTIFIER error ';' + { yyerror(@3, "error: %s doesn't name a type.", $2); + yyerrok; + } + | K_function K_new error K_endfunction endnew_opt { yyerror(@1, "error: I give up on this class constructor declaration."); yyerrok; @@ -1591,7 +1617,13 @@ type_declaration /* These are forward declarations... */ | K_typedef K_class IDENTIFIER ';' - { yyerror(@1, "sorry: Class forward declarations not supported yet.") } + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($3); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$3; + } | K_typedef K_enum IDENTIFIER ';' { yyerror(@1, "sorry: Enum forward declarations not supported yet.") } | K_typedef K_struct IDENTIFIER ';' @@ -1599,7 +1631,13 @@ type_declaration | K_typedef K_union IDENTIFIER ';' { yyerror(@1, "sorry: Union forward declarations not supported yet.") } | K_typedef IDENTIFIER ';' - { yyerror(@1, "sorry: Class forward declarations not supported yet.") } + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($2); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$2; + } ; /* The structure for an enumeration data type is the keyword "enum", diff --git a/parse_misc.h b/parse_misc.h index 6d1aed925..037fefffe 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -95,4 +95,6 @@ extern verinum*make_unsized_binary(const char*txt); extern verinum*make_unsized_octal(const char*txt); extern verinum*make_unsized_hex(const char*txt); +extern char* strdupnew(char const *str); + #endif diff --git a/pform_types.h b/pform_types.h index ab700cadc..5e5a4a48f 100644 --- a/pform_types.h +++ b/pform_types.h @@ -121,6 +121,13 @@ struct real_type_t : public data_type_t { int type_code; }; +struct class_type_t : public data_type_t { + inline explicit class_type_t(perm_string n) + : name(n) { } + + perm_string name; +}; + /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name