Flesh out VHDL parser engine.
Add enough rules to parse a simple VHDL program: Parse library and use clauses, Parse entity declarations, and Parse architecture bodies. Add some parser infrastructure: Handle syntax errors with useful error messages, Include file name and line numbers in parse errors, Add some parser debug aids.
This commit is contained in:
parent
8cf1fd1820
commit
04b239a5fb
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
# include "parse_api.h"
|
# include "parse_api.h"
|
||||||
# include "lexor_keyword.h"
|
# include "lexor_keyword.h"
|
||||||
|
# include "parse.h"
|
||||||
|
|
||||||
extern int lexor_keyword_code (const char*str, unsigned len);
|
extern int lexor_keyword_code (const char*str, unsigned len);
|
||||||
|
|
||||||
|
|
@ -35,7 +36,7 @@ extern int lexor_keyword_code (const char*str, unsigned len);
|
||||||
* the name as it exists in the list (and delete the passed string.)
|
* the name as it exists in the list (and delete the passed string.)
|
||||||
* If the name is new, it will be added to the list.
|
* If the name is new, it will be added to the list.
|
||||||
*/
|
*/
|
||||||
YYLTYPE yylloc;
|
extern YYLTYPE yylloc;
|
||||||
|
|
||||||
static int comment_enter;
|
static int comment_enter;
|
||||||
|
|
||||||
|
|
@ -71,3 +72,22 @@ W [ \t\b\f\r]+
|
||||||
int rc = lexor_keyword_code(yytext, yyleng);
|
int rc = lexor_keyword_code(yytext, yyleng);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compound symbols */
|
||||||
|
"<=" { return LEQ; }
|
||||||
|
">=" { return GEQ; }
|
||||||
|
":=" { return VASSIGN; }
|
||||||
|
|
||||||
|
. { return yytext[0]; }
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
extern void yyparse_set_filepath(const char*path);
|
||||||
|
|
||||||
|
void reset_lexor(FILE*fd, const char*path)
|
||||||
|
{
|
||||||
|
yylloc.first_line = 1;
|
||||||
|
yyrestart(fd);
|
||||||
|
|
||||||
|
yyparse_set_filepath(path);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,19 @@ struct lexor_keyword { const char*name; int mask; int tokenType; };
|
||||||
%%
|
%%
|
||||||
abs, GN_KEYWORD_2008, K_abs
|
abs, GN_KEYWORD_2008, K_abs
|
||||||
access, GN_KEYWORD_2008, K_access
|
access, GN_KEYWORD_2008, K_access
|
||||||
|
all, GN_KEYWORD_2008, K_all
|
||||||
|
and, GN_KEYWORD_2008, K_and
|
||||||
architecture, GN_KEYWORD_2008, K_architecture
|
architecture, GN_KEYWORD_2008, K_architecture
|
||||||
|
begin, GN_KEYWORD_2008, K_begin
|
||||||
|
end, GN_KEYWORD_2008, K_end
|
||||||
|
entity, GN_KEYWORD_2008, K_entity
|
||||||
|
in, GN_KEYWORD_2008, K_in
|
||||||
|
is, GN_KEYWORD_2008, K_is
|
||||||
|
library, GN_KEYWORD_2008, K_library
|
||||||
|
of, GN_KEYWORD_2008, K_of
|
||||||
|
out, GN_KEYWORD_2008, K_out
|
||||||
|
port, GN_KEYWORD_2008, K_port
|
||||||
|
use, GN_KEYWORD_2008, K_use
|
||||||
%%
|
%%
|
||||||
|
|
||||||
int lexor_keyword_mask = GN_KEYWORD_2008;
|
int lexor_keyword_mask = GN_KEYWORD_2008;
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,33 @@ const char NOTICE[] =
|
||||||
" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
|
" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
# include <stdio.h>
|
# include "parse_api.h"
|
||||||
# include <stdlib.h>
|
# include <cstdio>
|
||||||
|
# include <cstdlib>
|
||||||
|
# include <cstring>
|
||||||
#if defined(HAVE_GETOPT_H)
|
#if defined(HAVE_GETOPT_H)
|
||||||
# include <getopt.h>
|
# include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void process_debug_token(const char*word)
|
||||||
|
{
|
||||||
|
if (strcmp(word, "yydebug") == 0) {
|
||||||
|
yydebug = 1;
|
||||||
|
} else if (strcmp(word, "no-yydebug") == 0) {
|
||||||
|
yydebug = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char*argv[])
|
int main(int argc, char*argv[])
|
||||||
{
|
{
|
||||||
int opt;
|
int opt;
|
||||||
|
int rc;
|
||||||
|
|
||||||
while ( (opt=getopt(argc, argv, "vV")) != EOF) switch (opt) {
|
while ( (opt=getopt(argc, argv, "D:vV")) != EOF) switch (opt) {
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
process_debug_token(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
fprintf(stderr, "Icarus Verilog VHDL Parse version "
|
fprintf(stderr, "Icarus Verilog VHDL Parse version "
|
||||||
|
|
@ -66,5 +82,25 @@ int main(int argc, char*argv[])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int idx = optind ; idx < argc ; idx += 1) {
|
||||||
|
parse_errors = 0;
|
||||||
|
FILE*fd = fopen(argv[idx], "r");
|
||||||
|
if (fd == 0) {
|
||||||
|
perror(argv[idx]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_lexor(fd, argv[idx]);
|
||||||
|
rc = yyparse();
|
||||||
|
fprintf(stderr, "yyparse() returns %d, parse_errors=%d\n", rc, parse_errors);
|
||||||
|
|
||||||
|
if (parse_errors > 0) {
|
||||||
|
fprintf(stderr, "%d errors parsing %s\n", parse_errors, argv[idx]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
185
vhdlpp/parse.y
185
vhdlpp/parse.y
|
|
@ -21,9 +21,12 @@
|
||||||
|
|
||||||
# include "vhdlpp_config.h"
|
# include "vhdlpp_config.h"
|
||||||
# include "parse_api.h"
|
# include "parse_api.h"
|
||||||
|
# include <cstdarg>
|
||||||
|
|
||||||
static void yyerror(const char*msg);
|
static void yyerror(const char*msg);
|
||||||
|
|
||||||
|
static void errormsg(const YYLTYPE&loc, const char*msg, ...);
|
||||||
|
int parse_errors = 0;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
/* The keywords are all tokens. */
|
/* The keywords are all tokens. */
|
||||||
|
|
@ -53,12 +56,192 @@ static void yyerror(const char*msg);
|
||||||
%token K_xnor K_xor
|
%token K_xnor K_xor
|
||||||
/* Identifiers that are not keywords are identifiers. */
|
/* Identifiers that are not keywords are identifiers. */
|
||||||
%token IDENTIFIER
|
%token IDENTIFIER
|
||||||
|
/* compound symbols */
|
||||||
|
%token LEQ GEQ VASSIGN
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
main : ;
|
/* The design_file is the root for the VHDL parse. */
|
||||||
|
design_file : design_units ;
|
||||||
|
|
||||||
|
architecture_body
|
||||||
|
: K_architecture IDENTIFIER
|
||||||
|
K_of IDENTIFIER
|
||||||
|
K_is
|
||||||
|
K_begin architecture_statement_part K_end K_architecture_opt ';'
|
||||||
|
| K_architecture IDENTIFIER
|
||||||
|
K_of IDENTIFIER
|
||||||
|
K_is
|
||||||
|
K_begin error K_end K_architecture_opt ';'
|
||||||
|
{ errormsg(@1, "Syntax error in architecture statement.\n"); yyerrok; }
|
||||||
|
| K_architecture error ';'
|
||||||
|
{ errormsg(@1, "Syntax error in architecture body.\n"); yyerrok; }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* The architecture_statement_part is a list of concurrent
|
||||||
|
statements. */
|
||||||
|
architecture_statement_part
|
||||||
|
: architecture_statement_part concurrent_statement
|
||||||
|
| concurrent_statement
|
||||||
|
;
|
||||||
|
|
||||||
|
concurrent_signal_assignment_statement
|
||||||
|
: IDENTIFIER LEQ waveform ';'
|
||||||
|
;
|
||||||
|
|
||||||
|
concurrent_statement
|
||||||
|
: concurrent_signal_assignment_statement
|
||||||
|
;
|
||||||
|
|
||||||
|
context_clause : context_items | ;
|
||||||
|
|
||||||
|
context_item
|
||||||
|
: library_clause
|
||||||
|
| use_clause
|
||||||
|
;
|
||||||
|
|
||||||
|
context_items
|
||||||
|
: context_items context_item
|
||||||
|
| context_item
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
design_unit
|
||||||
|
: context_clause library_unit
|
||||||
|
| error { errormsg(@1, "Invalid design_unit\n"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
design_units
|
||||||
|
: design_units design_unit
|
||||||
|
| design_unit
|
||||||
|
;
|
||||||
|
|
||||||
|
entity_declaration
|
||||||
|
: K_entity IDENTIFIER K_is entity_header K_end K_entity ';'
|
||||||
|
;
|
||||||
|
|
||||||
|
entity_header
|
||||||
|
: port_clause
|
||||||
|
;
|
||||||
|
|
||||||
|
expression
|
||||||
|
: expression_logical
|
||||||
|
;
|
||||||
|
|
||||||
|
expression_logical
|
||||||
|
: relation K_and relation
|
||||||
|
| relation K_or relation
|
||||||
|
;
|
||||||
|
|
||||||
|
factor : primary ;
|
||||||
|
|
||||||
|
/* The interface_element is also an interface_declaration */
|
||||||
|
interface_element
|
||||||
|
: IDENTIFIER ':' mode IDENTIFIER
|
||||||
|
;
|
||||||
|
|
||||||
|
interface_list
|
||||||
|
: interface_list ';' interface_element
|
||||||
|
| interface_element
|
||||||
|
;
|
||||||
|
|
||||||
|
library_clause
|
||||||
|
: K_library logical_name_list ';'
|
||||||
|
| K_library error ';'
|
||||||
|
{ errormsg(@1, "Syntax error in library clause.\n"); yyerrok; }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Collapse the primary_unit and secondary_unit of the library_unit
|
||||||
|
into this single set of rules. */
|
||||||
|
library_unit
|
||||||
|
: entity_declaration
|
||||||
|
| architecture_body
|
||||||
|
;
|
||||||
|
|
||||||
|
logical_name : IDENTIFIER ;
|
||||||
|
|
||||||
|
logical_name_list
|
||||||
|
: logical_name_list ',' logical_name
|
||||||
|
| logical_name
|
||||||
|
;
|
||||||
|
|
||||||
|
mode : K_in | K_out ;
|
||||||
|
|
||||||
|
port_clause : K_port '(' interface_list ')' ';' ;
|
||||||
|
|
||||||
|
primary
|
||||||
|
: IDENTIFIER
|
||||||
|
;
|
||||||
|
|
||||||
|
relation : shift_expression ;
|
||||||
|
|
||||||
|
selected_name
|
||||||
|
: IDENTIFIER '.' K_all
|
||||||
|
| IDENTIFIER '.' IDENTIFIER '.' K_all
|
||||||
|
;
|
||||||
|
|
||||||
|
selected_names
|
||||||
|
: selected_names ',' selected_name
|
||||||
|
| selected_name
|
||||||
|
;
|
||||||
|
|
||||||
|
shift_expression : simple_expression ;
|
||||||
|
|
||||||
|
simple_expression : term ;
|
||||||
|
|
||||||
|
term : factor ;
|
||||||
|
|
||||||
|
use_clause
|
||||||
|
: K_use selected_names ';'
|
||||||
|
| K_use error ';'
|
||||||
|
{ errormsg(@1, "Syntax error in use clause.\n"); yyerrok; }
|
||||||
|
;
|
||||||
|
|
||||||
|
waveform
|
||||||
|
: waveform_elements
|
||||||
|
| K_unaffected
|
||||||
|
;
|
||||||
|
|
||||||
|
waveform_elements
|
||||||
|
: waveform_elements ',' waveform_element
|
||||||
|
| waveform_element
|
||||||
|
;
|
||||||
|
|
||||||
|
waveform_element
|
||||||
|
: expression
|
||||||
|
| K_null
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Some keywords are optional in some contexts. In all such cases, a
|
||||||
|
similar rule is used, as described here. */
|
||||||
|
K_architecture_opt : K_architecture | ;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
static void yyerror(const char*msg)
|
static void yyerror(const char*msg)
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "%s\n", msg);
|
||||||
|
parse_errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char*file_path = "";
|
||||||
|
|
||||||
|
static void errormsg(const YYLTYPE&loc, const char*fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
|
||||||
|
fprintf(stderr, "%s:%d: ", file_path, loc.first_line);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
parse_errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is used only by the lexor, to set the file path used in error
|
||||||
|
* messages.
|
||||||
|
*/
|
||||||
|
void yyparse_set_filepath(const char*path)
|
||||||
|
{
|
||||||
|
file_path = path;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
# include <cstdio>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The vlltype supports the passing of detailed source file location
|
* The vlltype supports the passing of detailed source file location
|
||||||
* information between the lexical analyzer and the parser. Defining
|
* information between the lexical analyzer and the parser. Defining
|
||||||
|
|
@ -33,6 +35,26 @@ struct yyltype {
|
||||||
};
|
};
|
||||||
# define YYLTYPE struct yyltype
|
# define YYLTYPE struct yyltype
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The reset_lexor function takes the fd and makes it the input file
|
||||||
|
* for the lexor. The path argument is used in lexor/parser error messages.
|
||||||
|
*/
|
||||||
|
extern void reset_lexor(FILE*fd, const char*path);
|
||||||
|
|
||||||
extern int yylex(void);
|
extern int yylex(void);
|
||||||
|
|
||||||
|
extern int yyparse(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set this to a non-zero value to enable parser debug output.
|
||||||
|
*/
|
||||||
|
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.)
|
||||||
|
*/
|
||||||
|
extern int parse_errors;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue