aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2015-02-18 04:22:25 +0000
committerThomas Preud'homme <robotux@celest.fr>2015-02-18 07:01:03 +0000
commita6c3ce6ec03516d850e6b987fcbe95aba192b76b (patch)
treefa1635b36484ebb90d3615356495807287d8a4fc
parentff783b94c7b973e86b1145e53a40926bb87eb47f (diff)
downloadtinycc-a6c3ce6ec03516d850e6b987fcbe95aba192b76b.tar.gz
tinycc-a6c3ce6ec03516d850e6b987fcbe95aba192b76b.tar.bz2
The "open a whisky and cut your finger open" patch
Make integer constant parsing C99 compliant
-rw-r--r--tccpp.c75
-rw-r--r--tests/tests2/72_long_long_constant.c17
-rw-r--r--tests/tests2/Makefile7
3 files changed, 62 insertions, 37 deletions
diff --git a/tccpp.c b/tccpp.c
index bc2d4a2..42f34aa 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -2012,7 +2012,8 @@ static void parse_number(const char *p)
}
} else {
unsigned long long n, n1;
- int lcount, ucount;
+ int lcount, ucount, must_64bit;
+ const char *p1;
/* integer number */
*q = '\0';
@@ -2025,17 +2026,16 @@ static void parse_number(const char *p)
while(1) {
t = *q++;
/* no need for checks except for base 10 / 8 errors */
- if (t == '\0') {
+ if (t == '\0')
break;
- } else if (t >= 'a') {
+ else if (t >= 'a')
t = t - 'a' + 10;
- } else if (t >= 'A') {
+ else if (t >= 'A')
t = t - 'A' + 10;
- } else {
+ else
t = t - '0';
- if (t >= b)
- tcc_error("invalid digit");
- }
+ if (t >= b)
+ tcc_error("invalid digit");
n1 = n;
n = n * b + t;
/* detect overflow */
@@ -2043,50 +2043,57 @@ static void parse_number(const char *p)
if (n < n1)
tcc_error("integer constant overflow");
}
-
- /* XXX: not exactly ANSI compliant */
- if ((n & 0xffffffff00000000LL) != 0) {
- if ((n >> 63) != 0)
- tok = TOK_CULLONG;
- else
- tok = TOK_CLLONG;
- } else if (n > 0x7fffffff) {
- tok = TOK_CUINT;
- } else {
- tok = TOK_CINT;
- }
- lcount = 0;
- ucount = 0;
+
+ /* Determine the characteristics (unsigned and/or 64bit) the type of
+ the constant must have according to the constant suffix(es) */
+ lcount = ucount = must_64bit = 0;
+ p1 = p;
for(;;) {
t = toup(ch);
if (t == 'L') {
if (lcount >= 2)
tcc_error("three 'l's in integer constant");
+ if (lcount && *(p - 1) != ch)
+ tcc_error("incorrect integer suffix: %s", p1);
lcount++;
#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
- if (lcount == 2) {
-#endif
- if (tok == TOK_CINT)
- tok = TOK_CLLONG;
- else if (tok == TOK_CUINT)
- tok = TOK_CULLONG;
-#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
- }
+ if (lcount == 2)
#endif
+ must_64bit = 1;
ch = *p++;
} else if (t == 'U') {
if (ucount >= 1)
tcc_error("two 'u's in integer constant");
ucount++;
- if (tok == TOK_CINT)
- tok = TOK_CUINT;
- else if (tok == TOK_CLLONG)
- tok = TOK_CULLONG;
ch = *p++;
} else {
break;
}
}
+
+ /* Whether 64 bits are needed to hold the constant's value */
+ if (n & 0xffffffff00000000LL || must_64bit) {
+ tok = TOK_CLLONG;
+ n1 = n >> 32;
+ } else {
+ tok = TOK_CINT;
+ n1 = n;
+ }
+
+ /* Whether type must be unsigned to hold the constant's value */
+ if (ucount || ((n1 >> 31) && (b != 10))) {
+ if (tok == TOK_CLLONG)
+ tok = TOK_CULLONG;
+ else
+ tok = TOK_CUINT;
+ /* If decimal and no unsigned suffix, bump to 64 bits or throw error */
+ } else if (n1 >> 31) {
+ if (tok == TOK_CINT)
+ tok = TOK_CLLONG;
+ else
+ tcc_error("integer constant overflow");
+ }
+
if (tok == TOK_CINT || tok == TOK_CUINT)
tokc.ui = n;
else
diff --git a/tests/tests2/72_long_long_constant.c b/tests/tests2/72_long_long_constant.c
new file mode 100644
index 0000000..a698fd6
--- /dev/null
+++ b/tests/tests2/72_long_long_constant.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+int main()
+{
+ long long int res = 0;
+
+ if (res < -2147483648LL) {
+ printf("Error: 0 < -2147483648\n");
+ return 1;
+ }
+ else
+ if (2147483647LL < res) {
+ printf("Error: 2147483647 < 0\n");
+ return 2;
+ }
+ return 0;
+}
diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile
index ec636ab..8d8a5e7 100644
--- a/tests/tests2/Makefile
+++ b/tests/tests2/Makefile
@@ -91,6 +91,7 @@ TESTS = \
69_macro_param_list_err_2.test \
70_floating_point_literals.test \
71_macro_empty_arg.test \
+ 72_long_long_constant.test \
# 34_array_assignment.test -- array assignment is not in C standard
@@ -113,14 +114,14 @@ ARGS =
all test: $(filter-out $(SKIP),$(TESTS))
-%.test: %.c %.expect
+%.test: %.c
@echo Test: $*...
@$(TCC) -run $< $(ARGS) 2>&1 | grep -v 'warning: soft float ABI currently not supported: default to softfp' >$*.output || true
- @diff -bu $*.expect $*.output && rm -f $*.output
+ @diff -Nbu $*.expect $*.output && rm -f $*.output
@($(TCC) $< -o $*.exe && ./$*.exe $(ARGS)) 2>&1 | grep -v 'warning: soft float ABI currently not supported: default to softfp' >$*.output2 || true
- @diff -bu $*.expect $*.output2 && rm -f $*.output2 $*.exe
+ @diff -Nbu $*.expect $*.output2 && rm -f $*.output2 $*.exe
clean:
rm -vf fred.txt *.output* *.exe