ack/lang/cem/cemcom.ansi/struct.c

462 lines
12 KiB
C
Raw Normal View History

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
/* ADMINISTRATION OF STRUCT AND UNION DECLARATIONS */
#include "parameters.h"
1989-02-07 11:04:05 +00:00
#include <alloc.h>
#include "idf.h"
1989-02-07 11:04:05 +00:00
#include "arith.h"
#include "stack.h"
#include "def.h"
#include "type.h"
#include "proto.h"
#include "struct.h"
#include "field.h"
#include "LLlex.h"
#include "Lpars.h"
#include "align.h"
#include "level.h"
#include "ch3.h"
1989-02-07 11:04:05 +00:00
#include "sizes.h"
#include "error.h"
1989-02-07 11:04:05 +00:00
/* Type of previous selector declared with a field width specified,
if any. If a selector is declared with no field with it is set to 0.
*/
static int field_busy = 0;
1989-02-07 11:04:05 +00:00
extern char options[];
1993-11-12 15:45:09 +00:00
char *symbol2str();
static void check_selector(register struct idf *, struct type *);
/* Greatest Common Divisor */
static int gcd(register int , register int );
/* Least Common Multiple */
static int lcm(register int, register int);
1989-02-07 11:04:05 +00:00
/* The semantics of the identification of structure/union tags is
obscure. Some highly regarded compilers are found out to accept,
e.g.:
f(xp) struct aap *xp; {
struct aap {char *za;};
xp->za;
}
Equally highly regarded software uses this feature, so we shall
humbly oblige.
The rules we use are:
1. A structure definition applies at the level where it is
found, unless there is a structure declaration without a
definition on an outer level, in which case the definition
is applied at that level.
2. A selector is applied on the same level as on which its
structure is being defined.
If below struct is mentioned, union is implied (and sometimes enum
as well).
*/
void add_sel( /* this is horrible */
register struct type *stp, /* type of the structure */
struct type *tp, /* type of the selector */
register struct idf *idf, /* idf of the selector */
struct sdef ***sdefpp, /* address of hook to selector definition */
arith *szp, /* pointer to struct size upto here */
struct field *fd)
1989-02-07 11:04:05 +00:00
{
/* The selector idf with type tp is added to two chains: the
selector identification chain starting at idf->id_sdef,
and to the end of the member list starting at stp->tp_sdef.
The address of the hook in the latest member (sdef) is
given in sdefpp; the hook itself must still be empty.
*/
arith offset;
struct tag *tg = stp->tp_idf->id_tag; /* or union */
1989-02-07 11:04:05 +00:00
struct sdef *sdef = idf->id_sdef;
register struct sdef *newsdef;
int lvl = tg->tg_level;
if (stp->tp_fund == STRUCT) {
#ifndef NOBITFIELD
if (fd == 0) { /* no field width specified */
offset = align(*szp, tp->tp_align);
field_busy = 0;
}
else {
/* if something is wrong, the type of the
specified selector remains unchanged; its
bitfield specifier, however, is thrown away.
*/
offset = add_field(szp, fd, &tp, idf, stp);
}
#else /* NOBITFIELD */
1989-02-07 11:04:05 +00:00
offset = align(*szp, tp->tp_align);
field_busy = 0;
#endif /* NOBITFIELD */
1989-02-07 11:04:05 +00:00
}
else { /* (stp->tp_fund == UNION) */
if (fd) offset = add_field(szp, fd, &tp, idf, stp);
1989-02-07 11:04:05 +00:00
offset = (arith)0;
}
check_selector(idf, stp);
newsdef = new_sdef();
1989-10-20 16:16:06 +00:00
/* newsdef->sd_sdef = (struct sdef *) 0; */
1989-02-07 11:04:05 +00:00
/* link into selector descriptor list of this id
*/
newsdef->next = sdef;
idf->id_sdef = newsdef;
newsdef->sd_level = lvl;
newsdef->sd_idf = idf;
newsdef->sd_stype = stp;
newsdef->sd_type = tp;
newsdef->sd_offset = offset;
#ifndef NOBITFIELD
if (tp->tp_fund == FIELD)
tp->tp_field->fd_sdef = newsdef;
#endif /* NOBITFIELD */
1989-02-07 11:04:05 +00:00
stack_idf(idf, stack_level_of(lvl));
/* link into selector definition list of the struct/union
*/
**sdefpp = newsdef;
*sdefpp = &newsdef->sd_sdef;
/* update the size of the struct/union upward */
if (stp->tp_fund == STRUCT && fd == 0) {
/* Note: the case that a bitfield is declared is
handled by add_field() !
*/
*szp = offset + size_of_type(tp, "member");
stp->tp_align = lcm(stp->tp_align, tp->tp_align);
}
else
if (stp->tp_fund == UNION && fd == 0) {
/* Note: the case that a bitfield is declared is
handled by add_field() !
*/
1989-02-07 11:04:05 +00:00
arith sel_size = size_of_type(tp, "member");
if (*szp < sel_size)
*szp = sel_size;
stp->tp_align = lcm(stp->tp_align, tp->tp_align);
}
}
static void check_selector(register struct idf *idf, struct type *stp)
1989-02-07 11:04:05 +00:00
{
/* checks if idf occurs already as a selector in
struct or union *stp. "stp" indicates the type
of the struct.
1989-02-07 11:04:05 +00:00
*/
register struct sdef *sdef = stp->tp_sdef;
while (sdef) {
if (sdef->sd_idf == idf)
error("multiple selector %s", idf->id_text);
sdef = sdef->sd_sdef;
}
}
void declare_struct(int fund, register struct idf *idf, struct type **tpp)
1989-02-07 11:04:05 +00:00
{
/* A struct, union or enum (depending on fund) with tag (!)
idf is declared, and its type (incomplete as it may be) is
returned in *tpp.
The idf may be missing (i.e. idf == 0), in which case an
anonymous struct etc. is defined.
*/
register struct tag **tgp;
register struct tag *tg;
if (*tpp) error("multiple types in declaration");
1989-02-07 11:04:05 +00:00
if (!idf)
idf = gen_idf();
tgp = &idf->id_tag;
1989-02-07 11:04:05 +00:00
tg = *tgp;
if (tg
&& tg->tg_type->tp_size < 0
&& tg->tg_type->tp_fund == fund
&& (tg->tg_level == level
|| (level >= L_FORMAL2
&& level <= L_LOCAL
&& tg->tg_level == L_FORMAL2))) {
/* An unfinished declaration has preceded it.
We just fill in the answer.
*/
1989-02-07 11:04:05 +00:00
if (tg->tg_busy) {
error("recursive declaration of struct/union %s",
idf->id_text);
declare_struct(fund, gen_idf(), tpp);
}
else {
/* hint: if (level <= L_PROTO) */
1989-02-07 11:04:05 +00:00
*tpp = tg->tg_type;
}
}
else if (tg && tg->tg_level == level && tg->tg_type->tp_size >= 0) {
1989-02-07 11:04:05 +00:00
/* There is an already defined struct/union of this name
on our level!
*/
error("redeclaration of struct/union %s", idf->id_text);
declare_struct(fund, gen_idf(), tpp);
/* to allow a second struct_declaration_pack */
}
else {
/* The struct is new. */
/* Hook in a new struct tag */
if (level <= L_PROTO)
warning("declaration of %s-tag inside parameter list",
symbol2str(fund));
1989-02-07 11:04:05 +00:00
tg = new_tag();
tg->next = *tgp;
*tgp = tg;
tg->tg_level = level;
/* and supply room for a type */
tg->tg_type = create_type(fund);
tg->tg_type->tp_align =
fund == ENUM ? int_align :
fund == STRUCT ? struct_align :
/* fund == UNION */ union_align;
tg->tg_type->tp_idf = idf;
*tpp = tg->tg_type;
stack_idf(idf, local_level);
}
}
void apply_struct(int fund,
register struct idf *idf,
struct type **tpp)
1989-02-07 11:04:05 +00:00
{
/* The occurrence of a struct, union or enum (depending on
fund) with tag idf is noted. It may or may not have been
declared before. Its type (complete or incomplete) is
returned in *tpp.
*/
register struct tag **tgp;
tgp = &idf->id_tag;
1989-02-07 11:04:05 +00:00
if (*tgp) {
if (fund != (*tgp)->tg_type->tp_fund) {
error("tag %s indicates a %s, not a %s",
idf->id_text,
symbol2str((*tgp)->tg_type->tp_fund),
symbol2str(fund));
}
1989-02-07 11:04:05 +00:00
*tpp = (*tgp)->tg_type;
}
1989-02-07 11:04:05 +00:00
else
declare_struct(fund, idf, tpp);
}
struct sdef *idf2sdef(
register struct idf *idf,
struct type *tp)
1989-02-07 11:04:05 +00:00
{
/* The identifier idf is identified as a selector
in the struct tp.
If there is no such member, give a member with the same
name.
If this fails too, a selector of type error_type is
1989-02-07 11:04:05 +00:00
created.
*/
register struct sdef **sdefp = &idf->id_sdef, *sdef;
/* Follow chain from idf, to meet tp. */
while ((sdef = *sdefp)) {
1991-03-26 09:45:20 +00:00
if (equal_type(sdef->sd_stype, tp, -999, 0)) /* ??? hack */
1989-02-07 11:04:05 +00:00
return sdef;
sdefp = &(*sdefp)->next;
}
/* Tp not met; take an identification. */
2019-02-23 16:46:05 +00:00
if ( (sdef = idf->id_sdef) ) {
1989-02-07 11:04:05 +00:00
/* There is an identification */
error("illegal use of selector %s", idf->id_text);
1989-02-07 11:04:05 +00:00
return sdef;
}
/* No luck; create an error entry. */
if (!is_anon_idf(idf))
error("unknown selector %s", idf->id_text);
*sdefp = sdef = new_sdef();
sdef->sd_idf = idf;
sdef->sd_stype = sdef->sd_type = error_type;
return sdef;
}
#if 0
int uniq_selector(register struct sdef *idf_sdef)
1989-02-07 11:04:05 +00:00
{
/* Returns true if idf_sdef (which is guaranteed to exist)
is unique for this level, i.e there is no other selector
on this level with the same name or the other selectors
with the same name have the same offset.
See /usr/src/cmd/sed/sed.h for an example of this absurd
case!
*/
register struct sdef *sdef = idf_sdef->next;
while (sdef && sdef->sd_level == idf_sdef->sd_level) {
if ( sdef->sd_type != idf_sdef->sd_type
|| sdef->sd_offset != idf_sdef->sd_offset
) {
return 0; /* ambiguity found */
}
sdef = sdef->next;
}
return 1;
}
#endif
1989-02-07 11:04:05 +00:00
#ifndef NOBITFIELD
arith
add_field(
arith *szp, /* size of struct upto here */
register struct field *fd, /* bitfield, containing width */
register struct type **fdtpp, /* type of selector */
struct idf *idf, /* name of selector */
register struct type *stp) /* current struct descriptor */
1989-02-07 11:04:05 +00:00
{
/* The address where this selector is put is returned. If the
selector with specified width does not fit in the word, or
an explicit alignment is given, a new address is needed.
Note that the fields are packed into machine words.
1989-02-07 11:04:05 +00:00
*/
1992-07-22 15:44:47 +00:00
int bits_in_type = (int) (*fdtpp)->tp_size * 8;
1989-02-07 11:04:05 +00:00
static int field_offset = (arith)0;
static struct type *current_struct = 0;
1989-11-21 11:28:56 +00:00
static int bits_declared; /* nr of bits used in *field_offset */
1989-02-07 11:04:05 +00:00
if (current_struct != stp) {
/* This struct differs from the last one
*/
field_busy = 0;
current_struct = stp;
}
if ( fd->fd_width < 0 ||
(fd->fd_width == 0 && !is_anon_idf(idf)) ||
fd->fd_width > bits_in_type
) {
error("illegal field-width specified");
*fdtpp = error_type;
return field_offset;
}
switch ((*fdtpp)->tp_fund) {
case CHAR:
case SHORT:
case ENUM:
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:
strict("non-portable field type");
case INT:
1989-02-07 11:04:05 +00:00
/* right type; size OK? */
1989-11-21 11:28:56 +00:00
if ((int) (*fdtpp)->tp_size > (int) word_size) {
1989-02-07 11:04:05 +00:00
error("bit field type %s does not fit in a word",
symbol2str((*fdtpp)->tp_fund));
*fdtpp = error_type;
return field_offset;
}
break;
default:
/* wrong type altogether */
error("field type cannot be %s",
symbol2str((*fdtpp)->tp_fund));
*fdtpp = error_type;
return field_offset;
}
if (field_busy == 0) {
/* align this selector on the next boundary :
the previous selector wasn't a bitfield.
*/
field_offset = align(*szp, int_align);
*szp = field_offset + int_size;
stp->tp_align = lcm(stp->tp_align, int_align);
1989-11-21 11:28:56 +00:00
bits_declared = 0;
1989-02-07 11:04:05 +00:00
field_busy = 1;
}
if (fd->fd_width > bits_in_type - bits_declared) {
/* field overflow: fetch next memory unit
*/
field_offset = align(*szp, int_align);
*szp = field_offset + int_size;
stp->tp_align = lcm(stp->tp_align, int_align);
bits_declared = fd->fd_width;
}
else
if (fd->fd_width == 0)
/* next field should be aligned on the next boundary.
This will take care that no field will fit in the
space allocated upto here.
*/
bits_declared = bits_in_type + 1;
else /* the bitfield fits in the current field */
bits_declared += fd->fd_width;
/* Arrived here, the place where the selector is stored in the
struct is computed.
Now we need a mask to use its value in expressions.
*/
*fdtpp = construct_type(FIELD, *fdtpp, 0, (arith)0, NO_PROTO);
(*fdtpp)->tp_field = fd;
/* Set the mask right shifted. This solution avoids the
problem of having sign extension when using the mask for
extracting the value from the field-int.
Sign extension could occur on some machines when shifting
the mask to the left.
*/
1991-10-02 13:41:33 +00:00
if (fd->fd_width >= 8*sizeof(arith)) fd->fd_mask = -1;
else fd->fd_mask = (1L << fd->fd_width) - 1;
1989-02-07 11:04:05 +00:00
if (options['r']) /* adjust the field at the right */
fd->fd_shift = bits_declared - fd->fd_width;
else /* adjust the field at the left */
fd->fd_shift = bits_in_type - bits_declared;
1989-11-21 11:28:56 +00:00
if (stp->tp_fund == UNION) bits_declared = 0;
1989-02-07 11:04:05 +00:00
return field_offset;
}
#endif /* NOBITFIELD */
1989-02-07 11:04:05 +00:00
/* some utilities */
int is_struct_or_union(register int fund)
1989-02-07 11:04:05 +00:00
{
return fund == STRUCT || fund == UNION;
}
static int gcd(register int m, register int n)
1989-02-07 11:04:05 +00:00
{
register int r;
while (n) {
r = m % n;
m = n;
n = r;
}
return m;
}
static int lcm(register int m, register int n)
1989-02-07 11:04:05 +00:00
{
return m * (n / gcd(m, n));
}