From ac28743eb0c91f196143aaf287fe56fb54a5ccfb Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Thu, 27 Jan 2011 15:13:38 +0100 Subject: [PATCH 1/5] New keywords to lexer added and typos corrected --- vhdlpp/lexor_keyword.gperf | 95 ++++++++++++++++++++++++++++++++++++++ vhdlpp/parse.y | 6 +-- 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/vhdlpp/lexor_keyword.gperf b/vhdlpp/lexor_keyword.gperf index b146ddb45..3a70881d5 100644 --- a/vhdlpp/lexor_keyword.gperf +++ b/vhdlpp/lexor_keyword.gperf @@ -18,19 +18,114 @@ struct lexor_keyword { const char*name; int mask; int tokenType; }; %% abs, GN_KEYWORD_2008, K_abs access, GN_KEYWORD_2008, K_access +after, GN_KEYWORD_2008, K_after +alias, GN_KEYWORD_2008, K_alias all, GN_KEYWORD_2008, K_all and, GN_KEYWORD_2008, K_and architecture, GN_KEYWORD_2008, K_architecture +array, GN_KEYWORD_2008, K_array +assert, GN_KEYWORD_2008, K_assert +attribute, GN_KEYWORD_2008, K_attribute begin, GN_KEYWORD_2008, K_begin +block, GN_KEYWORD_2008, K_block +body, GN_KEYWORD_2008, K_body +buffer, GN_KEYWORD_2008, K_buffer +bus, GN_KEYWORD_2008, K_bus +case, GN_KEYWORD_2008, K_case +component, GN_KEYWORD_2008, K_component +configuration, GN_KEYWORD_2008, K_configuration +constant, GN_KEYWORD_2008, K_constant +context, GN_KEYWORD_2008, K_context +//cover, GN_KEYWORD_2008, K_cover +default, GN_KEYWORD_2008, K_default +disconnect, GN_KEYWORD_2008, K_disconnect +downto, GN_KEYWORD_2008, K_downto +else, GN_KEYWORD_2008, K_else +elsif GN_KEYWORD_2008, K_elsif end, GN_KEYWORD_2008, K_end entity, GN_KEYWORD_2008, K_entity +exit, GN_KEYWORD_2008, K_exit +//fairness, GN_KEYWORD_2008, K_fairness +file, GN_KEYWORD_2008, K_file +for, GN_KEYWORD_2008, K_for +//force, GN_KEYWORD_2008, K_force +function, GN_KEYWORD_2008, K_function +generate, GN_KEYWORD_2008, K_generate +generic, GN_KEYWORD_2008, K_generic +group, GN_KEYWORD_2008, K_group +guarded, GN_KEYWORD_2008, K_guarded +if, GN_KEYWORD_2008, K_if +impure, GN_KEYWORD_2008, K_impure in, GN_KEYWORD_2008, K_in +inertial, GN_KEYWORD_2008, K_internal +inout, GN_KEYWORD_2008, K_inout is, GN_KEYWORD_2008, K_is +label, GN_KEYWORD_2008, K_label library, GN_KEYWORD_2008, K_library +linkage, GN_KEYWORD_2008, K_linkage +literal, GN_KEYWORD_2008, K_literal +loop, GN_KEYWORD_2008, K_loop +map, GN_KEYWORD_2008, K_map +mod, GN_KEYWORD_2008, K_mod +nand, GN_KEYWORD_2008, K_nand +new, GN_KEYWORD_2008, K_new +next, GN_KEYWORD_2008, K_next +nor, GN_KEYWORD_2008, K_nor +not, GN_KEYWORD_2008, K_not +null, GN_KEYWORD_2008, K_null of, GN_KEYWORD_2008, K_of +on, GN_KEYWORD_2008, K_on +or, GN_KEYWORD_2008, K_or +others, GN_KEYWORD_2008, K_others out, GN_KEYWORD_2008, K_out +package, GN_KEYWORD_2008, K_package port, GN_KEYWORD_2008, K_port +postponed, GN_KEYWORD_2008, K_postponed +procedure, GN_KEYWORD_2008, K_procedure +process, GN_KEYWORD_2008, K_process +//property, GN_KEYWORD_2008, K_propoerty +protected, GN_KEYWORD_2008, K_protected +pure, GN_KEYWORD_2008, K_pure +range, GN_KEYWORD_2008, K_range +record, GN_KEYWORD_2008, K_record +register, GN_KEYWORD_2008, K_register +reject, GN_KEYWORD_2008, K_reject +//release, GN_KEYWORD_2008, K_release +rem, GN_KEYWORD_2008, K_rem +report, GN_KEYWORD_2008, K_report +restrict, GN_KEYWORD_2008, K_restrict +return, GN_KEYWORD_2008, K_return +rol, GN_KEYWORD_2008, K_rol +ror, GN_KEYWORD_2008, K_ror +select, GN_KEYWORD_2008, K_select +//sequence, GN_KEYWORD_2008, K_sequence +severity, GN_KEYWORD_2008, K_severity +signal, GN_KEYWORD_2008, K_signal +shared, GN_KEYWORD_2008, K_shared +sla, GN_KEYWORD_2008, K_sla +sll, GN_KEYWORD_2008, K_sll +sra, GN_KEYWORD_2008, K_sra +srl, GN_KEYWORD_2008, K_srl +//string, GN_KEYWORD_2008, K_string +subtype, GN_KEYWORD_2008, K_subtype +then, GN_KEYWORD_2008, K_then +to, GN_KEYWORD_2008, K_to +transport, GN_KEYWORD_2008, K_transport +type, GN_KEYWORD_2008, K_type +unaffected, GN_KEYWORD_2008, K_unaffected +units. GN_KEYWORD_2008, K_units +until, GN_KEYWORD_2008, K_until use, GN_KEYWORD_2008, K_use +variable, GN_KEYWORD_2008, K_variable +//vmode, GN_KEYWORD_2008, K_vmode +//vprop, GN_KEYWORD_2008, K_vprop +//vunit, GN_KEYWORD_2008, K_vunit +wait, GN_KEYWORD_2008, K_wait +when, GN_KEYWORD_2008, K_when +while, GN_KEYWORD_2008, K_while +with, GN_KEYWORD_2008, K_with +xnor, GN_KEYWORD_2008, K_xnor +xor, GN_KEYWORD_2008, K_xor %% int lexor_keyword_mask = GN_KEYWORD_2008; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 306331d48..8524ff574 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -52,11 +52,11 @@ int parse_errors = 0; %token K_array K_assert K_assume K_assume_guarantee K_attribute %token K_begin K_block K_body K_buffer K_bus %token K_case K_component K_configuration K_constant K_context K_cover -%token K_default K_disconect K_downto +%token K_default K_disconnect K_downto %token K_else K_elsif K_end K_entity K_exit %token K_fairness K_file K_for K_force K_function %token K_generate K_generic K_group K_guarded -%token K_if K_impure K_in K_internal K_inout K_is +%token K_if K_impure K_in K_inertial K_inout K_is %token K_label K_library K_linkage K_literal K_loop %token K_map K_mod %token K_nand K_new K_next K_nor K_not K_null @@ -65,7 +65,7 @@ int parse_errors = 0; %token K_property K_protected K_pure %token K_range K_record K_register K_reject K_release K_rem K_report %token K_restrict K_restrict_guarantee K_return K_rol K_ror -%token K_select K_sequence K_seerity K_signal K_shared +%token K_select K_sequence K_severity K_signal K_shared %token K_sla K_sll K_sra K_srl K_string K_subtype %token K_then K_to K_transport K_type %token K_unaffected K_units K_until K_use From d747859a85ee1d1140b0449fb741af04fae7785d Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Fri, 28 Jan 2011 10:03:48 +0100 Subject: [PATCH 2/5] New compound VHDL symbols --- vhdlpp/lexor.lex | 13 +++++++++++++ vhdlpp/parse.y | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index d0d1d6b06..ba9d22c3b 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -73,6 +73,7 @@ W [ \t\b\f\r]+ \n { yylloc.first_line += 1; } "*/" { BEGIN(comment_enter); } + [a-zA-Z_][a-zA-Z0-9_]* { int rc = lexor_keyword_code(yytext, yyleng); switch (rc) { @@ -89,6 +90,18 @@ W [ \t\b\f\r]+ "<=" { return LEQ; } ">=" { return GEQ; } ":=" { return VASSIGN; } +"/=" { return NE; } +"<>" { return BOX; } +j + /* +"??" { return K_CC; } +"?=" {} +"?/=" {} +"?<" {} +"?<=" {} +"?>" {} +"?>=" {} +*/ . { return yytext[0]; } diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 8524ff574..5b7f5322c 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -75,7 +75,7 @@ int parse_errors = 0; /* Identifiers that are not keywords are identifiers. */ %token IDENTIFIER /* compound symbols */ -%token LEQ GEQ VASSIGN +%token LEQ GEQ VASSIGN NE BOX EXP /* The rules may have types. */ %type interface_element From 75203dc12140d5929f0b5b330b1ebdcb7b9989e9 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Fri, 28 Jan 2011 10:40:38 +0100 Subject: [PATCH 3/5] Minor changes to VHDL lexor --- vhdlpp/lexor.lex | 14 ++++++++++++-- vhdlpp/lexor_keyword.gperf | 20 ++++++++++---------- vhdlpp/parse.y | 2 +- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index ba9d22c3b..33011cee4 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -38,6 +38,8 @@ extern int lexor_keyword_code (const char*str, unsigned len); */ extern YYLTYPE yylloc; +static int check_underscores(char*); + static char* strdupnew(char const *str) { return str ? strcpy(new char [strlen(str)+1], str) : 0; @@ -51,7 +53,11 @@ static int comment_enter; %x LCOMMENT W [ \t\b\f\r]+ +decimal_literal {integer}(\.{integer})?({exponent})? +integer [0-9](_?[0-9])* +exponent [eE][-+]?{integer} +based_integer [0-9a-fA-F](_?[0-9a-fA-F])* %% [ \t\b\f\r] { ; } @@ -74,7 +80,7 @@ W [ \t\b\f\r]+ "*/" { BEGIN(comment_enter); } -[a-zA-Z_][a-zA-Z0-9_]* { +[a-zA-Z][a-zA-Z0-9_]* { int rc = lexor_keyword_code(yytext, yyleng); switch (rc) { case IDENTIFIER: @@ -92,7 +98,7 @@ W [ \t\b\f\r]+ ":=" { return VASSIGN; } "/=" { return NE; } "<>" { return BOX; } -j +"**" { return EXP; } /* "??" { return K_CC; } "?=" {} @@ -109,6 +115,10 @@ j extern void yyparse_set_filepath(const char*path); +static int check_underscores(char* text) { + +} + void reset_lexor(FILE*fd, const char*path) { yylloc.text = path; diff --git a/vhdlpp/lexor_keyword.gperf b/vhdlpp/lexor_keyword.gperf index 3a70881d5..2f31ad521 100644 --- a/vhdlpp/lexor_keyword.gperf +++ b/vhdlpp/lexor_keyword.gperf @@ -36,7 +36,7 @@ component, GN_KEYWORD_2008, K_component configuration, GN_KEYWORD_2008, K_configuration constant, GN_KEYWORD_2008, K_constant context, GN_KEYWORD_2008, K_context -//cover, GN_KEYWORD_2008, K_cover +cover, GN_KEYWORD_2008, K_cover default, GN_KEYWORD_2008, K_default disconnect, GN_KEYWORD_2008, K_disconnect downto, GN_KEYWORD_2008, K_downto @@ -45,10 +45,10 @@ elsif GN_KEYWORD_2008, K_elsif end, GN_KEYWORD_2008, K_end entity, GN_KEYWORD_2008, K_entity exit, GN_KEYWORD_2008, K_exit -//fairness, GN_KEYWORD_2008, K_fairness +fairness, GN_KEYWORD_2008, K_fairness file, GN_KEYWORD_2008, K_file for, GN_KEYWORD_2008, K_for -//force, GN_KEYWORD_2008, K_force +force, GN_KEYWORD_2008, K_force function, GN_KEYWORD_2008, K_function generate, GN_KEYWORD_2008, K_generate generic, GN_KEYWORD_2008, K_generic @@ -83,14 +83,14 @@ port, GN_KEYWORD_2008, K_port postponed, GN_KEYWORD_2008, K_postponed procedure, GN_KEYWORD_2008, K_procedure process, GN_KEYWORD_2008, K_process -//property, GN_KEYWORD_2008, K_propoerty +property, GN_KEYWORD_2008, K_propoerty protected, GN_KEYWORD_2008, K_protected pure, GN_KEYWORD_2008, K_pure range, GN_KEYWORD_2008, K_range record, GN_KEYWORD_2008, K_record register, GN_KEYWORD_2008, K_register reject, GN_KEYWORD_2008, K_reject -//release, GN_KEYWORD_2008, K_release +release, GN_KEYWORD_2008, K_release rem, GN_KEYWORD_2008, K_rem report, GN_KEYWORD_2008, K_report restrict, GN_KEYWORD_2008, K_restrict @@ -98,7 +98,7 @@ return, GN_KEYWORD_2008, K_return rol, GN_KEYWORD_2008, K_rol ror, GN_KEYWORD_2008, K_ror select, GN_KEYWORD_2008, K_select -//sequence, GN_KEYWORD_2008, K_sequence +sequence, GN_KEYWORD_2008, K_sequence severity, GN_KEYWORD_2008, K_severity signal, GN_KEYWORD_2008, K_signal shared, GN_KEYWORD_2008, K_shared @@ -106,7 +106,7 @@ sla, GN_KEYWORD_2008, K_sla sll, GN_KEYWORD_2008, K_sll sra, GN_KEYWORD_2008, K_sra srl, GN_KEYWORD_2008, K_srl -//string, GN_KEYWORD_2008, K_string +strong, GN_KEYWORD_2008, K_strong subtype, GN_KEYWORD_2008, K_subtype then, GN_KEYWORD_2008, K_then to, GN_KEYWORD_2008, K_to @@ -117,9 +117,9 @@ units. GN_KEYWORD_2008, K_units until, GN_KEYWORD_2008, K_until use, GN_KEYWORD_2008, K_use variable, GN_KEYWORD_2008, K_variable -//vmode, GN_KEYWORD_2008, K_vmode -//vprop, GN_KEYWORD_2008, K_vprop -//vunit, GN_KEYWORD_2008, K_vunit +vmode, GN_KEYWORD_2008, K_vmode +vprop, GN_KEYWORD_2008, K_vprop +vunit, GN_KEYWORD_2008, K_vunit wait, GN_KEYWORD_2008, K_wait when, GN_KEYWORD_2008, K_when while, GN_KEYWORD_2008, K_while diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 5b7f5322c..0c739cfcb 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -66,7 +66,7 @@ int parse_errors = 0; %token K_range K_record K_register K_reject K_release K_rem K_report %token K_restrict K_restrict_guarantee K_return K_rol K_ror %token K_select K_sequence K_severity K_signal K_shared -%token K_sla K_sll K_sra K_srl K_string K_subtype +%token K_sla K_sll K_sra K_srl K_strong K_subtype %token K_then K_to K_transport K_type %token K_unaffected K_units K_until K_use %token K_variable K_vmode K_vprop K_vunit From 0395eadbc8b4475c8d4e60edc7a42249a25455c8 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Mon, 31 Jan 2011 18:25:29 +0100 Subject: [PATCH 4/5] Introductory changes for numbers handling --- vhdlpp/lexor.lex | 65 +++++++++++++++++++++++++++++++++++--- vhdlpp/lexor_keyword.gperf | 4 +-- vhdlpp/parse.y | 14 ++++++-- vhdlpp/parse_wrap.h | 2 ++ vhdlpp/vhdlnum.h | 13 ++++++++ vhdlpp/vhdlreal.h | 11 +++++++ 6 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 vhdlpp/vhdlnum.h create mode 100644 vhdlpp/vhdlreal.h diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index 33011cee4..dd59ad95b 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -25,8 +25,15 @@ # include "parse_api.h" # include "lexor_keyword.h" +# include "vhdlnum.h" +# include "vhdlreal.h" # include "parse_wrap.h" +# include + +//class vhdlnum; +//class vhdlreal; + extern int lexor_keyword_code (const char*str, unsigned len); /* @@ -38,7 +45,10 @@ extern int lexor_keyword_code (const char*str, unsigned len); */ extern YYLTYPE yylloc; -static int check_underscores(char*); +static int check_underscores(char* text); + +vhdlnum* make_unisized_dec(char* text); +vhdlnum* make_unisized_based(char* text); static char* strdupnew(char const *str) { @@ -57,6 +67,7 @@ decimal_literal {integer}(\.{integer})?({exponent})? integer [0-9](_?[0-9])* exponent [eE][-+]?{integer} +based_literal {integer}#{based_integer}(\.{based_integer})?#{exponent}? based_integer [0-9a-fA-F](_?[0-9a-fA-F])* %% @@ -84,6 +95,9 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* int rc = lexor_keyword_code(yytext, yyleng); switch (rc) { case IDENTIFIER: + if(check_underscores(yytext)) + std::cerr << "An invalid underscore in the identifier" << std::endl; + //yywarn(yylloc, "An invalid underscore in the identifier"); yylval.text = strdupnew(yytext); break; default: @@ -91,7 +105,30 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* } return rc; } + +\\(.|\\\\)*\\ { /* extended identifiers */ + yylval.text = strdupnew(yytext); + printf("special %s\n", yytext); + return IDENTIFIER; +} + +{decimal_literal} { + if(strchr(yytext, '.')) { + yylval.real = new vhdlreal(yytext); + return REAL_LITERAL; + } else { + yylval.integer = new vhdlnum(yytext); + return INT_LITERAL; + } +} + +{based_literal} { + yylval.integer = new vhdlnum(yytext); + return INT_LITERAL; +} + + /* Compound symbols */ "<=" { return LEQ; } ">=" { return GEQ; } @@ -99,7 +136,13 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* "/=" { return NE; } "<>" { return BOX; } "**" { return EXP; } - /* +"=>" { return ARROW; } +"<<" { return DLT; } +">>" { return DGT; } + /* + Here comes a list of symbols that are more then strange, + at least for the time being. + "??" { return K_CC; } "?=" {} "?/=" {} @@ -115,8 +158,22 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* extern void yyparse_set_filepath(const char*path); -static int check_underscores(char* text) { - +static int check_underscores(char* text) +{ + unsigned char underscore_allowed = 0; + const char* cp; + for( cp = text; *cp; ++cp) + { + if (*cp == '_') + { + if (!underscore_allowed || *(cp+1) == '\0') + return 1; + underscore_allowed = 0; + } + else + underscore_allowed = 1; + } + return 0; } void reset_lexor(FILE*fd, const char*path) diff --git a/vhdlpp/lexor_keyword.gperf b/vhdlpp/lexor_keyword.gperf index 2f31ad521..39663f02f 100644 --- a/vhdlpp/lexor_keyword.gperf +++ b/vhdlpp/lexor_keyword.gperf @@ -57,7 +57,7 @@ guarded, GN_KEYWORD_2008, K_guarded if, GN_KEYWORD_2008, K_if impure, GN_KEYWORD_2008, K_impure in, GN_KEYWORD_2008, K_in -inertial, GN_KEYWORD_2008, K_internal +inertial, GN_KEYWORD_2008, K_inertial inout, GN_KEYWORD_2008, K_inout is, GN_KEYWORD_2008, K_is label, GN_KEYWORD_2008, K_label @@ -83,7 +83,7 @@ port, GN_KEYWORD_2008, K_port postponed, GN_KEYWORD_2008, K_postponed procedure, GN_KEYWORD_2008, K_procedure process, GN_KEYWORD_2008, K_process -property, GN_KEYWORD_2008, K_propoerty +property, GN_KEYWORD_2008, K_property protected, GN_KEYWORD_2008, K_protected pure, GN_KEYWORD_2008, K_pure range, GN_KEYWORD_2008, K_range diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 0c739cfcb..9c24a65a1 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -20,9 +20,11 @@ */ # include "vhdlpp_config.h" +# include "vhdlnum.h" +# include "vhdlreal.h" # include "compiler.h" # include "parse_api.h" -# include +# include # include # include @@ -39,10 +41,13 @@ static void errormsg(const YYLTYPE&loc, const char*msg, ...); int parse_errors = 0; %} + %union { port_mode_t port_mode; char*text; - + vhdlnum* integer; + vhdlreal* real; + InterfacePort*interface_element; std::list* interface_list; }; @@ -74,8 +79,11 @@ int parse_errors = 0; %token K_xnor K_xor /* Identifiers that are not keywords are identifiers. */ %token IDENTIFIER +%token INT_LITERAL +%token REAL_LITERAL +%token STRING_LITERAL CHARACTER_LITERAL /* compound symbols */ -%token LEQ GEQ VASSIGN NE BOX EXP +%token LEQ GEQ VASSIGN NE BOX EXP ARROW DLT DGT /* The rules may have types. */ %type interface_element diff --git a/vhdlpp/parse_wrap.h b/vhdlpp/parse_wrap.h index 1b835d5a9..2d09ecd62 100644 --- a/vhdlpp/parse_wrap.h +++ b/vhdlpp/parse_wrap.h @@ -26,6 +26,8 @@ */ # include +# include "vhdlnum.h" +# include "vhdlreal.h" # include "parse.h" #endif diff --git a/vhdlpp/vhdlnum.h b/vhdlpp/vhdlnum.h new file mode 100644 index 000000000..034760315 --- /dev/null +++ b/vhdlpp/vhdlnum.h @@ -0,0 +1,13 @@ +#ifndef __vhdlnum_H +#define __vhdlnum_H + +#include "config.h" + +#warning vhdlnum + +class vhdlnum { + public: + vhdlnum(char* text) {} +}; + +#endif diff --git a/vhdlpp/vhdlreal.h b/vhdlpp/vhdlreal.h new file mode 100644 index 000000000..c74263fdd --- /dev/null +++ b/vhdlpp/vhdlreal.h @@ -0,0 +1,11 @@ +#ifndef __vhdlreal_h +#define __vhdlreal_h + +#include "config.h" + +class vhdlreal { + public: + vhdlreal(char* text) {} +}; + +#endif From 77a346ffb18af8999941e5d0ec71c7e4a55dec53 Mon Sep 17 00:00:00 2001 From: Pawel Szostek Date: Fri, 4 Feb 2011 17:51:51 +0100 Subject: [PATCH 5/5] Added full number, based number (both int and float), string and character literals handling --- vhdlpp/Makefile.in | 4 +- vhdlpp/lexor.lex | 348 ++++++++++++++++++++++++++++++++++++++++++-- vhdlpp/parse.y | 4 +- vhdlpp/parse_wrap.h | 2 +- vhdlpp/vhdlint.cc | 68 +++++++++ vhdlpp/vhdlint.h | 28 ++++ vhdlpp/vhdlreal.cc | 59 ++++++++ vhdlpp/vhdlreal.h | 39 ++++- 8 files changed, 527 insertions(+), 25 deletions(-) create mode 100644 vhdlpp/vhdlint.cc create mode 100644 vhdlpp/vhdlint.h create mode 100644 vhdlpp/vhdlreal.cc diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index 7717473fb..4e51a4d1b 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -57,10 +57,10 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ @EXTRALIBS@ -M = StringHeap.o LineInfo.o +M = StringHeap.o LineInfo.o O = main.o compiler.o entity.o entity_elaborate.o \ - lexor.o lexor_keyword.o parse.o $M + lexor.o lexor_keyword.o parse.o vhdlreal.o vhdlint.o $M all: dep vhdlpp@EXEEXT@ diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index dd59ad95b..f00addcb9 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -19,17 +19,20 @@ * 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 + * aint64_t with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "parse_api.h" # include "lexor_keyword.h" -# include "vhdlnum.h" +# include "vhdlint.h" # include "vhdlreal.h" # include "parse_wrap.h" +# include +# include # include +# include //class vhdlnum; //class vhdlreal; @@ -45,10 +48,16 @@ extern int lexor_keyword_code (const char*str, unsigned len); */ extern YYLTYPE yylloc; -static int check_underscores(char* text); +static bool are_underscores_correct(char* text); +static bool is_based_correct(char* text); +static char* escape_quot_and_dup(char* text); +static char* escape_apostrophe_and_dup(char* text); -vhdlnum* make_unisized_dec(char* text); -vhdlnum* make_unisized_based(char* text); +static double make_double_from_based(char* text); +static int64_t make_long_from_based(char* text); + +static int64_t lpow(int64_t left, int64_t right); +static unsigned short short_from_hex_char(char ch); static char* strdupnew(char const *str) { @@ -90,13 +99,26 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* \n { yylloc.first_line += 1; } "*/" { BEGIN(comment_enter); } +\'.\' { + yylval.text = escape_apostrophe_and_dup(yytext); + return CHARACTER_LITERAL; +} + +(\"([^"]|(\"\"))*?\")|(\"[^\"]*\") { +/* first pattern: string literals with doubled quotation mark */ +/* second pattern: string literals without doubled quotation */ + yylval.text = escape_quot_and_dup(yytext); + assert(yylval.text); + return STRING_LITERAL; +} [a-zA-Z][a-zA-Z0-9_]* { int rc = lexor_keyword_code(yytext, yyleng); switch (rc) { case IDENTIFIER: - if(check_underscores(yytext)) - std::cerr << "An invalid underscore in the identifier" << std::endl; + if(!are_underscores_correct(yytext)) + std::cerr << "An invalid underscore in the identifier:" + << yytext << std::endl; //yywarn(yylloc, "An invalid underscore in the identifier"); yylval.text = strdupnew(yytext); break; @@ -106,26 +128,43 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* return rc; } -\\(.|\\\\)*\\ { /* extended identifiers */ +\\([^\\]|\\\\)*\\ { /* extended identifiers */ yylval.text = strdupnew(yytext); - printf("special %s\n", yytext); return IDENTIFIER; } {decimal_literal} { + if(!are_underscores_correct(yytext)) + std::cerr << "An invalid underscore in the decimal literal:" + << yytext << std::endl; + if(strchr(yytext, '.')) { yylval.real = new vhdlreal(yytext); return REAL_LITERAL; } else { - yylval.integer = new vhdlnum(yytext); + yylval.integer = new vhdlint(yytext); return INT_LITERAL; } } {based_literal} { - yylval.integer = new vhdlnum(yytext); - return INT_LITERAL; + if(!are_underscores_correct(yytext) || !is_based_correct(yytext)) + std::cerr << "An invalid form of based literal:" + << yytext << std::endl; + + if(strchr(yytext, '.')) + { + double val = make_double_from_based(yytext); + yylval.real = new vhdlreal(val); + return REAL_LITERAL; + } + else + { + int64_t val = make_long_from_based(yytext); + yylval.integer = new vhdlint(val); + return INT_LITERAL; + } } @@ -158,7 +197,14 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* extern void yyparse_set_filepath(const char*path); -static int check_underscores(char* text) +/** +* This function checks if underscores in an identifier +* or in a number are correct. +* +* \return true is returned if underscores are placed +* correctly according to specification +*/ +static bool are_underscores_correct(char* text) { unsigned char underscore_allowed = 0; const char* cp; @@ -167,13 +213,285 @@ static int check_underscores(char* text) if (*cp == '_') { if (!underscore_allowed || *(cp+1) == '\0') - return 1; + return 0; underscore_allowed = 0; } else underscore_allowed = 1; } - return 0; + return 1; +} + +/** +* This function checks if the format of a based number +* is correct according to the VHDL standard +* +* \return true is returned if a based number +* is formed well according to specification +*/ +static bool is_based_correct(char* text) +{ + char* ptr; + //BASE examination + char clean_base[4]; + clean_base[3] = '\0'; + char* clean_base_ptr = clean_base; + for(ptr = text; ptr != strchr(text, '#'); ++ptr) + { + if(*ptr == '_') + ++ptr; + if(!(*ptr >= '0' && *ptr <= '9')) //the base uses chars other than digits + return 0; + if(*clean_base_ptr == '\0') + break; + *clean_base_ptr = *ptr; + ++clean_base_ptr; + } + unsigned length = clean_base_ptr - clean_base; + unsigned base; + if(length > 2 || length == 0) + return 0; //the base is too big or too small + if(length == 2) + { + base = 10*(clean_base[0] - '0') + (clean_base[1] - '0'); + //the base exceeds 16 or equals 0 + if(base > 16 || base == 0) + return 0; + } + else + { //the base consists of one char and is equal to zero + base = clean_base[0] - '0'; + if(base == 0) + return 0; + } + bool point = 0; + set allowed_chars; + + unsigned c; + if(base <= 10) { + for(c = 0; c < base; ++c) + allowed_chars.insert(c + '0'); + } + else + { + for(c = 0; c < 10; ++c) + allowed_chars.insert(c + '0'); + for(c = 0; c < base - 10; ++c) + allowed_chars.insert(c + 'a'); + } + //MANTISSA examination + for(ptr = strchr(text, '#') + 1, length = 0; ptr != strrchr(text, '#'); ++ptr) + { + if(*ptr == '.') + { + //we found a dot and another one was already found + if(point == 1) + return 0; + else + { + //notice the fact of finding a point and continue, without increasing the length + point = 1; + continue; + } + } + //the number consists of other chars than allowed + if(allowed_chars.find(*ptr) == allowed_chars.end()) + return 0; + ++length; + } + if(length == 0) + return 0; + + //EXPONENT examination + if(strchr(text, '\0') - strrchr(text, '#') > 1) { //the number contains an exponent + if(*(strrchr(text, '#') + 2) == '-') + return 0; + length = 0; + for(ptr = strrchr(text, '#')+2; *ptr != '\0'; ++ptr) + { + //the exponent consists of other chars than {'0'.,'9','a'..'f'} + if(!((*ptr >= '0' && *ptr <= '9') || (*ptr >= 'a' && *ptr <= 'f'))) + return 0; + } + } + return 1; +} + +/** +* This function takes a string literal, gets rid of +* quotation marks and copies the remaining characters +* to a new persistent C-string +* +* \return pointer to the new string is returned +*/ +static char* escape_quot_and_dup(char* text) +{ + char* newstr = new char[strlen(text)+1]; + + unsigned old_idx, new_idx; + for(new_idx = 0, old_idx = 0; old_idx < strlen(text); ) + { + if(text[old_idx] == '"' && old_idx == 0) + { //the beginning of the literal + ++old_idx; + continue; + } + else + if(text[old_idx] == '"' && text[old_idx+1] == '\0') + { //the end + newstr[new_idx] = '\0'; + return newstr; + } + else + if(text[old_idx] == '"' && text[old_idx+1] == '"') + { + newstr[new_idx++] = '"'; + old_idx += 2; //jump across two chars + } + else + { + newstr[new_idx] = text[old_idx]; + ++old_idx; + ++new_idx; + } + } + //the function should never reach this point + return 0; +} + +/** +* This function takes a character literal, gets rid +* of the apostrophes and returns new C-string +* +* \return pointer to the new string is returned +*/ +static char* escape_apostrophe_and_dup(char* text) +{ + char* newstr = new char[2]; + newstr[0] = text[1]; + newstr[1] = '\0'; + return newstr; +} + +/** +* This function takes a floating point based number +* in form of a C-strings and converts it to a double. +* +* \return new double is returned +*/ +static double make_double_from_based(char* text) +{ + char* first_hash_ptr = strchr(text, '#'); + char* second_hash_ptr = strrchr(text, '#'); + char* last_char_ptr = strchr(text, '\0') - 1; + //put null byte in lieu of hashes + *first_hash_ptr = '\0'; + *second_hash_ptr = '\0'; + + //now lets deduce the base + unsigned base = (unsigned)strtol(text, 0, 10) ; + + double mantissa = 0.0; + char*ptr = first_hash_ptr + 1; + for( ; ptr != second_hash_ptr ; ++ptr) + { + if(*ptr == '.') + break; + if(*ptr != '_') + { + mantissa = mantissa*base + short_from_hex_char(*ptr); + } + } + double fraction = 0.0; + double factor = 1.0/base; + for(++ptr ; ptr != second_hash_ptr; ++ptr) + { + if(*ptr != '_') + { + fraction = fraction + short_from_hex_char(*ptr)*factor; + factor = factor / base; + } + } + if(last_char_ptr == second_hash_ptr) //there is no exponent + { + return mantissa + fraction; + } + + //now calculate the value of the exponent + double exponent = 0.0; + //leave 'e'/'E' and '+' + ptr = *(second_hash_ptr + 2) == '+' ? second_hash_ptr + 3 : second_hash_ptr + 2; + + for( ; *ptr != '\0'; ++ptr) + { + if(*ptr != '_') + { + exponent = exponent*base + short_from_hex_char(*ptr); + } + } + return pow(mantissa + fraction, exponent); +} + +/** +* This function takes a hexadecimal digit in form of +* a char and returns its litteral value as short +*/ +static unsigned short short_from_hex_char(char ch) +{ + if(ch >= '0' && ch <= '9') + return ch - '0'; + else + return ch - 'a' + 10; +} + +/** +* This function takes a based number in form of +* a C-strings and converts it to a int64_t. +* +* \return new double is returned +*/ +static int64_t make_long_from_based(char* text) { + char* first_hash_ptr = strchr(text, '#'); + char* second_hash_ptr = strrchr(text, '#'); + char* end_ptr = strrchr(text, '\0'); + //now lets deduce the base + *first_hash_ptr = '\0'; + unsigned base = (unsigned)strtol(text, 0, 10) ; + + char *ptr = first_hash_ptr + 1; + int64_t mantissa = 0; + for( ; ptr != second_hash_ptr ; ++ptr) + { + if(*ptr != '_') + { + mantissa = mantissa * base + short_from_hex_char(*ptr); + } + } + //if there is an exponent + if(end_ptr - second_hash_ptr > 1) + { + int64_t exponent = 0L; + + ptr = *(second_hash_ptr + 2) == '+' ? second_hash_ptr + 3 : second_hash_ptr + 2; + for( ; *ptr != '\0'; ++ptr) + { + if(*ptr != '_') + exponent = base*exponent + short_from_hex_char(*ptr); + } + return lpow(mantissa, exponent); + } + else + return mantissa; +} + +/** +* Recursive power function for int64_t +*/ +static int64_t lpow(int64_t left, int64_t right) { + if(right == 0) + return 1; + else + return left*lpow(left, right - 1); } void reset_lexor(FILE*fd, const char*path) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 9c24a65a1..d5f8de0e9 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -20,7 +20,7 @@ */ # include "vhdlpp_config.h" -# include "vhdlnum.h" +# include "vhdlint.h" # include "vhdlreal.h" # include "compiler.h" # include "parse_api.h" @@ -45,7 +45,7 @@ int parse_errors = 0; %union { port_mode_t port_mode; char*text; - vhdlnum* integer; + vhdlint* integer; vhdlreal* real; InterfacePort*interface_element; diff --git a/vhdlpp/parse_wrap.h b/vhdlpp/parse_wrap.h index 2d09ecd62..c5a30e353 100644 --- a/vhdlpp/parse_wrap.h +++ b/vhdlpp/parse_wrap.h @@ -26,7 +26,7 @@ */ # include -# include "vhdlnum.h" +# include "vhdlint.h" # include "vhdlreal.h" # include "parse.h" diff --git a/vhdlpp/vhdlint.cc b/vhdlpp/vhdlint.cc new file mode 100644 index 000000000..e2486b040 --- /dev/null +++ b/vhdlpp/vhdlint.cc @@ -0,0 +1,68 @@ +#include "config.h" +#include "vhdlint.h" +#include +#include +#include + +bool vhdlint::is_negative() const +{ + return value_ < 0L; +} + +bool vhdlint::is_positive() const +{ + return value_ > 0L; +} + +bool vhdlint::is_zero() const +{ + return value_ == 0L; +} + +vhdlint::vhdlint(const char* text) +{ + unsigned text_length = strlen(text); + if(text_length == 0) + { + value_ = 0L; + return; + } + + char* new_text = new char[text_length + 1]; + + const char* ptr; + char* new_ptr; + for(ptr = text, new_ptr = new_text; *ptr != '\0'; ++ptr) + { + if(*ptr == '_') + continue; + else + { + *new_ptr = *ptr; + ++new_ptr; + ++ptr; + } + } + *new_ptr = '\0'; + + istringstream str(new_text); + delete[] new_text; + + //TODO: check if numbers greater than MAX_INT are handled correctly + str >> value_; +} + +vhdlint::vhdlint(const int64_t& val) +{ + value_ = val; +} + +vhdlint::vhdlint(const vhdlint& val) +{ + value_ = val.as_long(); +} + +int64_t vhdlint::as_long() const +{ + return value_; +} \ No newline at end of file diff --git a/vhdlpp/vhdlint.h b/vhdlpp/vhdlint.h new file mode 100644 index 000000000..0ef5ef54a --- /dev/null +++ b/vhdlpp/vhdlint.h @@ -0,0 +1,28 @@ +#ifndef __vhdlint_H +#define __vhdlint_H + +#include "config.h" +#include + +using namespace std; + +class vhdlint +{ + public: + explicit vhdlint(const char* text); + explicit vhdlint(const int64_t& val); + explicit vhdlint(const vhdlint& val); + + bool is_negative() const; + bool is_positive() const; + bool is_zero() const; + + int64_t as_long() const; + //vhdlv get(const unsigned index) const; + //void set(const unsigned index, const unsigned val); + // unsigned short operator[](const unsigned index); + private: + int64_t value_; +}; + +#endif diff --git a/vhdlpp/vhdlreal.cc b/vhdlpp/vhdlreal.cc new file mode 100644 index 000000000..fd903d544 --- /dev/null +++ b/vhdlpp/vhdlreal.cc @@ -0,0 +1,59 @@ +#include "config.h" +#include "compiler.h" +#include "vhdlreal.h" +#include +#include +#include + +vhdlreal::vhdlreal() { + value_ = 0.0; +} + +vhdlreal::vhdlreal(const double& r) { + value_ = r; +} + +vhdlreal::vhdlreal(const vhdlreal& val) { + value_ = val.as_double(); +} + +vhdlreal::vhdlreal(const char* text) { + assert(strlen(text) != 0); + char* buffer = new char[strlen(text)+1]; + + char* buf_ptr; + for(buf_ptr = buffer; *text != 0; ++buf_ptr, ++text) { + if(*text == '_') + continue; + *buf_ptr = *text; + } + *buf_ptr = '\0'; + + value_ = strtod(buffer, NULL); + delete[] buffer; +} + +ostream& operator<< (ostream& str, const vhdlreal& r) { + return (str << r.as_double()); +} +vhdlreal operator+ (const vhdlreal& r1, const vhdlreal& r2) { + return vhdlreal(r1.as_double() + r2.as_double()); +} +vhdlreal operator- (const vhdlreal& r1, const vhdlreal& r2) { + return vhdlreal(r1.as_double() - r2.as_double()); +} +vhdlreal operator* (const vhdlreal& r1, const vhdlreal& r2) { + return vhdlreal(r1.as_double() * r2.as_double()); +} +vhdlreal operator/ (const vhdlreal& r1, const vhdlreal& r2) { + return vhdlreal(r1.as_double() / r2.as_double()); +} +vhdlreal operator% (const vhdlreal& r1, const vhdlreal& r2) { + return vhdlreal(fmod(r1.as_double(), r2.as_double())); +} +vhdlreal pow(const vhdlreal& r1, const vhdlreal& r2) { + return vhdlreal(pow(r1.as_double(), r2.as_double())); +} +vhdlreal operator- (const vhdlreal& r) { + return vhdlreal(-r.as_double()); +} \ No newline at end of file diff --git a/vhdlpp/vhdlreal.h b/vhdlpp/vhdlreal.h index c74263fdd..72c41f101 100644 --- a/vhdlpp/vhdlreal.h +++ b/vhdlpp/vhdlreal.h @@ -2,10 +2,39 @@ #define __vhdlreal_h #include "config.h" +#include +#include -class vhdlreal { - public: - vhdlreal(char* text) {} +using namespace std; +/* +* This class holds a floating point decimal number. The number is +* stored as double. All based numbers are converted by an external +* function to a double and then stored as class instance. +*/ +class vhdlreal +{ +public: + friend ostream& operator<< (ostream&, const vhdlreal&); + friend vhdlreal operator+ (const vhdlreal&, const vhdlreal&); + friend vhdlreal operator- (const vhdlreal&, const vhdlreal&); + friend vhdlreal operator* (const vhdlreal&, const vhdlreal&); + friend vhdlreal operator/ (const vhdlreal&, const vhdlreal&); + friend vhdlreal operator% (const vhdlreal&, const vhdlreal&); + friend vhdlreal pow(const vhdlreal&, const vhdlreal&); + // Unary minus. + friend vhdlreal operator- (const vhdlreal&); + + explicit vhdlreal(); + explicit vhdlreal(const char*text); + explicit vhdlreal(const double& val); + vhdlreal(const vhdlreal& val); + virtual ~vhdlreal() {}; + + double as_double() const + { + return value_; + } +protected: + double value_; }; - -#endif +#endif \ No newline at end of file