diff options
Diffstat (limited to 'frontends/verilog/verilog_parser.y')
-rw-r--r-- | frontends/verilog/verilog_parser.y | 323 |
1 files changed, 275 insertions, 48 deletions
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index a30935e0a..91982e2a3 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -38,8 +38,11 @@ #include <stack> #include <string.h> #include "frontends/verilog/verilog_frontend.h" +#include "frontends/verilog/verilog_parser.tab.hh" #include "kernel/log.h" +#define YYLEX_PARAM &yylval, &yylloc + USING_YOSYS_NAMESPACE using namespace AST; using namespace VERILOG_FRONTEND; @@ -68,6 +71,20 @@ namespace VERILOG_FRONTEND { } YOSYS_NAMESPACE_END +#define SET_AST_NODE_LOC(WHICH, BEGIN, END) \ + do { (WHICH)->location.first_line = (BEGIN).first_line; \ + (WHICH)->location.first_column = (BEGIN).first_column; \ + (WHICH)->location.last_line = (END).last_line; \ + (WHICH)->location.last_column = (END).last_column; } while(0) + +#define SET_RULE_LOC(LHS, BEGIN, END) \ + do { (LHS).first_line = (BEGIN).first_line; \ + (LHS).first_column = (BEGIN).first_column; \ + (LHS).last_line = (END).last_line; \ + (LHS).last_column = (END).last_column; } while(0) + +int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); + static void append_attr(AstNode *ast, std::map<std::string, AstNode*> *al) { for (auto &it : *al) { @@ -108,9 +125,24 @@ struct specify_rise_fall { specify_triple fall; }; +static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true) +{ + auto range = new AstNode(AST_RANGE); + range->children.push_back(AstNode::mkconst_int(msb, true)); + range->children.push_back(AstNode::mkconst_int(lsb, true)); + range->is_signed = isSigned; + return range; +} + +static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true) +{ + auto range = makeRange(msb, lsb, isSigned); + parent->children.push_back(range); +} %} %define api.prefix {frontend_verilog_yy} +%define api.pure /* The union is defined in the header, so we need to provide all the * includes it requires @@ -138,7 +170,7 @@ struct specify_rise_fall { %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP -%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR +%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_WILDCARD_CONNECT %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH @@ -146,7 +178,7 @@ struct specify_rise_fall { %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT %token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY -%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND +%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND TOK_IGNORED_SPECIFY_AND %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED @@ -157,13 +189,14 @@ struct specify_rise_fall { %type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list %type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id +%type <ast> opt_enum_init %type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff %type <al> attr case_attr %type <specify_target_ptr> specify_target -%type <specify_triple_ptr> specify_triple +%type <specify_triple_ptr> specify_triple specify_opt_triple %type <specify_rise_fall_ptr> specify_rise_fall -%type <ast> specify_if specify_condition specify_opt_arg +%type <ast> specify_if specify_condition %type <ch> specify_edge // operator precedence from low to high @@ -187,6 +220,7 @@ struct specify_rise_fall { %nonassoc TOK_ELSE %debug +%locations %% @@ -229,7 +263,9 @@ attr: }; attr_opt: - attr_opt ATTR_BEGIN opt_attr_list ATTR_END | + attr_opt ATTR_BEGIN opt_attr_list ATTR_END { + SET_RULE_LOC(@$, @2, @$); + }| /* empty */; defattr: @@ -311,6 +347,7 @@ module: if (port_stubs.size() != 0) frontend_verilog_yyerror("Missing details for module port `%s'.", port_stubs.begin()->first.c_str()); + SET_AST_NODE_LOC(ast_stack.back(), @2, @$); ast_stack.pop_back(); log_assert(ast_stack.size() == 1); current_ast_mod = NULL; @@ -374,6 +411,7 @@ module_arg: node->str = *$1; node->port_id = ++port_counter; ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @1); } else { if (port_stubs.count(*$1) != 0) frontend_verilog_yyerror("Duplicate module port `%s'.", $1->c_str()); @@ -399,6 +437,7 @@ module_arg: attr wire_type range TOK_ID { AstNode *node = $2; node->str = *$4; + SET_AST_NODE_LOC(node, @4, @4); node->port_id = ++port_counter; if ($3 != NULL) node->children.push_back($3); @@ -428,7 +467,9 @@ package: }; package_body: - package_body package_body_stmt |; + package_body package_body_stmt + | // optional + ; package_body_stmt: typedef_decl | @@ -476,8 +517,9 @@ wire_type: astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; - } wire_type_token_list delay { + } wire_type_token_list { $$ = astbuf3; + SET_RULE_LOC(@$, @2, @$); }; wire_type_token_list: @@ -551,13 +593,15 @@ non_opt_range: } | '[' expr TOK_POS_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, $2->clone(), $4), AstNode::mkconst_int(1, true))); - $$->children.push_back(new AstNode(AST_ADD, $2, AstNode::mkconst_int(0, true))); + AstNode *expr = new AstNode(AST_CONCAT, $2); + $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true))); + $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); } | '[' expr TOK_NEG_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - $$->children.push_back(new AstNode(AST_ADD, $2, AstNode::mkconst_int(0, true))); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true)), $4)); + AstNode *expr = new AstNode(AST_CONCAT, $2); + $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); + $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), AstNode::mkconst_int(1, true)), $4)); } | '[' expr ']' { $$ = new AstNode(AST_RANGE); @@ -604,6 +648,7 @@ module_body: module_body_stmt: task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | + enum_decl | always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; checker_decl: @@ -855,7 +900,7 @@ specify_item: delete target; delete timing; } | - TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' { + TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' specify_triple specify_opt_triple ')' ';' { if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str()); @@ -868,8 +913,8 @@ specify_item: AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1); - AstNode *limit = $11; - AstNode *limit2 = $12; + specify_triple *limit = $11; + specify_triple *limit2 = $12; AstNode *cell = new AstNode(AST_CELL); ast_stack.back()->children.push_back(cell); @@ -880,11 +925,23 @@ specify_item: cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1))); cell->children.back()->str = "\\TYPE"; - cell->children.push_back(new AstNode(AST_PARASET, limit)); - cell->children.back()->str = "\\T_LIMIT"; + cell->children.push_back(new AstNode(AST_PARASET, limit->t_min)); + cell->children.back()->str = "\\T_LIMIT_MIN"; + + cell->children.push_back(new AstNode(AST_PARASET, limit->t_avg)); + cell->children.back()->str = "\\T_LIMIT_TYP"; + + cell->children.push_back(new AstNode(AST_PARASET, limit->t_max)); + cell->children.back()->str = "\\T_LIMIT_MAX"; + + cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_min : AstNode::mkconst_int(0, true))); + cell->children.back()->str = "\\T_LIMIT2_MIN"; - cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true))); - cell->children.back()->str = "\\T_LIMIT2"; + cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_avg : AstNode::mkconst_int(0, true))); + cell->children.back()->str = "\\T_LIMIT2_TYP"; + + cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_max : AstNode::mkconst_int(0, true))); + cell->children.back()->str = "\\T_LIMIT2_MAX"; cell->children.push_back(new AstNode(AST_PARASET, src_pen)); cell->children.back()->str = "\\SRC_PEN"; @@ -913,8 +970,8 @@ specify_item: delete $1; }; -specify_opt_arg: - ',' expr { +specify_opt_triple: + ',' specify_triple { $$ = $2; } | /* empty */ { @@ -983,7 +1040,46 @@ specify_rise_fall: $$->fall = *$4; delete $2; delete $4; - }; + } | + '(' specify_triple ',' specify_triple ',' specify_triple ')' { + $$ = new specify_rise_fall; + $$->rise = *$2; + $$->fall = *$4; + delete $2; + delete $4; + delete $6; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + } | + '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { + $$ = new specify_rise_fall; + $$->rise = *$2; + $$->fall = *$4; + delete $2; + delete $4; + delete $6; + delete $8; + delete $10; + delete $12; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + } | + '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { + $$ = new specify_rise_fall; + $$->rise = *$2; + $$->fall = *$4; + delete $2; + delete $4; + delete $6; + delete $8; + delete $10; + delete $12; + delete $14; + delete $16; + delete $18; + delete $20; + delete $22; + delete $24; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + } specify_triple: expr { @@ -1031,7 +1127,7 @@ list_of_specparam_assignments: specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; specparam_assignment: - ignspec_id '=' constant_mintypmax_expression ; + ignspec_id '=' ignspec_expr ; ignspec_opt_cond: TOK_IF '(' ignspec_expr ')' | /* empty */; @@ -1048,13 +1144,15 @@ simple_path_declaration : ; path_delay_value : - '(' path_delay_expression list_of_path_delay_extra_expressions ')' - | path_delay_expression - | path_delay_expression list_of_path_delay_extra_expressions + '(' ignspec_expr list_of_path_delay_extra_expressions ')' + | ignspec_expr + | ignspec_expr list_of_path_delay_extra_expressions ; list_of_path_delay_extra_expressions : - ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions; + ',' ignspec_expr + | ',' ignspec_expr list_of_path_delay_extra_expressions + ; specify_edge_identifier : TOK_POSEDGE | TOK_NEGEDGE ; @@ -1105,16 +1203,9 @@ system_timing_arg : system_timing_args : system_timing_arg | + system_timing_args TOK_IGNORED_SPECIFY_AND system_timing_arg | system_timing_args ',' system_timing_arg ; -path_delay_expression : - ignspec_constant_expression; - -constant_mintypmax_expression : - ignspec_constant_expression - | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression - ; - // for the time being this is OK, but we may write our own expr here. // as I'm not sure it is legal to use a full expr here (probably not) // On the other hand, other rules requiring constant expressions also use 'expr' @@ -1123,10 +1214,16 @@ ignspec_constant_expression: expr { delete $1; }; ignspec_expr: - expr { delete $1; }; + expr { delete $1; } | + expr ':' expr ':' expr { + delete $1; + delete $3; + delete $5; + }; ignspec_id: - TOK_ID { delete $1; }; + TOK_ID { delete $1; } + range_or_multirange { delete $3; }; /**********************************************************************/ @@ -1224,6 +1321,85 @@ single_defparam_decl: ast_stack.back()->children.push_back(node); }; +enum_type: TOK_ENUM { + static int enum_count; + // create parent node for the enum + astbuf2 = new AstNode(AST_ENUM); + ast_stack.back()->children.push_back(astbuf2); + astbuf2->str = std::string("$enum"); + astbuf2->str += std::to_string(enum_count++); + // create the template for the names + astbuf1 = new AstNode(AST_ENUM_ITEM); + astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + } param_signed enum_base_type '{' enum_name_list '}' { // create template for the enum vars + auto tnode = astbuf1->clone(); + delete astbuf1; + astbuf1 = tnode; + tnode->type = AST_WIRE; + tnode->attributes["\\enum_type"] = AstNode::mkconst_str(astbuf2->str); + // drop constant but keep any range + delete tnode->children[0]; + tnode->children.erase(tnode->children.begin()); } + ; + +enum_base_type: int_vec param_range + | int_atom + | /* nothing */ {astbuf1->is_reg = true; addRange(astbuf1); } + ; + +int_atom: TOK_INTEGER {astbuf1->is_reg=true; addRange(astbuf1); } // probably should do byte, range [7:0] here + ; + +int_vec: TOK_REG {astbuf1->is_reg = true;} + | TOK_LOGIC {astbuf1->is_logic = true;} + ; + +enum_name_list: + enum_name_decl + | enum_name_list ',' enum_name_decl + ; + +enum_name_decl: + TOK_ID opt_enum_init { + // put in fn + log_assert(astbuf1); + log_assert(astbuf2); + auto node = astbuf1->clone(); + node->str = *$1; + delete $1; + delete node->children[0]; + node->children[0] = $2 ?: new AstNode(AST_NONE); + astbuf2->children.push_back(node); + } + ; + +opt_enum_init: + '=' basic_expr { $$ = $2; } // TODO: restrict this + | /* optional */ { $$ = NULL; } + ; + +enum_var_list: + enum_var + | enum_var_list ',' enum_var + ; + +enum_var: TOK_ID { + log_assert(astbuf1); + log_assert(astbuf2); + auto node = astbuf1->clone(); + ast_stack.back()->children.push_back(node); + node->str = *$1; + delete $1; + node->is_enum = true; + } + ; + +enum_decl: enum_type enum_var_list ';' { + //enum_type creates astbuf1 for use by typedef only + delete astbuf1; + } + ; + wire_decl: attr wire_type range { albuf = $1; @@ -1240,7 +1416,7 @@ wire_decl: } if (astbuf2 && astbuf2->children.size() != 2) frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]"); - } wire_name_list { + } delay wire_name_list { delete astbuf1; if (astbuf2 != NULL) delete astbuf2; @@ -1328,11 +1504,24 @@ wire_name_and_opt_assign: if (astbuf1->attributes.count("\\defaultvalue")) delete astbuf1->attributes.at("\\defaultvalue"); astbuf1->attributes["\\defaultvalue"] = $3; - } else - if (astbuf1->is_reg || astbuf1->is_logic) - ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3)))); - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3)); + } + else if (astbuf1->is_reg || astbuf1->is_logic){ + AstNode *assign = new AstNode(AST_ASSIGN_LE, wire, $3); + AstNode *block = new AstNode(AST_BLOCK, assign); + AstNode *init = new AstNode(AST_INITIAL, block); + + SET_AST_NODE_LOC(assign, @1, @3); + SET_AST_NODE_LOC(block, @1, @3); + SET_AST_NODE_LOC(init, @1, @3); + + ast_stack.back()->children.push_back(init); + } + else { + AstNode *assign = new AstNode(AST_ASSIGN, wire, $3); + SET_AST_NODE_LOC(assign, @1, @3); + ast_stack.back()->children.push_back(assign); + } + }; wire_name: @@ -1381,6 +1570,8 @@ wire_name: if (node->is_input || node->is_output) node->port_id = current_function_or_task_port_id++; } + //FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column... + SET_AST_NODE_LOC(node, @1, @1); ast_stack.back()->children.push_back(node); delete $1; @@ -1394,7 +1585,9 @@ assign_expr_list: assign_expr: lvalue '=' expr { - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3)); + AstNode *node = new AstNode(AST_ASSIGN, $1, $3); + SET_AST_NODE_LOC(node, @$, @$); + ast_stack.back()->children.push_back(node); }; typedef_decl: @@ -1434,7 +1627,12 @@ typedef_decl: ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1)); ast_stack.back()->children.back()->str = *$4; - }; + } | + TOK_TYPEDEF enum_type TOK_ID ';' { + ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1)); + ast_stack.back()->children.back()->str = *$3; + } + ; cell_stmt: attr TOK_ID { @@ -1474,14 +1672,19 @@ single_cell: astbuf2->str = *$1; delete $1; ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')' | + } '(' cell_port_list ')' { + SET_AST_NODE_LOC(astbuf2, @1, @$); + } | TOK_ID non_opt_range { astbuf2 = astbuf1->clone(); if (astbuf2->type != AST_PRIMITIVE) astbuf2->str = *$1; delete $1; ast_stack.back()->children.push_back(new AstNode(AST_CELLARRAY, $2, astbuf2)); - } '(' cell_port_list ')'; + } '(' cell_port_list ')'{ + SET_AST_NODE_LOC(astbuf2, @1, @$); + SET_AST_NODE_LOC(astbuf3, @1, @$); + }; prim_list: single_prim | @@ -1580,6 +1783,11 @@ cell_port: node->children.back()->str = *$3; delete $3; free_attr($1); + } | + attr TOK_WILDCARD_CONNECT { + if (!sv_mode) + frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode."); + astbuf2->attributes[ID(wildcard_port_conns)] = AstNode::mkconst_int(1, false); }; always_comb_or_latch: @@ -1611,8 +1819,13 @@ always_stmt: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @6, @6); ast_stack.pop_back(); + + SET_AST_NODE_LOC(ast_stack.back(), @2, @$); ast_stack.pop_back(); + + SET_RULE_LOC(@$, @2, @$); } | attr always_comb_or_latch { AstNode *node = new AstNode(AST_ALWAYS); @@ -1967,6 +2180,7 @@ behavioral_stmt: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @13, @13); ast_stack.pop_back(); ast_stack.pop_back(); } | @@ -1980,6 +2194,7 @@ behavioral_stmt: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @7, @7); ast_stack.pop_back(); ast_stack.pop_back(); } | @@ -1993,6 +2208,7 @@ behavioral_stmt: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @7, @7); ast_stack.pop_back(); ast_stack.pop_back(); } | @@ -2000,14 +2216,18 @@ behavioral_stmt: AstNode *node = new AstNode(AST_CASE); AstNode *block = new AstNode(AST_BLOCK); AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block); + SET_AST_NODE_LOC(cond, @4, @4); ast_stack.back()->children.push_back(node); node->children.push_back(new AstNode(AST_REDUCE_BOOL, $4)); node->children.push_back(cond); ast_stack.push_back(node); ast_stack.push_back(block); append_attr(node, $1); - } behavioral_stmt optional_else { + } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @7, @7); + } optional_else { ast_stack.pop_back(); + SET_AST_NODE_LOC(ast_stack.back(), @2, @9); ast_stack.pop_back(); } | case_attr case_type '(' expr ')' { @@ -2015,7 +2235,9 @@ behavioral_stmt: ast_stack.back()->children.push_back(node); ast_stack.push_back(node); append_attr(node, $1); + SET_AST_NODE_LOC(ast_stack.back(), @4, @4); } opt_synopsys_attr case_body TOK_ENDCASE { + SET_AST_NODE_LOC(ast_stack.back(), @2, @9); case_type_stack.pop_back(); ast_stack.pop_back(); }; @@ -2067,10 +2289,14 @@ optional_else: TOK_ELSE { AstNode *block = new AstNode(AST_BLOCK); AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block); + SET_AST_NODE_LOC(cond, @1, @1); + ast_stack.pop_back(); ast_stack.back()->children.push_back(cond); ast_stack.push_back(block); - } behavioral_stmt | + } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @3, @3); + } | /* empty */ %prec FAKE_THEN; case_body: @@ -2091,6 +2317,7 @@ case_item: case_type_stack.push_back(0); } behavioral_stmt { case_type_stack.pop_back(); + SET_AST_NODE_LOC(ast_stack.back(), @4, @4); ast_stack.pop_back(); ast_stack.pop_back(); }; |