Add parser support for architecture declaratives and component instantiations

Also include support for "sorry" messages so that we have a place
to hang unsupported but properly parsed constructs.

In the process of doing this, I also encountered and add parser support
for indexed names. And matching "sorry" messages.
This commit is contained in:
Stephen Williams 2011-03-19 18:26:43 -07:00
parent 2b7323f2c2
commit 89aa08e1aa
3 changed files with 215 additions and 28 deletions

View File

@ -96,6 +96,7 @@ int main(int argc, char*argv[])
for (int idx = optind ; idx < argc ; idx += 1) {
parse_errors = 0;
parse_sorrys = 0;
FILE*fd = fopen(argv[idx], "r");
if (fd == 0) {
perror(argv[idx]);
@ -105,10 +106,14 @@ int main(int argc, char*argv[])
reset_lexor(fd, argv[idx]);
rc = yyparse();
if (verbose_flag)
fprintf(stderr, "yyparse() returns %d, parse_errors=%d\n", rc, parse_errors);
fprintf(stderr, "yyparse() returns %d, parse_errors=%d, parse_sorrys=%d\n", rc, parse_errors, parse_sorrys);
if (parse_errors > 0) {
fprintf(stderr, "%d errors parsing %s\n", parse_errors, argv[idx]);
fprintf(stderr, "Encountered %d errors parsing %s\n", parse_errors, argv[idx]);
return 2;
}
if (parse_sorrys > 0) {
fprintf(stderr, "Encountered %d unsupported constructs parsing %s\n", parse_sorrys, argv[idx]);
return 2;
}

View File

@ -52,6 +52,7 @@ inline void FILE_NAME(LineInfo*tmp, const struct yyltype&where)
static void yyerror(const char*msg);
int parse_errors = 0;
int parse_sorrys = 0;
%}
@ -114,13 +115,17 @@ int parse_errors = 0;
%type <flag> direction
%type <interface_list> interface_element interface_list entity_header port_clause
%type <text> name
%type <interface_list> interface_element interface_list entity_header
%type <interface_list> port_clause port_clause_opt
%type <port_mode> mode
%type <arch_statement> concurrent_statement concurrent_signal_assignment_statement
%type <arch_statement> concurrent_statement component_instantiation_statement concurrent_signal_assignment_statement
%type <arch_statement_list> architecture_statement_part
%type <expr> expression expression_logical factor primary relation
%type <expr> expression factor primary relation
%type <expr> expression_logical expression_logical_and expression_logical_or
%type <expr> expression_logical_xnor expression_logical_xor
%type <expr> shift_expression simple_expression term waveform_element
%type <expr_list> waveform waveform_elements
@ -138,29 +143,31 @@ design_file : design_units ;
architecture_body
: K_architecture IDENTIFIER
K_of IDENTIFIER
K_is
K_is block_declarative_items_opt
K_begin architecture_statement_part K_end K_architecture_opt identifier_opt ';'
{ Architecture*tmp = new Architecture(lex_strings.make($2), *$7);
{ Architecture*tmp = new Architecture(lex_strings.make($2), *$8);
FILE_NAME(tmp, @1);
bind_architecture_to_entity($4, tmp);
if ($10 && tmp->get_name() != $10)
if ($11 && tmp->get_name() != $11)
errormsg(@2, "Architecture name doesn't match closing name\n");
delete[]$2;
delete[]$4;
delete $7;
if ($10) delete[]$10
delete $8;
if ($11) delete[]$11;
}
| K_architecture IDENTIFIER
K_of IDENTIFIER
K_is
K_is block_declarative_items_opt
K_begin error K_end K_architecture_opt identifier_opt ';'
{ errormsg(@1, "Syntax error in architecture statement.\n"); yyerrok; }
{ errormsg(@8, "Errors in architecture statements.\n"); yyerrok; }
| K_architecture error ';'
{ errormsg(@1, "Syntax error in architecture body.\n"); yyerrok; }
{ errormsg(@2, "Errors in architecture body.\n"); yyerrok; }
;
/* The architecture_statement_part is a list of concurrent
statements. */
/*
* The architecture_statement_part is a list of concurrent
* statements.
*/
architecture_statement_part
: architecture_statement_part concurrent_statement
{ std::list<Architecture::Statement*>*tmp = $1;
@ -172,10 +179,85 @@ architecture_statement_part
if ($1) tmp->push_back($1);
$$ = tmp;
}
| error ';'
{ $$ = 0;
errormsg(@1, "Syntax error in architecture statement.\n");
yyerrok;
}
;
association_element
: name ARROW name
;
association_list
: association_list ',' association_element
| association_element
;
block_declarative_item
: K_signal identifier_list ':' subtype_indication ';'
{ sorrymsg(@1, "Signal declarations are not supported.\n"); }
| K_component IDENTIFIER K_is_opt
port_clause_opt
K_end K_component identifier_opt ';'
{ perm_string name = lex_strings.make($2);
if ($7 && name != $7) {
errormsg(@7, "Identifier %s doesn't match component name %s\n",
$7, name.str());
}
delete[]$2;
if ($4) delete $4;
delete[]$7;
sorrymsg(@1, "Component declarations not supported.\n");
}
/* Various error handling rules for block_declarative_item... */
| K_signal error ';'
{ errormsg(@2, "Syntax error declaring signals.\n"); yyerrok; }
| error ';'
{ errormsg(@1, "Syntax error in block declarations.\n"); yyerrok; }
| K_component IDENTIFIER K_is_opt error K_end K_component identifier_opt ';'
{ errormsg(@4, "Syntax error in component declaration.\n"); yyerrok; }
;
/*
* The block_declarative_items rule matches "{ block_declarative_item }"
* which is a synonym for "architecture_declarative_part" and
* "block_declarative_part".
*/
block_declarative_items
: block_declarative_items block_declarative_item
| block_declarative_item
;
block_declarative_items_opt
: block_declarative_items
|
;
component_instantiation_statement
: IDENTIFIER ':' IDENTIFIER port_map_aspect_opt ';'
{ sorrymsg(@1, "Component instantiation statements are not supported.\n");
delete[]$1;
delete[]$3;
$$ = 0;
}
| IDENTIFIER ':' IDENTIFIER error ';'
{ errormsg(@4, "Errors in component instantiation.\n");
delete[]$1;
delete[]$3;
$$ = 0;
}
;
concurrent_signal_assignment_statement
: IDENTIFIER LEQ waveform ';'
: name LEQ waveform ';'
{ perm_string targ_name = lex_strings.make($1);
SignalAssignment*tmp = new SignalAssignment(targ_name, *$3);
FILE_NAME(tmp, @1);
@ -184,7 +266,7 @@ concurrent_signal_assignment_statement
delete[]$1;
delete $3;
}
| IDENTIFIER LEQ error ';'
| name LEQ error ';'
{ errormsg(@2, "Syntax error in signal assignment waveform.\n");
$$ = 0;
yyerrok;
@ -192,7 +274,8 @@ concurrent_signal_assignment_statement
;
concurrent_statement
: concurrent_signal_assignment_statement
: component_instantiation_statement
| concurrent_signal_assignment_statement
;
context_clause : context_items | ;
@ -267,19 +350,42 @@ expression
{ $$ = $1; }
;
/*
* The expression_logical matches the logical_expression from the
* standard. Note that this is a little more tricky then usual because
* of the strange VHDL rules for logical expressions. We have to
* account for things like this:
*
* <exp> and <exp> and <exp>...
*
* which is matched by the standard rule:
*
* logical_expression ::=
* ...
* relation { and relation }
*
* The {} is important, and implies that "and" can be strung together
* with other "and" operators without parentheses. This is true for
* "and", "or", "xor", and "xnor". The tricky part is that these
* cannot be mixed. For example, this is not OK:
*
* <exp> and <exp> or <exp>
*
* Also note that "nand" and "nor" can not be chained in this manner.
*/
expression_logical
: relation { $$ = $1; }
| relation K_and relation
| relation K_and expression_logical_and
{ ExpLogical*tmp = new ExpLogical(ExpLogical::AND, $1, $3);
FILE_NAME(tmp, @2);
$$ = tmp;
}
| relation K_or relation
| relation K_or expression_logical_or
{ ExpLogical*tmp = new ExpLogical(ExpLogical::OR, $1, $3);
FILE_NAME(tmp, @2);
$$ = tmp;
}
| relation K_xor relation
| relation K_xor expression_logical_xor
{ ExpLogical*tmp = new ExpLogical(ExpLogical::XOR, $1, $3);
FILE_NAME(tmp, @2);
$$ = tmp;
@ -294,13 +400,53 @@ expression_logical
FILE_NAME(tmp, @2);
$$ = tmp;
}
| relation K_xnor relation
| relation K_xnor expression_logical_xnor
{ ExpLogical*tmp = new ExpLogical(ExpLogical::XNOR, $1, $3);
FILE_NAME(tmp, @2);
$$ = tmp;
}
;
expression_logical_and
: relation
{ $$ = $1; }
| expression_logical_and K_and relation
{ ExpLogical*tmp = new ExpLogical(ExpLogical::AND, $1, $3);
FILE_NAME(tmp, @2);
$$ = tmp;
}
;
expression_logical_or
: relation
{ $$ = $1; }
| expression_logical_or K_or relation
{ ExpLogical*tmp = new ExpLogical(ExpLogical::OR, $1, $3);
FILE_NAME(tmp, @2);
$$ = tmp;
}
;
expression_logical_xnor
: relation
{ $$ = $1; }
| expression_logical_xnor K_xnor relation
{ ExpLogical*tmp = new ExpLogical(ExpLogical::XNOR, $1, $3);
FILE_NAME(tmp, @2);
$$ = tmp;
}
;
expression_logical_xor
: relation
{ $$ = $1; }
| expression_logical_xor K_xor relation
{ ExpLogical*tmp = new ExpLogical(ExpLogical::XOR, $1, $3);
FILE_NAME(tmp, @2);
$$ = tmp;
}
;
factor
: primary
{ $$ = $1; }
@ -407,6 +553,15 @@ mode
| K_out { $$ = PORT_OUT; }
;
name
: IDENTIFIER
{ $$ = $1; }
| IDENTIFIER '(' expression ')'
{ sorrymsg(@3, "Indexed names not supported yet.\n");
$$ = $1;
}
;
port_clause
: K_port '(' interface_list ')' ';'
{ $$ = $3; }
@ -417,8 +572,19 @@ port_clause
}
;
port_clause_opt : port_clause {$$ = $1;} | {$$ = 0;} ;
port_map_aspect
: K_port K_map '(' association_list ')'
;
port_map_aspect_opt
: port_map_aspect
|
;
primary
: IDENTIFIER
: name
{ ExpName*tmp = new ExpName(lex_strings.make($1));
FILE_NAME(tmp, @1);
delete[]$1;
@ -546,12 +712,13 @@ waveform_element
/* Some keywords are optional in some contexts. In all such cases, a
similar rule is used, as described here. */
K_architecture_opt : K_architecture | ;
K_entity_opt : K_entity | ;
K_entity_opt : K_entity | ;
K_is_opt : K_is | ;
%%
static void yyerror(const char*msg)
static void yyerror(const char* /*msg*/)
{
fprintf(stderr, "%s\n", msg);
//fprintf(stderr, "%s\n", msg);
parse_errors += 1;
}
@ -562,12 +729,23 @@ void errormsg(const YYLTYPE&loc, const char*fmt, ...)
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d: ", file_path, loc.first_line);
fprintf(stderr, "%s:%d: error: ", file_path, loc.first_line);
vfprintf(stderr, fmt, ap);
va_end(ap);
parse_errors += 1;
}
void sorrymsg(const YYLTYPE&loc, const char*fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d: sorry: ", file_path, loc.first_line);
vfprintf(stderr, fmt, ap);
va_end(ap);
parse_sorrys += 1;
}
/*
* This is used only by the lexor, to set the file path used in error
* messages.

View File

@ -60,6 +60,8 @@ extern int yyparse(void);
*/
extern void errormsg(const YYLTYPE&loc, const char*fmt, ...) __attribute__((format (printf, 2, 3)));
extern void sorrymsg(const YYLTYPE&loc, const char*fmt, ...) __attribute__((format (printf, 2, 3)));
/*
* Set this to a non-zero value to enable parser debug output.
*/
@ -68,8 +70,10 @@ extern int yydebug;
/*
* The parser counts the errors that is handed in the parse_errors
* variable. For a clean compile, this value should not change. (The
* caller sets its initial value.)
* caller sets its initial value.) The sorrys are the count of
* unsupported constructs that are encountered.
*/
extern int parse_errors;
extern int parse_sorrys;
#endif