/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * --- * * The Verilog frontend. * * This frontend is using the AST frontend library (see frontends/ast/). * Thus this frontend does not generate RTLIL code directly but creates an * AST directly from the Verilog parse tree and then passes this AST to * the AST frontend library. * * --- * * This is the actual bison parser for Verilog code. The AST ist created directly * from the bison reduce functions here. Note that this code uses a few global * variables to hold the state of the AST generator and therefore this parser is * not reentrant. * */ %{ #include #include #include "verilog_frontend.h" #include "kernel/log.h" using namespace AST; using namespace VERILOG_FRONTEND; namespace VERILOG_FRONTEND { int port_counter; std::map port_stubs; std::map attr_list, default_attr_list; std::map *albuf; std::vector ast_stack; struct AstNode *astbuf1, *astbuf2, *astbuf3; struct AstNode *current_function_or_task; struct AstNode *current_ast, *current_ast_mod; int current_function_or_task_port_id; std::vector case_type_stack; bool default_nettype_wire; bool sv_mode; } static void append_attr(AstNode *ast, std::map *al) { for (auto &it : *al) { if (ast->attributes.count(it.first) > 0) delete ast->attributes[it.first]; ast->attributes[it.first] = it.second; } delete al; } static void append_attr_clone(AstNode *ast, std::map *al) { for (auto &it : *al) { if (ast->attributes.count(it.first) > 0) delete ast->attributes[it.first]; ast->attributes[it.first] = it.second->clone(); } } static void free_attr(std::map *al) { for (auto &it : *al) delete it.second; delete al; } %} %name-prefix "frontend_verilog_yy" %union { std::string *string; struct AstNode *ast; std::map *al; bool boolean; } %token TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_POSEDGE TOK_NEGEDGE TOK_OR %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT %token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK %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 %token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_PROPERTY %type wire_type range non_opt_range range_or_signed_int expr basic_expr concat_list rvalue lvalue lvalue_concat_list %type opt_label tok_prim_wrapper hierarchical_id %type opt_signed %type attr // operator precedence from low to high %left OP_LOR %left OP_LAND %left '|' OP_NOR %left '^' OP_XNOR %left '&' OP_NAND %left OP_EQ OP_NE OP_EQX OP_NEX %left '<' OP_LE OP_GE '>' %left OP_SHL OP_SHR OP_SSHL OP_SSHR %left '+' '-' %left '*' '/' '%' %left OP_POW %right UNARY_OPS %expect 2 %debug %% input: module input | defattr input | /* empty */ { for (auto &it : default_attr_list) delete it.second; default_attr_list.clear(); }; attr: { for (auto &it : attr_list) delete it.second; attr_list.clear(); for (auto &it : default_attr_list) attr_list[it.first] = it.second->clone(); } attr_opt { std::map *al = new std::map; al->swap(attr_list); $$ = al; }; attr_opt: attr_opt ATTR_BEGIN opt_attr_list ATTR_END | /* empty */; defattr: DEFATTR_BEGIN { for (auto &it : default_attr_list) delete it.second; default_attr_list.clear(); for (auto &it : attr_list) delete it.second; attr_list.clear(); } opt_attr_list { default_attr_list = attr_list; attr_list.clear(); } DEFATTR_END; opt_attr_list: attr_list | /* empty */; attr_list: attr_assign | attr_list ',' attr_assign; attr_assign: hierarchical_id { if (attr_list.count(*$1) != 0) delete attr_list[*$1]; attr_list[*$1] = AstNode::mkconst_int(1, false); delete $1; } | hierarchical_id '=' expr { if (attr_list.count(*$1) != 0) delete attr_list[*$1]; attr_list[*$1] = $3; delete $1; }; hierarchical_id: TOK_ID { $$ = $1; } | hierarchical_id '.' TOK_ID { if ($3->substr(0, 1) == "\\") *$1 += "." + $3->substr(1); else *$1 += "." + *$3; delete $3; $$ = $1; }; module: attr TOK_MODULE TOK_ID { AstNode *mod = new AstNode(AST_MODULE); current_ast->children.push_back(mod); current_ast_mod = mod; ast_stack.push_back(mod); port_stubs.clear(); port_counter = 0; mod->str = *$3; append_attr(mod, $1); delete $3; } module_para_opt module_args_opt ';' module_body TOK_ENDMODULE { if (port_stubs.size() != 0) frontend_verilog_yyerror("Missing details for module port `%s'.", port_stubs.begin()->first.c_str()); ast_stack.pop_back(); log_assert(ast_stack.size() == 0); }; module_para_opt: '#' '(' module_para_list ')' | /* empty */; module_para_list: single_module_para | single_module_para ',' module_para_list | /* empty */; single_module_para: TOK_PARAMETER { astbuf1 = new AstNode(AST_PARAMETER); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); } param_signed param_integer param_range single_param_decl { delete astbuf1; }; module_args_opt: '(' ')' | /* empty */ | '(' module_args optional_comma ')'; module_args: module_arg | module_args ',' module_arg; optional_comma: ',' | /* empty */; module_arg_opt_assignment: '=' expr { if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { AstNode *wire = new AstNode(AST_IDENTIFIER); wire->str = ast_stack.back()->children.back()->str; if (ast_stack.back()->children.back()->is_reg) ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2)))); else ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2)); } else frontend_verilog_yyerror("Syntax error."); } | /* empty */; module_arg: TOK_ID { if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { AstNode *node = ast_stack.back()->children.back()->clone(); node->str = *$1; node->port_id = ++port_counter; ast_stack.back()->children.push_back(node); } else { if (port_stubs.count(*$1) != 0) frontend_verilog_yyerror("Duplicate module port `%s'.", $1->c_str()); port_stubs[*$1] = ++port_counter; } delete $1; } module_arg_opt_assignment | attr wire_type range TOK_ID { AstNode *node = $2; node->str = *$4; node->port_id = ++port_counter; if ($3 != NULL) node->children.push_back($3); if (!node->is_input && !node->is_output) frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str()); if (node->is_reg && node->is_input && !node->is_output) frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str()); ast_stack.back()->children.push_back(node); append_attr(node, $1); delete $4; } module_arg_opt_assignment; wire_type: { astbuf3 = new AstNode(AST_WIRE); } wire_type_token_list { $$ = astbuf3; }; wire_type_token_list: wire_type_token | wire_type_token_list wire_type_token; wire_type_token: TOK_INPUT { astbuf3->is_input = true; } | TOK_OUTPUT { astbuf3->is_output = true; } | TOK_INOUT { astbuf3->is_input = true; astbuf3->is_output = true; } | TOK_WIRE { } | TOK_REG { astbuf3->is_reg = true; } | TOK_INTEGER { astbuf3->is_reg = true; astbuf3->range_left = 31; astbuf3->range_right = 0; astbuf3->is_signed = true; } | TOK_GENVAR { astbuf3->type = AST_GENVAR; astbuf3->is_reg = true; astbuf3->range_left = 31; astbuf3->range_right = 0; } | TOK_SIGNED { astbuf3->is_signed = true; }; non_opt_range: '[' expr ':' expr ']' { $$ = new AstNode(AST_RANGE); $$->children.push_back($2); $$->children.push_back($4); } | '[' 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))); } | '[' 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)); } | '[' expr ']' { $$ = new AstNode(AST_RANGE); $$->children.push_back($2); }; range: non_opt_range { $$ = $1; } | /* empty */ { $$ = NULL; }; range_or_signed_int: range { $$ = $1; } | TOK_INTEGER { $$ = new AstNode(AST_RANGE); $$->children.push_back(AstNode::mkconst_int(31, true)); $$->children.push_back(AstNode::mkconst_int(0, true)); $$->is_signed = true; }; module_body: module_body module_body_stmt | /* the following line makes the generate..endgenrate keywords optional */ module_body gen_stmt | /* empty */; module_body_stmt: task_func_decl | param_decl | localparam_decl | defparam_decl | wire_decl | assign_stmt | cell_stmt | always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property; task_func_decl: TOK_TASK TOK_ID ';' { current_function_or_task = new AstNode(AST_TASK); current_function_or_task->str = *$2; ast_stack.back()->children.push_back(current_function_or_task); ast_stack.push_back(current_function_or_task); current_function_or_task_port_id = 1; delete $2; } task_func_body TOK_ENDTASK { current_function_or_task = NULL; ast_stack.pop_back(); } | TOK_FUNCTION opt_signed range_or_signed_int TOK_ID ';' { current_function_or_task = new AstNode(AST_FUNCTION); current_function_or_task->str = *$4; ast_stack.back()->children.push_back(current_function_or_task); ast_stack.push_back(current_function_or_task); AstNode *outreg = new AstNode(AST_WIRE); outreg->str = *$4; outreg->is_signed = $2; if ($3 != NULL) { outreg->children.push_back($3); outreg->is_signed = $2 || $3->is_signed; $3->is_signed = false; } current_function_or_task->children.push_back(outreg); current_function_or_task_port_id = 1; delete $4; } task_func_body TOK_ENDFUNCTION { current_function_or_task = NULL; ast_stack.pop_back(); }; opt_signed: TOK_SIGNED { $$ = true; } | /* empty */ { $$ = false; }; task_func_body: task_func_body behavioral_stmt | /* empty */; param_signed: TOK_SIGNED { astbuf1->is_signed = true; } | /* empty */; param_integer: TOK_INTEGER { if (astbuf1->children.size() != 1) frontend_verilog_yyerror("Syntax error."); astbuf1->children.push_back(new AstNode(AST_RANGE)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->is_signed = true; } | /* empty */; param_real: TOK_REAL { if (astbuf1->children.size() != 1) frontend_verilog_yyerror("Syntax error."); astbuf1->children.push_back(new AstNode(AST_REALVALUE)); } | /* empty */; param_range: range { if ($1 != NULL) { if (astbuf1->children.size() != 1) frontend_verilog_yyerror("Syntax error."); astbuf1->children.push_back($1); } }; param_decl: TOK_PARAMETER { astbuf1 = new AstNode(AST_PARAMETER); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); } param_signed param_integer param_real param_range param_decl_list ';' { delete astbuf1; }; localparam_decl: TOK_LOCALPARAM { astbuf1 = new AstNode(AST_LOCALPARAM); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); } param_signed param_integer param_real param_range param_decl_list ';' { delete astbuf1; }; param_decl_list: single_param_decl | param_decl_list ',' single_param_decl; single_param_decl: TOK_ID '=' expr { AstNode *node = astbuf1->clone(); node->str = *$1; delete node->children[0]; node->children[0] = $3; ast_stack.back()->children.push_back(node); delete $1; }; defparam_decl: TOK_DEFPARAM defparam_decl_list ';'; defparam_decl_list: single_defparam_decl | defparam_decl_list ',' single_defparam_decl; single_defparam_decl: range hierarchical_id '=' expr { AstNode *node = new AstNode(AST_DEFPARAM); node->str = *$2; node->children.push_back($4); if ($1 != NULL) node->children.push_back($1); ast_stack.back()->children.push_back(node); delete $2; }; wire_decl: attr wire_type range { albuf = $1; astbuf1 = $2; astbuf2 = $3; if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { if (astbuf2) { frontend_verilog_yyerror("Syntax error."); } else { astbuf2 = new AstNode(AST_RANGE); astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true)); astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true)); } } if (astbuf2 && astbuf2->children.size() != 2) frontend_verilog_yyerror("Syntax error."); } wire_name_list ';' { delete astbuf1; if (astbuf2 != NULL) delete astbuf2; free_attr(albuf); } | attr TOK_SUPPLY0 TOK_ID ';' { ast_stack.back()->children.push_back(new AstNode(AST_WIRE)); ast_stack.back()->children.back()->str = *$3; append_attr(ast_stack.back()->children.back(), $1); ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))); ast_stack.back()->children.back()->children[0]->str = *$3; delete $3; } | attr TOK_SUPPLY1 TOK_ID ';' { ast_stack.back()->children.push_back(new AstNode(AST_WIRE)); ast_stack.back()->children.back()->str = *$3; append_attr(ast_stack.back()->children.back(), $1); ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1))); ast_stack.back()->children.back()->children[0]->str = *$3; delete $3; }; wire_name_list: wire_name_and_opt_assign | wire_name_list ',' wire_name_and_opt_assign; wire_name_and_opt_assign: wire_name | wire_name '=' expr { AstNode *wire = new AstNode(AST_IDENTIFIER); wire->str = ast_stack.back()->children.back()->str; if (astbuf1->is_reg) 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)); }; wire_name: TOK_ID range { AstNode *node = astbuf1->clone(); node->str = *$1; append_attr_clone(node, albuf); if (astbuf2 != NULL) node->children.push_back(astbuf2->clone()); if ($2 != NULL) { if (node->is_input || node->is_output) frontend_verilog_yyerror("Syntax error."); if (!astbuf2) { AstNode *rng = new AstNode(AST_RANGE); rng->children.push_back(AstNode::mkconst_int(0, true)); rng->children.push_back(AstNode::mkconst_int(0, true)); node->children.push_back(rng); } node->type = AST_MEMORY; node->children.push_back($2); } if (current_function_or_task == NULL) { if (port_stubs.count(*$1) != 0) { if (!node->is_input && !node->is_output) frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str()); if (node->is_reg && node->is_input && !node->is_output) frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str()); node->port_id = port_stubs[*$1]; port_stubs.erase(*$1); } else { if (node->is_input || node->is_output) frontend_verilog_yyerror("Module port `%s' is not declared in module header.", $1->c_str()); } ast_stack.back()->children.push_back(node); } else { if (node->is_input || node->is_output) node->port_id = current_function_or_task_port_id++; current_function_or_task->children.push_back(node); } delete $1; }; assign_stmt: TOK_ASSIGN assign_expr_list ';'; assign_expr_list: assign_expr | assign_expr_list ',' assign_expr; assign_expr: expr '=' expr { ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3)); }; cell_stmt: attr TOK_ID { astbuf1 = new AstNode(AST_CELL); append_attr(astbuf1, $1); astbuf1->children.push_back(new AstNode(AST_CELLTYPE)); astbuf1->children[0]->str = *$2; delete $2; } cell_parameter_list_opt cell_list ';' { delete astbuf1; } | attr tok_prim_wrapper { astbuf1 = new AstNode(AST_PRIMITIVE); astbuf1->str = *$2; append_attr(astbuf1, $1); delete $2; } prim_list ';' { delete astbuf1; }; tok_prim_wrapper: TOK_PRIMITIVE { $$ = $1; } | TOK_OR { $$ = new std::string("or"); }; cell_list: single_cell | cell_list ',' single_cell; single_cell: TOK_ID { astbuf2 = astbuf1->clone(); if (astbuf2->type != AST_PRIMITIVE) astbuf2->str = *$1; delete $1; ast_stack.back()->children.push_back(astbuf2); } '(' cell_port_list ')' | 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 ')'; prim_list: single_prim | prim_list ',' single_prim; single_prim: single_cell | /* no name */ { astbuf2 = astbuf1->clone(); ast_stack.back()->children.push_back(astbuf2); } '(' cell_port_list ')'; cell_parameter_list_opt: '#' '(' cell_parameter_list ')' | /* empty */; cell_parameter_list: /* empty */ | cell_parameter | cell_parameter ',' cell_parameter_list; cell_parameter: expr { AstNode *node = new AstNode(AST_PARASET); astbuf1->children.push_back(node); node->children.push_back($1); } | '.' TOK_ID '(' expr ')' { AstNode *node = new AstNode(AST_PARASET); node->str = *$2; astbuf1->children.push_back(node); node->children.push_back($4); delete $2; }; cell_port_list: /* empty */ | cell_port | cell_port ',' cell_port_list | /* empty */ ',' { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); } cell_port_list; cell_port: expr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); node->children.push_back($1); } | '.' TOK_ID '(' expr ')' { AstNode *node = new AstNode(AST_ARGUMENT); node->str = *$2; astbuf2->children.push_back(node); node->children.push_back($4); delete $2; } | '.' TOK_ID '(' ')' { AstNode *node = new AstNode(AST_ARGUMENT); node->str = *$2; astbuf2->children.push_back(node); delete $2; }; always_stmt: attr TOK_ALWAYS { AstNode *node = new AstNode(AST_ALWAYS); append_attr(node, $1); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } always_cond { AstNode *block = new AstNode(AST_BLOCK); ast_stack.bac FILES_TO_SEND = [ '/var/log/' + x for x in [ 'syslog', 'messages', 'debug', 'xen/xend.log', 'xen/xend-debug.log', 'xen/xenstored-trace.log', 'xen/xen-hotplug.log' ] ] #FILES_TO_SEND = [ ] def main(argv = None): if argv is None: argv = sys.argv print ''' This application will collate the Xen dmesg output, details of the hardware configuration of your machine, information about the build of Xen that you are using, plus, if you allow it, various logs. The information collated can either be posted to a Xen Bugzilla bug (this bug must already exist in the system, and you must be a registered user there), or it can be saved as a .tar.bz2 for sending or archiving. The collated logs may contain private information, and if you are at all worried about that, you should exit now, or you should explicitly exclude those logs from the archive. ''' bugball = [] xc = xen.lowlevel.xc.xc() def do(n, f): try: s = f() except Exception, exn: s = str(exn) bugball.append(string_iterator(n, s)) do('xen-dmesg', lambda: xc.readconsolering()) do('physinfo', lambda: prettyDict(xc.physinfo())) do('xeninfo', lambda: prettyDict(xc.xeninfo())) for filename in FILES_TO_SEND: if not os.path.exists(filename): continue if yes('Include %s? [Y/n] ' % filename): bugball.append(file(filename)) maybeAttach(bugball) if (yes(''' Do you wish to save these details as a tarball (.tar.bz2)? [Y/n] ''')): tar(bugball) return 0 def maybeAttach(bugball): if not yes(''' Do you wish to attach these details to a Bugzilla bug? [Y/n] '''): return bug = int(raw_input('Bug number? ')) bug_title = getBugTitle(bug) if bug_title == 'Search by bug number' or bug_title == 'Invalid Bug ID': print >>sys.stderr, 'Bug %d does not exist!' % bug maybeAttach(bugball) elif yes('Are you sure that you want to attach to %s? [Y/n] ' % bug_title): attach(bug, bugball) (node); ast_stack.push_back(node); ast_stack.back()->children.push_back($3); } gen_stmt_block opt_gen_else { ast_stack.pop_back(); } | case_type '(' expr ')' { AstNode *node = new AstNode(AST_GENCASE, $3); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } gen_case_body TOK_ENDCASE { case_type_stack.pop_back(); ast_stack.pop_back(); } | TOK_BEGIN opt_label { AstNode *node = new AstNode(AST_GENBLOCK); node->str = $2 ? *$2 : std::string(); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } module_gen_body TOK_END opt_label { if ($2 != NULL) delete $2; if ($6 != NULL) delete $6; ast_stack.pop_back(); }; gen_stmt_block: { AstNode *node = new AstNode(AST_GENBLOCK); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } gen_stmt_or_module_body_stmt { ast_stack.pop_back(); }; gen_stmt_or_null: gen_stmt_block | ';'; opt_gen_else: TOK_ELSE gen_stmt_or_null | /* empty */; expr: basic_expr { $$ = $1; } | basic_expr '?' attr expr ':' expr { $$ = new AstNode(AST_TERNARY); $$->children.push_back($1); $$->children.push_back($4); $$->children.push_back($6); append_attr($$, $3); }; basic_expr: rvalue { $$ = $1; } | '(' expr ')' TOK_CONST { if ($4->substr(0, 1) != "'") frontend_verilog_yyerror("Syntax error."); AstNode *bits = $2; AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back()); if (val == NULL) log_error("Value conversion failed: `%s'\n", $4->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); delete $4; } | hierarchical_id TOK_CONST { if ($2->substr(0, 1) != "'") frontend_verilog_yyerror("Syntax error."); AstNode *bits = new AstNode(AST_IDENTIFIER); bits->str = *$1; AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back()); if (val == NULL) log_error("Value conversion failed: `%s'\n", $2->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); delete $1; delete $2; } | TOK_CONST TOK_CONST { $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back()); if ($$ == NULL || (*$2)[0] != '\'') log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str()); delete $1; delete $2; } | TOK_CONST { $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back()); if ($$ == NULL) log_error("Value conversion failed: `%s'\n", $1->c_str()); delete $1; } | TOK_REALVAL { $$ = new AstNode(AST_REALVALUE); char *p = strdup($1->c_str()), *q; for (int i = 0, j = 0; !p[j]; j++) if (p[j] != '_') p[i++] = p[j], p[i] = 0; $$->realvalue = strtod(p, &q); log_assert(*q == 0); delete $1; free(p); } | TOK_STRING { $$ = AstNode::mkconst_str(*$1); delete $1; } | hierarchical_id attr { AstNode *node = new AstNode(AST_FCALL); node->str = *$1; delete $1; ast_stack.push_back(node); append_attr(node, $2); } '(' arg_list optional_comma ')' { $$ = ast_stack.back(); ast_stack.pop_back(); } | TOK_TO_SIGNED attr '(' expr ')' { $$ = new AstNode(AST_TO_SIGNED, $4); append_attr($$, $2); } | TOK_TO_UNSIGNED attr '(' expr ')' { $$ = new AstNode(AST_TO_UNSIGNED, $4); append_attr($$, $2); } | '(' expr ')' { $$ = $2; } | '{' concat_list '}' { $$ = $2; } | '{' expr '{' expr '}' '}' { $$ = new AstNode(AST_REPLICATE, $2, $4); } | '~' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_BIT_NOT, $3); append_attr($$, $2); } | basic_expr '&' attr basic_expr { $$ = new AstNode(AST_BIT_AND, $1, $4); append_attr($$, $3); } | basic_expr '|' attr basic_expr { $$ = new AstNode(AST_BIT_OR, $1, $4); append_attr($$, $3); } | basic_expr '^' attr basic_expr { $$ = new AstNode(AST_BIT_XOR, $1, $4); append_attr($$, $3); } | basic_expr OP_XNOR attr basic_expr { $$ = new AstNode(AST_BIT_XNOR, $1, $4); append_attr($$, $3); } | '&' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_AND, $3); append_attr($$, $2); } | OP_NAND attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_AND, $3); append_attr($$, $2); $$ = new AstNode(AST_LOGIC_NOT, $$); } | '|' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_OR, $3); append_attr($$, $2); } | OP_NOR attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_OR, $3); append_attr($$, $2); $$ = new AstNode(AST_LOGIC_NOT, $$); } | '^' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_XOR, $3); append_attr($$, $2); } | OP_XNOR attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_XNOR, $3); append_attr($$, $2); } | basic_expr OP_SHL attr basic_expr { $$ = new AstNode(AST_SHIFT_LEFT, $1, $4); append_attr($$, $3); } | basic_expr OP_SHR attr basic_expr { $$ = new AstNode(AST_SHIFT_RIGHT, $1, $4); append_attr($$, $3); } | basic_expr OP_SSHL attr basic_expr { $$ = new AstNode(AST_SHIFT_SLEFT, $1, $4); append_attr($$, $3); } | basic_expr OP_SSHR attr basic_expr { $$ = new AstNode(AST_SHIFT_SRIGHT, $1, $4); append_attr($$, $3); } | basic_expr '<' attr basic_expr { $$ = new AstNode(AST_LT, $1, $4); append_attr($$, $3); } | basic_expr OP_LE attr basic_expr { $$ = new AstNode(AST_LE, $1, $4); append_attr($$, $3); } | basic_expr OP_EQ attr basic_expr { $$ = new AstNode(AST_EQ, $1, $4); append_attr($$, $3); } | basic_expr OP_NE attr basic_expr { $$ = new AstNode(AST_NE, $1, $4); append_attr($$, $3); } | basic_expr OP_EQX attr basic_expr { $$ = new AstNode(AST_EQX, $1, $4); append_attr($$, $3); } | basic_expr OP_NEX attr basic_expr { $$ = new AstNode(AST_NEX, $1, $4); append_attr($$, $3); } | basic_expr OP_GE attr basic_expr { $$ = new AstNode(AST_GE, $1, $4); append_attr($$, $3); } | basic_expr '>' attr basic_expr { $$ = new AstNode(AST_GT, $1, $4); append_attr($$, $3); } | basic_expr '+' attr basic_expr { $$ = new AstNode(AST_ADD, $1, $4); append_attr($$, $3); } | basic_expr '-' attr basic_expr { $$ = new AstNode(AST_SUB, $1, $4); append_attr($$, $3); } | basic_expr '*' attr basic_expr { $$ = new AstNode(AST_MUL, $1, $4); append_attr($$, $3); } | basic_expr '/' attr basic_expr { $$ = new AstNode(AST_DIV, $1, $4); append_attr($$, $3); } | basic_expr '%' attr basic_expr { $$ = new AstNode(AST_MOD, $1, $4); append_attr($$, $3); } | basic_expr OP_POW attr basic_expr { $$ = new AstNode(AST_POW, $1, $4); append_attr($$, $3); } | '+' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_POS, $3); append_attr($$, $2); } | '-' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_NEG, $3); append_attr($$, $2); } | basic_expr OP_LAND attr basic_expr { $$ = new AstNode(AST_LOGIC_AND, $1, $4); append_attr($$, $3); } | basic_expr OP_LOR attr basic_expr { $$ = new AstNode(AST_LOGIC_OR, $1, $4); append_attr($$, $3); } | '!' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_LOGIC_NOT, $3); append_attr($$, $2); }; concat_list: expr { $$ = new AstNode(AST_CONCAT, $1); } | expr ',' concat_list { $$ = $3; $$->children.push_back($1); };