/* * Copyright (c) 2005 - 2006, 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. * * Parsing of, and icode generation for, sub-expressions */ #include "expr.h" #include "subexpr.h" #include #include #include "token.h" #include "error.h" #if 0 #include "misc.h" #endif #include "defs.h" #if 0 #include "decl.h" #include "scope.h" #endif #include "type.h" #if 0 #include "icode.h" #include "cc1_main.h" #include "debug.h" #include "functions.h" #include "backend.h" #include "reg.h" #include "builtins.h" #endif #include "n_libc.h" struct context { struct type curtype; struct decl *var_lvalue; struct vreg *curitem; struct vreg *load; int is_lvalue; int indir; }; static struct s_expr * alloc_s_expr(void) { struct s_expr *ret = n_xmalloc(sizeof *ret); static struct s_expr nullop; *ret = nullop; return ret; } static int ambig_to_unary(struct token *t, int is_prefix) { int op = *(int *)t->data; switch (op) { case TOK_OP_AMB_PLUS: if (is_prefix) op = TOK_OP_UPLUS; break; case TOK_OP_AMB_MINUS: if (is_prefix) op = TOK_OP_UMINUS; break; case TOK_OP_AMB_MULTI: if (is_prefix) op = TOK_OP_DEREF; break; case TOK_OP_AMB_BAND: if (is_prefix) op = TOK_OP_ADDR; break; case TOK_OP_AMB_INCR: if (is_prefix) op = TOK_OP_INCPRE; else op = TOK_OP_INCPOST; break; case TOK_OP_AMB_DECR: if (is_prefix) op = TOK_OP_DECPRE; else op = TOK_OP_DECPOST; break; default: /* XXX handle labels! foo: */ ; break; } if (is_prefix && !IS_UNARY(op)) { /* * foo + bar is ok * / foo is not */ errorfl(t, "Invalid use of operator `%s'", t->ascii); return -1; } return op; } /* * Function that reads what I like to refer to as ``sub-expression''. * A sub-expression is just an argument to the binary and ternary * operators, and it includes all possible unary/prefix/postfix * operators (bitwise/logical negation, pre/post-inc/dec-rement, * function call, indirection, etc.) * This is typically an identifier or a constant, possibly including * operators, but it may also be a parenthesized expression, which * in turn consists of one or more sub-expressions. * * In other words, a ``sub-expression'' is what the standard refers to * as ``unary expression'' * * Examples: * +foo + *bar-- * ^^^^ ^^^^^^ * *(x + 5) - foo? bar: baz * ^ ^ * ^^^^^^^^ ^^^ ^^^ ^^^ */ struct s_expr * get_sub_expr(struct token **tok, int delim, int delim2, int extype) { struct token *t; struct token *meat = NULL; struct token *left; struct token *right; struct token *is_sizeof = NULL; struct token *continue_at = NULL; struct token *endp = NULL; struct expr *ex = NULL; struct expr *is_expr = NULL; struct decl **decv; int is_func_call = 0; struct token *operators[128]; /* XXX */ struct token *operators_f[128]; void *res = NULL; struct icode_instr *ii; struct icode_list *il; struct s_expr *ret = NULL; int op; int i; int j = 0; t = *tok; #if 0 il = alloc_icode_list(); il->head = il->tail = NULL; #endif /* * Read prefix or unary operators, if any, and the * identifier/constant/parenthesized expression * constituting this sub-expression */ for (t = *tok, i = 0; t != NULL; t = t->next) { ii = NULL; if (expr_ends(t, delim, delim2)) { if (t == *tok) { errorfl(t, "Parse error at `%s'", t->ascii); return NULL; } endp = t; goto out; } else if (t->type == TOK_PAREN_OPEN) { /* Must be parenthesized expression */ t = t->next; ex = parse_expr(&t, TOK_PAREN_CLOSE, 0, extype); if (ex == NULL) { return NULL; } is_expr = ex; continue_at = t; break; } else if (t->type == TOK_OPERATOR) { /* Must be unary prefix operator */ if ((op = ambig_to_unary(t, 1)) == -1) { return NULL; } *(int *)t->data = op; operators[i++] = t; } else if (t->type == TOK_IDENTIFIER) { int is_defined = 0; if (strcmp(t->data, "defined") == 0) { is_defined = 1; t->type = TOK_DEFINED; } if (t->next && t->next->type == TOK_PAREN_OPEN) { if (is_defined) { if (t->next->next == NULL || t->next->next->next == NULL) { lexerror("Incomplete `defined()' " "expression"); return NULL; } else if (t->next->next->type != TOK_IDENTIFIER) { lexerror("Invlaid `defined()' " "expression - no " "identifier argument"); return NULL; } else if (t->next->next->next->type != TOK_PAREN_CLOSE) { lexerror("Invalid `defined()' " "expression - no " "closing `)'"); return NULL; } t->data = t->next->next; continue_at = t->next->next->next->next; } else { /* Is function call */ is_func_call = 1; } } else if (is_defined) { if (t->next && t->next->type == TOK_IDENTIFIER) { t->data = t->next; continue_at = t->next->next; } else { lexerror("Invalid `defined' expression - " "not followed by identifier"); return NULL; } } meat = t; break; } else if (IS_CONSTANT(t->type)) { if (IS_FLOATING(t->type)) { lexerror("Floating point constant in preprocessor" " expression"); return NULL; } meat = t; break; } else if (t->type == TOK_STRING_LITERAL) { errorfl(t, "String constants may not be used in " "preprocessor expressions"); return NULL; } else { errorfl(t, "Parse error at `%s'(#1)", t->ascii); abort(); } } if (is_expr) { right = continue_at; if (next_token(&right) != 0) { return NULL; } } else if (meat->type == TOK_DEFINED) { right = continue_at; } else if (is_func_call) { right = meat->next; } else if (!is_sizeof) { if (meat != *tok) { left = meat->prev; } else { left = NULL; } right = meat; if (next_token(&right) != 0) { return NULL; } } else { right = NULL; } /* * Compare prefix with postfix operators and * bind them accordingly */ if (i > 0) { left = operators[--i]; } else { left = NULL; } j = 0; for (;;) { if (right != NULL) { endp = right; if (expr_ends(right, delim, delim2)) { right = NULL; } } /* * Postfix operators always have higher precedence * than prefix and unary operators */ res = NULL; if (right != NULL) { if (right->type == TOK_PAREN_OPEN) { /* Must be function-like macro ``call'' */ #if 0 res = do_func_call(meat, &right, 1); if (res == NULL) { return NULL; } fres = res; if (fres->builtin && fres->builtin->type == BUILTIN_EXPECT) { if (is_expr) { errorfl(right, "Parse error at `%s'", right->ascii); return NULL; } is_expr = fres->builtin->args[0]; } else { operators_f[j] = old_right; operators_f[j++]->data = res; } #endif } else if (right->type == TOK_OPERATOR) { /* * Must be postfix operator or end of * sub-expression */ op = ambig_to_unary(right, 0); if (IS_UNARY(op)) { /* XXX handle op */ operators_f[j++] = right; *(int *)right->data = op; } else { right = NULL; } } else if (right->type == TOK_ARRAY_OPEN) { operators_f[j] = right; if (next_token(&right) != 0) { return NULL; } res = parse_expr(&right, TOK_ARRAY_CLOSE, 0, 0); if (res == NULL) { return NULL; } operators_f[j++]->data = res; } else { right = NULL; } if (right) right = right->next; } else if (left != NULL) { operators_f[j++] = left; if (i > 0) { left = operators[--i]; } else { left = NULL; } } else { break; } } operators_f[j++] = NULL; out: *tok = endp; if (meat == NULL && is_expr == NULL && is_sizeof == NULL) { errorfl(endp, "Parse error at `%s'", endp->ascii); } ret = alloc_s_expr(); memcpy(ret->operators, operators_f, j * sizeof *operators_f); ret->is_expr = is_expr; ret->meat = meat; ret->is_sizeof = is_sizeof; return ret; }