lexor support for huge decimal numbers.

This commit is contained in:
steve 2002-04-14 21:42:01 +00:00
parent ea44866b2f
commit 95ccc1e904
1 changed files with 109 additions and 40 deletions

149
lexor.lex
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: lexor.lex,v 1.69 2002/02/15 05:20:58 steve Exp $"
#ident "$Id: lexor.lex,v 1.70 2002/04/14 21:42:01 steve Exp $"
#endif
# include "config.h"
@ -89,6 +89,8 @@ static verinum*make_unsized_dec(const char*txt);
static verinum*make_unsized_octal(const char*txt);
static verinum*make_unsized_hex(const char*txt);
static int dec_buf_div2(char *buf);
static void process_timescale(const char*txt);
static int comment_enter;
@ -253,19 +255,38 @@ W [ \t\b\f\r]+
return NUMBER; }
[0-9][0-9_]* {
/* Handle the special case of the unsized decimal number. */
unsigned long value = 0;
for (const char*cp = yytext ; *cp ; cp += 1) {
if (*cp != '_')
value = 10 * value + (*cp - '0');
char buf[4096];
if (strlen(yytext) >= sizeof(buf)-2){
fprintf(stderr, "Ridicilously long decimal constant will be truncated!\n");
}
assert(INTEGER_WIDTH <= (8*sizeof(value)));
unsigned nbits = INTEGER_WIDTH;
verinum::V*bits = new verinum::V[8 * sizeof value];
strncpy(buf, yytext, sizeof(buf)-2);
buf[sizeof(buf)-1] = 0;
for (unsigned idx = 0 ; idx < nbits ; idx += 1, value >>= 1) {
bits[idx] = (value&1) ? verinum::V1 : verinum::V0;
/* Convert the decimal number to a binary value, one digit at
a time. Watch out for overflow. */
verinum::V*bits = new verinum::V[INTEGER_WIDTH];
unsigned idx=0;
unsigned nbits=INTEGER_WIDTH;
while(idx<nbits){
int rem = dec_buf_div2(buf);
bits[idx] = (rem==1) ? verinum::V1 : verinum::V0;
++idx;
}
for(; idx<nbits; ++idx){
bits[idx] = verinum::V0;
}
/* If we run out of bits to hold the value, but there are
still valueable bits in the number, print a warning. */
if (strcmp(buf, "0") != 0){
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric decimal constant ``" << yytext <<
"'' truncated to " << nbits << " bits." << endl;
}
yylval.number = new verinum(bits, nbits, false);
@ -836,13 +857,65 @@ static verinum*make_unsized_hex(const char*txt)
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;
}
/*
* Making a decimal number is much easier then the other base numbers
* because there are no z or x values to worry about.
*/
static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr)
{
char buf[4096];
bool signed_flag = false;
if (tolower(*ptr) == 's') {
signed_flag = true;
ptr += 1;
@ -853,40 +926,36 @@ static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr)
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
const char*digits = ptr;
/* Convert the decimal number to a binary value, one digit at
a time. Watch out for overflow. */
unsigned long value = 0;
for ( ; *ptr ; ptr += 1)
if (isdigit(*ptr)) {
unsigned long tmp = value * 10 + (*ptr - '0');
if (tmp < value)
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric decimal constant ``"
<< digits << "'' is too large." << endl;
value *= 10;
value += *ptr - '0';
} else {
assert(*ptr == '_');
}
verinum::V*bits = new verinum::V[size];
for (unsigned idx = 0 ; idx < size ; idx += 1) {
bits[idx] = (value&1)? verinum::V1 : verinum::V0;
value /= 2;
if (strlen(ptr) >= sizeof(buf)-2){
fprintf(stderr, "Ridicilously long decimal constant will be truncated!\n");
}
/* If we run out of bits to hold the value, but there are
still valueable bits in the number, print a warning. */
strncpy(buf, ptr, sizeof(buf)-2);
buf[sizeof(buf)-1] = 0;
if (value != 0)
/* Convert the decimal number to a binary value, one digit at
a time. Watch out for overflow. */
verinum::V*bits = new verinum::V[size];
unsigned idx=0;
while(idx<size){
int rem = dec_buf_div2(buf);
bits[idx] = (rem==1) ? verinum::V1 : verinum::V0;
++idx;
}
for(; idx<size; ++idx){
bits[idx] = verinum::V0;
}
/* If we run out of bits to hold the value, but there are
still valueable bits in the number, print a warning. */
if (strcmp(buf, "0") != 0){
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric decimal constant ``" << digits <<
": warning: Numeric decimal constant ``" << ptr <<
"'' truncated to " << size << " bits." << endl;
}
verinum*out = new verinum(bits, size, fixed);
out->has_sign(signed_flag);