/*
- * Copyright (C) 2012
+ * Copyright (C) 2012, 2013
* Wolfgang Bumiller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
typedef struct ast_array_index_s ast_array_index;
typedef struct ast_breakcont_s ast_breakcont;
typedef struct ast_switch_s ast_switch;
+typedef struct ast_label_s ast_label;
+typedef struct ast_goto_s ast_goto;
enum {
- TYPE_ast_node,
- TYPE_ast_expression,
- TYPE_ast_value,
- TYPE_ast_function,
- TYPE_ast_block,
- TYPE_ast_binary,
- TYPE_ast_store,
- TYPE_ast_binstore,
- TYPE_ast_entfield,
- TYPE_ast_ifthen,
- TYPE_ast_ternary,
- TYPE_ast_loop,
- TYPE_ast_call,
- TYPE_ast_unary,
- TYPE_ast_return,
- TYPE_ast_member,
- TYPE_ast_array_index,
- TYPE_ast_breakcont,
- TYPE_ast_switch
+ TYPE_ast_node, /* 0 */
+ TYPE_ast_expression, /* 1 */
+ TYPE_ast_value, /* 2 */
+ TYPE_ast_function, /* 3 */
+ TYPE_ast_block, /* 4 */
+ TYPE_ast_binary, /* 5 */
+ TYPE_ast_store, /* 6 */
+ TYPE_ast_binstore, /* 7 */
+ TYPE_ast_entfield, /* 8 */
+ TYPE_ast_ifthen, /* 9 */
+ TYPE_ast_ternary, /* 10 */
+ TYPE_ast_loop, /* 11 */
+ TYPE_ast_call, /* 12 */
+ TYPE_ast_unary, /* 13 */
+ TYPE_ast_return, /* 14 */
+ TYPE_ast_member, /* 15 */
+ TYPE_ast_array_index, /* 16 */
+ TYPE_ast_breakcont, /* 17 */
+ TYPE_ast_switch, /* 18 */
+ TYPE_ast_label, /* 19 */
+ TYPE_ast_goto /* 20 */
};
#define ast_istype(x, t) ( ((ast_node_common*)x)->nodetype == (TYPE_##t) )
bool side_effects;
} ast_node_common;
-#define ast_delete(x) ( ( (ast_node*)(x) ) -> node.destroy )((ast_node*)(x))
+#define ast_delete(x) (*( ((ast_node*)(x))->node.destroy ))((ast_node*)(x))
#define ast_unref(x) do \
{ \
if (! (((ast_node*)(x))->node.keep) ) { \
/* arrays get a member-count */
size_t count;
ast_value* *params;
- bool variadic;
+ uint32_t flags;
/* 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
ir_value *outl;
ir_value *outr;
} ast_expression_common;
+#define AST_FLAG_VARIADIC (1<<0)
+#define AST_FLAG_NORETURN (1<<1)
+#define AST_FLAG_INLINE (1<<2)
+#define AST_FLAG_INITIALIZED (1<<3)
+#define AST_FLAG_DEPRECATED (1<<4)
+#define AST_FLAG_TYPE_MASK (AST_FLAG_VARIADIC | AST_FLAG_NORETURN)
/* Value
*
ast_expression_common expression;
const char *name;
+ const char *desc;
/*
int vtype;
ast_value *next;
*/
- bool isconst;
+ int cvq; /* const/var qualifier */
+ bool isfield; /* this declares a field */
+ bool hasvalue;
union {
double vfloat;
int vint;
const char *vstring;
int ventity;
ast_function *vfunc;
+ ast_value *vfield;
} constval;
/* usecount for the parser */
int opbin;
ast_expression *dest;
ast_expression *source;
+ /* for &~= which uses the destination in a binary in source we can use this */
+ bool keep_dest;
};
ast_binstore* ast_binstore_new(lex_ctx ctx,
int storeop,
ast_expression *owner;
unsigned int field;
const char *name;
+ bool rvalue;
};
ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int field, const char *name);
void ast_member_delete(ast_member*);
+bool ast_member_set_name(ast_member*, const char *name);
bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**);
ast_expression *postcond;
ast_expression *increment;
ast_expression *body;
+ /* For now we allow a seperate flag on whether or not the condition
+ * is supposed to be true or false.
+ * That way, the parser can generate a 'while not(!x)' for `while(x)`
+ * if desired, which is useful for the new -f{true,false}-empty-strings
+ * flag.
+ */
+ bool pre_not;
+ bool post_not;
};
ast_loop* ast_loop_new(lex_ctx ctx,
ast_expression *initexpr,
- ast_expression *precond,
- ast_expression *postcond,
+ ast_expression *precond, bool pre_not,
+ ast_expression *postcond, bool post_not,
ast_expression *increment,
ast_expression *body);
void ast_loop_delete(ast_loop*);
struct ast_breakcont_s
{
ast_expression_common expression;
- bool is_continue;
+ bool is_continue;
+ unsigned int levels;
};
-ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont);
+ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont, unsigned int levels);
void ast_breakcont_delete(ast_breakcont*);
bool ast_breakcont_codegen(ast_breakcont*, ast_function*, bool lvalue, ir_value**);
bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**);
+/* Label nodes
+ *
+ * Introduce a label which can be used together with 'goto'
+ */
+struct ast_label_s
+{
+ ast_expression_common expression;
+ const char *name;
+ ir_block *irblock;
+ ast_goto **gotos;
+ /* means it has not yet been defined */
+ bool undefined;
+};
+
+ast_label* ast_label_new(lex_ctx ctx, const char *name, bool undefined);
+void ast_label_delete(ast_label*);
+void ast_label_register_goto(ast_label*, ast_goto*);
+
+bool ast_label_codegen(ast_label*, ast_function*, bool lvalue, ir_value**);
+
+/* GOTO nodes
+ *
+ * Go to a label, the label node is filled in at a later point!
+ */
+struct ast_goto_s
+{
+ ast_expression_common expression;
+ const char *name;
+ ast_label *target;
+ ir_block *irblock_from;
+};
+
+ast_goto* ast_goto_new(lex_ctx ctx, const char *name);
+void ast_goto_delete(ast_goto*);
+void ast_goto_set_label(ast_goto*, ast_label*);
+
+bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**);
+
/* CALL node
*
* Contains an ast_expression as target, rather than an ast_function/value.
bool ast_block_codegen(ast_block*, ast_function*, bool lvalue, ir_value**);
void ast_block_collect(ast_block*, ast_expression*);
-void ast_block_add_expr(ast_block*, ast_expression*);
+bool GMQCC_WARN ast_block_add_expr(ast_block*, ast_expression*);
/* Function
*
ir_function *ir_func;
ir_block *curblock;
- ir_block *breakblock;
- ir_block *continueblock;
+ ir_block **breakblocks;
+ ir_block **continueblocks;
#if 0
/* In order for early-out logic not to go over
const char* ast_function_label(ast_function*, const char *prefix);
bool ast_function_codegen(ast_function *self, ir_builder *builder);
+bool ast_generate_accessors(ast_value *asvalue, ir_builder *ir);
/* Expression union
*/