/*
* 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 <stdlib.h>
#include <string.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1