*/
"""
-from ply import lex
-
-"""
-%x CCOMMENT
-%x PCOMMENT
-%x LCOMMENT
-%x CSTRING
-%s UDPTABLE
-%x PPTIMESCALE
-%x PPUCDRIVE
-%x PPDEFAULT_NETTYPE
-%x PPBEGIN_KEYWORDS
-%s EDGES
-%x REAL_SCALE
-
-# for timescales (regex subst patterns)
-W = r'[ \t\b\f\r]+'
-S = r'[afpnumkKMGT]'
-TU r'[munpf]'
-
-%%
-
- /* Recognize the various line directives. */
-^"#line"[ \t]+.+ { line_directive(); }
-^[ \t]?"`line"[ \t]+.+ { line_directive2(); }
-
-[ \t\b\f\r] { ; }
-\n { yylloc.first_line += 1; }
-
- /* C++ style comments start with / / and run to the end of the
- current line. These are very easy to handle. The meta-comments
- format is a little more tricky to handle, but do what we can. */
-
- /* The lexor detects "// synthesis translate_on/off" meta-comments,
- we handle them here by turning on/off a flag. The pform uses
- that flag to attach implicit attributes to "initial" and
- "always" statements. */
+lex_debug = 0
-"//"{W}*"synthesis"{W}+"translate_on"{W}*\n { pform_mc_translate_on(true); }
-"//"{W}*"synthesis"{W}+"translate_off"{W}*\n { pform_mc_translate_on(false); }
-"//" { comment_enter = YY_START; BEGIN(LCOMMENT); }
-<LCOMMENT>. { yymore(); }
-<LCOMMENT>\n { yylloc.first_line += 1; BEGIN(comment_enter); }
-
-
- /* The contents of C-style comments are ignored, like white space. */
+from ply import lex
-"/*" { comment_enter = YY_START; BEGIN(CCOMMENT); }
-<CCOMMENT>. { ; }
-<CCOMMENT>\n { yylloc.first_line += 1; }
-<CCOMMENT>"*/" { BEGIN(comment_enter); }
-"""
+#DOCSTRING REMOVED
states = (#('module', 'exclusive'),
('timescale', 'exclusive'),)
'#', '=', '.', '@', '&', '!', '?', '<', '>', '%',
'|', '^', '~', '+', '*', '/', '-']
-"""
- /* Watch out for the tricky case of (*). Cannot parse this as "(*"
- and ")", but since I know that this is really ( * ), replace it
- with "*" and return that. */
-"("{W}*"*"{W}*")" { return '*'; }
-
-<EDGES>"]" { BEGIN(0); return yytext[0]; }
-[}{;:\[\],()#=.@&!?<>%|^~+*/-] { return yytext[0]; }
-
-\" { BEGIN(CSTRING); }
-<CSTRING>\\\\ { yymore(); /* Catch \\, which is a \ escaping itself */ }
-<CSTRING>\\\" { yymore(); /* Catch \", which is an escaped quote */ }
-<CSTRING>\n { BEGIN(0);
- yylval.text = strdupnew(yytext);
- VLerror(yylloc, "Missing close quote of string.");
- yylloc.first_line += 1;
- return STRING; }
-<CSTRING>\" { BEGIN(0);
- yylval.text = strdupnew(yytext);
- yylval.text[strlen(yytext)-1] = 0;
- return STRING; }
-<CSTRING>. { yymore(); }
-
- /* The UDP Table is a unique lexical environment. These are most
- tokens that we can expect in a table. */
-<UDPTABLE>\(\?0\) { return '_'; }
-<UDPTABLE>\(\?1\) { return '+'; }
-<UDPTABLE>\(\?[xX]\) { return '%'; }
-<UDPTABLE>\(\?\?\) { return '*'; }
-<UDPTABLE>\(01\) { return 'r'; }
-<UDPTABLE>\(0[xX]\) { return 'Q'; }
-<UDPTABLE>\(b[xX]\) { return 'q'; }
-<UDPTABLE>\(b0\) { return 'f'; /* b0 is 10|00, but only 10 is meaningful */}
-<UDPTABLE>\(b1\) { return 'r'; /* b1 is 11|01, but only 01 is meaningful */}
-<UDPTABLE>\(0\?\) { return 'P'; }
-<UDPTABLE>\(10\) { return 'f'; }
-<UDPTABLE>\(1[xX]\) { return 'M'; }
-<UDPTABLE>\(1\?\) { return 'N'; }
-<UDPTABLE>\([xX]0\) { return 'F'; }
-<UDPTABLE>\([xX]1\) { return 'R'; }
-<UDPTABLE>\([xX]\?\) { return 'B'; }
-<UDPTABLE>[bB] { return 'b'; }
-<UDPTABLE>[lL] { return 'l'; /* IVL extension */ }
-<UDPTABLE>[hH] { return 'h'; /* IVL extension */ }
-<UDPTABLE>[fF] { return 'f'; }
-<UDPTABLE>[rR] { return 'r'; }
-<UDPTABLE>[xX] { return 'x'; }
-<UDPTABLE>[nN] { return 'n'; }
-<UDPTABLE>[pP] { return 'p'; }
-<UDPTABLE>[01\?\*\-:;] { return yytext[0]; }
-
-<EDGES>"01" { return K_edge_descriptor; }
-<EDGES>"0x" { return K_edge_descriptor; }
-<EDGES>"0z" { return K_edge_descriptor; }
-<EDGES>"10" { return K_edge_descriptor; }
-<EDGES>"1x" { return K_edge_descriptor; }
-<EDGES>"1z" { return K_edge_descriptor; }
-<EDGES>"x0" { return K_edge_descriptor; }
-<EDGES>"x1" { return K_edge_descriptor; }
-<EDGES>"z0" { return K_edge_descriptor; }
-<EDGES>"z1" { return K_edge_descriptor; }
-"""
-
"""
def t_module_end(t):
r'endmodule'
"""
def t_LITERAL(t):
- r'[a-zA-Z_][a-zA-Z0-9$_]*'
+ r'[a-zA-Z_$][a-zA-Z0-9$_]*'
word = t.value
- print ("literal", word)
keyword = lexor_keyword_code.get(t.value, 'IDENTIFIER')
+ if(lex_debug): print ("literal", word,keyword)
#if keyword in ['K_module', 'K_macromodule']:
# t.lexer.modulestart = t.lexpos+len(t.value)
# t.lexer.begin('module')
if keyword == 'IDENTIFIER':
t.type = 'IDENTIFIER'
- t.value = keyword
+ t.value = word
return t
t.type = keyword
return t
-"""
- switch (rc) {
- case IDENTIFIER:
- yylval.text = strdupnew(yytext);
- if (strncmp(yylval.text,"PATHPULSE$", 10) == 0)
- rc = PATHPULSE_IDENTIFIER;
- break;
-
- case K_edge:
- BEGIN(EDGES);
- break;
-
- case K_primitive:
- in_UDP = true;
- break;
-
- case K_endprimitive:
- in_UDP = false;
- break;
-
- case K_table:
- BEGIN(UDPTABLE);
- break;
-
- default:
- yylval.text = 0;
- break;
- }
-
- /* Special case: If this is part of a scoped name, then check
- the package for identifier details. For example, if the
- source file is foo::bar, the parse.y will note the
- PACKAGE_IDENTIFIER and "::" token and mark the
- "in_package_scope" variable. Then this lexor will see the
- identifier here and interpret it in the package scope. */
- if (in_package_scope) {
- if (rc == IDENTIFIER) {
- if (data_type_t*type = pform_test_type_identifier(in_package_scope, yylval.text)) {
- yylval.type_identifier.text = yylval.text;
- yylval.type_identifier.type = type;
- rc = TYPE_IDENTIFIER;
- }
- }
- in_package_scope = 0;
- return rc;
- }
-
- /* If this identifier names a discipline, then return this as
- a DISCIPLINE_IDENTIFIER and return the discipline as the
- value instead. */
- if (rc == IDENTIFIER && gn_verilog_ams_flag) {
- perm_string tmp = lex_strings.make(yylval.text);
- map<perm_string,ivl_discipline_t>::iterator cur = disciplines.find(tmp);
- if (cur != disciplines.end()) {
- delete[]yylval.text;
- yylval.discipline = (*cur).second;
- rc = DISCIPLINE_IDENTIFIER;
- }
- }
-
- /* If this identifier names a previously declared package, then
- return this as a PACKAGE_IDENTIFIER instead. */
- if (rc == IDENTIFIER && gn_system_verilog()) {
- if (PPackage*pkg = pform_test_package_identifier(yylval.text)) {
- delete[]yylval.text;
- yylval.package = pkg;
- rc = PACKAGE_IDENTIFIER;
- }
- }
-
- /* If this identifier names a previously declared type, then
- return this as a TYPE_IDENTIFIER instead. */
- if (rc == IDENTIFIER && gn_system_verilog()) {
- if (data_type_t*type = pform_test_type_identifier(yylval.text)) {
- yylval.type_identifier.text = yylval.text;
- yylval.type_identifier.type = type;
- rc = TYPE_IDENTIFIER;
- }
- }
-
- return rc;
- }
-"""
-
-"""
-\\[^ \t\b\f\r\n]+ {
- yylval.text = strdupnew(yytext+1);
- if (gn_system_verilog()) {
- if (PPackage*pkg = pform_test_package_identifier(yylval.text)) {
- delete[]yylval.text;
- yylval.package = pkg;
- return PACKAGE_IDENTIFIER;
- }
- }
- if (gn_system_verilog()) {
- if (data_type_t*type = pform_test_type_identifier(yylval.text)) {
- yylval.type_identifier.text = yylval.text;
- yylval.type_identifier.type = type;
- return TYPE_IDENTIFIER;
- }
- }
- return IDENTIFIER;
- }
-
-\$([a-zA-Z0-9$_]+) {
- /* The 1364-1995 timing checks. */
- if (strcmp(yytext,"$hold") == 0)
- return K_Shold;
- if (strcmp(yytext,"$nochange") == 0)
- return K_Snochange;
- if (strcmp(yytext,"$period") == 0)
- return K_Speriod;
- if (strcmp(yytext,"$recovery") == 0)
- return K_Srecovery;
- if (strcmp(yytext,"$setup") == 0)
- return K_Ssetup;
- if (strcmp(yytext,"$setuphold") == 0)
- return K_Ssetuphold;
- if (strcmp(yytext,"$skew") == 0)
- return K_Sskew;
- if (strcmp(yytext,"$width") == 0)
- return K_Swidth;
- /* The new 1364-2001 timing checks. */
- if (strcmp(yytext,"$fullskew") == 0)
- return K_Sfullskew;
- if (strcmp(yytext,"$recrem") == 0)
- return K_Srecrem;
- if (strcmp(yytext,"$removal") == 0)
- return K_Sremoval;
- if (strcmp(yytext,"$timeskew") == 0)
- return K_Stimeskew;
-
- if (strcmp(yytext,"$attribute") == 0)
- return KK_attribute;
-
- if (gn_system_verilog() && strcmp(yytext,"$unit") == 0) {
- yylval.package = pform_units.back();
- return PACKAGE_IDENTIFIER;
- }
-
- yylval.text = strdupnew(yytext);
- return SYSTEM_IDENTIFIER; }
-"""
-
def t_dec_number(t):
r'\'[sS]?[dD][ \t]*[0-9][0-9_]*'
t.type = 'BASED_NUMBER'
mode, where there are no decimal numbers. Reject the match if we
are in the UDPTABLE state. */
"""
-"""
- if (YY_START==UDPTABLE) {
- REJECT;
- } else {
-"""
def t_make_unsized_dec(t):
r'[0-9][0-9_]*'
t.type = 'DEC_NUMBER'
t.type = 'timescale'
t.value = code
t.lexer.pop_state()
- print "match", code
+ print ("match", code)
return t
-"""
-<PPTIMESCALE>.* { process_timescale(yytext); }
-<PPTIMESCALE>\n {
- if (in_module) {
- cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
- "`timescale directive can not be inside a module "
- "definition." << endl;
- error_count += 1;
- }
- yylloc.first_line += 1;
- BEGIN(0); }
-"""
-
-"""
-
- /* This rule handles scaled time values for SystemVerilog. */
-[0-9][0-9_]*(\.[0-9][0-9_]*)?{TU}?s {
- if (gn_system_verilog()) {
- yylval.text = strdupnew(yytext);
- return TIME_LITERAL;
- } else REJECT; }
-
- /* These rules handle the scaled real literals from Verilog-AMS. The
- value is a number with a single letter scale factor. If
- verilog-ams is not enabled, then reject this rule. If it is
- enabled, then collect the scale and use it to scale the value. */
-[0-9][0-9_]*\.[0-9][0-9_]*/{S} {
- if (!gn_verilog_ams_flag) REJECT;
- BEGIN(REAL_SCALE);
- yymore(); }
-
-[0-9][0-9_]*/{S} {
- if (!gn_verilog_ams_flag) REJECT;
- BEGIN(REAL_SCALE);
- yymore(); }
-
-<REAL_SCALE>{S} {
- size_t token_len = strlen(yytext);
- char*tmp = new char[token_len + 5];
- int scale = 0;
- strcpy(tmp, yytext);
- switch (tmp[token_len-1]) {
- case 'a': scale = -18; break; /* atto- */
- case 'f': scale = -15; break; /* femto- */
- case 'p': scale = -12; break; /* pico- */
- case 'n': scale = -9; break; /* nano- */
- case 'u': scale = -6; break; /* micro- */
- case 'm': scale = -3; break; /* milli- */
- case 'k': scale = 3; break; /* kilo- */
- case 'K': scale = 3; break; /* kilo- */
- case 'M': scale = 6; break; /* mega- */
- case 'G': scale = 9; break; /* giga- */
- case 'T': scale = 12; break; /* tera- */
- default: assert(0); break;
- }
- snprintf(tmp+token_len-1, 5, "e%d", scale);
- yylval.realtime = new verireal(tmp);
- delete[]tmp;
-
- BEGIN(0);
- return REALTIME; }
-
-[0-9][0-9_]*\.[0-9][0-9_]*([Ee][+-]?[0-9][0-9_]*)? {
- yylval.realtime = new verireal(yytext);
- return REALTIME; }
-
-[0-9][0-9_]*[Ee][+-]?[0-9][0-9_]* {
- yylval.realtime = new verireal(yytext);
- return REALTIME; }
-
-
- /* Notice and handle the `celldefine and `endcelldefine directives. */
-
-^{W}?`celldefine{W}? { in_celldefine = true; }
-^{W}?`endcelldefine{W}? { in_celldefine = false; }
-
- /* Notice and handle the resetall directive. */
-
-^{W}?`resetall{W}? {
- if (in_module) {
- cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
- "`resetall directive can not be inside a module "
- "definition." << endl;
- error_count += 1;
- } else if (in_UDP) {
- cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
- "`resetall directive can not be inside a UDP "
- "definition." << endl;
- error_count += 1;
- } else {
- reset_all();
- } }
-
- /* Notice and handle the `unconnected_drive directive. */
-^{W}?`unconnected_drive { BEGIN(PPUCDRIVE); }
-<PPUCDRIVE>.* { process_ucdrive(yytext); }
-<PPUCDRIVE>\n {
- if (in_module) {
- cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
- "`unconnected_drive directive can not be inside a "
- "module definition." << endl;
- error_count += 1;
- }
- yylloc.first_line += 1;
- BEGIN(0); }
-
-^{W}?`nounconnected_drive{W}? {
- if (in_module) {
- cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
- "`nounconnected_drive directive can not be inside a "
- "module definition." << endl;
- error_count += 1;
- }
- uc_drive = UCD_NONE; }
-
- /* These are directives that I do not yet support. I think that IVL
- should handle these, not an external preprocessor. */
- /* From 1364-2005 Chapter 19. */
-^{W}?`pragme{W}?.* { }
-
- /* From 1364-2005 Annex D. */
-^{W}?`default_decay_time{W}?.* { }
-^{W}?`default_trireg_strength{W}?.* { }
-^{W}?`delay_mode_distributed{W}?.* { }
-^{W}?`delay_mode_path{W}?.* { }
-^{W}?`delay_mode_unit{W}?.* { }
-^{W}?`delay_mode_zero{W}?.* { }
-
- /* From other places. */
-^{W}?`disable_portfaults{W}?.* { }
-^{W}?`enable_portfaults{W}?.* { }
-`endprotect { }
-^{W}?`nosuppress_faults{W}?.* { }
-`protect { }
-^{W}?`suppress_faults{W}?.* { }
-^{W}?`uselib{W}?.* { }
-
-^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); }
-
-<PPBEGIN_KEYWORDS>\"[a-zA-Z0-9 -\.]*\".* {
- keyword_mask_stack.push_front(lexor_keyword_mask);
-
- char*word = yytext+1;
- char*tail = strchr(word, '"');
- tail[0] = 0;
- if (strcmp(word,"1364-1995") == 0) {
- lexor_keyword_mask = GN_KEYWORDS_1364_1995;
- } else if (strcmp(word,"1364-2001") == 0) {
- lexor_keyword_mask = GN_KEYWORDS_1364_1995
- |GN_KEYWORDS_1364_2001
- |GN_KEYWORDS_1364_2001_CONFIG;
- } else if (strcmp(word,"1364-2001-noconfig") == 0) {
- lexor_keyword_mask = GN_KEYWORDS_1364_1995
- |GN_KEYWORDS_1364_2001;
- } else if (strcmp(word,"1364-2005") == 0) {
- lexor_keyword_mask = GN_KEYWORDS_1364_1995
- |GN_KEYWORDS_1364_2001
- |GN_KEYWORDS_1364_2001_CONFIG
- |GN_KEYWORDS_1364_2005;
- } else if (strcmp(word,"1800-2005") == 0) {
- lexor_keyword_mask = GN_KEYWORDS_1364_1995
- |GN_KEYWORDS_1364_2001
- |GN_KEYWORDS_1364_2001_CONFIG
- |GN_KEYWORDS_1364_2005
- |GN_KEYWORDS_1800_2005;
- } else if (strcmp(word,"1800-2009") == 0) {
- lexor_keyword_mask = GN_KEYWORDS_1364_1995
- |GN_KEYWORDS_1364_2001
- |GN_KEYWORDS_1364_2001_CONFIG
- |GN_KEYWORDS_1364_2005
- |GN_KEYWORDS_1800_2005
- |GN_KEYWORDS_1800_2009;
- } else if (strcmp(word,"1800-2012") == 0) {
- lexor_keyword_mask = GN_KEYWORDS_1364_1995
- |GN_KEYWORDS_1364_2001
- |GN_KEYWORDS_1364_2001_CONFIG
- |GN_KEYWORDS_1364_2005
- |GN_KEYWORDS_1800_2005
- |GN_KEYWORDS_1800_2009
- |GN_KEYWORDS_1800_2012;
- } else if (strcmp(word,"VAMS-2.3") == 0) {
- lexor_keyword_mask = GN_KEYWORDS_1364_1995
- |GN_KEYWORDS_1364_2001
- |GN_KEYWORDS_1364_2001_CONFIG
- |GN_KEYWORDS_1364_2005
- |GN_KEYWORDS_VAMS_2_3;
- } else {
- fprintf(stderr, "%s:%d: Ignoring unknown keywords string: %s\n",
- yylloc.text, yylloc.first_line, word);
- }
- BEGIN(0);
- }
-
-<PPBEGIN_KEYWORDS>.* {
- fprintf(stderr, "%s:%d: Malformed keywords specification: %s\n",
- yylloc.text, yylloc.first_line, yytext);
- BEGIN(0);
- }
-
-^{W}?`end_keywords{W}?.* {
- if (!keyword_mask_stack.empty()) {
- lexor_keyword_mask = keyword_mask_stack.front();
- keyword_mask_stack.pop_front();
- } else {
- fprintf(stderr, "%s:%d: Mismatched end_keywords directive\n",
- yylloc.text, yylloc.first_line);
- }
- }
-
- /* Notice and handle the default_nettype directive. The lexor
- detects the default_nettype keyword, and the second part of the
- rule collects the rest of the line and processes it. We only need
- to look for the first work, and interpret it. */
-
-`default_nettype{W}? { BEGIN(PPDEFAULT_NETTYPE); }
-<PPDEFAULT_NETTYPE>.* {
- NetNet::Type net_type;
- size_t wordlen = strcspn(yytext, " \t\f\r\n");
- yytext[wordlen] = 0;
- /* Add support for other wire types and better error detection. */
- if (strcmp(yytext,"wire") == 0) {
- net_type = NetNet::WIRE;
-
- } else if (strcmp(yytext,"tri") == 0) {
- net_type = NetNet::TRI;
-
- } else if (strcmp(yytext,"tri0") == 0) {
- net_type = NetNet::TRI0;
-
- } else if (strcmp(yytext,"tri1") == 0) {
- net_type = NetNet::TRI1;
-
- } else if (strcmp(yytext,"wand") == 0) {
- net_type = NetNet::WAND;
-
- } else if (strcmp(yytext,"triand") == 0) {
- net_type = NetNet::TRIAND;
-
- } else if (strcmp(yytext,"wor") == 0) {
- net_type = NetNet::WOR;
-
- } else if (strcmp(yytext,"trior") == 0) {
- net_type = NetNet::TRIOR;
-
- } else if (strcmp(yytext,"none") == 0) {
- net_type = NetNet::NONE;
-
- } else {
- cerr << yylloc.text << ":" << yylloc.first_line
- << ": error: Net type " << yytext
- << " is not a valid (or supported)"
- << " default net type." << endl;
- net_type = NetNet::WIRE;
- error_count += 1;
- }
- pform_set_default_nettype(net_type, yylloc.text, yylloc.first_line);
- }
-<PPDEFAULT_NETTYPE>\n {
- yylloc.first_line += 1;
- BEGIN(0); }
-
-
- /* These are directives that are not supported by me and should have
- been handled by an external preprocessor such as ivlpp. */
-
-^{W}?`define{W}?.* {
- cerr << yylloc.text << ":" << yylloc.first_line <<
- ": warning: `define not supported. Use an external preprocessor."
- << endl;
- }
-
-^{W}?`else{W}?.* {
- cerr << yylloc.text << ":" << yylloc.first_line <<
- ": warning: `else not supported. Use an external preprocessor."
- << endl;
- }
-
-^{W}?`elsif{W}?.* {
- cerr << yylloc.text << ":" << yylloc.first_line <<
- ": warning: `elsif not supported. Use an external preprocessor."
- << endl;
- }
-
-^{W}?`endif{W}?.* {
- cerr << yylloc.text << ":" << yylloc.first_line <<
- ": warning: `endif not supported. Use an external preprocessor."
- << endl;
- }
-
-^{W}?`ifdef{W}?.* {
- cerr << yylloc.text << ":" << yylloc.first_line <<
- ": warning: `ifdef not supported. Use an external preprocessor."
- << endl;
- }
-
-^{W}?`ifndef{W}?.* {
- cerr << yylloc.text << ":" << yylloc.first_line <<
- ": warning: `ifndef not supported. Use an external preprocessor."
- << endl;
- }
-
-^`include{W}?.* {
- cerr << yylloc.text << ":" << yylloc.first_line <<
- ": warning: `include not supported. Use an external preprocessor."
- << endl;
- }
-
-^`undef{W}?.* {
- cerr << yylloc.text << ":" << yylloc.first_line <<
- ": warning: `undef not supported. Use an external preprocessor."
- << endl;
- }
-
-
-`{W} { cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
- << "Stray tic (`) here. Perhaps you put white space" << endl;
- cerr << yylloc.text << ":" << yylloc.first_line << ": : "
- << "between the tic and preprocessor directive?"
- << endl;
- error_count += 1; }
-
-. { return yytext[0]; }
-
- /* Final catchall. something got lost or mishandled. */
- /* XXX Should we tell the user something about the lexical state? */
-
-<*>.|\n { cerr << yylloc.text << ":" << yylloc.first_line
- << ": error: unmatched character (";
- if (isprint(yytext[0]))
- cerr << yytext[0];
- else
- cerr << "hex " << hex << ((unsigned char) yytext[0]);
-
- cerr << ")" << endl;
- error_count += 1; }
-
-%%
-
-/*
- * The UDP state table needs some slightly different treatment by the
- * lexor. The level characters are normally accepted as other things,
- * so the parser needs to switch my mode when it believes in needs to.
- */
-void lex_end_table()
-{
- BEGIN(INITIAL);
-}
-
-static unsigned truncate_to_integer_width(verinum::V*bits, unsigned size)
-{
- if (size <= integer_width) return size;
-
- verinum::V pad = bits[size-1];
- if (pad == verinum::V1) pad = verinum::V0;
-
- for (unsigned idx = integer_width; idx < size; idx += 1) {
- if (bits[idx] != pad) {
- yywarn(yylloc, "Unsized numeric constant truncated to integer width.");
- break;
- }
- }
- return integer_width;
-}
-
-verinum*make_unsized_binary(const char*txt)
-{
- bool sign_flag = false;
- bool single_flag = false;
- const char*ptr = txt;
- assert(*ptr == '\'');
- ptr += 1;
-
- if (tolower(*ptr) == 's') {
- sign_flag = true;
- ptr += 1;
- }
-
- assert((tolower(*ptr) == 'b') || gn_system_verilog());
- if (tolower(*ptr) == 'b') {
- ptr += 1;
- } else {
- assert(sign_flag == false);
- single_flag = true;
- }
-
- while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
- ptr += 1;
-
- unsigned size = 0;
- for (const char*idx = ptr ; *idx ; idx += 1)
- if (*idx != '_') size += 1;
-
- if (size == 0) {
- VLerror(yylloc, "Numeric literal has no digits in it.");
- verinum*out = new verinum();
- out->has_sign(sign_flag);
- out->is_single(single_flag);
- return out;
- }
-
- if ((based_size > 0) && (size > based_size)) yywarn(yylloc,
- "extra digits given for sized binary constant.");
-
- verinum::V*bits = new verinum::V[size];
-
- unsigned idx = size;
- while (*ptr) {
- switch (ptr[0]) {
- case '0':
- bits[--idx] = verinum::V0;
- break;
- case '1':
- bits[--idx] = verinum::V1;
- break;
- case 'z': case 'Z': case '?':
- bits[--idx] = verinum::Vz;
- break;
- case 'x': case 'X':
- bits[--idx] = verinum::Vx;
- break;
- case '_':
- break;
- default:
- fprintf(stderr, "%c\n", ptr[0]);
- assert(0);
- }
- ptr += 1;
- }
-
- if (gn_strict_expr_width_flag && (based_size == 0))
- size = truncate_to_integer_width(bits, size);
-
- verinum*out = new verinum(bits, size, false);
- out->has_sign(sign_flag);
- out->is_single(single_flag);
- delete[]bits;
- return out;
-}
-
-
-verinum*make_unsized_octal(const char*txt)
-{
- bool sign_flag = false;
- const char*ptr = txt;
- assert(*ptr == '\'');
- ptr += 1;
-
- if (tolower(*ptr) == 's') {
- sign_flag = true;
- ptr += 1;
- }
-
- assert(tolower(*ptr) == 'o');
- ptr += 1;
-
- while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
- ptr += 1;
-
- unsigned size = 0;
- for (const char*idx = ptr ; *idx ; idx += 1)
- if (*idx != '_') size += 3;
-
- if (based_size > 0) {
- int rem = based_size % 3;
- if (rem != 0) based_size += 3 - rem;
- if (size > based_size) yywarn(yylloc,
- "extra digits given for sized octal constant.");
- }
-
- verinum::V*bits = new verinum::V[size];
-
- unsigned idx = size;
- while (*ptr) {
- unsigned val;
- switch (ptr[0]) {
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- val = *ptr - '0';
- bits[--idx] = (val&4) ? verinum::V1 : verinum::V0;
- bits[--idx] = (val&2) ? verinum::V1 : verinum::V0;
- bits[--idx] = (val&1) ? verinum::V1 : verinum::V0;
- break;
- case 'x': case 'X':
- bits[--idx] = verinum::Vx;
- bits[--idx] = verinum::Vx;
- bits[--idx] = verinum::Vx;
- break;
- case 'z': case 'Z': case '?':
- bits[--idx] = verinum::Vz;
- bits[--idx] = verinum::Vz;
- bits[--idx] = verinum::Vz;
- break;
- case '_':
- break;
- default:
- assert(0);
- }
- ptr += 1;
- }
-
- if (gn_strict_expr_width_flag && (based_size == 0))
- size = truncate_to_integer_width(bits, size);
-
- verinum*out = new verinum(bits, size, false);
- out->has_sign(sign_flag);
- delete[]bits;
- return out;
-}
-
-
-verinum*make_unsized_hex(const char*txt)
-{
- bool sign_flag = false;
- const char*ptr = txt;
- assert(*ptr == '\'');
- ptr += 1;
-
- if (tolower(*ptr) == 's') {
- sign_flag = true;
- ptr += 1;
- }
- assert(tolower(*ptr) == 'h');
-
- ptr += 1;
- while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
- ptr += 1;
-
- unsigned size = 0;
- for (const char*idx = ptr ; *idx ; idx += 1)
- if (*idx != '_') size += 4;
-
- if (based_size > 0) {
- int rem = based_size % 4;
- if (rem != 0) based_size += 4 - rem;
- if (size > based_size) yywarn(yylloc,
- "extra digits given for sized hex constant.");
- }
-
- verinum::V*bits = new verinum::V[size];
-
- unsigned idx = size;
- while (*ptr) {
- unsigned val;
- switch (ptr[0]) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- val = *ptr - '0';
- bits[--idx] = (val&8) ? verinum::V1 : verinum::V0;
- bits[--idx] = (val&4) ? verinum::V1 : verinum::V0;
- bits[--idx] = (val&2) ? verinum::V1 : verinum::V0;
- bits[--idx] = (val&1) ? verinum::V1 : verinum::V0;
- break;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- val = tolower(*ptr) - 'a' + 10;
- bits[--idx] = (val&8) ? verinum::V1 : verinum::V0;
- bits[--idx] = (val&4) ? verinum::V1 : verinum::V0;
- bits[--idx] = (val&2) ? verinum::V1 : verinum::V0;
- bits[--idx] = (val&1) ? verinum::V1 : verinum::V0;
- break;
- case 'x': case 'X':
- bits[--idx] = verinum::Vx;
- bits[--idx] = verinum::Vx;
- bits[--idx] = verinum::Vx;
- bits[--idx] = verinum::Vx;
- break;
- case 'z': case 'Z': case '?':
- bits[--idx] = verinum::Vz;
- bits[--idx] = verinum::Vz;
- bits[--idx] = verinum::Vz;
- bits[--idx] = verinum::Vz;
- break;
- case '_':
- break;
- default:
- assert(0);
- }
- ptr += 1;
- }
-
- if (gn_strict_expr_width_flag && (based_size == 0))
- size = truncate_to_integer_width(bits, size);
-
- verinum*out = new verinum(bits, size, false);
- out->has_sign(sign_flag);
- delete[]bits;
- return out;
-}
-
-
-/* Divide the integer given by the string by 2. Return the remainder bit. */
-static int dec_buf_div2(char *buf)
-{
- int partial;
- int len = strlen(buf);
- char *dst_ptr;
- int pos;
-
- partial = 0;
- pos = 0;
-
- /* dst_ptr overwrites buf, but all characters that are overwritten
- were already used by the reader. */
- dst_ptr = buf;
-
- while(buf[pos] == '0')
- ++pos;
-
- for(; pos<len; ++pos){
- if (buf[pos]=='_')
- continue;
-
- assert(isdigit(buf[pos]));
-
- partial= partial*10 + (buf[pos]-'0');
-
- if (partial >= 2){
- *dst_ptr = partial/2 + '0';
- partial = partial & 1;
-
- ++dst_ptr;
- }
- else{
- *dst_ptr = '0';
- ++dst_ptr;
- }
- }
-
- // If result of division was zero string, it should remain that way.
- // Don't eat the last zero...
- if (dst_ptr == buf){
- *dst_ptr = '0';
- ++dst_ptr;
- }
- *dst_ptr = 0;
-
- return partial;
-}
-
-/* Support a single x, z or ? as a decimal constant (from 1364-2005). */
-verinum* make_undef_highz_dec(const char* ptr)
-{
- bool signed_flag = false;
-
- assert(*ptr == '\'');
- /* The number may have decorations of the form 'sd<code>,
- possibly with space between the d and the <code>.
- Also, the 's' is optional, and marks the number as signed. */
- ptr += 1;
-
- if (tolower(*ptr) == 's') {
- signed_flag = true;
- ptr += 1;
- }
-
- assert(tolower(*ptr) == 'd');
- ptr += 1;
-
- while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
- ptr += 1;
-
- /* Process the code. */
- verinum::V* bits = new verinum::V[1];
- switch (*ptr) {
- case 'x':
- case 'X':
- bits[0] = verinum::Vx;
- break;
- case 'z':
- case 'Z':
- case '?':
- bits[0] = verinum::Vz;
- break;
- default:
- assert(0);
- }
- ptr += 1;
- while (*ptr == '_') ptr += 1;
- assert(*ptr == 0);
-
- verinum*out = new verinum(bits, 1, false);
- out->has_sign(signed_flag);
- delete[]bits;
- return out;
-}
-
-/*
- * Making a decimal number is much easier than the other base numbers
- * because there are no z or x values to worry about. It is much
- * harder than other base numbers because the width needed in bits is
- * hard to calculate.
- */
-
-verinum*make_unsized_dec(const char*ptr)
-{
- char buf[4096];
- bool signed_flag = false;
- unsigned idx;
-
- if (ptr[0] == '\'') {
- /* The number has decorations of the form 'sd<digits>,
- possibly with space between the d and the <digits>.
- Also, the 's' is optional, and marks the number as
- signed. */
- ptr += 1;
-
- if (tolower(*ptr) == 's') {
- signed_flag = true;
- ptr += 1;
- }
-
- assert(tolower(*ptr) == 'd');
- ptr += 1;
-
- while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
- ptr += 1;
-
- } else {
- /* ... or an undecorated decimal number is passed
- it. These numbers are treated as signed decimal. */
- assert(isdigit(*ptr));
- signed_flag = true;
- }
-
-
- /* Copy the digits into a buffer that I can use to do in-place
- decimal divides. */
- idx = 0;
- while ((idx < sizeof buf) && (*ptr != 0)) {
- if (*ptr == '_') {
- ptr += 1;
- continue;
- }
-
- buf[idx++] = *ptr++;
- }
-
- if (idx == sizeof buf) {
- fprintf(stderr, "Ridiculously long"
- " decimal constant will be truncated!\n");
- idx -= 1;
- }
-
- buf[idx] = 0;
- unsigned tmp_size = idx * 4 + 1;
- verinum::V *bits = new verinum::V[tmp_size];
-
- idx = 0;
- while (idx < tmp_size) {
- int rem = dec_buf_div2(buf);
- bits[idx++] = (rem == 1) ? verinum::V1 : verinum::V0;
- }
-
- assert(strcmp(buf, "0") == 0);
-
- /* Now calculate the minimum number of bits needed to
- represent this unsigned number. */
- unsigned size = tmp_size;
- while ((size > 1) && (bits[size-1] == verinum::V0))
- size -= 1;
-
- /* Now account for the signedness. Don't leave a 1 in the high
- bit if this is a signed number. */
- if (signed_flag && (bits[size-1] == verinum::V1)) {
- size += 1;
- assert(size <= tmp_size);
- }
-
- /* Since we never have the real number of bits that a decimal
- number represents we do not check for extra bits. */
-// if (based_size > 0) { }
-
- if (gn_strict_expr_width_flag && (based_size == 0))
- size = truncate_to_integer_width(bits, size);
-
- verinum*res = new verinum(bits, size, false);
- res->has_sign(signed_flag);
-
- delete[]bits;
- return res;
-}
-
-/*
- * Convert the string to a time unit or precision.
- * Returns true on failure.
- */
-static bool get_timescale_const(const char *&cp, int &res, bool is_unit)
-{
- /* Check for the 1 digit. */
- if (*cp != '1') {
- if (is_unit) {
- VLerror(yylloc, "Invalid `timescale unit constant "
- "(1st digit)");
- } else {
- VLerror(yylloc, "Invalid `timescale precision constant "
- "(1st digit)");
- }
- return true;
- }
- cp += 1;
-
- /* Check the number of zeros after the 1. */
- res = strspn(cp, "0");
- if (res > 2) {
- if (is_unit) {
- VLerror(yylloc, "Invalid `timescale unit constant "
- "(number of zeros)");
- } else {
- VLerror(yylloc, "Invalid `timescale precision constant "
- "(number of zeros)");
- }
- return true;
- }
- cp += res;
-
- /* Skip any space between the digits and the scaling string. */
- cp += strspn(cp, " \t");
-
- /* Now process the scaling string. */
- if (strncmp("s", cp, 1) == 0) {
- res -= 0;
- cp += 1;
- return false;
-
- } else if (strncmp("ms", cp, 2) == 0) {
- res -= 3;
- cp += 2;
- return false;
-
- } else if (strncmp("us", cp, 2) == 0) {
- res -= 6;
- cp += 2;
- return false;
-
- } else if (strncmp("ns", cp, 2) == 0) {
- res -= 9;
- cp += 2;
- return false;
-
- } else if (strncmp("ps", cp, 2) == 0) {
- res -= 12;
- cp += 2;
- return false;
-
- } else if (strncmp("fs", cp, 2) == 0) {
- res -= 15;
- cp += 2;
- return false;
-
- }
-
- if (is_unit) {
- VLerror(yylloc, "Invalid `timescale unit scale");
- } else {
- VLerror(yylloc, "Invalid `timescale precision scale");
- }
- return true;
-}
-
-
-/*
- * process either a pull0 or a pull1.
- */
-static void process_ucdrive(const char*txt)
-{
- UCDriveType ucd = UCD_NONE;
- const char*cp = txt + strspn(txt, " \t");
-
- /* Skip the space after the `unconnected_drive directive. */
- if (cp == txt) {
- VLerror(yylloc, "Space required after `unconnected_drive "
- "directive.");
- return;
- }
-
- /* Check for the pull keyword. */
- if (strncmp("pull", cp, 4) != 0) {
- VLerror(yylloc, "pull required for `unconnected_drive "
- "directive.");
- return;
- }
- cp += 4;
- if (*cp == '0') ucd = UCD_PULL0;
- else if (*cp == '1') ucd = UCD_PULL1;
- else {
- cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
- "`unconnected_drive does not support 'pull" << *cp
- << "'." << endl;
- error_count += 1;
- return;
- }
- cp += 1;
-
- /* Verify that only space and/or a single line comment is left. */
- cp += strspn(cp, " \t");
- if (strncmp(cp, "//", 2) != 0 &&
- (size_t)(cp-yytext) != strlen(yytext)) {
- VLerror(yylloc, "Invalid `unconnected_drive directive (extra "
- "garbage after precision).");
- return;
- }
-
- uc_drive = ucd;
-}
-
-/*
- * The timescale parameter has the form:
- * " <num> xs / <num> xs"
- */
-static void process_timescale(const char*txt)
-{
- const char*cp = txt + strspn(txt, " \t");
-
- /* Skip the space after the `timescale directive. */
- if (cp == txt) {
- VLerror(yylloc, "Space required after `timescale directive.");
- return;
- }
-
- int unit = 0;
- int prec = 0;
-
- /* Get the time units. */
- if (get_timescale_const(cp, unit, true)) return;
-
- /* Skip any space after the time units, the '/' and any
- * space after the '/'. */
- cp += strspn(cp, " \t");
- if (*cp != '/') {
- VLerror(yylloc, "`timescale separator '/' appears to be missing.");
- return;
- }
- cp += 1;
- cp += strspn(cp, " \t");
-
- /* Get the time precision. */
- if (get_timescale_const(cp, prec, false)) return;
-
- /* Verify that only space and/or a single line comment is left. */
- cp += strspn(cp, " \t");
- if (strncmp(cp, "//", 2) != 0 &&
- (size_t)(cp-yytext) != strlen(yytext)) {
- VLerror(yylloc, "Invalid `timescale directive (extra garbage "
- "after precision).");
- return;
- }
-
- /* The time unit must be greater than or equal to the precision. */
- if (unit < prec) {
- VLerror(yylloc, "error: `timescale unit must not be less than "
- "the precision.");
- return;
- }
-
- pform_set_timescale(unit, prec, yylloc.text, yylloc.first_line);
-}
-
-int yywrap()
-{
- return 1;
-}
-
-/*
- * The line directive matches lines of the form #line "foo" N and
- * calls this function. Here I parse out the file name and line
- * number, and change the yylloc to suite.
- */
-static void line_directive()
-{
- char *cpr;
- /* Skip any leading space. */
- char *cp = strchr(yytext, '#');
- /* Skip the #line directive. */
- assert(strncmp(cp, "#line", 5) == 0);
- cp += 5;
- /* Skip the space after the #line directive. */
- cp += strspn(cp, " \t");
-
- /* Find the starting " and skip it. */
- char*fn_start = strchr(cp, '"');
- if (cp != fn_start) {
- VLerror(yylloc, "Invalid #line directive (file name start).");
- return;
- }
- fn_start += 1;
-
- /* Find the last ". */
- char*fn_end = strrchr(fn_start, '"');
- if (!fn_end) {
- VLerror(yylloc, "Invalid #line directive (file name end).");
- return;
- }
-
- /* Copy the file name and assign it to yylloc. */
- char*buf = new char[fn_end-fn_start+1];
- strncpy(buf, fn_start, fn_end-fn_start);
- buf[fn_end-fn_start] = 0;
-
- /* Skip the space after the file name. */
- cp = fn_end;
- cp += 1;
- cpr = cp;
- cpr += strspn(cp, " \t");
- if (cp == cpr) {
- VLerror(yylloc, "Invalid #line directive (missing space after "
- "file name).");
- delete[] buf;
- return;
- }
- cp = cpr;
-
- /* Get the line number and verify that it is correct. */
- unsigned long lineno = strtoul(cp, &cpr, 10);
- if (cp == cpr) {
- VLerror(yylloc, "Invalid line number for #line directive.");
- delete[] buf;
- return;
- }
- cp = cpr;
-
- /* Verify that only space is left. */
- cpr += strspn(cp, " \t");
- if ((size_t)(cpr-yytext) != strlen(yytext)) {
- VLerror(yylloc, "Invalid #line directive (extra garbage after "
- "line number).");
- delete[] buf;
- return;
- }
-
- /* Now we can assign the new values to yyloc. */
- yylloc.text = set_file_name(buf);
- yylloc.first_line = lineno;
-}
-
-/*
- * The line directive matches lines of the form `line N "foo" M and
- * calls this function. Here I parse out the file name and line
- * number, and change the yylloc to suite. M is ignored.
- */
-static void line_directive2()
-{
- char *cpr;
- /* Skip any leading space. */
- char *cp = strchr(yytext, '`');
- /* Skip the `line directive. */
- assert(strncmp(cp, "`line", 5) == 0);
- cp += 5;
-
- /* strtoul skips leading space. */
- unsigned long lineno = strtoul(cp, &cpr, 10);
- if (cp == cpr) {
- VLerror(yylloc, "Invalid line number for `line directive.");
- return;
- }
- lineno -= 1;
- cp = cpr;
-
- /* Skip the space between the line number and the file name. */
- cpr += strspn(cp, " \t");
- if (cp == cpr) {
- VLerror(yylloc, "Invalid `line directive (missing space after "
- "line number).");
- return;
- }
- cp = cpr;
-
- /* Find the starting " and skip it. */
- char*fn_start = strchr(cp, '"');
- if (cp != fn_start) {
- VLerror(yylloc, "Invalid `line directive (file name start).");
- return;
- }
- fn_start += 1;
-
- /* Find the last ". */
- char*fn_end = strrchr(fn_start, '"');
- if (!fn_end) {
- VLerror(yylloc, "Invalid `line directive (file name end).");
- return;
- }
-
- /* Skip the space after the file name. */
- cp = fn_end + 1;
- cpr = cp;
- cpr += strspn(cp, " \t");
- if (cp == cpr) {
- VLerror(yylloc, "Invalid `line directive (missing space after "
- "file name).");
- return;
- }
- cp = cpr;
-
- /* Check that the level is correct, we do not need the level. */
- if (strspn(cp, "012") != 1) {
- VLerror(yylloc, "Invalid level for `line directive.");
- return;
- }
- cp += 1;
-
- /* Verify that only space and/or a single line comment is left. */
- cp += strspn(cp, " \t");
- if (strncmp(cp, "//", 2) != 0 &&
- (size_t)(cp-yytext) != strlen(yytext)) {
- VLerror(yylloc, "Invalid `line directive (extra garbage after "
- "level).");
- return;
- }
-
- /* Copy the file name and assign it and the line number to yylloc. */
- char*buf = new char[fn_end-fn_start+1];
- strncpy(buf, fn_start, fn_end-fn_start);
- buf[fn_end-fn_start] = 0;
-
- yylloc.text = set_file_name(buf);
- yylloc.first_line = lineno;
-}
-
-/*
- * Reset all compiler directives. This will be called when a `resetall
- * directive is encountered or when a new compilation unit is started.
- */
-static void reset_all()
-{
- pform_set_default_nettype(NetNet::WIRE, yylloc.text, yylloc.first_line);
- in_celldefine = false;
- uc_drive = UCD_NONE;
- pform_set_timescale(def_ts_units, def_ts_prec, 0, 0);
-}
-
-extern FILE*vl_input;
-void reset_lexor()
-{
- yyrestart(vl_input);
- yylloc.first_line = 1;
-
- /* Announce the first file name. */
- yylloc.text = set_file_name(strdupnew(vl_file.c_str()));
-
- if (separate_compilation) {
- reset_all();
- if (!keyword_mask_stack.empty()) {
- lexor_keyword_mask = keyword_mask_stack.back();
- keyword_mask_stack.clear();
- }
- }
-}
-
-/*
- * Modern version of flex (>=2.5.9) can clean up the scanner data.
- */
-void destroy_lexor()
-{
-# ifdef FLEX_SCANNER
-# if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5
-# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9
- yylex_destroy();
-# endif
-# endif
-# endif
-}
-"""
-
def t_timescale_error(t):
print("%d: Timescale error '%s'" % (t.lexer.lineno, t.value[0]))
print(t.value)