iverilog/lexor.lex

921 lines
23 KiB
Plaintext
Raw Normal View History

1998-11-04 00:28:49 +01:00
2006-05-17 06:15:12 +02:00
%option never-interactive
1998-11-04 00:28:49 +01:00
%{
/*
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
1998-11-04 00:28:49 +01:00
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
2003-08-26 18:26:01 +02:00
#ifdef HAVE_CVS_IDENT
#ident "$Id: lexor.lex,v 1.95 2007/04/19 02:52:53 steve Exp $"
1998-11-04 00:28:49 +01:00
#endif
# include "config.h"
1998-11-04 00:28:49 +01:00
//# define YYSTYPE lexval
2002-06-06 20:57:18 +02:00
# include <iostream>
# include "compiler.h"
1998-11-04 00:28:49 +01:00
# include "parse_misc.h"
2001-10-21 01:02:39 +02:00
# include "parse_api.h"
1998-11-04 00:28:49 +01:00
# include "parse.h"
# include <ctype.h>
1999-07-10 03:03:18 +02:00
# include <string.h>
2000-03-12 18:09:40 +01:00
# include "lexor_keyword.h"
1998-11-04 00:28:49 +01:00
# define YY_USER_INIT reset_lexor();
# define yylval VLlval
/*
* Lexical location information is passed in the yylloc variable to th
* parser. The file names, strings, are kept in a list so that I can
* re-use them. The set_file_name function will return a pointer to
* 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.
*/
1998-11-04 00:28:49 +01:00
extern YYLTYPE yylloc;
struct file_name_cell {
const char*text;
struct file_name_cell*next;
bool library_flag;
};
static struct file_name_cell*file_names = 0;
static const char* set_file_name(char*text)
{
struct file_name_cell*cur = file_names;
while (cur) {
if (strcmp(cur->text, text) == 0) {
delete[]text;
return cur->text;
}
cur = cur->next;
}
cur = new struct file_name_cell;
cur->text = text;
cur->next = file_names;
/* Check this file name with the list of library file
names. If there is a match, then turn on the
pform_library_flag. This is how the parser knows that
modules declared in this file are library modules. */
cur->library_flag = library_file_map[cur->text];
pform_library_flag = cur->library_flag;
return text;
}
2002-04-15 02:04:22 +02:00
extern void pform_set_timescale(int, int, const char*file, unsigned line);
2001-10-21 01:02:39 +02:00
void reset_lexor();
static void line_directive();
static void line_directive2();
1999-05-06 06:09:28 +02:00
static verinum*make_unsized_binary(const char*txt);
static verinum*make_unsized_dec(const char*txt);
static verinum*make_unsized_octal(const char*txt);
static verinum*make_unsized_hex(const char*txt);
1998-11-04 00:28:49 +01:00
static int dec_buf_div2(char *buf);
static void process_timescale(const char*txt);
static int comment_enter;
1998-11-04 00:28:49 +01:00
%}
%x CCOMMENT
2002-02-15 06:20:58 +01:00
%x PCOMMENT
%x LCOMMENT
1998-11-04 00:28:49 +01:00
%x CSTRING
%s UDPTABLE
1999-06-12 22:35:27 +02:00
%x PPTIMESCALE
%x PPDEFAULT_NETTYPE
1998-11-04 00:28:49 +01:00
1999-07-11 19:15:16 +02:00
W [ \t\b\f\r]+
1998-11-04 00:28:49 +01:00
%%
^"#line"[ ]+\"[^\"]*\"[ ]+[0-9]+.* { line_directive(); }
^"`line"[ ]+[0-9]+[ ]+\"[^\"]*\".* { line_directive2(); }
1998-11-04 00:28:49 +01:00
[ \t\b\f\r] { ; }
\n { yylloc.first_line += 1; }
2003-08-28 06:11:17 +02:00
/* C++ style comments start with / / and run to the end of the
2002-02-15 06:20:58 +01:00
current line. These are very easy to handle. */
"//".* { comment_enter = YY_START; BEGIN(LCOMMENT); }
<LCOMMENT>. { yymore(); }
<LCOMMENT>\n { yylloc.first_line += 1; BEGIN(comment_enter); }
1998-11-04 00:28:49 +01:00
2002-02-15 06:20:58 +01:00
/* The contents of C-style comments are ignored, like white space. */
"/*" { comment_enter = YY_START; BEGIN(CCOMMENT); }
1998-11-04 00:28:49 +01:00
<CCOMMENT>. { yymore(); }
<CCOMMENT>\n { yylloc.first_line += 1; yymore(); }
<CCOMMENT>"*/" { BEGIN(comment_enter); }
1998-11-04 00:28:49 +01:00
2002-02-15 06:20:58 +01:00
"(*" { return K_PSTAR; }
"*)" { return K_STARP; }
"<<" { return K_LS; }
2003-06-18 05:55:18 +02:00
"<<<" { return K_LS; /* Note: Functionally, <<< is the same as <<. */}
">>" { return K_RS; }
">>>" { return K_RSS; }
"**" { return K_POW; }
1998-11-04 00:28:49 +01:00
"<=" { return K_LE; }
">=" { return K_GE; }
1999-06-19 05:21:21 +02:00
"=>" { return K_EG; }
"*>" { return K_SG; }
"==" { return K_EQ; }
"!=" { return K_NE; }
"===" { return K_CEQ; }
"!==" { return K_CNE; }
"||" { return K_LOR; }
"&&" { return K_LAND; }
2001-07-02 01:44:43 +02:00
"&&&" { return K_TAND; }
1999-06-13 19:30:23 +02:00
"~|" { return K_NOR; }
"~^" { return K_NXOR; }
"^~" { return K_NXOR; }
"~&" { return K_NAND; }
"->" { return K_TRIGGER; }
2001-07-02 01:44:43 +02:00
"+:" { return K_PO_POS; }
"-:" { return K_PO_NEG; }
1999-06-13 19:30:23 +02:00
2003-06-17 06:23:25 +02:00
/* 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. */
2006-02-02 06:21:45 +01:00
"("{W}*"*"{W}*")" { return '*'; }
2003-06-17 06:23:25 +02:00
1998-11-04 00:28:49 +01:00
[}{;:\[\],()#=.@&!?<>%|^~+*/-] { return yytext[0]; }
1998-11-04 00:28:49 +01:00
\" { BEGIN(CSTRING); }
2007-02-09 06:19:04 +01:00
<CSTRING>\\\\ { yymore(); /* Catch \\, which is a \ escaping itself */ }
<CSTRING>\\\" { yymore(); /* Catch \", which is an escaped quote */ }
1998-11-04 00:28:49 +01:00
<CSTRING>\n { BEGIN(0);
1999-07-10 03:03:18 +02:00
yylval.text = strdup(yytext);
1998-11-04 00:28:49 +01:00
VLerror(yylloc, "Missing close quote of string.");
yylloc.first_line += 1;
1998-11-04 00:28:49 +01:00
return STRING; }
<CSTRING>\" { BEGIN(0);
1999-07-10 03:03:18 +02:00
yylval.text = strdup(yytext);
yylval.text[strlen(yytext)-1] = 0;
1998-11-04 00:28:49 +01:00
return STRING; }
<CSTRING>. { yymore(); }
2000-03-05 07:14:10 +01:00
<UDPTABLE>\(\?0\) { return '_'; }
<UDPTABLE>\(\?1\) { return '+'; }
<UDPTABLE>\(\?[xX]\) { return '%'; }
<UDPTABLE>\(\?\?\) { return '*'; }
<UDPTABLE>\(01\) { return 'r'; }
<UDPTABLE>\(0[xX]\) { return 'Q'; }
2003-03-18 02:36:14 +01:00
<UDPTABLE>\(b[xX]\) { return 'q'; }
2005-09-14 17:01:07 +02:00
<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'; }
2000-03-05 07:14:10 +01:00
<UDPTABLE>\(10\) { return 'f'; }
<UDPTABLE>\(1[xX]\) { return 'M'; }
<UDPTABLE>\(1\?\) { return 'N'; }
2000-03-05 07:14:10 +01:00
<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]; }
1998-11-04 00:28:49 +01:00
[a-zA-Z_][a-zA-Z0-9$_]* {
2000-03-12 18:09:40 +01:00
int rc = lexor_keyword_code(yytext, yyleng);
2005-07-07 18:22:49 +02:00
switch (rc) {
case IDENTIFIER:
1999-07-10 03:03:18 +02:00
yylval.text = strdup(yytext);
if (strncmp(yylval.text,"PATHPULSE$", 10) == 0)
rc = PATHPULSE_IDENTIFIER;
2005-07-07 18:22:49 +02:00
break;
case K_bool:
case K_logic:
case K_wone:
if (! gn_cadence_types_enabled()) {
yylval.text = strdup(yytext);
rc = IDENTIFIER;
} else {
yylval.text = 0;
}
break;
default:
1998-11-04 00:28:49 +01:00
yylval.text = 0;
2005-07-07 18:22:49 +02:00
break;
}
1998-11-04 00:28:49 +01:00
2000-03-12 18:09:40 +01:00
return rc;
}
1998-11-04 00:28:49 +01:00
2001-12-29 20:00:13 +01:00
\\[^ \t\b\f\r\n]+ {
yylval.text = strdup(yytext+1);
1998-11-04 00:28:49 +01:00
return IDENTIFIER; }
\$([a-zA-Z0-9$_]+) {
2001-08-31 19:38:41 +02:00
if (strcmp(yytext,"$setuphold") == 0)
return K_Ssetuphold;
if (strcmp(yytext,"$attribute") == 0)
return KK_attribute;
2001-07-02 01:44:43 +02:00
if (strcmp(yytext,"$hold") == 0)
return K_Shold;
if (strcmp(yytext,"$period") == 0)
return K_Speriod;
if (strcmp(yytext,"$recovery") == 0)
return K_Srecovery;
2003-08-31 23:14:28 +02:00
if (strcmp(yytext,"$recrem") == 0)
return K_Srecrem;
2001-07-02 01:44:43 +02:00
if (strcmp(yytext,"$setup") == 0)
return K_Ssetup;
if (strcmp(yytext,"$width") == 0)
return K_Swidth;
1999-07-10 03:03:18 +02:00
yylval.text = strdup(yytext);
1998-11-04 00:28:49 +01:00
return SYSTEM_IDENTIFIER; }
1999-06-14 05:15:14 +02:00
2000-01-07 04:45:49 +01:00
\'[sS]?[dD][ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext);
return BASED_NUMBER; }
2000-01-07 04:45:49 +01:00
\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext);
return BASED_NUMBER; }
2000-01-07 04:45:49 +01:00
\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext);
return BASED_NUMBER; }
2000-01-07 04:45:49 +01:00
\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext);
return BASED_NUMBER; }
1999-05-06 06:09:28 +02:00
[0-9][0-9_]* {
yylval.number = make_unsized_dec(yytext);
return DEC_NUMBER; }
1998-11-04 00:28:49 +01:00
1999-06-15 04:50:02 +02:00
[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; }
1999-07-11 19:15:16 +02:00
/* Notice and handle the timescale directive. */
1999-06-15 04:50:02 +02:00
^{W}?`timescale { BEGIN(PPTIMESCALE); }
<PPTIMESCALE>.* { process_timescale(yytext); }
1999-06-12 22:35:27 +02:00
<PPTIMESCALE>\n {
yylloc.first_line += 1;
BEGIN(0); }
1998-12-09 05:02:47 +01:00
1999-07-11 19:15:16 +02:00
/* These are directives that I do not yet support. I think that IVL
should handle these, not an external preprocessor. */
^{W}?`celldefine{W}?.* { }
^{W}?`delay_mode_distributed{W}?.* { }
^{W}?`delay_mode_unit{W}?.* { }
^{W}?`delay_mode_path{W}?.* { }
^{W}?`disable_portfaults{W}?.* { }
^{W}?`enable_portfaults{W}?.* { }
^{W}?`endcelldefine{W}?.* { }
`endprotect { }
^{W}?`nosuppress_faults{W}?.* { }
^{W}?`nounconnected_drive{W}?.* { }
`protect { }
^{W}?`resetall{W}?.* { }
^{W}?`suppress_faults{W}?.* { }
^{W}?`unconnected_drive{W}?.* { }
^{W}?`uselib{W}?.* { }
1999-07-11 19:15:16 +02:00
/* 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;
if (strcmp(yytext,"wire") == 0) {
net_type = NetNet::WIRE;
} 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 (and 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); }
1999-07-11 19:15:16 +02:00
/* These are directives that are not supported by me and should have
been handled by an external preprocessor such as ivlpp. */
^{W}?`define{W}?.* {
1999-07-11 19:15:16 +02:00
cerr << yylloc.text << ":" << yylloc.first_line <<
": `define not supported. Use an external preprocessor."
<< endl;
}
^{W}?`else{W}?.* {
cerr << yylloc.text << ":" << yylloc.first_line <<
": `else not supported. Use an external preprocessor."
<< endl;
}
^{W}?`endif{W}?.* {
cerr << yylloc.text << ":" << yylloc.first_line <<
": `endif not supported. Use an external preprocessor."
<< endl;
}
^{W}?`ifdef{W}?.* {
cerr << yylloc.text << ":" << yylloc.first_line <<
": `ifdef not supported. Use an external preprocessor."
<< endl;
}
^`include{W}?.* {
cerr << yylloc.text << ":" << yylloc.first_line <<
": `include not supported. Use an external preprocessor."
<< endl;
}
^`undef{W}?.* {
cerr << yylloc.text << ":" << yylloc.first_line <<
": `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; }
1999-07-11 19:15:16 +02:00
/* Final catchall. something got lost or mishandled. */
. { cerr << yylloc.text << ":" << yylloc.first_line
<< ": error: unmatched character (";
1998-11-04 00:28:49 +01:00
if (isgraph(yytext[0]))
cerr << yytext[0];
else
cerr << "hex " << hex << (0xffU & ((unsigned) (yytext[0])));
1998-11-04 00:28:49 +01:00
cerr << ")" << endl;
error_count += 1; }
1998-11-04 00:28:49 +01:00
%%
/*
* 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_start_table()
{
BEGIN(UDPTABLE);
}
void lex_end_table()
{
BEGIN(INITIAL);
}
1999-05-06 06:09:28 +02:00
static verinum*make_unsized_binary(const char*txt)
{
2000-01-07 04:45:49 +01:00
bool sign_flag = false;
1999-06-14 05:15:14 +02:00
const char*ptr = txt;
assert(*ptr == '\'');
ptr += 1;
2000-01-07 04:45:49 +01:00
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
2003-06-11 03:58:21 +02:00
1999-06-14 05:15:14 +02:00
assert(tolower(*ptr) == 'b');
2003-06-11 03:58:21 +02:00
ptr += 1;
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
1999-06-14 05:15:14 +02:00
ptr += 1;
unsigned size = 0;
for (const char*idx = ptr ; *idx ; idx += 1)
if (*idx != '_') size += 1;
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 '?':
1999-06-14 05:15:14 +02:00
bits[--idx] = verinum::Vz;
break;
case 'x': case 'X':
bits[--idx] = verinum::Vx;
break;
case '_':
break;
default:
fprintf(stderr, "%c\n", ptr[0]);
1999-06-14 05:15:14 +02:00
assert(0);
}
ptr += 1;
}
verinum*out = new verinum(bits, size, false);
2000-01-07 04:45:49 +01:00
out->has_sign(sign_flag);
delete[]bits;
return out;
1999-05-06 06:09:28 +02:00
}
1998-11-04 00:28:49 +01:00
1999-05-06 06:09:28 +02:00
static verinum*make_unsized_octal(const char*txt)
{
2000-01-07 04:45:49 +01:00
bool sign_flag = false;
1999-06-13 19:30:23 +02:00
const char*ptr = txt;
assert(*ptr == '\'');
ptr += 1;
2000-01-07 04:45:49 +01:00
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
1999-06-13 19:30:23 +02:00
assert(tolower(*ptr) == 'o');
ptr += 1;
1999-06-14 05:15:14 +02:00
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
unsigned size = 0;
for (const char*idx = ptr ; *idx ; idx += 1)
if (*idx != '_') size += 3;
1999-06-13 19:30:23 +02:00
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':
1999-06-13 19:30:23 +02:00
bits[--idx] = verinum::Vx;
bits[--idx] = verinum::Vx;
bits[--idx] = verinum::Vx;
break;
case 'z': case 'Z': case '?':
1999-06-13 19:30:23 +02:00
bits[--idx] = verinum::Vz;
bits[--idx] = verinum::Vz;
bits[--idx] = verinum::Vz;
break;
1999-06-14 05:15:14 +02:00
case '_':
break;
1999-06-13 19:30:23 +02:00
default:
assert(0);
}
ptr += 1;
}
verinum*out = new verinum(bits, size, false);
2000-01-07 04:45:49 +01:00
out->has_sign(sign_flag);
delete[]bits;
return out;
1999-05-06 06:09:28 +02:00
}
1998-11-04 00:28:49 +01:00
1999-05-06 06:09:28 +02:00
static verinum*make_unsized_hex(const char*txt)
{
2000-01-07 04:45:49 +01:00
bool sign_flag = false;
1999-06-13 19:30:23 +02:00
const char*ptr = txt;
assert(*ptr == '\'');
ptr += 1;
2000-01-07 04:45:49 +01:00
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
1999-06-13 19:30:23 +02:00
assert(tolower(*ptr) == 'h');
1999-06-14 05:15:14 +02:00
1999-06-13 19:30:23 +02:00
ptr += 1;
1999-06-14 05:15:14 +02:00
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
unsigned size = 0;
for (const char*idx = ptr ; *idx ; idx += 1)
if (*idx != '_') size += 4;
1999-06-13 19:30:23 +02:00
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':
1999-06-13 19:30:23 +02:00
bits[--idx] = verinum::Vx;
bits[--idx] = verinum::Vx;
bits[--idx] = verinum::Vx;
bits[--idx] = verinum::Vx;
break;
case 'z': case 'Z': case '?':
1999-06-13 19:30:23 +02:00
bits[--idx] = verinum::Vz;
bits[--idx] = verinum::Vz;
bits[--idx] = verinum::Vz;
bits[--idx] = verinum::Vz;
break;
1999-06-14 05:15:14 +02:00
case '_':
break;
1999-06-13 19:30:23 +02:00
default:
assert(0);
}
ptr += 1;
}
verinum*out = new verinum(bits, size, false);
2000-01-07 04:45:49 +01:00
out->has_sign(sign_flag);
delete[]bits;
return out;
1999-05-06 06:09:28 +02:00
}
/* 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;
}
/*
* Making a decimal number is much easier then the other base numbers
* because there are no z or x values to worry about. It is much
* harder then other base numbers because the width needed in bits is
* hard to calculate.
*/
static verinum*make_unsized_dec(const char*ptr)
{
char buf[4096];
2000-01-07 04:45:49 +01:00
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 markes the number as
signed. */
2000-01-07 04:45:49 +01:00
ptr += 1;
if (tolower(*ptr) == 's') {
signed_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'd');
1999-06-14 05:15:14 +02:00
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;
1999-06-14 05:15:14 +02:00
/* 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);
}
1999-06-14 05:15:14 +02:00
verinum*res = new verinum(bits, size, false);
res->has_sign(signed_flag);
delete[]bits;
return res;
}
/*
* The timescale parameter has the form:
* " <num> xs / <num> xs"
*/
static void process_timescale(const char*txt)
{
unsigned num;
const char*cp = txt + strspn(txt, " \t");
char*tmp;
const char*ctmp;
int unit = 0;
int prec = 0;
num = strtoul(cp, &tmp, 10);
if (num == 0) {
VLerror(yylloc, "Invalid timescale string.");
return;
}
while (num >= 10) {
unit += 1;
num /= 10;
}
if (num != 1) {
VLerror(yylloc, "Invalid timescale unit number.");
return;
}
cp = tmp;
cp += strspn(cp, " \t");
ctmp = cp + strcspn(cp, " \t/");
if (strncmp("s", cp, ctmp-cp) == 0) {
unit -= 0;
} else if (strncmp("ms", cp, ctmp-cp) == 0) {
unit -= 3;
} else if (strncmp("us", cp, ctmp-cp) == 0) {
unit -= 6;
} else if (strncmp("ns", cp, ctmp-cp) == 0) {
unit -= 9;
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
unit -= 12;
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
unit -= 15;
} else {
VLerror(yylloc, "Invalid timescale unit of measurement");
return;
}
cp = ctmp;
cp += strspn(cp, " \t/");
num = strtoul(cp, &tmp, 10);
if (num == 0) {
VLerror(yylloc, "Invalid timescale string.");
return;
}
assert(num);
while (num >= 10) {
prec += 1;
num /= 10;
}
if (num != 1) {
VLerror(yylloc, "Invalid timescale precision number.");
return;
}
cp = tmp;
cp += strspn(cp, " \t");
ctmp = cp + strcspn(cp, " \t\r");
if (strncmp("s", cp, ctmp-cp) == 0) {
prec -= 0;
} else if (strncmp("ms", cp, ctmp-cp) == 0) {
prec -= 3;
} else if (strncmp("us", cp, ctmp-cp) == 0) {
prec -= 6;
} else if (strncmp("ns", cp, ctmp-cp) == 0) {
prec -= 9;
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
prec -= 12;
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
prec -= 15;
} else {
VLerror(yylloc, "Invalid timescale precision units of measurement");
return;
}
2002-04-15 02:04:22 +02:00
pform_set_timescale(unit, prec, yylloc.text, yylloc.first_line);
}
1998-12-09 05:02:47 +01:00
2000-11-04 02:54:01 +01:00
int yywrap()
1998-12-09 05:02:47 +01:00
{
return 1;
1998-12-09 05:02:47 +01:00
}
/*
* 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()
1998-12-09 05:02:47 +01:00
{
char*qt1 = strchr(yytext, '"');
assert(qt1);
qt1 += 1;
1998-12-09 05:02:47 +01:00
char*qt2 = strchr(qt1, '"');
assert(qt2);
1998-12-09 05:02:47 +01:00
char*buf = new char[qt2-qt1+1];
strncpy(buf, qt1, qt2-qt1);
buf[qt2-qt1] = 0;
1998-12-09 05:02:47 +01:00
yylloc.text = set_file_name(buf);
qt2 += 1;
yylloc.first_line = strtoul(qt2,0,0);
1998-12-09 05:02:47 +01:00
}
static void line_directive2()
{
assert(strncmp(yytext,"`line",5) == 0);
char*cp = yytext + strlen("`line");
cp += strspn(cp, " ");
yylloc.first_line = strtoul(cp,&cp,10);
yylloc.first_line -= 1;
cp += strspn(cp, " ");
if (*cp == 0) return;
char*qt1 = strchr(yytext, '"');
assert(qt1);
qt1 += 1;
char*qt2 = strchr(qt1, '"');
assert(qt2);
char*buf = new char[qt2-qt1+1];
strncpy(buf, qt1, qt2-qt1);
buf[qt2-qt1] = 0;
yylloc.text = set_file_name(buf);
}
2001-10-21 01:02:39 +02:00
extern FILE*vl_input;
void reset_lexor()
1998-11-04 00:28:49 +01:00
{
yyrestart(vl_input);
yylloc.first_line = 1;
/* Start the file_names list. From here on, as I get a file
name, I will add it to this list. Only add the name if it
is not already in the list. */
file_names = new struct file_name_cell;
file_names->text = strdup(vl_file.c_str());
file_names->next = 0;
yylloc.text = file_names->text;
1998-11-04 00:28:49 +01:00
}