/* * Copyright (c) 2004 - 2007, Nils R. Weller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Expression parser */ #include "expr.h" #include #include #include #include "token.h" #include "error.h" #include "misc.h" #include "defs.h" #include "decl.h" #include "scope.h" #include "type.h" #include "icode.h" #include "debug.h" #include "cc1_main.h" #include "subexpr.h" #include "functions.h" #include "analyze.h" #include "typemap.h" #include "symlist.h" #include "backend.h" #include "libnwcc.h" #include "reg.h" #include "n_libc.h" void append_expr(struct expr **head, struct expr **tail, struct expr *e) { if (*head == NULL) { *head = *tail = e; } else { (*tail)->next = e; e->prev = *tail; *tail = (*tail)->next; } } struct expr * alloc_expr(void) { struct expr *ret = n_xmalloc(sizeof *ret); static struct expr nullexpr; *ret = nullexpr; return ret; } void recover(struct token **tok, int delim, int delim2); static int ambig_to_binary(struct token *t) { int op = *(int *)t->data; switch (op) { case TOK_OP_AMB_PLUS: op = TOK_OP_PLUS; break; case TOK_OP_AMB_MINUS: op = TOK_OP_MINUS; break; case TOK_OP_AMB_MULTI: op = TOK_OP_MULTI; break; case TOK_OP_AMB_BAND: op = TOK_OP_BAND; break; case TOK_OP_AMB_COND2: op = TOK_OP_COND2; break; } if (!IS_BINARY(op) && op != TOK_OP_COND2) { errorfl(t, "Invalid operator ``%s'' - " "binary or ternary operator expected", t->ascii); return -1; } *(int *)t->data = op; /* XXXXXXXXXXXXXXXXXXXXXXXXXXXX ok? */ return op; } int expr_ends(struct token *t, int delim, int delim2) { int type; if (t->type == TOK_OPERATOR) { type = *(int *)t->data; } else { type = t->type; } if (type == delim || type == delim2) { return 1; } return 0; } /* * Get lowest precedence operator in an expression. Note that the * conditional operator requires special handling; In * foo? bar: baz; * ... ? and : act like parentheses, i.e. lower precedence operators * such as the comma operator may occur between them. */ static struct operator * get_lowest_prec(struct expr *ex, struct expr **endp, int want_condop) { int lowest = 100; int cond_expr = 0; struct expr *lptr = NULL; *endp = NULL; for (; ex != NULL; ex = ex->next) { struct operator *tmp; if (ex->op == 0 || ex->used) { continue; } tmp = &operators[LOOKUP_OP2(ex->op)]; /* * 08/22/07: This flag had to be added because otherwise * the search loop for the second part of the conditional * operator didn't work right in * * 1? 0: 1? 1,1 : 2; */ if (want_condop && ex->op != TOK_OP_COND && ex->op != TOK_OP_COND2) { continue; } if (!cond_expr) { if (tmp->prec < lowest) { lowest = tmp->prec; lptr = ex; } else if (tmp->prec == lowest) { if (tmp->assoc != OP_ASSOC_RIGHT) { lptr = ex; } } } if (ex->op == TOK_OP_COND) { ++cond_expr; } else if (ex->op == TOK_OP_COND2) { if (cond_expr == 0) { if (want_condop) { /* * Added... Otherwise stuff breaks * because ? is selected rather than * : */ lptr = ex; break; } } --cond_expr; } } *endp = lptr; return lptr? (void *)&operators[LOOKUP_OP2(lptr->op)]: (void *)NULL; } static struct expr * bind_operators(struct expr *ex) { struct operator *op; struct expr *endp; struct expr *start = ex; if (ex == NULL) return NULL; if ((op = get_lowest_prec(ex, &endp, 0)) == NULL) { /* No more operators left */ if (!ex->used) { endp = ex; endp->used = 1; } else endp = NULL; return endp; } else if (op->value == TOK_OP_COND) { struct expr *endp2; struct expr *ex2 = endp->next; /* * Need to get second part of conditional operator. This * requires skipping intermediate conditional operators. * * 08/22/07: This loop is nonsense since we added the * want_condop flag to get_lowest_prec() */ /* for (;;) {*/ if (ex2 == NULL || (op = get_lowest_prec(ex2, &endp2, 1)) == NULL) { errorfl(ex2? ex2->tok: endp->tok, "Parse error - missing second part" " of conditional operator"); return NULL; } #if 0 } else if (op->value == TOK_OP_COND) { ++cond1; } else if (op->value == TOK_OP_COND2) { if (cond1 == 0) { /* done! */ break; } else { --cond1; } } #endif /* ex2 = endp2->next;*/ /* } */ /* * At this point, endp points to ``?'' and endp2 to ``:''. We * bind them such that: * Given x = ``?'' * ... x->left = cond-expr * ... x->right = : * ... x->right->left = expr-nonzero * ... x->right->right = expr-zero */ endp->used = endp2->used = 1; ex = endp->next; endp->next = NULL; endp->left = bind_operators(start); endp->right = endp2; ex2 = endp2->next; endp2->next = NULL; endp->right->left = bind_operators(ex); endp->right->right = bind_operators(ex2); return endp; } endp->used = 1; ex = endp->next; endp->next = NULL; endp->left = bind_operators(start); endp->right = bind_operators(ex); return endp; } static void append_init_list( struct initializer **init, struct initializer **init_tail, struct initializer *i) { if (i->type == 0) abort(); if (*init == NULL) { *init = *init_tail = i; } else { (*init_tail)->next = i; i->prev = *init_tail; *init_tail = (*init_tail)->next; } } struct initializer * alloc_initializer(void) { static struct initializer nullinit; struct initializer *ret; ret = n_xmalloc(sizeof *ret); *ret = nullinit; if (ret == (void *)0x80c46c0) abort(); return ret; } static void conv_init(struct tyval *tv, struct type *toty, struct token *t) { struct type *fromty = tv->type; struct type_node *ltn; struct type_node *rtn; if (toty->tlist == NULL) { /* Simple basic type conversion */ if (tv->address != NULL) { /* Must be pointer to int cast... Dangerous!!! */ return; } if (toty->code != fromty->code) { cross_do_conv(tv, toty->code); } return; } if (fromty->tlist == NULL || (toty->code != fromty->code && (toty->code != TY_VOID && fromty->code != TY_VOID))) { /* this bullshit doesn't work */ return; #if 0 #if 0 /* XXX */ && (!IS_CHAR(toty->code) || !IS_CHAR(fromty->code)))) { #endif if (!tv->is_nullptr_const) { errorfl(t, "Initializer of incompatible type"); return; } else { /* Explains various mysteries - Don't check tlists */ return; } #endif } /* * Must be assignment to pointer since this function is only * called for scalar types */ if (tv->is_nullptr_const) { return; } if (toty->code == TY_VOID && toty->tlist->type == TN_POINTER_TO && toty->tlist->next == NULL) { /* Assignment to void pointer */ return; } ltn = toty->tlist; rtn = fromty->tlist; if (rtn && rtn->type == TN_FUNCTION) { if (ltn->type == TN_POINTER_TO) { /* Probably pointer to function */ ltn = ltn->next; } } for (; ltn != NULL && rtn != NULL; ltn = ltn->next, rtn = rtn->next) { if (ltn->type != rtn->type) { if (rtn->type == TN_ARRAY_OF && rtn == fromty->tlist) { /* OK - assign array address to ptr */ ; } else { errorfl(t, "Initializer of incompatible type"); return; } } } if (ltn != rtn) { /* One type list is longer */ errorfl(t, "Initializer of incompatible type"); return; } } struct desig_init_data { struct initializer **init_head; struct initializer **init_tail; struct initializer *cur_init_ptr; struct sym_entry *highest_encountered_member; int highest_encountered_index; }; static void replace_cur_init(struct desig_init_data *data, struct initializer *init) { if (data->cur_init_ptr->prev) { data->cur_init_ptr->prev->next = init; } else { *data->init_head = init; } if (data->cur_init_ptr->next) { data->cur_init_ptr->next->prev = init; } else { *data->init_tail = init; } init->next = data->cur_init_ptr->next; init->prev = data->cur_init_ptr->prev; free/*initializer*/(data->cur_init_ptr); data->cur_init_ptr = init->next; } /* * Put an initializer into the designated initializer list. As soon as the * first designated initializer is encountered, this function also has to * be called for all subsequent initializers, since it may have trashed the * initializer order. * * There are four cases to handle here: * * - The initializer is itself designated, and it jumps forward. If that * happens we create a null initializer for every skipped member (this element * may have to be replaced later if another designated initializer jumps back * in the order) * * - The initializer is itself designated, and it jumps backward. In that * case we have to jump back and OVERWRITE an existing explicit data or null * initializer. Also, the current ``initializer pointer'' must be moved to * that location * * - The initializer is not designated, but overwrites an existing * initializer because the current initializer pointer points to one * * - The initializer is not designated and just appended at the end of * the list */ static void put_desig_init_struct(struct desig_init_data *data, struct sym_entry *desig_se, struct sym_entry *prev_se, struct sym_entry *whole_struct, struct initializer *init, struct token *tok, int *items_read) { int skipped = 0; if (desig_se != NULL && prev_se != NULL && desig_se->dec->offset == prev_se->dec->offset) { /* * Designating the initializer which would we done now * anyway - ignore designation. */ desig_se = NULL; } if (desig_se == NULL) { /* Not designated, thank heaven */ if (data->cur_init_ptr == NULL) { /* At end too! */ append_init_list(data->init_head, data->init_tail, init); } else { /* * We have to trash an existing initializer */ if (data->cur_init_ptr->type != INIT_NULL) { warningfl(tok, "Member `%s' already has an " "initializer", prev_se->dec->dtype->name); } replace_cur_init(data, init); } } else { /* * Designated! But is it forward or backward? */ if (prev_se == NULL) { /* * Brute-force search for the target */ struct initializer *tmpinit; tmpinit = *data->init_head; for (prev_se = whole_struct; prev_se != NULL; prev_se = prev_se->next) { if (prev_se->dec->offset == desig_se->dec->offset) { break; } if (tmpinit->next == NULL) { /* * Fill holes with null initializers */ struct initializer *nullb; nullb = backend->make_null_block(NULL, prev_se->next->dec->dtype, NULL, 1); nullb->prev = tmpinit; tmpinit->next = nullb; } tmpinit = tmpinit->next; ++skipped; } if (tmpinit->prev) { tmpinit->prev->next = init; } else { *data->init_head = init; } if (tmpinit->next) { tmpinit->next->prev = init; } else { *data->init_tail = init; } init->prev = tmpinit->prev; init->next = tmpinit->next; data->cur_init_ptr = tmpinit->next; free/*_initializer XXX */(tmpinit); *items_read = skipped; if (skipped == 0) { *data->init_head = init; } else if (skipped > *items_read) { *data->init_tail = init; } } else if (desig_se->dec->offset > prev_se->dec->offset) { int highest_offset = data->highest_encountered_member? (int)data->highest_encountered_member->dec->offset: -1; /* * Forward - create a null initializer for every * skipped member if necessary */ while (prev_se->dec->offset < desig_se->dec->offset) { if ((signed long)prev_se->dec->offset > highest_offset) { struct initializer *nullb; nullb = backend->make_null_block(NULL, prev_se->dec->dtype, NULL, 1); append_init_list(data->init_head, data->init_tail, nullb); } if (data->cur_init_ptr) { data->cur_init_ptr = data->cur_init_ptr->next; } ++skipped; prev_se = prev_se->next; } if (data->cur_init_ptr) { if (data->cur_init_ptr->type != INIT_NULL) { warningfl(tok, "Member `%s' already " "has an initializer", desig_se->dec->dtype->name); } replace_cur_init(data, init); } else { append_init_list(data->init_head, data->init_tail, init); } *items_read += skipped; } else { /* * Backward. First search the target initializer. * We can exploit the fact that every member behind * us has one initializer already (null if skipped.) */ struct initializer *tmp; tmp = *data->init_tail; prev_se = prev_se->prev; while (prev_se->dec->offset > desig_se->dec->offset) { prev_se = prev_se->prev; tmp = tmp->prev; ++skipped; } *items_read -= skipped; if (tmp->prev) { tmp->prev->next = init; } else { *data->init_head = init; } if (tmp->next) { tmp->next->prev = init; } else { *data->init_tail = init; } init->next = tmp->next; init->prev = tmp->prev; if (desig_se == whole_struct) { /* Start */ *data->init_head = init; } free/*_initializer XXX */(tmp); data->cur_init_ptr = init->next; } } if (desig_se != NULL) { if (data->highest_encountered_member == NULL || data->highest_encountered_member->dec->offset < desig_se->dec->offset) { data->highest_encountered_member = desig_se; } } else { if (data->cur_init_ptr == NULL) { /* Appending at end */ data->highest_encountered_member = prev_se; } } } static void put_desig_init_array(struct desig_init_data *data, int desig_elem, int *items_read, struct initializer *init, struct type *elem_type, struct token *tok) { int skipped = 0; if (desig_elem == *items_read) { /* * Designating the initializer which would we done now * anyway - ignore designation. */ desig_elem = -1; } if (desig_elem == -1) { /* Not designated, thank heaven */ if (data->cur_init_ptr == NULL) { /* At end too! */ append_init_list(data->init_head, data->init_tail, init); } else { /* * We have to trash an existing initializer */ if (data->cur_init_ptr->type != INIT_NULL) { warningfl(tok, "Element %d already has an " "initializer", items_read); } replace_cur_init(data, init); } } else { /* * Designated! But is it forward or backward? */ if (desig_elem > *items_read) { /* * Forward - create a null initializer for every * skipped member */ while (*items_read + skipped < desig_elem) { if (*items_read + skipped > data->highest_encountered_index) { struct initializer *nullb; nullb = backend->make_null_block(NULL, elem_type, NULL, 1); append_init_list(data->init_head, data->init_tail, nullb); } if (data->cur_init_ptr) { data->cur_init_ptr = data->cur_init_ptr->next; } ++skipped; } if (data->cur_init_ptr) { warningfl(tok, "Element %d already has an " "initializer", desig_elem); replace_cur_init(data, init); } else { append_init_list(data->init_head, data->init_tail, init); } *items_read += skipped; data->cur_init_ptr = NULL; } else { /* * Backward. First search the target initializer. * We can exploit the fact that every member behind * us has one initializer already (null if skipped.) */ struct initializer *tmp; tmp = *data->init_tail; ++skipped; while (*items_read - skipped > desig_elem) { tmp = tmp->prev; ++skipped; } *items_read -= skipped; if (tmp->prev) { tmp->prev->next = init; } else { *data->init_head = init; } if (tmp->next) { tmp->next->prev = init; } else { *data->init_tail = init; } init->next = tmp->next; init->prev = tmp->prev; free/*_initializer XXX */(tmp); data->cur_init_ptr = init->next; } } if (desig_elem != -1) { if (desig_elem > data->highest_encountered_index) { data->highest_encountered_index = desig_elem; } } else { if (data->cur_init_ptr == NULL) { /* Appending at end */ data->highest_encountered_index = *items_read; } } } struct initializer * get_init_expr(struct token **tok, int type, struct type *lvalue, int initial, int complit) { struct token *t = *tok; struct expr *ex; struct initializer *ret = NULL; struct initializer *rettail = NULL; struct initializer *init; struct sym_entry *se = NULL; struct type *curtype = NULL; struct type arrtype; struct desig_init_data init_data; struct sym_entry *prevse = NULL; int items_read = 0; int items_ok = 0; int is_aggregate = 0; int is_array = 0; int is_char_array = 0; int is_braced_string = 0; int warned = 0; int needbrace = 0; int have_desig = 0; init_data.init_head = &ret; init_data.init_tail = &rettail; init_data.cur_init_ptr = NULL; init_data.highest_encountered_member = NULL; init_data.highest_encountered_index = -1; if (lvalue->tlist != NULL && lvalue->tlist->type == TN_ARRAY_OF) { is_aggregate = 1; is_array = 1; items_ok = lvalue->tlist->arrarg_const; if (!initial && items_ok == 0) { errorfl(t, "Array size for nested array dimension " "unspecified"); return NULL; } arrtype = *lvalue; curtype = &arrtype; arrtype.tlist = arrtype.tlist->next; if (IS_CHAR(lvalue->code) && lvalue->tlist->next == NULL) { is_char_array = 1; } } else if (lvalue->code == TY_STRUCT && lvalue->tlist == NULL) { is_aggregate = 1; se = lvalue->tstruc->scope->slist; curtype = se->dec->dtype; /* XXX should set items_ok ?!?!? */ if (initial && t->type != TOK_COMP_OPEN) { /* * 09/07/07: This always used EXPR_INIT instead of * type!! (breaks for constant initializers like * compound literals) */ if (type == EXPR_OPTCONSTINIT) { type = EXPR_INIT; } ex = parse_expr(&t, TOK_OP_COMMA, TOK_SEMICOLON, type, 1); if (ex == NULL) { return NULL; } if (ex->const_value && ex->const_value->static_init) { init = ex->const_value->static_init; } else { init = alloc_initializer(); init->type = INIT_STRUCTEXPR; init->left_type = dup_type(curtype); init->data = ex; } *tok = t; return init; } } else if (lvalue->code == TY_UNION && lvalue->tlist == NULL) { se = lvalue->tstruc->scope->slist; curtype = se->dec->dtype; items_ok = 1; if (initial && t->type != TOK_COMP_OPEN) { /* XXX duplicates stuff for TY_STRUCT above */ if (type == EXPR_OPTCONSTINIT) { type = EXPR_INIT; } ex = parse_expr(&t, TOK_OP_COMMA, TOK_SEMICOLON, type, 1); if (ex == NULL) { return NULL; } if (ex->const_value && ex->const_value->static_init) { init = ex->const_value->static_init; } else { init = alloc_initializer(); init->left_type = dup_type(curtype); init->type = INIT_STRUCTEXPR; init->data = ex; } *tok = t; return init; } } else { struct initializer *was_nullblock = NULL; int was_varinit = 0; /* The following are for variable struct/array inits */ struct token *starttok; int delim1; int delim2; /* Only one item */ if (t->type == TOK_COMP_OPEN) { /* * Compound initializers are also allowed for * non-aggregate types; * int x = { 0 }; */ t = t->next; starttok = t; ex = parse_expr(&t, TOK_COMP_CLOSE, TOK_OP_COMMA,type,1); delim1 = TOK_COMP_CLOSE; delim2 = TOK_OP_COMMA; if (t->type == TOK_OP_COMMA && t->next != NULL && t->next->type == TOK_COMP_CLOSE) { /* Trailing comma permitted in compound init */ t = t->next->next; } else if (t->type != TOK_COMP_CLOSE) { /* * There may be a trailing comma here. BitchX * uses that */ if (t->type == TOK_OPERATOR && *(int *)t->data == TOK_OP_COMMA && t->next && t->next->type == TOK_COMP_CLOSE) { t = t->next->next; } else { errorfl(t, "Invalid initializer"); return NULL; } } else { t = t->next; } } else { starttok = t; delim1 = TOK_OP_COMMA; delim2 = initial? TOK_SEMICOLON: TOK_COMP_CLOSE; ex = parse_expr(&t, TOK_OP_COMMA, initial? TOK_SEMICOLON: TOK_COMP_CLOSE, type,1); } if (ex == NULL) { *tok = t; return NULL; } if (type == EXPR_CONSTINIT || type == EXPR_OPTCONSTINIT) { if (ex->const_value != NULL) { if (ex->const_value->static_init != NULL) { /* * Initialized with value of other static * variable */ struct initializer *tmp; tmp = ex->const_value->static_init; if (tmp->type == INIT_EXPR) { struct expr *tmpex = tmp->data; ex->const_value = tmpex->const_value; } else { /* INIT_NULL */ was_nullblock = tmp->data; } } /* * Convert constant initializer to destination * type */ if (!was_nullblock) { conv_init(ex->const_value, lvalue, t->prev); /* * 08/03/07: To make * static long nonsense = (long)&addr; * work */ if (ex->const_value->address != NULL && is_integral_type(lvalue)) { ; } else { ex->const_value->type = ex->type = n_xmemdup(lvalue, sizeof *lvalue); } } else { /* XXX */ unimpl(); } } else { if (type == EXPR_OPTCONSTINIT && !ex->is_const) { /* * This is a non-constant expression * used as initializer for a struct * or an array. We have to save the * expression and evaluate it when * the initializer assignment takes * place */ was_varinit = 1; ex = parse_expr(&starttok, delim1, delim2, 0,1); t = starttok; if (ex == NULL) { *tok = t; return NULL; } /* * Initialize value to 0 for now */ was_nullblock = backend-> make_null_block(NULL, lvalue, NULL, 1); was_nullblock->varinit = ex; } else { return NULL; } } } if (was_nullblock) { ret = init = was_nullblock; } else { ret = init = alloc_initializer(); init->type = INIT_EXPR; init->data = ex; } init->left_type = dup_type(lvalue); *tok = t; return init; } if (t->type == TOK_COMP_OPEN && is_char_array) { if (t->next && t->next->type == TOK_STRING_LITERAL) { /* * This must be a braces-enclosed string constant; * char buf[] = { "hello" }; * The GNU people love using unnecessary braces * (and parentheses) like this */ t = t->next; is_braced_string = 1; } } /* * 08/22/07: Null initializers for strings were completely ignored! * E.g. in * * static char buf[10] = "hehe"; * * ... only 5 bytes would be allocated for the buffer, since there * were only 5 bytes of initialized data! Same thing with string * initializers for nested array initializers. So now we resize the * string and add any necessary null bytes */ if (t->type == TOK_STRING_LITERAL) { struct ty_string *ts = t->data; size_t newlen; if (lvalue->tlist != NULL && lvalue->tlist->type == TN_ARRAY_OF && (newlen = lvalue->tlist->arrarg_const) > ts->size) { ts->str = n_xrealloc(ts->str, newlen); memset(ts->str + ts->size - 1, 0, newlen - ts->size); ts->size = newlen; ts->ty->tlist->arrarg_const = newlen; } } if (t->type != TOK_COMP_OPEN) { if (t->type == TOK_STRING_LITERAL && is_array) { struct token *tmp = t; if (lvalue->tlist->next != NULL || !IS_CHAR(lvalue->code)) { errorfl(t, "Invalid initializer"); return NULL; } else if (lvalue->sign == TOK_KEY_UNSIGNED) { #if 0 warningfl(t, "Assigning string constant to array of `unsigned char'"); #endif } /* * 09/01/07: The extra } check was needed because * othrwise * * char foo[1][2] = { "hello" }; * breaks, since "hello" is an un-braced array * initializer (the braces belong to the outer * array), and we ended up looking for a , or ; * * XXX MAybe this still isn't fully correct */ if (is_braced_string || (t->next && t->next->type == TOK_COMP_CLOSE)) { /* * Read up to closing brace */ ex = parse_expr(&t, TOK_COMP_CLOSE, 0, type, 1); } else { /* * Read up to comma or semicolon */ ex = parse_expr(&t, TOK_OP_COMMA, TOK_SEMICOLON, type, 1); } if (ex == NULL) { return NULL; } if (t != tmp->next) { tmp = tmp->next? tmp->next: t; errorfl(tmp, "Parse error at `%s'", tmp->ascii); return NULL; } if (is_braced_string && t != NULL) { /* Skip brace */ t = t->next; } init = alloc_initializer(); init->left_type = dup_type(lvalue); init->data = ex; init->type = INIT_EXPR; *tok = t; if (lvalue->tlist->arrarg->const_value != NULL) { (void) backend->get_sizeof_type(lvalue, NULL); } if (lvalue->tlist->arrarg_const == 0) { lvalue->tlist->arrarg_const = strlen(t->prev->ascii) + 1; } return init; } else if (initial) { /* Initial array initializer requires braces */ errorfl(t, "Parse error at `%s'", t->ascii); return NULL; } else if (is_aggregate) { warningfl(t, "Nested aggregate initializer not surrounded by braces"); needbrace = 0; } } else { needbrace = 1; if (next_token(&t) != 0) { return NULL; } } do { struct token *starttok = t; struct sym_entry *desig_se = NULL; struct sym_entry *prev_se = se; int desig_elem = -1; if ((t->type == TOK_OPERATOR && *(int *)t->data == TOK_OP_STRUMEMB) || (t->type == TOK_IDENTIFIER && t->next && t->next->type == TOK_OPERATOR && *(int *)t->next->data == TOK_OP_AMB_COND2)) { int is_c99_style = 0; /* * Designated initializer - * * .membername = expr * * ... as per C99 or * * membername: expr * * ... as per GNU C (deprecated) */ have_desig = 1; if (is_array) { /* * Only allowed for structs! (Note that we * can't check ``se'' because it may be * NULL here; * * struct foo { int x, y; } * f = { .y = 0, .x = 0 }; * ^ NULL here */ errorfl(t, "Invalid designated initializer"); return NULL; } if (t->type != TOK_IDENTIFIER) { is_c99_style = 1; /* Skip . */ if (next_token(&t) != 0) { return NULL; } if (t->type != TOK_IDENTIFIER) { errorfl(t, "Syntax error - " "identifier expected"); return NULL; } } else { warningfl(t, "GNU C designated initializiers " "are deprecated, use the C99 way " "instead (`.member = expr' instead " "of `member: expr')"); } desig_se = lookup_symbol_se( lvalue->tstruc->scope, t->data, 0); if (desig_se == NULL) { errorfl(t, "Unknown member `%s'", t->data); return NULL; } if (next_token(&t) != 0) { return NULL; } if (is_c99_style) { if (t->type != TOK_OPERATOR || *(int *)t->data != TOK_OP_ASSIGN) { errorfl(t, "Syntax error at `%s' - " "`=' expected", t->next->ascii); return NULL; } } /* Skip : (GNU C) or = (C99) */ if (next_token(&t) != 0) { return NULL; } se = desig_se; curtype = se->dec->dtype; } else if (t->type == TOK_ARRAY_OPEN) { struct expr *ex; size_t elem; have_desig = 1; if (next_token(&t) != 0) { return NULL; } ex = parse_expr(&t, TOK_ARRAY_CLOSE, 0, EXPR_CONST, 1); if (ex == NULL) { return NULL; } elem = cross_to_host_size_t(ex->const_value); if ((ssize_t)elem < 0) { errorfl(t, "Negative and very large designated " "array elements are not allowed"); return NULL; } else if (elem > items_ok && items_ok != 0) { errorfl(t, "Array index %lu out of bounds", (unsigned long)elem); return NULL; } else if (elem > INT_MAX) { errorfl(t, "Array index %lu too large", (unsigned long)elem); return NULL; } if (next_token(&t) != 0 || t->type != TOK_OPERATOR || *(int *)t->data != TOK_OP_ASSIGN) { if (t != NULL) { errorfl(t, "Syntax error at `%s' - ", "`=' expected", t->ascii); } return NULL; } if (next_token(&t) != 0) { return NULL; } desig_elem = (int)elem; } init = get_init_expr(&t, type, curtype, 0, 0); if (init == NULL) { return NULL; } if (is_basic_agg_type(curtype)) { struct initializer *init2; init2 = alloc_initializer(); init2->left_type = dup_type(curtype); init2->type = INIT_NESTED; init2->data = init; init = init2; /*append_init_list(&ret, &rettail, init2);*/ } else { /*append_init_list(&ret, &rettail, init);*/ } if (is_array) { /* append_init_list(&ret, &rettail, init);*/ put_desig_init_array(&init_data, desig_elem, &items_read, init, curtype, NULL); } else { put_desig_init_struct(&init_data, desig_se, prev_se, lvalue->tstruc->scope->slist, init, NULL, &items_read); } ++items_read; if (items_ok != 0) { if (items_read > items_ok && !warned) { if (!is_aggregate) { errorfl(starttok, "Invalid aggregate initializer"); } else { errorfl(starttok, "Initializer for aggregate type too big"); } warned = 1; } else if (!needbrace && items_read == items_ok) { /* We're done */ t = t->prev; break; } } if (se != NULL) { prevse = se; se = se->next; if (se != NULL) { /* XXX error msg if se = NULL maybe? */ curtype = se->dec->dtype; } } /* * 08/05/07: The code below was previously BEFORE the se * update above! Thus if there was a trailing comma, the * make_null_block() call at the bottom would wrongly * create a null initializer for this structure member * even though it already has an initializer * * This broke some vim option structs */ if (t->type == TOK_OPERATOR && *(int *)t->data == TOK_OP_COMMA && t->next != NULL && t->next->type == TOK_COMP_CLOSE) { /* Trailing comma permitted in compound init. */ t = t->next; break; } if (t->type == TOK_SEMICOLON) break; /* XXXXXXXX */ } while (!expr_ends(t, TOK_COMP_CLOSE, 0) && (t = t->next) != NULL); if (t->type != TOK_SEMICOLON) /* XXXXXXXXXXX */ t = t->next; *tok = t; if (is_array && items_ok == 0) { lvalue->tlist->arrarg_const = items_ok = items_read; } if (initial && t->type != TOK_SEMICOLON && (t->type != TOK_OPERATOR || *(int *)t->data != TOK_OP_COMMA)) { if (!complit) { errorfl(t, "Parse error at `%s'- expected semicolon or comma", t->ascii); return NULL; } } /* * Remaining fields are initialized to 0. This is very straightforward * for normal initializers - just initialize the rest of the struct * or array - and requires brute-force for designated initializers */ if (have_desig) { init = NULL; if (is_array) { if (items_ok != 0) { int remaining = items_ok - (init_data.highest_encountered_index+1); if (remaining < 0) { puts("BUG: ??????"); abort(); } else if (remaining > 0) { init = backend-> make_null_block(NULL, curtype, NULL, remaining); } } } else { struct initializer *tmp; se = lvalue->tstruc->scope->slist; tmp = ret; for (; se != NULL; se = se->next) { if (tmp->next == NULL) { break; } tmp = tmp->next; } se = se->next; if (se != NULL) { init = backend->make_null_block(se, NULL, lvalue, 0); } } if (init != NULL) { append_init_list(&ret, &rettail, init); } } else { if (items_read < items_ok || se != NULL) { /* Remaining fields are initialized to 0 */ if (se != NULL) { /* Structure */ init = backend-> make_null_block(se, NULL, lvalue, 0); } else { /* Array */ int remaining = items_ok - items_read; init = backend-> make_null_block(NULL, curtype, NULL, remaining); } if (init != NULL) { append_init_list(&ret, &rettail, init); } } } return ret; } /* * Parses an expression and returns a pointer to the parse tree. * * 09/07/07: Finally the ``nesting'' variable is gone! Instead the caller * passes an ``initial'' flag, which states whether this is the initial * call to get a particular expression. * * Only if ``initial'' is set, will constant expression results be * evaluated before returning */ struct expr * parse_expr(struct token **tok, int delim, int delim2, int type, int initial) { struct token *t; struct token *tokstart = *tok; struct expr *ret = NULL; struct expr *rettail = NULL; struct expr *ex = NULL; struct s_expr *s_ex; struct s_expr *last_s_ex = NULL; #ifdef NO_EXPR /* Don't use expression parser */ recover(tok, delim, delim2); if (*tok == NULL) { lexerror("Unterminated expression"); exit(1); } return NULL; #endif t = *tok; if (t->type == TOK_SEMICOLON) { /* Empty expression */ if ((delim != TOK_SEMICOLON && delim2 != TOK_SEMICOLON) || type == EXPR_INIT || type == EXPR_CONSTINIT || type == EXPR_OPTCONSTINIT || type == EXPR_OPTCONSTARRAYSIZE) { errorfl(t, "Parse error at `%s'", t->ascii); return NULL; } ret = alloc_expr(); ret->is_const = 1; return ret; } else if (t->type == TOK_ARRAY_CLOSE && (delim == TOK_ARRAY_CLOSE || delim2 == TOK_ARRAY_CLOSE)) { ret = alloc_expr(); ret->is_const = 1; return ret; } else if (delim == TOK_ARRAY_CLOSE && type == EXPR_CONST_FUNCARRAYPARAM) { if ((t->type == TOK_KEY_RESTRICT || t->type == TOK_KEY_CONST /* XXX honor this */ || t->type == TOK_KEY_VOLATILE) && t->next != NULL && t->next->type == TOK_ARRAY_CLOSE) { /* * This is a construct of the form * * char buf[restrict] * * which is equivalent to * * char *restrict buf */ *tok = t->next; ret = alloc_expr(); ret->is_const = 1; return ret; } type = EXPR_CONST; } else if (t->type == TOK_COMP_OPEN) { struct scope *scope; /* GNU C statement-as-expression */ if (ansiflag) { warningfl(t, "Statement-as-expression (`({ ... })') isn't " "available in ISO C (don't use -ansi!)"); } scope = new_scope(SCOPE_CODE); if (analyze(&t) != 0) { close_scope(); return NULL; } close_scope(); scope->code->type = ST_EXPRSTMT; *tok = t->next; ret = alloc_expr(); ret->stmt_as_expr = /*curscope->next*/scope; return ret; } /* * Strategy: An expression is a number of sub-expressions * connected through binary and ternary operators, so we * just always need to read a sub-expression, a connecting * operator - if any - and then the next sub-expression. */ while ((s_ex = get_sub_expr(&t, delim, delim2, type)) != NULL) { int op; last_s_ex = s_ex; ex = alloc_expr(); ex->op = 0; ex->data = s_ex; append_expr(&ret, &rettail, ex); if (expr_ends(t, delim, delim2)) { if ((ex->tok = s_ex->meat) == NULL) { if ((ex->tok = s_ex->is_sizeof) == NULL) { /* Must be parenthesized expr */ ex->tok = s_ex->is_expr->tok; } } break; } else if (t->type != TOK_OPERATOR) { errorfl(t, "Parse error at `%s'(#2)", t->ascii); ex = NULL; break; } /* Must be binary or ternary operator */ ex = alloc_expr(); ex->data = NULL; op = *(int *)t->data; ex->tok = t; if (op != TOK_OP_COND) { op = ambig_to_binary(t); } if (type == EXPR_CONST || type == EXPR_CONSTINIT) { int err = 0; char *is_what = type == EXPR_CONST? "expression": "initializer"; if (op == TOK_OP_COMMA) { errorfl(t, "The comma operator is not allowed " "in constant %ss", is_what); err = 1; } else if (IS_ASSIGN_OP(op)) { errorfl(t, "Assignment operators are not allowed " "in constant %ss", is_what); err = 1; } if (err) { free(ex); ex = NULL; break; } } ex->op = op; append_expr(&ret, &rettail, ex); if (next_token(&t) != 0) { return NULL; } if (expr_ends(t, delim, delim2)) { errorfl(ex->tok, "Syntax error at `%s'", ex->tok->ascii); break; } if (op == TOK_OP_COND) { /* * 08/18/07: Allow GNU C's empty first conditional * operator operand */ if (t->type == TOK_OPERATOR && *(int *)t->data == TOK_OP_AMB_COND2) { warningfl(t, "Conditionals with omitted " "operands are not ISO C (GNU C only)"); if (next_token(&t) != 0) { return NULL; } if (expr_ends(t, delim, delim2)) { errorfl(t, "Syntax error at `%s'", t->ascii); break; } ex = alloc_expr(); ex->tok = t; ex->op = TOK_OP_COND2; append_expr(&ret, &rettail, ex); } } } *tok = t; if (ex == NULL || !expr_ends(t, delim, delim2)) { /* Try to recover from parse errors */ if (initial) { recover(&tokstart, delim, delim2); *tok = tokstart; } return NULL; } debug_print_expr(ret); fflush(stdout); if ((ret = bind_operators(ret)) == NULL) { puts("panic: cannot bind operators"); exit(1); /* XXX */ } debug_print_tree(ret); ret->extype = type; if (initial && (type == EXPR_CONST || type == EXPR_CONSTINIT || type == EXPR_OPTCONSTINIT || type == EXPR_OPTCONSTARRAYSIZE)) { int not_constant; if (eval_const_expr(ret, type, ¬_constant) != 0) { if ((type == EXPR_OPTCONSTINIT || type == EXPR_OPTCONSTARRAYSIZE) && not_constant) { ret->is_const = 0; } else { return NULL; } } else { ret->is_const = 1; } } return ret; } void recover(struct token **tok, int delim, int delim2) { struct token *t; int parens = 0; int brackets = 0; int braces = 0; if (*tok == NULL) return; if (delim == TOK_PAREN_CLOSE || delim2 == TOK_PAREN_CLOSE) { ++parens; } if (delim == TOK_ARRAY_CLOSE || delim2 == TOK_ARRAY_CLOSE) { ++brackets; } if (delim == TOK_COMP_CLOSE || delim2 == TOK_COMP_CLOSE) { ++braces; } for (t = *tok; t != NULL; t = t->next) { int ty = -1; /* 0 compared even with unused delim :( */ #ifdef DEBUG2 printf(" lol %s\n", t->ascii); #endif if (t->type == TOK_OPERATOR) { ty = *(int *)t->data; } else if (t->type == TOK_PAREN_OPEN) { ++parens; continue; } else if (t->type == TOK_PAREN_CLOSE) { /* * The below was --parens < 0, but <= * seems more permissive for parse * errors - so use that! */ if (--parens <= 0 && (delim == TOK_PAREN_CLOSE || delim2 == TOK_PAREN_CLOSE)) { *tok = t; return; } continue; } else if (t->type == TOK_ARRAY_OPEN) { ++brackets; continue; } else if (t->type == TOK_ARRAY_CLOSE) { if (--brackets <= 0 && (delim == TOK_ARRAY_CLOSE || delim2 == TOK_ARRAY_CLOSE)) { *tok = t; return; } continue; } else if (t->type == TOK_COMP_OPEN) { ++braces; continue; } else if (t->type == TOK_COMP_CLOSE) { if (--braces <= 0 && (delim == TOK_COMP_CLOSE || delim2 == TOK_COMP_CLOSE)) { *tok = t; return; } continue; } else { ty = t->type; } if (ty == delim || ty == delim2) { if (ty == TOK_OP_COMMA) { /* * We must take into account that someone * could write * int foo = bar(x, y, z); * ... in which case we do not want to exit * after x! */ if (parens != 0) { continue; } } *tok = t; return; } } *tok = NULL; }