From 15950f9c9593aa55245ad2ca1b26786ec6ff0dff Mon Sep 17 00:00:00 2001 From: George Koehler Date: Wed, 4 Sep 2019 22:14:38 -0400 Subject: [PATCH] Add long long literals like 123LL to ACK C. For now, a long long literal must have the 'LL' or 'll' suffix. A literal without 'LL' or 'll' acts as before: it may become unsigned long but not long long. (For targets where int and long have the same size, some literals change from unsigned int to unsigned long.) Type `arith` may be too narrow for long long values. Add a second type `writh` for wide arithmetic, and change some variables from arith to writh. This may cause bugs if I forget to use writh, or if a conversion from writh to arith overflows. I mark some conversions with (arith) or (writh) casts. - BigPars, SmallPars: Remove SPECIAL_ARITHMETICS. This feature would change arith to a different type, but can't work, because it would conflict with definitions of arith in both and . - LLlex.c: Understand 'LL' or 'll' suffix. Cut size of constant when it overflows writh, not only when it overflows the target machine's types. (This cut might not be necessary, because we might cut it again later.) When picking signed long or unsigned long, check the target's long type, not the compiler's arith type; the old check for `val >= 0` was broken where sizeof(arith) > 4. - LLlex.h: Change struct token's tok_ival to writh, so it can hold a long long literal. - arith.c: Adjust to VL_VALUE being writh. Don't convert between float and integer at compile-time if the integer might be too wide for . Add writh2str(), because writh might be too wide for long2str(). - arith.h: Remove SPECIAL_ARITHMETICS. Declare full_mask[] here, not in several *.c files. Declare writh2str(). - ch3.c, ch3bin.c, ch3mon.c, declarator.c, statement.g: Remove obsolete casts. Adjust to VL_VALUE being writh. - conversion.c, stab.c: Don't declare full_mask[]. - cstoper.c: Use writh for constant operations on VL_VALUE, and for full_mask[]. - declar., field.c, ival.g: Add casts. - dumpidf.c: Need to #include "parameters.h" before checking DEBUG. Use writh2str, because "%ld" might not work. - eval.c, eval.h: Add casts. Use writh when writing a wide constant in EM. - expr.c: Add and remove casts. In fill_int_expr(), make expression from long long literal. In chk_cst_expr(), allow long long as constant expression, so the compiler may accept `case 123LL:` in a switch statement. - expr.str: Change struct value's vl_value and struct expr's VL_VALUE to writh, so an expression may have a long long value at compile time. - statement.g: Remove obsolete casts. - switch.c, switch.str: Use writh in case entries for switch statements, so `switch (ll) {...}` with long long ll works. - tokenname.c: Add ULNGLNG so LLlex.c can use it for literals. --- lang/cem/cemcom.ansi/BigPars | 5 -- lang/cem/cemcom.ansi/LLlex.c | 118 ++++++++++++++++++++---------- lang/cem/cemcom.ansi/LLlex.h | 2 +- lang/cem/cemcom.ansi/SmallPars | 5 -- lang/cem/cemcom.ansi/arith.c | 72 ++++++++++++++---- lang/cem/cemcom.ansi/arith.h | 34 ++++----- lang/cem/cemcom.ansi/ch3.c | 4 +- lang/cem/cemcom.ansi/ch3bin.c | 6 +- lang/cem/cemcom.ansi/ch3mon.c | 3 +- lang/cem/cemcom.ansi/code.c | 2 +- lang/cem/cemcom.ansi/conversion.c | 2 - lang/cem/cemcom.ansi/cstoper.c | 61 ++++++++------- lang/cem/cemcom.ansi/declar.g | 6 +- lang/cem/cemcom.ansi/declarator.c | 6 +- lang/cem/cemcom.ansi/dumpidf.c | 6 +- lang/cem/cemcom.ansi/eval.c | 20 ++--- lang/cem/cemcom.ansi/eval.h | 3 +- lang/cem/cemcom.ansi/expr.c | 21 ++++-- lang/cem/cemcom.ansi/expr.str | 6 +- lang/cem/cemcom.ansi/field.c | 7 +- lang/cem/cemcom.ansi/ival.g | 14 ++-- lang/cem/cemcom.ansi/stab.c | 2 - lang/cem/cemcom.ansi/statement.g | 10 +-- lang/cem/cemcom.ansi/switch.c | 16 ++-- lang/cem/cemcom.ansi/switch.str | 6 +- lang/cem/cemcom.ansi/tokenname.c | 1 + 26 files changed, 258 insertions(+), 180 deletions(-) diff --git a/lang/cem/cemcom.ansi/BigPars b/lang/cem/cemcom.ansi/BigPars index ad758c8a6..882841e64 100644 --- a/lang/cem/cemcom.ansi/BigPars +++ b/lang/cem/cemcom.ansi/BigPars @@ -117,11 +117,6 @@ /*#define NOBITFIELD 1 *//* if NOT defined, implement bitfields */ -!File: spec_arith.h -/* describes internal compiler arithmetics */ -#undef SPECIAL_ARITHMETICS /* something different from native long */ - - !File: static.h #define GSTATIC /* for large global "static" arrays */ diff --git a/lang/cem/cemcom.ansi/LLlex.c b/lang/cem/cemcom.ansi/LLlex.c index d4be03449..da18e42cb 100644 --- a/lang/cem/cemcom.ansi/LLlex.c +++ b/lang/cem/cemcom.ansi/LLlex.c @@ -17,6 +17,7 @@ #include "Lpars.h" #include "class.h" #include "sizes.h" +#include "type.h" /* no_long_long() */ #include "error.h" #include "domacro.h" #include "specials.h" /* registration of special identifiers */ @@ -37,7 +38,6 @@ int LexSave = 0; /* last character read by GetChar */ #define FLG_ESEEN 0x01 /* possibly a floating point number */ #define FLG_DOTSEEN 0x02 /* certainly a floating point number */ -extern arith full_mask[]; #ifdef LINT extern int lint_skip_comment; @@ -594,10 +594,12 @@ static void strflt2tok(char fltbuf[], struct token* ptok) static void strint2tok(char intbuf[], struct token* ptok) { register char* cp = intbuf; - int base = 10; - arith val = 0, dig, ubound; - int uns_flg = 0, lng_flg = 0, malformed = 0, ovfl = 0; - int fund; + int base = 10, dig; + unsigned writh val = 0, ubound; + int uns_flg = 0, lng_flg = 0, lnglng_flg = 0; + int malformed = 0, ovfl = 0; + unsigned writh uint_mask, ulng_mask, ulnglng_mask; + int cut, fund; assert(*cp != '-'); if (*cp == '0') @@ -611,11 +613,8 @@ static void strint2tok(char intbuf[], struct token* ptok) else base = 8; } - /* The upperbound will be the same as when computed with - * max_unsigned_arith / base (since base is even). The problem here - * is that unsigned arith is not accepted by all compilers. - */ - ubound = max_arith / (base / 2); + /* The upperbound checks if val * base would overflow. */ + ubound = ~(unsigned writh)0 / base; while (is_hex(*cp)) { @@ -626,10 +625,10 @@ static void strint2tok(char intbuf[], struct token* ptok) } else { - if (val < 0 || val > ubound) + if (val > ubound) ovfl++; val *= base; - if (val < 0 && val + dig >= 0) + if (val > val + dig) ovfl++; val += dig; } @@ -639,7 +638,16 @@ static void strint2tok(char intbuf[], struct token* ptok) while (*cp) { if (*cp == 'l' || *cp == 'L') - lng_flg++; + { + if (*cp == *(cp + 1)) + { + /* 'll' or 'LL' */ + lnglng_flg++; + cp++; + } + else + lng_flg++; + } else if (*cp == 'u' || *cp == 'U') uns_flg++; else @@ -658,51 +666,83 @@ static void strint2tok(char intbuf[], struct token* ptok) } else { - if (lng_flg > 1) + if (lng_flg + lnglng_flg > 1) lexerror("only one long suffix allowed"); if (uns_flg > 1) lexerror("only one unsigned suffix allowed"); } + + /* Get masks like 0XFFFF, 0XFFFFFFFF as unsigned values. */ + uint_mask = (unsigned writh)full_mask[(int)int_size]; + ulng_mask = (unsigned writh)full_mask[(int)long_size]; + if (lnglng_size < 0) + ulnglng_mask = 0; + else + ulnglng_mask = (unsigned writh)full_mask[(int)lnglng_size]; + + /* If a decimal literal with no suffix is too big for int + and long, then C89 tries unsigned long, but C99 tries + long long (WG14, Rationale for C99, C99RationaleV5.10.pdf, + 6.4.4.1 Integer constants). + This compiler follows C89 when the literal has no + long long suffix. + */ + cut = 0; if (ovfl) { lexwarning("overflow in constant"); - fund = ULONG; + cut = 1; /* cut the size of the constant */ } - else if (!lng_flg && (val & full_mask[(int)int_size]) == val) + else if (!lng_flg && !lnglng_flg && (val & uint_mask) == val) { - if (val >= 0 && val <= max_int) - { + if ((val & (uint_mask >> 1)) == val) fund = INT; - } - else if (int_size == long_size) - { - fund = UNSIGNED; - } else if (base == 10 && !uns_flg) - fund = LONG; + { + if ((val & (ulng_mask >> 1)) == val) + fund = LONG; + else + fund = ULONG; + } else fund = UNSIGNED; } - else if ((val & full_mask[(int)long_size]) == val) + else if (!lnglng_flg && (val & ulng_mask) == val) { - if (val >= 0) + if ((val & (ulng_mask >> 1)) == val) fund = LONG; else fund = ULONG; } - else - { /* sizeof(arith) is greater than long_size */ - assert(arith_size > long_size); - lexwarning("constant too large for target machine"); - /* cut the size to prevent further complaints */ - val &= full_mask[(int)long_size]; - fund = ULONG; - } - if (lng_flg) + else if (lnglng_flg && (val & ulnglng_mask) == val) { - /* fund can't be INT */ - if (fund == UNSIGNED) + if ((val & (ulnglng_mask >> 1)) == val) + fund = LNGLNG; + else + fund = ULNGLNG; + } + else if (lnglng_flg && no_long_long()) + fund = ERRONEOUS; + else + { + assert(sizeof(val) > long_size || + (lnglng_size >= 0 && sizeof(val) > lnglng_size)); + lexwarning("constant too large for target machine"); + cut = 1; + } + if (cut) + { + /* cut the size to prevent further complaints */ + if (lnglng_flg) + { + fund = ULNGLNG; + val &= ulnglng_mask; + } + else + { fund = ULONG; + val &= ulng_mask; + } } if (uns_flg) { @@ -710,7 +750,9 @@ static void strint2tok(char intbuf[], struct token* ptok) fund = UNSIGNED; else if (fund == LONG) fund = ULONG; + else if (fund == LNGLNG) + fund = ULNGLNG; } ptok->tk_fund = fund; - ptok->tk_ival = val; + ptok->tk_ival = (writh)val; } diff --git a/lang/cem/cemcom.ansi/LLlex.h b/lang/cem/cemcom.ansi/LLlex.h index a52f5ed78..921c255dd 100644 --- a/lang/cem/cemcom.ansi/LLlex.h +++ b/lang/cem/cemcom.ansi/LLlex.h @@ -26,7 +26,7 @@ struct token { char *tok_bts; /* row of bytes */ int tok_len; /* length of row of bytes */ } tok_string; - arith tok_ival; /* for INTEGER */ + writh tok_ival; /* for INTEGER */ char *tok_fval; /* for FLOATING */ } tok_data; }; diff --git a/lang/cem/cemcom.ansi/SmallPars b/lang/cem/cemcom.ansi/SmallPars index 01f7073b1..fa3147ea9 100644 --- a/lang/cem/cemcom.ansi/SmallPars +++ b/lang/cem/cemcom.ansi/SmallPars @@ -117,11 +117,6 @@ /*#define NOBITFIELD 1 /* if NOT defined, implement bitfields */ -!File: spec_arith.h -/* describes internal compiler arithmetics */ -#undef SPECIAL_ARITHMETICS /* something different from native long */ - - !File: static.h #define GSTATIC /* for large global "static" arrays */ diff --git a/lang/cem/cemcom.ansi/arith.c b/lang/cem/cemcom.ansi/arith.c index e1c3311c3..21a86faf3 100644 --- a/lang/cem/cemcom.ansi/arith.c +++ b/lang/cem/cemcom.ansi/arith.c @@ -371,8 +371,7 @@ int int2int(struct expr **expp, register struct type *tp) unsigned int x = ~0; unsigned int y = -1; */ - extern long full_mask[]; - long remainder = exp->VL_VALUE & + writh remainder = exp->VL_VALUE & ~full_mask[(int)(tp->tp_size)]; if (remainder == 0 || @@ -389,6 +388,16 @@ int int2int(struct expr **expp, register struct type *tp) return exp->ex_type->tp_fund; } +static int fit4(writh val, int uns) +{ + /* Does this value fit in 4 bytes? */ + unsigned writh u = (unsigned writh)val; + + if (!uns) + u += 0x80000000UL; + return (u & full_mask[4]) == u; +} + /* With compile-time constants, we don't set fp_used, since this is done * only when necessary in eval.c. */ @@ -400,10 +409,10 @@ void int2float(register struct expr **expp, struct type *tp) register struct expr *exp = *expp; int uns = exp->ex_type->tp_unsigned; - if (is_cp_cst(exp)) { + if (is_cp_cst(exp) && fit4(exp->VL_VALUE, uns)) { exp->ex_type = tp; exp->ex_class = Float; - flt_arith2flt(exp->VL_VALUE, &(exp->FL_ARITH), uns); + flt_arith2flt((arith)exp->VL_VALUE, &(exp->FL_ARITH), uns); } else { fp_used = 1; @@ -417,24 +426,35 @@ void float2int(struct expr **expp, struct type *tp) converted to the integral type tp. */ register struct expr *ex = *expp; - + if (is_fp_cst(ex)) { arith ar = flt_flt2arith(&ex->FL_ARITH, tp->tp_unsigned); - +#ifdef NOTDEF + /* Historically, we always did the conversion at + compile time. This is now wrong if type arith is + too narrow for an 8-byte integer. + */ if (flt_status == FLT_OVFL) expr_warning(ex,"overflow in float to int conversion"); else if (flt_status == FLT_UNFL) expr_warning(ex,"underflow in float to unsigned conversion"); - ex->ex_type = tp; - /* The following lines are copied from fill_int_expr */ - ex->ex_class = Value; - ex->VL_CLASS = Const; - ex->VL_VALUE = ar; - cut_size(ex); - } else { - fp_used = 1; - *expp = arith2arith(tp, FLOAT2INT, ex); +#endif /* NOTDEF */ + /* Now, we defer the conversion until run time + unless it fits in 4 bytes. + */ + if (flt_status != FLT_OVFL && flt_status != FLT_UNFL && + fit4((writh)ar, tp->tp_unsigned)) { + ex->ex_type = tp; + /* The following lines are copied from fill_int_expr */ + ex->ex_class = Value; + ex->VL_CLASS = Const; + ex->VL_VALUE = (writh)ar; + cut_size(ex); + return; + } } + fp_used = 1; + *expp = arith2arith(tp, FLOAT2INT, ex); } void float2float(register struct expr **expp, struct type *tp) @@ -640,3 +660,25 @@ void switch_sign_fp(register struct expr *expr) { flt_umin(&(expr->FL_ARITH)); } + +char *writh2str(writh val, int uns) +{ + /* Converts val to a decimal string, like + long2str(val, 10), but allows wider values. + */ + static char buf[NUMSIZE + 1]; + char *cp = &buf[NUMSIZE + 1]; + int negative = (!uns && val < 0); + unsigned writh u = (unsigned writh)val; + + if (negative) + u = -u; + *--cp = '\0'; + do { + *--cp = '0' + (u % 10); + u /= 10; + } while (u != 0); + if (negative) + *--cp = '-'; + return cp; +} diff --git a/lang/cem/cemcom.ansi/arith.h b/lang/cem/cemcom.ansi/arith.h index 65b0003de..a0b7148a7 100644 --- a/lang/cem/cemcom.ansi/arith.h +++ b/lang/cem/cemcom.ansi/arith.h @@ -5,30 +5,25 @@ /* $Id$ */ /* COMPILER ARITHMETIC */ -/* Normally the compiler does its internal arithmetics in longs - native to the source machine, which is always good for local - compilations, and generally OK too for cross compilations - downwards and sidewards. For upwards cross compilation and - to save storage on small machines, SPECIAL_ARITHMETICS will - be handy. +/* The compiler uses 2 types, arith and writh, for its internal + arithmetic. Type arith is normally long, and may be too + narrow for long long values. We can't change arith to a wider + type, because both (pulled by ) and + define arith. + + Type writh (wide arithmetic) is for values that might not fit + in arith. Normally writh is the long long native to the + source machine, which is always good for local compilations, + and generally OK too for cross compilations downwards and + sidewards. */ #ifndef ARITH_H_ #define ARITH_H_ -#include "parameters.h" - -#ifndef SPECIAL_ARITHMETICS - #include /* obtain definition of "arith" */ -#include -#else /* SPECIAL_ARITHMETICS */ - -/* All preprocessor arithmetic should be done in longs. -*/ -#define arith long /* dummy */ - -#endif /* SPECIAL_ARITHMETICS */ +#define writh long long +/* The compiler also uses "unsigned writh". */ struct expr; struct type; @@ -37,6 +32,8 @@ struct type; #define arith_sign ((arith) 1 << (arith_size * 8 - 1)) #define max_arith (~arith_sign) +extern writh full_mask[]; /* cstoper.c */ + void arithbalance(register struct expr **e1p, int oper, register struct expr **e2p); void relbalance(register struct expr **e1p, int oper, register struct expr **e2p); void ch3pointer(struct expr **expp, int oper, register struct type *tp); @@ -57,5 +54,6 @@ void any2opnd(register struct expr **expp, int oper); void any2parameter(register struct expr **expp); void field2arith(register struct expr **expp); void switch_sign_fp(register struct expr *expr); +char *writh2str(writh val, int uns); #endif /* ARITH_H_ */ diff --git a/lang/cem/cemcom.ansi/ch3.c b/lang/cem/cemcom.ansi/ch3.c index 69c75fed6..2f70c0c38 100644 --- a/lang/cem/cemcom.ansi/ch3.c +++ b/lang/cem/cemcom.ansi/ch3.c @@ -320,7 +320,7 @@ void ch3cast(register struct expr **expp, int oper, register struct type *tp) } if (oldtp->tp_up->tp_fund == VOID && is_cp_cst(exp) - && exp->VL_VALUE == (arith)0) + && exp->VL_VALUE == 0) break; /* switch */ } /* falltrough */ @@ -366,7 +366,7 @@ void ch3cast(register struct expr **expp, int oper, register struct type *tp) case NOTEQUAL: case '=': case RETURN: - if (is_cp_cst(exp) && exp->VL_VALUE == (arith)0) + if (is_cp_cst(exp) && exp->VL_VALUE == 0) break; default: expr_strict(exp, diff --git a/lang/cem/cemcom.ansi/ch3bin.c b/lang/cem/cemcom.ansi/ch3bin.c index e692e98fa..d95f5b739 100644 --- a/lang/cem/cemcom.ansi/ch3bin.c +++ b/lang/cem/cemcom.ansi/ch3bin.c @@ -206,7 +206,7 @@ void ch3bin(register struct expr **expp, int oper, struct expr *expr) where o1 == (*expp)->VL_VALUE; and ((oper == AND) || (oper == OR)) */ - if ((oper == AND) == (ex->VL_VALUE != (arith)0)) { + if ((oper == AND) == (ex->VL_VALUE != 0)) { *expp = expr; } else { @@ -224,13 +224,13 @@ void ch3bin(register struct expr **expp, int oper, struct expr *expr) where o2 == expr->VL_VALUE and ((oper == AND) || (oper == OR)) */ - if ((oper == AND) == (expr->VL_VALUE != (arith)0)) { + if ((oper == AND) == (expr->VL_VALUE != 0)) { (*expp)->ex_flags |= expr->ex_flags | EX_ILVALUE; free_expression(expr); } else { if (oper == OR) - expr->VL_VALUE = (arith)1; + expr->VL_VALUE = 1; ch3bin(expp, ',', expr); } } diff --git a/lang/cem/cemcom.ansi/ch3mon.c b/lang/cem/cemcom.ansi/ch3mon.c index a84a141f2..456f25f8a 100644 --- a/lang/cem/cemcom.ansi/ch3mon.c +++ b/lang/cem/cemcom.ansi/ch3mon.c @@ -22,7 +22,6 @@ extern char options[]; -extern arith full_mask[/*MAXSIZE + 1*/]; /* cstoper.c */ char *symbol2str(); void ch3mon(int oper, register struct expr **expp) @@ -122,7 +121,7 @@ void ch3mon(int oper, register struct expr **expp) case '-': any2arith(expp, oper); if (is_cp_cst(*expp)) { - arith o1 = (*expp)->VL_VALUE; + writh o1 = (*expp)->VL_VALUE; (*expp)->VL_VALUE = (oper == '-') ? -o1 : ((*expp)->ex_type->tp_unsigned ? diff --git a/lang/cem/cemcom.ansi/code.c b/lang/cem/cemcom.ansi/code.c index cef708cbf..762124338 100644 --- a/lang/cem/cemcom.ansi/code.c +++ b/lang/cem/cemcom.ansi/code.c @@ -602,7 +602,7 @@ void loc_init(struct expr *expr, struct idf *id) EVAL(expr, RVAL, TRUE, NO_LABEL, NO_LABEL); vl.vl_class = Name; vl.vl_data.vl_idf = id; - vl.vl_value = (arith)0; + vl.vl_value = 0; store_val(&vl, tp); } #else /* LINT */ diff --git a/lang/cem/cemcom.ansi/conversion.c b/lang/cem/cemcom.ansi/conversion.c index 13af3cef8..c2a1071b7 100644 --- a/lang/cem/cemcom.ansi/conversion.c +++ b/lang/cem/cemcom.ansi/conversion.c @@ -112,8 +112,6 @@ void conversion(register struct type *from_type, register struct type *to_type) if ((int)(to_type->tp_size) < (int)word_size && to_cnvtype != T_FLOATING ) { - extern arith full_mask[]; - if (to_cnvtype == T_SIGNED) { C_loc(to_type->tp_size); C_loc(word_size); diff --git a/lang/cem/cemcom.ansi/cstoper.c b/lang/cem/cemcom.ansi/cstoper.c index 61c3fd6e3..769c6940b 100644 --- a/lang/cem/cemcom.ansi/cstoper.c +++ b/lang/cem/cemcom.ansi/cstoper.c @@ -18,7 +18,7 @@ #include "error.h" /* full_mask[1] == 0XFF, full_mask[2] == 0XFFFF, .. */ -arith full_mask[MAXSIZE + 1]; +writh full_mask[MAXSIZE + 1]; #ifndef NOCROSS arith max_int; /* maximum integer on target machine */ arith max_unsigned; /* maximum unsigned on target machine */ @@ -31,8 +31,8 @@ void cstbin(register struct expr **expp, int oper, register struct expr *expr) expressions *expp(ld) and expr(ct), and the result restored in *expp. */ - register arith o1 = (*expp)->VL_VALUE; - register arith o2 = expr->VL_VALUE; + unsigned writh o1 = (unsigned writh)(*expp)->VL_VALUE; + unsigned writh o2 = (unsigned writh)expr->VL_VALUE; int uns = (*expp)->ex_type->tp_unsigned; assert(is_ld_cst(*expp) && is_cp_cst(expr)); @@ -49,9 +49,9 @@ void cstbin(register struct expr **expp, int oper, register struct expr *expr) break; } if (uns) - o1 /= (unsigned arith) o2; - else o1 /= o2; + else + o1 = (unsigned writh)((writh)o1 / (writh)o2); break; case '%': if (o2 == 0) { @@ -62,9 +62,9 @@ void cstbin(register struct expr **expp, int oper, register struct expr *expr) break; } if (uns) - o1 %= (unsigned arith) o2; - else o1 %= o2; + else + o1 = (unsigned writh)((writh)o1 % (writh)o2); break; case '+': o1 += o2; @@ -78,15 +78,14 @@ void cstbin(register struct expr **expp, int oper, register struct expr *expr) case RIGHT: if (o2 == 0) break; - if (uns) { - o1 = (o1 >> 1) & ~arith_sign; - o1 >>= (o2 - 1); - } - else o1 >>= o2; + if (uns) + o1 >>= o2; + else + o1 = (unsigned writh)((writh)o1 >> (writh)o2); break; case '<': { - arith tmp = o1; + writh tmp = o1; o1 = o2; o2 = tmp; @@ -94,13 +93,13 @@ void cstbin(register struct expr **expp, int oper, register struct expr *expr) /* Fall through */ case '>': if (uns) - o1 = (unsigned arith) o1 > (unsigned arith) o2; - else o1 = o1 > o2; + else + o1 = (writh)o1 > (writh)o2; break; case LESSEQ: { - arith tmp = o1; + writh tmp = o1; o1 = o2; o2 = tmp; @@ -108,9 +107,9 @@ void cstbin(register struct expr **expp, int oper, register struct expr *expr) /* Fall through */ case GREATEREQ: if (uns) - o1 = (unsigned arith) o1 >= (unsigned arith) o2; - else o1 = o1 >= o2; + else + o1 = (writh)o1 >= (writh)o2; break; case EQUAL: o1 = o1 == o2; @@ -128,7 +127,7 @@ void cstbin(register struct expr **expp, int oper, register struct expr *expr) o1 ^= o2; break; } - (*expp)->VL_VALUE = o1; + (*expp)->VL_VALUE = (writh)o1; cut_size(*expp); (*expp)->ex_flags |= expr->ex_flags; (*expp)->ex_flags &= ~EX_PARENS; @@ -140,7 +139,7 @@ void cut_size(register struct expr *expr) /* The constant value of the expression expr is made to conform to the size of the type of the expression. */ - register arith o1 = expr->VL_VALUE; + writh o1 = expr->VL_VALUE; int uns = expr->ex_type->tp_unsigned; int size = (int) expr->ex_type->tp_size; @@ -159,8 +158,8 @@ void cut_size(register struct expr *expr) o1 &= full_mask[size]; } else { - int nbits = (int) (arith_size - size) * 8; - arith remainder = o1 & ~full_mask[size]; + int nbits = (int) (sizeof(o1) - size) * 8; + writh remainder = o1 & ~full_mask[size]; if (remainder != 0 && remainder != ~full_mask[size]) if (!ResultKnown) @@ -173,22 +172,20 @@ void cut_size(register struct expr *expr) void init_cst(void) { register int i = 0; - register arith bt = (arith)0; + unsigned writh bt = 0; - /* FIXME arith is insufficient for long long. We ignore - this problem and write masks up to full_mask[8], but - masks are wrong after bt < 0. - */ - while (!(bt < 0) || i < 8) { + while (!((writh)bt < 0)) { bt = (bt << 8) + 0377, i++; if (i > MAXSIZE) fatal("array full_mask too small for this machine"); full_mask[i] = bt; } - if ((int)long_size > arith_size) - fatal("sizeof (arith) insufficient on this machine"); + /* signed comparison; lnglng_size might be -1 */ + if (long_size > (arith)sizeof(writh) || + lnglng_size > (arith)sizeof(writh)) + fatal("sizeof(writh) insufficient on this machine"); #ifndef NOCROSS - max_int = full_mask[(int)int_size] & ~(1L << ((int)int_size * 8 - 1)); - max_unsigned = full_mask[(int)int_size]; + max_int = (arith)((unsigned writh)full_mask[(int)int_size] >> 1); + max_unsigned = (arith)full_mask[(int)int_size]; #endif /* NOCROSS */ } diff --git a/lang/cem/cemcom.ansi/declar.g b/lang/cem/cemcom.ansi/declar.g index 8bec8e72d..abd7263d4 100644 --- a/lang/cem/cemcom.ansi/declar.g +++ b/lang/cem/cemcom.ansi/declar.g @@ -343,7 +343,7 @@ arrayer(arith *sizep;) constant_expression(&expr) { check_array_subscript(expr); - *sizep = expr->VL_VALUE; + *sizep = (arith)expr->VL_VALUE; free_expression(expr); } ]? @@ -430,7 +430,7 @@ enumerator(struct type *tp; arith *lp;) '=' constant_expression(&expr) { - *lp = expr->VL_VALUE; + *lp = (arith)expr->VL_VALUE; free_expression(expr); } ]? @@ -548,7 +548,7 @@ bit_expression(struct field **fd;) ':' constant_expression(&expr) { - (*fd)->fd_width = expr->VL_VALUE; + (*fd)->fd_width = (arith)expr->VL_VALUE; free_expression(expr); #ifdef NOBITFIELD error("bitfields are not implemented"); diff --git a/lang/cem/cemcom.ansi/declarator.c b/lang/cem/cemcom.ansi/declarator.c index 2795bda86..c1ce2d88f 100644 --- a/lang/cem/cemcom.ansi/declarator.c +++ b/lang/cem/cemcom.ansi/declarator.c @@ -118,11 +118,11 @@ void reject_params(register struct declarator *dc) void check_array_subscript(register struct expr *expr) { - arith size = expr->VL_VALUE; + writh size = expr->VL_VALUE; if (size < 0) { error("array size is negative"); - expr->VL_VALUE = (arith)1; + expr->VL_VALUE = 1; } else if (size == 0) { @@ -131,6 +131,6 @@ void check_array_subscript(register struct expr *expr) else if (size & ~max_unsigned) { /* absolutely ridiculous */ expr_error(expr, "overflow in array size"); - expr->VL_VALUE = (arith)1; + expr->VL_VALUE = 1; } } diff --git a/lang/cem/cemcom.ansi/dumpidf.c b/lang/cem/cemcom.ansi/dumpidf.c index 3c866b36b..c8f4e1a60 100644 --- a/lang/cem/cemcom.ansi/dumpidf.c +++ b/lang/cem/cemcom.ansi/dumpidf.c @@ -6,8 +6,8 @@ /* DUMP ROUTINES */ -#ifdef DEBUG #include "parameters.h" +#ifdef DEBUG #include #include #include @@ -442,8 +442,8 @@ static void p1_expr(int lvl, register struct expr *expr) print("(Unknown) "); break; } - print(expr->ex_type->tp_unsigned ? "%lu\n" : "%ld\n", - expr->VL_VALUE); + print("%s\n", writh2str(expr->VL_VALUE, + expr->ex_type->tp_unsigned)); break; case String: { diff --git a/lang/cem/cemcom.ansi/eval.c b/lang/cem/cemcom.ansi/eval.c index 338ca51cb..efe40bad6 100644 --- a/lang/cem/cemcom.ansi/eval.c +++ b/lang/cem/cemcom.ansi/eval.c @@ -106,7 +106,7 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label case String: /* a string constant */ if (gencode) { string2pointer(expr); - C_lae_dlb(expr->VL_LBL, expr->VL_VALUE); + C_lae_dlb(expr->VL_LBL, (arith)expr->VL_VALUE); } break; case Float: /* a floating constant */ @@ -575,7 +575,7 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label NO_LABEL, NO_LABEL); assert(is_cp_cst(right)); if (gencode) { - C_adp(right->VL_VALUE); + C_adp((arith)right->VL_VALUE); } break; case ',': @@ -858,10 +858,11 @@ void store_val(register struct value *vl, register struct type *tp) { register int inword = 0; register int indword = 0; - arith val = vl->vl_value; + writh wval = vl->vl_value; + arith val = (arith)wval; if (vl->vl_class == Const) { /* absolute addressing */ - load_cst(val, pointer_size); + load_cst(wval, pointer_size); store_block(tp->tp_size, tp->tp_align); return; } @@ -930,7 +931,8 @@ void load_val(register struct expr *expr, int rlval) register struct type *tp = expr->ex_type; int rvalue = (rlval == RVAL && expr->ex_lvalue != 0); register int inword = 0, indword = 0; - register arith val = expr->VL_VALUE; + writh wval = expr->VL_VALUE; + arith val = (arith)wval; if (expr->ex_type->tp_fund == FLOAT || expr->ex_type->tp_fund == DOUBLE @@ -938,11 +940,11 @@ void load_val(register struct expr *expr, int rlval) fp_used = 1; if (expr->VL_CLASS == Const) { if (rvalue) { /* absolute addressing */ - load_cst(val, pointer_size); + load_cst(wval, pointer_size); load_block(tp->tp_size, tp->tp_align); } else /* integer, unsigned, long, enum etc */ - load_cst(val, tp->tp_size); + load_cst(wval, tp->tp_size); return; } if (rvalue) { @@ -1022,7 +1024,7 @@ void load_val(register struct expr *expr, int rlval) } } -void load_cst(arith val, arith siz) +void load_cst(writh val, arith siz) { /* EM can't encode ldc with constant over 4 bytes. Such a constant must go into rom. @@ -1036,7 +1038,7 @@ void load_cst(arith val, arith siz) label datlab; C_df_dlb(datlab = data_label()); - C_rom_icon(long2str((long)val, 10), siz); + C_rom_icon(writh2str(val, 0), siz); C_lae_dlb(datlab, (arith)0); C_loi(siz); } diff --git a/lang/cem/cemcom.ansi/eval.h b/lang/cem/cemcom.ansi/eval.h index 337b5ac57..53a7f8d12 100644 --- a/lang/cem/cemcom.ansi/eval.h +++ b/lang/cem/cemcom.ansi/eval.h @@ -12,6 +12,7 @@ #include +#include "arith.h" /* writh */ struct expr; struct value; @@ -30,7 +31,7 @@ void assop(register struct type *type, int oper); */ void store_val(register struct value *vl, register struct type *tp); void load_val(register struct expr *expr, int rlval); -void load_cst(arith val, arith siz); +void load_cst(writh val, arith siz); #endif /* LINT */ diff --git a/lang/cem/cemcom.ansi/expr.c b/lang/cem/cemcom.ansi/expr.c index b24c408d0..3dfbc5da5 100644 --- a/lang/cem/cemcom.ansi/expr.c +++ b/lang/cem/cemcom.ansi/expr.c @@ -184,21 +184,21 @@ void idf2expr(register struct expr *expr) if (def->df_sc == ENUM) { expr->VL_CLASS = Const; - expr->VL_VALUE = def->df_address; + expr->VL_VALUE = (writh)def->df_address; } #ifndef LINT else if (def->df_sc == STATIC && def->df_level >= L_LOCAL) { expr->VL_CLASS = Label; expr->VL_LBL = def->df_address; - expr->VL_VALUE = (arith) 0; + expr->VL_VALUE = 0; } #endif /* LINT */ else { expr->VL_CLASS = Name; expr->VL_IDF = idf; - expr->VL_VALUE = (arith) 0; + expr->VL_VALUE = 0; } } @@ -270,12 +270,12 @@ arith ivalue, int fund) expr->ex_file = dot.tk_file; expr->ex_line = dot.tk_line; - fill_int_expr(expr, ivalue, fund); + fill_int_expr(expr, (writh)ivalue, fund); return expr; } void fill_int_expr(register struct expr *ex, -arith ivalue, int fund) +writh ivalue, int fund) { /* Details derived from ivalue and fund are put into the constant integer expression ex. @@ -294,6 +294,16 @@ arith ivalue, int fund) case ULONG: ex->ex_type = ulong_type; break; + case LNGLNG: + ex->ex_type = lnglng_type; + break; + case ULNGLNG: + ex->ex_type = ulnglng_type; + break; + case ERRONEOUS: /* 123LL when no_long_long() */ + ex->ex_type = error_type; + ex->ex_flags |= EX_ERROR; + break; default: crash("(fill_int_expr) bad fund %s\n", symbol2str(fund)); /*NOTREACHED*/ @@ -406,6 +416,7 @@ void chk_cst_expr(struct expr **expp) case INT: case ENUM: case LONG: + case LNGLNG: if (is_ld_cst(expr)) { return; diff --git a/lang/cem/cemcom.ansi/expr.str b/lang/cem/cemcom.ansi/expr.str index 97ac5b1f9..51718ace6 100644 --- a/lang/cem/cemcom.ansi/expr.str +++ b/lang/cem/cemcom.ansi/expr.str @@ -23,7 +23,7 @@ struct value { int vl_class; /* Const, Name or Label */ - arith vl_value; /* constant value or offset */ + writh vl_value; /* constant value or offset */ union { struct idf *vl_idf; /* external name */ label vl_lbl; /* compiler-generated label */ @@ -100,8 +100,6 @@ struct expr { #define ISNAME(e) ((e)->ex_class == Value && (e)->VL_CLASS == Name) #define ISCOMMA(e) ((e)->ex_class == Oper && (e)->OP_OPER == INITCOMMA) -extern struct expr *intexpr(), *new_oper(); - /* ALLOCDEF "expr" 20 */ @@ -113,7 +111,7 @@ void string2expr(register struct expr **expp, char *str, int len); void int2expr(struct expr *expr); void float2expr(register struct expr *expr); struct expr* intexpr(arith ivalue, int fund); -void fill_int_expr(register struct expr *ex,arith ivalue, int fund); +void fill_int_expr(register struct expr *ex, writh ivalue, int fund); struct expr *new_oper(struct type *tp, register struct expr *e1, int oper, register struct expr *e2); void chk_cst_expr(struct expr **expp); diff --git a/lang/cem/cemcom.ansi/field.c b/lang/cem/cemcom.ansi/field.c index d1b014c01..7d7f27726 100644 --- a/lang/cem/cemcom.ansi/field.c +++ b/lang/cem/cemcom.ansi/field.c @@ -28,8 +28,6 @@ #include "eval.h" -extern arith full_mask[]; /* cstoper.c */ - /* Eval_field() evaluates expressions involving bit fields. The various instructions are not yet optimised in the expression tree and are therefore dealt with in this function. @@ -136,6 +134,8 @@ void store_field( register struct expr *leftop, arith tmpvar) { + arith high_mask; + C_loc(fd->fd_mask); C_and(word_size); if (code == TRUE) @@ -145,7 +145,8 @@ void store_field( C_slu(word_size); else C_sli(word_size); - C_loc(~((fd->fd_mask << fd->fd_shift) | ~full_mask[(int)word_size])); + high_mask = (arith)~full_mask[(int)word_size]; + C_loc(~((fd->fd_mask << fd->fd_shift) | high_mask)); if (leftop->ex_depth == 0) { /* simple case */ load_val(leftop, RVAL); C_and(word_size); diff --git a/lang/cem/cemcom.ansi/ival.g b/lang/cem/cemcom.ansi/ival.g index 995d46248..05fcc4881 100644 --- a/lang/cem/cemcom.ansi/ival.g +++ b/lang/cem/cemcom.ansi/ival.g @@ -544,11 +544,11 @@ void check_ival(struct expr **expp, register struct type *tp) if (idf->id_def->df_type->tp_fund == FUNCTION) C_con_pnam(idf->id_text); else /* e.g., int a; int *p = &a; */ - C_con_dnam(idf->id_text, expr->VL_VALUE); + C_con_dnam(idf->id_text, (arith)expr->VL_VALUE); } else { assert(expr->VL_CLASS == Label); - C_con_dlb(expr->VL_LBL, expr->VL_VALUE); + C_con_dlb(expr->VL_LBL, (arith)expr->VL_VALUE); } break; case FLOAT: @@ -595,7 +595,7 @@ and also to prevent runtime coercions for compile-time constants. print_expr("init-expr after cast", expr); #endif /* DEBUG */ if (is_cp_cst(expr)) - put_bf(tp, expr->VL_VALUE); + put_bf(tp, (arith)expr->VL_VALUE); else illegal_init_cst(expr); break; @@ -701,7 +701,7 @@ void put_bf(struct type *tp, arith val) field |= (val & fd->fd_mask) << fd->fd_shift; if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) { /* the selector was the last stored at this address */ - exp.VL_VALUE = field; + exp.VL_VALUE = (writh)field; con_int(&exp); field = (arith)0; offset = (arith)-1; @@ -739,11 +739,11 @@ void con_int(register struct expr *ex) assert(is_cp_cst(ex)); if (tp->tp_unsigned) - C_con_ucon(long2str((long)ex->VL_VALUE, -10), tp->tp_size); + C_con_ucon(writh2str(ex->VL_VALUE, 1), tp->tp_size); else if (tp->tp_size == word_size) - C_con_cst(ex->VL_VALUE); + C_con_cst((arith)ex->VL_VALUE); else - C_con_icon(long2str((long)ex->VL_VALUE, 10), tp->tp_size); + C_con_icon(writh2str(ex->VL_VALUE, 0), tp->tp_size); } void illegal_init_cst(struct expr *ex) diff --git a/lang/cem/cemcom.ansi/stab.c b/lang/cem/cemcom.ansi/stab.c index 5a002301f..864201aa1 100644 --- a/lang/cem/cemcom.ansi/stab.c +++ b/lang/cem/cemcom.ansi/stab.c @@ -32,8 +32,6 @@ #include "level.h" #include "print.h" -extern long full_mask[]; - #define INCR_SIZE 64 static struct db_str diff --git a/lang/cem/cemcom.ansi/statement.g b/lang/cem/cemcom.ansi/statement.g index 3d1dcd4f2..d58ec4b6a 100644 --- a/lang/cem/cemcom.ansi/statement.g +++ b/lang/cem/cemcom.ansi/statement.g @@ -147,7 +147,7 @@ if_statement /* The comparison has been optimized to a 0 or 1. */ - if (expr->VL_VALUE == (arith)0) { + if (expr->VL_VALUE == 0) { C_bra(l_false); } /* else fall through */ @@ -210,7 +210,7 @@ while_statement { opnd2test(&expr, WHILE); if (is_cp_cst(expr)) { - if (expr->VL_VALUE == (arith)0) { + if (expr->VL_VALUE == 0) { C_bra(l_break); } } @@ -264,11 +264,11 @@ do_statement { opnd2test(&expr, WHILE); if (is_cp_cst(expr)) { - if (expr->VL_VALUE == (arith)1) { + if (expr->VL_VALUE == 1) { C_bra(l_body); } #ifdef LINT - end_do_stmt(1, expr->VL_VALUE != (arith)0); + end_do_stmt(1, expr->VL_VALUE != 0); #endif /* LINT */ } else { @@ -313,7 +313,7 @@ for_statement { opnd2test(&e_test, FOR); if (is_cp_cst(e_test)) { - if (e_test->VL_VALUE == (arith)0) { + if (e_test->VL_VALUE == 0) { C_bra(l_break); } } diff --git a/lang/cem/cemcom.ansi/switch.c b/lang/cem/cemcom.ansi/switch.c index 7db1f28bd..95da9aabf 100644 --- a/lang/cem/cemcom.ansi/switch.c +++ b/lang/cem/cemcom.ansi/switch.c @@ -32,13 +32,13 @@ extern char options[]; int density = DENSITY; -static int compact(int nr, arith low, arith up) +static int compact(int nr, writh low, writh up) { /* Careful! up - low might not fit in an arith. And then, the test "up-low < 0" might also not work to detect this situation! Or is this just a bug in the M68020/M68000? */ - arith diff = up - low; + writh diff = up - low; return (nr == 0 || (diff >= 0 && diff / nr <= (density - 1))); } @@ -117,10 +117,10 @@ void code_endswitch(void) C_rom_ilb(sh->sh_default); if (compact(sh->sh_nrofentries, sh->sh_lowerbd, sh->sh_upperbd)) { /* CSA */ - register arith val; + writh val; - C_rom_icon(long2str((long)sh->sh_lowerbd,10), size); - C_rom_icon(long2str((long)(sh->sh_upperbd - sh->sh_lowerbd),10), + C_rom_icon(writh2str(sh->sh_lowerbd, 0), size); + C_rom_icon(writh2str(sh->sh_upperbd - sh->sh_lowerbd, 0), size); ce = sh->sh_entries; for (val = sh->sh_lowerbd; val <= sh->sh_upperbd; val++) { @@ -136,10 +136,10 @@ void code_endswitch(void) C_csa(size); } else { /* CSB */ - C_rom_icon(long2str((long)sh->sh_nrofentries,10),size); + C_rom_icon(writh2str(sh->sh_nrofentries, 0), size); for (ce = sh->sh_entries; ce; ce = ce->next) { /* generate the entries: value + prog.label */ - C_rom_icon(long2str((long)ce->ce_value,10),size); + C_rom_icon(writh2str(ce->ce_value, 0), size); C_rom_ilb(ce->ce_label); } C_lae_dlb(tablabel, (arith)0); /* perform the switch */ @@ -162,7 +162,7 @@ void code_endswitch(void) void code_case(struct expr *expr) { - register arith val; + writh val; register struct case_entry *ce; register struct switch_hdr *sh = switch_stack; diff --git a/lang/cem/cemcom.ansi/switch.str b/lang/cem/cemcom.ansi/switch.str index 94a45ca42..3ba693498 100644 --- a/lang/cem/cemcom.ansi/switch.str +++ b/lang/cem/cemcom.ansi/switch.str @@ -22,8 +22,8 @@ struct switch_hdr { int sh_nrofentries; struct type *sh_type; struct expr *sh_expr; - arith sh_lowerbd; - arith sh_upperbd; + writh sh_lowerbd; + writh sh_upperbd; struct case_entry *sh_entries; }; @@ -32,7 +32,7 @@ struct switch_hdr { struct case_entry { struct case_entry *next; label ce_label; - arith ce_value; + writh ce_value; }; /* ALLOCDEF "case_entry" 20 */ diff --git a/lang/cem/cemcom.ansi/tokenname.c b/lang/cem/cemcom.ansi/tokenname.c index fb3bae349..0a86f480e 100644 --- a/lang/cem/cemcom.ansi/tokenname.c +++ b/lang/cem/cemcom.ansi/tokenname.c @@ -107,6 +107,7 @@ struct tokenname tkfunny[] = { /* internal keywords */ {LNGLNG, "long long"}, {LNGDBL, "long double"}, {ULONG, "unsigned long"}, + {ULNGLNG, "unsigned long long"}, {ARRAY, "array"}, {FUNCTION, "function"},