From: Wolfgang Bumiller Date: Sat, 1 Jun 2013 16:16:56 +0000 (+0200) Subject: Merge branch 'master' into cooking X-Git-Tag: v0.3.0~151^2~30 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=1dce501b7058000e19421af246ec14fd98aceab9;hp=ed585f8c048ea3cf591ee9f59963b02171d94424 Merge branch 'master' into cooking --- diff --git a/.gitignore b/.gitignore index 416e445..0405639 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,8 @@ distro/archbsd/* !distro/archbsd/release/PKGBUILD !distro/archbsd/git/PKGBUILD !distro/archlinux/this/Makefile + +gmqcc +gmqpak +qcvm +testsuite diff --git a/Makefile b/Makefile index 35b825a..fea3356 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,12 @@ OBJ_T = test.o util.o conout.o fs.o OBJ_C = main.o lexer.o parser.o fs.o OBJ_X = exec-standalone.o util.o conout.o fs.o +#we have duplicate object files when dealing with creating a simple list +#for dependinces. To combat this we use some clever recrusive-make to +#filter the list and remove duplicates which we use for make depend +RMDUP = $(if $1,$(firstword $1) $(call RMDUP,$(filter-out $(firstword $1),$1))) +DEPS := $(call RMDUP, $(OBJ_D) $(OBJ_P) $(OBJ_T) $(OBJ_C) $(OBJ_X)) + ifneq ("$(CYGWIN)", "") #nullify the common variables that #most *nix systems have (for windows) @@ -72,12 +78,12 @@ ifneq ("$(MINGW)", "") QCVM = qcvm.exe GMQCC = gmqcc.exe TESTSUITE = testsuite.exe - PAK = pak.exe + PAK = gmqpak.exe else QCVM = qcvm GMQCC = gmqcc TESTSUITE = testsuite - PAK = pak + PAK = gmqpak endif endif @@ -129,7 +135,6 @@ SPLINTFLAGS = \ -onlytrans \ -predboolint \ -boolops \ - -exportlocal \ -incondefs \ -macroredef \ -retvalint \ @@ -142,7 +147,6 @@ SPLINTFLAGS = \ -temptrans \ -usereleased \ -warnposix \ - -shiftimplementation \ +charindex \ -kepttrans \ -unqualifiedtrans \ @@ -156,8 +160,6 @@ SPLINTFLAGS = \ -mayaliasunique \ -realcompare \ -observertrans \ - -shiftnegative \ - -freshtrans \ -abstract \ -statictrans \ -castfcnptr @@ -203,34 +205,32 @@ gource-record: depend: @makedepend -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_D)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_T)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_C)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_X)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_P)) + $(subst .o,.c,$(DEPS)) #install rules -install: install-gmqcc install-qcvm install-doc +install: install-gmqcc install-qcvm install-gmqpak install-doc install-gmqcc: $(GMQCC) install -d -m755 $(DESTDIR)$(BINDIR) install -m755 $(GMQCC) $(DESTDIR)$(BINDIR)/$(GMQCC) install-qcvm: $(QCVM) install -d -m755 $(DESTDIR)$(BINDIR) install -m755 $(QCVM) $(DESTDIR)$(BINDIR)/$(QCVM) +install-gmqpak: $(PAK) + install -d -m755 $(DESTDIR)$(BINDIR) + install -m755 $(PAK) $(DESTDIR)$(BINDIR)/$(PAK) install-doc: install -d -m755 $(DESTDIR)$(MANDIR)/man1 install -m644 doc/gmqcc.1 $(DESTDIR)$(MANDIR)/man1/ install -m644 doc/qcvm.1 $(DESTDIR)$(MANDIR)/man1/ + install -m644 doc/gmqpak.1 $(DESTDIR)$(MANDIR)/man1/ uninstall: - rm $(DESTDIR)$(BINDIR)/gmqcc - rm $(DESTDIR)$(BINDIR)/qcvm - rm $(DESTDIR)$(MANDIR)/man1/doc/gmqcc.1 - rm $(DESTDIR)$(MANDIR)/man1/doc/qcvm.1 + rm -f $(DESTDIR)$(BINDIR)/gmqcc + rm -f $(DESTDIR)$(BINDIR)/qcvm + rm -f $(DESTDIR)$(BINDIR)/gmqpak + rm -f $(DESTDIR)$(MANDIR)/man1/doc/gmqcc.1 + rm -f $(DESTDIR)$(MANDIR)/man1/doc/qcvm.1 + rm -f $(DESTDIR)$(MANDIR)/man1/doc/gmqpak.1 # DO NOT DELETE @@ -244,23 +244,8 @@ opts.o: gmqcc.h opts.def fs.o: gmqcc.h opts.def utf8.o: gmqcc.h opts.def correct.o: gmqcc.h opts.def - +pak.o: gmqcc.h opts.def test.o: gmqcc.h opts.def -util.o: gmqcc.h opts.def -conout.o: gmqcc.h opts.def -fs.o: gmqcc.h opts.def - main.o: gmqcc.h opts.def lexer.h lexer.o: gmqcc.h opts.def lexer.h parser.o: gmqcc.h opts.def lexer.h ast.h ir.h intrin.h -fs.o: gmqcc.h opts.def - -util.o: gmqcc.h opts.def -conout.o: gmqcc.h opts.def -fs.o: gmqcc.h opts.def - -util.o: gmqcc.h opts.def -fs.o: gmqcc.h opts.def -conout.o: gmqcc.h opts.def -opts.o: gmqcc.h opts.def -pak.o: gmqcc.h opts.def diff --git a/ast.c b/ast.c index 3e5d304..81e1c12 100644 --- a/ast.c +++ b/ast.c @@ -34,8 +34,45 @@ return NULL; \ } \ ast_node_init((ast_node*)self, ctx, TYPE_##T); \ - ( (ast_node*)self )->node.destroy = (ast_node_delete*)destroyfn + ( (ast_node*)self )->destroy = (ast_node_delete*)destroyfn +/* + * forward declarations, these need not be in ast.h for obvious + * static reasons. + */ +static bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**); +static void ast_array_index_delete(ast_array_index*); +static bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_value**); +static void ast_store_delete(ast_store*); +static bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**); +static void ast_ifthen_delete(ast_ifthen*); +static bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**); +static void ast_ternary_delete(ast_ternary*); +static bool ast_ternary_codegen(ast_ternary*, ast_function*, bool lvalue, ir_value**); +static void ast_loop_delete(ast_loop*); +static bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**); +static void ast_breakcont_delete(ast_breakcont*); +static bool ast_breakcont_codegen(ast_breakcont*, ast_function*, bool lvalue, ir_value**); +static void ast_switch_delete(ast_switch*); +static bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**); +static void ast_label_delete(ast_label*); +static void ast_label_register_goto(ast_label*, ast_goto*); +static bool ast_label_codegen(ast_label*, ast_function*, bool lvalue, ir_value**); +static bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**); +static void ast_goto_delete(ast_goto*); +static void ast_call_delete(ast_call*); +static bool ast_call_codegen(ast_call*, ast_function*, bool lvalue, ir_value**); +static bool ast_block_codegen(ast_block*, ast_function*, bool lvalue, ir_value**); +static void ast_unary_delete(ast_unary*); +static bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**); +static void ast_entfield_delete(ast_entfield*); +static bool ast_entfield_codegen(ast_entfield*, ast_function*, bool lvalue, ir_value**); +static void ast_return_delete(ast_return*); +static bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**); +static void ast_binstore_delete(ast_binstore*); +static bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**); +static void ast_binary_delete(ast_binary*); +static bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**); /* It must not be possible to get here. */ static GMQCC_NORETURN void _ast_node_destroy(ast_node *self) @@ -48,11 +85,11 @@ static GMQCC_NORETURN void _ast_node_destroy(ast_node *self) /* Initialize main ast node aprts */ 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; - self->node.side_effects = false; + self->context = ctx; + self->destroy = &_ast_node_destroy; + self->keep = false; + self->nodetype = nodetype; + self->side_effects = false; } /* weight and side effects */ @@ -67,28 +104,28 @@ static void _ast_propagate_effects(ast_node *self, ast_node *other) static void ast_expression_init(ast_expression *self, ast_expression_codegen *codegen) { - self->expression.codegen = codegen; - self->expression.vtype = TYPE_VOID; - self->expression.next = NULL; - self->expression.outl = NULL; - self->expression.outr = NULL; - self->expression.params = NULL; - self->expression.count = 0; - self->expression.flags = 0; - self->expression.varparam = NULL; + self->codegen = codegen; + self->vtype = TYPE_VOID; + self->next = NULL; + self->outl = NULL; + self->outr = NULL; + self->params = NULL; + self->count = 0; + self->flags = 0; + self->varparam = NULL; } static void ast_expression_delete(ast_expression *self) { size_t i; - if (self->expression.next) - ast_delete(self->expression.next); - for (i = 0; i < vec_size(self->expression.params); ++i) { - ast_delete(self->expression.params[i]); + if (self->next) + ast_delete(self->next); + for (i = 0; i < vec_size(self->params); ++i) { + ast_delete(self->params[i]); } - vec_free(self->expression.params); - if (self->expression.varparam) - ast_delete(self->expression.varparam); + vec_free(self->params); + if (self->varparam) + ast_delete(self->varparam); } static void ast_expression_delete_full(ast_expression *self) @@ -100,8 +137,8 @@ static void ast_expression_delete_full(ast_expression *self) ast_value* ast_value_copy(const ast_value *self) { size_t i; - const ast_expression_common *fromex; - ast_expression_common *selfex; + const ast_expression *fromex; + ast_expression *selfex; ast_value *cp = ast_value_new(self->expression.node.context, self->name, self->expression.vtype); if (self->expression.next) { cp->expression.next = ast_type_copy(self->expression.node.context, self->expression.next); @@ -120,14 +157,14 @@ ast_value* ast_value_copy(const ast_value *self) void ast_type_adopt_impl(ast_expression *self, const ast_expression *other) { size_t i; - const ast_expression_common *fromex; - ast_expression_common *selfex; - self->expression.vtype = other->expression.vtype; - if (other->expression.next) { - self->expression.next = (ast_expression*)ast_type_copy(ast_ctx(self), other->expression.next); - } - fromex = &other->expression; - selfex = &self->expression; + const ast_expression *fromex; + ast_expression *selfex; + self->vtype = other->vtype; + if (other->next) { + self->next = (ast_expression*)ast_type_copy(ast_ctx(self), other->next); + } + fromex = other; + selfex = self; selfex->count = fromex->count; selfex->flags = fromex->flags; for (i = 0; i < vec_size(fromex->params); ++i) { @@ -140,17 +177,17 @@ static ast_expression* ast_shallow_type(lex_ctx ctx, int vtype) { ast_instantiate(ast_expression, ctx, ast_expression_delete_full); ast_expression_init(self, NULL); - self->expression.codegen = NULL; - self->expression.next = NULL; - self->expression.vtype = vtype; + self->codegen = NULL; + self->next = NULL; + self->vtype = vtype; return self; } ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex) { size_t i; - const ast_expression_common *fromex; - ast_expression_common *selfex; + const ast_expression *fromex; + ast_expression *selfex; if (!ex) return NULL; @@ -159,8 +196,8 @@ ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex) ast_instantiate(ast_expression, ctx, ast_expression_delete_full); ast_expression_init(self, NULL); - fromex = &ex->expression; - selfex = &self->expression; + fromex = ex; + selfex = self; /* This may never be codegen()d */ selfex->codegen = NULL; @@ -184,30 +221,30 @@ ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex) bool ast_compare_type(ast_expression *a, ast_expression *b) { - if (a->expression.vtype == TYPE_NIL || - b->expression.vtype == TYPE_NIL) + if (a->vtype == TYPE_NIL || + b->vtype == TYPE_NIL) return true; - if (a->expression.vtype != b->expression.vtype) + if (a->vtype != b->vtype) return false; - if (!a->expression.next != !b->expression.next) + if (!a->next != !b->next) return false; - if (vec_size(a->expression.params) != vec_size(b->expression.params)) + if (vec_size(a->params) != vec_size(b->params)) return false; - if ((a->expression.flags & AST_FLAG_TYPE_MASK) != - (b->expression.flags & AST_FLAG_TYPE_MASK) ) + if ((a->flags & AST_FLAG_TYPE_MASK) != + (b->flags & AST_FLAG_TYPE_MASK) ) { return false; } - if (vec_size(a->expression.params)) { + if (vec_size(a->params)) { size_t i; - for (i = 0; i < vec_size(a->expression.params); ++i) { - if (!ast_compare_type((ast_expression*)a->expression.params[i], - (ast_expression*)b->expression.params[i])) + for (i = 0; i < vec_size(a->params); ++i) { + if (!ast_compare_type((ast_expression*)a->params[i], + (ast_expression*)b->params[i])) return false; } } - if (a->expression.next) - return ast_compare_type(a->expression.next, b->expression.next); + if (a->next) + return ast_compare_type(a->next, b->next); return true; } @@ -227,43 +264,43 @@ static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsi if (pos + 1 >= bufsize) goto full; - switch (e->expression.vtype) { + switch (e->vtype) { case TYPE_VARIANT: util_strncpy(buf + pos, "(variant)", 9); return pos + 9; case TYPE_FIELD: buf[pos++] = '.'; - return ast_type_to_string_impl(e->expression.next, buf, bufsize, pos); + return ast_type_to_string_impl(e->next, buf, bufsize, pos); case TYPE_POINTER: if (pos + 3 >= bufsize) goto full; buf[pos++] = '*'; buf[pos++] = '('; - pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos); + pos = ast_type_to_string_impl(e->next, buf, bufsize, pos); if (pos + 1 >= bufsize) goto full; buf[pos++] = ')'; return pos; case TYPE_FUNCTION: - pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos); + pos = ast_type_to_string_impl(e->next, buf, bufsize, pos); if (pos + 2 >= bufsize) goto full; - if (!vec_size(e->expression.params)) { + if (!vec_size(e->params)) { buf[pos++] = '('; buf[pos++] = ')'; return pos; } buf[pos++] = '('; - pos = ast_type_to_string_impl((ast_expression*)(e->expression.params[0]), buf, bufsize, pos); - for (i = 1; i < vec_size(e->expression.params); ++i) { + pos = ast_type_to_string_impl((ast_expression*)(e->params[0]), buf, bufsize, pos); + for (i = 1; i < vec_size(e->params); ++i) { if (pos + 2 >= bufsize) goto full; buf[pos++] = ','; buf[pos++] = ' '; - pos = ast_type_to_string_impl((ast_expression*)(e->expression.params[i]), buf, bufsize, pos); + pos = ast_type_to_string_impl((ast_expression*)(e->params[i]), buf, bufsize, pos); } if (pos + 1 >= bufsize) goto full; @@ -271,18 +308,18 @@ static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsi return pos; case TYPE_ARRAY: - pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos); + pos = ast_type_to_string_impl(e->next, buf, bufsize, pos); if (pos + 1 >= bufsize) goto full; buf[pos++] = '['; - pos += util_snprintf(buf + pos, bufsize - pos - 1, "%i", (int)e->expression.count); + pos += util_snprintf(buf + pos, bufsize - pos - 1, "%i", (int)e->count); if (pos + 1 >= bufsize) goto full; buf[pos++] = ']'; return pos; default: - typestr = type_name[e->expression.vtype]; + typestr = type_name[e->vtype]; typelen = strlen(typestr); if (pos + typelen >= bufsize) goto full; @@ -303,6 +340,7 @@ void ast_type_to_string(ast_expression *e, char *buf, size_t bufsize) buf[pos] = 0; } +static bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out); ast_value* ast_value_new(lex_ctx ctx, const char *name, int t) { ast_instantiate(ast_value, ctx, ast_value_delete); @@ -317,8 +355,9 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t) self->cvq = CV_NONE; self->hasvalue = false; self->isimm = false; - self->uses = 0; + self->uses = 0; memset(&self->constval, 0, sizeof(self->constval)); + self->initlist = NULL; self->ir_v = NULL; self->ir_values = NULL; @@ -362,6 +401,20 @@ void ast_value_delete(ast_value* self) if (self->desc) mem_d(self->desc); + if (self->initlist) { + if (self->expression.next->vtype == TYPE_STRING) { + /* strings are allocated, free them */ + size_t i, len = vec_size(self->initlist); + /* in theory, len should be expression.count + * but let's not take any chances */ + for (i = 0; i < len; ++i) { + if (self->initlist[i].vstring) + mem_d(self->initlist[i].vstring); + } + } + vec_free(self->initlist); + } + ast_expression_delete((ast_expression*)self); mem_d(self); } @@ -407,7 +460,7 @@ ast_binary* ast_binary_new(lex_ctx ctx, int op, else if (op == INSTR_MUL_V) self->expression.vtype = TYPE_FLOAT; else - self->expression.vtype = left->expression.vtype; + self->expression.vtype = left->vtype; /* references all */ self->refs = AST_REF_ALL; @@ -501,11 +554,11 @@ void ast_return_delete(ast_return *self) ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field) { - if (field->expression.vtype != TYPE_FIELD) { + if (field->vtype != TYPE_FIELD) { compile_error(ctx, "ast_entfield_new with expression not of type field"); return NULL; } - return ast_entfield_new_force(ctx, entity, field, field->expression.next); + return ast_entfield_new_force(ctx, entity, field, field->next); } ast_entfield* ast_entfield_new_force(lex_ctx ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype) @@ -545,9 +598,9 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel return NULL; } - if (owner->expression.vtype != TYPE_VECTOR && - owner->expression.vtype != TYPE_FIELD) { - compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->expression.vtype]); + if (owner->vtype != TYPE_VECTOR && + owner->vtype != TYPE_FIELD) { + compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->vtype]); mem_d(self); return NULL; } @@ -555,7 +608,7 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_member_codegen); self->expression.node.keep = true; /* keep */ - if (owner->expression.vtype == TYPE_VECTOR) { + if (owner->vtype == TYPE_VECTOR) { self->expression.vtype = TYPE_FLOAT; self->expression.next = NULL; } else { @@ -604,7 +657,7 @@ ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_exp ast_expression *outtype; ast_instantiate(ast_array_index, ctx, ast_array_index_delete); - outtype = array->expression.next; + outtype = array->next; if (!outtype) { mem_d(self); /* Error: field has no type... */ @@ -619,7 +672,7 @@ ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_exp ast_propagate_effects(self, index); ast_type_adopt(self, outtype); - if (array->expression.vtype == TYPE_FIELD && outtype->expression.vtype == TYPE_ARRAY) { + if (array->vtype == TYPE_FIELD && outtype->vtype == TYPE_ARRAY) { if (self->expression.vtype != TYPE_ARRAY) { compile_error(ast_ctx(self), "array_index node on type"); ast_array_index_delete(self); @@ -693,7 +746,7 @@ ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression * ast_propagate_effects(self, ontrue); ast_propagate_effects(self, onfalse); - if (ontrue->expression.vtype == TYPE_NIL) + if (ontrue->vtype == TYPE_NIL) exprtype = onfalse; ast_type_adopt(self, exprtype); @@ -830,7 +883,7 @@ void ast_label_delete(ast_label *self) mem_d(self); } -void ast_label_register_goto(ast_label *self, ast_goto *g) +static void ast_label_register_goto(ast_label *self, ast_goto *g) { vec_push(self->gotos, g); } @@ -863,7 +916,7 @@ ast_call* ast_call_new(lex_ctx ctx, ast_expression *funcexpr) { ast_instantiate(ast_call, ctx, ast_call_delete); - if (!funcexpr->expression.next) { + if (!funcexpr->next) { compile_error(ctx, "not a function"); mem_d(self); return NULL; @@ -876,7 +929,7 @@ ast_call* ast_call_new(lex_ctx ctx, self->func = funcexpr; self->va_count = NULL; - ast_type_adopt(self, funcexpr->expression.next); + ast_type_adopt(self, funcexpr->next); return self; } @@ -906,14 +959,14 @@ bool ast_call_check_types(ast_call *self) bool retval = true; const ast_expression *func = self->func; size_t count = vec_size(self->params); - if (count > vec_size(func->expression.params)) - count = vec_size(func->expression.params); + if (count > vec_size(func->params)) + count = vec_size(func->params); for (i = 0; i < count; ++i) { - if (!ast_compare_type(self->params[i], (ast_expression*)(func->expression.params[i]))) + if (!ast_compare_type(self->params[i], (ast_expression*)(func->params[i]))) { ast_type_to_string(self->params[i], tgot, sizeof(tgot)); - ast_type_to_string((ast_expression*)func->expression.params[i], texp, sizeof(texp)); + ast_type_to_string((ast_expression*)func->params[i], texp, sizeof(texp)); compile_error(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s", (unsigned int)(i+1), texp, tgot); /* we don't immediately return */ @@ -921,12 +974,12 @@ bool ast_call_check_types(ast_call *self) } } count = vec_size(self->params); - if (count > vec_size(func->expression.params) && func->expression.varparam) { + if (count > vec_size(func->params) && func->varparam) { for (; i < count; ++i) { - if (!ast_compare_type(self->params[i], func->expression.varparam)) + if (!ast_compare_type(self->params[i], func->varparam)) { ast_type_to_string(self->params[i], tgot, sizeof(tgot)); - ast_type_to_string(func->expression.varparam, texp, sizeof(texp)); + ast_type_to_string(func->varparam, texp, sizeof(texp)); compile_error(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s", (unsigned int)(i+1), texp, tgot); /* we don't immediately return */ @@ -990,7 +1043,7 @@ bool ast_block_add_expr(ast_block *self, ast_expression *e) void ast_block_collect(ast_block *self, ast_expression *expr) { vec_push(self->collect, expr); - expr->expression.node.keep = true; + expr->node.keep = true; } void ast_block_delete(ast_block *self) @@ -1048,9 +1101,10 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype) vtype->hasvalue = true; vtype->constval.vfunc = self; - self->varargs = NULL; - self->argc = NULL; - self->fixedparams = NULL; + self->varargs = NULL; + self->argc = NULL; + self->fixedparams = NULL; + self->return_value = NULL; return self; } @@ -1080,10 +1134,12 @@ void ast_function_delete(ast_function *self) ast_delete(self->argc); if (self->fixedparams) ast_unref(self->fixedparams); + if (self->return_value) + ast_unref(self->return_value); mem_d(self); } -const char* ast_function_label(ast_function *self, const char *prefix) +static const char* ast_function_label(ast_function *self, const char *prefix) { size_t id; size_t len; @@ -1117,12 +1173,12 @@ const char* ast_function_label(ast_function *self, const char *prefix) * But I can't imagine a pituation where the output is truly unnecessary. */ -void _ast_codegen_output_type(ast_expression_common *self, ir_value *out) +static void _ast_codegen_output_type(ast_expression *self, ir_value *out) { if (out->vtype == TYPE_FIELD) - out->fieldtype = self->next->expression.vtype; + out->fieldtype = self->next->vtype; if (out->vtype == TYPE_FUNCTION) - out->outtype = self->next->expression.vtype; + out->outtype = self->next->vtype; } #define codegen_output_type(a,o) (_ast_codegen_output_type(&((a)->expression),(o))) @@ -1163,7 +1219,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) if (self->hasvalue && self->expression.vtype == TYPE_FUNCTION) { - ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->expression.vtype); + ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->vtype); if (!func) return false; func->context = ast_ctx(self); @@ -1185,14 +1241,14 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) goto error; } - if (fieldtype->expression.vtype == TYPE_ARRAY) { + if (fieldtype->vtype == TYPE_ARRAY) { size_t ai; char *name; size_t namelen; - ast_expression_common *elemtype; - int vtype; - ast_value *array = (ast_value*)fieldtype; + ast_expression *elemtype; + int vtype; + ast_value *array = (ast_value*)fieldtype; if (!ast_istype(fieldtype, ast_value)) { compile_error(ast_ctx(self), "internal error: ast_value required"); @@ -1203,7 +1259,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) if (!array->expression.count || array->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE)) compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count); - elemtype = &array->expression.next->expression; + elemtype = array->expression.next; vtype = elemtype->vtype; v = ir_builder_create_field(ir, self->name, vtype); @@ -1242,7 +1298,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) } else { - v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype); + v = ir_builder_create_field(ir, self->name, self->expression.next->vtype); if (!v) return false; v->context = ast_ctx(self); @@ -1258,7 +1314,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) char *name; size_t namelen; - ast_expression_common *elemtype = &self->expression.next->expression; + ast_expression *elemtype = self->expression.next; int vtype = elemtype->vtype; /* same as with field arrays */ @@ -1366,7 +1422,7 @@ error: /* clean up */ return false; } -bool ast_local_codegen(ast_value *self, ir_function *func, bool param) +static bool ast_local_codegen(ast_value *self, ir_function *func, bool param) { ir_value *v = NULL; @@ -1388,7 +1444,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param) char *name; size_t namelen; - ast_expression_common *elemtype = &self->expression.next->expression; + ast_expression *elemtype = self->expression.next; int vtype = elemtype->vtype; func->flags |= IR_FLAG_HAS_ARRAYS; @@ -1535,7 +1591,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) { ir_function *irf; ir_value *dummy; - ast_expression_common *ec; + ast_expression *ec; ast_expression_codegen *cgen; size_t i; @@ -1552,7 +1608,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) for (i = 0; i < vec_size(ec->params); ++i) { if (ec->params[i]->expression.vtype == TYPE_FIELD) - vec_push(irf->params, ec->params[i]->expression.next->expression.vtype); + vec_push(irf->params, ec->params[i]->expression.next->vtype); else vec_push(irf->params, ec->params[i]->expression.vtype); if (!self->builtin) { @@ -1572,6 +1628,12 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) return true; } + /* have a local return value variable? */ + if (self->return_value) { + if (!ast_local_codegen(self->return_value, self->ir_func, false)) + return false; + } + if (!vec_size(self->blocks)) { compile_error(ast_ctx(self), "function `%s` has no body", self->name); return false; @@ -1617,14 +1679,19 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) if (!self->curblock->final) { if (!self->vtype->expression.next || - self->vtype->expression.next->expression.vtype == TYPE_VOID) + self->vtype->expression.next->vtype == TYPE_VOID) { return ir_block_create_return(self->curblock, ast_ctx(self), NULL); } else if (vec_size(self->curblock->entries) || self->curblock == irf->first) { - /* error("missing return"); */ - if (compile_warning(ast_ctx(self), WARN_MISSING_RETURN_VALUES, + if (self->return_value) { + cgen = self->return_value->expression.codegen; + if (!(*cgen)((ast_expression*)(self->return_value), self, false, &dummy)) + return false; + return ir_block_create_return(self->curblock, ast_ctx(self), dummy); + } + else if (compile_warning(ast_ctx(self), WARN_MISSING_RETURN_VALUES, "control reaches end of non-void function (`%s`) via %s", self->name, self->curblock->label)) { @@ -1686,7 +1753,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu return false; continue; } - gen = self->exprs[i]->expression.codegen; + gen = self->exprs[i]->codegen; if (!(*gen)(self->exprs[i], func, false, out)) return false; } @@ -1750,7 +1817,7 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval)) return false; - cgen = self->source->expression.codegen; + cgen = self->source->codegen; if (!(*cgen)((ast_expression*)(self->source), func, false, &right)) return false; @@ -1765,13 +1832,13 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu { /* regular code */ - cgen = self->dest->expression.codegen; + cgen = self->dest->codegen; /* lvalue! */ if (!(*cgen)((ast_expression*)(self->dest), func, true, &left)) return false; self->expression.outl = left; - cgen = self->source->expression.codegen; + cgen = self->source->codegen; /* rvalue! */ if (!(*cgen)((ast_expression*)(self->source), func, false, &right)) return false; @@ -1823,7 +1890,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge")); /* generate the left expression */ - cgen = self->left->expression.codegen; + cgen = self->left->codegen; if (!(*cgen)((ast_expression*)(self->left), func, false, &left)) return false; /* remember the block */ @@ -1846,7 +1913,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va /* enter the right-expression's block */ func->curblock = other; /* generate */ - cgen = self->right->expression.codegen; + cgen = self->right->codegen; if (!(*cgen)((ast_expression*)(self->right), func, false, &right)) return false; /* remember block */ @@ -1909,11 +1976,11 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va return true; } - cgen = self->left->expression.codegen; + cgen = self->left->codegen; if (!(*cgen)((ast_expression*)(self->left), func, false, &left)) return false; - cgen = self->right->expression.codegen; + cgen = self->right->codegen; if (!(*cgen)((ast_expression*)(self->right), func, false, &right)) return false; @@ -1964,12 +2031,12 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i if (!(*cgen)((ast_expression*)(idx), func, false, &iridx)) return false; } - cgen = self->dest->expression.codegen; + cgen = self->dest->codegen; if (!(*cgen)((ast_expression*)(self->dest), func, false, &leftr)) return false; /* source as rvalue only */ - cgen = self->source->expression.codegen; + cgen = self->source->codegen; if (!(*cgen)((ast_expression*)(self->source), func, false, &right)) return false; @@ -2007,7 +2074,7 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i self->expression.outr = bin; } else { /* now store them */ - cgen = self->dest->expression.codegen; + cgen = self->dest->codegen; /* lvalue of destination */ if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftl)) return false; @@ -2046,7 +2113,7 @@ bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_valu return true; } - cgen = self->operand->expression.codegen; + cgen = self->operand->codegen; /* lvalue! */ if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand)) return false; @@ -2082,7 +2149,7 @@ bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_va self->expression.outr = (ir_value*)1; if (self->operand) { - cgen = self->operand->expression.codegen; + cgen = self->operand->codegen; /* lvalue! */ if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand)) return false; @@ -2117,11 +2184,11 @@ bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, i return true; } - cgen = self->entity->expression.codegen; + cgen = self->entity->codegen; if (!(*cgen)((ast_expression*)(self->entity), func, false, &ent)) return false; - cgen = self->field->expression.codegen; + cgen = self->field->codegen; if (!(*cgen)((ast_expression*)(self->field), func, false, &field)) return false; @@ -2169,12 +2236,12 @@ bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_va return true; } - cgen = self->owner->expression.codegen; + cgen = self->owner->codegen; if (!(*cgen)((ast_expression*)(self->owner), func, false, &vec)) return false; if (vec->vtype != TYPE_VECTOR && - !(vec->vtype == TYPE_FIELD && self->owner->expression.next->expression.vtype == TYPE_VECTOR)) + !(vec->vtype == TYPE_FIELD && self->owner->next->vtype == TYPE_VECTOR)) { return false; } @@ -2228,7 +2295,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva return false; } - cgen = self->index->expression.codegen; + cgen = self->index->codegen; if (!(*cgen)((ast_expression*)(self->index), func, false, &iridx)) return false; @@ -2250,7 +2317,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva if (idx->expression.vtype == TYPE_FLOAT) { unsigned int arridx = idx->constval.vfloat; - if (arridx >= self->array->expression.count) + if (arridx >= self->array->count) { compile_error(ast_ctx(self), "array index out of bounds: %i", arridx); return false; @@ -2259,7 +2326,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva } else if (idx->expression.vtype == TYPE_INTEGER) { unsigned int arridx = idx->constval.vint; - if (arridx >= self->array->expression.count) + if (arridx >= self->array->count) { compile_error(ast_ctx(self), "array index out of bounds: %i", arridx); return false; @@ -2300,7 +2367,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va self->expression.outr = (ir_value*)1; /* generate the condition */ - cgen = self->cond->expression.codegen; + cgen = self->cond->codegen; if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval)) return false; /* update the block which will get the jump - because short-logic or ternaries may have changed this */ @@ -2318,7 +2385,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va func->curblock = ontrue; /* generate */ - cgen = self->on_true->expression.codegen; + cgen = self->on_true->codegen; if (!(*cgen)((ast_expression*)(self->on_true), func, false, &dummy)) return false; @@ -2338,7 +2405,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va func->curblock = onfalse; /* generate */ - cgen = self->on_false->expression.codegen; + cgen = self->on_false->codegen; if (!(*cgen)((ast_expression*)(self->on_false), func, false, &dummy)) return false; @@ -2407,7 +2474,7 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ /* generate the condition */ func->curblock = cond; - cgen = self->cond->expression.codegen; + cgen = self->cond->codegen; if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval)) return false; cond_out = func->curblock; @@ -2422,7 +2489,7 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ func->curblock = ontrue; /* generate */ - cgen = self->on_true->expression.codegen; + cgen = self->on_true->codegen; if (!(*cgen)((ast_expression*)(self->on_true), func, false, &trueval)) return false; @@ -2439,7 +2506,7 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ func->curblock = onfalse; /* generate */ - cgen = self->on_false->expression.codegen; + cgen = self->on_false->codegen; if (!(*cgen)((ast_expression*)(self->on_false), func, false, &falseval)) return false; @@ -2536,7 +2603,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value */ if (self->initexpr) { - cgen = self->initexpr->expression.codegen; + cgen = self->initexpr->codegen; if (!(*cgen)((ast_expression*)(self->initexpr), func, false, &dummy)) return false; } @@ -2560,7 +2627,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value func->curblock = bprecond; /* generate */ - cgen = self->precond->expression.codegen; + cgen = self->precond->codegen; if (!(*cgen)((ast_expression*)(self->precond), func, false, &precond)) return false; @@ -2614,7 +2681,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value /* generate */ if (self->body) { - cgen = self->body->expression.codegen; + cgen = self->body->codegen; if (!(*cgen)((ast_expression*)(self->body), func, false, &dummy)) return false; } @@ -2631,7 +2698,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value func->curblock = bpostcond; /* generate */ - cgen = self->postcond->expression.codegen; + cgen = self->postcond->codegen; if (!(*cgen)((ast_expression*)(self->postcond), func, false, &postcond)) return false; @@ -2645,7 +2712,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value func->curblock = bincrement; /* generate */ - cgen = self->increment->expression.codegen; + cgen = self->increment->codegen; if (!(*cgen)((ast_expression*)(self->increment), func, false, &dummy)) return false; @@ -2794,7 +2861,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va (void)lvalue; (void)out; - cgen = self->operand->expression.codegen; + cgen = self->operand->codegen; if (!(*cgen)((ast_expression*)(self->operand), func, false, &irop)) return false; @@ -2827,7 +2894,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va if (swcase->value) { /* A regular case */ /* generate the condition operand */ - cgen = swcase->value->expression.codegen; + cgen = swcase->value->codegen; if (!(*cgen)((ast_expression*)(swcase->value), func, false, &val)) return false; /* generate the condition */ @@ -2855,7 +2922,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va /* enter the case */ func->curblock = bcase; - cgen = swcase->code->expression.codegen; + cgen = swcase->code->codegen; if (!(*cgen)((ast_expression*)swcase->code, func, false, &dummy)) return false; @@ -2900,7 +2967,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va } /* Now generate the default code */ - cgen = def_case->code->expression.codegen; + cgen = def_case->code->codegen; if (!(*cgen)((ast_expression*)def_case->code, func, false, &dummy)) return false; @@ -3025,7 +3092,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value return true; } - cgen = self->func->expression.codegen; + cgen = self->func->codegen; if (!(*cgen)((ast_expression*)(self->func), func, false, &funval)) return false; if (!funval) @@ -3039,7 +3106,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value ir_value *param; ast_expression *expr = self->params[i]; - cgen = expr->expression.codegen; + cgen = expr->codegen; if (!(*cgen)(expr, func, false, ¶m)) goto error; if (!param) @@ -3051,7 +3118,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value if (self->va_count) { ir_value *va_count; ir_builder *builder = func->curblock->owner->owner; - cgen = self->va_count->expression.codegen; + cgen = self->va_count->codegen; if (!(*cgen)((ast_expression*)(self->va_count), func, false, &va_count)) return false; if (!ir_block_create_store_op(func->curblock, ast_ctx(self), INSTR_STORE_F, @@ -3063,7 +3130,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value callinstr = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "call"), - funval, !!(self->func->expression.flags & AST_FLAG_NORETURN)); + funval, !!(self->func->flags & AST_FLAG_NORETURN)); if (!callinstr) goto error; diff --git a/ast.h b/ast.h index bae07db..a0fa14d 100644 --- a/ast.h +++ b/ast.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2012, 2013 * Wolfgang Bumiller + * Dale Weiler * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -28,8 +29,8 @@ * "main" ast node types for now. */ -typedef union ast_node_u ast_node; -typedef union ast_expression_u ast_expression; +typedef struct ast_node_common ast_node; +typedef struct ast_expression_common ast_expression; typedef struct ast_value_s ast_value; typedef struct ast_function_s ast_function; @@ -75,14 +76,14 @@ enum { TYPE_ast_goto /* 20 */ }; -#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) +#define ast_istype(x, t) ( ((ast_node*)x)->nodetype == (TYPE_##t) ) +#define ast_ctx(node) (((ast_node*)(node))->context) +#define ast_side_effects(node) (((ast_node*)(node))->side_effects) /* Node interface with common components */ typedef void ast_node_delete(ast_node*); -typedef struct +struct ast_node_common { lex_ctx context; /* I don't feel comfortable using keywords like 'delete' as names... */ @@ -93,14 +94,14 @@ typedef struct */ bool keep; bool side_effects; -} ast_node_common; - -#define ast_delete(x) (*( ((ast_node*)(x))->node.destroy ))((ast_node*)(x)) -#define ast_unref(x) do \ -{ \ - if (! (((ast_node*)(x))->node.keep) ) { \ - ast_delete(x); \ - } \ +}; + +#define ast_delete(x) (*( ((ast_node*)(x))->destroy ))((ast_node*)(x)) +#define ast_unref(x) do \ +{ \ + if (! (((ast_node*)(x))->keep) ) { \ + ast_delete(x); \ + } \ } while(0) /* Expression interface @@ -122,9 +123,9 @@ typedef bool ast_expression_codegen(ast_expression*, * type `expression`, so the ast_ident's codegen would search for * variables through the environment (or functions, constants...). */ -typedef struct +struct ast_expression_common { - ast_node_common node; + ast_node node; ast_expression_codegen *codegen; int vtype; ast_expression *next; @@ -143,7 +144,7 @@ typedef struct */ 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) @@ -161,9 +162,18 @@ typedef struct * typedef float foo; * is like creating a 'float foo', foo serving as the type's name. */ +typedef union { + double vfloat; + int vint; + vector vvec; + const char *vstring; + int ventity; + ast_function *vfunc; + ast_value *vfield; +} basic_value_t; struct ast_value_s { - ast_expression_common expression; + ast_expression expression; const char *name; const char *desc; @@ -179,15 +189,12 @@ struct ast_value_s bool isfield; /* this declares a field */ bool isimm; /* an immediate, not just const */ bool hasvalue; - union { - double vfloat; - int vint; - vector vvec; - const char *vstring; - int ventity; - ast_function *vfunc; - ast_value *vfield; - } constval; + basic_value_t constval; + /* for TYPE_ARRAY we have an optional vector + * of constants when an initializer list + * was provided. + */ + basic_value_t *initlist; /* usecount for the parser */ size_t uses; @@ -208,8 +215,11 @@ void ast_value_delete(ast_value*); 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 isfield); void ast_value_params_add(ast_value*, ast_value*); @@ -233,7 +243,7 @@ typedef enum ast_binary_ref_s { */ struct ast_binary_s { - ast_expression_common expression; + ast_expression expression; int op; ast_expression *left; @@ -245,9 +255,6 @@ ast_binary* ast_binary_new(lex_ctx ctx, int op, ast_expression *left, ast_expression *right); -void ast_binary_delete(ast_binary*); - -bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**); /* Binstore * @@ -256,7 +263,7 @@ bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**); */ struct ast_binstore_s { - ast_expression_common expression; + ast_expression expression; int opstore; int opbin; @@ -270,9 +277,6 @@ ast_binstore* ast_binstore_new(lex_ctx ctx, 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 * @@ -280,7 +284,7 @@ bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**) */ struct ast_unary_s { - ast_expression_common expression; + ast_expression expression; int op; ast_expression *operand; @@ -288,9 +292,6 @@ struct ast_unary_s ast_unary* ast_unary_new(lex_ctx ctx, int op, ast_expression *expr); -void ast_unary_delete(ast_unary*); - -bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**); /* Return * @@ -300,14 +301,11 @@ bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**); */ struct ast_return_s { - ast_expression_common expression; + ast_expression expression; ast_expression *operand; }; ast_return* ast_return_new(lex_ctx ctx, ast_expression *expr); -void ast_return_delete(ast_return*); - -bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**); /* Entity-field * @@ -324,7 +322,7 @@ bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**); */ struct ast_entfield_s { - ast_expression_common expression; + ast_expression expression; /* The entity can come from an expression of course. */ ast_expression *entity; /* As can the field, it just must result in a value of TYPE_FIELD */ @@ -332,9 +330,6 @@ struct ast_entfield_s }; 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**); /* Member access: * @@ -343,7 +338,7 @@ bool ast_entfield_codegen(ast_entfield*, ast_function*, bool lvalue, ir_value**) */ struct ast_member_s { - ast_expression_common expression; + ast_expression expression; ast_expression *owner; unsigned int field; const char *name; @@ -353,7 +348,6 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel 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**); /* Array index access: * @@ -367,14 +361,11 @@ bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**); */ struct ast_array_index_s { - ast_expression_common expression; + ast_expression 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 * @@ -383,16 +374,13 @@ bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_va */ struct ast_store_s { - ast_expression_common expression; + ast_expression expression; int op; ast_expression *dest; ast_expression *source; }; ast_store* ast_store_new(lex_ctx ctx, int op, ast_expression *d, ast_expression *s); -void ast_store_delete(ast_store*); - -bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**); /* If * @@ -407,16 +395,13 @@ bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**); */ struct ast_ifthen_s { - ast_expression_common expression; + ast_expression expression; ast_expression *cond; /* It's all just 'expressions', since an ast_block is one too. */ ast_expression *on_true; ast_expression *on_false; }; ast_ifthen* ast_ifthen_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse); -void ast_ifthen_delete(ast_ifthen*); - -bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**); /* Ternary expressions... * @@ -433,16 +418,13 @@ bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**); */ struct ast_ternary_s { - ast_expression_common expression; + ast_expression expression; ast_expression *cond; /* It's all just 'expressions', since an ast_block is one too. */ ast_expression *on_true; ast_expression *on_false; }; 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_ternary_codegen(ast_ternary*, ast_function*, bool lvalue, ir_value**); /* A general loop node * @@ -469,7 +451,7 @@ continue: // a 'continue' will jump here */ struct ast_loop_s { - ast_expression_common expression; + ast_expression expression; ast_expression *initexpr; ast_expression *precond; ast_expression *postcond; @@ -490,22 +472,16 @@ ast_loop* ast_loop_new(lex_ctx ctx, ast_expression *postcond, bool post_not, ast_expression *increment, ast_expression *body); -void ast_loop_delete(ast_loop*); - -bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**); /* Break/Continue */ struct ast_breakcont_s { - ast_expression_common expression; + ast_expression expression; bool is_continue; unsigned int levels; }; 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**); /* Switch Statements * @@ -523,16 +499,13 @@ typedef struct { } ast_switch_case; struct ast_switch_s { - ast_expression_common expression; + ast_expression expression; ast_expression *operand; ast_switch_case *cases; }; ast_switch* ast_switch_new(lex_ctx ctx, ast_expression *op); -void ast_switch_delete(ast_switch*); - -bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**); /* Label nodes * @@ -540,7 +513,7 @@ bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**); */ struct ast_label_s { - ast_expression_common expression; + ast_expression expression; const char *name; ir_block *irblock; ast_goto **gotos; @@ -549,10 +522,6 @@ struct ast_label_s }; 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 * @@ -560,18 +529,15 @@ bool ast_label_codegen(ast_label*, ast_function*, bool lvalue, ir_value**); */ struct ast_goto_s { - ast_expression_common expression; + ast_expression 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. @@ -584,15 +550,13 @@ bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**); */ struct ast_call_s { - ast_expression_common expression; + ast_expression expression; ast_expression *func; ast_expression* *params; ast_expression *va_count; }; ast_call* ast_call_new(lex_ctx ctx, ast_expression *funcexpr); -void ast_call_delete(ast_call*); -bool ast_call_codegen(ast_call*, ast_function*, bool lvalue, ir_value**); bool ast_call_check_types(ast_call*); /* Blocks @@ -600,7 +564,7 @@ bool ast_call_check_types(ast_call*); */ struct ast_block_s { - ast_expression_common expression; + ast_expression expression; ast_value* *locals; ast_expression* *exprs; @@ -609,8 +573,6 @@ struct ast_block_s ast_block* ast_block_new(lex_ctx ctx); void ast_block_delete(ast_block*); void ast_block_set_type(ast_block*, ast_expression *from); - -bool ast_block_codegen(ast_block*, ast_function*, bool lvalue, ir_value**); void ast_block_collect(ast_block*, ast_expression*); bool GMQCC_WARN ast_block_add_expr(ast_block*, ast_expression*); @@ -627,7 +589,7 @@ bool GMQCC_WARN ast_block_add_expr(ast_block*, ast_expression*); */ struct ast_function_s { - ast_node_common node; + ast_node node; ast_value *vtype; const char *name; @@ -660,6 +622,7 @@ struct ast_function_s ast_value *varargs; ast_value *argc; ast_value *fixedparams; + ast_value *return_value; }; ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype); /* This will NOT delete the underlying ast_value */ @@ -667,32 +630,9 @@ void ast_function_delete(ast_function*); /* For "optimized" builds this can just keep returning "foo"... * or whatever... */ -const char* ast_function_label(ast_function*, const char *prefix); +/*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 - */ -union ast_expression_u -{ - ast_expression_common expression; - - ast_value value; - ast_binary binary; - ast_block block; - ast_ternary ternary; - ast_ifthen ifthen; - ast_store store; - ast_entfield entfield; -}; - -/* Node union - */ -union ast_node_u -{ - ast_node_common node; - ast_expression expression; -}; - #endif diff --git a/code.c b/code.c index b0ce2ba..35f758a 100644 --- a/code.c +++ b/code.c @@ -23,10 +23,25 @@ */ #include "gmqcc.h" -/* This is outrageous! */ -#define QCINT_ENTRY void* -#define QCINT_TO_HASH_ENTRY(q) ((void*)(uintptr_t)(q)) -#define HASH_ENTRY_TO_QCINT(h) ((qcint)(uintptr_t)(h)) +/* + * We could use the old method of casting to uintptr_t then to void* + * or qcint; however, it's incredibly unsafe for two reasons. + * 1) The compilers aliasing optimization can legally make it unstable + * (it's undefined behaviour). + * + * 2) The cast itself depends on fresh storage (newly allocated in which + * ever function is using the cast macros), the contents of which are + * transferred in a way that the obligation to release storage is not + * propagated. + */ +typedef union { + void *enter; + qcint leave; +} code_hash_entry_t; + +/* Some sanity macros */ +#define CODE_HASH_ENTER(ENTRY) ((ENTRY).enter) +#define CODE_HASH_LEAVE(ENTRY) ((ENTRY).leave) void code_push_statement(code_t *code, prog_section_statement *stmt, int linenum) { @@ -72,11 +87,9 @@ code_t *code_init() { void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin); -uint32_t code_genstring(code_t *code, const char *str) -{ - uint32_t off; - size_t hash; - QCINT_ENTRY existing; +uint32_t code_genstring(code_t *code, const char *str) { + size_t hash; + code_hash_entry_t existing; if (!str) return 0; @@ -90,21 +103,21 @@ uint32_t code_genstring(code_t *code, const char *str) } if (OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS)) { - hash = ((unsigned char*)str)[strlen(str)-1]; - existing = code_util_str_htgeth(code->string_cache, str, hash); + hash = ((unsigned char*)str)[strlen(str)-1]; + CODE_HASH_ENTER(existing) = code_util_str_htgeth(code->string_cache, str, hash); } else { - hash = util_hthash(code->string_cache, str); - existing = util_htgeth(code->string_cache, str, hash); + hash = util_hthash(code->string_cache, str); + CODE_HASH_ENTER(existing) = util_htgeth(code->string_cache, str, hash); } - if (existing) - return HASH_ENTRY_TO_QCINT(existing); + if (CODE_HASH_ENTER(existing)) + return CODE_HASH_LEAVE(existing); - off = vec_size(code->chars); + CODE_HASH_LEAVE(existing) = vec_size(code->chars); vec_upload(code->chars, str, strlen(str)+1); - util_htseth(code->string_cache, str, hash, QCINT_TO_HASH_ENTRY(off)); - return off; + util_htseth(code->string_cache, str, hash, CODE_HASH_ENTER(existing)); + return CODE_HASH_LEAVE(existing); } qcint code_alloc_field (code_t *code, size_t qcsize) @@ -114,30 +127,26 @@ qcint code_alloc_field (code_t *code, size_t qcsize) return pos; } -bool code_write(code_t *code, const char *filename, const char *lnofile) { - prog_header code_header; - FILE *fp = NULL; - size_t it = 2; - - code_header.statements.offset = sizeof(prog_header); - code_header.statements.length = vec_size(code->statements); - code_header.defs.offset = code_header.statements.offset + (sizeof(prog_section_statement) * vec_size(code->statements)); - code_header.defs.length = vec_size(code->defs); - code_header.fields.offset = code_header.defs.offset + (sizeof(prog_section_def) * vec_size(code->defs)); - code_header.fields.length = vec_size(code->fields); - code_header.functions.offset = code_header.fields.offset + (sizeof(prog_section_field) * vec_size(code->fields)); - code_header.functions.length = vec_size(code->functions); - code_header.globals.offset = code_header.functions.offset + (sizeof(prog_section_function) * vec_size(code->functions)); - code_header.globals.length = vec_size(code->globals); - code_header.strings.offset = code_header.globals.offset + (sizeof(int32_t) * vec_size(code->globals)); - code_header.strings.length = vec_size(code->chars); - code_header.version = 6; +static void code_create_header(code_t *code, prog_header *code_header) { + code_header->statements.offset = sizeof(prog_header); + code_header->statements.length = vec_size(code->statements); + code_header->defs.offset = code_header->statements.offset + (sizeof(prog_section_statement) * vec_size(code->statements)); + code_header->defs.length = vec_size(code->defs); + code_header->fields.offset = code_header->defs.offset + (sizeof(prog_section_def) * vec_size(code->defs)); + code_header->fields.length = vec_size(code->fields); + code_header->functions.offset = code_header->fields.offset + (sizeof(prog_section_field) * vec_size(code->fields)); + code_header->functions.length = vec_size(code->functions); + code_header->globals.offset = code_header->functions.offset + (sizeof(prog_section_function) * vec_size(code->functions)); + code_header->globals.length = vec_size(code->globals); + code_header->strings.offset = code_header->globals.offset + (sizeof(int32_t) * vec_size(code->globals)); + code_header->strings.length = vec_size(code->chars); + code_header->version = 6; if (OPTS_OPTION_BOOL(OPTION_FORCECRC)) - code_header.crc16 = OPTS_OPTION_U16(OPTION_FORCED_CRC); + code_header->crc16 = OPTS_OPTION_U16(OPTION_FORCED_CRC); else - code_header.crc16 = code->crc; - code_header.entfield = code->entfields; + code_header->crc16 = code->crc; + code_header->entfield = code->entfields; if (OPTS_FLAG(DARKPLACES_STRING_TABLE_BUG)) { util_debug("GEN", "Patching stringtable for -fdarkplaces-stringtablebug\n"); @@ -149,20 +158,118 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { } /* ensure all data is in LE format */ - util_endianswap(&code_header.version, 1, sizeof(code_header.version)); - util_endianswap(&code_header.crc16, 1, sizeof(code_header.crc16)); - util_endianswap(&code_header.statements, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.defs, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.fields, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.functions, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.strings, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.globals, 2, sizeof(code_header.statements.offset)); - util_endianswap(&code_header.entfield, 1, sizeof(code_header.entfield)); + util_endianswap(&code_header->version, 1, sizeof(code_header->version)); + util_endianswap(&code_header->crc16, 1, sizeof(code_header->crc16)); + util_endianswap(&code_header->statements, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->defs, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->fields, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->functions, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->strings, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->globals, 2, sizeof(code_header->statements.offset)); + util_endianswap(&code_header->entfield, 1, sizeof(code_header->entfield)); + + /* + * These are not part of the header but we ensure LE format here to save on duplicated + * code. + */ util_endianswap(code->statements, vec_size(code->statements), sizeof(prog_section_statement)); util_endianswap(code->defs, vec_size(code->defs), sizeof(prog_section_def)); util_endianswap(code->fields, vec_size(code->fields), sizeof(prog_section_field)); util_endianswap(code->functions, vec_size(code->functions), sizeof(prog_section_function)); util_endianswap(code->globals, vec_size(code->globals), sizeof(int32_t)); +} + +/* + * Same principle except this one allocates memory and writes the lno(optional) and the dat file + * directly out to allocated memory. Which is actually very useful for the future library support + * we're going to add. + */ +bool code_write_memory(code_t *code, uint8_t **datmem, size_t *sizedat, uint8_t **lnomem, size_t *sizelno) { + prog_header code_header; + uint32_t offset = 0; + + if (!datmem) + return false; + + code_create_header(code, &code_header); + + #define WRITE_CHUNK(C,X,S) \ + do { \ + memcpy((void*)(&(*C)[offset]), (const void*)(X), (S)); \ + offset += (S); \ + } while (0) + + /* Calculate size required to store entire file out to memory */ + if (lnomem) { + uint32_t version = 1; + + *sizelno += 4; /* LNOF */ + *sizelno += sizeof(version); + *sizelno += sizeof(code_header.defs.length); + *sizelno += sizeof(code_header.globals.length); + *sizelno += sizeof(code_header.fields.length); + *sizelno += sizeof(code_header.statements.length); + *sizelno += sizeof(code->linenums[0]) * vec_size(code->linenums); + + *lnomem = (uint8_t*)mem_a(*sizelno); + + WRITE_CHUNK(lnomem, "LNOF", 4); + WRITE_CHUNK(lnomem, &version, sizeof(version)); + WRITE_CHUNK(lnomem, &code_header.defs.length, sizeof(code_header.defs.length)); + WRITE_CHUNK(lnomem, &code_header.globals.length, sizeof(code_header.globals.length)); + WRITE_CHUNK(lnomem, &code_header.fields.length, sizeof(code_header.fields.length)); + WRITE_CHUNK(lnomem, &code_header.statements.length, sizeof(code_header.statements.length)); + + /* something went terribly wrong */ + if (offset != *sizelno) { + mem_d(*lnomem); + *sizelno = 0; + return false; + } + offset = 0; + } + + /* Write out the dat */ + *sizedat += sizeof(prog_header); + *sizedat += sizeof(prog_section_statement) * vec_size(code->statements); + *sizedat += sizeof(prog_section_def) * vec_size(code->defs); + *sizedat += sizeof(prog_section_field) * vec_size(code->fields); + *sizedat += sizeof(prog_section_function) * vec_size(code->functions); + *sizedat += sizeof(int32_t) * vec_size(code->globals); + *sizedat += 1 * vec_size(code->chars); + + *datmem = (uint8_t*)mem_a(*sizedat); + + WRITE_CHUNK(datmem, &code_header, sizeof(prog_header)); + WRITE_CHUNK(datmem, code->statements, sizeof(prog_section_statement) * vec_size(code->statements)); + WRITE_CHUNK(datmem, code->defs, sizeof(prog_section_def) * vec_size(code->defs)); + WRITE_CHUNK(datmem, code->fields, sizeof(prog_section_field) * vec_size(code->fields)); + WRITE_CHUNK(datmem, code->functions, sizeof(prog_section_function) * vec_size(code->functions)); + WRITE_CHUNK(datmem, code->globals, sizeof(int32_t) * vec_size(code->globals)); + WRITE_CHUNK(datmem, code->chars, 1 * vec_size(code->chars)); + + #undef WRITE_CHUNK + + vec_free(code->statements); + vec_free(code->linenums); + vec_free(code->defs); + vec_free(code->fields); + vec_free(code->functions); + vec_free(code->globals); + vec_free(code->chars); + + util_htdel(code->string_cache); + mem_d(code); + + return true; +} + +bool code_write(code_t *code, const char *filename, const char *lnofile) { + prog_header code_header; + FILE *fp = NULL; + size_t it = 2; + + code_create_header(code, &code_header); if (lnofile) { uint32_t version = 1; @@ -175,13 +282,13 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { util_endianswap(code->linenums, vec_size(code->linenums), sizeof(code->linenums[0])); - if (fs_file_write("LNOF", 4, 1, fp) != 1 || - fs_file_write(&version, sizeof(version), 1, fp) != 1 || + if (fs_file_write("LNOF", 4, 1, fp) != 1 || + fs_file_write(&version, sizeof(version), 1, fp) != 1 || fs_file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 || fs_file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 || fs_file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 || fs_file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 || - fs_file_write(code->linenums, sizeof(code->linenums[0]), vec_size(code->linenums), fp) != vec_size(code->linenums)) + fs_file_write(code->linenums, sizeof(code->linenums[0]), vec_size(code->linenums), fp) != vec_size(code->linenums)) { con_err("failed to write lno file\n"); } @@ -194,7 +301,7 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { if (!fp) return false; - if (1 != fs_file_write(&code_header, sizeof(prog_header) , 1 , fp) || + if (1 != fs_file_write(&code_header, sizeof(prog_header) , 1 , fp) || vec_size(code->statements) != fs_file_write(code->statements, sizeof(prog_section_statement), vec_size(code->statements), fp) || vec_size(code->defs) != fs_file_write(code->defs, sizeof(prog_section_def) , vec_size(code->defs) , fp) || vec_size(code->fields) != fs_file_write(code->fields, sizeof(prog_section_field) , vec_size(code->fields) , fp) || @@ -260,6 +367,11 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { } } + fs_file_close(fp); + return true; +} + +void code_cleanup(code_t *code) { vec_free(code->statements); vec_free(code->linenums); vec_free(code->defs); @@ -270,7 +382,5 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) { util_htdel(code->string_cache); - fs_file_close(fp); mem_d(code); - return true; } diff --git a/conout.c b/conout.c index dd4dca3..687fdf4 100644 --- a/conout.c +++ b/conout.c @@ -333,7 +333,7 @@ int con_out(const char *fmt, ...) { * for reporting of file:line based on lexer context, These are used * heavily in the parser/ir/ast. */ -void con_vprintmsg_c(int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap, const char *condname) { +static void con_vprintmsg_c(int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap, const char *condname) { /* color selection table */ static int sel[] = { CON_WHITE, @@ -347,9 +347,9 @@ void con_vprintmsg_c(int level, const char *name, size_t line, const char *msgty int (*vprint)(const char *, va_list) = (err) ? &con_verr : &con_vout; if (color) - print("\033[0;%dm%s:%d: \033[0;%dm%s: \033[0m", CON_CYAN, name, (int)line, sel[level], msgtype); + print("\033[0;%dm%s:%d:%d: \033[0;%dm%s: \033[0m", CON_CYAN, name, (int)line, (int)column, sel[level], msgtype); else - print("%s:%d: %s: ", name, (int)line, msgtype); + print("%s:%d:%d: %s: ", name, (int)line, (int)column, msgtype); vprint(msg, ap); if (condname) @@ -358,19 +358,19 @@ void con_vprintmsg_c(int level, const char *name, size_t line, const char *msgty print("\n"); } -void con_vprintmsg(int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap) { - con_vprintmsg_c(level, name, line, msgtype, msg, ap, NULL); +void con_vprintmsg(int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap) { + con_vprintmsg_c(level, name, line, column, msgtype, msg, ap, NULL); } -void con_printmsg(int level, const char *name, size_t line, const char *msgtype, const char *msg, ...) { +void con_printmsg(int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...) { va_list va; va_start(va, msg); - con_vprintmsg(level, name, line, msgtype, msg, va); + con_vprintmsg(level, name, line, column, msgtype, msg, va); va_end (va); } void con_cvprintmsg(void *ctx, int lvl, const char *msgtype, const char *msg, va_list ap) { - con_vprintmsg(lvl, ((lex_ctx*)ctx)->file, ((lex_ctx*)ctx)->line, msgtype, msg, ap); + con_vprintmsg(lvl, ((lex_ctx*)ctx)->file, ((lex_ctx*)ctx)->line, ((lex_ctx*)ctx)->column, msgtype, msg, ap); } void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ...) { @@ -432,7 +432,7 @@ bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_ lvl = LVL_ERROR; } - con_vprintmsg_c(lvl, ctx.file, ctx.line, msgtype, fmt, ap, warn_name); + con_vprintmsg_c(lvl, ctx.file, ctx.line, ctx.column, msgtype, fmt, ap, warn_name); return OPTS_WERROR(warntype) && OPTS_FLAG(BAIL_ON_WERROR); } diff --git a/distro/deb/Makefile b/distro/deb/Makefile index df23602..7594400 100644 --- a/distro/deb/Makefile +++ b/distro/deb/Makefile @@ -10,12 +10,14 @@ DEB := $(DEBDIR)-$(CARCH).deb CONTROL := $(DEBDIR)/DEBIAN/control ifneq (, $(findstring i686, $(CARCH))) - CFLAGS := -m32 + CFLAGS += -m32 + LDFLAGS += -m32 endif base: $(MAKE) -C $(BASEDIR) clean - $(MAKE) -C $(BASEDIR) DESTDIR=distro/deb/$(DEBDIR) PREFIX=$(PREFIX) install + CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" \ + $(MAKE) -C $(BASEDIR) DESTDIR=distro/deb/$(DEBDIR) PREFIX=$(PREFIX) install @install -d -m755 $(DEBDIR)/DEBIAN @echo "Package: gmqcc" > $(CONTROL) @echo "Version: $(MAJOR).$(MINOR).$(PATCH)" >> $(CONTROL) diff --git a/doc/gmqcc.1 b/doc/gmqcc.1 index 60257dc..6ede944 100644 --- a/doc/gmqcc.1 +++ b/doc/gmqcc.1 @@ -506,6 +506,18 @@ Example: void printA() = #1; // the usual way void printB() = #2-1; // with a constant expression .Ed +.It Fl f Ns Cm return-assignments +Enabiling this option will allow assigning values or expressions to the +return keyword as if it were a local variable of the same type as the +function's signature's return type. +.Pp +Example: +.Bd -literal -offset indent +float bar() { return 1024; } +float fun() { + return = bar(); + return; // returns value of bar +} .El .Sh OPTIMIZATIONS .Bl -tag -width Ds diff --git a/doc/gmqpak.1 b/doc/gmqpak.1 new file mode 100644 index 0000000..967d432 --- /dev/null +++ b/doc/gmqpak.1 @@ -0,0 +1,38 @@ +.\" gmqpak mdoc manpage +.Dd April 27, 2013 +.Dt GMQPAK 2 PRM +.Os +.Sh NAME +.Nm gmqpak +.Nd A standalone Quake PAK utility +.Sh SYNOPSIS +.Nm gmqpak +.Op Cm options +.Op Cm files +.Sh DESCRIPTION +.Nm gmqpak +Is a standalone Quake PAK file utility supporting the extraction of files, +directories, or whole PAKs, as well as the opposite (creation of PAK files). +.Sh OPTIONS +.Bl -tag +.It Fl -file Ar file +Specify the PAK file to create or extract +.It Fl -e +Used to denote the extraction operation on a PAK file. +.It Fl -c +Used to denote the creation operation on a PAK file. +.El +.Sh EXAMPLES +Here's some examples of how to use the utility to manipulate PAK files. +.Bl -ohang +.It Li gmqpak -file id1.pak -e +.D1 extracts a PAK to ./ +.It Li gmqpak -file new.pak -c file1 dir/file2 +.D1 creates a PAK with the files specified +.It Li gmqpak -file new1.pak -c directory. +.D1 creates a PAK from files within the directory, including subdirectories and files. +.Sh AUTHOR +See . +.Sh BUGS +Please report bugs on , +or see on how to contact us. diff --git a/exec.c b/exec.c index 0ef3211..49cff44 100644 --- a/exec.c +++ b/exec.c @@ -167,16 +167,15 @@ void prog_delete(qc_program *prog) * VM code */ -char* prog_getstring(qc_program *prog, qcint str) -{ +const char* prog_getstring(qc_program *prog, qcint str) { /* cast for return required for C++ */ if (str < 0 || str >= (qcint)vec_size(prog->strings)) - return (char*)"<<>>"; + return "<<>>"; + return prog->strings + str; } -prog_section_def* prog_entfield(qc_program *prog, qcint off) -{ +prog_section_def* prog_entfield(qc_program *prog, qcint off) { size_t i; for (i = 0; i < vec_size(prog->fields); ++i) { if (prog->fields[i].offset == off) @@ -195,8 +194,7 @@ prog_section_def* prog_getdef(qc_program *prog, qcint off) return NULL; } -qcany* prog_getedict(qc_program *prog, qcint e) -{ +qcany* prog_getedict(qc_program *prog, qcint e) { if (e >= (qcint)vec_size(prog->entitypool)) { prog->vmerror++; fprintf(stderr, "Accessing out of bounds edict %i\n", (int)e); @@ -205,8 +203,7 @@ qcany* prog_getedict(qc_program *prog, qcint e) return (qcany*)(prog->entitydata + (prog->entityfields * e)); } -qcint prog_spawn_entity(qc_program *prog) -{ +qcint prog_spawn_entity(qc_program *prog) { char *data; qcint e; for (e = 0; e < (qcint)vec_size(prog->entitypool); ++e) { @@ -223,8 +220,7 @@ qcint prog_spawn_entity(qc_program *prog) return e; } -void prog_free_entity(qc_program *prog, qcint e) -{ +void prog_free_entity(qc_program *prog, qcint e) { if (!e) { prog->vmerror++; fprintf(stderr, "Trying to free world entity\n"); @@ -243,8 +239,7 @@ void prog_free_entity(qc_program *prog, qcint e) prog->entitypool[e] = false; } -qcint prog_tempstring(qc_program *prog, const char *str) -{ +qcint prog_tempstring(qc_program *prog, const char *str) { size_t len = strlen(str); size_t at = prog->tempstring_at; @@ -266,8 +261,7 @@ qcint prog_tempstring(qc_program *prog, const char *str) return at; } -static size_t print_escaped_string(const char *str, size_t maxlen) -{ +static size_t print_escaped_string(const char *str, size_t maxlen) { size_t len = 2; putchar('"'); --maxlen; /* because we're lazy and have escape sequences */ @@ -300,8 +294,7 @@ static size_t print_escaped_string(const char *str, size_t maxlen) return len; } -static void trace_print_global(qc_program *prog, unsigned int glob, int vtype) -{ +static void trace_print_global(qc_program *prog, unsigned int glob, int vtype) { static char spaces[28+1] = " "; prog_section_def *def; qcany *value; @@ -359,8 +352,7 @@ done: } } -static void prog_print_statement(qc_program *prog, prog_section_statement *st) -{ +static void prog_print_statement(qc_program *prog, prog_section_statement *st) { if (st->opcode >= (sizeof(asm_instr)/sizeof(asm_instr[0]))) { printf("\n", st->opcode); return; @@ -457,8 +449,7 @@ static void prog_print_statement(qc_program *prog, prog_section_statement *st) } } -static qcint prog_enterfunction(qc_program *prog, prog_section_function *func) -{ +static qcint prog_enterfunction(qc_program *prog, prog_section_function *func) { qc_exec_stack st; size_t parampos; int32_t p; @@ -507,8 +498,7 @@ static qcint prog_enterfunction(qc_program *prog, prog_section_function *func) return func->entry; } -static qcint prog_leavefunction(qc_program *prog) -{ +static qcint prog_leavefunction(qc_program *prog) { prog_section_function *prev = NULL; size_t oldsp; @@ -540,8 +530,7 @@ static qcint prog_leavefunction(qc_program *prog) return st.stmt - 1; /* offset the ++st */ } -bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps) -{ +bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps) { long jumpcount = 0; size_t oldxflags = prog->xflags; prog_section_statement *st; @@ -640,8 +629,7 @@ static qcvm_parameter *main_params = NULL; #define GetArg(num) GetGlobal(OFS_PARM0 + 3*(num)) #define Return(any) *(GetGlobal(OFS_RETURN)) = (any) -static int qc_print(qc_program *prog) -{ +static int qc_print(qc_program *prog) { size_t i; const char *laststr = NULL; for (i = 0; i < (size_t)prog->argc; ++i) { @@ -657,16 +645,14 @@ static int qc_print(qc_program *prog) return 0; } -static int qc_error(qc_program *prog) -{ +static int qc_error(qc_program *prog) { fprintf(stderr, "*** VM raised an error:\n"); qc_print(prog); prog->vmerror++; return -1; } -static int qc_ftos(qc_program *prog) -{ +static int qc_ftos(qc_program *prog) { char buffer[512]; qcany *num; qcany str; @@ -678,8 +664,7 @@ static int qc_ftos(qc_program *prog) return 0; } -static int qc_stof(qc_program *prog) -{ +static int qc_stof(qc_program *prog) { qcany *str; qcany num; CheckArgs(1); @@ -689,8 +674,7 @@ static int qc_stof(qc_program *prog) return 0; } -static int qc_vtos(qc_program *prog) -{ +static int qc_vtos(qc_program *prog) { char buffer[512]; qcany *num; qcany str; @@ -702,8 +686,7 @@ static int qc_vtos(qc_program *prog) return 0; } -static int qc_etos(qc_program *prog) -{ +static int qc_etos(qc_program *prog) { char buffer[512]; qcany *num; qcany str; @@ -715,8 +698,7 @@ static int qc_etos(qc_program *prog) return 0; } -static int qc_spawn(qc_program *prog) -{ +static int qc_spawn(qc_program *prog) { qcany ent; CheckArgs(0); ent.edict = prog_spawn_entity(prog); @@ -724,8 +706,7 @@ static int qc_spawn(qc_program *prog) return (ent.edict ? 0 : -1); } -static int qc_kill(qc_program *prog) -{ +static int qc_kill(qc_program *prog) { qcany *ent; CheckArgs(1); ent = GetArg(0); @@ -733,8 +714,7 @@ static int qc_kill(qc_program *prog) return 0; } -static int qc_sqrt(qc_program *prog) -{ +static int qc_sqrt(qc_program *prog) { qcany *num, out; CheckArgs(1); num = GetArg(0); @@ -743,8 +723,7 @@ static int qc_sqrt(qc_program *prog) return 0; } -static int qc_vlen(qc_program *prog) -{ +static int qc_vlen(qc_program *prog) { qcany *vec, len; CheckArgs(1); vec = GetArg(0); @@ -755,8 +734,7 @@ static int qc_vlen(qc_program *prog) return 0; } -static int qc_normalize(qc_program *prog) -{ +static int qc_normalize(qc_program *prog) { double len; qcany *vec; qcany out; @@ -776,13 +754,14 @@ static int qc_normalize(qc_program *prog) return 0; } -static int qc_strcat(qc_program *prog) -{ +static int qc_strcat(qc_program *prog) { char *buffer; size_t len1, len2; - char *cstr1, *cstr2; qcany *str1, *str2; qcany out; + + const char *cstr1; + const char *cstr2; CheckArgs(2); str1 = GetArg(0); @@ -800,12 +779,13 @@ static int qc_strcat(qc_program *prog) return 0; } -static int qc_strcmp(qc_program *prog) -{ - char *cstr1, *cstr2; +static int qc_strcmp(qc_program *prog) { qcany *str1, *str2; qcany out; + const char *cstr1; + const char *cstr2; + if (prog->argc != 2 && prog->argc != 3) { fprintf(stderr, "ERROR: invalid number of arguments for strcmp/strncmp: %i, expected 2 or 3\n", prog->argc); @@ -824,8 +804,7 @@ static int qc_strcmp(qc_program *prog) return 0; } -static int qc_floor(qc_program *prog) -{ +static int qc_floor(qc_program *prog) { qcany *num, out; CheckArgs(1); num = GetArg(0); @@ -865,8 +844,7 @@ static void version() { ); } -static void usage() -{ +static void usage() { printf("usage: %s [options] [parameters] file\n", arg0); printf("options:\n"); printf(" -h, --help print this message\n" @@ -886,8 +864,7 @@ static void usage() " -string pass a string parameter to main() \n"); } -static void prog_main_setparams(qc_program *prog) -{ +static void prog_main_setparams(qc_program *prog) { size_t i; qcany *arg; @@ -923,9 +900,35 @@ static void prog_main_setparams(qc_program *prog) } } +void escapestring(char* dest, const char* src) { + char c; + while ((c = *(src++))) { + switch(c) { + case '\t': + *(dest++) = '\\', *(dest++) = 't'; + break; + case '\n': + *(dest++) = '\\', *(dest++) = 'n'; + break; + case '\r': + *(dest++) = '\\', *(dest++) = 'r'; + break; + case '\\': + *(dest++) = '\\', *(dest++) = '\\'; + break; + case '\"': + *(dest++) = '\\', *(dest++) = '\"'; + break; + default: + *(dest++) = c; + } + } + *dest = '\0'; +} + void prog_disasm_function(qc_program *prog, size_t id); -int main(int argc, char **argv) -{ + +int main(int argc, char **argv) { size_t i; qcint fnmain = -1; qc_program *prog; @@ -1137,6 +1140,9 @@ int main(int argc, char **argv) return 0; } if (opts_printdefs) { + char *escape = NULL; + const char *getstring = NULL; + for (i = 0; i < vec_size(prog->defs); ++i) { printf("Global: %8s %-16s at %u%s", type_name[prog->defs[i].type & DEF_TYPEMASK], @@ -1158,7 +1164,12 @@ int main(int argc, char **argv) printf(" [init: %u]", (unsigned)( ((qcany*)(prog->globals + prog->defs[i].offset))->_int )); break; case TYPE_STRING: - printf(" [init: `%s`]", prog_getstring(prog, ((qcany*)(prog->globals + prog->defs[i].offset))->string )); + getstring = prog_getstring(prog, ((qcany*)(prog->globals + prog->defs[i].offset))->string); + escape = (char*)mem_a(strlen(getstring) * 2 + 1); /* will be enough */ + escapestring(escape, getstring); + printf(" [init: `%s`]", escape); + + mem_d(escape); /* free */ break; default: break; @@ -1232,8 +1243,7 @@ int main(int argc, char **argv) return 0; } -void prog_disasm_function(qc_program *prog, size_t id) -{ +void prog_disasm_function(qc_program *prog, size_t id) { prog_section_function *fdef = prog->functions + id; prog_section_statement *st; diff --git a/ftepp.c b/ftepp.c index 595b520..5348dfb 100644 --- a/ftepp.c +++ b/ftepp.c @@ -81,7 +81,7 @@ static uint32_t ftepp_predef_countval = 0; static uint32_t ftepp_predef_randval = 0; /* __DATE__ */ -char *ftepp_predef_date(lex_file *context) { +static char *ftepp_predef_date(lex_file *context) { struct tm *itime = NULL; time_t rtime; char *value = (char*)mem_a(82); @@ -104,7 +104,7 @@ char *ftepp_predef_date(lex_file *context) { } /* __TIME__ */ -char *ftepp_predef_time(lex_file *context) { +static char *ftepp_predef_time(lex_file *context) { struct tm *itime = NULL; time_t rtime; char *value = (char*)mem_a(82); @@ -127,13 +127,13 @@ char *ftepp_predef_time(lex_file *context) { } /* __LINE__ */ -char *ftepp_predef_line(lex_file *context) { +static char *ftepp_predef_line(lex_file *context) { char *value; util_asprintf(&value, "%d", (int)context->line); return value; } /* __FILE__ */ -char *ftepp_predef_file(lex_file *context) { +static char *ftepp_predef_file(lex_file *context) { size_t length = strlen(context->name) + 3; /* two quotes and a terminator */ char *value = (char*)mem_a(length); util_snprintf(value, length, "\"%s\"", context->name); @@ -141,7 +141,7 @@ char *ftepp_predef_file(lex_file *context) { return value; } /* __COUNTER_LAST__ */ -char *ftepp_predef_counterlast(lex_file *context) { +static char *ftepp_predef_counterlast(lex_file *context) { char *value; util_asprintf(&value, "%u", ftepp_predef_countval); @@ -149,7 +149,7 @@ char *ftepp_predef_counterlast(lex_file *context) { return value; } /* __COUNTER__ */ -char *ftepp_predef_counter(lex_file *context) { +static char *ftepp_predef_counter(lex_file *context) { char *value; ftepp_predef_countval ++; util_asprintf(&value, "%u", ftepp_predef_countval); @@ -158,7 +158,7 @@ char *ftepp_predef_counter(lex_file *context) { return value; } /* __RANDOM__ */ -char *ftepp_predef_random(lex_file *context) { +static char *ftepp_predef_random(lex_file *context) { char *value; ftepp_predef_randval = (util_rand() % 0xFF) + 1; util_asprintf(&value, "%u", ftepp_predef_randval); @@ -167,7 +167,7 @@ char *ftepp_predef_random(lex_file *context) { return value; } /* __RANDOM_LAST__ */ -char *ftepp_predef_randomlast(lex_file *context) { +static char *ftepp_predef_randomlast(lex_file *context) { char *value; util_asprintf(&value, "%u", ftepp_predef_randval); @@ -175,7 +175,7 @@ char *ftepp_predef_randomlast(lex_file *context) { return value; } /* __TIMESTAMP__ */ -char *ftepp_predef_timestamp(lex_file *context) { +static char *ftepp_predef_timestamp(lex_file *context) { struct stat finfo; char *find; char *value; @@ -374,7 +374,7 @@ static GMQCC_INLINE ppmacro* ftepp_macro_find(ftepp_t *ftepp, const char *name) static GMQCC_INLINE void ftepp_macro_delete(ftepp_t *ftepp, const char *name) { - util_htrm(ftepp->macros, name, NULL); + util_htrm(ftepp->macros, name, (void (*)(void*))&ppmacro_delete); } static GMQCC_INLINE int ftepp_next(ftepp_t *ftepp) @@ -564,10 +564,6 @@ static bool ftepp_define(ftepp_t *ftepp) return false; } -#if 0 - if (ftepp->output_on) - vec_push(ftepp->macros, macro); -#endif if (ftepp->output_on) util_htset(ftepp->macros, macro->name, (void*)macro); else { @@ -1885,7 +1881,7 @@ ftepp_t *ftepp_create() void ftepp_add_define(ftepp_t *ftepp, const char *source, const char *name) { ppmacro *macro; - lex_ctx ctx = { "__builtin__", 0 }; + lex_ctx ctx = { "__builtin__", 0, 0 }; ctx.file = source; macro = ppmacro_new(ctx, name); /*vec_push(ftepp->macros, macro);*/ diff --git a/gmqcc.h b/gmqcc.h index 0031227..a92e109 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -734,7 +734,9 @@ typedef struct { * code_pop_statement -- keeps statements and linenumbers together */ bool code_write (code_t *, const char *filename, const char *lno); +GMQCC_WARN code_t *code_init (void); +void code_cleanup (code_t *); uint32_t code_genstring (code_t *, const char *string); qcint code_alloc_field (code_t *, size_t qcsize); void code_push_statement(code_t *, prog_section_statement *stmt, int linenum); @@ -747,6 +749,7 @@ void code_pop_statement (code_t *); typedef struct { const char *file; size_t line; + size_t column; } lex_ctx; /*===================================================================*/ @@ -773,8 +776,8 @@ enum { FILE *con_default_out(); FILE *con_default_err(); -void con_vprintmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap); -void con_printmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, ...); +void con_vprintmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap); +void con_printmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...); void con_cvprintmsg(void *ctx, int lvl, const char *msgtype, const char *msg, va_list ap); void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ...); @@ -991,7 +994,7 @@ void prog_delete(qc_program *prog); bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps); -char* prog_getstring (qc_program *prog, qcint str); +const char* prog_getstring (qc_program *prog, qcint str); prog_section_def* prog_entfield (qc_program *prog, qcint off); prog_section_def* prog_getdef (qc_program *prog, qcint off); qcany* prog_getedict (qc_program *prog, qcint e); @@ -1161,7 +1164,7 @@ typedef struct { extern opts_cmd_t opts; -#define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1<< ((i)%32)))) +#define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1<< (unsigned)((i)%32)))) #define OPTS_FLAG(i) OPTS_GENERIC(opts.flags, (i)) #define OPTS_WARN(i) OPTS_GENERIC(opts.warn, (i)) #define OPTS_WERROR(i) OPTS_GENERIC(opts.werror, (i)) diff --git a/intrin.h b/intrin.h index 4f672dd..81af620 100644 --- a/intrin.h +++ b/intrin.h @@ -36,7 +36,7 @@ typedef struct { const char *alias; } intrin_t; -ht intrin_intrinsics() { +static ht intrin_intrinsics() { static ht intrinsics = NULL; if (!intrinsics) intrinsics = util_htnew(PARSER_HT_SIZE); @@ -69,12 +69,10 @@ ht intrin_intrinsics() { vec_push(parser->globals, (ast_expression*)(VALUE)); \ } while (0) - -ast_expression *intrin_func (parser_t *parser, const char *name); - #define QC_M_E 2.71828182845905 -ast_expression *intrin_pow(parser_t *parser) { +static ast_expression *intrin_func(parser_t *parser, const char *name); +static ast_expression *intrin_pow (parser_t *parser) { /* * float pow(float x, float y) { * float local = 1.0f; @@ -221,7 +219,7 @@ ast_expression *intrin_pow(parser_t *parser) { return (ast_expression*)value; } -ast_expression *intrin_mod(parser_t *parser) { +static ast_expression *intrin_mod(parser_t *parser) { /* * float mod(float x, float y) { * return x - y * floor(x / y); @@ -276,7 +274,7 @@ ast_expression *intrin_mod(parser_t *parser) { return (ast_expression*)value; } -ast_expression *intrin_exp(parser_t *parser) { +static ast_expression *intrin_exp(parser_t *parser) { /* * float exp(float x) { * return pow(QC_M_E, x); @@ -314,7 +312,7 @@ ast_expression *intrin_exp(parser_t *parser) { return (ast_expression*)value; } -ast_expression *intrin_isnan(parser_t *parser) { +static ast_expression *intrin_isnan(parser_t *parser) { /* * float isnan(float x) { * float local; @@ -383,7 +381,7 @@ void intrin_intrinsics_destroy(parser_t *parser) { } -ast_expression *intrin_func(parser_t *parser, const char *name) { +static ast_expression *intrin_func(parser_t *parser, const char *name) { static bool init = false; size_t i = 0; void *find; diff --git a/ir.c b/ir.c index 82dcb9b..5dae734 100644 --- a/ir.c +++ b/ir.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2012, 2013 * Wolfgang Bumiller + * Dale Weiler * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -211,9 +212,31 @@ const uint16_t type_not_instr[TYPE_COUNT] = { }; /* protos */ -static ir_value* ir_gen_extparam_proto(ir_builder *ir); -static void ir_gen_extparam (code_t *, ir_builder *ir); - +static ir_value* ir_value_var(const char *name, int st, int vtype); +static bool ir_value_set_name(ir_value*, const char *name); +static void ir_value_dump(ir_value*, int (*oprintf)(const char*,...)); + +static ir_value* ir_gen_extparam_proto(ir_builder *ir); +static void ir_gen_extparam (code_t *, ir_builder *ir); + +static bool ir_builder_set_name(ir_builder *self, const char *name); + +static ir_function* ir_function_new(struct ir_builder_s *owner, int returntype); +static bool ir_function_set_name(ir_function*, const char *name); +static void ir_function_delete(ir_function*); +static void ir_function_dump(ir_function*, char *ind, int (*oprintf)(const char*,...)); + +static ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx, const char *label, + int op, ir_value *a, ir_value *b, int outype); +static void ir_block_delete(ir_block*); +static ir_block* ir_block_new(struct ir_function_s *owner, const char *label); +static bool GMQCC_WARN ir_block_create_store(ir_block*, lex_ctx, ir_value *target, ir_value *what); +static bool ir_block_set_label(ir_block*, const char *label); +static void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...)); + +static bool ir_instr_op(ir_instr*, int op, ir_value *value, bool writing); +static void ir_instr_delete(ir_instr*); +static void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...)); /* error functions */ static void irerror(lex_ctx ctx, const char *msg, ...) @@ -238,7 +261,7 @@ static bool irwarning(lex_ctx ctx, int warntype, const char *fmt, ...) * Vector utility functions */ -bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx) +static bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx) { size_t i; size_t len = vec_size(vec); @@ -251,7 +274,7 @@ bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t * return false; } -bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx) +static bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx) { size_t i; size_t len = vec_size(vec); @@ -264,7 +287,7 @@ bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx) return false; } -bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx) +static bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx) { size_t i; size_t len = vec_size(vec); @@ -340,6 +363,7 @@ void ir_builder_delete(ir_builder* self) ir_value_delete(self->extparams[i]); } vec_free(self->extparams); + vec_free(self->extparam_protos); for (i = 0; i != vec_size(self->globals); ++i) { ir_value_delete(self->globals[i]); } @@ -362,7 +386,7 @@ bool ir_builder_set_name(ir_builder *self, const char *name) return !!self->name; } -ir_function* ir_builder_get_function(ir_builder *self, const char *name) +static ir_function* ir_builder_get_function(ir_builder *self, const char *name) { return (ir_function*)util_htget(self->htfunctions, name); } @@ -397,7 +421,7 @@ ir_function* ir_builder_create_function(ir_builder *self, const char *name, int return fn; } -ir_value* ir_builder_get_global(ir_builder *self, const char *name) +static ir_value* ir_builder_get_global(ir_builder *self, const char *name) { return (ir_value*)util_htget(self->htglobals, name); } @@ -427,7 +451,7 @@ ir_value* ir_builder_get_va_count(ir_builder *self) return (self->reserved_va_count = ir_builder_create_global(self, "reserved:va_count", TYPE_FLOAT)); } -ir_value* ir_builder_get_field(ir_builder *self, const char *name) +static ir_value* ir_builder_get_field(ir_builder *self, const char *name) { return (ir_value*)util_htget(self->htfields, name); } @@ -451,10 +475,10 @@ ir_value* ir_builder_create_field(ir_builder *self, const char *name, int vtype) *IR Function */ -bool ir_function_naive_phi(ir_function*); -void ir_function_enumerate(ir_function*); -bool ir_function_calculate_liferanges(ir_function*); -bool ir_function_allocate_locals(ir_function*); +static bool ir_function_naive_phi(ir_function*); +static void ir_function_enumerate(ir_function*); +static bool ir_function_calculate_liferanges(ir_function*); +static bool ir_function_allocate_locals(ir_function*); ir_function* ir_function_new(ir_builder* owner, int outtype) { @@ -551,7 +575,7 @@ void ir_function_delete(ir_function *self) mem_d(self); } -void ir_function_collect_value(ir_function *self, ir_value *v) +static void ir_function_collect_value(ir_function *self, ir_value *v) { vec_push(self->values, v); } @@ -574,7 +598,7 @@ static bool instr_is_operation(uint16_t op) (op >= INSTR_CALL0 && op <= INSTR_CALL8) ); } -bool ir_function_pass_peephole(ir_function *self) +static bool ir_function_pass_peephole(ir_function *self) { size_t b; @@ -690,7 +714,7 @@ bool ir_function_pass_peephole(ir_function *self) return true; } -bool ir_function_pass_tailrecursion(ir_function *self) +static bool ir_function_pass_tailrecursion(ir_function *self) { size_t b, p; @@ -926,7 +950,7 @@ bool ir_block_set_label(ir_block *self, const char *name) *IR Instructions */ -ir_instr* ir_instr_new(lex_ctx ctx, ir_block* owner, int op) +static ir_instr* ir_instr_new(lex_ctx ctx, ir_block* owner, int op) { ir_instr *self; self = (ir_instr*)mem_a(sizeof(*self)); @@ -958,7 +982,7 @@ static void ir_instr_delete_quick(ir_instr *self) mem_d(self); } -void ir_instr_delete(ir_instr *self) +static void ir_instr_delete(ir_instr *self) { size_t i; /* The following calls can only delete from @@ -989,7 +1013,7 @@ void ir_instr_delete(ir_instr *self) mem_d(self); } -bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing) +static bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing) { if (self->_ops[op]) { size_t idx; @@ -1012,7 +1036,7 @@ bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing) *IR Value */ -void ir_value_code_setaddr(ir_value *self, int32_t gaddr) +static void ir_value_code_setaddr(ir_value *self, int32_t gaddr) { self->code.globaladdr = gaddr; if (self->members[0]) self->members[0]->code.globaladdr = gaddr; @@ -1020,7 +1044,7 @@ void ir_value_code_setaddr(ir_value *self, int32_t gaddr) if (self->members[2]) self->members[2]->code.globaladdr = gaddr; } -int32_t ir_value_code_addr(const ir_value *self) +static int32_t ir_value_code_addr(const ir_value *self) { if (self->store == store_return) return OFS_RETURN + self->code.addroffset; @@ -1133,7 +1157,7 @@ static GMQCC_INLINE size_t ir_value_sizeof(const ir_value *self) return type_sizeof_[self->vtype]; } -ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype) +static ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype) { ir_value *v = ir_value_var(name, storetype, vtype); if (!v) @@ -1240,7 +1264,7 @@ bool ir_value_lives(ir_value *self, size_t at) return false; } -bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) +static bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) { size_t k; vec_push(self->life, e); @@ -1250,7 +1274,7 @@ bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) return true; } -bool ir_value_life_merge(ir_value *self, size_t s) +static bool ir_value_life_merge(ir_value *self, size_t s) { size_t i; const size_t vs = vec_size(self->life); @@ -1313,7 +1337,7 @@ bool ir_value_life_merge(ir_value *self, size_t s) return ir_value_life_insert(self, i, new_entry); } -bool ir_value_life_merge_into(ir_value *self, const ir_value *other) +static bool ir_value_life_merge_into(ir_value *self, const ir_value *other) { size_t i, myi; @@ -1387,7 +1411,7 @@ bool ir_value_life_merge_into(ir_value *self, const ir_value *other) return true; } -bool ir_values_overlap(const ir_value *a, const ir_value *b) +static bool ir_values_overlap(const ir_value *a, const ir_value *b) { /* For any life entry in A see if it overlaps with * any life entry in B. @@ -1483,7 +1507,7 @@ bool ir_block_create_store_op(ir_block *self, lex_ctx ctx, int op, ir_value *tar return true; } -bool ir_block_create_store(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what) +static bool ir_block_create_store(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what) { int op = 0; int vtype; @@ -1826,7 +1850,7 @@ ir_value* ir_block_create_unary(ir_block *self, lex_ctx ctx, return ir_block_create_general_instr(self, ctx, label, opcode, operand, NULL, ot); } -ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx ctx, const char *label, +static ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx ctx, const char *label, int op, ir_value *a, ir_value *b, int outype) { ir_instr *instr; @@ -3418,7 +3442,8 @@ static bool ir_builder_gen_global(code_t *code, ir_builder *self, ir_value *glob { ir_value_code_setaddr(global, vec_size(code->globals)); if (global->hasvalue) { - vec_push(code->globals, code_genstring(code, global->constval.vstring)); + uint32_t load = code_genstring(code, global->constval.vstring); + vec_push(code->globals, load); } else { vec_push(code->globals, 0); } @@ -3568,8 +3593,6 @@ bool ir_builder_generate(code_t *code, ir_builder *self, const char *filename) size_t i; char *lnofile = NULL; - code_init(); - for (i = 0; i < vec_size(self->fields); ++i) { ir_builder_prepare_field(code, self->fields[i]); @@ -3686,7 +3709,7 @@ bool ir_builder_generate(code_t *code, ir_builder *self, const char *filename) # define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE) #endif -const char *qc_opname(int op) +static const char *qc_opname(int op) { if (op < 0) return ""; if (op < (int)( sizeof(asm_instr) / sizeof(asm_instr[0]) )) @@ -3838,7 +3861,7 @@ void ir_block_dump(ir_block* b, char *ind, ind[strlen(ind)-1] = 0; } -void dump_phi(ir_instr *in, int (*oprintf)(const char*, ...)) +static void dump_phi(ir_instr *in, int (*oprintf)(const char*, ...)) { size_t i; oprintf("%s <- phi ", in->_ops[0]->name); @@ -3908,7 +3931,7 @@ void ir_instr_dump(ir_instr *in, char *ind, ind[strlen(ind)-1] = 0; } -void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...)) +static void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...)) { oprintf("\""); for (; *str; ++str) { diff --git a/ir.h b/ir.h index dac16a3..cd38295 100644 --- a/ir.h +++ b/ir.h @@ -23,7 +23,6 @@ #ifndef GMQCC_IR_HDR #define GMQCC_IR_HDR #include "gmqcc.h" -/* ir_value */ typedef struct { @@ -86,42 +85,19 @@ typedef struct ir_value_s { ir_life_entry_t *life; } ir_value; -int32_t ir_value_code_addr(const ir_value*); - /* ir_value can be a variable, or created by an operation */ -ir_value* ir_value_var(const char *name, int st, int vtype); /* if a result of an operation: the function should store * it to remember to delete it / garbage collect it */ -ir_value* ir_value_out(struct ir_function_s *owner, const char *name, int st, int vtype); -void ir_value_delete(ir_value*); -bool ir_value_set_name(ir_value*, const char *name); -ir_value* ir_value_vector_member(ir_value*, unsigned int member); - -bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx); - +void ir_value_delete(ir_value*); +ir_value* ir_value_vector_member(ir_value*, unsigned int member); bool GMQCC_WARN ir_value_set_float(ir_value*, float f); bool GMQCC_WARN ir_value_set_func(ir_value*, int f); -#if 0 -bool GMQCC_WARN ir_value_set_int(ir_value*, int i); -#endif bool GMQCC_WARN ir_value_set_string(ir_value*, const char *s); bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v); bool GMQCC_WARN ir_value_set_field(ir_value*, ir_value *fld); -/*bool ir_value_set_pointer_v(ir_value*, ir_value* p); */ -/*bool ir_value_set_pointer_i(ir_value*, int i); */ - -/* merge an instruction into the life-range */ -/* returns false if the lifepoint was already known */ -bool ir_value_life_merge(ir_value*, size_t); -bool ir_value_life_merge_into(ir_value*, const ir_value*); -/* check if a value lives at a specific point */ -bool ir_value_lives(ir_value*, size_t); -/* check if the life-range of 2 values overlaps */ -bool ir_values_overlap(const ir_value*, const ir_value*); - -void ir_value_dump(ir_value*, int (*oprintf)(const char*,...)); -void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...)); +bool ir_value_lives(ir_value*, size_t); +void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...)); /* PHI data */ typedef struct ir_phi_entry_s @@ -150,15 +126,6 @@ typedef struct ir_instr_s struct ir_block_s *owner; } ir_instr; -ir_instr* ir_instr_new(lex_ctx ctx, struct ir_block_s *owner, int opcode); -void ir_instr_delete(ir_instr*); - -bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx); - -bool ir_instr_op(ir_instr*, int op, ir_value *value, bool writing); - -void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...)); - /* block */ typedef struct ir_block_s { @@ -182,30 +149,16 @@ typedef struct ir_block_s size_t code_start; } ir_block; -ir_block* ir_block_new(struct ir_function_s *owner, const char *label); -void ir_block_delete(ir_block*); - -bool ir_block_set_label(ir_block*, const char *label); - -ir_value* ir_block_create_binop(ir_block*, lex_ctx, const char *label, int op, - ir_value *left, ir_value *right); -ir_value* ir_block_create_unary(ir_block*, lex_ctx, const char *label, int op, - ir_value *operand); +ir_value* ir_block_create_binop(ir_block*, lex_ctx, const char *label, int op, ir_value *left, ir_value *right); +ir_value* ir_block_create_unary(ir_block*, lex_ctx, const char *label, int op, ir_value *operand); bool GMQCC_WARN ir_block_create_store_op(ir_block*, lex_ctx, int op, ir_value *target, ir_value *what); -bool GMQCC_WARN ir_block_create_store(ir_block*, lex_ctx, ir_value *target, ir_value *what); bool GMQCC_WARN ir_block_create_storep(ir_block*, lex_ctx, ir_value *target, ir_value *what); - -/* field must be of TYPE_FIELD */ -ir_value* ir_block_create_load_from_ent(ir_block*, lex_ctx, const char *label, ir_value *ent, ir_value *field, int outype); - -ir_value* ir_block_create_fieldaddress(ir_block*, lex_ctx, const char *label, ir_value *entity, ir_value *field); +ir_value* ir_block_create_load_from_ent(ir_block*, lex_ctx, const char *label, ir_value *ent, ir_value *field, int outype); +ir_value* ir_block_create_fieldaddress(ir_block*, lex_ctx, const char *label, ir_value *entity, ir_value *field); /* This is to create an instruction of the form * %label := opcode a, b */ -ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx, const char *label, - int op, ir_value *a, ir_value *b, int outype); - ir_instr* ir_block_create_phi(ir_block*, lex_ctx, const char *label, int vtype); ir_value* ir_phi_value(ir_instr*); void ir_phi_add(ir_instr*, ir_block *b, ir_value *v); @@ -226,10 +179,7 @@ bool GMQCC_WARN ir_block_create_if(ir_block*, lex_ctx, ir_value *cond, bool GMQCC_WARN ir_block_create_jump(ir_block*, lex_ctx, ir_block *to); bool GMQCC_WARN ir_block_create_goto(ir_block*, lex_ctx, ir_block *to); -void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...)); - /* function */ - typedef struct ir_function_s { char *name; @@ -276,6 +226,7 @@ typedef struct ir_function_s /* vararg support: */ size_t max_varargs; } ir_function; + #define IR_FLAG_HAS_ARRAYS (1<<1) #define IR_FLAG_HAS_UNINITIALIZED (1<<2) #define IR_FLAG_HAS_GOTO (1<<3) @@ -283,25 +234,9 @@ typedef struct ir_function_s #define IR_FLAG_MASK_NO_OVERLAP (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED) #define IR_FLAG_MASK_NO_LOCAL_TEMPS (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED) -ir_function* ir_function_new(struct ir_builder_s *owner, int returntype); -void ir_function_delete(ir_function*); - -void ir_function_collect_value(ir_function*, ir_value *value); - -bool ir_function_set_name(ir_function*, const char *name); - -ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param); - +ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param); bool GMQCC_WARN ir_function_finalize(ir_function*); -/* -bool ir_function_naive_phi(ir_function*); -bool ir_function_enumerate(ir_function*); -bool ir_function_calculate_liferanges(ir_function*); -*/ - -ir_block* ir_function_create_block(lex_ctx ctx, ir_function*, const char *label); - -void ir_function_dump(ir_function*, char *ind, int (*oprintf)(const char*,...)); +ir_block* ir_function_create_block(lex_ctx ctx, ir_function*, const char *label); /* builder */ #define IR_HT_SIZE 1024 @@ -334,25 +269,14 @@ typedef struct ir_builder_s ir_value *reserved_va_count; } ir_builder; -ir_builder* ir_builder_new(const char *modulename); -void ir_builder_delete(ir_builder*); - -bool ir_builder_set_name(ir_builder *self, const char *name); - -ir_function* ir_builder_get_function(ir_builder*, const char *fun); +ir_builder* ir_builder_new(const char *modulename); +void ir_builder_delete(ir_builder*); 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); - -ir_value* ir_builder_get_va_count(ir_builder*); - -bool ir_builder_generate(code_t *, ir_builder *self, const char *filename); - -void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...)); - +ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype); +ir_value* ir_builder_create_field(ir_builder*, const char *name, int vtype); +ir_value* ir_builder_get_va_count(ir_builder*); +bool ir_builder_generate(code_t *, ir_builder *self, const char *filename); +void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...)); /* * This code assumes 32 bit floats while generating binary diff --git a/lexer.c b/lexer.c index 7722f4f..862131e 100644 --- a/lexer.c +++ b/lexer.c @@ -60,19 +60,19 @@ static size_t num_keywords_fg = sizeof(keywords_fg) / sizeof(keywords_fg[0]); static char* *lex_filenames; -void lexerror(lex_file *lex, const char *fmt, ...) +static void lexerror(lex_file *lex, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (lex) - con_vprintmsg(LVL_ERROR, lex->name, lex->sline, "parse error", fmt, ap); + con_vprintmsg(LVL_ERROR, lex->name, lex->sline, lex->column, "parse error", fmt, ap); else - con_vprintmsg(LVL_ERROR, "", 0, "parse error", fmt, ap); + con_vprintmsg(LVL_ERROR, "", 0, 0, "parse error", fmt, ap); va_end(ap); } -bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...) +static bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...) { bool r; lex_ctx ctx; @@ -174,9 +174,11 @@ static void lex_token_new(lex_file *lex) #else if (lex->tok.value) vec_shrinkto(lex->tok.value, 0); + lex->tok.constval.t = 0; - lex->tok.ctx.line = lex->sline; - lex->tok.ctx.file = lex->name; + lex->tok.ctx.line = lex->sline; + lex->tok.ctx.file = lex->name; + lex->tok.ctx.column = lex->column; #endif } #endif @@ -200,12 +202,12 @@ lex_file* lex_open(const char *file) memset(lex, 0, sizeof(*lex)); - lex->file = in; - lex->name = util_strdup(file); - lex->line = 1; /* we start counting at 1 */ - + lex->file = in; + lex->name = util_strdup(file); + lex->line = 1; /* we start counting at 1 */ + lex->column = 0; lex->peekpos = 0; - lex->eof = false; + lex->eof = false; vec_push(lex_filenames, lex->name); return lex; @@ -228,11 +230,11 @@ lex_file* lex_open_string(const char *str, size_t len, const char *name) lex->open_string_length = len; lex->open_string_pos = 0; - lex->name = util_strdup(name ? name : ""); - lex->line = 1; /* we start counting at 1 */ - + lex->name = util_strdup(name ? name : ""); + lex->line = 1; /* we start counting at 1 */ lex->peekpos = 0; - lex->eof = false; + lex->eof = false; + lex->column = 0; vec_push(lex_filenames, lex->name); @@ -271,11 +273,14 @@ void lex_close(lex_file *lex) static int lex_fgetc(lex_file *lex) { - if (lex->file) + if (lex->file) { + lex->column++; return fs_file_getc(lex->file); + } if (lex->open_string) { if (lex->open_string_pos >= lex->open_string_length) return EOF; + lex->column++; return lex->open_string[lex->open_string_pos++]; } return EOF; @@ -291,16 +296,22 @@ static int lex_try_trigraph(lex_file *lex, int old) { int c2, c3; c2 = lex_fgetc(lex); - if (!lex->push_line && c2 == '\n') + if (!lex->push_line && c2 == '\n') { lex->line++; + lex->column = 0; + } + if (c2 != '?') { lex_ungetch(lex, c2); return old; } c3 = lex_fgetc(lex); - if (!lex->push_line && c3 == '\n') + if (!lex->push_line && c3 == '\n') { lex->line++; + lex->column = 0; + } + switch (c3) { case '=': return '#'; case '/': return '\\'; @@ -365,8 +376,11 @@ static int lex_getch(lex_file *lex) static void lex_ungetch(lex_file *lex, int ch) { lex->peek[lex->peekpos++] = ch; - if (!lex->push_line && ch == '\n') + lex->column--; + if (!lex->push_line && ch == '\n') { lex->line--; + lex->column = 0; + } } /* classify characters @@ -872,6 +886,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) ch = 0; else { --u8len; + lex->column += u8len; for (uc = 0; uc < u8len; ++uc) lex_tokench(lex, u8buf[uc]); /* the last character will be inserted with the tokench() call diff --git a/lexer.h b/lexer.h index 24ac39a..cde0863 100644 --- a/lexer.h +++ b/lexer.h @@ -114,6 +114,7 @@ typedef struct lex_file_s { char *name; size_t line; size_t sline; /* line at the start of a token */ + size_t column; int peek[256]; size_t peekpos; @@ -163,9 +164,14 @@ typedef struct { unsigned int flags; } oper_info; -#define opid1(a) (a) -#define opid2(a,b) ((a<<8)|b) -#define opid3(a,b,c) ((a<<16)|(b<<8)|c) +/* + * Explicit uint8_t casts since the left operand of shift operator cannot + * be negative, even though it won't happen, this supresses the future + * possibility. + */ +#define opid1(a) ((uint8_t)a) +#define opid2(a,b) (((uint8_t)a<<8) |(uint8_t)b) +#define opid3(a,b,c) (((uint8_t)a<<16)|((uint8_t)b<<8)|(uint8_t)c) static const oper_info c_operators[] = { { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */ @@ -335,6 +341,6 @@ static const size_t qcc_operator_count = (sizeof(qcc_operators) / sizeof(qcc_ope extern const oper_info *operators; extern size_t operator_count; -void lexerror(lex_file*, const char *fmt, ...); +/*void lexerror(lex_file*, const char *fmt, ...);*/ #endif diff --git a/main.c b/main.c index bbc685a..840a6a7 100644 --- a/main.c +++ b/main.c @@ -41,6 +41,7 @@ static ppitem *ppems = NULL; #define TYPE_ASM 1 #define TYPE_SRC 2 + static const char *app_name; static void version() { diff --git a/opts.c b/opts.c index 77aa9c0..abd012f 100644 --- a/opts.c +++ b/opts.c @@ -361,7 +361,7 @@ void opts_ini_init(const char *file) { if ((line = opts_ini_parse(ini, &opts_ini_load, &error)) != 0) { /* there was a parse error with the ini file */ - con_printmsg(LVL_ERROR, file, line, "error", error); + con_printmsg(LVL_ERROR, file, line, 0 /*TODO: column for ini error*/, "error", error); vec_free(error); } diff --git a/opts.def b/opts.def index a9301a5..520f9b9 100644 --- a/opts.def +++ b/opts.def @@ -51,6 +51,7 @@ GMQCC_DEFINE_FLAG(VARIADIC_ARGS) GMQCC_DEFINE_FLAG(LEGACY_VECTOR_MATHS) GMQCC_DEFINE_FLAG(EXPRESSIONS_FOR_BUILTINS) + GMQCC_DEFINE_FLAG(RETURN_ASSIGNMENTS) #endif /* warning flags */ diff --git a/pak.c b/pak.c index 653a463..9ff7e78 100644 --- a/pak.c +++ b/pak.c @@ -26,7 +26,7 @@ * The PAK format uses a FOURCC concept for storing the magic ident within * the header as a uint32_t. */ -#define PAK_FOURCC ((uint32_t)(('P' | ('A' << 8) | ('C' << 16) | ('K' << 24)))) +#define PAK_FOURCC ((uint32_t)(((uint8_t)'P'|((uint8_t)'A'<<8)|((uint8_t)'C'<<16)|((uint8_t)'K'<<24)))) typedef struct { uint32_t magic; /* "PACK" */ @@ -222,7 +222,7 @@ static pak_file_t *pak_open_write(const char *file) { return pak; } -pak_file_t *pak_open(const char *file, const char *mode) { +static pak_file_t *pak_open(const char *file, const char *mode) { if (!file || !mode) return NULL; @@ -234,7 +234,7 @@ pak_file_t *pak_open(const char *file, const char *mode) { return NULL; } -bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) { +static bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) { size_t itr; if (!pak || !file) @@ -259,7 +259,7 @@ bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) { /* * Extraction abilities. These work as you expect them to. */ -bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) { +static bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) { pak_directory_t *dir = NULL; unsigned char *dat = NULL; char *local = NULL; @@ -310,7 +310,7 @@ bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) { return true; } -bool pak_extract_all(pak_file_t *pak, const char *dir) { +static bool pak_extract_all(pak_file_t *pak, const char *dir) { size_t itr; if (!fs_dir_make(dir)) @@ -328,7 +328,7 @@ bool pak_extract_all(pak_file_t *pak, const char *dir) { * Insertion functions (the opposite of extraction). Yes for generating * PAKs. */ -bool pak_insert_one(pak_file_t *pak, const char *file) { +static bool pak_insert_one(pak_file_t *pak, const char *file) { pak_directory_t dir; unsigned char *dat; FILE *fp; @@ -413,7 +413,7 @@ bool pak_insert_all(pak_file_t *pak, const char *dir) { return true; } -bool pak_close(pak_file_t *pak) { +static bool pak_close(pak_file_t *pak) { size_t itr; if (!pak) @@ -575,7 +575,6 @@ int main(int argc, char **argv) { pak_close(pak); vec_free(files); - util_meminfo(); return EXIT_SUCCESS; } diff --git a/parser.c b/parser.c index 1b9e7c7..7d9ac6a 100644 --- a/parser.c +++ b/parser.c @@ -185,7 +185,7 @@ vector vec3_mulvf(vector a, float b) * parsing */ -bool parser_next(parser_t *parser) +static bool parser_next(parser_t *parser) { /* lex_do kills the previous token */ parser->tok = lex_do(parser->lex); @@ -587,7 +587,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) blocks[i] = sy->out[vec_size(sy->out)+i].block; asvalue[i] = (ast_value*)exprs[i]; - if (exprs[i]->expression.vtype == TYPE_NOEXPR && + if (exprs[i]->vtype == TYPE_NOEXPR && !(i != 0 && op->id == opid2('?',':')) && !(i == 1 && op->id == opid1('.'))) { @@ -605,11 +605,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } #define NotSameType(T) \ - (exprs[0]->expression.vtype != exprs[1]->expression.vtype || \ - exprs[0]->expression.vtype != T) + (exprs[0]->vtype != exprs[1]->vtype || \ + exprs[0]->vtype != T) #define CanConstFold1(A) \ (ast_istype((A), ast_value) && ((ast_value*)(A))->hasvalue && (((ast_value*)(A))->cvq == CV_CONST) &&\ - (A)->expression.vtype != TYPE_FUNCTION) + (A)->vtype != TYPE_FUNCTION) #define CanConstFold(A, B) \ (CanConstFold1(A) && CanConstFold1(B)) #define ConstV(i) (asvalue[(i)]->constval.vvec) @@ -622,8 +622,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; case opid1('.'): - if (exprs[0]->expression.vtype == TYPE_VECTOR && - exprs[1]->expression.vtype == TYPE_NOEXPR) + if (exprs[0]->vtype == TYPE_VECTOR && + exprs[1]->vtype == TYPE_NOEXPR) { if (exprs[1] == (ast_expression*)parser->const_vec[0]) out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL); @@ -636,14 +636,14 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } } - else if (exprs[0]->expression.vtype == TYPE_ENTITY) { - if (exprs[1]->expression.vtype != TYPE_FIELD) { + else if (exprs[0]->vtype == TYPE_ENTITY) { + if (exprs[1]->vtype != TYPE_FIELD) { compile_error(ast_ctx(exprs[1]), "type error: right hand of member-operand should be an entity-field"); return false; } out = (ast_expression*)ast_entfield_new(ctx, exprs[0], exprs[1]); } - else if (exprs[0]->expression.vtype == TYPE_VECTOR) { + else if (exprs[0]->vtype == TYPE_VECTOR) { compile_error(ast_ctx(exprs[1]), "vectors cannot be accessed this way"); return false; } @@ -654,15 +654,15 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid1('['): - if (exprs[0]->expression.vtype != TYPE_ARRAY && - !(exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_ARRAY)) + if (exprs[0]->vtype != TYPE_ARRAY && + !(exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_ARRAY)) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "cannot index value of type %s", ty1); return false; } - if (exprs[1]->expression.vtype != TYPE_FLOAT) { + if (exprs[1]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[1]), "index must be of type float, not %s", ty1); return false; @@ -709,7 +709,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = exprs[0]; break; case opid2('-','P'): - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold1(exprs[0])) out = (ast_expression*)parser_const_float(parser, -ConstF(0)); @@ -729,13 +729,13 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot negate type %s", - type_name[exprs[0]->expression.vtype]); + type_name[exprs[0]->vtype]); return false; } break; case opid2('!','P'): - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold1(exprs[0])) out = (ast_expression*)parser_const_float(parser, !ConstF(0)); @@ -771,21 +771,21 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot logically negate type %s", - type_name[exprs[0]->expression.vtype]); + type_name[exprs[0]->vtype]); return false; } break; case opid1('+'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold(exprs[0], exprs[1])) { @@ -802,21 +802,21 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; case opid1('-'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_float(parser, ConstF(0) - ConstF(1)); @@ -831,27 +831,27 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; }; break; case opid1('*'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype && - !(exprs[0]->expression.vtype == TYPE_VECTOR && - exprs[1]->expression.vtype == TYPE_FLOAT) && - !(exprs[1]->expression.vtype == TYPE_VECTOR && - exprs[0]->expression.vtype == TYPE_FLOAT) + if (exprs[0]->vtype != exprs[1]->vtype && + !(exprs[0]->vtype == TYPE_VECTOR && + exprs[1]->vtype == TYPE_FLOAT) && + !(exprs[1]->vtype == TYPE_VECTOR && + exprs[0]->vtype == TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: - if (exprs[1]->expression.vtype == TYPE_VECTOR) + if (exprs[1]->vtype == TYPE_VECTOR) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(1), ConstF(0))); @@ -867,7 +867,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } break; case TYPE_VECTOR: - if (exprs[1]->expression.vtype == TYPE_FLOAT) + if (exprs[1]->vtype == TYPE_FLOAT) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), ConstF(1))); @@ -883,7 +883,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (!vec.y && !vec.z) { /* 'n 0 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 0, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.x != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.x), out); @@ -891,7 +891,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.z) { /* '0 n 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 1, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.y != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.y), out); @@ -899,7 +899,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.y) { /* '0 n 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 2, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.z != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.z), out); @@ -912,7 +912,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (!vec.y && !vec.z) { /* v * 'n 0 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.x != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.x)); @@ -920,7 +920,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.z) { /* v * '0 n 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 1, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.y != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.y)); @@ -928,7 +928,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.y) { /* v * '0 n 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 2, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.z != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.z)); @@ -942,25 +942,25 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; }; break; case opid1('/'): - if (exprs[1]->expression.vtype != TYPE_FLOAT) { + if (exprs[1]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); compile_error(ctx, "invalid types used in expression: cannot divide tyeps %s and %s", ty1, ty2); return false; } - if (exprs[0]->expression.vtype == TYPE_FLOAT) { + if (exprs[0]->vtype == TYPE_FLOAT) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_float(parser, ConstF(0) / ConstF(1)); else out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]); } - else if (exprs[0]->expression.vtype == TYPE_VECTOR) { + else if (exprs[0]->vtype == TYPE_VECTOR) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), 1.0/ConstF(1))); else { @@ -990,8 +990,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid1('%'): if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform modulo operation between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } if (CanConstFold(exprs[0], exprs[1])) { @@ -1019,8 +1019,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid1('&'): if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform bit operations between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } if (CanConstFold(exprs[0], exprs[1])) @@ -1040,9 +1040,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid2('>','>'): if (CanConstFold(exprs[0], exprs[1]) && ! NotSameType(TYPE_FLOAT)) { if (op->id == opid2('<','<')) - out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) << (int)(ConstF(1)))); + out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) << (unsigned int)(ConstF(1)))); else - out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) >> (int)(ConstF(1)))); + out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) >> (unsigned int)(ConstF(1)))); break; } case opid3('<','<','='): @@ -1076,7 +1076,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } for (i = 0; i < 2; ++i) { - if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->expression.vtype == TYPE_VECTOR) { + if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->vtype == TYPE_VECTOR) { out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]); if (!out) break; out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); @@ -1087,7 +1087,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; } } - else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->expression.vtype == TYPE_STRING) { + else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->vtype == TYPE_STRING) { out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[i]); if (!out) break; out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); @@ -1194,49 +1194,49 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) generated_op += INSTR_LE; if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); break; case opid2('!', '='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + if (exprs[0]->vtype != exprs[1]->vtype) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid2('=', '='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + if (exprs[0]->vtype != exprs[1]->vtype) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid1('='): if (ast_istype(exprs[0], ast_entfield)) { ast_expression *field = ((ast_entfield*)exprs[0])->field; if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) && - exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_VECTOR) + exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_VECTOR) { assignop = type_storep_instr[TYPE_VECTOR]; } else - assignop = type_storep_instr[exprs[0]->expression.vtype]; - if (assignop == VINSTR_END || !ast_compare_type(field->expression.next, exprs[1])) + assignop = type_storep_instr[exprs[0]->vtype]; + if (assignop == VINSTR_END || !ast_compare_type(field->next, exprs[1])) { - ast_type_to_string(field->expression.next, ty1, sizeof(ty1)); + ast_type_to_string(field->next, ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) && - field->expression.next->expression.vtype == TYPE_FUNCTION && - exprs[1]->expression.vtype == TYPE_FUNCTION) + field->next->vtype == TYPE_FUNCTION && + exprs[1]->vtype == TYPE_FUNCTION) { (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@ -1248,13 +1248,13 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else { if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) && - exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_VECTOR) + exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_VECTOR) { assignop = type_store_instr[TYPE_VECTOR]; } else { - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; } if (assignop == VINSTR_END) { @@ -1267,8 +1267,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) && - exprs[0]->expression.vtype == TYPE_FUNCTION && - exprs[1]->expression.vtype == TYPE_FUNCTION) + exprs[0]->vtype == TYPE_FUNCTION && + exprs[1]->vtype == TYPE_FUNCTION) { (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@ -1285,7 +1285,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid3('+','+','P'): case opid3('-','-','P'): /* prefix ++ */ - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for prefix increment: %s", ty1); return false; @@ -1310,7 +1310,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid3('S','+','+'): case opid3('S','-','-'): /* prefix ++ */ - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for suffix increment: %s", ty1); return false; @@ -1342,8 +1342,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid2('+','='): case opid2('-','='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -1355,10 +1355,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; - switch (exprs[0]->expression.vtype) { + assignop = type_store_instr[exprs[0]->vtype]; + switch (exprs[0]->vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('+','=') ? INSTR_ADD_F : INSTR_SUB_F), @@ -1371,16 +1371,16 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; case opid2('*','='): case opid2('/','='): - if (exprs[1]->expression.vtype != TYPE_FLOAT || - !(exprs[0]->expression.vtype == TYPE_FLOAT || - exprs[0]->expression.vtype == TYPE_VECTOR)) + if (exprs[1]->vtype != TYPE_FLOAT || + !(exprs[0]->vtype == TYPE_FLOAT || + exprs[0]->vtype == TYPE_VECTOR)) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -1392,10 +1392,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; - switch (exprs[0]->expression.vtype) { + assignop = type_store_instr[exprs[0]->vtype]; + switch (exprs[0]->vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('*','=') ? INSTR_MUL_F : INSTR_DIV_F), @@ -1424,8 +1424,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; @@ -1442,9 +1442,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('&','=') ? INSTR_BITAND : INSTR_BITOR), exprs[0], exprs[1]); @@ -1462,9 +1462,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]); if (!out) return false; @@ -1477,7 +1477,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid2('~', 'P'): - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for bit not: %s", ty1); return false; @@ -1573,7 +1573,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) if (ast_istype(fun, ast_value)) { funval = (ast_value*)fun; - if ((fun->expression.flags & AST_FLAG_VARIADIC) && + if ((fun->flags & AST_FLAG_VARIADIC) && !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin)) { call->va_count = (ast_expression*)parser_const_float(parser, (double)paramcount); @@ -1583,18 +1583,18 @@ static bool parser_close_call(parser_t *parser, shunt *sy) /* overwrite fid, the function, with a call */ sy->out[fid] = syexp(call->expression.node.context, (ast_expression*)call); - if (fun->expression.vtype != TYPE_FUNCTION) { - parseerror(parser, "not a function (%s)", type_name[fun->expression.vtype]); + if (fun->vtype != TYPE_FUNCTION) { + parseerror(parser, "not a function (%s)", type_name[fun->vtype]); return false; } - if (!fun->expression.next) { + if (!fun->next) { parseerror(parser, "could not determine function return type"); return false; } else { ast_value *fval = (ast_istype(fun, ast_value) ? ((ast_value*)fun) : NULL); - if (fun->expression.flags & AST_FLAG_DEPRECATED) { + if (fun->flags & AST_FLAG_DEPRECATED) { if (!fval) { return !parsewarning(parser, WARN_DEPRECATED, "call to function (which is marked deprecated)\n", @@ -1614,22 +1614,22 @@ static bool parser_close_call(parser_t *parser, shunt *sy) ast_ctx(fun).line); } - if (vec_size(fun->expression.params) != paramcount && - !((fun->expression.flags & AST_FLAG_VARIADIC) && - vec_size(fun->expression.params) < paramcount)) + if (vec_size(fun->params) != paramcount && + !((fun->flags & AST_FLAG_VARIADIC) && + vec_size(fun->params) < paramcount)) { - const char *fewmany = (vec_size(fun->expression.params) > paramcount) ? "few" : "many"; + const char *fewmany = (vec_size(fun->params) > paramcount) ? "few" : "many"; if (fval) return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, "too %s parameters for call to %s: expected %i, got %i\n" " -> `%s` has been declared here: %s:%i", - fewmany, fval->name, (int)vec_size(fun->expression.params), (int)paramcount, + fewmany, fval->name, (int)vec_size(fun->params), (int)paramcount, fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line); else return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, "too %s parameters for function call: expected %i, got %i\n" " -> it has been declared here: %s:%i", - fewmany, (int)vec_size(fun->expression.params), (int)paramcount, + fewmany, (int)vec_size(fun->params), (int)paramcount, ast_ctx(fun).file, (int)ast_ctx(fun).line); } } @@ -1883,7 +1883,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) /* When adding more intrinsics, fix the above condition */ prev = NULL; } - if (prev && prev->expression.vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1]) + if (prev && prev->vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1]) { var = (ast_expression*)parser->const_vec[ctoken[0]-'x']; } else { @@ -2229,8 +2229,8 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma } parser->lex->flags.noops = true; - if (!vec_size(sy.out)) { - parseerror(parser, "empty expression"); + if (vec_size(sy.out) != 1) { + parseerror(parser, "expression with not 1 but %lu output values...", (unsigned long) vec_size(sy.out)); expr = NULL; } else expr = sy.out[0].out; @@ -2365,13 +2365,13 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond, ast_unary *unary; ast_expression *prev; - if (cond->expression.vtype == TYPE_VOID || cond->expression.vtype >= TYPE_VARIANT) { + if (cond->vtype == TYPE_VOID || cond->vtype >= TYPE_VARIANT) { char ty[1024]; ast_type_to_string(cond, ty, sizeof(ty)); compile_error(ast_ctx(cond), "invalid type for if() condition: %s", ty); } - if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->expression.vtype == TYPE_STRING) + if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->vtype == TYPE_STRING) { prev = cond; cond = (ast_expression*)ast_unary_new(ast_ctx(cond), INSTR_NOT_S, cond); @@ -2382,7 +2382,7 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond, } ifnot = !ifnot; } - else if (OPTS_FLAG(CORRECT_LOGIC) && cond->expression.vtype == TYPE_VECTOR) + else if (OPTS_FLAG(CORRECT_LOGIC) && cond->vtype == TYPE_VECTOR) { /* vector types need to be cast to true booleans */ ast_binary *bin = (ast_binary*)cond; @@ -2455,17 +2455,17 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) /* closing paren */ if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'if' condition"); - ast_delete(cond); + ast_unref(cond); return false; } /* parse into the 'then' branch */ if (!parser_next(parser)) { parseerror(parser, "expected statement for on-true branch of 'if'"); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &ontrue)) { - ast_delete(cond); + ast_unref(cond); return false; } if (!ontrue) @@ -2476,12 +2476,12 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) if (!parser_next(parser)) { parseerror(parser, "expected on-false branch after 'else'"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &onfalse)) { ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } } @@ -2578,23 +2578,23 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression ** /* closing paren */ if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'while' condition"); - ast_delete(cond); + ast_unref(cond); return false; } /* parse into the 'then' branch */ if (!parser_next(parser)) { parseerror(parser, "expected while-loop body"); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &ontrue)) { - ast_delete(cond); + ast_unref(cond); return false; } cond = process_condition(parser, cond, &ifnot); if (!cond) { - ast_delete(ontrue); + ast_unref(ontrue); return false; } aloop = ast_loop_new(ctx, NULL, cond, ifnot, NULL, false, NULL, ontrue); @@ -2694,21 +2694,21 @@ static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'while' condition"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } /* parse on */ if (!parser_next(parser) || parser->tok != ';') { parseerror(parser, "expected semicolon after condition"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } if (!parser_next(parser)) { parseerror(parser, "parse error"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } @@ -2781,7 +2781,6 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou ast_expression *initexpr, *cond, *increment, *ontrue; ast_value *typevar; - bool retval = true; bool ifnot = false; lex_ctx ctx = parser_ctx(parser); @@ -2881,21 +2880,25 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou aloop = ast_loop_new(ctx, initexpr, cond, ifnot, NULL, false, increment, ontrue); *out = (ast_expression*)aloop; - if (!parser_leaveblock(parser)) - retval = false; - return retval; + if (!parser_leaveblock(parser)) { + ast_delete(aloop); + return false; + } + return true; onerr: - if (initexpr) ast_delete(initexpr); - if (cond) ast_delete(cond); - if (increment) ast_delete(increment); + if (initexpr) ast_unref(initexpr); + if (cond) ast_unref(cond); + if (increment) ast_unref(increment); (void)!parser_leaveblock(parser); return false; } static bool parse_return(parser_t *parser, ast_block *block, ast_expression **out) { - ast_expression *exp = NULL; - ast_return *ret = NULL; + ast_expression *exp = NULL; + ast_expression *var = NULL; + ast_return *ret = NULL; + ast_value *retval = parser->function->return_value; ast_value *expected = parser->function->vtype; lex_ctx ctx = parser_ctx(parser); @@ -2907,29 +2910,87 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou return false; } + /* return assignments */ + if (parser->tok == '=') { + if (!OPTS_FLAG(RETURN_ASSIGNMENTS)) { + parseerror(parser, "return assignments not activated, try using -freturn-assigments"); + return false; + } + + if (type_store_instr[expected->expression.next->vtype] == VINSTR_END) { + char ty1[1024]; + ast_type_to_string(expected->expression.next, ty1, sizeof(ty1)); + parseerror(parser, "invalid return type: `%s'", ty1); + return false; + } + + if (!parser_next(parser)) { + parseerror(parser, "expected return assignment expression"); + return false; + } + + if (!(exp = parse_expression_leave(parser, false, false, false))) + return false; + + /* prepare the return value */ + if (!retval) { + retval = ast_value_new(ctx, "#LOCAL_RETURN", TYPE_VOID); + ast_type_adopt(retval, expected->expression.next); + parser->function->return_value = retval; + } + + if (!ast_compare_type(exp, (ast_expression*)retval)) { + char ty1[1024], ty2[1024]; + ast_type_to_string(exp, ty1, sizeof(ty1)); + ast_type_to_string(&retval->expression, ty2, sizeof(ty2)); + parseerror(parser, "invalid type for return value: `%s', expected `%s'", ty1, ty2); + } + + /* store to 'return' local variable */ + var = (ast_expression*)ast_store_new( + ctx, + type_store_instr[expected->expression.next->vtype], + (ast_expression*)retval, exp); + + if (!var) { + ast_unref(exp); + return false; + } + + if (parser->tok != ';') + parseerror(parser, "missing semicolon after return assignment"); + else if (!parser_next(parser)) + parseerror(parser, "parse error after return assignment"); + + *out = var; + return true; + } + if (parser->tok != ';') { exp = parse_expression(parser, false, false); if (!exp) return false; - if (exp->expression.vtype != TYPE_NIL && - exp->expression.vtype != expected->expression.next->expression.vtype) + if (exp->vtype != TYPE_NIL && + exp->vtype != ((ast_expression*)expected)->next->vtype) { parseerror(parser, "return with invalid expression"); } ret = ast_return_new(ctx, exp); if (!ret) { - ast_delete(exp); + ast_unref(exp); return false; } } else { if (!parser_next(parser)) parseerror(parser, "parse error"); - if (expected->expression.next->expression.vtype != TYPE_VOID) { + + if (!retval && expected->expression.next->vtype != TYPE_VOID) + { (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); } - ret = ast_return_new(ctx, NULL); + ret = ast_return_new(ctx, (ast_expression*)retval); } *out = (ast_expression*)ret; return true; @@ -3677,7 +3738,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } return parse_typedef(parser); } - parseerror(parser, "Unexpected keyword"); + parseerror(parser, "Unexpected keyword: `%s'", parser_tokval(parser)); return false; } else if (parser->tok == '{') @@ -4068,9 +4129,9 @@ static bool parse_function_body(parser_t *parser, ast_value *var) /* qc allows the use of not-yet-declared functions here * - this automatically creates a prototype */ ast_value *thinkfunc; - ast_expression *functype = fld_think->expression.next; + ast_expression *functype = fld_think->next; - thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->expression.vtype); + thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->vtype); if (!thinkfunc) { /* || !ast_type_adopt(thinkfunc, functype)*/ ast_unref(framenum); parseerror(parser, "failed to create implicit prototype for `%s`", parser_tokval(parser)); @@ -4225,7 +4286,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) if (param->expression.vtype != TYPE_VECTOR && (param->expression.vtype != TYPE_FIELD || - param->expression.next->expression.vtype != TYPE_VECTOR)) + param->expression.next->vtype != TYPE_VECTOR)) { continue; } @@ -4277,6 +4338,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } vec_push(func->blocks, block); + parser->function = old; if (!parser_leaveblock(parser)) @@ -4355,7 +4417,7 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast ast_store *st; int assignop = type_store_instr[value->expression.vtype]; - if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) + if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STORE_V; subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); @@ -4421,7 +4483,7 @@ static ast_expression *array_field_setter_node( ast_store *st; int assignop = type_storep_instr[value->expression.vtype]; - if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) + if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STOREP_V; subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); @@ -5272,7 +5334,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield { /* deal with other globals */ old = parser_find_global(parser, var->name); - if (old && var->expression.vtype == TYPE_FUNCTION && old->expression.vtype == TYPE_FUNCTION) + if (old && var->expression.vtype == TYPE_FUNCTION && old->vtype == TYPE_FUNCTION) { /* This is a function which had a prototype */ if (!ast_istype(old, ast_value)) { @@ -5380,7 +5442,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield if (var->expression.vtype == TYPE_VECTOR) isvector = true; else if (var->expression.vtype == TYPE_FIELD && - var->expression.next->expression.vtype == TYPE_VECTOR) + var->expression.next->vtype == TYPE_VECTOR) isvector = true; if (isvector) { @@ -5419,7 +5481,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield return false; } - if (var->expression.vtype != find->expression.vtype) { + if (var->expression.vtype != find->vtype) { char ty1[1024]; char ty2[1024]; @@ -5568,7 +5630,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } else if (!localblock && !nofields && var->expression.vtype == TYPE_FIELD && - var->expression.next->expression.vtype == TYPE_ARRAY) + var->expression.next->vtype == TYPE_ARRAY) { char name[1024]; ast_expression *telem; @@ -5625,7 +5687,7 @@ skipvar: } } - if (parser->tok != '{') { + if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) { if (parser->tok != '=') { parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); break; @@ -5727,7 +5789,22 @@ skipvar: break; } } - else if (parser->tok == '{' || parser->tok == '[') + else if (var->expression.vtype == TYPE_ARRAY && parser->tok == '{') + { + if (localblock) { + /* Note that fteqcc and most others don't even *have* + * local arrays, so this is not a high priority. + */ + parseerror(parser, "TODO: initializers for local arrays"); + break; + } + /* +static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels); +*/ + parseerror(parser, "TODO: initializing global arrays is not supported yet!"); + break; + } + else if (var->expression.vtype == TYPE_FUNCTION && (parser->tok == '{' || parser->tok == '[')) { if (localblock) { parseerror(parser, "cannot declare functions within functions"); @@ -5800,6 +5877,7 @@ skipvar: } vec_free(sy.out); vec_free(sy.ops); + vec_free(sy.argc); var->cvq = cvq; } } @@ -5970,7 +6048,7 @@ static void generate_checksum(parser_t *parser) if (!ast_istype(parser->fields[i], ast_value)) continue; value = (ast_value*)(parser->fields[i]); - switch (value->expression.next->expression.vtype) { + switch (value->expression.next->vtype) { case TYPE_FLOAT: crc = progdefs_crc_both(crc, "\tfloat\t"); break; case TYPE_VECTOR: crc = progdefs_crc_both(crc, "\tvec3_t\t"); break; case TYPE_STRING: crc = progdefs_crc_both(crc, "\tstring_t\t"); break; @@ -6003,7 +6081,6 @@ parser_t *parser_create() mem_d(parser); return NULL; } - for (i = 0; i < operator_count; ++i) { if (operators[i].id == opid1('=')) { @@ -6056,7 +6133,7 @@ parser_t *parser_create() return parser; } -bool parser_compile(parser_t *parser) +static bool parser_compile(parser_t *parser) { /* initial lexer/parser state */ parser->lex->flags.noops = true; @@ -6182,6 +6259,8 @@ void parser_cleanup(parser_t *parser) intrin_intrinsics_destroy(parser); + code_cleanup(parser->code); + mem_d(parser); } @@ -6220,11 +6299,11 @@ bool parser_finish(parser_t *parser, const char *output) ast_expression *subtype; field->hasvalue = true; subtype = field->expression.next; - ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype); - if (subtype->expression.vtype == TYPE_FIELD) - ifld->fieldtype = subtype->expression.next->expression.vtype; - else if (subtype->expression.vtype == TYPE_FUNCTION) - ifld->outtype = subtype->expression.next->expression.vtype; + ifld = ir_builder_create_field(ir, field->name, subtype->vtype); + if (subtype->vtype == TYPE_FIELD) + ifld->fieldtype = subtype->next->vtype; + else if (subtype->vtype == TYPE_FUNCTION) + ifld->outtype = subtype->next->vtype; (void)!ir_value_set_field(field->ir_v, ifld); } } @@ -6312,7 +6391,7 @@ bool parser_finish(parser_t *parser, const char *output) } for (i = 0; i < vec_size(parser->fields); ++i) { ast_value *asvalue; - asvalue = (ast_value*)(parser->fields[i]->expression.next); + asvalue = (ast_value*)(parser->fields[i]->next); if (!ast_istype((ast_expression*)asvalue, ast_value)) continue; diff --git a/test.c b/test.c index 7722af2..6682983 100644 --- a/test.c +++ b/test.c @@ -60,7 +60,7 @@ typedef struct { int pid; } popen_t; -FILE ** task_popen(const char *command, const char *mode) { +static FILE ** task_popen(const char *command, const char *mode) { int inhandle [2]; int outhandle [2]; int errhandle [2]; @@ -137,7 +137,7 @@ task_popen_error_0: return NULL; } -int task_pclose(FILE **handles) { +static int task_pclose(FILE **handles) { popen_t *data = (popen_t*)handles; int status = 0; @@ -158,7 +158,7 @@ int task_pclose(FILE **handles) { char name_out[L_tmpnam]; } popen_t; - FILE **task_popen(const char *command, const char *mode) { + static FILE **task_popen(const char *command, const char *mode) { char *cmd = NULL; popen_t *open = (popen_t*)mem_a(sizeof(popen_t)); @@ -179,7 +179,7 @@ int task_pclose(FILE **handles) { return open->handles; } - void task_pclose(FILE **files) { + static void task_pclose(FILE **files) { popen_t *open = ((popen_t*)files); fs_file_close(files[1]); fs_file_close(files[2]); @@ -281,7 +281,7 @@ typedef struct { * This is very much like a compiler code generator :-). This generates * a value from some data observed from the compiler. */ -bool task_template_generate(task_template_t *tmpl, char tag, const char *file, size_t line, char *value, size_t *pad) { +static bool task_template_generate(task_template_t *tmpl, char tag, const char *file, size_t line, char *value, size_t *pad) { size_t desclen = 0; size_t filelen = 0; char **destval = NULL; @@ -297,7 +297,7 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s case 'I': destval = &tmpl->sourcefile; break; case 'F': destval = &tmpl->testflags; break; default: - con_printmsg(LVL_ERROR, __FILE__, __LINE__, "internal error", + con_printmsg(LVL_ERROR, __FILE__, __LINE__, 0, "internal error", "invalid tag `%c:` during code generation\n", tag ); @@ -309,7 +309,7 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s * assigned value. */ if (*destval) { - con_printmsg(LVL_ERROR, file, line, "compile error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "compile error", "tag `%c:` already assigned value: %s\n", tag, *destval ); @@ -354,7 +354,7 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s return true; } -bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size_t *pad) { +static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size_t *pad) { char *data = NULL; char *back = NULL; size_t size = 0; @@ -377,7 +377,7 @@ bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size */ case '/': if (data[1] != '/') { - con_printmsg(LVL_ERROR, file, line, "tmpl parse error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error", "invalid character `/`, perhaps you meant `//` ?"); mem_d(back); @@ -407,14 +407,14 @@ bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size case 'I': case 'F': if (data[1] != ':') { - con_printmsg(LVL_ERROR, file, line, "tmpl parse error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error", "expected `:` after `%c`", *data ); goto failure; } if (!task_template_generate(tmpl, *data, file, line, &data[3], pad)) { - con_printmsg(LVL_ERROR, file, line, "tmpl compile error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl compile error", "failed to generate for given task\n" ); goto failure; @@ -429,7 +429,7 @@ bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size { char *value = &data[3]; if (data[1] != ':') { - con_printmsg(LVL_ERROR, file, line, "tmpl parse error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error", "expected `:` after `%c`", *data ); @@ -454,7 +454,7 @@ bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size } default: - con_printmsg(LVL_ERROR, file, line, "tmpl parse error", + con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error", "invalid tag `%c`", *data ); goto failure; @@ -480,7 +480,7 @@ failure: * Nullifies the template data: used during initialization of a new * template and free. */ -void task_template_nullify(task_template_t *tmpl) { +static void task_template_nullify(task_template_t *tmpl) { if (!tmpl) return; @@ -495,7 +495,7 @@ void task_template_nullify(task_template_t *tmpl) { tmpl->testflags = NULL; } -task_template_t *task_template_compile(const char *file, const char *dir, size_t *pad) { +static task_template_t *task_template_compile(const char *file, const char *dir, size_t *pad) { /* a page should be enough */ char fullfile[4096]; size_t filepadd = 0; @@ -609,7 +609,7 @@ failure: return NULL; } -void task_template_destroy(task_template_t **tmpl) { +static void task_template_destroy(task_template_t **tmpl) { if (!tmpl) return; @@ -660,7 +660,7 @@ static task_t *task_tasks = NULL; * Read a directory and searches for all template files in it * which is later used to run all tests. */ -bool task_propagate(const char *curdir, size_t *pad, const char *defs) { +static bool task_propagate(const char *curdir, size_t *pad, const char *defs) { bool success = true; DIR *dir; struct dirent *files; @@ -840,7 +840,7 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) { * Task precleanup removes any existing temporary files or log files * left behind from a previous invoke of the test-suite. */ -void task_precleanup(const char *curdir) { +static void task_precleanup(const char *curdir) { DIR *dir; struct dirent *files; char buffer[4096]; @@ -863,7 +863,7 @@ void task_precleanup(const char *curdir) { fs_dir_close(dir); } -void task_destroy(void) { +static void task_destroy(void) { /* * Free all the data in the task list and finally the list itself * then proceed to cleanup anything else outside the program like @@ -912,7 +912,7 @@ void task_destroy(void) { * messages IF the procedure type is -execute, otherwise it matches * the preprocessor output. */ -bool task_trymatch(task_template_t *tmpl, char ***line) { +static bool task_trymatch(task_template_t *tmpl, char ***line) { bool success = true; bool preprocessing = false; FILE *execute; @@ -1020,7 +1020,7 @@ bool task_trymatch(task_template_t *tmpl, char ***line) { return success; } -const char *task_type(task_template_t *tmpl) { +static const char *task_type(task_template_t *tmpl) { if (!strcmp(tmpl->proceduretype, "-pp")) return "type: preprocessor"; if (!strcmp(tmpl->proceduretype, "-execute")) @@ -1037,7 +1037,7 @@ const char *task_type(task_template_t *tmpl) { * from thin air and executed INLINE. */ #include -void task_schedualize(size_t *pad) { +static void task_schedualize(size_t *pad) { char space[2][64]; bool execute = false; char *data = NULL; @@ -1210,7 +1210,7 @@ void task_schedualize(size_t *pad) { * * It expects con_init() was called before hand. */ -GMQCC_WARN bool test_perform(const char *curdir, const char *defs) { +static GMQCC_WARN bool test_perform(const char *curdir, const char *defs) { static const char *default_defs = "defs.qh"; size_t pad[] = { diff --git a/tests/rassign.qc b/tests/rassign.qc new file mode 100644 index 0000000..5c72e6f --- /dev/null +++ b/tests/rassign.qc @@ -0,0 +1,35 @@ +float f_float() { + return = 100.0f; + return = 200.0f; + return; +} + +vector f_vector() { + vector foo; + foo.x = f_float(); + foo.y = f_float(); + foo.z = f_float(); + + return = foo; + return; +} + +string f_string() { +#ifndef FAIL_TEST + return = "hello"; + return = "world"; +#endif + return; +} + +float factorial(float n) { + if (n == 0) return = 1; + else return = n * factorial(n - 1); +} + +void main() { + print(ftos(f_float()), "\n"); // 200.0f + print(vtos(f_vector()), "\n"); // '1 2 3' + print(f_string(), "\n"); // world + print(ftos(factorial(4)), "\n"); // 24 +} diff --git a/tests/rassign.tmpl b/tests/rassign.tmpl new file mode 100644 index 0000000..948cb54 --- /dev/null +++ b/tests/rassign.tmpl @@ -0,0 +1,8 @@ +I: rassign.qc +D: test return assignments +T: -execute +C: -fftepp -freturn-assignments +M: 200 +M: '200 200 200' +M: world +M: 24 diff --git a/util.c b/util.c index c8d50f5..d695ae6 100644 --- a/util.c +++ b/util.c @@ -491,7 +491,7 @@ GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) { return (size_t) (hash % ht->size); } -hash_node_t *_util_htnewpair(const char *key, void *value) { +static hash_node_t *_util_htnewpair(const char *key, void *value) { hash_node_t *node; if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t)))) return NULL;