123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 |
- /* $Header$ */
- /* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */
- #include "debug.h"
- #include "nobitfield.h"
- #include "string.h"
- #include "em.h"
- #include "arith.h"
- #include "align.h"
- #include "label.h"
- #include "expr.h"
- #include "type.h"
- #include "struct.h"
- #include "field.h"
- #include "assert.h"
- #include "Lpars.h"
- #include "class.h"
- #include "sizes.h"
- #include "idf.h"
- #include "level.h"
- #include "def.h"
- extern char *symbol2str();
- #define con_byte(c) C_co_ucon(itos((long)(c) & 0xFF), (arith)1)
- struct expr *do_array(), *do_struct(), *IVAL();
- struct expr *strings = 0; /* list of string constants within initialiser */
- static ConStarted; /* indicates the generation of a 'con' pseudo */
- /* do_ival() performs the initialisation of a global variable
- of type tp with the initialisation expression expr by calling IVAL().
- Guided by type tp, the expression is evaluated.
- */
- do_ival(tpp, expr)
- struct type **tpp;
- struct expr *expr;
- {
- ConStarted = 0;
- if (IVAL(tpp, expr) != 0)
- too_many_initialisers(expr);
- /* The following loop declares the string constants
- used in the initialisation.
- The code for these string constants may not appear in
- the code of the initialisation because a data label
- in EM causes the current initialisation to be completed.
- E.g. char *s[] = {"hello", "world"};
- */
- C_con_end();
- while (strings != 0) {
- C_ndlb(strings->SG_DATLAB);
- C_con_begin();
- C_co_scon(strings->SG_VALUE, (arith)0);
- C_con_end();
- strings = strings->next;
- }
- }
- /* store_string() collects the string constants appearing in an
- initialisation.
- */
- store_string(expr)
- struct expr *expr;
- {
- expr->next = strings;
- strings = expr;
- }
- /* IVAL() recursively guides the initialisation expression through the
- different routines for the different types of initialisation:
- - array initialisation
- - struct initialisation
- - fundamental type initialisation
- Upto now, the initialisation of a union is not allowed!
- An initialisation expression tree consists of normal expressions
- which can be joined together by ',' nodes, which operator acts
- like the lisp function "cons" to build lists.
- IVAL() returns a pointer to the remaining expression tree.
- */
- struct expr *
- IVAL(tpp, expr)
- struct type **tpp; /* type of global variable */
- struct expr *expr; /* initialiser expression */
- {
- register struct type *tp = *tpp;
-
- switch (tp->tp_fund) {
- case ARRAY: /* array initialisation */
- if (valid_type(tp->tp_up, "array element") == 0)
- return 0;
- if (ISCOMMA(expr)) {
- /* list of initialisation expressions */
- return do_array(expr, tpp);
- }
- /* There might be an initialisation of a string
- like char s[] = "I am a string"
- */
- if (tp->tp_up->tp_fund == CHAR && expr->ex_class == String)
- init_string(tpp, expr);
- else /* " int i[24] = 12;" */
- check_and_pad(expr, tpp);
- return 0; /* nothing left */
- case STRUCT: /* struct initialisation */
- if (valid_type(tp, "struct") == 0)
- return 0;
- if (ISCOMMA(expr)) {
- /* list of initialisation expressions */
- return do_struct(expr, tp);
- }
- /* "struct foo f = 12;" */
- check_and_pad(expr, tpp);
- return 0;
- case UNION: /* sorry, but .... */
- error("union initialisation not allowed");
- return 0;
- case ERRONEOUS:
- return 0;
- default: /* fundamental type */
- if (ISCOMMA(expr)) { /* " int i = {12};" */
- if (IVAL(tpp, expr->OP_LEFT) != 0)
- too_many_initialisers(expr);
- /* return remainings of the list for the
- other members of the aggregate, if this
- item belongs to an aggregate.
- */
- return expr->OP_RIGHT;
- }
- else { /* "int i = 12;" */
- check_ival(expr, tp);
- return 0;
- }
- }
- /* NOTREACHED */
- }
- /* do_array() initialises the members of an array described
- by type tp with the expressions in expr.
- Two important cases:
- - the number of members is known
- - the number of members is not known
- In the latter case, do_array() digests the whole expression
- tree it is given.
- In the former case, do_array() eats as many members from
- the expression tree as are needed for the array.
- If there are not sufficient members for the array, the remaining
- members are padded with zeroes
- */
- struct expr *
- do_array(expr, tpp)
- struct expr *expr;
- struct type **tpp;
- {
- /* it is certain that ISCOMMA(expr) and tp->tp_fund == ARRAY */
- register struct type *tp = *tpp;
- register arith elem_count;
-
- ASSERT(tp->tp_fund == ARRAY);
- /* the following test catches initialisations like
- char c[] = {"just a string"};
- or
- char d[] = {{"just another string"}}
- The use of the brackets causes this problem.
- Note: although the implementation of such initialisations
- is completely foolish, we did it!! (no applause, thank you)
- */
- if (tp->tp_up->tp_fund == CHAR) {
- register struct expr *f = expr->OP_LEFT;
- register struct expr *g = 0;
- while (ISCOMMA(f)) { /* eat the brackets!!! */
- g = f;
- f = f->OP_LEFT;
- }
- if (f->ex_class == String) { /* hallelujah, it's a string! */
- init_string(tpp, f);
- return g ? g->OP_RIGHT : expr->OP_RIGHT;
- }
- /* else: just go on with the next part of this function */
- if (g != 0)
- expr = g;
- }
- if (tp->tp_size == (arith)-1) {
- /* declared with unknown size: [] */
- for (elem_count = 0; expr; elem_count++) {
- /* eat whole initialisation expression */
- if (ISCOMMA(expr->OP_LEFT)) {
- /* the member expression is embraced */
- if (IVAL(&(tp->tp_up), expr->OP_LEFT) != 0)
- too_many_initialisers(expr);
- expr = expr->OP_RIGHT;
- }
- else {
- if (aggregate_type(tp->tp_up))
- expr = IVAL(&(tp->tp_up), expr);
- else {
- check_ival(expr->OP_LEFT, tp->tp_up);
- expr = expr->OP_RIGHT;
- }
- }
- }
- /* set the proper size */
- *tpp = construct_type(ARRAY, tp->tp_up, elem_count);
- }
- else { /* the number of members is already known */
- arith dim = tp->tp_size / tp->tp_up->tp_size;
- for (elem_count = 0; elem_count < dim && expr; elem_count++) {
- if (ISCOMMA(expr->OP_LEFT)) {
- /* embraced member initialisation */
- if (IVAL(&(tp->tp_up), expr->OP_LEFT) != 0)
- too_many_initialisers(expr);
- expr = expr->OP_RIGHT;
- }
- else {
- if (aggregate_type(tp->tp_up))
- /* the member is an aggregate */
- expr = IVAL(&(tp->tp_up), expr);
- else {
- check_ival(expr->OP_LEFT, tp->tp_up);
- expr = expr->OP_RIGHT;
- }
- }
- }
- if (expr && elem_count == dim)
- /* all the members are initialised but there
- remains a part of the expression tree which
- is returned
- */
- return expr;
- if ((expr == 0) && elem_count < dim) {
- /* the expression tree is completely absorbed
- but there are still members which must be
- initialised with zeroes
- */
- do
- pad(tp->tp_up);
- while (++elem_count < dim);
- }
- }
- return 0;
- }
- /* do_struct() initialises a struct of type tp with the expression expr.
- The main loop is just controlled by the definition of the selectors
- during which alignment is taken care of.
- */
- struct expr *
- do_struct(expr, tp)
- struct expr *expr;
- struct type *tp;
- {
- /* tp is a STRUCT and expr->OP_OPER == INITCOMMA */
- struct sdef *sd = tp->tp_sdef;
- arith bytes_upto_here = (arith)0;
- arith last_offset = (arith)-1;
- /* as long as there are selectors and there is an initialiser.. */
- while (sd && expr) {
- if (ISCOMMA(expr->OP_LEFT)) { /* embraced expression */
- if (IVAL(&(sd->sd_type), expr->OP_LEFT) != 0)
- too_many_initialisers(expr);
- expr = expr->OP_RIGHT;
- }
- else {
- if (aggregate_type(sd->sd_type))
- /* selector is an aggregate itself */
- expr = IVAL(&(sd->sd_type), expr);
- else {
- #ifdef NOBITFIELD
- /* fundamental type, not embraced */
- check_ival(expr->OP_LEFT, sd->sd_type);
- expr = expr->OP_RIGHT;
- #else
- if (is_anon_idf(sd->sd_idf))
- /* a hole in the struct due to
- the use of ";:n;" in a struct
- definition.
- */
- put_bf(sd->sd_type, (arith)0);
- else {
- /* fundamental type, not embraced */
- check_ival(expr->OP_LEFT,
- sd->sd_type);
- expr = expr->OP_RIGHT;
- }
- #endif NOBITFIELD
- }
- }
- /* align upto the next selector boundary */
- if (sd->sd_sdef)
- bytes_upto_here += zero_bytes(sd);
- if (last_offset != sd->sd_offset) {
- /* don't take the field-width more than once */
- bytes_upto_here += size_of_type(sd->sd_type, "selector");
- last_offset = sd->sd_offset;
- }
- sd = sd->sd_sdef;
- }
- /* perfect fit if (expr && (sd == 0)) holds */
- if ((expr == 0) && (sd != 0)) {
- /* there are selectors left which must be padded with
- zeroes
- */
- do {
- pad(sd->sd_type);
- /* take care of the alignment restrictions */
- if (sd->sd_sdef)
- bytes_upto_here += zero_bytes(sd);
- /* no field thrown-outs here */
- bytes_upto_here += size_of_type(sd->sd_type, "selector");
- } while (sd = sd->sd_sdef);
- }
- /* keep on aligning... */
- while (bytes_upto_here++ < tp->tp_size)
- con_byte(0);
- return expr;
- }
- /* check_and_pad() is given a simple initialisation expression
- where the type can be either a simple or an aggregate type.
- In the latter case, only the first member is initialised and
- the rest is zeroed.
- */
- check_and_pad(expr, tpp)
- struct expr *expr;
- struct type **tpp;
- {
- /* expr is of a fundamental type */
- struct type *tp = *tpp;
- if (tp->tp_fund == ARRAY) {
- if (valid_type(tp->tp_up, "array element") == 0)
- return;
- check_and_pad(expr, &(tp->tp_up)); /* first member */
- if (tp->tp_size == (arith)-1)
- /* no size specified upto here: just
- set it to the size of one member.
- */
- tp = *tpp =
- construct_type(ARRAY, tp->tp_up, (arith)1);
- else {
- register dim = tp->tp_size / tp->tp_up->tp_size;
- /* pad remaining members with zeroes */
- while (--dim > 0)
- pad(tp->tp_up);
- }
- }
- else
- if (tp->tp_fund == STRUCT) {
- register struct sdef *sd = tp->tp_sdef;
- if (valid_type(tp, "struct") == 0)
- return;
- check_and_pad(expr, &(sd->sd_type));
- /* Next selector is aligned by adding extra zeroes */
- if (sd->sd_sdef)
- zero_bytes(sd);
- while (sd = sd->sd_sdef) { /* pad remaining selectors */
- pad(sd->sd_type);
- if (sd->sd_sdef)
- zero_bytes(sd);
- }
- }
- else /* simple type */
- check_ival(expr, tp);
- }
- /* pad() fills an element of type tp with zeroes.
- If the element is an aggregate, pad() is called recursively.
- */
- pad(tp)
- struct type *tp;
- {
- if (ConStarted == 0) {
- C_con_begin();
- ConStarted = 1;
- }
- switch (tp->tp_fund) {
- case ARRAY:
- {
- register long dim;
- if (valid_type(tp->tp_up, "array element") == 0)
- return;
- dim = tp->tp_size / tp->tp_up->tp_size;
- /* Assume the dimension is known */
- while (dim-- > 0)
- pad(tp->tp_up);
- break;
- }
- case STRUCT:
- {
- register struct sdef *sdef = tp->tp_sdef;
- if (valid_type(tp, "struct") == 0)
- return;
- do {
- pad(sdef->sd_type);
- if (sdef->sd_sdef)
- zero_bytes(sdef);
- } while (sdef = sdef->sd_sdef);
- break;
- }
- #ifndef NOBITFIELD
- case FIELD:
- put_bf(tp, (arith)0);
- break;
- #endif NOBITFIELD
- case INT:
- case SHORT:
- case LONG:
- case CHAR:
- case ENUM:
- case POINTER:
- C_co_ucon("0", tp->tp_size);
- break;
- case FLOAT:
- case DOUBLE:
- C_co_fcon("0", tp->tp_size);
- break;
- case UNION:
- error("initialisation of unions not allowed");
- break;
- case ERRONEOUS:
- break;
- default:
- crash("(generate) bad fundamental type %s\n",
- symbol2str(tp->tp_fund));
- }
- }
- /* check_ival() checks whether the initialisation of an element
- of a fundamental type is legal and, if so, performs the initialisation
- by directly generating the necessary code.
- No further comment is needed to explain the internal structure
- of this straightforward function.
- */
- check_ival(expr, type)
- struct expr *expr;
- struct type *type;
- {
- /* The philosophy here is that ch7cast puts an explicit
- conversion node in front of the expression if the types
- are not compatible. In this case, the initialisation is
- not legal. ???
- */
-
- switch (type->tp_fund) {
- case CHAR:
- case SHORT:
- case INT:
- case LONG:
- if (expr->ex_class == Oper || expr->VL_IDF != 0) {
- illegal_init_cst(expr);
- break;
- }
- ch7cast(&expr, '=', type);
- if (ConStarted == 0) {
- C_con_begin();
- ConStarted = 1;
- }
- con_int(expr);
- break;
- #ifndef NOBITFIELD
- case FIELD:
- if (expr->ex_class == Oper || expr->VL_IDF != 0) {
- illegal_init_cst(expr);
- break;
- }
- ch7cast(&expr, '=', type->tp_up);
- put_bf(type, expr->VL_VALUE);
- break;
- #endif NOBITFIELD
- case ENUM:
- if (expr->ex_class == Oper) {
- illegal_init_cst(expr);
- break;
- }
- ch7cast(&expr, '=', type);
- if (ConStarted == 0) {
- C_con_begin();
- ConStarted = 1;
- }
- con_int(expr);
- break;
- case FLOAT:
- case DOUBLE:
- ch7cast(&expr, '=', type);
- if (ConStarted == 0) {
- C_con_begin();
- ConStarted = 1;
- }
- if (expr->ex_class == Float)
- C_co_fcon(expr->FL_VALUE, expr->ex_type->tp_size);
- else
- if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) {
- expr = expr->OP_RIGHT;
- if (expr->ex_class == Value && expr->VL_IDF == 0)
- C_co_fcon(itos(expr->VL_VALUE), type->tp_size);
- else
- illegal_init_cst(expr);
- }
- else
- illegal_init_cst(expr);
- break;
- case POINTER:
- ch7cast(&expr, '=', type);
- switch (expr->ex_class) {
- case Oper:
- illegal_init_cst(expr);
- break;
- case String: /* char *s = "...." */
- {
- label datlab = data_label();
-
- if (ConStarted)
- C_con_end();
- else
- ConStarted = 1; /* ??? */
- C_ina_pt(datlab);
- C_con_begin();
- C_co_ndlb(datlab, (arith)0);
- expr->SG_DATLAB = datlab;
- store_string(expr);
- break;
- }
- case Value:
- {
- struct value *vl = &(expr->ex_object.ex_value);
- struct idf *idf = vl->vl_idf;
- ASSERT(expr->ex_type->tp_fund == POINTER);
- if (ConStarted == 0) {
- C_con_begin();
- ConStarted = 1;
- }
- if (expr->ex_type->tp_up->tp_fund == FUNCTION) {
- if (idf)
- C_co_pnam(idf->id_text);
- else /* int (*func)() = 0 */
- con_int(expr);
- }
- else
- if (idf) {
- register struct def *def = idf->id_def;
- if (def->df_level >= L_LOCAL) {
- if (def->df_sc != STATIC)
- /* Eg. int a;
- static int *p = &a;
- */
- expr_error(expr,
- "illegal initialisation");
- else
- C_co_ndlb((label)def->df_address,
- vl->vl_value);
- }
- else
- C_co_dnam(idf->id_text, vl->vl_value);
- }
- else
- con_int(expr);
- break;
- }
- default:
- crash("(check_ival) illegal initialisation expression");
- }
- break;
- case ERRONEOUS:
- break;
- default:
- crash("(check_ival) bad fundamental type %s",
- symbol2str(type->tp_fund));
- }
- }
- /* init_string() initialises an array of characters by specifying
- a string constant.
- Escaped characters should be converted into its corresponding
- ASCII character value. E.g. '\000' -> (char) 0.
- Alignment is taken care of.
- */
- init_string(tpp, expr)
- struct type **tpp; /* type tp = array of characters */
- struct expr *expr;
- {
- register struct type *tp = *tpp;
- register arith length;
- char *s = expr->SG_VALUE;
- arith ntopad;
- length = prepare_string(s);
- if (tp->tp_size == (arith)-1) {
- /* set the dimension */
- tp = *tpp = construct_type(ARRAY, tp->tp_up, length);
- ntopad = align(tp->tp_size, word_align) - tp->tp_size;
- }
- else {
- arith dim = tp->tp_size / tp->tp_up->tp_size;
- ntopad = align(dim, word_align) - length;
- if (length > dim)
- expr_error(expr,
- "too many characters in initialiser string");
- }
- if (ConStarted == 0) {
- C_con_begin();
- ConStarted = 1;
- }
- /* throw out the characters of the already prepared string */
- do
- con_byte(*s++);
- while (--length > 0);
- /* pad the allocated memory (the alignment has been calculated) */
- while (ntopad-- > 0)
- con_byte(0);
- }
- /* prepare_string() strips the escaped characters of a
- string and replaces them by the ascii characters they stand for.
- The ascii length of the resulting string is returned, including the
- terminating null-character.
- */
- int
- prepare_string(str)
- register char *str;
- {
- register char *t = str;
- register count = 1; /* there's always a null at the end ! */
- while (*str) {
- count++;
- if (*str == '\\') {
- switch (*++str) {
- case 'b':
- *t++ = '\b';
- str++;
- break;
- case 'f':
- *t++ = '\f';
- str++;
- break;
- case 'n':
- *t++ = '\n';
- str++;
- break;
- case 'r':
- *t++ = '\r';
- str++;
- break;
- case 't':
- *t++ = '\t';
- str++;
- break;
- /* octal value of: */
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- {
- register cnt = 0, oct = 0;
- do
- oct = oct * 8 + *str - '0';
- while (is_oct(*++str) && ++cnt < 3);
- *t++ = (char) oct;
- break;
- }
- default:
- *t++ = *str++;
- break;
- }
- }
- else
- *t++ = *str++;
- }
- *t = '\0'; /* don't forget this one !!! */
- return count;
- }
- #ifndef NOBITFIELD
- /* put_bf() takes care of the initialisation of (bit-)field
- selectors of a struct: each time such an initialisation takes place,
- put_bf() is called instead of the normal code generating routines.
- Put_bf() stores the given integral value into "field" and
- "throws" the result of "field" out if the current selector
- is the last of this number of fields stored at the same address.
- */
- put_bf(tp, val)
- struct type *tp;
- arith val;
- {
- static long field = (arith)0;
- static arith offset = (arith)-1;
- register struct field *fd = tp->tp_field;
- register struct sdef *sd = fd->fd_sdef;
- static struct expr expr;
- ASSERT(sd);
- if (offset == (arith)-1) {
- /* first bitfield in this field */
- offset = sd->sd_offset;
- expr.ex_type = tp->tp_up;
- expr.ex_class = Value;
- }
- if (val != 0) /* insert the value into "field" */
- field |= (val & fd->fd_mask) << fd->fd_shift;
- if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) {
- /* the selector was the last stored at this address */
- expr.VL_VALUE = field;
- if (ConStarted == 0) {
- C_con_begin();
- ConStarted = 1;
- }
- con_int(&expr);
- field = (arith)0;
- offset = (arith)-1;
- }
- }
- #endif NOBITFIELD
- int
- zero_bytes(sd)
- struct sdef *sd;
- {
- /* fills the space between a selector of a struct
- and the next selector of that struct with zero-bytes.
- */
- register int n =
- sd->sd_sdef->sd_offset - sd->sd_offset -
- size_of_type(sd->sd_type, "struct member");
- register count = n;
- while (n-- > 0)
- con_byte((arith)0);
- return count;
- }
- int
- valid_type(tp, str)
- struct type *tp;
- char *str;
- {
- if (tp->tp_size < 0) {
- error("size of %s unknown", str);
- return 0;
- }
- return 1;
- }
- con_int(expr)
- register struct expr *expr;
- {
- register struct type *tp = expr->ex_type;
- if (tp->tp_unsigned)
- C_co_ucon(itos(expr->VL_VALUE), tp->tp_size);
- else
- C_co_icon(itos(expr->VL_VALUE), tp->tp_size);
- }
- illegal_init_cst(expr)
- struct expr *expr;
- {
- if (expr->ex_type->tp_fund != ERRONEOUS)
- expr_error(expr, "illegal initialisation constant");
- }
- too_many_initialisers(expr)
- struct expr *expr;
- {
- expr_error(expr, "too many initialisers");
- }
- aggregate_type(tp)
- struct type *tp;
- {
- return tp->tp_fund == ARRAY || tp->tp_fund == STRUCT;
- }
|