Merge branch 'master' into blub/parser

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-08-14 10:42:34 +02:00
commit 82d9651529
2 changed files with 201 additions and 6 deletions

175
ast.c
View file

@ -58,6 +58,8 @@ static void ast_expression_init(ast_expression *self,
self->expression.codegen = codegen;
self->expression.vtype = TYPE_VOID;
self->expression.next = NULL;
self->expression.outl = NULL;
self->expression.outr = NULL;
MEM_VECTOR_INIT(&self->expression, params);
}
@ -234,6 +236,39 @@ void ast_binary_delete(ast_binary *self)
mem_d(self);
}
ast_binstore* ast_binstore_new(lex_ctx ctx, int storop, int op,
ast_expression* left, ast_expression* right)
{
ast_instantiate(ast_binstore, ctx, ast_binstore_delete);
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_binstore_codegen);
self->opstore = storop;
self->opbin = op;
self->dest = left;
self->source = right;
self->expression.vtype = left->expression.vtype;
if (left->expression.next) {
self->expression.next = ast_type_copy(ctx, left);
if (!self->expression.next) {
ast_delete(self);
return NULL;
}
}
else
self->expression.next = NULL;
return self;
}
void ast_binstore_delete(ast_binstore *self)
{
ast_unref(self->dest);
ast_unref(self->source);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
ast_unary* ast_unary_new(lex_ctx ctx, int op,
ast_expression *expr)
{
@ -823,6 +858,10 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu
* of the form: (a, b, c) = x should not assign to c...
*/
(void)lvalue;
if (self->expression.outr) {
*out = self->expression.outr;
return true;
}
/* output is NULL at first, we'll have each expression
* assign to out output, thus, a comma-operator represention
@ -846,6 +885,8 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu
return false;
}
self->expression.outr = *out;
return true;
}
@ -854,10 +895,21 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu
ast_expression_codegen *cgen;
ir_value *left, *right;
if (lvalue && self->expression.outl) {
*out = self->expression.outl;
return true;
}
if (!lvalue && self->expression.outr) {
*out = self->expression.outr;
return true;
}
cgen = self->dest->expression.codegen;
/* lvalue! */
if (!(*cgen)((ast_expression*)(self->dest), func, true, &left))
return false;
self->expression.outl = left;
cgen = self->source->expression.codegen;
/* rvalue! */
@ -866,6 +918,7 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu
if (!ir_block_create_store_op(func->curblock, self->op, left, right))
return false;
self->expression.outr = right;
/* Theoretically, an assinment returns its left side as an
* lvalue, if we don't need an lvalue though, we return
@ -887,7 +940,11 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
/* In the context of a binary operation, we can disregard
* the lvalue flag.
*/
(void)lvalue;
(void)lvalue;
if (self->expression.outr) {
*out = self->expression.outr;
return true;
}
cgen = self->left->expression.codegen;
/* lvalue! */
@ -903,6 +960,61 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
self->op, left, right);
if (!*out)
return false;
self->expression.outr = *out;
return true;
}
bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
ir_value *leftl, *leftr, *right, *bin;
if (lvalue && self->expression.outl) {
*out = self->expression.outl;
return true;
}
if (!lvalue && self->expression.outr) {
*out = self->expression.outr;
return true;
}
/* for a binstore we need both an lvalue and an rvalue for the left side */
/* rvalue of destination! */
cgen = self->dest->expression.codegen;
if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftr))
return false;
/* source as rvalue only */
cgen = self->source->expression.codegen;
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
/* now the binary */
bin = ir_block_create_binop(func->curblock, ast_function_label(func, "binst"),
self->opbin, leftr, right);
self->expression.outr = bin;
/* now store them */
cgen = self->dest->expression.codegen;
/* lvalue of destination */
if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftl))
return false;
self->expression.outl = leftl;
if (!ir_block_create_store_op(func->curblock, self->opstore, leftl, bin))
return false;
self->expression.outr = bin;
/* Theoretically, an assinment returns its left side as an
* lvalue, if we don't need an lvalue though, we return
* the right side as an rvalue, otherwise we have to
* somehow know whether or not we need to dereference the pointer
* on the left side - that is: OP_LOAD if it was an address.
* Also: in original QC we cannot OP_LOADP *anyway*.
*/
*out = (lvalue ? leftl : bin);
return true;
}
@ -916,6 +1028,10 @@ bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_valu
* the lvalue flag.
*/
(void)lvalue;
if (self->expression.outr) {
*out = self->expression.outr;
return true;
}
cgen = self->operand->expression.codegen;
/* lvalue! */
@ -926,6 +1042,7 @@ bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_valu
self->op, operand);
if (!*out)
return false;
self->expression.outr = *out;
return true;
}
@ -939,6 +1056,11 @@ bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_va
* the lvalue flag.
*/
(void)lvalue;
if (self->expression.outr) {
printf("internal error: ast_return cannot be reused, it bears no result!\n");
return false;
}
self->expression.outr = (ir_value*)1;
cgen = self->operand->expression.codegen;
/* lvalue! */
@ -961,6 +1083,16 @@ bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, i
* value in a temp.
*/
if (lvalue && self->expression.outl) {
*out = self->expression.outl;
return true;
}
if (!lvalue && self->expression.outr) {
*out = self->expression.outr;
return true;
}
cgen = self->entity->expression.codegen;
if (!(*cgen)((ast_expression*)(self->entity), func, false, &ent))
return false;
@ -980,6 +1112,11 @@ bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, i
if (!*out)
return false;
if (lvalue)
self->expression.outl = *out;
else
self->expression.outr = *out;
/* Hm that should be it... */
return true;
}
@ -989,6 +1126,13 @@ bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_va
ast_expression_codegen *cgen;
ir_value *vec;
/* in QC this is always an lvalue */
(void)lvalue;
if (self->expression.outl) {
*out = self->expression.outl;
return true;
}
cgen = self->owner->expression.codegen;
if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec))
return false;
@ -1000,6 +1144,7 @@ bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_va
}
*out = ir_value_vector_member(vec, self->field);
self->expression.outl = *out;
return (*out != NULL);
}
@ -1020,6 +1165,12 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va
(void)out;
(void)lvalue;
if (self->expression.outr) {
printf("internal error: ast_ifthen cannot be reused, it bears no result!\n");
return false;
}
self->expression.outr = (ir_value*)1;
/* generate the condition */
func->curblock = cond;
cgen = self->cond->expression.codegen;
@ -1100,6 +1251,10 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_
ir_block *onfalse;
ir_block *merge;
/* Ternary can never create an lvalue... */
if (lvalue)
return false;
/* In theory it shouldn't be possible to pass through a node twice, but
* in case we add any kind of optimization pass for the AST itself, it
* may still happen, thus we remember a created ir_value and simply return one
@ -1110,10 +1265,6 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_
return true;
}
/* Ternary can never create an lvalue... */
if (lvalue)
return false;
/* In the following, contraty to ast_ifthen, we assume both paths exist. */
/* generate the condition */
@ -1225,6 +1376,12 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
(void)lvalue;
(void)out;
if (self->expression.outr) {
printf("internal error: ast_loop cannot be reused, it bears no result!\n");
return false;
}
self->expression.outr = (ir_value*)1;
/* NOTE:
* Should we ever need some kind of block ordering, better make this function
* move blocks around than write a block ordering algorithm later... after all
@ -1429,9 +1586,14 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value
ir_value *funval = NULL;
/* return values are never rvalues */
/* return values are never lvalues */
(void)lvalue;
if (self->expression.outr) {
*out = self->expression.outr;
return true;
}
cgen = self->func->expression.codegen;
if (!(*cgen)((ast_expression*)(self->func), func, false, &funval))
return false;
@ -1465,6 +1627,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value
}
*out = ir_call_value(callinstr);
self->expression.outr = *out;
MEM_VECTOR_CLEAR(&params, v);
return true;

32
ast.h
View file

@ -36,6 +36,7 @@ typedef struct ast_function_s ast_function;
typedef struct ast_block_s ast_block;
typedef struct ast_binary_s ast_binary;
typedef struct ast_store_s ast_store;
typedef struct ast_binstore_s ast_binstore;
typedef struct ast_entfield_s ast_entfield;
typedef struct ast_ifthen_s ast_ifthen;
typedef struct ast_ternary_s ast_ternary;
@ -53,6 +54,7 @@ enum {
TYPE_ast_block,
TYPE_ast_binary,
TYPE_ast_store,
TYPE_ast_binstore,
TYPE_ast_entfield,
TYPE_ast_ifthen,
TYPE_ast_ternary,
@ -104,6 +106,13 @@ typedef struct
int vtype;
ast_expression *next;
MEM_VECTOR_MAKE(ast_value*, params);
/* The codegen functions should store their output values
* so we can call it multiple times without re-evaluating.
* Store lvalue and rvalue seperately though. So that
* ast_entfield for example can generate both if required.
*/
ir_value *outl;
ir_value *outr;
} ast_expression_common;
MEM_VECTOR_PROTO(ast_expression_common, ast_value*, params);
@ -170,6 +179,29 @@ void ast_binary_delete(ast_binary*);
bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**);
/* Binstore
*
* An assignment including a binary expression with the source as left operand.
* Eg. a += b; is a binstore { INSTR_STORE, INSTR_ADD, a, b }
*/
struct ast_binstore_s
{
ast_expression_common expression;
int opstore;
int opbin;
ast_expression *dest;
ast_expression *source;
};
ast_binstore* ast_binstore_new(lex_ctx ctx,
int storeop,
int op,
ast_expression *left,
ast_expression *right);
void ast_binstore_delete(ast_binstore*);
bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**);
/* Unary
*
* Regular unary expressions: not,neg