1989-02-07 11:04:05 +00:00
|
|
|
/*
|
|
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
|
|
*/
|
1994-06-27 08:03:14 +00:00
|
|
|
/* $Id$ */
|
1989-02-07 11:04:05 +00:00
|
|
|
/* A R I T H M E T I C C O N V E R S I O N S */
|
|
|
|
|
|
|
|
/* This file contains the routines for the various conversions that
|
|
|
|
may befall operands in C. It is structurally a mess, but I haven't
|
|
|
|
decided yet whether I can't find the right structure or the
|
|
|
|
semantics of C is a mess.
|
|
|
|
*/
|
|
|
|
|
2017-11-10 03:22:13 +00:00
|
|
|
#include <assert.h>
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
#include <stddef.h>
|
2013-05-12 19:45:55 +00:00
|
|
|
#include "parameters.h"
|
1989-02-07 11:04:05 +00:00
|
|
|
#include <alloc.h>
|
1989-09-19 16:13:23 +00:00
|
|
|
#include <flt_arith.h>
|
1989-02-07 11:04:05 +00:00
|
|
|
#include "arith.h"
|
|
|
|
#include "sizes.h"
|
|
|
|
#include "type.h"
|
|
|
|
#include "proto.h"
|
|
|
|
#include "label.h"
|
|
|
|
#include "expr.h"
|
|
|
|
#include "Lpars.h"
|
|
|
|
#include "field.h"
|
|
|
|
#include "mes.h"
|
2019-02-18 16:42:15 +00:00
|
|
|
#include "cstoper.h"
|
|
|
|
#include "ch3bin.h"
|
|
|
|
#include "ch3.h"
|
|
|
|
#include "error.h"
|
|
|
|
|
1989-02-07 11:04:05 +00:00
|
|
|
|
|
|
|
extern char *symbol2str();
|
|
|
|
extern char options[];
|
1990-02-26 15:39:45 +00:00
|
|
|
extern arith flt_flt2arith();
|
1993-03-30 09:41:00 +00:00
|
|
|
extern label code_string();
|
1989-02-07 11:04:05 +00:00
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
/* 3.1.2.5 */
|
|
|
|
void arithbalance(register struct expr **e1p, int oper, register struct expr **e2p)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expressions *e1p and *e2p are balanced to be operands
|
|
|
|
of the arithmetic operator oper.
|
1990-04-25 15:09:51 +00:00
|
|
|
We check here if the EX_PTRDIFF flag should be retained.
|
|
|
|
They are set to zero in because one of the opreands might
|
|
|
|
have a floating type, in which case the flags shouldn't
|
|
|
|
travel upward in the expression tree.
|
1989-02-07 11:04:05 +00:00
|
|
|
*/
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
struct type *convert1, *convert2;
|
|
|
|
int t1, t2, u1, u2;
|
1989-09-19 16:13:23 +00:00
|
|
|
int shifting = (oper == LEFT || oper == RIGHT
|
|
|
|
|| oper == LEFTAB || oper == RIGHTAB);
|
1990-04-25 15:09:51 +00:00
|
|
|
int ptrdiff = 0;
|
1989-02-07 11:04:05 +00:00
|
|
|
|
|
|
|
t1 = any2arith(e1p, oper);
|
|
|
|
t2 = any2arith(e2p, oper);
|
1990-04-25 15:09:51 +00:00
|
|
|
|
|
|
|
if (int_size != pointer_size) {
|
|
|
|
if (ptrdiff = ((*e1p)->ex_flags & EX_PTRDIFF)
|
|
|
|
|| ((*e2p)->ex_flags & EX_PTRDIFF)) {
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
if (!((*e1p)->ex_flags & EX_PTRDIFF)
|
|
|
|
&& (t1 == LONG || t1 == LNGLNG))
|
1990-04-25 15:09:51 +00:00
|
|
|
ptrdiff = 0;
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
if (!((*e2p)->ex_flags & EX_PTRDIFF)
|
|
|
|
&& (t2 == LONG || t2 == LNGLNG)
|
1990-04-25 15:09:51 +00:00
|
|
|
&& !shifting)
|
|
|
|
ptrdiff = 0;
|
|
|
|
}
|
|
|
|
/* Now turn off ptrdiff flags */
|
|
|
|
(*e1p)->ex_flags &= ~EX_PTRDIFF;
|
|
|
|
(*e2p)->ex_flags &= ~EX_PTRDIFF;
|
|
|
|
}
|
|
|
|
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
/* Now t1 and t2 are either INT, LONG, LNGLNG,
|
|
|
|
FLOAT, DOUBLE, or LNGDBL
|
|
|
|
*/
|
1989-02-07 11:04:05 +00:00
|
|
|
|
|
|
|
/* If any operand has the type long double, the other operand
|
|
|
|
is converted to long double.
|
|
|
|
*/
|
1989-09-19 16:13:23 +00:00
|
|
|
/* ??? t1 == LNGDBL, t2 == DOUBLE */
|
1989-02-07 11:04:05 +00:00
|
|
|
if (t1 == LNGDBL) {
|
1992-04-21 09:54:32 +00:00
|
|
|
if (t2 != LNGDBL) {
|
|
|
|
if (t2 == DOUBLE || t2 == FLOAT)
|
|
|
|
float2float(e2p, lngdbl_type);
|
|
|
|
else
|
1989-02-07 11:04:05 +00:00
|
|
|
int2float(e2p, lngdbl_type);
|
1992-04-21 09:54:32 +00:00
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
return;
|
|
|
|
} else if (t2 == LNGDBL) {
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
if (t1 != LNGDBL) {
|
1992-04-21 09:54:32 +00:00
|
|
|
if (t1 == DOUBLE || t1 == FLOAT)
|
|
|
|
float2float(e1p, lngdbl_type);
|
|
|
|
else
|
1989-02-07 11:04:05 +00:00
|
|
|
int2float(e1p, lngdbl_type);
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If any operand has the type double, the other operand
|
|
|
|
is converted to double.
|
|
|
|
*/
|
|
|
|
if (t1 == DOUBLE) {
|
1992-04-21 09:54:32 +00:00
|
|
|
if (t2 == FLOAT)
|
|
|
|
float2float(e2p, double_type);
|
|
|
|
else if (t2 != DOUBLE)
|
1989-02-07 11:04:05 +00:00
|
|
|
int2float(e2p, double_type);
|
|
|
|
return;
|
|
|
|
} else if (t2 == DOUBLE) {
|
1992-04-21 09:54:32 +00:00
|
|
|
if (t1 == FLOAT)
|
|
|
|
float2float(e1p, double_type);
|
|
|
|
else if (t1 != DOUBLE)
|
1989-02-07 11:04:05 +00:00
|
|
|
int2float(e1p, double_type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If any operand has the type float, the other operand
|
|
|
|
is converted to float.
|
|
|
|
*/
|
|
|
|
if (t1 == FLOAT) {
|
|
|
|
if (t2 != FLOAT)
|
|
|
|
int2float(e2p, float_type);
|
|
|
|
return;
|
|
|
|
} else if (t2 == FLOAT) {
|
|
|
|
if (t1 != FLOAT)
|
|
|
|
int2float(e1p, float_type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
/* Now they are INT, LONG or LNGLNG */
|
1989-02-07 11:04:05 +00:00
|
|
|
u1 = (*e1p)->ex_type->tp_unsigned;
|
|
|
|
u2 = (*e2p)->ex_type->tp_unsigned;
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
convert1 = NULL;
|
|
|
|
convert2 = NULL;
|
|
|
|
|
|
|
|
/* If either operand is a long long, the other operand
|
|
|
|
is converted to long long; else if either operand is
|
|
|
|
a long, the other operand is converted to a long.
|
|
|
|
|
|
|
|
If one operand is signed and the other operand is
|
|
|
|
unsigned, if the signed type can represent all values
|
|
|
|
of the unsigned type, the unsigned operand is
|
|
|
|
converted to the signed type, else both operands are
|
|
|
|
converted to an unsigned type.
|
1989-02-07 11:04:05 +00:00
|
|
|
*/
|
2019-09-17 01:35:38 +00:00
|
|
|
if (shifting) {
|
|
|
|
/* In shifts like o1 << o2, never convert o1,
|
|
|
|
and let ch3bin() convert o2 to int.
|
|
|
|
*/
|
|
|
|
} else if (t1 == LNGLNG && u1 && (t2 != LNGLNG || !u2))
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
convert2 = ulnglng_type;
|
|
|
|
else if (t2 == LNGLNG && u2 && (t1 != LNGLNG || !u1))
|
|
|
|
convert1 = ulnglng_type;
|
|
|
|
else if (t1 == LNGLNG && t2 != LNGLNG && u2) {
|
|
|
|
if ((t2 == LONG ? long_size : int_size) < lnglng_size)
|
|
|
|
convert2 = lnglng_type;
|
|
|
|
else
|
|
|
|
convert1 = convert2 = ulnglng_type;
|
|
|
|
} else if (t2 == LNGLNG && t1 != LNGLNG && u1) {
|
|
|
|
if ((t1 == LONG ? long_size : int_size) < lnglng_size)
|
|
|
|
convert1 = lnglng_type;
|
|
|
|
else
|
|
|
|
convert1 = convert2 = ulnglng_type;
|
|
|
|
} else if (t1 == LNGLNG && t2 != LNGLNG)
|
|
|
|
convert2 = lnglng_type;
|
|
|
|
else if (t2 == LNGLNG && t1 != LNGLNG)
|
|
|
|
convert1 = lnglng_type;
|
|
|
|
else if (t1 == LONG && u1 && (t2 != LONG || !u2))
|
|
|
|
convert2 = ulong_type;
|
|
|
|
else if (t2 == LONG && u2 && (t1 != LONG || !u1))
|
|
|
|
convert1 = ulong_type;
|
|
|
|
else if (t1 == LONG && t2 == INT && u2) {
|
|
|
|
if (int_size < long_size)
|
|
|
|
convert2 = long_type;
|
|
|
|
else
|
|
|
|
convert1 = convert2 = ulong_type;
|
|
|
|
} else if (t2 == LONG && t1 == INT && u1) {
|
|
|
|
if (int_size < long_size)
|
|
|
|
convert1 = long_type;
|
|
|
|
else
|
|
|
|
convert1 = convert2 = ulong_type;
|
|
|
|
} else if (t1 == LONG && t2 != LONG)
|
|
|
|
convert2 = long_type;
|
|
|
|
else if (t2 == LONG && t1 != LONG)
|
|
|
|
convert1 = long_type;
|
|
|
|
|
2019-09-17 01:35:38 +00:00
|
|
|
if (convert1)
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
t1 = int2int(e1p, convert1);
|
|
|
|
if (convert2)
|
|
|
|
t2 = int2int(e2p, convert2);
|
1989-02-07 11:04:05 +00:00
|
|
|
|
1990-02-20 13:31:52 +00:00
|
|
|
u1 = (*e1p)->ex_type->tp_unsigned;
|
|
|
|
u2 = (*e2p)->ex_type->tp_unsigned;
|
|
|
|
|
1989-02-07 11:04:05 +00:00
|
|
|
/* If either operand has type unsigned int, the other operand
|
|
|
|
is converted to unsigned int.
|
|
|
|
Otherwise, both operands have type int.
|
|
|
|
*/
|
1989-09-19 16:13:23 +00:00
|
|
|
if (u1 && !u2 && !shifting)
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
t2 = int2int(e2p, uint_type);
|
1989-02-07 11:04:05 +00:00
|
|
|
else
|
1989-09-19 16:13:23 +00:00
|
|
|
if (!u1 && u2 && !shifting)
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
t1 = int2int(e1p, uint_type);
|
1990-04-25 15:09:51 +00:00
|
|
|
|
|
|
|
if (int_size != pointer_size) {
|
|
|
|
if (ptrdiff) {
|
|
|
|
(*e1p)->ex_flags |= EX_PTRDIFF;
|
|
|
|
(*e2p)->ex_flags |= EX_PTRDIFF;
|
|
|
|
}
|
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void relbalance(register struct expr **e1p, int oper, register struct expr **e2p)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expressions *e1p and *e2p are balanced to be operands
|
1989-12-12 12:52:03 +00:00
|
|
|
of the relational operator oper, or the ':'.
|
|
|
|
Care is taken to switch the operands in case of a
|
|
|
|
null-pointer constant. This is done so that ch3cast()
|
|
|
|
allows assignments of a null-pointer to a function
|
|
|
|
pointer.
|
1989-02-07 11:04:05 +00:00
|
|
|
*/
|
1989-12-12 12:52:03 +00:00
|
|
|
register struct expr *e1 = *e1p, *e2 = *e2p;
|
|
|
|
struct expr *tmpexpr;
|
|
|
|
|
|
|
|
if (e1->ex_type->tp_fund == POINTER
|
|
|
|
&& is_cp_cst(e1)
|
|
|
|
&& e1->VL_VALUE == 0) {
|
|
|
|
tmpexpr = e1;
|
|
|
|
e1 = e2;
|
|
|
|
e2 = tmpexpr;
|
|
|
|
}
|
|
|
|
if (e1->ex_type->tp_fund == POINTER)
|
|
|
|
ch3pointer(e2p, oper, e1->ex_type);
|
|
|
|
else if (e2->ex_type->tp_fund == POINTER)
|
|
|
|
ch3pointer(e1p, oper, e2->ex_type);
|
|
|
|
else if (e1->ex_type == e2->ex_type
|
|
|
|
&& e1->ex_type->tp_fund == ENUM) {}
|
1989-09-29 16:20:38 +00:00
|
|
|
else if (oper == ':'
|
1989-12-12 12:52:03 +00:00
|
|
|
&& e1->ex_type->tp_fund == VOID
|
|
|
|
&& e2->ex_type->tp_fund == VOID) {}
|
1989-02-07 11:04:05 +00:00
|
|
|
else
|
|
|
|
arithbalance(e1p, oper, e2p);
|
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void ch3pointer(struct expr **expp, int oper, register struct type *tp)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* Checks whether *expp may be compared to tp using oper,
|
1989-09-29 16:20:38 +00:00
|
|
|
as described in chapter 3.3.8 and 3.3.9.
|
1989-02-07 11:04:05 +00:00
|
|
|
tp is known to be a pointer.
|
|
|
|
*/
|
|
|
|
register struct expr *exp = *expp;
|
|
|
|
|
|
|
|
if (exp->ex_type->tp_fund == POINTER) {
|
|
|
|
if (exp->ex_type != tp)
|
1989-09-25 14:28:10 +00:00
|
|
|
ch3cast(expp, oper, tp);
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
else
|
1989-09-19 16:13:23 +00:00
|
|
|
if (is_integral_type(exp->ex_type)) {
|
|
|
|
if ((oper != EQUAL && oper != NOTEQUAL && oper != ':')
|
|
|
|
|| !(is_cp_cst(exp) && exp->VL_VALUE == 0)) {
|
|
|
|
expr_error(exp,"%s on %s and pointer",
|
|
|
|
symbol2str(oper),
|
|
|
|
symbol2str(exp->ex_type->tp_fund));
|
|
|
|
}
|
1989-09-25 14:28:10 +00:00
|
|
|
ch3cast(expp, CAST, tp);
|
1989-09-19 16:13:23 +00:00
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
else {
|
|
|
|
expr_error(exp, "%s on %s and pointer",
|
|
|
|
symbol2str(oper),
|
|
|
|
symbol2str(exp->ex_type->tp_fund)
|
|
|
|
);
|
1989-09-25 14:28:10 +00:00
|
|
|
ch3cast(expp, oper, tp);
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-02-18 16:42:15 +00:00
|
|
|
any2arith(register struct expr **expp, register int oper)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
1989-09-19 16:13:23 +00:00
|
|
|
/* Turns any expression into int_type, long_type,
|
|
|
|
float_type, double_type or lngdbl_type.
|
1989-02-07 11:04:05 +00:00
|
|
|
*/
|
|
|
|
int fund;
|
|
|
|
|
|
|
|
switch (fund = (*expp)->ex_type->tp_fund) {
|
|
|
|
case CHAR:
|
|
|
|
case SHORT:
|
2017-11-10 03:22:13 +00:00
|
|
|
assert((*expp)->ex_type->tp_size <= int_type->tp_size);
|
1989-09-19 16:13:23 +00:00
|
|
|
|
|
|
|
if ((*expp)->ex_type->tp_unsigned
|
|
|
|
&& (*expp)->ex_type->tp_size == int_type->tp_size) {
|
|
|
|
int2int(expp, uint_type);
|
|
|
|
} else {
|
|
|
|
int2int(expp, int_type);
|
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
break;
|
|
|
|
case INT:
|
|
|
|
case LONG:
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
case LNGLNG:
|
1989-02-07 11:04:05 +00:00
|
|
|
break;
|
|
|
|
case ENUM:
|
|
|
|
#ifndef LINT
|
1991-01-07 12:33:38 +00:00
|
|
|
/* we do not want this conversion for lint, since we
|
|
|
|
want to keep enums and ints separate
|
|
|
|
*/
|
1989-02-07 11:04:05 +00:00
|
|
|
int2int(expp, int_type);
|
1991-12-17 13:12:22 +00:00
|
|
|
#endif /* LINT */
|
1989-02-07 11:04:05 +00:00
|
|
|
break;
|
|
|
|
case FLOAT:
|
1989-09-19 16:13:23 +00:00
|
|
|
/* only when it is a parameter and the default promotion should
|
|
|
|
occur. Hence this code is moved to any2parameter().
|
1989-02-07 11:04:05 +00:00
|
|
|
float2float(expp, double_type);
|
|
|
|
break;
|
|
|
|
*/
|
|
|
|
case DOUBLE:
|
|
|
|
case LNGDBL:
|
|
|
|
break;
|
|
|
|
#ifndef NOBITFIELD
|
|
|
|
case FIELD:
|
|
|
|
field2arith(expp);
|
|
|
|
break;
|
1991-12-17 13:12:22 +00:00
|
|
|
#endif /* NOBITFIELD */
|
1989-02-07 11:04:05 +00:00
|
|
|
default:
|
|
|
|
expr_error(*expp, "operator %s on non-numerical operand (%s)",
|
|
|
|
symbol2str(oper), symbol2str(fund));
|
|
|
|
case ERRONEOUS:
|
|
|
|
erroneous2int(expp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (*expp)->ex_type->tp_fund;
|
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void erroneous2int(struct expr **expp)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* the (erroneous) expression *expp is replaced by an
|
|
|
|
int expression
|
|
|
|
*/
|
|
|
|
register struct expr *exp = *expp;
|
|
|
|
int flags = exp->ex_flags;
|
|
|
|
|
|
|
|
free_expression(exp);
|
|
|
|
exp = intexpr((arith)0, INT);
|
|
|
|
exp->ex_flags = (flags | EX_ERROR);
|
|
|
|
*expp = exp;
|
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
struct expr *arith2arith(struct type *tp, int oper, register struct expr *expr)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* arith2arith constructs a new expression containing a
|
|
|
|
run-time conversion between some arithmetic types.
|
|
|
|
*/
|
|
|
|
register struct expr *new = new_expr();
|
|
|
|
|
|
|
|
new->ex_file = expr->ex_file;
|
|
|
|
new->ex_line = expr->ex_line;
|
|
|
|
new->ex_type = tp;
|
|
|
|
new->ex_class = Type;
|
|
|
|
return new_oper(tp, new, oper, expr);
|
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
int int2int(struct expr **expp, register struct type *tp)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expression *expp, which is of some integral type, is
|
|
|
|
converted to the integral type tp.
|
|
|
|
*/
|
|
|
|
register struct expr *exp = *expp;
|
|
|
|
|
|
|
|
if (is_cp_cst(exp)) {
|
|
|
|
register struct type *tp1 = exp->ex_type;
|
|
|
|
|
|
|
|
exp->ex_type = tp;
|
|
|
|
if (! tp1->tp_unsigned && tp->tp_unsigned) {
|
|
|
|
/* Avoid "unreal" overflow warnings, such as
|
|
|
|
caused by f.i.:
|
|
|
|
unsigned int x = ~0;
|
|
|
|
unsigned int y = -1;
|
|
|
|
*/
|
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 <em_arith.h> and
<flt_arith.h>.
- 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 <flt_arith.h>. 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.
2019-09-05 02:14:38 +00:00
|
|
|
writh remainder = exp->VL_VALUE &
|
1989-02-07 11:04:05 +00:00
|
|
|
~full_mask[(int)(tp->tp_size)];
|
|
|
|
|
|
|
|
if (remainder == 0 ||
|
|
|
|
remainder == ~full_mask[(int)(tp->tp_size)]) {
|
|
|
|
exp->VL_VALUE &= ~remainder;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cut_size(exp);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
exp = arith2arith(tp, INT2INT, exp);
|
|
|
|
}
|
|
|
|
*expp = exp;
|
|
|
|
return exp->ex_type->tp_fund;
|
|
|
|
}
|
|
|
|
|
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 <em_arith.h> and
<flt_arith.h>.
- 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 <flt_arith.h>. 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.
2019-09-05 02:14:38 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1990-02-28 14:51:35 +00:00
|
|
|
/* With compile-time constants, we don't set fp_used, since this is done
|
|
|
|
* only when necessary in eval.c.
|
|
|
|
*/
|
2019-02-18 16:42:15 +00:00
|
|
|
void int2float(register struct expr **expp, struct type *tp)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expression *expp, which is of some integral type, is
|
|
|
|
converted to the floating type tp.
|
|
|
|
*/
|
|
|
|
register struct expr *exp = *expp;
|
1990-07-19 17:16:36 +00:00
|
|
|
int uns = exp->ex_type->tp_unsigned;
|
1989-02-07 11:04:05 +00:00
|
|
|
|
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 <em_arith.h> and
<flt_arith.h>.
- 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 <flt_arith.h>. 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.
2019-09-05 02:14:38 +00:00
|
|
|
if (is_cp_cst(exp) && fit4(exp->VL_VALUE, uns)) {
|
1989-02-07 11:04:05 +00:00
|
|
|
exp->ex_type = tp;
|
|
|
|
exp->ex_class = Float;
|
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 <em_arith.h> and
<flt_arith.h>.
- 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 <flt_arith.h>. 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.
2019-09-05 02:14:38 +00:00
|
|
|
flt_arith2flt((arith)exp->VL_VALUE, &(exp->FL_ARITH), uns);
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
1990-02-28 14:51:35 +00:00
|
|
|
else {
|
|
|
|
fp_used = 1;
|
|
|
|
*expp = arith2arith(tp, INT2FLOAT, *expp);
|
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void float2int(struct expr **expp, struct type *tp)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expression *expp, which is of some floating type, is
|
|
|
|
converted to the integral type tp.
|
|
|
|
*/
|
1989-11-22 13:58:36 +00:00
|
|
|
register struct expr *ex = *expp;
|
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 <em_arith.h> and
<flt_arith.h>.
- 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 <flt_arith.h>. 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.
2019-09-05 02:14:38 +00:00
|
|
|
|
1989-11-22 13:58:36 +00:00
|
|
|
if (is_fp_cst(ex)) {
|
|
|
|
arith ar = flt_flt2arith(&ex->FL_ARITH, tp->tp_unsigned);
|
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 <em_arith.h> and
<flt_arith.h>.
- 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 <flt_arith.h>. 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.
2019-09-05 02:14:38 +00:00
|
|
|
#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.
|
|
|
|
*/
|
1989-11-22 13:58:36 +00:00
|
|
|
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");
|
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 <em_arith.h> and
<flt_arith.h>.
- 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 <flt_arith.h>. 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.
2019-09-05 02:14:38 +00:00
|
|
|
#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;
|
|
|
|
}
|
1990-02-28 14:51:35 +00:00
|
|
|
}
|
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 <em_arith.h> and
<flt_arith.h>.
- 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 <flt_arith.h>. 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.
2019-09-05 02:14:38 +00:00
|
|
|
fp_used = 1;
|
|
|
|
*expp = arith2arith(tp, FLOAT2INT, ex);
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void float2float(register struct expr **expp, struct type *tp)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expression *expp, which is of some floating type, is
|
|
|
|
converted to the floating type tp.
|
|
|
|
There is no need for an explicit conversion operator
|
|
|
|
if the expression is a constant.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (is_fp_cst(*expp))
|
|
|
|
(*expp)->ex_type = tp;
|
1990-02-28 14:51:35 +00:00
|
|
|
else {
|
|
|
|
fp_used = 1;
|
1989-02-07 11:04:05 +00:00
|
|
|
*expp = arith2arith(tp, FLOAT2FLOAT, *expp);
|
1990-02-28 14:51:35 +00:00
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void array2pointer(register struct expr *exp)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expression, which must be an array, is converted
|
|
|
|
to a pointer.
|
|
|
|
*/
|
1989-09-19 16:13:23 +00:00
|
|
|
exp->ex_type = construct_type(POINTER, exp->ex_type->tp_up
|
|
|
|
, /* exp->ex_type->tp_typequal */ 0
|
|
|
|
, (arith)0, NO_PROTO);
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void function2pointer(register struct expr *exp)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expression, which must be a function, is converted
|
|
|
|
to a pointer to the function.
|
|
|
|
*/
|
|
|
|
exp->ex_type = construct_type(POINTER, exp->ex_type, 0,
|
|
|
|
(arith)0, NO_PROTO);
|
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void string2pointer(register struct expr *ex)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expression, which must be a string constant, is converted
|
|
|
|
to a pointer to the string-containing area.
|
|
|
|
*/
|
1993-03-30 09:41:00 +00:00
|
|
|
label lbl;
|
1989-02-07 11:04:05 +00:00
|
|
|
|
1993-03-30 09:41:00 +00:00
|
|
|
lbl = code_string(ex->SG_VALUE, ex->SG_LEN);
|
1989-02-07 11:04:05 +00:00
|
|
|
ex->ex_class = Value;
|
|
|
|
ex->VL_CLASS = Label;
|
|
|
|
ex->VL_LBL = lbl;
|
|
|
|
ex->VL_VALUE = (arith)0;
|
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void opnd2integral(register struct expr **expp, int oper)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
register int fund = (*expp)->ex_type->tp_fund;
|
|
|
|
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
if (fund != INT && fund != LONG && fund != LNGLNG) {
|
1989-02-07 11:04:05 +00:00
|
|
|
expr_error(*expp, "%s operand to %s",
|
|
|
|
symbol2str(fund), symbol2str(oper));
|
|
|
|
erroneous2int(expp);
|
|
|
|
/* fund = INT; */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void opnd2logical(register struct expr **expp, int oper)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
int fund = (*expp)->ex_type->tp_fund;
|
|
|
|
|
1991-07-01 14:10:15 +00:00
|
|
|
if (fund == FUNCTION || fund == ARRAY) {
|
|
|
|
expr_warning(*expp, "%s operand to %s",
|
|
|
|
symbol2str(fund),
|
|
|
|
symbol2str(oper));
|
|
|
|
if (fund == FUNCTION) function2pointer(*expp);
|
|
|
|
else array2pointer(*expp);
|
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
#ifndef NOBITFIELD
|
1991-07-01 14:10:15 +00:00
|
|
|
else
|
1989-02-07 11:04:05 +00:00
|
|
|
if (fund == FIELD)
|
|
|
|
field2arith(expp);
|
1991-12-17 13:12:22 +00:00
|
|
|
#endif /* NOBITFIELD */
|
1989-02-07 11:04:05 +00:00
|
|
|
switch (fund = (*expp)->ex_type->tp_fund) {
|
|
|
|
case CHAR:
|
|
|
|
case SHORT:
|
|
|
|
case INT:
|
|
|
|
case LONG:
|
Begin to add `long long` to C compiler for linux386.
Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough. Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:
union q {
long long ll;
unsigned long long ull;
int i[2];
};
Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform. The default for other platforms is to disable
long long (size -1).
In lang/cem/cemcom.ansi,
- BigPars, SmallPars: Add default size, alignment of long long.
- align.h: Add lnglng_align.
- arith.c: Convert arithmetic operands to long long or unsigned long
long when necessary; avoid conversion from long long to long.
Allow long long as an arithmetic, integral, or logical operand.
- ch3.c: Handle long long like int and long when erroneously applying
a selector, like `long long ll; ll.member` or `ll->member`. Add
long long to integral and arithmetic types.
- code.c: Add long long to type stabs for debugging.
- conversion.c: Add long long to integral conversions.
- cstoper.c: Write masks up to full_mask[8]. Add FIXME comment.
- declar.g: Parse `long long` in code.
- decspecs.c: Understand long long in type declarations.
- eval.c: Add long long to operations, to generate code like `adi 8`.
Don't use `ldc` with constant over 4 bytes.
- ival.g: Allow long long in initializations.
- main.c: Set lnglng_type and related values.
- options.c: Add option like `-Vq8.4` to set long long to size 8,
alignment 4. I chose 'q', because Perl's pack and Ruby's
Array#pack use 'q' for 64-bit or long long values; it might be a
reference to BSD's old quad_t alias for long long.
- sizes.h: Add lnglng_size.
- stab.c: Allow long long when writing the type stab for debugging.
Switch from calculating the ranges to hardcoding them in strings;
add 8-byte ranges as a special case. This also hardcodes the
unsigned 4-byte range as "0;-1". Before it was either "0;-1" or
"0;4294967295", depending on sizeof(long) in the compiler.
- struct.c: Try long long bitfield, but it will probably give the
error, "bit field type long long does not fit in a word".
- switch.c: Update comment.
- tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
- type.c, type.str: Add lnglng_type and ulnglng_type. Add function
no_long_long() to check if long long is disabled.
2019-09-02 15:24:44 +00:00
|
|
|
case LNGLNG:
|
1989-02-07 11:04:05 +00:00
|
|
|
case ENUM:
|
|
|
|
case POINTER:
|
|
|
|
case FLOAT:
|
|
|
|
case DOUBLE:
|
1989-09-19 16:13:23 +00:00
|
|
|
case LNGDBL:
|
1989-02-07 11:04:05 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
expr_error(*expp, "%s operand to %s",
|
|
|
|
symbol2str(fund), symbol2str(oper));
|
|
|
|
case ERRONEOUS:
|
|
|
|
erroneous2int(expp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-10 21:04:18 +00:00
|
|
|
void
|
2019-02-18 16:42:15 +00:00
|
|
|
opnd2test(register struct expr **expp, int oper)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
opnd2logical(expp, oper);
|
1989-10-23 13:50:27 +00:00
|
|
|
if ((*expp)->ex_class == Oper) {
|
|
|
|
switch((*expp)->OP_OPER) {
|
|
|
|
case '<':
|
|
|
|
case '>':
|
|
|
|
case LESSEQ:
|
|
|
|
case GREATEREQ:
|
|
|
|
case EQUAL:
|
|
|
|
case NOTEQUAL:
|
|
|
|
case '!':
|
|
|
|
case AND:
|
|
|
|
case OR: /* && and || also impose a test */
|
|
|
|
/* It is already a test */
|
|
|
|
return;
|
|
|
|
case ',':
|
|
|
|
opnd2test(&((*expp)->OP_RIGHT), oper);
|
|
|
|
return;
|
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
1989-10-23 13:50:27 +00:00
|
|
|
ch3bin(expp, NOTEQUAL, intexpr((arith)0, INT));
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void any2opnd(register struct expr **expp, int oper)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
if (!*expp)
|
|
|
|
return;
|
1989-11-22 13:58:36 +00:00
|
|
|
|
1989-11-22 16:41:09 +00:00
|
|
|
if (oper == SIZEOF || oper == ADDRESSOF) return;
|
1989-11-22 13:58:36 +00:00
|
|
|
|
1989-09-19 16:13:23 +00:00
|
|
|
switch ((*expp)->ex_type->tp_fund) {
|
1989-02-07 11:04:05 +00:00
|
|
|
case CHAR:
|
|
|
|
case SHORT:
|
|
|
|
case ENUM:
|
2019-02-23 16:46:05 +00:00
|
|
|
/* case FLOAT: *//* not necessary anymore */
|
1989-02-07 11:04:05 +00:00
|
|
|
any2arith(expp, oper);
|
|
|
|
break;
|
|
|
|
case ARRAY:
|
|
|
|
array2pointer(*expp);
|
|
|
|
break;
|
|
|
|
case POINTER:
|
|
|
|
if ((*expp)->ex_class == String)
|
|
|
|
string2pointer(*expp);
|
|
|
|
break;
|
1989-11-22 13:58:36 +00:00
|
|
|
case FUNCTION:
|
|
|
|
function2pointer(*expp);
|
|
|
|
break;
|
1989-02-07 11:04:05 +00:00
|
|
|
#ifndef NOBITFIELD
|
|
|
|
case FIELD:
|
|
|
|
field2arith(expp);
|
|
|
|
break;
|
1991-12-17 13:12:22 +00:00
|
|
|
#endif /* NOBITFIELD */
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:15 +00:00
|
|
|
void any2parameter(register struct expr **expp)
|
1989-02-07 13:16:02 +00:00
|
|
|
{
|
|
|
|
/* To handle default argument promotions
|
|
|
|
*/
|
|
|
|
any2opnd(expp, '(');
|
1990-04-25 15:09:51 +00:00
|
|
|
if (int_size != pointer_size)
|
|
|
|
if ((*expp)->ex_flags & EX_PTRDIFF)
|
|
|
|
expr_warning(*expp, "pointer difference caused long expression");
|
1989-02-07 13:16:02 +00:00
|
|
|
if ((*expp)->ex_type->tp_fund == FLOAT)
|
|
|
|
float2float(expp, double_type);
|
|
|
|
}
|
|
|
|
|
1989-02-07 11:04:05 +00:00
|
|
|
#ifndef NOBITFIELD
|
2019-02-18 16:42:15 +00:00
|
|
|
void field2arith(register struct expr **expp)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
|
|
|
/* The expression to extract the bitfield value from the
|
|
|
|
memory word is put in the tree.
|
|
|
|
*/
|
|
|
|
register struct type *tp = (*expp)->ex_type->tp_up;
|
|
|
|
register struct field *fd = (*expp)->ex_type->tp_field;
|
|
|
|
|
1990-05-18 10:29:57 +00:00
|
|
|
(*expp)->ex_type = word_type;
|
1989-02-07 11:04:05 +00:00
|
|
|
|
1990-03-29 10:41:46 +00:00
|
|
|
if (tp->tp_unsigned) { /* don't worry about the sign bit */
|
1990-07-19 17:16:36 +00:00
|
|
|
if (fd->fd_width >= 8 * (int)word_size)
|
1990-05-18 10:29:57 +00:00
|
|
|
(*expp)->ex_type = uword_type;
|
1989-09-25 14:28:10 +00:00
|
|
|
ch3bin(expp, RIGHT, intexpr((arith)fd->fd_shift, INT));
|
|
|
|
ch3bin(expp, '&', intexpr(fd->fd_mask, INT));
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
else { /* take care of the sign bit: sign extend if needed */
|
1990-07-19 17:16:36 +00:00
|
|
|
arith other_bits = (int)word_size * 8 - fd->fd_width;
|
1989-02-07 11:04:05 +00:00
|
|
|
|
1989-09-25 14:28:10 +00:00
|
|
|
ch3bin(expp, LEFT,
|
1990-07-19 17:16:36 +00:00
|
|
|
intexpr(other_bits - fd->fd_shift,
|
1989-02-07 11:04:05 +00:00
|
|
|
INT)
|
|
|
|
);
|
1990-07-19 17:16:36 +00:00
|
|
|
ch3bin(expp, RIGHT, intexpr(other_bits, INT));
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
}
|
1991-12-17 13:12:22 +00:00
|
|
|
#endif /* NOBITFIELD */
|
1989-02-07 11:04:05 +00:00
|
|
|
|
1989-09-19 16:13:23 +00:00
|
|
|
/* switch_sign_fp() negates the given floating constant expression,
|
|
|
|
* and frees the string representing the old value.
|
|
|
|
*/
|
2019-02-18 16:42:15 +00:00
|
|
|
void switch_sign_fp(register struct expr *expr)
|
1989-02-07 11:04:05 +00:00
|
|
|
{
|
1989-09-19 16:13:23 +00:00
|
|
|
flt_umin(&(expr->FL_ARITH));
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
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 <em_arith.h> and
<flt_arith.h>.
- 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 <flt_arith.h>. 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.
2019-09-05 02:14:38 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|