aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--evaluate.c63
-rw-r--r--expression.c21
-rw-r--r--expression.h24
-rw-r--r--lib.c13
-rw-r--r--lib.h17
-rw-r--r--parse.h2
-rw-r--r--show-parse.c24
-rw-r--r--test-parsing.c2
8 files changed, 158 insertions, 8 deletions
diff --git a/evaluate.c b/evaluate.c
index b9f9bf82..7dcbd08d 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -146,6 +146,13 @@ static int evaluate_binop(struct expression *expr)
return 0;
}
+static int evaluate_assignment(struct expression *expr)
+{
+ // FIXME! We need to cast and check the rigth side!
+ expr->ctype = expr->left->ctype;
+ return 1;
+}
+
static int evaluate_preop(struct expression *expr)
{
struct symbol *ctype = expr->unop->ctype;
@@ -289,6 +296,54 @@ static int evaluate_sizeof(struct expression *expr)
return 1;
}
+static int evaluate_lvalue_expression(struct expression *expr)
+{
+ // FIXME!
+ return evaluate_expression(expr);
+}
+
+static int evaluate_expression_list(struct expression_list *head)
+{
+ if (head) {
+ struct ptr_list *list = (struct ptr_list *)head;
+ do {
+ int i;
+ for (i = 0; i < list->nr; i++) {
+ struct expression *expr = (struct expression *)list->list[i];
+ evaluate_expression(expr);
+ }
+ } while ((list = list->next) != (struct ptr_list *)head);
+ }
+ // FIXME!
+ return 1;
+}
+
+static int evaluate_call(struct expression *expr)
+{
+ int args, fnargs;
+ struct symbol *ctype;
+ struct expression *fn = expr->fn;
+ struct expression_list *arglist = expr->args;
+
+ if (!evaluate_expression(fn))
+ return 0;
+ if (!evaluate_expression_list(arglist))
+ return 0;
+ ctype = fn->ctype;
+ if (ctype->type != SYM_FN) {
+ warn(expr->token, "not a function");
+ return 0;
+ }
+ args = expression_list_size(expr->args);
+ fnargs = symbol_list_size(ctype->arguments);
+ if (args < fnargs)
+ warn(expr->token, "not enough arguments for function");
+ if (args > fnargs && !ctype->variadic)
+ warn(expr->token, "too many arguments for function");
+ expr->ctype = ctype->ctype.base_type;
+ return 1;
+}
+
int evaluate_expression(struct expression *expr)
{
if (!expr)
@@ -307,6 +362,12 @@ int evaluate_expression(struct expression *expr)
if (!evaluate_expression(expr->right))
return 0;
return evaluate_binop(expr);
+ case EXPR_ASSIGNMENT:
+ if (!evaluate_lvalue_expression(expr->left))
+ return 0;
+ if (!evaluate_expression(expr->right))
+ return 0;
+ return evaluate_assignment(expr);
case EXPR_PREOP:
if (!evaluate_expression(expr->unop))
return 0;
@@ -324,6 +385,8 @@ int evaluate_expression(struct expression *expr)
return evaluate_sizeof(expr);
case EXPR_DEREF:
return evaluate_dereference(expr);
+ case EXPR_CALL:
+ return evaluate_call(expr);
default:
break;
}
diff --git a/expression.c b/expression.c
index 0ca6c19e..0d3f66f7 100644
--- a/expression.c
+++ b/expression.c
@@ -93,6 +93,21 @@ struct token *primary_expression(struct token *token, struct expression **tree)
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;
+}
+
static struct token *postfix_expression(struct token *token, struct expression **tree)
{
struct expression *expr = NULL;
@@ -142,8 +157,8 @@ static struct token *postfix_expression(struct token *token, struct expression *
case '(': { /* Function call */
struct expression *call = alloc_expression(token, EXPR_CALL);
call->op = '(';
- call->left = expr;
- token = comma_expression(token->next, &call->right);
+ call->fn = expr;
+ token = expression_list(token->next, &call->args);
token = expect(token, ')', "in function call");
expr = call;
continue;
@@ -331,7 +346,7 @@ struct token *assignment_expression(struct token *token, struct expression **tre
int i, op = token->special;
for (i = 0; i < sizeof(assignments)/sizeof(int); i++)
if (assignments[i] == op) {
- struct expression * expr = alloc_expression(token, EXPR_BINOP);
+ struct expression * expr = alloc_expression(token, EXPR_ASSIGNMENT);
expr->left = *tree;
expr->op = op;
*tree = expr;
diff --git a/expression.h b/expression.h
index 83dbc6a8..56a1d7df 100644
--- a/expression.h
+++ b/expression.h
@@ -8,11 +8,14 @@
* Declarations and helper functions for expression parsing.
*/
+struct expression_list;
+
enum expression_type {
EXPR_CONSTANT,
EXPR_VALUE,
EXPR_SYMBOL,
EXPR_BINOP,
+ EXPR_ASSIGNMENT,
EXPR_DEREF,
EXPR_PREOP,
EXPR_POSTOP,
@@ -28,27 +31,40 @@ struct expression {
struct token *token;
struct symbol *ctype;
union {
+ // EXPR_VALUE
long long value;
+
+ // EXPR_UNOP, EXPR_PREOP and EXPR_POSTOP
struct expression *unop;
- struct statement *statement;
+
+ // EXPR_SYMBOL
struct symbol *symbol;
+
+ // EXPR_STATEMENT
+ struct statement *statement;
+
+ // EXPR_BINOP and EXPR_ASSIGNMENT
struct binop_arg {
struct expression *left, *right;
};
+ // EXPR_DEREF
struct deref_arg {
struct expression *deref;
struct token *member;
};
+ // EXPR_CAST and EXPR_SIZEOF
struct cast_arg {
struct symbol *cast_type;
struct expression *cast_expression;
};
+ // EXPR_CONDITIONAL
struct conditional_expr {
struct expression *conditional, *cond_true, *cond_false;
};
- struct statement_struct {
- struct symbol_list *syms;
- struct statement_list *stmts;
+ // EXPR_CALL
+ struct call_expr {
+ struct expression *fn;
+ struct expression_list *args;
};
};
};
diff --git a/lib.c b/lib.c
index 277e43f2..3c89fd28 100644
--- a/lib.c
+++ b/lib.c
@@ -163,6 +163,19 @@ ALLOCATOR(ident); ALLOCATOR(token); ALLOCATOR(symbol);
ALLOCATOR(expression); ALLOCATOR(statement); ALLOCATOR(string);
__ALLOCATOR(void, 0, , bytes);
+int ptr_list_size(struct ptr_list *head)
+{
+ int nr = 0;
+
+ if (head) {
+ struct ptr_list *list = head;
+ do {
+ nr += list->nr;
+ } while ((list = list->next) != head);
+ }
+ return nr;
+}
+
void iterate(struct ptr_list *head, void (*callback)(void *, void *, int), void *data)
{
struct ptr_list *list = head;
diff --git a/lib.h b/lib.h
index 6ad1a770..34c51b1e 100644
--- a/lib.h
+++ b/lib.h
@@ -14,6 +14,8 @@ struct symbol;
struct symbol_list;
struct statement;
struct statement_list;
+struct expression;
+struct expression_list;
struct token *skip_to(struct token *, int);
struct token *expect(struct token *, int, const char *);
@@ -47,6 +49,11 @@ struct ptr_list {
#define ITERATE_LAST 2
void iterate(struct ptr_list *,void (*callback)(void *, void *, int), void*);
extern void add_ptr_list(struct ptr_list **, void *);
+extern int ptr_list_size(struct ptr_list *);
+
+#define symbol_list_size(list) ptr_list_size((struct ptr_list *)(list))
+#define statement_list_size(list) ptr_list_size((struct ptr_list *)(list))
+#define expression_list_size(list) ptr_list_size((struct ptr_list *)(list))
static inline void add_symbol(struct symbol_list **list, struct symbol *sym)
{
@@ -58,6 +65,11 @@ static inline void add_statement(struct statement_list **list, struct statement
add_ptr_list((struct ptr_list **)list, stmt);
}
+static inline void add_expression(struct expression_list **list, struct expression *expr)
+{
+ add_ptr_list((struct ptr_list **)list, expr);
+}
+
static inline void symbol_iterate(struct symbol_list *list, void (*callback)(struct symbol *, void *, int), void *data)
{
iterate((struct ptr_list *)list, (void (*)(void *, void *, int))callback, data);
@@ -68,4 +80,9 @@ static inline void statement_iterate(struct statement_list *list, void (*callbac
iterate((struct ptr_list *)list, (void (*)(void *, void *, int))callback, data);
}
+static inline void expression_iterate(struct expression_list *list, void (*callback)(struct expression *, void *, int), void *data)
+{
+ iterate((struct ptr_list *)list, (void (*)(void *, void *, int))callback, data);
+}
+
#endif
diff --git a/parse.h b/parse.h
index 7e74814e..6909efe8 100644
--- a/parse.h
+++ b/parse.h
@@ -25,7 +25,7 @@ enum statement_type {
};
struct statement {
- int type;
+ enum statement_type type;
struct token *token;
struct statement *next;
union {
diff --git a/show-parse.c b/show-parse.c
index 8ac94500..b3badd2c 100644
--- a/show-parse.c
+++ b/show-parse.c
@@ -334,6 +334,18 @@ static void show_size(struct symbol *sym)
printf("%d:%d", sym->bit_size, sym->alignment);
}
+static void show_one_expression(struct expression *expr, void *sep, int flags)
+{
+ show_expression(expr);
+ if (!(flags & ITERATE_LAST))
+ printf("%s", (const char *)sep);
+}
+
+void show_expression_list(struct expression_list *list, const char *sep)
+{
+ expression_iterate(list, show_one_expression, (void *)sep);
+}
+
/*
* Print out an expression
*/
@@ -347,6 +359,18 @@ void show_expression(struct expression *expr)
show_type(expr->ctype);
printf(") ");
switch (expr->type) {
+ case EXPR_CALL:
+ show_expression(expr->fn);
+ printf("( ");
+ show_expression_list(expr->args, ", ");
+ printf(" )");
+ break;
+
+ case EXPR_ASSIGNMENT:
+ show_expression(expr->left);
+ printf(" %s ", show_special(expr->op));
+ show_expression(expr->right);
+ break;
case EXPR_BINOP:
show_expression(expr->left);
printf(" %s ", show_special(expr->op));
diff --git a/test-parsing.c b/test-parsing.c
index b5ecb501..908a70cb 100644
--- a/test-parsing.c
+++ b/test-parsing.c
@@ -60,6 +60,8 @@ static void simplify_statement(struct statement *stmt, struct symbol *fn)
evaluate_expression(stmt->case_to);
simplify_statement(stmt->case_statement, fn);
return;
+ default:
+ break;
}
}