]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'master' into cooking
authorWolfgang Bumiller <wry.git@bumiller.com>
Sat, 1 Jun 2013 16:16:56 +0000 (18:16 +0200)
committerWolfgang Bumiller <wry.git@bumiller.com>
Sat, 1 Jun 2013 16:16:56 +0000 (18:16 +0200)
26 files changed:
.gitignore
Makefile
ast.c
ast.h
code.c
conout.c
distro/deb/Makefile
doc/gmqcc.1
doc/gmqpak.1 [new file with mode: 0644]
exec.c
ftepp.c
gmqcc.h
intrin.h
ir.c
ir.h
lexer.c
lexer.h
main.c
opts.c
opts.def
pak.c
parser.c
test.c
tests/rassign.qc [new file with mode: 0644]
tests/rassign.tmpl [new file with mode: 0644]
util.c

index 416e445e16c72e2818595e75a99fbf375fc67bed..0405639aa93c6abbdc8072a2684234e45cb22903 100644 (file)
@@ -12,3 +12,8 @@ distro/archbsd/*
 !distro/archbsd/release/PKGBUILD
 !distro/archbsd/git/PKGBUILD
 !distro/archlinux/this/Makefile
+
+gmqcc
+gmqpak
+qcvm
+testsuite
index 35b825a1f917a9d0a74898471f54c2a4d2db1d54..fea33566c7340c90010e19ca4e7ffc0dbaf68e13 100644 (file)
--- 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 3e5d304d1e53c6ba9666f56ddfd6aafdc4bc94c8..81e1c121231e16bbb9bdde2c92cf72ec642fda1b 100644 (file)
--- a/ast.c
+++ b/ast.c
         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, &param))
             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 bae07db39ec85c13481a10ecec947ece7f0c7ce8..a0fa14defca70bfadeeee0224bf5936d6f6249b4 100644 (file)
--- 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 b0ce2baa04aa138b24a81004257414b7ad81a3cc..35f758a22526f966cc00c7a28c45c74c0ee0d43a 100644 (file)
--- a/code.c
+++ b/code.c
  */
 #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;
 }
index dd4dca399dac9bc659c0f67a9e5c5a6f9d547975..687fdf499a9e590af16c6c90a4006187b3ca5b4f 100644 (file)
--- 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);
 }
index df23602b592b94a07c7ef47d0792b030dad86e0b..7594400300c9482bab11df2ae93b5509683a4114 100644 (file)
@@ -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)
index 60257dc444b9645fe100f213d000f2ca3412437e..6ede944f1ffb68be44140899140e0ae7ba1e8439 100644 (file)
@@ -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 (file)
index 0000000..967d432
--- /dev/null
@@ -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 <http://graphitemaster.github.com/gmqcc>.
+.Sh BUGS
+Please report bugs on <http://github.com/graphitemaster/gmqcc/issues>,
+or see <http://graphitemaster.github.com/gmqcc> on how to contact us.
diff --git a/exec.c b/exec.c
index 0ef32119a0a475a3c9446b314c423ea2f2152622..49cff447a223df7b8f24b55ad9c7ba1103f3f90e 100644 (file)
--- 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*)"<<<invalid string>>>";
+        return  "<<<invalid string>>>";
+        
     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("<illegal instruction %d>\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 <s>   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 595b520fec5439f34a1614f737f9f83f7ef3c150..5348dfb5448ba923d95de60cf7e8829df71f24fd 100644 (file)
--- 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 0031227457eded092b0b4d25d7e5793b5d45d464..a92e109f716b10ffb3450bc189a8aba4f8785a27 100644 (file)
--- 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))
index 4f672dd9c04e349d68cad54e7fd42e5a449352aa..81af620c18a7f8e4966a94e0c8c3dad33ce88340 100644 (file)
--- 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 82dcb9befaf578f2c6d671a41ef88ac7fe6c3644..5dae734462fe6b7513f60588ebce6439383fd778 100644 (file)
--- 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 "<INVALID>";
     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 dac16a39b4d492f22bbd5f59c3738d6cf243b1a4..cd382957f022c34d82a0bdd2f1603bf1aa1ef7d9 100644 (file)
--- 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
  * <outtype>%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 7722f4f5795f02ee6c355aa6ea1b172c89948440..862131e1162ecb764acdd3ae7e72d569b65f0e95 100644 (file)
--- 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 : "<string-source>");
-    lex->line = 1; /* we start counting at 1 */
-
+    lex->name    = util_strdup(name ? name : "<string-source>");
+    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 24ac39a63f7f574d1e9a8a7dfc1f8236cc51612a..cde0863e80877952a7dd8f518bed167ed0355780 100644 (file)
--- 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 bbc685a05fdb69bb2b8e7d31071e7d620468df58..840a6a730fe83065b663ef92875cdb1948ba8fc9 100644 (file)
--- 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 77aa9c06e02c07fad5916386470f98fab7ad0683..abd012fa6a160d12ad4db4aea7fb306ae38b2632 100644 (file)
--- 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);
     }
 
index a9301a593998f5b7a99cdd857d279e39ec9ca5d4..520f9b95cb6f0d33872cd756f865d3a805e15168 100644 (file)
--- 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 653a4630a133905d62c99845c9902e15dddf3566..9ff7e78f598bf88d307188856fb3c9186e4b48eb 100644 (file)
--- 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;
 }
index 1b9e7c71a018039a8ad632d8046856bc308ba24b..7d9ac6a353155724928a29a70b10c4e25f27cca9 100644 (file)
--- 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 7722af26a4a5caae39c636fcfc6ee78be72e40e4..6682983a30e997278cd1745b585480a128bc916d 100644 (file)
--- 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 <math.h>
-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 (file)
index 0000000..5c72e6f
--- /dev/null
@@ -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 (file)
index 0000000..948cb54
--- /dev/null
@@ -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 c8d50f5b5fbc15fbff326efbaa45a40f4f734d49..d695ae62f451e2de25f79c029877294cf17c6599 100644 (file)
--- 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;