iverilog/parse.y

1045 lines
23 KiB
Plaintext
Raw Normal View History

1998-11-04 00:28:49 +01:00
%{
/*
1999-04-29 04:16:26 +02:00
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
1998-11-04 00:28:49 +01:00
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: parse.y,v 1.23 1999/05/07 04:26:49 steve Exp $"
1998-11-04 00:28:49 +01:00
#endif
# include "parse_misc.h"
# include "pform.h"
extern void lex_start_table();
extern void lex_end_table();
1998-11-04 00:28:49 +01:00
%}
%union {
char letter;
1998-11-04 00:28:49 +01:00
string*text;
list<string>*strings;
PCase::Item*citem;
list<PCase::Item*>*citems;
1998-11-04 00:28:49 +01:00
lgate*gate;
1999-05-06 06:37:17 +02:00
svector<lgate>*gates;
1998-11-04 00:28:49 +01:00
PExpr*expr;
list<PExpr*>*exprs;
1999-04-29 04:16:26 +02:00
svector<PEEvent*>*event_expr;
1998-11-04 00:28:49 +01:00
NetNet::Type nettype;
PGBuiltin::Type gatetype;
NetNet::PortType porttype;
PWire*wire;
list<PWire*>*wires;
PEventStatement*event_statement;
Statement*statement;
list<Statement*>*statement_list;
verinum* number;
};
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING
%token <number> NUMBER
%token K_LE K_GE K_EQ K_NE K_CEQ K_CNE
%token K_LOR K_LAND
1998-11-04 00:28:49 +01:00
%token K_always K_and K_assign K_begin K_buf K_bufif0 K_bufif1 K_case
%token K_casex K_casez K_cmos K_deassign K_default K_defparam K_disable
%token K_edge K_else K_end K_endcase K_endfunction K_endmodule
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_for
%token K_force K_forever K_fork K_function K_highz0 K_highz1 K_if
%token K_initial K_inout K_input K_integer K_join K_large K_macromodule
%token K_medium K_module K_nand K_negedge K_nmos K_nor K_not K_notif0
1999-02-21 18:01:57 +01:00
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_primitive
%token K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_reg K_release K_repeat
1998-11-04 00:28:49 +01:00
%token K_rnmos K_rpmos K_rtran K_rtranif0 K_rtranif1 K_scalered
%token K_small K_specify
%token K_specparam K_strong0 K_strong1 K_supply0 K_supply1 K_table K_task
%token K_time K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand
%token K_trior K_vectored K_wait K_wand K_weak0 K_weak1 K_while K_wire
%token K_wor K_xnor K_xor
%token KK_attribute
%type <letter> udp_input_sym udp_output_sym
%type <text> udp_input_list udp_sequ_entry udp_comb_entry
%type <strings> udp_entry_list udp_comb_entry_list udp_sequ_entry_list
%type <strings> udp_body udp_port_list
%type <wires> udp_port_decl udp_port_decls
%type <statement> udp_initial udp_init_opt
%type <text> identifier lpvalue register_variable
%type <strings> register_variable_list
1998-11-04 00:28:49 +01:00
%type <strings> list_of_variables
%type <wire> port
%type <wires> list_of_ports list_of_ports_opt
%type <citem> case_item
%type <citems> case_items
1998-11-04 00:28:49 +01:00
%type <gate> gate_instance
%type <gates> gate_instance_list
%type <expr> bitsel delay delay_opt expression expr_primary const_expression
%type <expr> lavalue
1998-11-04 00:28:49 +01:00
%type <exprs> expression_list
%type <exprs> range range_opt
%type <nettype> net_type
%type <gatetype> gatetype
%type <porttype> port_type
1999-04-29 04:16:26 +02:00
%type <event_expr> event_expression
%type <event_statement> event_control
1998-11-04 00:28:49 +01:00
%type <statement> statement statement_opt
%type <statement_list> statement_list
%left K_LOR
%left K_LAND
%left '|'
%left '^'
%left '&'
%left K_EQ K_NE K_CEQ K_CNE
%left K_GE K_LE '<' '>'
%left '+' '-'
%left UNARY_PREC
1998-11-04 00:28:49 +01:00
%%
source_file
: description
| source_file description
;
bitsel
: '[' const_expression ']'
{ $$ = $2; }
;
case_item
: expression ':' statement_opt
{ PCase::Item*tmp = new PCase::Item;
tmp->expr = $1;
tmp->stat = $3;
$$ = tmp;
}
| K_default ':' statement_opt
{ PCase::Item*tmp = new PCase::Item;
tmp->expr = 0;
tmp->stat = $3;
$$ = tmp;
}
| K_default statement_opt
{ PCase::Item*tmp = new PCase::Item;
tmp->expr = 0;
tmp->stat = $2;
$$ = tmp;
}
;
case_items
: case_items case_item
{ list<PCase::Item*>*tmp = $1;
tmp->push_back($2);
$$ = tmp;
}
| case_item
{ list<PCase::Item*>*tmp = new list<PCase::Item*>;
tmp->push_back($1);
$$ = tmp;
}
;
1999-05-06 06:09:28 +02:00
/* const_expressions are restricted expressions that have guaranteed
known values at compile time. I treat them differently at parse
time so that I can tack correctness checking onto the parse
process. */
1998-11-04 00:28:49 +01:00
const_expression
: NUMBER
{ verinum*tmp = $1;
if (tmp == 0) {
yyerror(@1, "XXXX internal error: const_expression.");
$$ = 0;
} else {
$$ = new PENumber(tmp);
}
1998-11-04 00:28:49 +01:00
}
| STRING
{ $$ = new PEString(*$1);
delete $1;
}
1999-05-06 06:09:28 +02:00
| IDENTIFIER
{ if (!pform_is_parameter(*$1)) {
yyerror(@1, "Identifier in constant expression"
" must be a parameter name.");
delete $1;
$$ = 0;
} else {
PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
delete $1;
}
}
| const_expression '-' const_expression
{ $$ = new PEBinary('-', $1, $3);
}
1998-11-04 00:28:49 +01:00
;
delay
: '#' NUMBER
{ verinum*tmp = $2;
if (tmp == 0) {
yyerror(@2, "XXXX internal error: delay.");
$$ = 0;
} else {
$$ = new PENumber(tmp);
}
1998-11-04 00:28:49 +01:00
}
| '#' IDENTIFIER
{ PEIdent*tmp = new PEIdent(*$2);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
1998-11-04 00:28:49 +01:00
delete $2;
}
;
delay_opt
: delay { $$ = $1; }
| { $$ = 0; }
;
description
: module
| udp_primitive
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')'
{ pform_set_type_attrib(*$3, *$5, *$7);
delete $3;
delete $5;
delete $7;
}
1998-11-04 00:28:49 +01:00
;
event_control
: '@' IDENTIFIER
{ yyerror(@1, "Sorry, event control not supported.");
$$ = 0;
}
| '@' '(' event_expression ')'
1999-04-29 04:16:26 +02:00
{ PEventStatement*tmp = new PEventStatement(*$3);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $3;
$$ = tmp;
}
| '@' '(' error ')'
{ yyerror(@1, "Malformed event control expression.");
$$ = 0;
1998-11-04 00:28:49 +01:00
}
;
event_expression
: K_posedge expression
{ PEEvent*tmp = new PEEvent(NetNEvent::POSEDGE, $2);
1999-04-29 04:16:26 +02:00
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
svector<PEEvent*>*tl = new svector<PEEvent*>(1);
(*tl)[0] = tmp;
$$ = tl;
1998-11-04 00:28:49 +01:00
}
| K_negedge expression
{ PEEvent*tmp = new PEEvent(NetNEvent::NEGEDGE, $2);
1999-04-29 04:16:26 +02:00
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
svector<PEEvent*>*tl = new svector<PEEvent*>(1);
(*tl)[0] = tmp;
$$ = tl;
}
| expression
{ PEEvent*tmp = new PEEvent(NetNEvent::ANYEDGE, $1);
1999-04-29 04:16:26 +02:00
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
svector<PEEvent*>*tl = new svector<PEEvent*>(1);
(*tl)[0] = tmp;
$$ = tl;
}
| event_expression K_or event_expression
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
1998-11-04 00:28:49 +01:00
}
;
expression
: expr_primary
{ $$ = $1; }
| '(' expression ')'
{ $$ = $2; }
1999-05-06 06:09:28 +02:00
| '{' expression_list '}'
{ yyerror(@1, "Sorry, concatenation operator not supported.");
$$ = 0;
}
1998-11-04 00:28:49 +01:00
| '~' expression %prec UNARY_PREC
{ $$ = new PEUnary('~', $2);
}
| '&' expression %prec UNARY_PREC
{ $$ = new PEUnary('&', $2);
}
| '!' expression %prec UNARY_PREC
{ $$ = new PEUnary('!', $2);
}
1998-11-04 00:28:49 +01:00
| expression '^' expression
{ $$ = new PEBinary('^', $1, $3);
}
| expression '+' expression
{ $$ = new PEBinary('+', $1, $3);
}
| expression '-' expression
{ $$ = new PEBinary('-', $1, $3);
}
1998-11-04 00:28:49 +01:00
| expression '&' expression
{ $$ = new PEBinary('&', $1, $3);
}
| expression '|' expression
{ $$ = new PEBinary('|', $1, $3);
}
| expression K_EQ expression
{ $$ = new PEBinary('e', $1, $3);
}
| expression K_CEQ expression
{ $$ = new PEBinary('E', $1, $3);
}
| expression K_NE expression
{ $$ = new PEBinary('n', $1, $3);
}
| expression K_CNE expression
{ $$ = new PEBinary('N', $1, $3);
}
| expression K_LOR expression
{ $$ = new PEBinary('o', $1, $3);
}
| expression K_LAND expression
{ $$ = new PEBinary('a', $1, $3);
}
1998-11-04 00:28:49 +01:00
;
expression_list
: expression_list ',' expression
{ list<PExpr*>*tmp = $1;
tmp->push_back($3);
$$ = tmp;
}
| expression
{ list<PExpr*>*tmp = new list<PExpr*>;
tmp->push_back($1);
$$ = tmp;
}
| expression_list ','
{ list<PExpr*>*tmp = $1;
tmp->push_back(0);
$$ = tmp;
}
;
expr_primary
: NUMBER
{ if ($1 == 0) {
yyerror(@1, "XXXX No number value in primary?");
$$ = 0;
} else {
$$ = new PENumber($1);
}
1998-11-04 00:28:49 +01:00
}
| STRING
{ $$ = new PEString(*$1);
delete $1;
}
| identifier
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
1998-11-04 00:28:49 +01:00
delete $1;
}
| SYSTEM_IDENTIFIER
{ $$ = new PEIdent(*$1);
delete $1;
}
| identifier '[' expression ']'
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
1998-11-04 00:28:49 +01:00
tmp->msb_ = $3;
delete $1;
$$ = tmp;
}
| identifier '[' expression ':' expression ']'
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
1998-11-04 00:28:49 +01:00
tmp->msb_ = $3;
tmp->lsb_ = $5;
delete $1;
$$ = tmp;
}
;
gate_instance
: IDENTIFIER '(' expression_list ')'
{ lgate*tmp = new lgate;
tmp->name = *$1;
tmp->parms = $3;
tmp->file = @1.text;
tmp->lineno = @1.first_line;
1998-11-04 00:28:49 +01:00
delete $1;
$$ = tmp;
}
1999-02-15 03:06:15 +01:00
| IDENTIFIER range '(' expression_list ')'
{ lgate*tmp = new lgate;
list<PExpr*>*rng = $2;
tmp->name = *$1;
tmp->parms = $4;
tmp->range[0] = rng->front();
rng->pop_front();
tmp->range[1] = rng->front();
rng->pop_front();
tmp->file = @1.text;
tmp->lineno = @1.first_line;
delete $1;
delete rng;
$$ = tmp;
}
1998-11-04 00:28:49 +01:00
| '(' expression_list ')'
{ lgate*tmp = new lgate;
tmp->name = "";
tmp->parms = $2;
tmp->file = @1.text;
tmp->lineno = @1.first_line;
1998-11-04 00:28:49 +01:00
$$ = tmp;
}
;
gate_instance_list
: gate_instance_list ',' gate_instance
1999-05-06 06:37:17 +02:00
{ svector<lgate>*tmp1 = $1;
lgate*tmp2 = $3;
svector<lgate>*out = new svector<lgate> (*tmp1, *tmp2);
delete tmp1;
delete tmp2;
$$ = out;
1998-11-04 00:28:49 +01:00
}
| gate_instance
1999-05-06 06:37:17 +02:00
{ svector<lgate>*tmp = new svector<lgate>(1);
(*tmp)[0] = *$1;
1998-11-04 00:28:49 +01:00
delete $1;
$$ = tmp;
}
;
gatetype
: K_and { $$ = PGBuiltin::AND; }
| K_nand { $$ = PGBuiltin::NAND; }
| K_or { $$ = PGBuiltin::OR; }
| K_nor { $$ = PGBuiltin::NOR; }
| K_xor { $$ = PGBuiltin::XOR; }
| K_xnor { $$ = PGBuiltin::XNOR; }
| K_buf { $$ = PGBuiltin::BUF; }
| K_bufif0 { $$ = PGBuiltin::BUFIF0; }
| K_bufif1 { $$ = PGBuiltin::BUFIF1; }
| K_not { $$ = PGBuiltin::NOT; }
| K_notif0 { $$ = PGBuiltin::NOTIF0; }
| K_notif1 { $$ = PGBuiltin::NOTIF1; }
| K_pulldown { $$ = PGBuiltin::PULLDOWN; }
| K_pullup { $$ = PGBuiltin::PULLUP; }
| K_nmos { $$ = PGBuiltin::NMOS; }
| K_rnmos { $$ = PGBuiltin::RNMOS; }
| K_pmos { $$ = PGBuiltin::PMOS; }
| K_rpmos { $$ = PGBuiltin::RPMOS; }
| K_cmos { $$ = PGBuiltin::CMOS; }
| K_rcmos { $$ = PGBuiltin::RCMOS; }
| K_tran { $$ = PGBuiltin::TRAN; }
| K_rtran { $$ = PGBuiltin::RTRAN; }
| K_tranif0 { $$ = PGBuiltin::TRANIF0; }
| K_tranif1 { $$ = PGBuiltin::TRANIF1; }
| K_rtranif0 { $$ = PGBuiltin::RTRANIF0; }
| K_rtranif1 { $$ = PGBuiltin::RTRANIF1; }
;
identifier
: identifier '.' IDENTIFIER
{ yyerror(@1, "Sorry, qualified identifiers not supported.");
$$ = $3;
delete $1;
}
| IDENTIFIER
{ $$ = $1; }
;
list_of_ports
: port
{ list<PWire*>*tmp = new list<PWire*>;
tmp->push_back($1);
$$ = tmp;
}
| list_of_ports ',' port
{ list<PWire*>*tmp = $1;
tmp->push_back($3);
$$ = tmp;
}
;
list_of_ports_opt
: '(' list_of_ports ')' { $$ = $2; }
| '(' ')' { $$ = 0; }
| { $$ = 0; }
;
list_of_variables
: IDENTIFIER
{ list<string>*tmp = new list<string>;
tmp->push_back(*$1);
delete $1;
$$ = tmp;
}
| list_of_variables ',' IDENTIFIER
{ list<string>*tmp = $1;
tmp->push_back(*$3);
delete $3;
$$ = tmp;
}
;
/* An lavalue is the expression that can go on the left side of a
continuous assign statement. This checks (where it can) that the
expression meets the constraints of continuous assignments. */
lavalue
: IDENTIFIER
{ PEIdent*tmp = new PEIdent(*$1);
delete $1;
$$ = tmp;
}
| IDENTIFIER bitsel
{ PEIdent*tmp = new PEIdent(*$1);
tmp->msb_ = $2;
delete $1;
$$ = tmp;
}
| IDENTIFIER range
{ PEIdent*tmp = new PEIdent(*$1);
yyerror(@3, "Sorry, lvalue bit range not supported.");
delete $1;
delete $2;
$$ = tmp;
}
| '{' expression_list '}'
{ yyerror(@1, "Sorry, concatenation expressions"
" not supported in lvalue.");
$$ = 0;
delete $2;
}
;
/* An lpvalue is the expression that can go on the left side of a
procedural assignment. This rule handles only procedural assignments. */
lpvalue
1998-11-04 00:28:49 +01:00
: identifier { $$ = $1; }
1999-05-06 06:09:28 +02:00
| identifier '[' expression ']'
{ yyerror(@2, "Sorry, bit/memory selects "
"not supported in lvalue.");
$$ = $1;
delete $3;
}
| '{' expression_list '}'
{ yyerror(@1, "Sorry, concatenation expressions"
" not supported in lvalue.");
$$ = 0;
delete $2;
}
1998-11-04 00:28:49 +01:00
;
module
: K_module IDENTIFIER list_of_ports_opt ';'
{ pform_startmodule(*$2, $3);
}
module_item_list
K_endmodule
{ pform_endmodule(*$2);
delete $2;
}
;
module_item
: net_type range_opt list_of_variables ';'
{ pform_makewire($3, $1);
if ($2) {
pform_set_net_range($3, $2);
delete $2;
}
delete $3;
}
| port_type range_opt list_of_variables ';'
{ pform_set_port_type($3, $1);
if ($2) {
pform_set_net_range($3, $2);
delete $2;
}
delete $3;
}
| K_reg range register_variable_list ';'
{ pform_set_net_range($3, $2);
delete $2;
1998-11-04 00:28:49 +01:00
delete $3;
}
| K_reg register_variable_list ';'
{ delete $2; }
| K_integer list_of_variables ';'
{ yyerror(@1, "Sorry, integer types not supported."); }
1999-02-21 18:01:57 +01:00
| K_parameter parameter_assign_list ';'
1998-11-04 00:28:49 +01:00
| gatetype delay_opt gate_instance_list ';'
{ pform_makegates($1, $2, $3);
}
| IDENTIFIER gate_instance_list ';'
{ pform_make_modgates(*$1, $2);
delete $1;
}
| K_assign lavalue '=' expression ';'
{ pform_make_pgassign($2, $4); }
| K_assign error '=' expression ';'
1998-11-04 00:28:49 +01:00
| K_always statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
1998-11-04 00:28:49 +01:00
}
| K_initial statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_INITIAL, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
1998-11-04 00:28:49 +01:00
}
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' ';'
{ pform_set_attrib(*$3, *$5, *$7);
delete $3;
delete $5;
delete $7;
}
| KK_attribute '(' error ')' ';'
{ yyerror(@1, "Misformed $attribute parameter list."); }
1998-11-04 00:28:49 +01:00
;
module_item_list
: module_item_list module_item
| module_item
;
net_type
: K_wire { $$ = NetNet::WIRE; }
| K_tri { $$ = NetNet::TRI; }
| K_tri1 { $$ = NetNet::TRI1; }
| K_supply0 { $$ = NetNet::SUPPLY0; }
| K_wand { $$ = NetNet::WAND; }
| K_triand { $$ = NetNet::TRIAND; }
| K_tri0 { $$ = NetNet::TRI0; }
| K_supply1 { $$ = NetNet::SUPPLY1; }
| K_wor { $$ = NetNet::WOR; }
| K_trior { $$ = NetNet::TRIOR; }
;
1999-02-21 18:01:57 +01:00
parameter_assign
: IDENTIFIER '=' const_expression
{ pform_set_parameter(*$1, $3);
delete $1;
}
;
parameter_assign_list
: parameter_assign
| parameter_assign_list ',' parameter_assign
;
1998-11-04 00:28:49 +01:00
port
: IDENTIFIER
{ $$ = new PWire(*$1, NetNet::IMPLICIT);
$$->port_type = NetNet::PIMPLICIT;
delete $1;
}
| IDENTIFIER '[' const_expression ':' const_expression ']'
{ $$ = new PWire(*$1, NetNet::IMPLICIT);
$$->port_type = NetNet::PIMPLICIT;
$$->msb = $3;
$$->lsb = $5;
delete $1;
}
| IDENTIFIER '[' error ']'
{ yyerror(@1, "invalid port bit select");
$$ = new PWire(*$1, NetNet::IMPLICIT);
$$->port_type = NetNet::PIMPLICIT;
delete $1;
}
;
port_type
: K_input { $$ = NetNet::PINPUT; }
| K_output { $$ = NetNet::POUTPUT; }
| K_inout { $$ = NetNet::PINOUT; }
;
range
1998-11-11 01:01:51 +01:00
: '[' const_expression ':' const_expression ']'
1998-11-04 00:28:49 +01:00
{ list<PExpr*>*tmp = new list<PExpr*>;
1998-11-11 01:01:51 +01:00
tmp->push_back($2);
tmp->push_back($4);
1998-11-04 00:28:49 +01:00
$$ = tmp;
}
;
range_opt
: range
| { $$ = 0; }
;
/* The register_variable rule is matched only when I am parsing
variables in a "reg" definition. I therefore know that I am
creating registers and I do not need to let the containing rule
handle it. The register variable list simply packs them together
so that bit ranges can be assigned. */
1998-11-04 00:28:49 +01:00
register_variable
: IDENTIFIER
{ pform_makewire(*$1, NetNet::REG);
1998-11-04 00:28:49 +01:00
$$ = $1;
}
| IDENTIFIER '[' const_expression ':' const_expression ']'
{ pform_makewire(*$1, NetNet::REG);
pform_set_reg_idx(*$1, $3, $5);
$$ = $1;
}
;
register_variable_list
: register_variable
{ list<string>*tmp = new list<string>;
tmp->push_back(*$1);
delete $1;
$$ = tmp;
}
| register_variable_list ',' register_variable
{ list<string>*tmp = $1;
tmp->push_back(*$3);
delete $3;
$$ = tmp;
}
1998-11-04 00:28:49 +01:00
;
statement
: K_begin statement_list K_end
{ $$ = pform_make_block(PBlock::BL_SEQ, $2); }
| K_fork statement_list K_join
{ $$ = pform_make_block(PBlock::BL_PAR, $2); }
| K_begin K_end
{ $$ = pform_make_block(PBlock::BL_SEQ, 0); }
| K_fork K_join
{ $$ = pform_make_block(PBlock::BL_PAR, 0); }
| K_case '(' expression ')' case_items K_endcase
{ PCase*tmp = new PCase($3, $5);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_if '(' expression ')' statement_opt
{ PCondit*tmp = new PCondit($3, $5, 0);
$$ = tmp;
}
| K_if '(' expression ')' statement_opt K_else statement_opt
{ PCondit*tmp = new PCondit($3, $5, $7);
$$ = tmp;
}
| K_if '(' error ')' statement_opt
{ yyerror(@1, "Malformed conditional expression.");
$$ = $5;
}
| K_if '(' error ')' statement_opt K_else statement_opt
{ yyerror(@1, "Malformed conditional expression.");
$$ = $5;
}
| K_for '(' lpvalue '=' expression ';' expression ';'
lpvalue '=' expression ')' statement
{ $$ = new PForStatement(*$3, $5, $7, *$9, $11, $13);
delete $3;
delete $9;
}
| K_for '(' lpvalue '=' expression ';' expression ';'
error ')' statement
{ $$ = 0;
yyerror(@9, "Error in for loop step assigment.");
}
| K_for '(' lpvalue '=' expression ';' error ';'
lpvalue '=' expression ')' statement
{ $$ = 0;
yyerror(@7, "Error in for loop condition expression.");
}
| K_for '(' error ')' statement
{ $$ = 0;
yyerror(@3, "Incomprehensible for loop.");
}
| K_while '(' expression ')' statement
1998-11-11 04:13:04 +01:00
{ PWhile*tmp = new PWhile($3, $5);
$$ = tmp;
}
| K_while '(' error ')' statement
{ $$ = 0;
yyerror(@3, "Error in while loop condition.");
}
1998-11-04 00:28:49 +01:00
| delay statement_opt
{ PDelayStatement*tmp = new PDelayStatement($1, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
1998-11-04 00:28:49 +01:00
$$ = tmp;
}
| event_control statement_opt
{ PEventStatement*tmp = $1;
1999-04-29 04:16:26 +02:00
if (tmp == 0) {
yyerror(@1, "Invalid event control.");
$$ = 0;
} else {
tmp->set_statement($2);
$$ = tmp;
}
1998-11-04 00:28:49 +01:00
}
| lpvalue '=' expression ';'
{ Statement*tmp = pform_make_assignment($1, $3);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
1998-11-04 00:28:49 +01:00
}
| lpvalue K_LE expression ';'
1998-11-04 00:28:49 +01:00
{ $$ = pform_make_assignment($1, $3);
yyerror(@1, "Sorry, non-blocking assignment not implemented.");
}
| K_wait '(' expression ')' statement_opt
{ PEventStatement*tmp;
PEEvent*etmp = new PEEvent(NetNEvent::POSITIVE, $3);
1999-04-29 04:16:26 +02:00
tmp = new PEventStatement(etmp);
tmp->set_statement($5);
$$ = tmp;
}
1998-11-04 00:28:49 +01:00
| SYSTEM_IDENTIFIER '(' expression_list ')' ';'
{ $$ = pform_make_calltask($1, $3);
}
| SYSTEM_IDENTIFIER ';'
{ $$ = pform_make_calltask($1);
}
| error ';'
{ yyerror(@1, "malformed statement");
$$ = new PNoop;
}
;
statement_list
: statement_list statement
{ list<Statement*>*tmp = $1;
tmp->push_back($2);
$$ = tmp;
}
| statement
{ list<Statement*>*tmp = new list<Statement*>();
tmp->push_back($1);
$$ = tmp;
}
;
statement_opt
: statement
| ';' { $$ = 0; }
;
udp_body
: K_table { lex_start_table(); }
udp_entry_list
K_endtable { lex_end_table(); $$ = $3; }
;
udp_entry_list
: udp_comb_entry_list
| udp_sequ_entry_list
;
udp_comb_entry
: udp_input_list ':' udp_output_sym ';'
{ string*tmp = $1;
*tmp += ':';
*tmp += $3;
$$ = tmp;
}
;
udp_comb_entry_list
: udp_comb_entry
{ list<string>*tmp = new list<string>;
tmp->push_back(*$1);
delete $1;
$$ = tmp;
}
| udp_comb_entry_list udp_comb_entry
{ list<string>*tmp = $1;
tmp->push_back(*$2);
delete $2;
$$ = tmp;
}
;
udp_sequ_entry_list
: udp_sequ_entry
{ list<string>*tmp = new list<string>;
tmp->push_back(*$1);
delete $1;
$$ = tmp;
}
| udp_sequ_entry_list udp_sequ_entry
{ list<string>*tmp = $1;
tmp->push_back(*$2);
delete $2;
$$ = tmp;
}
;
udp_sequ_entry
: udp_input_list ':' udp_input_sym ':' udp_output_sym ';'
{ string*tmp = $1;
*tmp += ':';
*tmp += $3;
*tmp += ':';
*tmp += $5;
$$ = tmp;
}
;
udp_initial
: K_initial IDENTIFIER '=' NUMBER ';'
{ PExpr*etmp = new PENumber($4);
PAssign*atmp = new PAssign(*$2, etmp);
atmp->set_file(@2.text);
atmp->set_lineno(@2.first_line);
delete $2;
$$ = atmp;
}
;
udp_init_opt
: udp_initial { $$ = $1; }
| { $$ = 0; }
;
udp_input_list
: udp_input_sym
{ string*tmp = new string;
*tmp += $1;
$$ = tmp;
}
| udp_input_list udp_input_sym
{ string*tmp = $1;
*tmp += $2;
$$ = tmp;
}
;
udp_input_sym
: '0' { $$ = '0'; }
| '1' { $$ = '1'; }
| 'x' { $$ = 'x'; }
| '?' { $$ = '?'; }
| 'b' { $$ = 'b'; }
| '*' { $$ = '*'; }
| 'f' { $$ = 'f'; }
| 'r' { $$ = 'r'; }
| 'n' { $$ = 'n'; }
| 'p' { $$ = 'p'; }
| '_' { $$ = '_'; }
;
udp_output_sym
: '0' { $$ = '0'; }
| '1' { $$ = '1'; }
| 'x' { $$ = 'x'; }
| '-' { $$ = '-'; }
;
udp_port_decl
: K_input list_of_variables ';'
{ $$ = pform_make_udp_input_ports($2); }
| K_output IDENTIFIER ';'
{ PWire*pp = new PWire(*$2);
pp->port_type = NetNet::POUTPUT;
list<PWire*>*tmp = new list<PWire*>;
tmp->push_back(pp);
delete $2;
$$ = tmp;
}
| K_reg IDENTIFIER ';'
{ PWire*pp = new PWire(*$2, NetNet::REG);
pp->port_type = NetNet::PIMPLICIT;
list<PWire*>*tmp = new list<PWire*>;
tmp->push_back(pp);
delete $2;
$$ = tmp;
}
;
udp_port_decls
: udp_port_decl
{ $$ = $1; }
| udp_port_decls udp_port_decl
{ list<PWire*>*tmp = $1;
tmp->merge(*$2);
delete $2;
$$ = tmp;
}
;
udp_port_list
: IDENTIFIER
{ list<string>*tmp = new list<string>;
tmp->push_back(*$1);
delete $1;
$$ = tmp;
}
| udp_port_list ',' IDENTIFIER
{ list<string>*tmp = $1;
tmp->push_back(*$3);
delete $3;
$$ = tmp;
}
;
udp_primitive
: K_primitive IDENTIFIER '(' udp_port_list ')' ';'
udp_port_decls
udp_init_opt
udp_body
K_endprimitive
{ pform_make_udp($2, $4, $7, $9, $8); }
;