Improve numerical constant parsing.

This commit is contained in:
Jack Palevich 2009-07-15 16:16:37 -07:00
parent 8c246a9dc2
commit 2aaf21f1be
3 changed files with 105 additions and 51 deletions

View File

@ -3425,6 +3425,17 @@ class Compiler : public ErrorSink {
return isalnum(ch) | (ch == '_');
}
int decodeHex(int c) {
if (isdigit(c)) {
c -= '0';
} else if (c <= 'F') {
c = c - 'A' + 10;
} else {
c =c - 'a' + 10;
}
return c;
}
/* read a character constant, advances ch to after end of constant */
int getq() {
int val = ch;
@ -3448,15 +3459,7 @@ class Compiler : public ErrorSink {
} else {
val = 0;
while (isxdigit(ch)) {
int d = ch;
if (isdigit(d)) {
d -= '0';
} else if (d <= 'F') {
d = d - 'A' + 10;
} else {
d = d - 'a' + 10;
}
val = (val << 4) + d;
val = (val << 4) + decodeHex(ch);
inp();
}
}
@ -3535,32 +3538,35 @@ class Compiler : public ErrorSink {
void parseFloat() {
tok = TOK_NUM_DOUBLE;
// mTokenString already has the integral part of the number.
if(mTokenString.len() == 0) {
mTokenString.append('0');
}
acceptCh('.');
acceptDigitsCh();
bool doExp = true;
if (acceptCh('e') || acceptCh('E')) {
// Don't need to do any extra work
} else if (ch == 'f' || ch == 'F') {
pdef('e'); // So it can be parsed by strtof.
inp();
tok = TOK_NUM_FLOAT;
} else {
doExp = false;
acceptCh('-') || acceptCh('+');
acceptDigitsCh();
}
if (doExp) {
bool digitsRequired = acceptCh('-');
bool digitsFound = acceptDigitsCh();
if (digitsRequired && ! digitsFound) {
error("malformed exponent");
}
if (ch == 'f' || ch == 'F') {
tok = TOK_NUM_FLOAT;
inp();
} else if (ch == 'l' || ch == 'L') {
inp();
error("Long floating point constants not supported.");
}
char* pText = mTokenString.getUnwrapped();
char* pEnd = pText + strlen(pText);
char* pEndPtr = 0;
errno = 0;
if (tok == TOK_NUM_FLOAT) {
tokd = strtof(pText, 0);
tokd = strtof(pText, &pEndPtr);
} else {
tokd = strtod(pText, 0);
tokd = strtod(pText, &pEndPtr);
}
//fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
if (errno || pEndPtr != pEnd) {
error("Can't parse constant: %s", pText);
}
// fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
}
void next() {
@ -3584,35 +3590,66 @@ class Compiler : public ErrorSink {
tokl = 0;
tok = ch;
/* encode identifiers & numbers */
if (isid()) {
if (isdigit(ch) || ch == '.') {
// Start of a numeric constant. Could be integer, float, or
// double, won't know until we look further.
mTokenString.clear();
pdef(ch);
inp();
int base = 10;
if (tok == '0') {
if (ch == 'x' || ch == 'X') {
base = 16;
tok = TOK_NUM;
tokc = 0;
inp();
while ( isxdigit(ch) ) {
tokc = (tokc << 4) + decodeHex(ch);
inp();
}
} else if (isoctal(ch)){
base = 8;
tok = TOK_NUM;
tokc = 0;
while ( isoctal(ch) ) {
tokc = (tokc << 3) + (ch - '0');
inp();
}
}
} else if (isdigit(tok)){
acceptDigitsCh();
}
if (base == 10) {
if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
parseFloat();
} else {
// It's an integer constant
char* pText = mTokenString.getUnwrapped();
char* pEnd = pText + strlen(pText);
char* pEndPtr = 0;
errno = 0;
tokc = strtol(pText, &pEndPtr, base);
if (errno || pEndPtr != pEnd) {
error("Can't parse constant: %s %d %d", pText, base, errno);
}
tok = TOK_NUM;
}
}
} else if (isid()) {
mTokenString.clear();
while (isid()) {
pdef(ch);
inp();
}
if (isdigit(tok)) {
// Start of a numeric constant. Could be integer, float, or
// double, won't know until we look further.
if (ch == '.' || ch == 'e' || ch == 'e'
|| ch == 'f' || ch == 'F') {
parseFloat();
} else {
// It's an integer constant
tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
tok = TOK_NUM;
}
} else {
tok = mTokenTable.intern(mTokenString.getUnwrapped(),
mTokenString.len());
// Is this a macro?
char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
if(pMacroDefinition) {
// Yes, it is a macro
dptr = pMacroDefinition;
dch = ch;
inp();
next();
}
tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
// Is this a macro?
char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
if (pMacroDefinition) {
// Yes, it is a macro
dptr = pMacroDefinition;
dch = ch;
inp();
next();
}
} else {
inp();

View File

@ -17,6 +17,11 @@ double itod(int i) {
float f0, f1;
double d0, d1;
void testParseConsts() {
printf("Constants: %g %g %g %g %g %g %g %g %g\n", 0e1, 0E1, 0.f, .01f,
.01e0f, 1.0e-1, 1.0e1, 1.0e+1,
.1f);
}
void testVars(float arg0, float arg1, double arg2, double arg3) {
float local0, local1;
double local2, local3;
@ -41,6 +46,7 @@ void testVars(float arg0, float arg1, double arg2, double arg3) {
}
int main() {
testParseConsts();
printf("int: %d float: %g double: %g\n", 1, 2.2f, 3.3);
printf(" ftoi(1.4f)=%d\n", ftoi(1.4f));
printf(" dtoi(2.4)=%d\n", dtoi(2.4));

View File

@ -174,7 +174,18 @@ class TestACC(unittest.TestCase):
def testRunFloat(self):
self.compileCheck(["-R", "data/float.c"],
"Executing compiled code:\nresult: 0\n",
"int: 1 float: 2.2 double: 3.3\n ftoi(1.4f)=1\n dtoi(2.4)=2\n itof(3)=3\n itod(4)=4\nglobals: 1 2 3 4\nargs: 1 2 3 4\nlocals: 1 2 3 4\ncast rval: 2 4\ncast lval: 1.1 2 3.3 4\n")
"""Constants: 0 0 0 0.01 0.01 0.1 10 10 0.1
int: 1 float: 2.2 double: 3.3
ftoi(1.4f)=1
dtoi(2.4)=2
itof(3)=3
itod(4)=4
globals: 1 2 3 4
args: 1 2 3 4
locals: 1 2 3 4
cast rval: 2 4
cast lval: 1.1 2 3.3 4
""")
def testRunFlops(self):
self.compileCheck(["-R", "data/flops.c"],