More class syntax

Part of ongoing parser work to support SystemVerilog classes.
This commit is contained in:
Stephen Williams 2012-02-19 10:29:50 -08:00
parent 5880a3ad8f
commit 8456252c0c
6 changed files with 306 additions and 405 deletions

662
parse.y
View File

@ -49,8 +49,9 @@ static struct {
ivl_variable_type_t var_type;
bool sign_flag;
list<PExpr*>* range;
data_type_t* data_type;
} port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT,
IVL_VT_NO_TYPE, false, 0};
IVL_VT_NO_TYPE, false, 0, 0};
/* The task and function rules need to briefly hold the pointer to the
task/function that is currently in progress. */
@ -106,7 +107,7 @@ static list<pair<perm_string,PExpr*> >* make_port_list(list<pair<perm_string,
return tmp;
}
static list<PExpr*>* make_range_from_width(uint64_t wid)
list<PExpr*>* make_range_from_width(uint64_t wid)
{
list<PExpr*>*range = new list<PExpr*>;
@ -447,8 +448,8 @@ static void current_task_set_statement(vector<Statement*>*s)
%type <flag> from_exclude
%type <number> number pos_neg_number
%type <flag> unsigned_signed_opt signed_unsigned_opt
%type <flag> K_packed_opt K_reg_opt
%type <flag> udp_reg_opt edge_operator automatic_opt
%type <flag> K_automatic_opt K_packed_opt K_reg_opt K_virtual_opt
%type <flag> udp_reg_opt edge_operator
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
%type <letter> udp_input_sym udp_output_sym
%type <text> udp_input_list udp_sequ_entry udp_comb_entry
@ -472,7 +473,7 @@ static void current_task_set_statement(vector<Statement*>*s)
%type <mports> list_of_ports module_port_list_opt list_of_port_declarations module_attribute_foreign
%type <value_range> parameter_value_range parameter_value_ranges
%type <value_range> parameter_value_ranges_opt
%type <expr> value_range_expression
%type <expr> task_port_decl_expr_opt value_range_expression
%type <named_pexprs> enum_name_list enum_name
%type <enum_type> enum_data_type
@ -514,7 +515,7 @@ static void current_task_set_statement(vector<Statement*>*s)
%type <dimensions> dimensions_opt dimensions
%type <nettype> net_type var_type net_type_opt
%type <gatetype> gatetype switchtype
%type <porttype> port_type
%type <porttype> port_direction port_direction_opt
%type <datatype> primitive_type primitive_type_opt bit_logic
%type <parmvalue> parameter_value_opt
@ -573,6 +574,73 @@ source_file
| source_file description
;
class_declaration /* IEEE1800-2005: A.1.2 */
: K_virtual_opt K_class IDENTIFIER ';'
class_items_opt K_endclass endname_opt
{ // Process a class
if ($7 && strcmp($3,$7)!=0) {
yyerror(@7, "error: Class end name doesn't match class name.");
delete[]$7;
}
yyerror(@2, "sorry: Class declarations not supported yet.");
}
;
class_items_opt
: class_items
|
;
class_items
: class_items class_item
| class_item
;
class_item /* IEEE1800-2005: A.1.8 */
/* class_constructor_declaration */
: K_function K_new '(' task_port_decl_list_opt ')' ';'
K_endfunction endnew_opt
/* Class properties... */
| data_type list_of_variable_decl_assignments ';'
/* Here are some error matching rules to help recover from various
syntax errors within a class declaration. */
| K_function K_new error K_endfunction endnew_opt
{ yyerror(@1, "error: I give up on this class constructor declaration.");
yyerrok;
}
;
data_type /* IEEE1800-2005: A.2.2.1 */
: struct_data_type
{ $$ = $1; }
| enum_data_type
{ $$ = $1; }
| atom2_type signed_unsigned_opt
{ atom2_type_t*tmp = new atom2_type_t($1, $2);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| TYPE_IDENTIFIER
{ $$ = $1; }
| K_string
{ yyerror(@1, "sorry: String data type not supported.");
$$ = 0;
}
;
endnew_opt : ':' K_new | ;
implicit_class_handle /* IEEE1800-2005: A.8.4 */
: K_this
| K_super
;
number : BASED_NUMBER
{ $$ = $1; based_size = 0;}
| DEC_NUMBER
@ -703,11 +771,6 @@ block_item_decl
if ($1) delete $1;
}
| attribute_list_opt atom2_type signed_unsigned_opt register_variable_list ';'
{ pform_set_integer_2atom($2, $3, $4);
if ($1) delete $1;
}
/* variable declarations. Note that data_type can be 0 if we are
recovering from an error. */
@ -782,21 +845,27 @@ block_item_decls_opt
|
;
data_type
: struct_data_type
{ $$ = $1; }
| enum_data_type
{ $$ = $1; }
| TYPE_IDENTIFIER
{ $$ = $1; }
;
/* Type declarations are parsed here. The rule actions call pform
functions that add the declaration to the current lexical scope. */
type_declaration
: K_typedef data_type IDENTIFIER ';'
{ perm_string name = lex_strings.make($3);
pform_set_typedef(name, $2);
delete[]$3;
}
/* These are forward declarations... */
| K_typedef K_class IDENTIFIER ';'
{ yyerror(@1, "sorry: Class forward declarations not supported yet.") }
| K_typedef K_enum IDENTIFIER ';'
{ yyerror(@1, "sorry: Enum forward declarations not supported yet.") }
| K_typedef K_struct IDENTIFIER ';'
{ yyerror(@1, "sorry: Struct forward declarations not supported yet.") }
| 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.") }
;
/* The structure for an enumeration data type is the keyword "enum",
@ -2620,19 +2689,28 @@ atom2_type
assignments. It is more limited than the general expr_primary
rule to reflect the rules for assignment l-values. */
lpvalue
: hierarchy_identifier
{ PEIdent*tmp = new PEIdent(*$1);
FILE_NAME(tmp, @1);
$$ = tmp;
delete $1;
}
| '{' expression_list_proper '}'
{ PEConcat*tmp = new PEConcat(*$2);
FILE_NAME(tmp, @1);
delete $2;
$$ = tmp;
}
;
: hierarchy_identifier
{ PEIdent*tmp = new PEIdent(*$1);
FILE_NAME(tmp, @1);
$$ = tmp;
delete $1;
}
| implicit_class_handle '.' hierarchy_identifier
{ yyerror(@1, "sorry: implicit class handles (this/super) not supported.");
PEIdent*tmp = new PEIdent(*$3);
FILE_NAME(tmp, @1);
$$ = tmp;
delete $3;
}
| '{' expression_list_proper '}'
{ PEConcat*tmp = new PEConcat(*$2);
FILE_NAME(tmp, @1);
delete $2;
$$ = tmp;
}
;
/* Continuous assignments have a list of individual assignments. */
@ -2694,7 +2772,7 @@ module
pform_check_timeunit_prec();
}
module_item_list_opt
module_end endname_opt
module_end
{ Module::UCDriveType ucd;
// The lexor detected `unconnected_drive directives and
// marked what it found in the uc_drive variable. Use that
@ -2725,18 +2803,25 @@ module
break;
}
}
if ($14 && (strcmp($3,$14) != 0)) {
yyerror(@14, "error: End name doesn't match module/program name");
}
if ($2 == K_program) {
yyerror(@2, "sorry: Program blocks not supported yet.");
}
pform_endmodule($3, in_celldefine, ucd);
delete[]$3;
if ($14) delete[]$14;
have_timeunit_decl = false; // We will allow decls again.
have_timeprec_decl = false;
}
endname_opt
{ // Last step: check any closing name. This is done late so
// that the parser can look ahead to detect the present
// endname_opt but still have the pform_endmodule() called
// early enough that the lexor can know we are outside the
// module.
if ($15 && (strcmp($3,$15) != 0)) {
yyerror(@15, "error: End name doesn't match module/program name");
}
if ($15) delete[]$15;
}
;
/* Modules start with module/macromodule or program keyword, and end
@ -2890,7 +2975,7 @@ module_item
delete $4;
}
| port_type unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';'
| port_direction unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';'
{ pform_set_port_type(@1, $5, $3, $2, $1);
}
@ -2898,7 +2983,7 @@ module_item
input wire signed [h:l] <list>;
This creates the wire and sets the port type all at once. */
| port_type net_type unsigned_signed_opt range_opt list_of_identifiers ';'
| port_direction net_type unsigned_signed_opt range_opt list_of_identifiers ';'
{ pform_makewire(@1, $4, $3, $5, $2, $1, IVL_VT_NO_TYPE, 0,
SR_BOTH);
}
@ -2919,7 +3004,7 @@ module_item
delete $5;
}
| port_type K_wreal list_of_identifiers ';'
| port_direction K_wreal list_of_identifiers ';'
{ pform_makewire(@1, 0, true, $3, NetNet::WIRE, $1,
IVL_VT_REAL, 0, SR_BOTH);
}
@ -2940,7 +3025,7 @@ module_item
yyerror(@2, "error: reg variables cannot be inouts.");
}
| port_type unsigned_signed_opt range_opt delay3_opt error ';'
| port_direction unsigned_signed_opt range_opt delay3_opt error ';'
{ yyerror(@1, "error: Invalid variable list"
" in port declaration.");
if ($3) delete $3;
@ -3072,6 +3157,8 @@ module_item
| attribute_list_opt K_analog analog_statement
{ pform_make_analog_behavior(@2, IVL_PR_ALWAYS, $3); }
| class_declaration
/* The task declaration rule matches the task declaration
header, then pushes the function scope. This causes the
definitions in the task_body to take on the scope of the task
@ -3080,7 +3167,7 @@ module_item
statements in the task body. But we continue to accept it as an
extension. */
| K_task automatic_opt IDENTIFIER ';'
| K_task K_automatic_opt IDENTIFIER ';'
{ assert(current_task == 0);
current_task = pform_push_task_scope(@1, $3, $2);
}
@ -3098,7 +3185,7 @@ module_item
delete $7;
}
| K_task automatic_opt IDENTIFIER '('
| K_task K_automatic_opt IDENTIFIER '('
{ assert(current_task == 0);
current_task = pform_push_task_scope(@1, $3, $2);
}
@ -3117,7 +3204,7 @@ module_item
delete $10;
}
| K_task automatic_opt IDENTIFIER '(' ')' ';'
| K_task K_automatic_opt IDENTIFIER '(' ')' ';'
{ assert(current_task == 0);
current_task = pform_push_task_scope(@1, $3, $2);
}
@ -3137,7 +3224,7 @@ module_item
delete $9;
}
| K_task automatic_opt IDENTIFIER error K_endtask
| K_task K_automatic_opt IDENTIFIER error K_endtask
{
assert(current_task == 0);
delete[]$3;
@ -3148,7 +3235,7 @@ module_item
definitions in the func_body to take on the scope of the function
instead of the module. */
| K_function automatic_opt function_range_or_type_opt IDENTIFIER ';'
| K_function K_automatic_opt function_range_or_type_opt IDENTIFIER ';'
{ assert(current_function == 0);
current_function = pform_push_function_scope(@1, $4, $2);
}
@ -3175,7 +3262,7 @@ module_item
delete[]$4;
}
| K_function automatic_opt function_range_or_type_opt IDENTIFIER
| K_function K_automatic_opt function_range_or_type_opt IDENTIFIER
{ assert(current_function == 0);
current_function = pform_push_function_scope(@1, $4, $2);
}
@ -3206,7 +3293,7 @@ module_item
yyerror(@4, "error: Empty parenthesis syntax requires SystemVerilog.");
}
}
| K_function automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction
| K_function K_automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction
{ /* */
if (current_function) {
pform_pop_scope();
@ -3347,11 +3434,6 @@ module_item
{ pform_set_timeprecision($2, true, true); }
;
automatic_opt
: K_automatic { $$ = true; }
| { $$ = false;}
;
generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); }
generate_case_items
@ -3962,11 +4044,16 @@ port_reference_list
}
;
port_type
: K_input { $$ = NetNet::PINPUT; }
| K_output { $$ = NetNet::POUTPUT; }
| K_inout { $$ = NetNet::PINOUT; }
;
port_direction /* IEEE1800-2005 A.1.3 */
: K_input { $$ = NetNet::PINPUT; }
| K_output { $$ = NetNet::POUTPUT; }
| K_inout { $$ = NetNet::PINOUT; }
;
port_direction_opt
: port_direction { $$ = $1; }
| { $$ = NetNet::PINPUT; }
;
range
: '[' expression ':' expression ']'
@ -5024,24 +5111,8 @@ task_item
;
task_port_item
: K_input K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINPUT,
$2 ? IVL_VT_LOGIC :
IVL_VT_NO_TYPE,
$3, $4, $5,
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp = pform_make_task_ports(NetNet::POUTPUT,
$2 ? IVL_VT_LOGIC :
IVL_VT_NO_TYPE,
$3, $4, $5,
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINOUT,
: port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp = pform_make_task_ports($1,
$2 ? IVL_VT_LOGIC :
IVL_VT_NO_TYPE,
$3, $4, $5,
@ -5052,26 +5123,9 @@ task_port_item
/* When the port is an integer, infer a signed vector of the integer
shape. Generate a range ([31:0]) to make it work. */
| K_input K_integer list_of_identifiers ';'
| port_direction K_integer list_of_identifiers ';'
{ list<PExpr*>*range_stub = make_range_from_width(integer_width);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, true,
range_stub, $3,
@1.text, @1.first_line, true);
$$ = tmp;
}
| K_output K_integer list_of_identifiers ';'
{ list<PExpr*>*range_stub = make_range_from_width(integer_width);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_LOGIC, true,
range_stub, $3,
@1.text, @1.first_line, true);
$$ = tmp;
}
| K_inout K_integer list_of_identifiers ';'
{ list<PExpr*>*range_stub = make_range_from_width(integer_width);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINOUT,
IVL_VT_LOGIC, true,
svector<PWire*>*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true,
range_stub, $3,
@1.text, @1.first_line, true);
$$ = tmp;
@ -5079,26 +5133,9 @@ task_port_item
/* Ports can be time with a width of [63:0] (unsigned). */
| K_input K_time list_of_identifiers ';'
| port_direction K_time list_of_identifiers ';'
{ list<PExpr*>*range_stub = make_range_from_width(64);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, false,
range_stub, $3,
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_time list_of_identifiers ';'
{ list<PExpr*>*range_stub = make_range_from_width(64);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_LOGIC, false,
range_stub, $3,
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_time list_of_identifiers ';'
{ list<PExpr*>*range_stub = make_range_from_width(64);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINOUT,
IVL_VT_LOGIC, false,
svector<PWire*>*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false,
range_stub, $3,
@1.text, @1.first_line);
$$ = tmp;
@ -5106,31 +5143,13 @@ task_port_item
/* Ports can be real or realtime. */
| K_input real_or_realtime list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_REAL, false,
0, $3,
@1.text, @1.first_line);
$$ = tmp;
}
| K_output real_or_realtime list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_REAL, true,
0, $3,
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout real_or_realtime list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT,
IVL_VT_REAL, true,
0, $3,
@1.text, @1.first_line);
$$ = tmp;
}
;
| port_direction real_or_realtime list_of_identifiers ';'
{ svector<PWire*>*tmp = pform_make_task_ports($1, IVL_VT_REAL, false,
0, $3, @1.text, @1.first_line);
$$ = tmp;
}
;
task_item_list
: task_item_list task_item
@ -5152,173 +5171,56 @@ task_item_list_opt
task_port_decl
: K_input K_reg_opt unsigned_signed_opt range_opt IDENTIFIER
{ port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
: port_direction K_reg_opt unsigned_signed_opt range_opt IDENTIFIER
{ port_declaration_context.port_type = $1;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_reg_opt unsigned_signed_opt range_opt IDENTIFIER
{ port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_LOGIC, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_reg_opt unsigned_signed_opt range_opt IDENTIFIER
{ port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT,
IVL_VT_LOGIC, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
| K_input bit_logic unsigned_signed_opt range_opt IDENTIFIER
{
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.var_type = $2;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp =
pform_make_task_ports(NetNet::PINPUT, $2, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
| K_output bit_logic unsigned_signed_opt range_opt IDENTIFIER
{
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.var_type = $2;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp =
pform_make_task_ports(NetNet::POUTPUT, $2, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout bit_logic unsigned_signed_opt range_opt IDENTIFIER
{
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.var_type = $2;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp =
pform_make_task_ports(NetNet::PINOUT, $2, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
| port_direction_opt bit_logic unsigned_signed_opt range_opt IDENTIFIER
{ port_declaration_context.port_type = $1;
port_declaration_context.var_type = $2;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range($4);
svector<PWire*>*tmp = pform_make_task_ports($1, $2, $3,
$4, list_from_identifier($5),
@1.text, @1.first_line);
$$ = tmp;
}
/* Ports can be integer with a width of [31:0]. */
| K_input K_integer IDENTIFIER
| port_direction_opt K_integer IDENTIFIER
{ list<PExpr*>*range_stub = make_range_from_width(integer_width);
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.port_type = $1;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = true;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, true,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line, true);
$$ = tmp;
}
| K_output K_integer IDENTIFIER
{ list<PExpr*>*range_stub = make_range_from_width(integer_width);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = true;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_LOGIC, true,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line, true);
$$ = tmp;
}
| K_inout K_integer IDENTIFIER
{ list<PExpr*>*range_stub = make_range_from_width(integer_width);
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = true;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINOUT,
IVL_VT_LOGIC, true,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line, true);
svector<PWire*>*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line, true);
$$ = tmp;
}
/* Ports can be time with a width of [63:0] (unsigned). */
| K_input K_time IDENTIFIER
| port_direction_opt K_time IDENTIFIER
{ list<PExpr*>*range_stub = make_range_from_width(64);
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.port_type = $1;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_time IDENTIFIER
{ list<PExpr*>*range_stub = make_range_from_width(64);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_time IDENTIFIER
{ list<PExpr*>*range_stub = make_range_from_width(64);
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.var_type = IVL_VT_LOGIC;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINOUT,
IVL_VT_LOGIC, false,
svector<PWire*>*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
@ -5327,90 +5229,40 @@ task_port_decl
/* Ports can be real or realtime. */
| K_input real_or_realtime IDENTIFIER
{ port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = 0;
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_REAL, false,
0, list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_output real_or_realtime IDENTIFIER
{ port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = 0;
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_REAL, false,
0, list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout real_or_realtime IDENTIFIER
{ port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = 0;
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT,
IVL_VT_REAL, false,
0, list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| port_direction_opt real_or_realtime IDENTIFIER
{ port_declaration_context.port_type = $1;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = 0;
svector<PWire*>*tmp = pform_make_task_ports($1, IVL_VT_REAL, false,
0, list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
/* Ports can be 2-value atom types. */
| K_input atom2_type signed_unsigned_opt IDENTIFIER
{ list<PExpr*>*range_stub = make_range_from_width($2);
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.var_type = IVL_VT_BOOL;
port_declaration_context.sign_flag = $3;
| port_direction_opt data_type IDENTIFIER task_port_decl_expr_opt
{ port_declaration_context.port_type = $1;
port_declaration_context.var_type = IVL_VT_NO_TYPE;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINPUT,
IVL_VT_BOOL, $3,
range_stub, list_from_identifier($4),
@1.text, @1.first_line);
port_declaration_context.range = 0;
port_declaration_context.data_type = $2;
svector<PWire*>*tmp = pform_make_task_ports(@1, $1, $2,
list_from_identifier($3));
$$ = tmp;
if ($4) {
yyerror(@4, "sorry: Port default expressions not supported yet.");
delete $4;
}
}
| K_output atom2_type signed_unsigned_opt IDENTIFIER
{ list<PExpr*>*range_stub = make_range_from_width($2);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.var_type = IVL_VT_BOOL;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::POUTPUT,
IVL_VT_BOOL, $3,
range_stub, list_from_identifier($4),
@1.text, @1.first_line);
$$ = tmp;
}
;
| K_inout atom2_type signed_unsigned_opt IDENTIFIER
{ list<PExpr*>*range_stub = make_range_from_width($2);
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.var_type = IVL_VT_BOOL;
port_declaration_context.sign_flag = $3;
delete port_declaration_context.range;
port_declaration_context.range = copy_range(range_stub);
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINOUT,
IVL_VT_BOOL, $3,
range_stub, list_from_identifier($4),
@1.text, @1.first_line);
$$ = tmp;
}
;
task_port_decl_expr_opt
: '=' expression { $$ = $2; }
| { $$ = 0; }
;
task_port_decl_list_opt
: task_port_decl_list { $$ = $1; }
@ -5418,40 +5270,40 @@ task_port_decl_list_opt
;
task_port_decl_list
: task_port_decl_list ',' task_port_decl
{ svector<PWire*>*tmp = new svector<PWire*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
}
| task_port_decl
{ $$ = $1; }
| task_port_decl_list ',' IDENTIFIER
{ svector<PWire*>*new_decl
= pform_make_task_ports(
port_declaration_context.port_type,
port_declaration_context.var_type,
port_declaration_context.sign_flag,
copy_range(port_declaration_context.range),
list_from_identifier($3),
@3.text, @3.first_line);
svector<PWire*>*tmp = new svector<PWire*>(*$1, *new_decl);
delete $1;
delete new_decl;
$$ = tmp;
}
| task_port_decl_list ','
{
yyerror(@2, "error: NULL port declarations are not "
"allowed.");
}
| task_port_decl_list ';'
{
yyerror(@2, "error: ';' is an invalid port declaration "
"separator.");
}
;
;
: task_port_decl_list ',' task_port_decl
{ svector<PWire*>*tmp = new svector<PWire*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
}
| task_port_decl
{ $$ = $1; }
| task_port_decl_list ',' IDENTIFIER
{ // The declaration is already parsed, apply it to IDENTIFIER
svector<PWire*>*new_decl;
if (port_declaration_context.var_type == IVL_VT_NO_TYPE) {
assert(port_declaration_context.data_type);
new_decl = pform_make_task_ports(@3, port_declaration_context.port_type,
port_declaration_context.data_type,
list_from_identifier($3));
} else {
new_decl = pform_make_task_ports(port_declaration_context.port_type,
port_declaration_context.var_type,
port_declaration_context.sign_flag,
copy_range(port_declaration_context.range),
list_from_identifier($3),
@3.text, @3.first_line);
}
svector<PWire*>*tmp = new svector<PWire*>(*$1, *new_decl);
delete $1;
delete new_decl;
$$ = tmp;
}
| task_port_decl_list ','
{ yyerror(@2, "error: NULL port declarations are not allowed."); }
| task_port_decl_list ';'
{ yyerror(@2, "error: ';' is an invalid port declaration separator."); }
;
udp_body
: K_table { lex_start_table(); }
@ -5703,5 +5555,11 @@ udp_primitive
}
;
K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ;
K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ;
/* Many keywords can be optional in the syntax, although their
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_virtual_opt : K_virtual { $$ = true; } | { $$ = false; } ;

View File

@ -20,6 +20,8 @@
# include "config.h"
# include "parse_misc.h"
# include <cstdarg>
# include <cstdio>
# include <iostream>
extern const char*vl_file;
@ -42,10 +44,16 @@ void VLerror(const char*msg)
cerr << yylloc.text << ":" << yylloc.first_line << ": " << msg << endl;
}
void VLerror(const YYLTYPE&loc, const char*msg)
void VLerror(const YYLTYPE&loc, const char*msg, ...)
{
va_list ap;
va_start(ap, msg);
fprintf(stderr, "%s:%d: ", loc.text, loc.first_line);
vfprintf(stderr, msg, ap);
fprintf(stderr, "\n");
error_count += 1;
cerr << loc << ": " << msg << endl;
based_size = 0; /* Clear the base information if we have an error. */
}

View File

@ -56,7 +56,7 @@ extern YYLTYPE yylloc;
*/
extern int VLlex();
extern void VLerror(const char*msg);
extern void VLerror(const YYLTYPE&loc, const char*msg);
extern void VLerror(const YYLTYPE&loc, const char*msg, ...) __attribute__((format(printf,2,3)));
#define yywarn VLwarn
extern void VLwarn(const YYLTYPE&loc, const char*msg);

View File

@ -2193,6 +2193,22 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
return res;
}
svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
data_type_t*vtype,
list<perm_string>*names)
{
atom2_type_t*atype = dynamic_cast<atom2_type_t*> (vtype);
if (atype == 0) {
VLerror(loc, "sorry: Given type not supported here.");
return 0;
}
list<PExpr*>*range_tmp = make_range_from_width(atype->type_code);
return pform_make_task_ports(pt, IVL_VT_BOOL, atype->signed_flag,
range_tmp, names, loc.text, loc.first_line);
}
void pform_set_attrib(perm_string name, perm_string key, char*value)
{
if (PWire*cur = lexical_scope->wires_find(name)) {
@ -2541,6 +2557,11 @@ void pform_set_integer_2atom(uint64_t width, bool signed_flag, list<perm_string>
*/
void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list<perm_string>*names)
{
if (atom2_type_t*atom2_type = dynamic_cast<atom2_type_t*> (data_type)) {
pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names);
return;
}
if (struct_type_t*struct_type = dynamic_cast<struct_type_t*> (data_type)) {
pform_set_struct_type(struct_type, names);
return;

View File

@ -117,6 +117,8 @@ struct lgate {
unsigned lineno;
};
extern std::list<PExpr*>* make_range_from_width(uint64_t wid);
/* Use this function to transform the parted form of the attribute
list to the attribute map that is used later. */
extern void pform_bind_attributes(map<perm_string,PExpr*>&attributes,
@ -392,6 +394,11 @@ extern svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
unsigned lineno,
bool isint = false);
extern svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
data_type_t*vtype,
list<perm_string>*names);
/*
* These are functions that the outside-the-parser code uses the do

View File

@ -100,6 +100,13 @@ struct struct_type_t : public data_type_t {
std::auto_ptr< list<struct_member_t*> > members;
};
struct atom2_type_t : public data_type_t {
inline explicit atom2_type_t(int tc, bool flag)
: type_code(tc), signed_flag(flag) { }
int type_code;
bool signed_flag;
};
/*
* The pform_name_t is the general form for a hierarchical
* identifier. It is an ordered list of name components. Each name