Browse Source

'long' review

add some features for more complete 'long' support

tcc.h:
- use LONG_SIZE=4/8 instead of TCC_LONG_ARE_64_BIT
tccgen.c:
- add ptrdiff_type, update size_type
- support shift and ?: operations
- support long enum types
- display 'long' from type_to_str
- nwchar_t is unsigned short on windows
- unrelated: use memcpy in init_putv for long doubles to avoid
  random bytes in the image (if tcc was compiled by gcc) for
  diff purposes.
tccpp.c:
- make parse_number return correct types
- improve multi-character-constants 'XX' 'abcd'
Changelog:
- update
grischka 2 years ago
parent
commit
1443039416
6 changed files with 164 additions and 176 deletions
  1. 4 2
      Changelog
  2. 7 7
      libtcc.c
  3. 11 12
      tcc.h
  4. 83 90
      tccgen.c
  5. 58 64
      tccpp.c
  6. 1 1
      win32/build-tcc.bat

+ 4 - 2
Changelog

@@ -9,11 +9,10 @@ User interface:
 - -mno-sse on x86-64 disables use of SSE instructions
 - @listfile support (Vlad Vissoultchev)
 - tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka)
-- CPATH, C_INCLUDE_PATH and LD_LIBRARY_PATH environment variables support
+- CPATH, C_INCLUDE_PATH and LIBRARY_PATH environment variables support
   (Andrew Aladjev, Urs Janssen)
 
 Platforms:
-- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
 - new AARCH64 (arm64) target (Edmund Grimley Evans)
 - vastly improved support for ARM hard float calling convention
    (Thomas Preud'homme, Daniel Glöckner)
@@ -22,6 +21,7 @@ Platforms:
 - ABI tests with native compiler using libtcc (James Lyon)
 - UNICODE startup code supports wmain and wWinMain (YX Hao)
 - shared libraries for x86_64 (Michael Matz)
+- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
 
 Features:
 - VLA (variable length array) improved (James Lyon, Pip Cet)
@@ -35,6 +35,8 @@ Features:
 - standard conforming (and GCC compatible) struct initialization
    (Michael Matz)
 - bit-field layout made compatible with GCC (Michael Matz)
+- UTF8 in string literals supported (Zdenek Pavlas)
+_ _Generic(...) supported (Matthias Gatto)
 
 Licensing:
 - TinyCC partly relicensed to MIT license (See RELICENSING file).

+ 7 - 7
libtcc.c

@@ -836,21 +836,21 @@ LIBTCCAPI TCCState *tcc_new(void)
 # endif
 
     /* TinyCC & gcc defines */
-#if defined(TCC_TARGET_PE) && PTR_SIZE == 8
+#if PTR_SIZE == 4
+    /* 32bit systems. */
+    tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
+    tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
+    tcc_define_symbol(s, "__ILP32__", NULL);
+#elif LONG_SIZE == 4
     /* 64bit Windows. */
     tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long");
     tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long");
     tcc_define_symbol(s, "__LLP64__", NULL);
-#elif PTR_SIZE == 8
+#else
     /* Other 64bit systems. */
     tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
     tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
     tcc_define_symbol(s, "__LP64__", NULL);
-#else
-    /* Other 32bit systems. */
-    tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
-    tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
-    tcc_define_symbol(s, "__ILP32__", NULL);
 #endif
 
 #if defined(TCC_MUSL)

+ 11 - 12
tcc.h

@@ -361,6 +361,12 @@ extern long double strtold (const char *__nptr, char **__endptr);
 /* target address type */
 #define addr_t ElfW(Addr)
 
+#if PTR_SIZE == 8 && !defined TCC_TARGET_PE
+# define LONG_SIZE 8
+#else
+# define LONG_SIZE 4
+#endif
+
 /* -------------------------------------------- */
 
 #define INCLUDE_STACK_SIZE  32
@@ -880,14 +886,14 @@ struct filespec {
 #define VT_CONSTANT    0x0100  /* const modifier */
 #define VT_VOLATILE    0x0200  /* volatile modifier */
 #define VT_VLA         0x0400  /* VLA type (also has VT_PTR and VT_ARRAY) */
-#define VT_LONG	       0x0800
+#define VT_LONG        0x0800  /* long type (also has VT_INT rsp. VT_LLONG) */
 
 /* storage */
 #define VT_EXTERN  0x00001000  /* extern definition */
 #define VT_STATIC  0x00002000  /* static variable */
 #define VT_TYPEDEF 0x00004000  /* typedef definition */
 #define VT_INLINE  0x00008000  /* inline definition */
-/* currently unused: 0x0800, 0x000[1248]0000  */
+/* currently unused: 0x000[1248]0000  */
 
 #define VT_STRUCT_SHIFT 20     /* shift for bitfield shift values (32 - 2*6) */
 #define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
@@ -906,7 +912,6 @@ struct filespec {
 #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
 #define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
 
-
 /* token values */
 
 /* warning: the following compare tokens depend on i386 asm code */
@@ -947,6 +952,7 @@ struct filespec {
 #define TOK_PPNUM   0xbe /* preprocessor number */
 #define TOK_PPSTR   0xbf /* preprocessor string */
 #define TOK_LINENUM 0xc0 /* line number info */
+#define TOK_TWODOTS 0xa8 /* C++ token ? */
 /* <-- */
 
 #define TOK_UMULL    0xc2 /* unsigned 32x32 -> 64 mul */
@@ -961,15 +967,8 @@ struct filespec {
 #define TOK_PLCHLDR  0xcb /* placeholder token as defined in C99 */
 #define TOK_NOSUBST  0xcc /* means following token has already been pp'd */
 #define TOK_PPJOIN   0xcd /* A '##' in the right position to mean pasting */
-
-#define TOK_CLONG   0xce /* long constant */
-#define TOK_CULONG  0xcf /* unsigned long constant */
-
-
-#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
-    #define TCC_LONG_ARE_64_BIT
-#endif
-
+#define TOK_CLONG    0xce /* long constant */
+#define TOK_CULONG   0xcf /* unsigned long constant */
 
 #define TOK_SHL   0x01 /* shift left */
 #define TOK_SAR   0x02 /* signed shift right */

+ 83 - 90
tccgen.c

@@ -61,7 +61,7 @@ ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc
 ST_DATA const char *funcname;
 ST_DATA int g_debug;
 
-ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
+ST_DATA CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type;
 
 ST_DATA struct switch_t {
     struct case_t {
@@ -240,9 +240,14 @@ ST_FUNC int tccgen_compile(TCCState *s1)
     char_pointer_type.t = VT_BYTE;
     mk_pointer(&char_pointer_type);
 #if PTR_SIZE == 4
-    size_type.t = VT_INT;
+    size_type.t = VT_INT | VT_UNSIGNED;
+    ptrdiff_type.t = VT_INT;
+#elif LONG_SIZE == 4
+    size_type.t = VT_LLONG | VT_UNSIGNED;
+    ptrdiff_type.t = VT_LLONG;
 #else
-    size_type.t = VT_LLONG;
+    size_type.t = VT_LONG | VT_LLONG | VT_UNSIGNED;
+    ptrdiff_type.t = VT_LONG | VT_LLONG;
 #endif
     func_old_type.t = VT_FUNC;
     func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0);
@@ -2127,12 +2132,7 @@ redo:
             }
             vrott(3);
             gen_opic(op);
-            /* set to integer type */
-#if PTR_SIZE == 8
-            vtop->type.t = VT_LLONG;
-#else
-            vtop->type.t = VT_INT; 
-#endif
+            vtop->type.t = ptrdiff_type.t;
             vswap();
             gen_op(TOK_PDIV);
         } else {
@@ -2218,14 +2218,15 @@ redo:
         t = bt1 == VT_LLONG ? VT_LLONG : VT_INT;
         if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED))
           t |= VT_UNSIGNED;
+        t |= (VT_LONG & t1);
         goto std_op;
     } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
         /* cast to biggest op */
-        t = VT_LLONG;
-	/* check if we need to keep type as long or as long long */
-	if ((t1 & VT_LONG &&  (t2 & (VT_BTYPE | VT_LONG)) != VT_LLONG) ||
-	    (t2 & VT_LONG &&  (t1 & (VT_BTYPE | VT_LONG)) != VT_LLONG))
-	  t |= VT_LONG;
+        t = VT_LLONG | VT_LONG;
+        if (bt1 == VT_LLONG)
+            t &= t1;
+        if (bt2 == VT_LLONG)
+            t &= t2;
         /* convert to unsigned if it does not fit in a long long */
         if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
             (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
@@ -2233,12 +2234,8 @@ redo:
         goto std_op;
     } else {
         /* integer operations */
-        t = VT_INT;
-
-	if ((t1 & VT_LONG) || (t2 & VT_LONG))
-	  t |= VT_LONG;
-
-	/* convert to unsigned if it does not fit in an integer */
+        t = VT_INT | (VT_LONG & (t1 | t2));
+        /* convert to unsigned if it does not fit in an integer */
         if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
             (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
             t |= VT_UNSIGNED;
@@ -2741,7 +2738,6 @@ static int compare_types(CType *type1, CType *type2, int unqualified)
         t1 &= ~VT_DEFSIGN;
         t2 &= ~VT_DEFSIGN;
     }
-
     /* XXX: bitfields ? */
     if (t1 != t2)
         return 0;
@@ -2790,14 +2786,7 @@ static void type_to_str(char *buf, int buf_size,
     t = type->t;
     bt = t & VT_BTYPE;
     buf[0] = '\0';
-    if (t & VT_CONSTANT)
-        pstrcat(buf, buf_size, "const ");
-    if (t & VT_VOLATILE)
-        pstrcat(buf, buf_size, "volatile ");
-    if ((t & (VT_DEFSIGN | VT_UNSIGNED)) == (VT_DEFSIGN | VT_UNSIGNED))
-        pstrcat(buf, buf_size, "unsigned ");
-    else if (t & VT_DEFSIGN)
-        pstrcat(buf, buf_size, "signed ");
+
     if (t & VT_EXTERN)
         pstrcat(buf, buf_size, "extern ");
     if (t & VT_STATIC)
@@ -2806,17 +2795,20 @@ static void type_to_str(char *buf, int buf_size,
         pstrcat(buf, buf_size, "typedef ");
     if (t & VT_INLINE)
         pstrcat(buf, buf_size, "inline ");
+    if (t & VT_VOLATILE)
+        pstrcat(buf, buf_size, "volatile ");
+    if (t & VT_CONSTANT)
+        pstrcat(buf, buf_size, "const ");
+
+    if (((t & VT_DEFSIGN) && bt == VT_BYTE)
+        || ((t & VT_UNSIGNED)
+            && (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG)
+            && !IS_ENUM(t)
+            ))
+        pstrcat(buf, buf_size, (t & VT_UNSIGNED) ? "unsigned " : "signed ");
+
     buf_size -= strlen(buf);
     buf += strlen(buf);
-    if (IS_ENUM(t)) {
-        tstr = "enum ";
-        goto tstruct;
-    }
-
-    if (!bt && VT_LONG & t) {
-      tstr = "long";
-      goto add_tstr;
-    }
 
     switch(bt) {
     case VT_VOID:
@@ -2833,10 +2825,16 @@ static void type_to_str(char *buf, int buf_size,
         goto add_tstr;
     case VT_INT:
         tstr = "int";
-        goto add_tstr;
+        goto maybe_long;
     case VT_LLONG:
         tstr = "long long";
-        goto add_tstr;
+    maybe_long:
+        if (t & VT_LONG)
+            tstr = "long";
+        if (!IS_ENUM(t))
+            goto add_tstr;
+        tstr = "enum ";
+        goto tstruct;
     case VT_FLOAT:
         tstr = "float";
         goto add_tstr;
@@ -2902,7 +2900,7 @@ static void type_to_str(char *buf, int buf_size,
    casts if needed. */
 static void gen_assign_cast(CType *dt)
 {
-    CType *st, *type1, *type2, tmp_type1, tmp_type2;
+    CType *st, *type1, *type2;
     char buf1[256], buf2[256];
     int dbt, sbt;
 
@@ -2958,7 +2956,7 @@ static void gen_assign_cast(CType *dt)
 		   in pointer target signedness.  Do warn for different
 		   base types, though, in particular for unsigned enums
 		   and signed int targets.  */
-		if ((type1->t & VT_BTYPE) != (type2->t & VT_BTYPE)
+		if ((type1->t & (VT_BTYPE|VT_LONG)) != (type2->t & (VT_BTYPE|VT_LONG))
                     || IS_ENUM(type1->t) || IS_ENUM(type2->t)
                     )
 		    tcc_warning("assignment from incompatible pointer type");
@@ -2982,11 +2980,7 @@ static void gen_assign_cast(CType *dt)
         break;
     case VT_STRUCT:
     case_VT_STRUCT:
-        tmp_type1 = *dt;
-        tmp_type2 = *st;
-        tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE);
-        tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE);
-        if (!is_compatible_types(&tmp_type1, &tmp_type2)) {
+        if (!is_compatible_unqualified_types(dt, st)) {
         error:
             type_to_str(buf1, sizeof(buf1), st, NULL);
             type_to_str(buf2, sizeof(buf2), dt, NULL);
@@ -3775,10 +3769,10 @@ do_decl:
             t.t = VT_INT;
             if (nl >= 0) {
                 if (pl != (unsigned)pl)
-                    t.t = VT_LLONG;
+                    t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
                 t.t |= VT_UNSIGNED;
             } else if (pl != (int)pl || nl != (int)nl)
-                t.t = VT_LLONG;
+                t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
             s->type.t = type->t = t.t | VT_ENUM;
             s->c = 0;
             /* set type for enum members */
@@ -3791,7 +3785,8 @@ do_decl:
                     if (ll == (unsigned)ll)
                         continue;
                 }
-                ss->type.t = (ss->type.t & ~VT_BTYPE) | VT_LLONG;
+                ss->type.t = (ss->type.t & ~VT_BTYPE)
+                    | (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
             }
         } else {
             c = 0;
@@ -3964,7 +3959,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
                 bt = u;
             }
             if (u != VT_INT)
-                t = (t & ~VT_BTYPE) | u;
+                t = (t & ~(VT_BTYPE|VT_LONG)) | u;
             typespec_found = 1;
             break;
         case TOK_VOID:
@@ -3978,11 +3973,9 @@ static int parse_btype(CType *type, AttributeDef *ad)
             goto basic_type;
         case TOK_LONG:
             if ((t & VT_BTYPE) == VT_DOUBLE) {
-#ifndef TCC_TARGET_PE
-	      t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE;
-#endif
-            } else if (t &  VT_LONG) {
-	      t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LLONG;
+                t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE;
+            } else if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) {
+                t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LLONG;
             } else {
                 u = VT_LONG;
                 goto basic_type;
@@ -4003,12 +3996,8 @@ static int parse_btype(CType *type, AttributeDef *ad)
             u = VT_FLOAT;
             goto basic_type;
         case TOK_DOUBLE:
-            if (t & VT_LONG) {
-#ifdef TCC_TARGET_PE
-		t = (t & ~(VT_LONG | VT_BTYPE)) | VT_DOUBLE;
-#else
-		t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE;
-#endif
+            if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) {
+                t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE;
             } else {
                 u = VT_DOUBLE;
                 goto basic_type;
@@ -4098,7 +4087,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
             parse_attribute(ad);
             if (ad->attr_mode) {
                 u = ad->attr_mode -1;
-                t = (t & ~VT_BTYPE) | u;
+                t = (t & ~(VT_BTYPE|VT_LONG)) | u;
             }
             break;
             /* GNUC typeof */
@@ -4118,7 +4107,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
             s = sym_find(tok);
             if (!s || !(s->type.t & VT_TYPEDEF))
                 goto the_end;
-            t &= ~VT_BTYPE;
+            t &= ~(VT_BTYPE|VT_LONG);
             u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u;
             type->t = (s->type.t & ~VT_TYPEDEF) | u;
             type->ref = s->type.ref;
@@ -4139,13 +4128,13 @@ the_end:
         if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE)
             t |= VT_UNSIGNED;
     }
-
-    /* long is never used as type */
-    if (t & VT_LONG)
-#if PTR_SIZE == 8 && !defined TCC_TARGET_PE
-        t = (t & ~VT_BTYPE) | VT_LLONG;
-#else
-        t = (t & ~VT_BTYPE) | VT_INT;
+    /* VT_LONG is used just as a modifier for VT_INT / VT_LLONG */
+    bt = t & (VT_BTYPE|VT_LONG);
+    if (bt == VT_LONG)
+        t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT;
+#ifdef TCC_TARGET_PE
+    if (bt == VT_LDOUBLE)
+        t = (t & ~(VT_BTYPE|VT_LONG)) | VT_DOUBLE;
 #endif
     type->t = t;
     return type_found;
@@ -4544,9 +4533,13 @@ ST_FUNC void unary(void)
     case TOK_EXTENSION:
         next();
         goto tok_next;
+    case TOK_LCHAR:
+#ifdef TCC_TARGET_PE
+        t = VT_SHORT|VT_UNSIGNED;
+        goto push_tokc;
+#endif
     case TOK_CINT:
     case TOK_CCHAR: 
-    case TOK_LCHAR:
 	t = VT_INT;
  push_tokc:
 	type.t = t;
@@ -4572,14 +4565,10 @@ ST_FUNC void unary(void)
         t = VT_LDOUBLE;
 	goto push_tokc;
     case TOK_CLONG:
+        t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG;
+	goto push_tokc;
     case TOK_CULONG:
-	#ifdef TCC_LONG_ARE_64_BIT
-	t = VT_LLONG | VT_LONG;
-	#else
-	t = VT_INT | VT_LONG;
-	#endif
-	if (tok == TOK_CULONG)
-	    t |= VT_UNSIGNED;
+        t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED;
 	goto push_tokc;
     case TOK___FUNCTION__:
         if (!gnu_ext)
@@ -5491,7 +5480,11 @@ static void expr_cond(void)
                 }
             } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
                 /* cast to biggest op */
-                type.t = VT_LLONG;
+                type.t = VT_LLONG | VT_LONG;
+                if (bt1 == VT_LLONG)
+                    type.t &= t1;
+                if (bt2 == VT_LLONG)
+                    type.t &= t2;
                 /* convert to unsigned if it does not fit in a long long */
                 if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
                     (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
@@ -5518,7 +5511,7 @@ static void expr_cond(void)
                 type.t = VT_VOID;
             } else {
                 /* integer operations */
-                type.t = VT_INT;
+                type.t = VT_INT | (VT_LONG & (t1 | t2));
                 /* convert to unsigned if it does not fit in an integer */
                 if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
                     (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
@@ -6490,20 +6483,20 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
 		*(double *)ptr = vtop->c.d;
 		break;
 	    case VT_LDOUBLE:
-                if (sizeof(long double) == LDOUBLE_SIZE)
-		    *(long double *)ptr = vtop->c.ld;
-		else if (sizeof(double) == LDOUBLE_SIZE)
-		    *(double *)ptr = (double)vtop->c.ld;
 #if (defined __i386__ || defined __x86_64__) && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
-                else if (sizeof (long double) >= 10)
-                    memcpy(memset(ptr, 0, LDOUBLE_SIZE), &vtop->c.ld, 10);
+                if (sizeof (long double) >= 10) /* zero pad ten-byte LD */
+                    memcpy(ptr, &vtop->c.ld, 10);
 #ifdef __TINYC__
                 else if (sizeof (long double) == sizeof (double))
-                    __asm__("fldl %1\nfstpt %0\n" : "=m"
-                        (memset(ptr, 0, LDOUBLE_SIZE), ptr) : "m" (vtop->c.ld));
+                    __asm__("fldl %1\nfstpt %0\n" : "=m" (ptr) : "m" (vtop->c.ld));
 #endif
+                else
 #endif
-		else
+                if (sizeof(long double) == LDOUBLE_SIZE)
+		    *(long double*)ptr = vtop->c.ld;
+                else if (sizeof(double) == LDOUBLE_SIZE)
+		    *(double *)ptr = (double)vtop->c.ld;
+                else
                     tcc_error("can't cross compile long double constants");
 		break;
 #if PTR_SIZE != 8

+ 58 - 64
tccpp.c

@@ -89,7 +89,7 @@ static const unsigned char tok_two_chars[] =
     '^','=', TOK_A_XOR,
     '|','=', TOK_A_OR,
     '-','>', TOK_ARROW,
-    '.','.', 0xa8, // C++ token ?
+    '.','.', TOK_TWODOTS,
     '#','#', TOK_TWOSHARPS,
     0
 };
@@ -1017,23 +1017,18 @@ static inline int tok_size(const int *p)
     case TOK_LCHAR:
     case TOK_CFLOAT:
     case TOK_LINENUM:
-#ifndef TCC_LONG_ARE_64_BIT
-    case TOK_CLONG;
-    case TOK_CULONG;
-#endif
         return 1 + 1;
     case TOK_STR:
     case TOK_LSTR:
     case TOK_PPNUM:
     case TOK_PPSTR:
         return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2);
+    case TOK_CLONG:
+    case TOK_CULONG:
+	return 1 + LONG_SIZE / 4;
     case TOK_CDOUBLE:
     case TOK_CLLONG:
     case TOK_CULLONG:
-#ifdef TCC_LONG_ARE_64_BIT
-    case TOK_CLONG;
-    case TOK_CULONG;
-#endif
         return 1 + 2;
     case TOK_CLDOUBLE:
         return 1 + LDOUBLE_SIZE / 4;
@@ -1149,7 +1144,7 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
     case TOK_LCHAR:
     case TOK_CFLOAT:
     case TOK_LINENUM:
-#ifndef TCC_LONG_ARE_64_BIT
+#if LONG_SIZE == 4
     case TOK_CLONG:
     case TOK_CULONG:
 #endif
@@ -1173,7 +1168,7 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
     case TOK_CDOUBLE:
     case TOK_CLLONG:
     case TOK_CULLONG:
-#ifdef TCC_LONG_ARE_64_BIT
+#if LONG_SIZE == 8
     case TOK_CLONG:
     case TOK_CULONG:
 #endif
@@ -1227,17 +1222,20 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
 
     tab = cv->tab;
     switch(*t = *p++) {
+#if LONG_SIZE == 4
+    case TOK_CLONG:
+#endif
     case TOK_CINT:
-    case TOK_CUINT:
     case TOK_CCHAR:
     case TOK_LCHAR:
     case TOK_LINENUM:
-#ifndef TCC_LONG_ARE_64_BIT
-    case TOK_CLONG:
+        cv->i = *p++;
+        break;
+#if LONG_SIZE == 4
     case TOK_CULONG:
 #endif
-        tab[0] = *p++;
-	cv->i = (*t == TOK_CUINT) ? (unsigned)cv->i : (int)cv->i;
+    case TOK_CUINT:
+        cv->i = (unsigned)*p++;
         break;
     case TOK_CFLOAT:
 	tab[0] = *p++;
@@ -1253,7 +1251,7 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
     case TOK_CDOUBLE:
     case TOK_CLLONG:
     case TOK_CULLONG:
-#ifdef TCC_LONG_ARE_64_BIT
+#if LONG_SIZE == 8
     case TOK_CLONG:
     case TOK_CULONG:
 #endif
@@ -2206,23 +2204,24 @@ static void parse_string(const char *s, int len)
         tcc_free(p);
 
     if (sep == '\'') {
-        int char_size;
+        int char_size, i, n, c;
         /* XXX: make it portable */
         if (!is_long)
-            char_size = 1;
+            tok = TOK_CCHAR, char_size = 1;
         else
-            char_size = sizeof(nwchar_t);
-        if (tokcstr.size <= char_size)
+            tok = TOK_LCHAR, char_size = sizeof(nwchar_t);
+        n = tokcstr.size / char_size - 1;
+        if (n < 1)
             tcc_error("empty character constant");
-        if (tokcstr.size > 2 * char_size)
+        if (n > 1)
             tcc_warning("multi-character character constant");
-        if (!is_long) {
-            tokc.i = *(int8_t *)tokcstr.data;
-            tok = TOK_CCHAR;
-        } else {
-            tokc.i = *(nwchar_t *)tokcstr.data;
-            tok = TOK_LCHAR;
+        for (c = i = 0; i < n; ++i) {
+            if (is_long)
+                c = ((nwchar_t *)tokcstr.data)[i];
+            else
+                c = (c << 8) | ((char *)tokcstr.data)[i];
         }
+        tokc.i = c;
     } else {
         tokc.str.size = tokcstr.size;
         tokc.str.data = tokcstr.data;
@@ -2456,7 +2455,7 @@ static void parse_number(const char *p)
         }
     } else {
         unsigned long long n, n1;
-        int lcount, ucount, must_64bit;
+        int lcount, ucount, ov = 0;
         const char *p1;
 
         /* integer number */
@@ -2483,14 +2482,13 @@ static void parse_number(const char *p)
             n1 = n;
             n = n * b + t;
             /* detect overflow */
-            /* XXX: this test is not reliable */
-            if (n < n1)
-                tcc_error("integer constant overflow");
+            if (n1 >= 0x1000000000000000ULL && n / b != n1)
+                ov = 1;
         }
 
         /* 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;
+        lcount = ucount = 0;
         p1 = p;
         for(;;) {
             t = toup(ch);
@@ -2500,8 +2498,6 @@ static void parse_number(const char *p)
                 if (lcount && *(p - 1) != ch)
                     tcc_error("incorrect integer suffix: %s", p1);
                 lcount++;
-                if (lcount == 2)
-                    must_64bit = 1;
                 ch = *p++;
             } else if (t == 'U') {
                 if (ucount >= 1)
@@ -2513,38 +2509,36 @@ static void parse_number(const char *p)
             }
         }
 
-        /* Whether 64 bits are needed to hold the constant's value */
-        if (n & 0xffffffff00000000LL || must_64bit) {
-            tok = TOK_CLLONG;
-            n1 = n >> 32;
-	} else if (lcount) {
-#ifdef TCC_LONG_ARE_64_BIT
-	    n1 = n >> 32;
-#else
-            n1 = n;
-#endif
-	    tok = TOK_CLONG;
-	} else {
-            tok = TOK_CINT;
-            n1 = n;
+        /* Determine if it needs 64 bits and/or unsigned in order to fit */
+        if (ucount == 0 && b == 10) {
+            if (lcount <= (LONG_SIZE == 4)) {
+                if (n >= 0x80000000U)
+                    lcount = (LONG_SIZE == 4) + 1;
+            }
+            if (n >= 0x8000000000000000ULL)
+                ov = 1, ucount = 1;
+        } else {
+            if (lcount <= (LONG_SIZE == 4)) {
+                if (n >= 0x100000000ULL)
+                    lcount = (LONG_SIZE == 4) + 1;
+                else if (n >= 0x80000000U)
+                    ucount = 1;
+            }
+            if (n >= 0x8000000000000000ULL)
+                ucount = 1;
         }
 
-        /* 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 if (tok == TOK_CLONG)
-                tok = TOK_CULONG;
-	    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 (ov)
+            tcc_warning("integer constant overflow");
 
+        tok = TOK_CINT;
+	if (lcount) {
+            tok = TOK_CLONG;
+            if (lcount == 2)
+                tok = TOK_CLLONG;
+	}
+	if (ucount)
+	    ++tok; /* TOK_CU... */
         tokc.i = n;
     }
     if (ch)

+ 1 - 1
win32/build-tcc.bat

@@ -113,7 +113,7 @@ for %%f in (*tcc.exe *tcc.dll) do @del %%f
 :compiler
 %CC% -o libtcc.dll -shared ..\libtcc.c %D% -DLIBTCC_AS_DLL
 @if errorlevel 1 goto :the_end
-%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE=0
+%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0"
 %CC% -o %PX%-tcc.exe ..\tcc.c %DX%
 
 @if (%TCC_FILES%)==(no) goto :files-done