if (!self) { \
return NULL; \
} \
- ast_node_init((ast_node*)self, ctx); \
+ ast_node_init((ast_node*)self, ctx, TYPE_##T); \
( (ast_node*)self )->node.destroy = (ast_node_delete*)destroyfn
/* It must not be possible to get here. */
}
/* Initialize main ast node aprts */
- static void ast_node_init(ast_node *self, lex_ctx ctx)
+ static void ast_node_init(ast_node *self, lex_ctx ctx, int nodetype)
{
self->node.context = ctx;
self->node.destroy = &_ast_node_destroy;
self->node.keep = false;
+ self->node.nodetype = nodetype;
}
/* General expression initialization */
self->left = left;
self->right = right;
+ if (op >= INSTR_EQ_F && op <= INSTR_GT)
+ self->expression.vtype = TYPE_FLOAT;
+ else if (op == INSTR_AND || op == INSTR_OR ||
+ op == INSTR_BITAND || op == INSTR_BITOR)
+ self->expression.vtype = TYPE_FLOAT;
+ else if (op == INSTR_MUL_VF || op == INSTR_MUL_FV)
+ self->expression.vtype = TYPE_VECTOR;
+ else if (op == INSTR_MUL_V)
+ self->expression.vtype = TYPE_FLOAT;
+ else
+ self->expression.vtype = left->expression.vtype;
+
return self;
}
}
v = ir_builder_create_global(ir, self->name, self->expression.vtype);
- if (!v)
+ if (!v) {
+ printf("ir_builder_create_global failed\n");
return false;
+ }
if (self->isconst) {
switch (self->expression.vtype)
typedef struct ast_unary_s ast_unary;
typedef struct ast_return_s ast_return;
+ enum {
+ TYPE_ast_node,
+ TYPE_ast_expression,
+ TYPE_ast_value,
+ TYPE_ast_function,
+ TYPE_ast_block,
+ TYPE_ast_binary,
+ TYPE_ast_store,
+ TYPE_ast_entfield,
+ TYPE_ast_ifthen,
+ TYPE_ast_ternary,
+ TYPE_ast_loop,
+ TYPE_ast_call,
+ TYPE_ast_unary,
+ TYPE_ast_return
+ };
+
+ #define ast_istype(x, t) ( ((ast_node_common*)x)->nodetype == (t) )
+
/* Node interface with common components
*/
typedef void ast_node_delete(ast_node*);
lex_ctx context;
/* I don't feel comfortable using keywords like 'delete' as names... */
ast_node_delete *destroy;
+ int nodetype;
/* keep: if a node contains this node, 'keep'
* prevents its dtor from destroying this node as well.
*/
const char *vstring;
int ventity;
ast_function *vfunc;
+ quaternion vquat;
+ matrix vmat;
} constval;
ir_value *ir_v;
typedef char uintptr_size_is_correct[sizeof(intptr_t) == sizeof(int*)?1:-1];
typedef char intptr_size_is_correct [sizeof(uintptr_t)== sizeof(int*)?1:-1];
-/*===================================================================*/
-/*============================ lex.c ================================*/
-/*===================================================================*/
-typedef struct lex_file_t {
- FILE *file; /* file handler */
- char *name; /* name of file */
- char peek [5];
- char lastok[8192];
-
- int last; /* last token */
- int current; /* current token */
- int length; /* bytes left to parse */
- int size; /* never changes (size of file) */
- int line; /* what line are we on? */
-} lex_file;
-
-/*
- * It's important that this table never exceed 32 keywords, the ascii
- * table starts at 33 (and we don't want conflicts)
- */
-enum {
- TOKEN_DO ,
- TOKEN_ELSE ,
- TOKEN_IF ,
- TOKEN_WHILE ,
- TOKEN_BREAK ,
- TOKEN_CONTINUE ,
- TOKEN_RETURN ,
- TOKEN_GOTO ,
- TOKEN_FOR , /* extension */
- TOKEN_TYPEDEF , /* extension */
-
- /* ensure the token types are out of the */
- /* bounds of anyothers that may conflict. */
- TOKEN_FLOAT = 110,
- TOKEN_VECTOR ,
- TOKEN_STRING ,
- TOKEN_ENTITY ,
- TOKEN_VOID
-};
-
-/*
- * Lexer state constants, these are numbers for where exactly in
- * the lexing the lexer is at. Or where it decided to stop if a lexer
- * error occurs. These numbers must be > where the ascii-table ends
- * and > the last type token which is TOKEN_VOID
- */
-enum {
- LEX_COMMENT = 1128,
- LEX_CHRLIT ,
- LEX_STRLIT ,
- LEX_IDENT
-};
-
-int lex_token (lex_file *);
-void lex_reset (lex_file *);
-void lex_close (lex_file *);
-void lex_parse (lex_file *);
-lex_file *lex_include(lex_file *, const char *);
-void lex_init (const char *, lex_file **);
-
-/*===================================================================*/
-/*========================== error.c ================================*/
-/*===================================================================*/
-#define ERROR_LEX (SHRT_MAX+0)
-#define ERROR_PARSE (SHRT_MAX+1)
-#define ERROR_INTERNAL (SHRT_MAX+2)
-#define ERROR_COMPILER (SHRT_MAX+3)
-#define ERROR_PREPRO (SHRT_MAX+4)
-int error(lex_file *, int, const char *, ...);
-
-/*===================================================================*/
-/*========================== parse.c ================================*/
-/*===================================================================*/
-int parse_gen(lex_file *);
-
-/*===================================================================*/
-/*========================== typedef.c ==============================*/
-/*===================================================================*/
-typedef struct typedef_node_t {
- char *name;
-} typedef_node;
-
-void typedef_init();
-void typedef_clear();
-typedef_node *typedef_find(const char *);
-int typedef_add (lex_file *file, const char *, const char *);
-
-
/*===================================================================*/
/*=========================== util.c ================================*/
/*===================================================================*/
while (N##_add(*++elements) != -1 && len--); \
return N##_elements; \
} \
- typedef char VECTOR_FILL(extra_semicolon_,__COUNTER__)
+ typedef char VECTOR_FILL(extra_semicolon_##N,__COUNTER__)
#define VECTOR_PROT(T,N) \
extern T* N##_data ; \
extern long N##_elements ; \
TYPE_FIELD ,
TYPE_FUNCTION ,
TYPE_POINTER ,
- /* TYPE_INTEGER , */
+ TYPE_INTEGER ,
+ TYPE_QUATERNION ,
+ TYPE_MATRIX ,
TYPE_VARIANT ,
TYPE_COUNT
};
+extern const char *type_name[TYPE_COUNT];
+
extern size_t type_sizeof[TYPE_COUNT];
extern uint16_t type_store_instr[TYPE_COUNT];
/* could use type_store_instr + INSTR_STOREP_F - INSTR_STORE_F
INSTR_DONE,
INSTR_MUL_F,
INSTR_MUL_V,
- INSTR_MUL_FV,
INSTR_MUL_VF,
+ INSTR_MUL_FV,
INSTR_DIV_F,
INSTR_ADD_F,
INSTR_ADD_V,
INSTR_BITAND,
INSTR_BITOR,
+/* warning: will be reordered */
+ INSTR_MUL_Q,
+ INSTR_MUL_QF,
+ INSTR_MUL_M,
+ INSTR_MUL_MF,
+ INSTR_EQ_Q,
+ INSTR_EQ_M,
+ INSTR_NE_Q,
+ INSTR_NE_M,
+ INSTR_LOAD_Q,
+ INSTR_LOAD_M,
+ INSTR_STORE_Q,
+ INSTR_STORE_M,
+ INSTR_STOREP_Q,
+ INSTR_STOREP_M,
+ INSTR_INV_Q,
+ INSTR_INV_M,
/*
* Virtual instructions used by the assembler
* keep at the end but before virtual instructions
VECTOR_PROT(int, code_globals );
VECTOR_PROT(char, code_chars );
+ typedef float qcfloat;
+ typedef int32_t qcint;
+
/*
* code_write -- writes out the compiled file
* code_init -- prepares the code file
void code_init ();
uint32_t code_genstring (const char *string);
uint32_t code_cachedstring(const char *string);
+ qcint code_alloc_field (size_t qcsize);
/*===================================================================*/
/*========================= assembler.c =============================*/
{ "DONE" , 1, 4 },
{ "MUL_F" , 3, 5 },
{ "MUL_V" , 3, 5 },
- { "MUL_FV" , 3, 6 },
{ "MUL_VF" , 3, 6 },
+ { "MUL_FV" , 3, 6 },
{ "DIV" , 0, 3 },
{ "ADD_F" , 3, 5 },
{ "ADD_V" , 3, 5 },
{ "OR" , 0, 2 },
{ "BITAND" , 0, 6 },
{ "BITOR" , 0, 5 },
+
+ { "MUL_Q" , 3, 5 },
+ { "MUL_QF" , 3, 6 },
+ { "MUL_M" , 3, 5 },
+ { "MUL_MF" , 3, 6 },
+ { "EQ_Q" , 0, 4 },
+ { "EQ_M" , 0, 4 },
+ { "NE_Q" , 0, 4 },
+ { "NE_M" , 0, 4 },
+ { "FIELD_Q" , 0, 7 },
+ { "FIELD_M" , 0, 7 },
+ { "STORE_Q" , 0, 7 },
+ { "STORE_M" , 0, 7 },
+ { "STOREP_Q" , 0, 8 },
+ { "STOREP_M" , 0, 8 },
+ { "INV_Q" , 0, 5 },
+ { "INV_M" , 0, 5 },
+
{ "END" , 0, 3 } /* virtual assembler instruction */
};
(owner)->mem##_alloc = 0; \
}
+#define MEM_VECTOR_MOVE(from, mem, to, tm) \
+{ \
+ (to)->tm = (from)->mem; \
+ (to)->tm##_count = (from)->mem##_count; \
+ (to)->tm##_alloc = (from)->mem##_alloc; \
+ (from)->mem = NULL; \
+ (from)->mem##_count = 0; \
+ (from)->mem##_alloc = 0; \
+}
+
#define MEM_VEC_FUNCTIONS(Tself, Twhat, mem) \
MEM_VEC_FUN_REMOVE(Tself, Twhat, mem) \
MEM_VEC_FUN_ADD(Tself, Twhat, mem)
float x, y, z;
} vector;
+typedef float matrix[4][4]; /* OpenGL layout */
+typedef float quaternion[4]; /* order: x, y, z, w */
+#define MATRIX(axis, elem) ((4*(axis)) + (elem))
+#define QUAT_X 0
+#define QUAT_Y 1
+#define QUAT_Z 2
+#define QUAT_W 3
+
/*
* A shallow copy of a lex_file to remember where which ast node
* came from.
* Since we may want to support that as well, let's redefine
* float and int here.
*/
- typedef float qcfloat;
- typedef int32_t qcint;
-
typedef union {
qcint _int;
qcint string;
* Type sizes used at multiple points in the IR codegen
*/
+const char *type_name[TYPE_COUNT] = {
+ "void",
+ "string",
+ "float",
+ "vector",
+ "entity",
+ "field",
+ "function",
+ "pointer",
+#if 0
+ "integer",
+#endif
+ "quaternion",
+ "matrix",
+ "variant"
+};
+
size_t type_sizeof[TYPE_COUNT] = {
1, /* TYPE_VOID */
1, /* TYPE_STRING */
#if 0
1, /* TYPE_INTEGER */
#endif
- 3, /* TYPE_VARIANT */
+ 4, /* TYPE_QUATERNION */
+ 16, /* TYPE_MATRIX */
+ 16, /* TYPE_VARIANT */
};
uint16_t type_store_instr[TYPE_COUNT] = {
INSTR_STORE_FNC,
INSTR_STORE_ENT, /* should use I */
#if 0
- INSTR_STORE_ENT, /* integer type */
+ INSTR_STORE_I, /* integer type */
#endif
- INSTR_STORE_V, /* variant, should never be accessed */
+ INSTR_STORE_Q,
+ INSTR_STORE_M,
+
+ INSTR_STORE_M, /* variant, should never be accessed */
};
uint16_t type_storep_instr[TYPE_COUNT] = {
#if 0
INSTR_STOREP_ENT, /* integer type */
#endif
- INSTR_STOREP_V, /* variant, should never be accessed */
+ INSTR_STOREP_Q,
+ INSTR_STOREP_M,
+
+ INSTR_STOREP_M, /* variant, should never be accessed */
};
MEM_VEC_FUNCTIONS(ir_value_vector, ir_value*, v)
MEM_VECTOR_INIT(self, functions);
MEM_VECTOR_INIT(self, globals);
+ MEM_VECTOR_INIT(self, fields);
self->name = NULL;
if (!ir_builder_set_name(self, modulename)) {
mem_d(self);
}
MEM_VEC_FUNCTIONS(ir_builder, ir_value*, globals)
+ MEM_VEC_FUNCTIONS(ir_builder, ir_value*, fields)
MEM_VEC_FUNCTIONS(ir_builder, ir_function*, functions)
void ir_builder_delete(ir_builder* self)
for (i = 0; i != self->globals_count; ++i) {
ir_value_delete(self->globals[i]);
}
- MEM_VECTOR_CLEAR(self, globals);
+ MEM_VECTOR_CLEAR(self, fields);
+ for (i = 0; i != self->fields_count; ++i) {
+ ir_value_delete(self->fields[i]);
+ }
+ MEM_VECTOR_CLEAR(self, fields);
mem_d(self);
}
ir_value* ir_builder_create_global(ir_builder *self, const char *name, int vtype)
{
- ir_value *ve = ir_builder_get_global(self, name);
- if (ve) {
- return NULL;
+ ir_value *ve;
+
+ if (name && name[0] != '#')
+ {
+ ve = ir_builder_get_global(self, name);
+ if (ve) {
+ return NULL;
+ }
}
ve = ir_value_var(name, store_global, vtype);
return ve;
}
+ ir_value* ir_builder_get_field(ir_builder *self, const char *name)
+ {
+ size_t i;
+ for (i = 0; i < self->fields_count; ++i) {
+ if (!strcmp(self->fields[i]->name, name))
+ return self->fields[i];
+ }
+ return NULL;
+ }
+
+
+ ir_value* ir_builder_create_field(ir_builder *self, const char *name, int vtype)
+ {
+ ir_value *ve = ir_builder_get_field(self, name);
+ if (ve) {
+ return NULL;
+ }
+
+ ve = ir_value_var(name, store_global, TYPE_FIELD);
+ ve->fieldtype = vtype;
+ if (!ir_builder_fields_add(self, ve)) {
+ ir_value_delete(ve);
+ return NULL;
+ }
+ return ve;
+ }
+
/***********************************************************************
*IR Function
*/
return true;
}
+bool ir_value_set_quaternion(ir_value *self, quaternion v)
+{
+ if (self->vtype != TYPE_QUATERNION)
+ return false;
+ memcpy(&self->constval.vquat, v, sizeof(self->constval.vquat));
+ self->isconst = true;
+ return true;
+}
+
+bool ir_value_set_matrix(ir_value *self, matrix v)
+{
+ if (self->vtype != TYPE_MATRIX)
+ return false;
+ memcpy(&self->constval.vmat, v, sizeof(self->constval.vmat));
+ self->isconst = true;
+ return true;
+}
+
bool ir_value_set_string(ir_value *self, const char *str)
{
if (self->vtype != TYPE_STRING)
vtype = what->vtype;
op = type_storep_instr[vtype];
-
return ir_block_create_store_op(self, op, target, what);
}
ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_value *ent, ir_value *field)
{
+ ir_value *v;
+
/* Support for various pointer types todo if so desired */
if (ent->vtype != TYPE_ENTITY)
return NULL;
if (field->vtype != TYPE_FIELD)
return NULL;
- return ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
+ v = ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
+ v->fieldtype = field->fieldtype;
+ return v;
}
ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_value *ent, ir_value *field, int outype)
case TYPE_POINTER: op = INSTR_LOAD_I; break;
case TYPE_INTEGER: op = INSTR_LOAD_I; break;
#endif
+ case TYPE_QUATERNION: op = INSTR_LOAD_Q; break;
+ case TYPE_MATRIX: op = INSTR_LOAD_M; break;
default:
return NULL;
}
case TYPE_VECTOR:
op = INSTR_MUL_V;
break;
+ case TYPE_QUATERNION:
+ op = INSTR_MUL_Q;
+ break;
+ case TYPE_MATRIX:
+ op = INSTR_MUL_M;
+ break;
}
} else {
if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
op = INSTR_MUL_VF;
else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) )
op = INSTR_MUL_FV;
+ else if ( (l == TYPE_QUATERNION && r == TYPE_FLOAT) )
+ op = INSTR_MUL_QF;
+ else if ( (l == TYPE_MATRIX && r == TYPE_FLOAT) )
+ op = INSTR_MUL_MF;
#if 0
else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) )
op = INSTR_MUL_VI;
}
else
{
- prog_section_field fld;
-
- fld.name = global->code.name;
- fld.offset = code_fields_elements;
- fld.type = global->fieldtype;
-
- if (fld.type == TYPE_VOID) {
- printf("Field is missing a type: %s\n", global->name);
- return false;
- }
-
- if (code_fields_add(fld) < 0)
- return false;
-
- global->code.globaladdr = code_globals_add(fld.offset);
+ global->code.globaladdr = code_globals_add(0);
}
if (global->code.globaladdr < 0)
return false;
return global->code.globaladdr >= 0;
}
case TYPE_VECTOR:
+ case TYPE_QUATERNION:
+ case TYPE_MATRIX:
{
size_t d;
if (code_defs_add(def) < 0)
}
}
+ static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
+ {
+ prog_section_def def;
+ prog_section_field fld;
+
+ def.type = field->vtype;
+ def.offset = code_globals_elements;
+ def.name = field->code.name = code_genstring(field->name);
+
+ if (code_defs_add(def) < 0)
+ return false;
+
+ fld.name = def.name;
+ fld.offset = code_fields_elements;
+ fld.type = field->fieldtype;
+
+ if (fld.type == TYPE_VOID) {
+ printf("field is missing a type: %s - don't know its size\n", field->name);
+ return false;
+ }
+
+ if (code_fields_add(fld) < 0)
+ return false;
+
+ if (!code_globals_add(code_alloc_field(type_sizeof[field->fieldtype])))
+ return false;
+
+ field->code.globaladdr = code_globals_add(fld.offset);
+ return field->code.globaladdr >= 0;
+ }
+
bool ir_builder_generate(ir_builder *self, const char *filename)
{
size_t i;
code_init();
+ for (i = 0; i < self->fields_count; ++i)
+ {
+ if (!ir_builder_gen_field(self, self->fields[i])) {
+ return false;
+ }
+ }
+
for (i = 0; i < self->globals_count; ++i)
{
if (!ir_builder_gen_global(self, self->globals[i])) {
{
if (v->isconst) {
switch (v->vtype) {
+ default:
case TYPE_VOID:
oprintf("(void)");
break;
char *vstring;
struct ir_value_s *vpointer;
struct ir_function_s *vfunc;
+ quaternion vquat;
+ matrix vmat;
} constval;
struct {
bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v);
/*bool ir_value_set_pointer_v(ir_value*, ir_value* p); */
/*bool ir_value_set_pointer_i(ir_value*, int i); */
+bool GMQCC_WARN ir_value_set_quaternion(ir_value*, quaternion v);
+bool GMQCC_WARN ir_value_set_matrix(ir_value*, matrix v);
MEM_VECTOR_PROTO(ir_value, ir_life_entry_t, life);
/* merge an instruction into the life-range */
char *name;
MEM_VECTOR_MAKE(ir_function*, functions);
MEM_VECTOR_MAKE(ir_value*, globals);
+ MEM_VECTOR_MAKE(ir_value*, fields);
} ir_builder;
ir_builder* ir_builder_new(const char *modulename);
MEM_VECTOR_PROTO(ir_builder, ir_function*, functions);
MEM_VECTOR_PROTO(ir_builder, ir_value*, globals);
+ MEM_VECTOR_PROTO(ir_builder, ir_value*, fields);
ir_function* ir_builder_get_function(ir_builder*, const char *fun);
ir_function* ir_builder_create_function(ir_builder*, const char *name, int outtype);
ir_value* ir_builder_get_global(ir_builder*, const char *fun);
ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype);
+ ir_value* ir_builder_get_field(ir_builder*, const char *fun);
+ ir_value* ir_builder_create_field(ir_builder*, const char *name, int vtype);
bool ir_builder_generate(ir_builder *self, const char *filename);