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_member,
TYPE_ast_array_index,
TYPE_ast_breakcont,
- TYPE_ast_switch
+ TYPE_ast_switch,
+ TYPE_ast_label,
+ TYPE_ast_goto
};
#define ast_istype(x, t) ( ((ast_node_common*)x)->nodetype == (TYPE_##t) )
#define ast_ctx(node) (((ast_node_common*)(node))->context)
+#define ast_side_effects(node) (((ast_node_common*)(node))->side_effects)
/* Node interface with common components
*/
* prevents its dtor from destroying this node as well.
*/
bool keep;
+ bool side_effects;
} ast_node_common;
#define ast_delete(x) ( ( (ast_node*)(x) ) -> node.destroy )((ast_node*)(x))
ast_value *next;
*/
- bool isconst;
+ bool cvq; /* const/var qualifier */
+ bool hasvalue;
union {
double vfloat;
int vint;
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_common expression;
ast_expression *owner;
unsigned int field;
+ const char *name;
};
-ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int field);
+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_codegen(ast_member*, ast_function*, bool lvalue, ir_value**);
/* It's all just 'expressions', since an ast_block is one too. */
ast_expression *on_true;
ast_expression *on_false;
- /* After a ternary expression we find ourselves in a new IR block
- * and start with a PHI node */
- ir_value *phi_out;
};
ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse);
void ast_ternary_delete(ast_ternary*);
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;
+};
+
+ast_label* ast_label_new(lex_ctx ctx, const char *name);
+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*);
+
/* Function
*
* Contains a list of blocks... at least in theory.
ir_block *breakblock;
ir_block *continueblock;
+#if 0
+ /* In order for early-out logic not to go over
+ * excessive jumps, we remember their target
+ * blocks...
+ */
+ ir_block *iftrue;
+ ir_block *iffalse;
+#endif
+
size_t labelcount;
/* in order for thread safety - for the optional
* channel abesed multithreading... keeping a buffer