Merging in new-syntax

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-11-14 21:39:16 +01:00
commit 84088cb5f0
15 changed files with 1847 additions and 593 deletions

View file

@ -1,5 +1,5 @@
CC ?= clang
CFLAGS += -Wall -I. -fomit-frame-pointer -fno-stack-protector -O3
CFLAGS += -Wall -I. -fomit-frame-pointer -fno-stack-protector
#turn on tons of warnings if clang is present
ifeq ($(CC), clang)
CFLAGS += \
@ -29,7 +29,7 @@ OBJ = \
OBJ_A = test/ast-test.o
OBJ_I = test/ir-test.o
OBJ_C = main.o lexer.o parser.o
OBJ_X = exec-standalone.o util.o
OBJ_X = exec-standalone.o util.o con.o
#default is compiler only
default: gmqcc

440
ast.c
View file

@ -276,6 +276,17 @@ static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsi
buf[pos++] = ')';
return pos;
case TYPE_ARRAY:
pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos);
if (pos + 1 >= bufsize)
goto full;
buf[pos++] = '[';
pos += snprintf(buf + pos, bufsize - pos - 1, "%i", (int)e->expression.count);
if (pos + 1 >= bufsize)
goto full;
buf[pos++] = ']';
return pos;
default:
typestr = type_name[e->expression.vtype];
typelen = strlen(typestr);
@ -312,7 +323,12 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
self->uses = 0;
memset(&self->constval, 0, sizeof(self->constval));
self->ir_v = NULL;
self->ir_v = NULL;
self->ir_values = NULL;
self->ir_value_count = 0;
self->setter = NULL;
self->getter = NULL;
return self;
}
@ -338,6 +354,8 @@ void ast_value_delete(ast_value* self)
break;
}
}
if (self->ir_values)
mem_d(self->ir_values);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
@ -465,16 +483,17 @@ void ast_return_delete(ast_return *self)
ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field)
{
const ast_expression *outtype;
ast_instantiate(ast_entfield, ctx, ast_entfield_delete);
if (field->expression.vtype != TYPE_FIELD) {
mem_d(self);
asterror(ctx, "ast_entfield_new with expression not of type field");
return NULL;
}
return ast_entfield_new_force(ctx, entity, field, field->expression.next);
}
ast_entfield* ast_entfield_new_force(lex_ctx ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype)
{
ast_instantiate(ast_entfield, ctx, ast_entfield_delete);
outtype = field->expression.next;
if (!outtype) {
mem_d(self);
/* Error: field has no type... */
@ -548,6 +567,48 @@ void ast_member_delete(ast_member *self)
mem_d(self);
}
ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_expression *index)
{
ast_expression *outtype;
ast_instantiate(ast_array_index, ctx, ast_array_index_delete);
outtype = array->expression.next;
if (!outtype) {
mem_d(self);
/* Error: field has no type... */
return NULL;
}
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_array_index_codegen);
self->array = array;
self->index = index;
if (!ast_type_adopt(self, outtype)) {
ast_array_index_delete(self);
return NULL;
}
if (array->expression.vtype == TYPE_FIELD && outtype->expression.vtype == TYPE_ARRAY) {
if (self->expression.vtype != TYPE_ARRAY) {
asterror(ast_ctx(self), "array_index node on type");
ast_array_index_delete(self);
return NULL;
}
self->array = outtype;
self->expression.vtype = TYPE_FIELD;
}
return self;
}
void ast_array_index_delete(ast_array_index *self)
{
ast_unref(self->array);
ast_unref(self->index);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
ast_ifthen* ast_ifthen_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse)
{
ast_instantiate(ast_ifthen, ctx, ast_ifthen_delete);
@ -870,16 +931,19 @@ bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_valu
* on all the globals.
*/
if (!self->ir_v) {
asterror(ast_ctx(self), "ast_value used before generated (%s)", self->name);
char typename[1024];
ast_type_to_string((ast_expression*)self, typename, sizeof(typename));
asterror(ast_ctx(self), "ast_value used before generated %s %s", typename, self->name);
return false;
}
*out = self->ir_v;
return true;
}
bool ast_global_codegen(ast_value *self, ir_builder *ir)
bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
{
ir_value *v = NULL;
if (self->isconst && self->expression.vtype == TYPE_FUNCTION)
{
ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->expression.vtype);
@ -894,25 +958,131 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir)
return true;
}
if (self->expression.vtype == TYPE_FIELD) {
v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype);
if (!v)
return false;
v->context = ast_ctx(self);
if (isfield && self->expression.vtype == TYPE_FIELD) {
ast_expression *fieldtype = self->expression.next;
if (self->isconst) {
asterror(ast_ctx(self), "TODO: constant field pointers with value");
goto error;
}
self->ir_v = v;
if (fieldtype->expression.vtype == TYPE_ARRAY) {
size_t ai;
char *name;
size_t namelen;
ast_expression_common *elemtype;
int vtype;
ast_value *array = (ast_value*)fieldtype;
if (!ast_istype(fieldtype, ast_value)) {
asterror(ast_ctx(self), "internal error: ast_value required");
return false;
}
/* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
if (!array->expression.count || array->expression.count > opts_max_array_size)
asterror(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
elemtype = &array->expression.next->expression;
vtype = elemtype->vtype;
v = ir_builder_create_field(ir, self->name, vtype);
if (!v) {
asterror(ast_ctx(self), "ir_builder_create_global failed");
return false;
}
if (vtype == TYPE_FIELD)
v->fieldtype = elemtype->next->expression.vtype;
v->context = ast_ctx(self);
array->ir_v = self->ir_v = v;
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
strcpy(name, self->name);
array->ir_values = (ir_value**)mem_a(sizeof(array->ir_values[0]) * array->expression.count);
array->ir_values[0] = v;
for (ai = 1; ai < array->expression.count; ++ai) {
snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
array->ir_values[ai] = ir_builder_create_field(ir, name, vtype);
if (!array->ir_values[ai]) {
mem_d(name);
asterror(ast_ctx(self), "ir_builder_create_global failed");
return false;
}
if (vtype == TYPE_FIELD)
array->ir_values[ai]->fieldtype = elemtype->next->expression.vtype;
array->ir_values[ai]->context = ast_ctx(self);
}
mem_d(name);
}
else
{
v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype);
if (!v)
return false;
v->context = ast_ctx(self);
self->ir_v = v;
}
return true;
}
v = ir_builder_create_global(ir, self->name, self->expression.vtype);
if (!v) {
asterror(ast_ctx(self), "ir_builder_create_global failed");
return false;
if (self->expression.vtype == TYPE_ARRAY) {
size_t ai;
char *name;
size_t namelen;
ast_expression_common *elemtype = &self->expression.next->expression;
int vtype = elemtype->vtype;
/* same as with field arrays */
if (!self->expression.count || self->expression.count > opts_max_array_size)
asterror(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
v = ir_builder_create_global(ir, self->name, vtype);
if (!v) {
asterror(ast_ctx(self), "ir_builder_create_global failed");
return false;
}
if (vtype == TYPE_FIELD)
v->fieldtype = elemtype->next->expression.vtype;
v->context = ast_ctx(self);
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
strcpy(name, self->name);
self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->expression.count);
self->ir_values[0] = v;
for (ai = 1; ai < self->expression.count; ++ai) {
snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
self->ir_values[ai] = ir_builder_create_global(ir, name, vtype);
if (!self->ir_values[ai]) {
mem_d(name);
asterror(ast_ctx(self), "ir_builder_create_global failed");
return false;
}
if (vtype == TYPE_FIELD)
self->ir_values[ai]->fieldtype = elemtype->next->expression.vtype;
self->ir_values[ai]->context = ast_ctx(self);
}
mem_d(name);
}
else
{
/* Arrays don't do this since there's no "array" value which spans across the
* whole thing.
*/
v = ir_builder_create_global(ir, self->name, self->expression.vtype);
if (!v) {
asterror(ast_ctx(self), "ir_builder_create_global failed");
return false;
}
if (self->expression.vtype == TYPE_FIELD)
v->fieldtype = self->expression.next->expression.vtype;
v->context = ast_ctx(self);
}
v->context = ast_ctx(self);
if (self->isconst) {
switch (self->expression.vtype)
@ -929,6 +1099,9 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir)
if (!ir_value_set_string(v, self->constval.vstring))
goto error;
break;
case TYPE_ARRAY:
asterror(ast_ctx(self), "TODO: global constant array");
break;
case TYPE_FUNCTION:
asterror(ast_ctx(self), "global of type function not properly generated");
goto error;
@ -961,10 +1134,65 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
return false;
}
v = ir_function_create_local(func, self->name, self->expression.vtype, param);
if (!v)
return false;
v->context = ast_ctx(self);
if (self->expression.vtype == TYPE_ARRAY) {
size_t ai;
char *name;
size_t namelen;
ast_expression_common *elemtype = &self->expression.next->expression;
int vtype = elemtype->vtype;
if (param) {
asterror(ast_ctx(self), "array-parameters are not supported");
return false;
}
/* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
if (!self->expression.count || self->expression.count > opts_max_array_size) {
asterror(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
}
self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->expression.count);
if (!self->ir_values) {
asterror(ast_ctx(self), "failed to allocate array values");
return false;
}
v = ir_function_create_local(func, self->name, vtype, param);
if (!v) {
asterror(ast_ctx(self), "ir_function_create_local failed");
return false;
}
if (vtype == TYPE_FIELD)
v->fieldtype = elemtype->next->expression.vtype;
v->context = ast_ctx(self);
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
strcpy(name, self->name);
self->ir_values[0] = v;
for (ai = 1; ai < self->expression.count; ++ai) {
snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
self->ir_values[ai] = ir_function_create_local(func, name, vtype, param);
if (!self->ir_values[ai]) {
asterror(ast_ctx(self), "ir_builder_create_global failed");
return false;
}
if (vtype == TYPE_FIELD)
self->ir_values[ai]->fieldtype = elemtype->next->expression.vtype;
self->ir_values[ai]->context = ast_ctx(self);
}
}
else
{
v = ir_function_create_local(func, self->name, self->expression.vtype, param);
if (!v)
return false;
if (self->expression.vtype == TYPE_FIELD)
v->fieldtype = self->expression.next->expression.vtype;
v->context = ast_ctx(self);
}
/* A constant local... hmmm...
* I suppose the IR will have to deal with this
@ -992,6 +1220,19 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
/* link us to the ir_value */
self->ir_v = v;
if (self->setter) {
if (!ast_global_codegen(self->setter, func->owner, false) ||
!ast_function_codegen(self->setter->constval.vfunc, func->owner) ||
!ir_function_finalize(self->setter->constval.vfunc->ir_func))
return false;
}
if (self->getter) {
if (!ast_global_codegen(self->getter, func->owner, false) ||
!ast_function_codegen(self->getter->constval.vfunc, func->owner) ||
!ir_function_finalize(self->getter->constval.vfunc->ir_func))
return false;
}
return true;
error: /* clean up */
@ -1127,6 +1368,10 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu
ast_expression_codegen *cgen;
ir_value *left, *right;
ast_value *arr;
ast_value *idx;
ast_array_index *ai = NULL;
if (lvalue && self->expression.outl) {
*out = self->expression.outl;
return true;
@ -1137,20 +1382,72 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu
return true;
}
cgen = self->dest->expression.codegen;
/* lvalue! */
if (!(*cgen)((ast_expression*)(self->dest), func, true, &left))
return false;
self->expression.outl = left;
if (ast_istype(self->dest, ast_array_index))
{
cgen = self->source->expression.codegen;
/* rvalue! */
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
ai = (ast_array_index*)self->dest;
idx = (ast_value*)ai->index;
if (!ir_block_create_store_op(func->curblock, self->op, left, right))
return false;
self->expression.outr = right;
if (ast_istype(ai->index, ast_value) && idx->isconst)
ai = NULL;
}
if (ai) {
/* we need to call the setter */
ir_value *iridx, *funval;
ir_instr *call;
if (lvalue) {
asterror(ast_ctx(self), "array-subscript assignment cannot produce lvalues");
return false;
}
arr = (ast_value*)ai->array;
if (!ast_istype(ai->array, ast_value) || !arr->setter) {
asterror(ast_ctx(self), "value has no setter (%s)", arr->name);
return false;
}
cgen = idx->expression.codegen;
if (!(*cgen)((ast_expression*)(idx), func, false, &iridx))
return false;
cgen = arr->setter->expression.codegen;
if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval))
return false;
cgen = self->source->expression.codegen;
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
if (!call)
return false;
if (!ir_call_param(call, iridx))
return false;
if (!ir_call_param(call, right))
return false;
self->expression.outr = right;
}
else
{
/* regular code */
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! */
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
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
@ -1398,6 +1695,77 @@ bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_va
return (*out != NULL);
}
bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_value *arr;
ast_value *idx;
if (!lvalue && self->expression.outr) {
*out = self->expression.outr;
}
if (lvalue && self->expression.outl) {
*out = self->expression.outl;
}
if (!ast_istype(self->array, ast_value)) {
asterror(ast_ctx(self), "array indexing this way is not supported");
/* note this would actually be pointer indexing because the left side is
* not an actual array but (hopefully) an indexable expression.
* Once we get integer arithmetic, and GADDRESS/GSTORE/GLOAD instruction
* support this path will be filled.
*/
return false;
}
arr = (ast_value*)self->array;
idx = (ast_value*)self->index;
if (!ast_istype(self->index, ast_value) || !idx->isconst) {
/* Time to use accessor functions */
ast_expression_codegen *cgen;
ir_value *iridx, *funval;
ir_instr *call;
if (lvalue) {
asterror(ast_ctx(self), "(.2) array indexing here needs a compile-time constant");
return false;
}
if (!arr->getter) {
asterror(ast_ctx(self), "value has no getter, don't know how to index it");
return false;
}
cgen = self->index->expression.codegen;
if (!(*cgen)((ast_expression*)(self->index), func, true, &iridx))
return false;
cgen = arr->getter->expression.codegen;
if (!(*cgen)((ast_expression*)(arr->getter), func, true, &funval))
return false;
call = ir_block_create_call(func->curblock, ast_function_label(func, "fetch"), funval);
if (!call)
return false;
if (!ir_call_param(call, iridx))
return false;
*out = ir_call_value(call);
self->expression.outr = *out;
return true;
}
if (idx->expression.vtype == TYPE_FLOAT)
*out = arr->ir_values[(int)idx->constval.vfloat];
else if (idx->expression.vtype == TYPE_INTEGER)
*out = arr->ir_values[idx->constval.vint];
else {
asterror(ast_ctx(self), "array indexing here needs an integer constant");
return false;
}
return true;
}
bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;

64
ast.h
View file

@ -31,20 +31,21 @@
typedef union ast_node_u ast_node;
typedef union ast_expression_u ast_expression;
typedef struct ast_value_s ast_value;
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;
typedef struct ast_loop_s ast_loop;
typedef struct ast_call_s ast_call;
typedef struct ast_unary_s ast_unary;
typedef struct ast_return_s ast_return;
typedef struct ast_member_s ast_member;
typedef struct ast_value_s ast_value;
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;
typedef struct ast_loop_s ast_loop;
typedef struct ast_call_s ast_call;
typedef struct ast_unary_s ast_unary;
typedef struct ast_return_s ast_return;
typedef struct ast_member_s ast_member;
typedef struct ast_array_index_s ast_array_index;
enum {
TYPE_ast_node,
@ -62,7 +63,8 @@ enum {
TYPE_ast_call,
TYPE_ast_unary,
TYPE_ast_return,
TYPE_ast_member
TYPE_ast_member,
TYPE_ast_array_index
};
#define ast_istype(x, t) ( ((ast_node_common*)x)->nodetype == (TYPE_##t) )
@ -116,6 +118,8 @@ typedef struct
ast_expression_codegen *codegen;
int vtype;
ast_expression *next;
/* arrays get a member-count */
size_t count;
MEM_VECTOR_MAKE(ast_value*, params);
bool variadic;
/* The codegen functions should store their output values
@ -160,6 +164,12 @@ struct ast_value_s
size_t uses;
ir_value *ir_v;
ir_value **ir_values;
size_t ir_value_count;
/* ONLY for arrays in progs version up to 6 */
ast_value *setter;
ast_value *getter;
};
ast_value* ast_value_new(lex_ctx ctx, const char *name, int qctype);
@ -171,7 +181,7 @@ bool ast_value_set_name(ast_value*, const char *name);
bool ast_value_codegen(ast_value*, ast_function*, bool lvalue, ir_value**);
bool ast_local_codegen(ast_value *self, ir_function *func, bool isparam);
bool ast_global_codegen(ast_value *self, ir_builder *ir);
bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield);
bool GMQCC_WARN ast_value_params_add(ast_value*, ast_value*);
@ -281,6 +291,7 @@ struct ast_entfield_s
ast_expression *field;
};
ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field);
ast_entfield* ast_entfield_new_force(lex_ctx ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype);
void ast_entfield_delete(ast_entfield*);
bool ast_entfield_codegen(ast_entfield*, ast_function*, bool lvalue, ir_value**);
@ -301,6 +312,27 @@ void ast_member_delete(ast_member*);
bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**);
/* Array index access:
*
* QC forces us to take special action on arrays:
* an ast_store on an ast_array_index must not codegen the index,
* but call its setter - unless we have an instruction set which supports
* what we need.
* Any other array index access will be codegened to a call to the getter.
* In any case, accessing an element via a compiletime-constant index will
* result in quick access to that variable.
*/
struct ast_array_index_s
{
ast_expression_common expression;
ast_expression *array;
ast_expression *index;
};
ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_expression *index);
void ast_array_index_delete(ast_array_index*);
bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_value**);
/* Store
*
* Stores left<-right and returns left.

23
exec.c
View file

@ -50,6 +50,8 @@ MEM_VEC_FUN_RESIZE(qc_program, size_t, profile)
MEM_VEC_FUNCTIONS(qc_program, prog_builtin, builtins)
MEM_VEC_FUNCTIONS(qc_program, const char*, function_stack)
static void loaderror(const char *fmt, ...)
{
int err = errno;
@ -375,7 +377,7 @@ static void trace_print_global(qc_program *prog, unsigned int glob, int vtype)
len = printf("$");
else
len = printf("%s ", name);
vtype = def->type;
vtype = def->type & DEF_TYPEMASK;
}
else
len = printf("[@%u] ", glob);
@ -417,6 +419,12 @@ static void prog_print_statement(qc_program *prog, prog_section_statement *st)
printf("<illegal instruction %d>\n", st->opcode);
return;
}
if ((prog->xflags & VMXF_TRACE) && prog->function_stack_count) {
size_t i;
for (i = 0; i < prog->function_stack_count; ++i)
printf("->");
printf("%s:", prog->function_stack[prog->function_stack_count-1]);
}
printf(" <> %-12s", asm_instr[st->opcode].m);
if (st->opcode >= INSTR_IF &&
st->opcode <= INSTR_IFNOT)
@ -427,6 +435,7 @@ static void prog_print_statement(qc_program *prog, prog_section_statement *st)
else if (st->opcode >= INSTR_CALL0 &&
st->opcode <= INSTR_CALL8)
{
trace_print_global(prog, st->o1.u1, TYPE_FUNCTION);
printf("\n");
}
else if (st->opcode == INSTR_GOTO)
@ -513,6 +522,10 @@ static qcint prog_enterfunction(qc_program *prog, prog_section_function *func)
st.stmt = prog->statement;
st.function = func;
if (prog->xflags & VMXF_TRACE) {
(void)!qc_program_function_stack_add(prog, prog_getstring(prog, func->name));
}
#ifdef QCVM_BACKUP_STRATEGY_CALLER_VARS
if (prog->stack_count)
{
@ -565,6 +578,11 @@ static qcint prog_leavefunction(qc_program *prog)
qc_exec_stack st = prog->stack[prog->stack_count-1];
if (prog->xflags & VMXF_TRACE) {
if (prog->function_stack_count)
prog->function_stack_count--;
}
#ifdef QCVM_BACKUP_STRATEGY_CALLER_VARS
if (prog->stack_count > 1) {
prev = prog->stack[prog->stack_count-2].function;
@ -1197,8 +1215,7 @@ while (1) {
}
ed = prog_getedict(prog, OPA->edict);
OPC->_int = ((qcint*)ed) - prog->entitydata;
OPC->_int += OPB->_int;
OPC->_int = ((qcint*)ed) - prog->entitydata + OPB->_int;
break;
case INSTR_STORE_F:

View file

@ -290,6 +290,9 @@ enum {
TYPE_POINTER ,
TYPE_INTEGER ,
TYPE_VARIANT ,
TYPE_STRUCT ,
TYPE_UNION ,
TYPE_ARRAY ,
TYPE_COUNT
};
@ -298,6 +301,7 @@ extern const char *type_name[TYPE_COUNT];
extern size_t type_sizeof[TYPE_COUNT];
extern uint16_t type_store_instr[TYPE_COUNT];
extern uint16_t field_store_instr[TYPE_COUNT];
/* could use type_store_instr + INSTR_STOREP_F - INSTR_STORE_F
* but this breaks when TYPE_INTEGER is added, since with the enhanced
* instruction set, the old ones are left untouched, thus the _I instructions
@ -881,6 +885,8 @@ typedef struct qc_program_s {
MEM_VECTOR_MAKE(qcint, entitydata);
MEM_VECTOR_MAKE(bool, entitypool);
MEM_VECTOR_MAKE(const char*, function_stack);
uint16_t crc16;
size_t tempstring_start;
@ -1023,6 +1029,7 @@ extern bool opts_werror;
extern bool opts_forcecrc;
extern uint16_t opts_forced_crc;
extern bool opts_pp_only;
extern size_t opts_max_array_size;
/*===================================================================*/
#define OPTS_FLAG(i) (!! (opts_flags[(i)/32] & (1<< ((i)%32))))

60
ir.c
View file

@ -38,10 +38,11 @@ const char *type_name[TYPE_COUNT] = {
"field",
"function",
"pointer",
#if 0
"integer",
#endif
"variant"
"variant",
"struct",
"union",
"array"
};
size_t type_sizeof[TYPE_COUNT] = {
@ -53,10 +54,11 @@ size_t type_sizeof[TYPE_COUNT] = {
1, /* TYPE_FIELD */
1, /* TYPE_FUNCTION */
1, /* TYPE_POINTER */
#if 0
1, /* TYPE_INTEGER */
#endif
3, /* TYPE_VARIANT */
0, /* TYPE_STRUCT */
0, /* TYPE_UNION */
0, /* TYPE_ARRAY */
};
uint16_t type_store_instr[TYPE_COUNT] = {
@ -70,9 +72,15 @@ uint16_t type_store_instr[TYPE_COUNT] = {
INSTR_STORE_ENT, /* should use I */
#if 0
INSTR_STORE_I, /* integer type */
#else
INSTR_STORE_F,
#endif
INSTR_STORE_V, /* variant, should never be accessed */
AINSTR_END, /* struct */
AINSTR_END, /* union */
AINSTR_END, /* array */
};
uint16_t field_store_instr[TYPE_COUNT] = {
@ -86,9 +94,15 @@ uint16_t field_store_instr[TYPE_COUNT] = {
INSTR_STORE_FLD,
#if 0
INSTR_STORE_FLD, /* integer type */
#else
INSTR_STORE_FLD,
#endif
INSTR_STORE_V, /* variant, should never be accessed */
AINSTR_END, /* struct */
AINSTR_END, /* union */
AINSTR_END, /* array */
};
uint16_t type_storep_instr[TYPE_COUNT] = {
@ -102,9 +116,15 @@ uint16_t type_storep_instr[TYPE_COUNT] = {
INSTR_STOREP_ENT, /* should use I */
#if 0
INSTR_STOREP_ENT, /* integer type */
#else
INSTR_STOREP_F,
#endif
INSTR_STOREP_V, /* variant, should never be accessed */
AINSTR_END, /* struct */
AINSTR_END, /* union */
AINSTR_END, /* array */
};
uint16_t type_eq_instr[TYPE_COUNT] = {
@ -118,9 +138,15 @@ uint16_t type_eq_instr[TYPE_COUNT] = {
INSTR_EQ_E, /* should use I */
#if 0
INSTR_EQ_I,
#else
INSTR_EQ_F,
#endif
INSTR_EQ_V, /* variant, should never be accessed */
AINSTR_END, /* struct */
AINSTR_END, /* union */
AINSTR_END, /* array */
};
uint16_t type_ne_instr[TYPE_COUNT] = {
@ -134,9 +160,15 @@ uint16_t type_ne_instr[TYPE_COUNT] = {
INSTR_NE_E, /* should use I */
#if 0
INSTR_NE_I,
#else
INSTR_NE_F,
#endif
INSTR_NE_V, /* variant, should never be accessed */
AINSTR_END, /* struct */
AINSTR_END, /* union */
AINSTR_END, /* array */
};
MEM_VEC_FUNCTIONS(ir_value_vector, ir_value*, v)
@ -1561,6 +1593,7 @@ ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_va
case TYPE_INTEGER: op = INSTR_LOAD_I; break;
#endif
default:
irerror(self->context, "invalid type for ir_block_create_load_from_ent: %s", type_name[outype]);
return NULL;
}
@ -1577,6 +1610,7 @@ ir_value* ir_block_create_add(ir_block *self,
if (l == r) {
switch (l) {
default:
irerror(self->context, "invalid type for ir_block_create_add: %s", type_name[l]);
return NULL;
case TYPE_FLOAT:
op = INSTR_ADD_F;
@ -1598,7 +1632,10 @@ ir_value* ir_block_create_add(ir_block *self,
op = INSTR_ADD_IF;
else
#endif
{
irerror(self->context, "invalid type for ir_block_create_add: %s", type_name[l]);
return NULL;
}
}
return ir_block_create_binop(self, label, op, left, right);
}
@ -1614,6 +1651,7 @@ ir_value* ir_block_create_sub(ir_block *self,
switch (l) {
default:
irerror(self->context, "invalid type for ir_block_create_sub: %s", type_name[l]);
return NULL;
case TYPE_FLOAT:
op = INSTR_SUB_F;
@ -1635,7 +1673,10 @@ ir_value* ir_block_create_sub(ir_block *self,
op = INSTR_SUB_IF;
else
#endif
{
irerror(self->context, "invalid type for ir_block_create_sub: %s", type_name[l]);
return NULL;
}
}
return ir_block_create_binop(self, label, op, left, right);
}
@ -1651,6 +1692,7 @@ ir_value* ir_block_create_mul(ir_block *self,
switch (l) {
default:
irerror(self->context, "invalid type for ir_block_create_mul: %s", type_name[l]);
return NULL;
case TYPE_FLOAT:
op = INSTR_MUL_F;
@ -1679,8 +1721,10 @@ ir_value* ir_block_create_mul(ir_block *self,
else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
op = INSTR_MUL_IF;
#endif
else
else {
irerror(self->context, "invalid type for ir_block_create_mul: %s", type_name[l]);
return NULL;
}
}
return ir_block_create_binop(self, label, op, left, right);
}
@ -1696,6 +1740,7 @@ ir_value* ir_block_create_div(ir_block *self,
switch (l) {
default:
irerror(self->context, "invalid type for ir_block_create_div: %s", type_name[l]);
return NULL;
case TYPE_FLOAT:
op = INSTR_DIV_F;
@ -1716,7 +1761,10 @@ ir_value* ir_block_create_div(ir_block *self,
op = INSTR_DIV_IF;
else
#endif
{
irerror(self->context, "invalid type for ir_block_create_div: %s", type_name[l]);
return NULL;
}
}
return ir_block_create_binop(self, label, op, left, right);
}

View file

@ -892,6 +892,7 @@ int lex_do(lex_file *lex)
/* single-character tokens */
switch (ch)
{
case '[':
case '(':
if (!lex_tokench(lex, ch) ||
!lex_endtoken(lex))
@ -906,7 +907,6 @@ int lex_do(lex_file *lex)
case ';':
case '{':
case '}':
case '[':
case ']':
case '#':
@ -1095,7 +1095,8 @@ int lex_do(lex_file *lex)
!strcmp(v, "struct") ||
!strcmp(v, "union") ||
!strcmp(v, "break") ||
!strcmp(v, "continue"))
!strcmp(v, "continue") ||
!strcmp(v, "var"))
{
lex->tok.ttype = TOKEN_KEYWORD;
}

View file

@ -167,6 +167,7 @@ static const oper_info c_operators[] = {
{ ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 },
{ "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */
{ "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */
{ "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
{ "~", 1, opid2('~', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
@ -227,6 +228,7 @@ static const oper_info qcc_operators[] = {
{ ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 },
{ "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */
{ "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */
{ "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX },
{ "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX },

49
main.c
View file

@ -35,6 +35,7 @@ bool opts_dump = false;
bool opts_werror = false;
bool opts_forcecrc = false;
bool opts_pp_only = false;
size_t opts_max_array_size = 1024;
uint16_t opts_forced_crc;
@ -161,6 +162,22 @@ static bool options_long_gcc(const char *optname, int *argc_, char ***argv_, cha
return options_long_witharg_all(optname, argc_, argv_, out, 1, false);
}
static void options_set(uint32_t *flags, size_t idx, bool on)
{
longbit lb = LONGBIT(idx);
#if 0
if (on)
flags[lb.idx] |= (1<<(lb.bit));
else
flags[lb.idx] &= ~(1<<(lb.bit));
#else
if (on)
flags[0] |= (1<<(lb));
else
flags[0] &= ~(1<<(lb));
#endif
}
static bool options_parse(int argc, char **argv) {
bool argend = false;
size_t itr;
@ -175,15 +192,19 @@ static bool options_parse(int argc, char **argv) {
if (argv[0][0] == '-') {
/* All gcc-type long options */
if (options_long_gcc("std", &argc, &argv, &argarg)) {
if (!strcmp(argarg, "gmqcc") || !strcmp(argarg, "default"))
if (!strcmp(argarg, "gmqcc") || !strcmp(argarg, "default")) {
options_set(opts_flags, ADJUST_VECTOR_FIELDS, true);
opts_standard = COMPILER_GMQCC;
else if (!strcmp(argarg, "qcc"))
} else if (!strcmp(argarg, "qcc")) {
options_set(opts_flags, ADJUST_VECTOR_FIELDS, false);
opts_standard = COMPILER_QCC;
else if (!strcmp(argarg, "fte") || !strcmp(argarg, "fteqcc"))
} else if (!strcmp(argarg, "fte") || !strcmp(argarg, "fteqcc")) {
options_set(opts_flags, ADJUST_VECTOR_FIELDS, false);
opts_standard = COMPILER_FTEQCC;
else if (!strcmp(argarg, "qccx"))
} else if (!strcmp(argarg, "qccx")) {
options_set(opts_flags, ADJUST_VECTOR_FIELDS, false);
opts_standard = COMPILER_QCCX;
else {
} else {
con_out("Unknown standard: %s\n", argarg);
return false;
}
@ -349,22 +370,6 @@ static bool options_parse(int argc, char **argv) {
return true;
}
static void options_set(uint32_t *flags, size_t idx, bool on)
{
longbit lb = LONGBIT(idx);
#if 0
if (on)
flags[lb.idx] |= (1<<(lb.bit));
else
flags[lb.idx] &= ~(1<<(lb.bit));
#else
if (on)
flags[0] |= (1<<(lb));
else
flags[0] &= ~(1<<(lb));
#endif
}
/* returns the line number, or -1 on error */
static bool progs_nextline(char **out, size_t *alen,FILE *src)
{
@ -417,6 +422,8 @@ int main(int argc, char **argv) {
options_set(opts_warn, WARN_END_SYS_FIELDS, true);
options_set(opts_warn, WARN_ASSIGN_FUNCTION_TYPES, true);
options_set(opts_flags, ADJUST_VECTOR_FIELDS, true);
if (!options_parse(argc, argv)) {
return usage();
}

1757
parser.c

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,8 @@ TESTLIST = \
ngraphs \
invalid-assign \
field-parameters \
functions-as-parameters
functions-as-parameters \
shadow-qcc shadow-gmqcc
.PHONY: clean test
@ -168,6 +169,16 @@ functions-as-parameters:
@$(VM) $< > $@/output
@diff $@/output $@/expected
$(eval $(call maketest,shadow-qcc,qcc))
shadow-qcc:
@$(VM) -vector '33 44 55' $< > $@/output
@diff $@/output $@/expected
$(eval $(call maketest,shadow-gmqcc,gm))
shadow-gmqcc:
@$(VM) -vector '33 44 55' $< > $@/output
@diff $@/output $@/expected
#######################################################################
obj:
mkdir obj

View file

@ -0,0 +1 @@
'0 0 0'

View file

@ -0,0 +1,7 @@
void(string, string) print = #1;
string(vector) vtos = #5;
void(vector org) main = {
local vector org;
print(vtos(org), "\n");
};

View file

@ -0,0 +1 @@
'33 44 55'

View file

@ -0,0 +1,7 @@
void(string, string) print = #1;
string(vector) vtos = #5;
void(vector org) main = {
local vector org;
print(vtos(org), "\n");
};