123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970 |
- /*
- * sparse/expression.c
- *
- * Copyright (C) 2003 Transmeta Corp.
- * 2003-2004 Linus Torvalds
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This is the expression parsing part of parsing C.
- */
- #include <stdarg.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <limits.h>
- #include "lib.h"
- #include "allocate.h"
- #include "token.h"
- #include "parse.h"
- #include "symbol.h"
- #include "scope.h"
- #include "expression.h"
- #include "target.h"
- #include "char.h"
- ALLOCATOR(type_expression, "type-expr-maps");
- static int match_oplist(int op, ...)
- {
- va_list args;
- int nextop;
- va_start(args, op);
- do {
- nextop = va_arg(args, int);
- } while (nextop != 0 && nextop != op);
- va_end(args);
- return nextop != 0;
- }
- static struct token *comma_expression(struct token *, struct expression **);
- struct token *parens_expression(struct token *token, struct expression **expr, const char *where)
- {
- struct token *p;
- token = expect(token, '(', where);
- p = token;
- if (match_op(token, '{')) {
- struct expression *e = alloc_expression(token->pos, EXPR_STATEMENT);
- struct statement *stmt = alloc_statement(token->pos, STMT_COMPOUND);
- *expr = e;
- e->statement = stmt;
- start_label_scope();
- token = compound_statement(token->next, stmt);
- end_label_scope();
- token = expect(token, '}', "at end of statement expression");
- } else
- token = parse_expression(token, expr);
- if (token == p)
- sparse_error(token->pos, "an expression is expected before ')'");
- return expect(token, ')', where);
- }
- struct token *string_expression(struct token *token, struct expression **expr, const char *where)
- {
- struct token *next = primary_expression(token, expr);
- if (!*expr || (*expr)->type != EXPR_STRING) {
- sparse_error(token->pos, "string literal expected for %s", where);
- *expr = NULL;
- }
- return next;
- }
- /*
- * Handle __func__, __FUNCTION__ and __PRETTY_FUNCTION__ token
- * conversion
- */
- static struct symbol *handle_func(struct token *token)
- {
- struct ident *ident = token->ident;
- struct symbol *decl, *array;
- struct string *string;
- int len;
- if (ident != &__func___ident &&
- ident != &__FUNCTION___ident &&
- ident != &__PRETTY_FUNCTION___ident)
- return NULL;
- if (!current_fn || !current_fn->ident)
- return NULL;
- /* OK, it's one of ours */
- array = alloc_symbol(token->pos, SYM_ARRAY);
- array->ctype.base_type = &char_ctype;
- array->ctype.alignment = 1;
- array->endpos = token->pos;
- decl = alloc_symbol(token->pos, SYM_NODE);
- decl->ctype.base_type = array;
- decl->ctype.alignment = 1;
- decl->ctype.modifiers = MOD_STATIC;
- decl->endpos = token->pos;
- /* NS_SYMBOL but in function-scope */
- bind_symbol_with_scope(decl, ident, NS_SYMBOL, function_scope);
- len = current_fn->ident->len;
- string = __alloc_string(len + 1);
- memcpy(string->data, current_fn->ident->name, len);
- string->data[len] = 0;
- string->length = len + 1;
- decl->initializer = alloc_expression(token->pos, EXPR_STRING);
- decl->initializer->string = string;
- decl->initializer->ctype = decl;
- decl->array_size = alloc_const_expression(token->pos, len + 1);
- array->array_size = decl->array_size;
- decl->bit_size = array->bit_size = bytes_to_bits(len + 1);
- return decl;
- }
- static struct token *parse_type(struct token *token, struct expression **tree)
- {
- struct symbol *sym;
- *tree = alloc_expression(token->pos, EXPR_TYPE);
- token = typename(token, &sym, NULL);
- if (sym->ident)
- sparse_error(token->pos,
- "type expression should not include identifier "
- "\"%s\"", sym->ident->name);
- (*tree)->symbol = sym;
- return token;
- }
- static struct token *builtin_types_compatible_p_expr(struct token *token,
- struct expression **tree)
- {
- struct expression *expr = alloc_expression(
- token->pos, EXPR_COMPARE);
- expr->op = SPECIAL_EQUAL;
- token = token->next;
- if (!match_op(token, '('))
- return expect(token, '(',
- "after __builtin_types_compatible_p");
- token = token->next;
- token = parse_type(token, &expr->left);
- if (!match_op(token, ','))
- return expect(token, ',',
- "in __builtin_types_compatible_p");
- token = token->next;
- token = parse_type(token, &expr->right);
- if (!match_op(token, ')'))
- return expect(token, ')',
- "at end of __builtin_types_compatible_p");
- token = token->next;
-
- *tree = expr;
- return token;
- }
- static struct token *builtin_offsetof_expr(struct token *token,
- struct expression **tree)
- {
- struct expression *expr = NULL;
- struct expression **p = &expr;
- struct symbol *sym;
- int op = '.';
- token = token->next;
- if (!match_op(token, '('))
- return expect(token, '(', "after __builtin_offset");
- token = token->next;
- token = typename(token, &sym, NULL);
- if (sym->ident)
- sparse_error(token->pos,
- "type expression should not include identifier "
- "\"%s\"", sym->ident->name);
- if (!match_op(token, ','))
- return expect(token, ',', "in __builtin_offset");
- while (1) {
- struct expression *e;
- switch (op) {
- case ')':
- expr->in = sym;
- *tree = expr;
- default:
- return expect(token, ')', "at end of __builtin_offset");
- case SPECIAL_DEREFERENCE:
- e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->op = '[';
- *p = e;
- p = &e->down;
- /* fall through */
- case '.':
- token = token->next;
- e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->op = '.';
- if (token_type(token) != TOKEN_IDENT) {
- sparse_error(token->pos, "Expected member name");
- return token;
- }
- e->ident = token->ident;
- token = token->next;
- break;
- case '[':
- token = token->next;
- e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->op = '[';
- token = parse_expression(token, &e->index);
- token = expect(token, ']',
- "at end of array dereference");
- if (!e->index)
- return token;
- }
- *p = e;
- p = &e->down;
- op = token_type(token) == TOKEN_SPECIAL ? token->special : 0;
- }
- }
- #ifndef ULLONG_MAX
- #define ULLONG_MAX (~0ULL)
- #endif
- static unsigned long long parse_num(const char *nptr, char **end)
- {
- if (nptr[0] == '0' && tolower((unsigned char)nptr[1]) == 'b')
- return strtoull(&nptr[2], end, 2);
- return strtoull(nptr, end, 0);
- }
- static void get_number_value(struct expression *expr, struct token *token)
- {
- const char *str = token->number;
- unsigned long long value;
- char *end;
- int size = 0, want_unsigned = 0;
- int overflow = 0, do_warn = 0;
- int try_unsigned = 1;
- int bits;
- errno = 0;
- value = parse_num(str, &end);
- if (end == str)
- goto Float;
- if (value == ULLONG_MAX && errno == ERANGE)
- overflow = 1;
- while (1) {
- char c = *end++;
- if (!c) {
- break;
- } else if (c == 'u' || c == 'U') {
- if (want_unsigned)
- goto Enoint;
- want_unsigned = 1;
- } else if (c == 'l' || c == 'L') {
- if (size)
- goto Enoint;
- size = 1;
- if (*end == c) {
- size = 2;
- end++;
- }
- } else
- goto Float;
- }
- if (overflow)
- goto Eoverflow;
- /* OK, it's a valid integer */
- /* decimals can be unsigned only if directly specified as such */
- if (str[0] != '0' && !want_unsigned)
- try_unsigned = 0;
- if (!size) {
- bits = bits_in_int - 1;
- if (!(value & (~1ULL << bits))) {
- if (!(value & (1ULL << bits))) {
- goto got_it;
- } else if (try_unsigned) {
- want_unsigned = 1;
- goto got_it;
- }
- }
- size = 1;
- do_warn = 1;
- }
- if (size < 2) {
- bits = bits_in_long - 1;
- if (!(value & (~1ULL << bits))) {
- if (!(value & (1ULL << bits))) {
- goto got_it;
- } else if (try_unsigned) {
- want_unsigned = 1;
- goto got_it;
- }
- do_warn |= 2;
- }
- size = 2;
- do_warn |= 1;
- }
- bits = bits_in_longlong - 1;
- if (value & (~1ULL << bits))
- goto Eoverflow;
- if (!(value & (1ULL << bits)))
- goto got_it;
- if (!try_unsigned)
- warning(expr->pos, "decimal constant %s is too big for long long",
- show_token(token));
- want_unsigned = 1;
- got_it:
- if (do_warn && Wconstant_suffix)
- warning(expr->pos, "constant %s is so big it is%s%s%s",
- show_token(token),
- want_unsigned ? " unsigned":"",
- size > 0 ? " long":"",
- size > 1 ? " long":"");
- if (do_warn & 2)
- warning(expr->pos,
- "decimal constant %s is between LONG_MAX and ULONG_MAX."
- " For C99 that means long long, C90 compilers are very "
- "likely to produce unsigned long (and a warning) here",
- show_token(token));
- expr->type = EXPR_VALUE;
- expr->flags = CEF_SET_INT;
- expr->ctype = ctype_integer(size, want_unsigned);
- expr->value = value;
- return;
- Eoverflow:
- error_die(expr->pos, "constant %s is too big even for unsigned long long",
- show_token(token));
- return;
- Float:
- expr->fvalue = string_to_ld(str, &end);
- if (str == end)
- goto Enoint;
- if (*end && end[1])
- goto Enoint;
- if (*end == 'f' || *end == 'F')
- expr->ctype = &float_ctype;
- else if (*end == 'l' || *end == 'L')
- expr->ctype = &ldouble_ctype;
- else if (!*end)
- expr->ctype = &double_ctype;
- else
- goto Enoint;
- expr->flags = CEF_SET_FLOAT;
- expr->type = EXPR_FVALUE;
- return;
- Enoint:
- sparse_error(expr->pos, "constant %s is not a valid number", show_token(token));
- expr->type = EXPR_VALUE;
- expr->value = 0;
- expr->ctype = &int_ctype;
- }
- static struct token *generic_selection(struct token *token, struct expression **tree)
- {
- struct expression *expr = alloc_expression(token->pos, EXPR_GENERIC);
- struct type_expression **last = &expr->map;
- token = expect(token, '(', "after '_Generic'");
- token = assignment_expression(token, &expr->control);
- if (!match_op(token, ',')) {
- goto end;
- }
- while (match_op(token, ',')) {
- token = token->next;
- if (lookup_type(token)) {
- struct type_expression *map = __alloc_type_expression(0);
- token = typename(token, &map->type, NULL);
- token = expect(token, ':', "after typename");
- token = assignment_expression(token, &map->expr);
- *last = map;
- last = &map->next;
- } else if (match_ident(token, &default_ident)) {
- if (expr->def) {
- warning(token->pos, "multiple default in generic expression");
- info(expr->def->pos, "note: previous was here");
- }
- token = token->next;
- token = expect(token, ':', "after typename");
- token = assignment_expression(token, &expr->def);
- }
- }
- end:
- *tree = expr;
- return expect(token, ')', "after expression");
- }
- struct token *primary_expression(struct token *token, struct expression **tree)
- {
- struct expression *expr = NULL;
- switch (token_type(token)) {
- case TOKEN_CHAR ... TOKEN_WIDE_CHAR_EMBEDDED_3:
- expr = alloc_expression(token->pos, EXPR_VALUE);
- expr->flags = CEF_SET_CHAR;
- expr->ctype = token_type(token) < TOKEN_WIDE_CHAR ? &int_ctype : &long_ctype;
- get_char_constant(token, &expr->value);
- token = token->next;
- break;
- case TOKEN_NUMBER:
- expr = alloc_expression(token->pos, EXPR_VALUE);
- get_number_value(expr, token); /* will see if it's an integer */
- token = token->next;
- break;
- case TOKEN_ZERO_IDENT: {
- expr = alloc_expression(token->pos, EXPR_SYMBOL);
- expr->flags = CEF_SET_INT;
- expr->ctype = &int_ctype;
- expr->symbol = &zero_int;
- expr->symbol_name = token->ident;
- token = token->next;
- break;
- }
- case TOKEN_IDENT: {
- struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL | NS_TYPEDEF);
- struct token *next = token->next;
- if (!sym) {
- sym = handle_func(token);
- if (token->ident == &__builtin_types_compatible_p_ident) {
- token = builtin_types_compatible_p_expr(token, &expr);
- break;
- }
- if (token->ident == &__builtin_offsetof_ident) {
- token = builtin_offsetof_expr(token, &expr);
- break;
- }
- if (token->ident == &_Generic_ident) {
- token = generic_selection(token->next, &expr);
- break;
- }
- } else if (sym->enum_member) {
- expr = alloc_expression(token->pos, EXPR_VALUE);
- *expr = *sym->initializer;
- /* we want the right position reported, thus the copy */
- expr->pos = token->pos;
- expr->flags = CEF_SET_ENUM;
- token = next;
- break;
- }
- expr = alloc_expression(token->pos, EXPR_SYMBOL);
- /*
- * We support types as real first-class citizens, with type
- * comparisons etc:
- *
- * if (typeof(a) == int) ..
- */
- if (sym && sym->namespace == NS_TYPEDEF) {
- sparse_error(token->pos, "typename in expression");
- sym = NULL;
- }
- expr->symbol_name = token->ident;
- expr->symbol = sym;
- /*
- * A pointer to an lvalue designating a static storage
- * duration object is an address constant [6.6(9)].
- */
- if (sym && (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_STATIC)))
- expr->flags = CEF_ADDR;
- token = next;
- break;
- }
- case TOKEN_STRING:
- case TOKEN_WIDE_STRING:
- expr = alloc_expression(token->pos, EXPR_STRING);
- token = get_string_constant(token, expr);
- break;
- case TOKEN_SPECIAL:
- if (token->special == '(') {
- expr = alloc_expression(token->pos, EXPR_PREOP);
- expr->op = '(';
- token = parens_expression(token, &expr->unop, "in expression");
- break;
- }
- if (token->special == '[' && lookup_type(token->next)) {
- expr = alloc_expression(token->pos, EXPR_TYPE);
- token = typename(token->next, &expr->symbol, NULL);
- token = expect(token, ']', "in type expression");
- break;
- }
-
- default:
- ;
- }
- *tree = expr;
- return token;
- }
- static struct token *expression_list(struct token *token, struct expression_list **list)
- {
- while (!match_op(token, ')')) {
- struct expression *expr = NULL;
- token = assignment_expression(token, &expr);
- if (!expr)
- break;
- add_expression(list, expr);
- if (!match_op(token, ','))
- break;
- token = token->next;
- }
- return token;
- }
- /*
- * extend to deal with the ambiguous C grammar for parsing
- * a cast expressions followed by an initializer.
- */
- static struct token *postfix_expression(struct token *token, struct expression **tree, struct expression *cast_init_expr)
- {
- struct expression *expr = cast_init_expr;
- if (!expr)
- token = primary_expression(token, &expr);
- while (expr && token_type(token) == TOKEN_SPECIAL) {
- switch (token->special) {
- case '[': { /* Array dereference */
- struct expression *deref = alloc_expression(token->pos, EXPR_PREOP);
- struct expression *add = alloc_expression(token->pos, EXPR_BINOP);
- deref->op = '*';
- deref->unop = add;
- add->op = '+';
- add->left = expr;
- token = parse_expression(token->next, &add->right);
- token = expect(token, ']', "at end of array dereference");
- expr = deref;
- continue;
- }
- case SPECIAL_INCREMENT: /* Post-increment */
- case SPECIAL_DECREMENT: { /* Post-decrement */
- struct expression *post = alloc_expression(token->pos, EXPR_POSTOP);
- post->op = token->special;
- post->unop = expr;
- expr = post;
- token = token->next;
- continue;
- }
- case SPECIAL_DEREFERENCE: { /* Structure pointer member dereference */
- /* "x->y" is just shorthand for "(*x).y" */
- struct expression *inner = alloc_expression(token->pos, EXPR_PREOP);
- inner->op = '*';
- inner->unop = expr;
- expr = inner;
- }
- /* Fall through!! */
- case '.': { /* Structure member dereference */
- struct expression *deref = alloc_expression(token->pos, EXPR_DEREF);
- deref->op = '.';
- deref->deref = expr;
- token = token->next;
- if (token_type(token) != TOKEN_IDENT) {
- sparse_error(token->pos, "Expected member name");
- break;
- }
- deref->member = token->ident;
- token = token->next;
- expr = deref;
- continue;
- }
- case '(': { /* Function call */
- struct expression *call = alloc_expression(token->pos, EXPR_CALL);
- call->op = '(';
- call->fn = expr;
- token = expression_list(token->next, &call->args);
- token = expect(token, ')', "in function call");
- expr = call;
- continue;
- }
- default:
- break;
- }
- break;
- }
- *tree = expr;
- return token;
- }
- static struct token *cast_expression(struct token *token, struct expression **tree);
- static struct token *unary_expression(struct token *token, struct expression **tree);
- static struct token *type_info_expression(struct token *token,
- struct expression **tree, int type)
- {
- struct expression *expr = alloc_expression(token->pos, type);
- struct token *p;
- *tree = expr;
- expr->flags = CEF_SET_ICE; /* XXX: VLA support will need that changed */
- token = token->next;
- if (!match_op(token, '(') || !lookup_type(token->next))
- return unary_expression(token, &expr->cast_expression);
- p = token;
- token = typename(token->next, &expr->cast_type, NULL);
- if (!match_op(token, ')')) {
- static const char * error[] = {
- [EXPR_SIZEOF] = "at end of sizeof",
- [EXPR_ALIGNOF] = "at end of __alignof__",
- [EXPR_PTRSIZEOF] = "at end of __sizeof_ptr__"
- };
- return expect(token, ')', error[type]);
- }
- token = token->next;
- /*
- * C99 ambiguity: the typename might have been the beginning
- * of a typed initializer expression..
- */
- if (match_op(token, '{')) {
- struct expression *cast = alloc_expression(p->pos, EXPR_CAST);
- cast->cast_type = expr->cast_type;
- expr->cast_type = NULL;
- expr->cast_expression = cast;
- token = initializer(&cast->cast_expression, token);
- token = postfix_expression(token, &expr->cast_expression, cast);
- }
- return token;
- }
- static struct token *unary_expression(struct token *token, struct expression **tree)
- {
- if (token_type(token) == TOKEN_IDENT) {
- struct ident *ident = token->ident;
- if (ident->reserved) {
- static const struct {
- struct ident *id;
- int type;
- } type_information[] = {
- { &sizeof_ident, EXPR_SIZEOF },
- { &__alignof___ident, EXPR_ALIGNOF },
- { &__alignof_ident, EXPR_ALIGNOF },
- { &_Alignof_ident, EXPR_ALIGNOF },
- { &__sizeof_ptr___ident, EXPR_PTRSIZEOF },
- };
- int i;
- for (i = 0; i < ARRAY_SIZE(type_information); i++) {
- if (ident == type_information[i].id)
- return type_info_expression(token, tree, type_information[i].type);
- }
- }
- }
- if (token_type(token) == TOKEN_SPECIAL) {
- if (match_oplist(token->special,
- SPECIAL_INCREMENT, SPECIAL_DECREMENT,
- '&', '*', 0)) {
- struct expression *unop;
- struct expression *unary;
- struct token *next;
- next = cast_expression(token->next, &unop);
- if (!unop) {
- sparse_error(token->pos, "Syntax error in unary expression");
- *tree = NULL;
- return next;
- }
- unary = alloc_expression(token->pos, EXPR_PREOP);
- unary->op = token->special;
- unary->unop = unop;
- *tree = unary;
- return next;
- }
- /* possibly constant ones */
- if (match_oplist(token->special, '+', '-', '~', '!', 0)) {
- struct expression *unop;
- struct expression *unary;
- struct token *next;
- next = cast_expression(token->next, &unop);
- if (!unop) {
- sparse_error(token->pos, "Syntax error in unary expression");
- *tree = NULL;
- return next;
- }
- unary = alloc_expression(token->pos, EXPR_PREOP);
- unary->op = token->special;
- unary->unop = unop;
- *tree = unary;
- return next;
- }
- /* Gcc extension: &&label gives the address of a label */
- if (match_op(token, SPECIAL_LOGICAL_AND) &&
- token_type(token->next) == TOKEN_IDENT) {
- struct expression *label = alloc_expression(token->pos, EXPR_LABEL);
- struct symbol *sym = label_symbol(token->next, 1);
- if (!(sym->ctype.modifiers & MOD_ADDRESSABLE)) {
- sym->ctype.modifiers |= MOD_ADDRESSABLE;
- add_symbol(&function_computed_target_list, sym);
- }
- check_label_usage(sym, token->pos);
- label->flags = CEF_ADDR;
- label->label_symbol = sym;
- *tree = label;
- return token->next->next;
- }
-
- }
-
- return postfix_expression(token, tree, NULL);
- }
- /*
- * Ambiguity: a '(' can be either a cast-expression or
- * a primary-expression depending on whether it is followed
- * by a type or not.
- *
- * additional ambiguity: a "cast expression" followed by
- * an initializer is really a postfix-expression.
- */
- static struct token *cast_expression(struct token *token, struct expression **tree)
- {
- if (match_op(token, '(')) {
- struct token *next = token->next;
- if (lookup_type(next)) {
- struct expression *cast = alloc_expression(next->pos, EXPR_CAST);
- struct expression *v;
- struct symbol *sym;
- int is_force;
- token = typename(next, &sym, &is_force);
- cast->cast_type = sym;
- token = expect(token, ')', "at end of cast operator");
- if (match_op(token, '{')) {
- if (toplevel(block_scope))
- sym->ctype.modifiers |= MOD_TOPLEVEL;
- if (is_force)
- warning(sym->pos,
- "[force] in compound literal");
- token = initializer(&cast->cast_expression, token);
- return postfix_expression(token, tree, cast);
- }
- *tree = cast;
- if (is_force)
- cast->type = EXPR_FORCE_CAST;
- token = cast_expression(token, &v);
- if (!v)
- return token;
- cast->cast_expression = v;
- return token;
- }
- }
- return unary_expression(token, tree);
- }
- /*
- * Generic left-to-right binop parsing
- *
- * This _really_ needs to be inlined, because that makes the inner
- * function call statically deterministic rather than a totally
- * unpredictable indirect call. But gcc-3 is so "clever" that it
- * doesn't do so by default even when you tell it to inline it.
- *
- * Making it a macro avoids the inlining problem, and also means
- * that we can pass in the op-comparison as an expression rather
- * than create a data structure for it.
- */
- #define LR_BINOP_EXPRESSION(__token, tree, type, inner, compare) \
- struct expression *left = NULL; \
- struct token * next = inner(__token, &left); \
- \
- if (left) { \
- while (token_type(next) == TOKEN_SPECIAL) { \
- struct expression *top, *right = NULL; \
- int op = next->special; \
- \
- if (!(compare)) \
- goto out; \
- top = alloc_expression(next->pos, type); \
- next = inner(next->next, &right); \
- if (!right) { \
- sparse_error(next->pos, "No right hand side of '%s'-expression", show_special(op)); \
- break; \
- } \
- top->op = op; \
- top->left = left; \
- top->right = right; \
- left = top; \
- } \
- } \
- out: \
- *tree = left; \
- return next; \
- static struct token *multiplicative_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_BINOP, cast_expression,
- (op == '*') || (op == '/') || (op == '%')
- );
- }
- static struct token *additive_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_BINOP, multiplicative_expression,
- (op == '+') || (op == '-')
- );
- }
- static struct token *shift_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_BINOP, additive_expression,
- (op == SPECIAL_LEFTSHIFT) || (op == SPECIAL_RIGHTSHIFT)
- );
- }
- static struct token *relational_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_COMPARE, shift_expression,
- (op == '<') || (op == '>') ||
- (op == SPECIAL_LTE) || (op == SPECIAL_GTE)
- );
- }
- static struct token *equality_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_COMPARE, relational_expression,
- (op == SPECIAL_EQUAL) || (op == SPECIAL_NOTEQUAL)
- );
- }
- static struct token *bitwise_and_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_BINOP, equality_expression,
- (op == '&')
- );
- }
- static struct token *bitwise_xor_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_BINOP, bitwise_and_expression,
- (op == '^')
- );
- }
- static struct token *bitwise_or_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_BINOP, bitwise_xor_expression,
- (op == '|')
- );
- }
- static struct token *logical_and_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_LOGICAL, bitwise_or_expression,
- (op == SPECIAL_LOGICAL_AND)
- );
- }
- static struct token *logical_or_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_LOGICAL, logical_and_expression,
- (op == SPECIAL_LOGICAL_OR)
- );
- }
- struct token *conditional_expression(struct token *token, struct expression **tree)
- {
- token = logical_or_expression(token, tree);
- if (*tree && match_op(token, '?')) {
- struct expression *expr = alloc_expression(token->pos, EXPR_CONDITIONAL);
- expr->op = token->special;
- expr->conditional = *tree;
- *tree = expr;
- token = parse_expression(token->next, &expr->cond_true);
- token = expect(token, ':', "in conditional expression");
- token = conditional_expression(token, &expr->cond_false);
- }
- return token;
- }
- struct token *assignment_expression(struct token *token, struct expression **tree)
- {
- token = conditional_expression(token, tree);
- if (*tree && token_type(token) == TOKEN_SPECIAL) {
- static const int assignments[] = {
- '=',
- SPECIAL_ADD_ASSIGN, SPECIAL_SUB_ASSIGN,
- SPECIAL_MUL_ASSIGN, SPECIAL_DIV_ASSIGN,
- SPECIAL_MOD_ASSIGN, SPECIAL_SHL_ASSIGN,
- SPECIAL_SHR_ASSIGN, SPECIAL_AND_ASSIGN,
- SPECIAL_OR_ASSIGN, SPECIAL_XOR_ASSIGN };
- int i, op = token->special;
- for (i = 0; i < ARRAY_SIZE(assignments); i++)
- if (assignments[i] == op) {
- struct expression * expr = alloc_expression(token->pos, EXPR_ASSIGNMENT);
- struct token *next = token->next;
- expr->left = *tree;
- expr->op = op;
- *tree = expr;
- token = assignment_expression(next, &expr->right);
- if (token == next)
- expression_error(expr, "expression expected before '%s'", show_token(token));
- return token;
- }
- }
- return token;
- }
- static struct token *comma_expression(struct token *token, struct expression **tree)
- {
- LR_BINOP_EXPRESSION(
- token, tree, EXPR_COMMA, assignment_expression,
- (op == ',')
- );
- }
- struct token *parse_expression(struct token *token, struct expression **tree)
- {
- return comma_expression(token,tree);
- }
|