Merge branch 'cooking'
authorDale Weiler <killfieldengine@gmail.com>
Thu, 6 Jun 2013 06:20:58 +0000 (06:20 +0000)
committerDale Weiler <killfieldengine@gmail.com>
Thu, 6 Jun 2013 06:20:58 +0000 (06:20 +0000)
Conflicts:
.gitignore

34 files changed:
.gitignore
AUTHORS
CHANGES
Makefile
ast.c
ast.h
code.c
conout.c
correct.c
distro/deb/Makefile
distro/gentoo/INSTALL [new file with mode: 0644]
distro/gentoo/gmqcc-0.3.0.ebuild [new file with mode: 0644]
distro/slackware/this/Makefile [new file with mode: 0644]
distro/slackware/this/slack-desc [new file with mode: 0644]
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
stat.c [new file with mode: 0644]
test.c
tests/rassign.qc [new file with mode: 0644]
tests/rassign.tmpl [new file with mode: 0644]
util.c

index 0e0593c..0405639 100644 (file)
@@ -17,4 +17,3 @@ gmqcc
 gmqpak
 qcvm
 testsuite
-pak
diff --git a/AUTHORS b/AUTHORS
index 472760f..16255d2 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,6 +1,6 @@
 Authors:
-    Dale Weiler       - Charismatic Visionary / Programmer
-    Wolfgang Bumiller - Main Programmer
+    Dale `graphitemaster` Weiler   - Charismatic Visionary / Programmer
+    Wolfgang `Blub\w` Bumiller     - Main Programmer
 
 Thanks to:
     Forest `LordHavoc` Hale        - Technical support and assistance
diff --git a/CHANGES b/CHANGES
index 01af3ff..b7499a1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,25 @@
 Release v0.3.0
-    * to fill
+    * Language:
+        - Return assignments, the ability to assign to the return keyword
+          as if it were a local variable.
+    * Compilation:
+        - Optimized memory usage (now uses on average %3 less memory for
+          compilation).
+        - Fixed dotranslate (translatable strings)
+    * QCVM:
+        - Escape strings for -printdefs
+    * Commandline:
+        - Added statistic dumps, gives information about the number of used
+          hashtables, vectors, and number of unique sizes of vectors and
+          hashtables. The amount of memory used for vectors. As well as the
+          number of strdups used in total for compilation.
+    * Testsuite:
+        - Fixed a floating point exception rasied by modulo operation in
+          -memchk.
+    * Build:
+        - Added gentoo ebuilds.
+        - Added win32 Makefile for building win32 packages.
+        - Added slackware pkg build files
 
 2012-04-27 v0.2.9
     * Preprocessor:
@@ -56,12 +76,12 @@ Release v0.3.0
         - Added defs.qh (auto included) for qcvm definitions
     * Syntax Highlighting:
         - Added various syntax highlighting description files for
-        various text editors / integrated development envirorments,
-        including support for: geany, kate, kwrite, kdevelop, QtCreator,
-        gtksourceview, gedit, sany, nano, jedit
+          various text editors / integrated development envirorments,
+          including support for: geany, kate, kwrite, kdevelop, QtCreator,
+          gtksourceview, gedit, sany, nano, jedit
     * Build:
         - Build scripts for building debian, archlinux and archbsd
-        packages for x86, and x86_64.
+          packages for x86, and x86_64.
         - Makefile targets for gource visualization, and render of
           gource visualization.
 
index 35b825a..2e5c1ee 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -29,12 +29,13 @@ ifeq ($(CC), clang)
            -Wno-conversion                    \
            -Wno-missing-prototypes            \
            -Wno-float-equal                   \
-           -Wno-unknown-warning-option
+           -Wno-unknown-warning-option        \
+           -Wstrict-prototypes
 else
        #Tiny C Compiler doesn't know what -pedantic-errors is
        # and instead of ignoring .. just errors.
        ifneq ($(CC), tcc)
-               CFLAGS += -pedantic-errors
+               CFLAGS += -Wstrict-prototypes -pedantic-errors
        else
                CFLAGS += -Wno-pointer-sign -fno-common
        endif
@@ -44,11 +45,17 @@ ifeq ($(track), no)
        CFLAGS += -DNOTRACK
 endif
 
-OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o
-OBJ_P = util.o fs.o conout.o opts.o pak.o
-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
+OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o stat.o
+OBJ_P = util.o fs.o conout.o opts.o pak.o stat.o
+OBJ_T = test.o util.o conout.o fs.o stat.o
+OBJ_C = main.o lexer.o parser.o fs.o stat.o
+OBJ_X = exec-standalone.o util.o conout.o fs.o stat.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
@@ -72,12 +79,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 +136,6 @@ SPLINTFLAGS =            \
     -onlytrans           \
     -predboolint         \
     -boolops             \
-    -exportlocal         \
     -incondefs           \
     -macroredef          \
     -retvalint           \
@@ -142,7 +148,6 @@ SPLINTFLAGS =            \
     -temptrans           \
     -usereleased         \
     -warnposix           \
-    -shiftimplementation \
     +charindex           \
     -kepttrans           \
     -unqualifiedtrans    \
@@ -156,8 +161,6 @@ SPLINTFLAGS =            \
     -mayaliasunique      \
     -realcompare         \
     -observertrans       \
-    -shiftnegative       \
-    -freshtrans          \
     -abstract            \
     -statictrans         \
     -castfcnptr
@@ -203,34 +206,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 +245,9 @@ opts.o: gmqcc.h opts.def
 fs.o: gmqcc.h opts.def
 utf8.o: gmqcc.h opts.def
 correct.o: gmqcc.h opts.def
-
+stat.o: gmqcc.h opts.def
+pak.o: gmqcc.h opts.def
 test.o: gmqcc.h opts.def
-util.o: gmqcc.h opts.def
-conout.o: gmqcc.h opts.def
-fs.o: gmqcc.h opts.def
-
 main.o: gmqcc.h opts.def lexer.h
 lexer.o: gmqcc.h opts.def lexer.h
 parser.o: gmqcc.h opts.def lexer.h ast.h ir.h intrin.h
-fs.o: gmqcc.h opts.def
-
-util.o: gmqcc.h opts.def
-conout.o: gmqcc.h opts.def
-fs.o: gmqcc.h opts.def
-
-util.o: gmqcc.h opts.def
-fs.o: gmqcc.h opts.def
-conout.o: gmqcc.h opts.def
-opts.o: gmqcc.h opts.def
-pak.o: gmqcc.h opts.def
diff --git a/ast.c b/ast.c
index 3e5d304..d845eb2 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -21,7 +21,6 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
         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 +84,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 +103,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 +136,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 +156,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 +176,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 +195,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 +220,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 +263,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 +307,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 +339,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 +354,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 +400,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 +459,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 +553,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 +597,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 +607,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 +656,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 +671,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 +745,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 +882,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 +915,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 +928,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 +958,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 +973,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 +1042,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 +1100,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 +1133,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 +1172,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 +1218,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 +1240,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 +1258,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 +1297,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 +1313,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 +1421,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 +1443,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 +1590,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 +1607,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 +1627,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 +1678,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 +1752,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 +1816,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 +1831,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 +1889,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 +1912,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 +1975,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 +2030,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 +2073,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 +2112,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 +2148,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 +2183,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 +2235,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 +2294,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 +2316,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 +2325,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 +2366,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 +2384,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 +2404,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 +2473,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 +2488,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 +2505,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 +2602,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 +2626,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 +2680,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 +2697,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 +2711,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 +2860,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 +2893,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 +2921,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 +2966,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 +3091,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 +3105,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 +3117,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 +3129,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value
 
     callinstr = ir_block_create_call(func->curblock, ast_ctx(self),
                                      ast_function_label(func, "call"),
-                                     funval, !!(self->func->expression.flags & AST_FLAG_NORETURN));
+                                     funval, !!(self->func->flags & AST_FLAG_NORETURN));
     if (!callinstr)
         goto error;
 
diff --git a/ast.h b/ast.h
index bae07db..a0fa14d 100644 (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 b0ce2ba..c2838ef 100644 (file)
--- a/code.c
+++ b/code.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include <string.h>
 #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 +88,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 +104,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 +128,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 +159,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 +283,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 +302,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 +368,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 +383,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 dd4dca3..13a242f 100644 (file)
--- a/conout.c
+++ b/conout.c
@@ -21,7 +21,6 @@
  * SOFTWARE.
  */
 #include "gmqcc.h"
-#include <stdio.h>
 
 /*
  * isatty/STDERR_FILENO/STDOUT_FILNO
@@ -198,7 +197,7 @@ static con_t console;
  * NOTE: This prevents colored output to piped stdout/err via isatty
  * checks.
  */
-static void con_enablecolor() {
+static void con_enablecolor(void) {
     if (console.handle_err == stderr || console.handle_err == stdout)
         console.color_err = !!(isatty(STDERR_FILENO));
     if (console.handle_out == stderr || console.handle_out == stdout)
@@ -333,7 +332,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 +346,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 +357,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 +431,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 7e16608..f501817 100644 (file)
--- a/correct.c
+++ b/correct.c
@@ -21,6 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include <string.h>
 #include "gmqcc.h"
 
 /*
index df23602..7594400 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)
diff --git a/distro/gentoo/INSTALL b/distro/gentoo/INSTALL
new file mode 100644 (file)
index 0000000..7a4f778
--- /dev/null
@@ -0,0 +1,35 @@
+To use the ebuilds provided in this gentoo directory you first must
+create a directory in your overlay tree.
+
+If you don't already have your own directory for custom ebuilds, you can
+create one. If you already have one, and that directory is set in your
+/etc/make.conf for PORTDIR_OVERLAY, this step can be skiped. Otherwise
+if you don't already, you can create one as such.
+
+# mkdir -p /usr/local/portage
+# vim /etc/make.conf
+       Set PORTDIR_OVERLAY=/usr/local/portage
+       Then save and exit
+
+Once that is completed, or you skiped that step, you need to create a
+directory in your overlay tree for gmqcc, this can be done as such:
+(subsitute [[PORTDIR_OVERLAY]] with the one set in /etc/make.conf)
+
+# mkdir -p [[PORTDIR_OVERLAY]]/gmqcc
+
+After the directory is created you need to move the correct version ebuild
+into that directory depending on which version of GMQCC you want. For
+instance, if you want gmqcc 0.3.0, you move gmqcc-0.3.0.ebuild into that
+directory.
+
+# mv gmqcc-{version}.ebuild [[PORTDIR_OVERLAY]]/gmqcc/
+
+After the file is moved into your newly created portage overlay tree, you'll
+need to build a digest for it with ebuild. A digest is simply a Manifest and
+digital signature for the source files used.
+
+# ebuild gmqcc-0.3.0.ebuild digest
+
+After the digest is built, you can emerge gmqcc as usual.
+
+# emerge gmqcc
diff --git a/distro/gentoo/gmqcc-0.3.0.ebuild b/distro/gentoo/gmqcc-0.3.0.ebuild
new file mode 100644 (file)
index 0000000..28630d3
--- /dev/null
@@ -0,0 +1,20 @@
+EAPI=5
+
+DESCRIPTION="An Improved Quake C Compiler"
+HOMEPAGE="http://graphitemaster.github.com/gmqcc/"
+SRC_URI="https://github.com/graphitemaster/${PN}/archive/${PV}.tar.gz -> ${P}.tar.gz"
+
+LICENSE="MIT"
+
+SLOT="0"
+IUSE=""
+KEYWORDS="~amd64 ~x86"
+
+src_prepare() {
+       sed -i -e "s:-Werror ::" Makefile || die
+}
+
+src_install() {
+       emake install PREFIX="${D}/usr"
+       dodoc README
+}
diff --git a/distro/slackware/this/Makefile b/distro/slackware/this/Makefile
new file mode 100644 (file)
index 0000000..3f70b8b
--- /dev/null
@@ -0,0 +1,35 @@
+BASEDIR := ../../../
+PREFIX  := /usr
+HEADER  := $(BASEDIR)/gmqcc.h
+MAJOR   := $(shell sed -n -e '/GMQCC_VERSION_MAJOR/{s/.* .* //;p;q;}' $(HEADER))
+MINOR   := $(shell sed -n -e '/GMQCC_VERSION_MINOR/{s/.* .* //;p;q;}' $(HEADER))
+PATCH   := $(shell sed -n -e '/GMQCC_VERSION_PATCH/{s/.* .* //;p;q;}' $(HEADER))
+CARCH   := $(shell uname -m)
+PKGDIR  := gmqcc-$(MAJOR).$(MINOR).$(PATCH)-$(CARCH)-git
+PKG     := $(PKGDIR).txz
+PKGINFO := $(PKGDIR)/.PKGINFO
+DESTDIR := distro/slackware/this/$(PKGDIR)
+CFLAGS  :=
+
+
+ifneq (, $(findstring i686, $(CARCH)))
+       CFLAGS += -m32
+       LDFLAGS += -m32
+endif
+
+base:
+       $(MAKE) -C $(BASEDIR) clean
+       CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" \
+         $(MAKE) -C $(BASEDIR) "DESTDIR=$(DESTDIR)" "PREFIX=$(PREFIX)" install
+       gzip -9 $(PKGDIR)/usr/share/man/man?/*.?
+       strip -s $(PKGDIR)/usr/bin/*
+       mkdir $(PKGDIR)/install
+       cp slack-desc $(PKGDIR)/install
+       @tar -cJvf $(PKG) -C $(PKGDIR)/ install/ usr/
+       @rm -rf $(PKGDIR)
+
+clean:
+       $(MAKE) -C $(BASEDIR) clean
+       @rm -f *.txz
+
+all: base
diff --git a/distro/slackware/this/slack-desc b/distro/slackware/this/slack-desc
new file mode 100644 (file)
index 0000000..3384ef9
--- /dev/null
@@ -0,0 +1,12 @@
+     |-----handy-ruler------------------------------------------------------|
+gmqcc: gmqcc (Quake C compiler)
+gmqcc:
+gmqcc: A modern written-from-scratch compiler for the QuakeC language with
+gmqcc: support for many common features found in other QC compilers.
+gmqcc: Additionally contains a standalone QCVM executor, and a tool to deal
+gmqcc: with .pak archive files.
+gmqcc:
+gmqcc:
+gmqcc: github page:
+gmqcc:   http://github.com/graphitemaster/gmqcc
+gmqcc:
index 60257dc..6ede944 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 0ef3211..6934a0c 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
+#include <stdlib.h>
 
 #include "gmqcc.h"
 
@@ -167,16 +168,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 +195,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 +204,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 +221,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 +240,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 +262,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 +295,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 +353,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 +450,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 +499,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 +531,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 +630,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 +646,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 +665,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 +675,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 +687,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 +699,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 +707,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 +715,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 +724,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 +735,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 +755,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 +780,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 +805,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);
@@ -855,7 +835,7 @@ static size_t qc_builtins_count = sizeof(qc_builtins) / sizeof(qc_builtins[0]);
 
 static const char *arg0 = NULL;
 
-static void version() {
+static void version(void) {
     printf("GMQCC-QCVM %d.%d.%d Built %s %s\n",
            GMQCC_VERSION_MAJOR,
            GMQCC_VERSION_MINOR,
@@ -865,8 +845,7 @@ static void version() {
     );
 }
 
-static void usage()
-{
+static void usage(void) {
     printf("usage: %s [options] [parameters] file\n", arg0);
     printf("options:\n");
     printf("  -h, --help         print this message\n"
@@ -886,8 +865,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 +901,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 +1141,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 +1165,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 +1244,7 @@ int main(int argc, char **argv)
     return 0;
 }
 
-void prog_disasm_function(qc_program *prog, size_t id)
-{
+void prog_disasm_function(qc_program *prog, size_t id) {
     prog_section_function *fdef = prog->functions + id;
     prog_section_statement *st;
 
diff --git a/ftepp.c b/ftepp.c
index 595b520..55d4fff 100644 (file)
--- a/ftepp.c
+++ b/ftepp.c
  * SOFTWARE.
  */
 #include <time.h>
+#include <string.h>
+#include <stdlib.h>
 #include <sys/stat.h>
+
 #include "gmqcc.h"
 #include "lexer.h"
 
@@ -81,7 +84,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 +107,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 +130,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 +144,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 +152,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 +161,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 +170,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 +178,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;
@@ -313,7 +316,7 @@ static void ppmacro_delete(ppmacro *self)
     mem_d(self);
 }
 
-static ftepp_t* ftepp_new()
+static ftepp_t* ftepp_new(void)
 {
     ftepp_t *ftepp;
 
@@ -374,7 +377,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 +567,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 +1884,7 @@ ftepp_t *ftepp_create()
 void ftepp_add_define(ftepp_t *ftepp, const char *source, const char *name)
 {
     ppmacro *macro;
-    lex_ctx ctx = { "__builtin__", 0 };
+    lex_ctx ctx = { "__builtin__", 0, 0 };
     ctx.file = source;
     macro = ppmacro_new(ctx, name);
     /*vec_push(ftepp->macros, macro);*/
diff --git a/gmqcc.h b/gmqcc.h
index 0031227..d6055db 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
  */
 #ifndef GMQCC_HDR
 #define GMQCC_HDR
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
 #include <stdarg.h>
-#include <stdio.h>
-#include <ctype.h>
+#include <stdio.h> /* TODO: remove this */
 
 /*
  * Disable some over protective warnings in visual studio because fixing them is a waste
@@ -288,20 +284,30 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #   include <dirent.h>
 #endif /*! _WIN32 && !defined(__MINGW32__) */
 
+/*===================================================================*/
+/*=========================== stat.c ================================*/
+/*===================================================================*/
+void  stat_info          (void);
+char *stat_mem_strdup    (const char *, size_t,         const char *, bool);
+void *stat_mem_reallocate(void *,       size_t, size_t, const char *);
+void  stat_mem_deallocate(void *);
+void *stat_mem_allocate  (size_t, size_t, const char *);
+
+#define mem_a(SIZE)              stat_mem_allocate  ((SIZE), __LINE__, __FILE__)
+#define mem_d(PTRN)              stat_mem_deallocate((void*)(PTRN))
+#define mem_r(PTRN, SIZE)        stat_mem_reallocate((void*)(PTRN), (SIZE), __LINE__, __FILE__)
+#define mem_af(SIZE, FILE, LINE) stat_mem_allocate  ((SIZE), (LINE), (FILE))
+
+/* TODO: rename to mem variations */
+#define util_strdup(SRC)         stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, false)
+#define util_strdupe(SRC)        stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, true)
 
 /*===================================================================*/
 /*=========================== util.c ================================*/
 /*===================================================================*/
-void *util_memory_a      (size_t, /*****/ unsigned int, const char *);
-void *util_memory_r      (void *, size_t, unsigned int, const char *);
-void  util_memory_d      (void *);
-void  util_meminfo       ();
-
 bool  util_filexists     (const char *);
 bool  util_strupper      (const char *);
 bool  util_strdigit      (const char *);
-char *_util_Estrdup      (const char *, const char *, size_t);
-char *_util_Estrdup_empty(const char *, const char *, size_t);
 void  util_debug         (const char *, const char *, ...);
 void  util_endianswap    (void *,  size_t, unsigned int);
 
@@ -311,7 +317,7 @@ size_t util_strtononcmd (const char *, char *, size_t);
 uint16_t util_crc16(uint16_t crc, const char *data, size_t len);
 
 void     util_seed(uint32_t);
-uint32_t util_rand();
+uint32_t util_rand(void);
 
 /*
  * String functions (formatting, copying, concatenating, errors). These are wrapped
@@ -326,22 +332,6 @@ char       *util_strcat   (char *dest, const char *src);
 char       *util_strncpy  (char *dest, const char *src, size_t num);
 const char *util_strerror (int num);
 
-
-#ifdef NOTRACK
-#    define mem_a(x)      malloc (x)
-#    define mem_d(x)      free   ((void*)x)
-#    define mem_r(x, n)   realloc((void*)x, n)
-#    define mem_af(x,f,l) malloc (x)
-#else
-#    define mem_a(x)      util_memory_a((x), __LINE__, __FILE__)
-#    define mem_d(x)      util_memory_d((void*)(x))
-#    define mem_r(x, n)   util_memory_r((void*)(x), (n), __LINE__, __FILE__)
-#    define mem_af(x,f,l) util_memory_a((x), __LINE__, __FILE__)
-#endif /*! NOTRACK */
-
-#define util_strdup(X)  _util_Estrdup((X), __FILE__, __LINE__)
-#define util_strdupe(X) _util_Estrdup_empty((X), __FILE__, __LINE__)
-
 /*
  * A flexible vector implementation: all vector pointers contain some
  * data about themselfs exactly - sizeof(vector_t) behind the pointer
@@ -383,7 +373,7 @@ typedef struct trie_s {
     struct trie_s *entries;
 } correct_trie_t;
 
-correct_trie_t* correct_trie_new();
+correct_trie_t* correct_trie_new(void);
 
 typedef struct hash_table_t {
     size_t                size;
@@ -734,7 +724,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 +739,7 @@ void      code_pop_statement (code_t *);
 typedef struct {
     const char *file;
     size_t      line;
+    size_t      column;
 } lex_ctx;
 
 /*===================================================================*/
@@ -770,17 +763,17 @@ enum {
     LVL_ERROR
 };
 
-FILE *con_default_out();
-FILE *con_default_err();
+FILE *con_default_out(void);
+FILE *con_default_err(void);
 
-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, ...);
 
-void con_close ();
-void con_init  ();
-void con_reset ();
+void con_close (void);
+void con_init  (void);
+void con_reset (void);
 void con_color (int);
 int  con_change(const char *, const char *);
 int  con_verr  (const char *, va_list);
@@ -797,7 +790,7 @@ void /********/ compile_error   (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, ...
 void /********/ vcompile_error  (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, va_list ap);
 bool GMQCC_WARN compile_warning (lex_ctx ctx, int warntype, const char *fmt, ...);
 bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap);
-void            compile_show_werrors();
+void            compile_show_werrors(void);
 
 /*===================================================================*/
 /*========================= assembler.c =============================*/
@@ -991,7 +984,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);
@@ -1002,8 +995,7 @@ qcint             prog_tempstring(qc_program *prog, const char *_str);
 /*===================== parser.c commandline ========================*/
 /*===================================================================*/
 struct parser_s;
-
-struct parser_s *parser_create        ();
+struct parser_s *parser_create        (void);
 bool             parser_compile_file  (struct parser_s *parser, const char *);
 bool             parser_compile_string(struct parser_s *parser, const char *, const char *, size_t);
 bool             parser_finish        (struct parser_s *parser, const char *);
@@ -1013,7 +1005,7 @@ void             parser_cleanup       (struct parser_s *parser);
 /*====================== ftepp.c commandline ========================*/
 /*===================================================================*/
 struct ftepp_s;
-struct ftepp_s *ftepp_create           ();
+struct ftepp_s *ftepp_create           (void);
 bool            ftepp_preprocess_file  (struct ftepp_s *ftepp, const char *filename);
 bool            ftepp_preprocess_string(struct ftepp_s *ftepp, const char *name, const char *str);
 void            ftepp_finish           (struct ftepp_s *ftepp);
@@ -1073,10 +1065,10 @@ void opts_setoptimlevel(unsigned int);
 void opts_ini_init     (const char *);
 
 /* Saner flag handling */
-void opts_backup_non_Wall();
-void opts_restore_non_Wall();
-void opts_backup_non_Werror_all();
-void opts_restore_non_Werror_all();
+void opts_backup_non_Wall(void);
+void opts_restore_non_Wall(void);
+void opts_backup_non_Werror_all(void);
+void opts_restore_non_Werror_all(void);
 
 enum {
 # define GMQCC_TYPE_FLAGS
@@ -1161,7 +1153,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 4f672dd..00464aa 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(void) {
     static ht intrinsics = NULL;
     if (!intrinsics)
         intrinsics = util_htnew(PARSER_HT_SIZE);
@@ -69,12 +69,10 @@ ht intrin_intrinsics() {
         vec_push(parser->globals,   (ast_expression*)(VALUE));        \
     } while (0)
 
-
-ast_expression *intrin_func (parser_t *parser, const char *name);
-
 #define QC_M_E 2.71828182845905
 
-ast_expression *intrin_pow(parser_t *parser) {
+static ast_expression *intrin_func(parser_t *parser, const char *name);
+static ast_expression *intrin_pow (parser_t *parser) {
     /*
      * float pow(float x, float y) {
      *   float local = 1.0f;
@@ -221,7 +219,7 @@ ast_expression *intrin_pow(parser_t *parser) {
     return (ast_expression*)value;
 }
 
-ast_expression *intrin_mod(parser_t *parser) {
+static ast_expression *intrin_mod(parser_t *parser) {
     /*
      * float mod(float x, float y) {
      *   return x - y * floor(x / y);
@@ -276,7 +274,7 @@ ast_expression *intrin_mod(parser_t *parser) {
     return (ast_expression*)value;
 }
 
-ast_expression *intrin_exp(parser_t *parser) {
+static ast_expression *intrin_exp(parser_t *parser) {
     /*
      * float exp(float x) {
      *     return pow(QC_M_E, x);
@@ -314,7 +312,7 @@ ast_expression *intrin_exp(parser_t *parser) {
     return (ast_expression*)value;
 }
 
-ast_expression *intrin_isnan(parser_t *parser) {
+static ast_expression *intrin_isnan(parser_t *parser) {
     /*
      * float isnan(float x) {
      *   float local;
@@ -383,7 +381,7 @@ void intrin_intrinsics_destroy(parser_t *parser) {
 }
 
 
-ast_expression *intrin_func(parser_t *parser, const char *name) {
+static ast_expression *intrin_func(parser_t *parser, const char *name) {
     static bool  init = false;
     size_t       i    = 0;
     void        *find;
diff --git a/ir.c b/ir.c
index 82dcb9b..fcf4caa 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
@@ -22,6 +23,7 @@
  */
 #include <stdlib.h>
 #include <string.h>
+
 #include "gmqcc.h"
 #include "ir.h"
 
@@ -211,9 +213,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 +262,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 +275,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 +288,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 +364,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 +387,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 +422,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 +452,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 +476,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 +576,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 +599,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 +715,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 +951,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 +983,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 +1014,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 +1037,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 +1045,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 +1158,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 +1265,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 +1275,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 +1338,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 +1412,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 +1508,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 +1851,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 +3443,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 +3594,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 +3710,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 +3862,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 +3932,7 @@ void ir_instr_dump(ir_instr *in, char *ind,
     ind[strlen(ind)-1] = 0;
 }
 
-void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...))
+static void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...))
 {
     oprintf("\"");
     for (; *str; ++str) {
diff --git a/ir.h b/ir.h
index dac16a3..cd38295 100644 (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 7722f4f..8289057 100644 (file)
--- a/lexer.c
+++ b/lexer.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-#include <stdio.h>
-#include <stdlib.h>
+#include <ctype.h>
 #include <string.h>
-#include <stdarg.h>
+#include <stdlib.h>
 
 #include "gmqcc.h"
 #include "lexer.h"
-
 /*
  * List of Keywords
  */
@@ -60,19 +58,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 +172,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 +200,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 +228,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 +271,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 +294,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 +374,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 +884,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
                         ch = 0;
                     else {
                         --u8len;
+                        lex->column += u8len;
                         for (uc = 0; uc < u8len; ++uc)
                             lex_tokench(lex, u8buf[uc]);
                         /* the last character will be inserted with the tokench() call
diff --git a/lexer.h b/lexer.h
index 24ac39a..f51d56e 100644 (file)
--- a/lexer.h
+++ b/lexer.h
@@ -22,7 +22,6 @@
  */
 #ifndef GMQCC_LEXER_HDR
 #define GMQCC_LEXER_HDR
-
 typedef struct token_s token;
 
 struct token_s {
@@ -114,6 +113,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 +163,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 +340,6 @@ static const size_t qcc_operator_count = (sizeof(qcc_operators) / sizeof(qcc_ope
 
 extern const oper_info *operators;
 extern size_t           operator_count;
-void lexerror(lex_file*, const char *fmt, ...);
+/*void lexerror(lex_file*, const char *fmt, ...);*/
 
 #endif
diff --git a/main.c b/main.c
index bbc685a..37638e9 100644 (file)
--- a/main.c
+++ b/main.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+
 #include "gmqcc.h"
 #include "lexer.h"
-#include <time.h>
 
 /* TODO: cleanup this whole file .. it's a fuckign mess */
 
@@ -41,9 +47,10 @@ static ppitem  *ppems = NULL;
 #define TYPE_ASM 1
 #define TYPE_SRC 2
 
+
 static const char *app_name;
 
-static void version() {
+static void version(void) {
     con_out("GMQCC %d.%d.%d Built %s %s\n" GMQCC_DEV_VERSION_STRING,
         GMQCC_VERSION_MAJOR,
         GMQCC_VERSION_MINOR,
@@ -53,7 +60,7 @@ static void version() {
     );
 }
 
-static int usage() {
+static int usage(void) {
     con_out("usage: %s [options] [files...]", app_name);
     con_out("options:\n"
             "  -h, --help             show this help message\n"
@@ -172,6 +179,7 @@ static bool options_parse(int argc, char **argv) {
 
 
                     OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_GMQCC;
+                    OPTS_OPTION_BOOL(OPTION_STATISTICS) = true;
 
                 } else if (!strcmp(argarg, "qcc")) {
 
@@ -794,6 +802,7 @@ cleanup:
         mem_d((void*)operators);
 
     lex_cleanup();
-    util_meminfo();
+    stat_info();
+
     return retval;
 }
diff --git a/opts.c b/opts.c
index 77aa9c0..e6ca420 100644 (file)
--- a/opts.c
+++ b/opts.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
 #include "gmqcc.h"
+
 unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS];
 opts_cmd_t   opts; /* command lien options */
 
-static void opts_setdefault() {
+static void opts_setdefault(void) {
     memset(&opts, 0, sizeof(opts_cmd_t));
     OPTS_OPTION_BOOL(OPTION_CORRECTION) = true;
 
@@ -361,7 +366,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 a9301a5..77a4094 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 */
     GMQCC_DEFINE_FLAG(MAX_ARRAY_SIZE)
     GMQCC_DEFINE_FLAG(ADD_INFO)
     GMQCC_DEFINE_FLAG(CORRECTION)
+    GMQCC_DEFINE_FLAG(STATISTICS)
 #endif
 
 /* some cleanup so we don't have to */
diff --git a/pak.c b/pak.c
index 653a463..2371ee1 100644 (file)
--- a/pak.c
+++ b/pak.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include <string.h>
+#include <stdlib.h>
+
 #include "gmqcc.h"
 
 /*
  * 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 +225,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 +237,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 +262,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 +313,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 +331,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 +416,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)
@@ -552,7 +555,8 @@ int main(int argc, char **argv) {
         /* not possible */
         pak_close(pak);
         vec_free(files);
-        util_meminfo();
+        stat_info();
+        
         return EXIT_SUCCESS;
     }
 
@@ -575,7 +579,6 @@ int main(int argc, char **argv) {
     pak_close(pak);
     vec_free(files);
 
-
-    util_meminfo();
+    stat_info();
     return EXIT_SUCCESS;
 }
index c681922..e92cb6e 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -21,8 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-#include <stdio.h>
-#include <stdarg.h>
+#include <string.h>
 #include <math.h>
 
 #include "gmqcc.h"
@@ -39,6 +38,8 @@ typedef struct parser_s {
     lex_file *lex;
     int      tok;
 
+    bool     ast_cleaned;
+
     ast_expression **globals;
     ast_expression **fields;
     ast_function **functions;
@@ -185,7 +186,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 +588,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 +606,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 +623,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 +637,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 +655,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 +710,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 +730,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 +772,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 +803,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 +832,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 +868,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 +884,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 +892,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 +900,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 +913,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 +921,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 +929,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 +943,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 +991,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 +1020,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 +1041,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 +1077,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 +1088,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 +1195,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 +1249,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 +1268,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 +1286,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 +1311,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 +1343,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 +1356,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 +1372,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 +1393,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 +1425,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 +1443,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 +1463,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 +1478,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 +1574,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 +1584,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 +1615,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 +1884,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 +2230,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 +2366,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 +2383,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 +2456,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 +2477,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 +2579,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 +2695,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 +2782,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 +2881,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 +2911,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 +3739,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 +4130,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 +4287,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 +4339,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 +4418,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 +4484,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));
@@ -4731,6 +4794,7 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
 
     /* for the sake of less code we parse-in in this function */
     if (!parser_next(parser)) {
+        ast_delete(var);
         parseerror(parser, "expected parameter list");
         return NULL;
     }
@@ -4998,6 +5062,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
         /* parse on */
         if (!parser_next(parser)) {
             ast_delete(var);
+            mem_d(name);
             parseerror(parser, "error after variable or field declaration");
             return NULL;
         }
@@ -5007,8 +5072,10 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
     if (parser->tok == '[') {
         wasarray = true;
         var = parse_arraysize(parser, var);
-        if (!var)
+        if (!var) {
+            if (name) mem_d(name);
             return NULL;
+        }
     }
 
     /* This is the point where we can turn it into a field */
@@ -5027,8 +5094,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
     while (parser->tok == '(') {
         var = parse_parameter_list(parser, var);
         if (!var) {
-            if (name)
-                mem_d((void*)name);
+            if (name) mem_d(name);
             return NULL;
         }
     }
@@ -5037,11 +5103,12 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
     if (name) {
         if (!ast_value_set_name(var, name)) {
             ast_delete(var);
+            mem_d(name);
             parseerror(parser, "internal error: failed to set name");
             return NULL;
         }
         /* free the name, ast_value_set_name duplicates */
-        mem_d((void*)name);
+        mem_d(name);
     }
 
     return var;
@@ -5272,7 +5339,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 +5447,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 +5486,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 +5635,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 +5692,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 +5794,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 +5882,7 @@ skipvar:
                 }
                 vec_free(sy.out);
                 vec_free(sy.ops);
+                vec_free(sy.argc);
                 var->cvq = cvq;
             }
         }
@@ -5970,7 +6053,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 +6086,6 @@ parser_t *parser_create()
         mem_d(parser);
         return NULL;
     }
-    
 
     for (i = 0; i < operator_count; ++i) {
         if (operators[i].id == opid1('=')) {
@@ -6056,7 +6138,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;
@@ -6108,9 +6190,12 @@ bool parser_compile_string(parser_t *parser, const char *name, const char *str,
     return parser_compile(parser);
 }
 
-void parser_cleanup(parser_t *parser)
+static void parser_remove_ast(parser_t *parser)
 {
     size_t i;
+    if (parser->ast_cleaned)
+        return;
+    parser->ast_cleaned = true;
     for (i = 0; i < vec_size(parser->accessors); ++i) {
         ast_delete(parser->accessors[i]->constval.vfunc);
         parser->accessors[i]->constval.vfunc = NULL;
@@ -6179,8 +6264,13 @@ void parser_cleanup(parser_t *parser)
     ast_value_delete(parser->const_vec[2]);
 
     util_htdel(parser->aliases);
-
     intrin_intrinsics_destroy(parser);
+}
+
+void parser_cleanup(parser_t *parser)
+{
+    parser_remove_ast(parser);
+    code_cleanup(parser->code);
 
     mem_d(parser);
 }
@@ -6220,11 +6310,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 +6402,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;
@@ -6338,6 +6428,8 @@ bool parser_finish(parser_t *parser, const char *output)
             return false;
         }
     }
+
+    generate_checksum(parser);
     if (OPTS_OPTION_BOOL(OPTION_DUMP))
         ir_builder_dump(ir, con_out);
     for (i = 0; i < vec_size(parser->functions); ++i) {
@@ -6347,6 +6439,7 @@ bool parser_finish(parser_t *parser, const char *output)
             return false;
         }
     }
+    parser_remove_ast(parser);
 
     if (compile_Werrors) {
         con_out("*** there were warnings treated as errors\n");
@@ -6358,15 +6451,12 @@ bool parser_finish(parser_t *parser, const char *output)
         if (OPTS_OPTION_BOOL(OPTION_DUMPFIN))
             ir_builder_dump(ir, con_out);
 
-        generate_checksum(parser);
-
         if (!ir_builder_generate(parser->code, ir, output)) {
             con_out("*** failed to generate output file\n");
             ir_builder_delete(ir);
             return false;
         }
     }
-
     ir_builder_delete(ir);
     return retval;
 }
diff --git a/stat.c b/stat.c
new file mode 100644 (file)
index 0000000..21447eb
--- /dev/null
+++ b/stat.c
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2012, 2013
+ *     Dale Weiler
+ *     Wolfgang Bumiller
+ *
+ * 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
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "gmqcc.h"
+
+/*
+ * GMQCC performs tons of allocations, constructions, and crazyness
+ * all around. When trying to optimizes systems, or just get fancy
+ * statistics out of the compiler, it's often printf mess. This file
+ * implements the statistics system of the compiler. I.E the allocator
+ * we use to track allocations, and other systems of interest.
+ */
+#define ST_SIZE 1024
+
+typedef struct stat_mem_block_s {
+    const char              *file;
+    size_t                   line;
+    size_t                   size;
+    struct stat_mem_block_s *next;
+    struct stat_mem_block_s *prev;
+} stat_mem_block_t;
+
+typedef struct {
+    size_t key;
+    size_t value;
+} stat_size_entry_t, **stat_size_table_t;
+
+static uint64_t          stat_mem_allocated         = 0;
+static uint64_t          stat_mem_deallocated       = 0;
+static uint64_t          stat_mem_allocated_total   = 0;
+static uint64_t          stat_mem_deallocated_total = 0;
+static uint64_t          stat_mem_high              = 0;
+static uint64_t          stat_mem_peak              = 0;
+static uint64_t          stat_used_strdups          = 0;
+static uint64_t          stat_used_vectors          = 0;
+static uint64_t          stat_used_hashtables       = 0;
+static uint64_t          stat_type_vectors          = 0;
+static uint64_t          stat_type_hashtables       = 0;
+static stat_size_table_t stat_size_vectors          = NULL;
+static stat_size_table_t stat_size_hashtables       = NULL;
+static stat_mem_block_t *stat_mem_block_root        = NULL;
+
+/*
+ * A tiny size_t key-value hashtbale for tracking vector and hashtable
+ * sizes. We can use it for other things too, if we need to. This is
+ * very TIGHT, and efficent in terms of space though.
+ */
+static stat_size_table_t stat_size_new(void) {
+    return (stat_size_table_t)memset(
+        mem_a(sizeof(stat_size_entry_t*) * ST_SIZE),
+        0, ST_SIZE * sizeof(stat_size_entry_t*)
+    );
+}
+
+static void stat_size_del(stat_size_table_t table) {
+    size_t i = 0;
+    for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]);
+    mem_d(table);
+}
+
+static stat_size_entry_t *stat_size_get(stat_size_table_t table, size_t key) {
+    size_t hash = (key % ST_SIZE);
+    while (table[hash] && table[hash]->key != key)
+        hash = (hash + 1) % ST_SIZE;
+    return table[hash];
+}
+static void stat_size_put(stat_size_table_t table, size_t key, size_t value) {
+    size_t hash = (key % ST_SIZE);
+    while (table[hash] && table[hash]->key != key)
+        hash = (hash + 1) % ST_SIZE;
+    table[hash] = (stat_size_entry_t*)mem_a(sizeof(stat_size_entry_t));
+    table[hash]->key = key;
+    table[hash]->value = value;
+}
+
+/*
+ * A basic header of information wrapper allocator. Simply stores
+ * information as a header, returns the memory + 1 past it, can be
+ * retrieved again with - 1. Where type is stat_mem_block_t*.
+ */
+void *stat_mem_allocate(size_t size, size_t line, const char *file) {
+    stat_mem_block_t *info = (stat_mem_block_t*)malloc(sizeof(stat_mem_block_t) + size);
+    void             *data = (void*)(info + 1);
+    
+    if(!info)
+        return NULL;
+        
+    info->line = line;
+    info->size = size;
+    info->file = file;
+    info->prev = NULL;
+    info->next = stat_mem_block_root;
+    
+    if (stat_mem_block_root)
+        stat_mem_block_root->prev = info;
+        
+    stat_mem_block_root       = info;
+    stat_mem_allocated       += size;
+    stat_mem_high            += size;
+    stat_mem_allocated_total ++;
+    
+    if (stat_mem_high > stat_mem_peak)
+        stat_mem_peak = stat_mem_high;
+
+    return data;
+}
+
+void stat_mem_deallocate(void *ptr) {
+    stat_mem_block_t *info = NULL;
+    
+    if (!ptr)
+        return;
+        
+    info = ((stat_mem_block_t*)ptr - 1);
+    
+    stat_mem_deallocated       += info->size;
+    stat_mem_high              -= info->size;
+    stat_mem_deallocated_total ++;
+    
+    if (info->prev) info->prev->next = info->next;
+    if (info->next) info->next->prev = info->prev;
+    
+    /* move ahead */
+    if (info == stat_mem_block_root)
+        stat_mem_block_root = info->next;
+        
+    free(info);
+}
+
+void *stat_mem_reallocate(void *ptr, size_t size, size_t line, const char *file) {
+    stat_mem_block_t *oldinfo = NULL;
+    stat_mem_block_t *newinfo;
+    
+    if (!ptr)
+        return stat_mem_allocate(size, line, file);
+    
+    /* stay consistent with glic */
+    if (!size) {
+        stat_mem_deallocate(ptr);
+        return NULL;
+    }
+    
+    oldinfo = ((stat_mem_block_t*)ptr - 1);
+    newinfo = ((stat_mem_block_t*)malloc(sizeof(stat_mem_block_t) + size));
+    
+    if (!newinfo) {
+        stat_mem_deallocate(ptr);
+        return NULL;
+    }
+    
+    memcpy(newinfo+1, oldinfo+1, oldinfo->size);
+    
+    if (oldinfo->prev) oldinfo->prev->next = oldinfo->next;
+    if (oldinfo->next) oldinfo->next->prev = oldinfo->prev;
+    
+    /* move ahead */
+    if (oldinfo == stat_mem_block_root)
+        stat_mem_block_root = oldinfo->next;
+        
+    newinfo->line = line;
+    newinfo->size = size;
+    newinfo->file = file;
+    newinfo->prev = NULL;
+    newinfo->next = stat_mem_block_root;
+    
+    if (stat_mem_block_root)
+        stat_mem_block_root->prev = newinfo;
+    
+    stat_mem_block_root = newinfo;
+    stat_mem_allocated -= oldinfo->size;
+    stat_mem_high      -= oldinfo->size;
+    stat_mem_allocated += newinfo->size;
+    stat_mem_high      += newinfo->size;
+    
+    if (stat_mem_high > stat_mem_peak)
+        stat_mem_peak = stat_mem_high;
+        
+    free(oldinfo);
+    
+    return newinfo + 1;
+}
+
+/*
+ * strdup does it's own malloc, we need to track malloc. We don't want
+ * to overwrite malloc though, infact, we can't really hook it at all
+ * without library specific assumptions. So we re implement strdup.
+ */
+char *stat_mem_strdup(const char *src, size_t line, const char *file, bool empty) {
+    size_t len = 0;
+    char  *ptr = NULL;
+    
+    if (!src)
+        return NULL;
+    
+    len = strlen(src);
+    if (((!empty) ? len : true) && (ptr = (char*)stat_mem_allocate(len + 1, line, file))) {
+        memcpy(ptr, src, len);
+        ptr[len] = '\0';
+    }
+    
+    stat_used_strdups ++;
+    return ptr;
+}
+
+/*
+ * The reallocate function for resizing vectors.
+ */
+void _util_vec_grow(void **a, size_t i, size_t s) {
+    vector_t          *d = vec_meta(*a);
+    size_t             m = 0;
+    stat_size_entry_t *e = NULL;
+    void              *p = NULL;
+    
+    if (*a) {
+        m = 2 * d->allocated + i;
+        p = mem_r(d, s * m + sizeof(vector_t));
+    } else {
+        m = i + 1;
+        p = mem_a(s * m + sizeof(vector_t));
+        ((vector_t*)p)->used = 0;
+        stat_used_vectors++;
+    }
+    
+    if (!stat_size_vectors)
+        stat_size_vectors = stat_size_new();
+
+    if ((e = stat_size_get(stat_size_vectors, s))) {
+        e->value ++;
+    } else {
+        stat_size_put(stat_size_vectors, s, 1); /* start off with 1 */
+        stat_type_vectors++;
+    }
+
+    *a = (vector_t*)p + 1;
+    vec_meta(*a)->allocated = m;
+}
+
+/*
+ * Hash table for generic data, based on dynamic memory allocations
+ * all around.  This is the internal interface, please look for
+ * EXPOSED INTERFACE comment below
+ */
+typedef struct hash_node_t {
+    char               *key;   /* the key for this node in table */
+    void               *value; /* pointer to the data as void*   */
+    struct hash_node_t *next;  /* next node (linked list)        */
+} hash_node_t;
+
+GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) {
+    const uint32_t       mix   = 0x5BD1E995;
+    const uint32_t       rot   = 24;
+    size_t               size  = strlen(key);
+    uint32_t             hash  = 0x1EF0 /* LICRC TAB */  ^ size;
+    uint32_t             alias = 0;
+    const unsigned char *data  = (const unsigned char*)key;
+
+    while (size >= 4) {
+        alias  = (data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));
+        alias *= mix;
+        alias ^= alias >> rot;
+        alias *= mix;
+
+        hash  *= mix;
+        hash  ^= alias;
+
+        data += 4;
+        size -= 4;
+    }
+
+    switch (size) {
+        case 3: hash ^= data[2] << 16;
+        case 2: hash ^= data[1] << 8;
+        case 1: hash ^= data[0];
+                hash *= mix;
+    }
+
+    hash ^= hash >> 13;
+    hash *= mix;
+    hash ^= hash >> 15;
+
+    return (size_t) (hash % ht->size);
+}
+
+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;
+
+    if (!(node->key = util_strdupe(key))) {
+        mem_d(node);
+        return NULL;
+    }
+
+    node->value = value;
+    node->next  = NULL;
+
+    return node;
+}
+
+/*
+ * EXPOSED INTERFACE for the hashtable implementation
+ * util_htnew(size)                             -- to make a new hashtable
+ * util_htset(table, key, value, sizeof(value)) -- to set something in the table
+ * util_htget(table, key)                       -- to get something from the table
+ * util_htdel(table)                            -- to delete the table
+ */
+hash_table_t *util_htnew(size_t size) {
+    hash_table_t      *hashtable = NULL;
+    stat_size_entry_t *find      = NULL;
+    
+    if (size < 1)
+        return NULL;
+        
+    if (!stat_size_hashtables)
+        stat_size_hashtables = stat_size_new();
+
+    if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t))))
+        return NULL;
+
+    if (!(hashtable->table = (hash_node_t**)mem_a(sizeof(hash_node_t*) * size))) {
+        mem_d(hashtable);
+        return NULL;
+    }
+    
+    if ((find = stat_size_get(stat_size_hashtables, size)))
+        find->value++;
+    else {
+        stat_type_hashtables++;
+        stat_size_put(stat_size_hashtables, size, 1);
+    }
+
+    hashtable->size = size;
+    memset(hashtable->table, 0, sizeof(hash_node_t*) * size);
+
+    stat_used_hashtables++;
+    return hashtable;
+}
+
+void util_htseth(hash_table_t *ht, const char *key, size_t bin, void *value) {
+    hash_node_t *newnode = NULL;
+    hash_node_t *next    = NULL;
+    hash_node_t *last    = NULL;
+
+    next = ht->table[bin];
+
+    while (next && next->key && strcmp(key, next->key) > 0)
+        last = next, next = next->next;
+
+    /* already in table, do a replace */
+    if (next && next->key && strcmp(key, next->key) == 0) {
+        next->value = value;
+    } else {
+        /* not found, grow a pair man :P */
+        newnode = _util_htnewpair(key, value);
+        if (next == ht->table[bin]) {
+            newnode->next  = next;
+            ht->table[bin] = newnode;
+        } else if (!next) {
+            last->next = newnode;
+        } else {
+            newnode->next = next;
+            last->next = newnode;
+        }
+    }
+}
+
+void util_htset(hash_table_t *ht, const char *key, void *value) {
+    util_htseth(ht, key, util_hthash(ht, key), value);
+}
+
+void *util_htgeth(hash_table_t *ht, const char *key, size_t bin) {
+    hash_node_t *pair = ht->table[bin];
+
+    while (pair && pair->key && strcmp(key, pair->key) > 0)
+        pair = pair->next;
+
+    if (!pair || !pair->key || strcmp(key, pair->key) != 0)
+        return NULL;
+
+    return pair->value;
+}
+
+void *util_htget(hash_table_t *ht, const char *key) {
+    return util_htgeth(ht, key, util_hthash(ht, key));
+}
+
+void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin) {
+    hash_node_t *pair;
+    size_t len, keylen;
+    int cmp;
+
+    keylen = strlen(key);
+
+    pair = ht->table[bin];
+    while (pair && pair->key) {
+        len = strlen(pair->key);
+        if (len < keylen) {
+            pair = pair->next;
+            continue;
+        }
+        if (keylen == len) {
+            cmp = strcmp(key, pair->key);
+            if (cmp == 0)
+                return pair->value;
+            if (cmp < 0)
+                return NULL;
+            pair = pair->next;
+            continue;
+        }
+        cmp = strcmp(key, pair->key + len - keylen);
+        if (cmp == 0) {
+            uintptr_t up = (uintptr_t)pair->value;
+            up += len - keylen;
+            return (void*)up;
+        }
+        pair = pair->next;
+    }
+    return NULL;
+}
+
+/*
+ * Free all allocated data in a hashtable, this is quite the amount
+ * of work.
+ */
+void util_htrem(hash_table_t *ht, void (*callback)(void *data)) {
+    size_t i = 0;
+    for (; i < ht->size; i++) {
+        hash_node_t *n = ht->table[i];
+        hash_node_t *p;
+
+        /* free in list */
+        while (n) {
+            if (n->key)
+                mem_d(n->key);
+            if (callback)
+                callback(n->value);
+            p = n;
+            n = n->next;
+            mem_d(p);
+        }
+
+    }
+    /* free table */
+    mem_d(ht->table);
+    mem_d(ht);
+}
+
+void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) {
+    hash_node_t **pair = &ht->table[bin];
+    hash_node_t *tmp;
+
+    while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0)
+        pair = &(*pair)->next;
+
+    tmp = *pair;
+    if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0)
+        return;
+
+    if (cb)
+        (*cb)(tmp->value);
+
+    *pair = tmp->next;
+    mem_d(tmp->key);
+    mem_d(tmp);
+}
+
+void util_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)) {
+    util_htrmh(ht, key, util_hthash(ht, key), cb);
+}
+
+void util_htdel(hash_table_t *ht) {
+    util_htrem(ht, NULL);
+}
+
+/*
+ * The following functions below implement printing / dumping of statistical
+ * information.
+ */
+static void stat_dump_mem_contents(stat_mem_block_t *memory, uint16_t cols) {
+    uint32_t i, j;
+    for (i = 0; i < memory->size + ((memory->size % cols) ? (cols - memory->size % cols) : 0); i++) {
+        if (i % cols == 0)    con_out(" 0x%06X: ", i);
+        if (i < memory->size) con_out("%02X " , 0xFF & ((unsigned char*)(memory + 1))[i]);
+        else                  con_out(" ");
+
+        if ((uint16_t)(i % cols) == (cols - 1)) {
+            for (j = i - (cols - 1); j <= i; j++) {
+                con_out("%c",
+                    (j >= memory->size)
+                        ? ' '
+                        : (isprint(((unsigned char*)(memory + 1))[j]))
+                            ? 0xFF & ((unsigned char*)(memory + 1)) [j]
+                            : '.'
+                );
+            }
+            con_out("\n");
+        }
+    }
+}
+
+static void stat_dump_mem_leaks(void) {
+    stat_mem_block_t *info;
+    for (info = stat_mem_block_root; info; info = info->next) {
+        con_out("lost: %u (bytes) at %s:%u\n",
+            info->size,
+            info->file,
+            info->line
+        );
+        
+        stat_dump_mem_contents(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS));
+    }
+}
+
+static void stat_dump_mem_info(void) {
+    con_out("Memory information:\n\
+    Total allocations:   %llu\n\
+    Total deallocations: %llu\n\
+    Total allocated:     %f (MB)\n\
+    Total deallocated:   %f (MB)\n\
+    Total peak memory:   %f (MB)\n\
+    Total leaked memory: %f (MB) in %llu allocations\n",
+        stat_mem_allocated_total,
+        stat_mem_deallocated_total,
+        (float)(stat_mem_allocated)                        / 1048576.0f,
+        (float)(stat_mem_deallocated)                      / 1048576.0f,
+        (float)(stat_mem_peak)                             / 1048576.0f,
+        (float)(stat_mem_allocated - stat_mem_deallocated) / 1048576.0f,
+        stat_mem_allocated_total - stat_mem_deallocated_total
+    );
+}
+
+static void stat_dump_stats_table(stat_size_table_t table, const char *string, uint64_t *size) {
+    size_t i,j;
+    
+    if (!table)
+        return;
+    
+    for (i = 0, j = 1; i < ST_SIZE; i++) {
+        stat_size_entry_t *entry;
+
+        if (!(entry = table[i]))
+            continue;
+
+        con_out(string, (unsigned)j, (unsigned)entry->key, (unsigned)entry->value);
+        j++;
+        
+        if (size)
+            *size += entry->key * entry->value;
+    }
+}
+
+void stat_info() {
+    if (OPTS_OPTION_BOOL(OPTION_DEBUG))
+        stat_dump_mem_leaks();
+
+    if (OPTS_OPTION_BOOL(OPTION_DEBUG) ||
+        OPTS_OPTION_BOOL(OPTION_MEMCHK))
+        stat_dump_mem_info();
+
+    if (OPTS_OPTION_BOOL(OPTION_MEMCHK) ||
+        OPTS_OPTION_BOOL(OPTION_STATISTICS)) {
+        uint64_t mem = 0;
+        
+        con_out("\nAdditional Statistics:\n\
+    Total vectors allocated:    %llu\n\
+    Total string duplicates:    %llu\n\
+    Total hashtables allocated: %llu\n\
+    Total unique vector sizes:  %llu\n",
+            stat_used_vectors,
+            stat_used_strdups,
+            stat_used_hashtables,
+            stat_type_vectors
+        );
+        
+        stat_dump_stats_table (
+            stat_size_vectors,
+            "        %2u| # of %4u byte vectors: %u\n",
+            &mem
+        );
+        
+        con_out (
+            "    Total unique hashtable sizes: %llu\n",
+            stat_type_hashtables
+        );
+        
+        stat_dump_stats_table (
+            stat_size_hashtables,
+            "        %2u| # of %4u element hashtables: %u\n",
+            NULL
+        );
+        
+        con_out (
+            "    Total vector memory:          %f (MB)\n",
+            (float)(mem) / 1048576.0f
+        );
+    }
+
+    if (stat_size_vectors)
+        stat_size_del(stat_size_vectors);
+    if (stat_size_hashtables)
+        stat_size_del(stat_size_hashtables);
+}
+#undef ST_SIZE
diff --git a/test.c b/test.c
index 7722af2..1ebb33a 100644 (file)
--- a/test.c
+++ b/test.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-#include "gmqcc.h"
+#include <stdlib.h>
+#include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#include "gmqcc.h"
+
 opts_cmd_t opts;
 
 static const char *task_bins[] = {
@@ -60,7 +63,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 +140,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 +161,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 +182,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 +284,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 +300,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 +312,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 +357,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 +380,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 +410,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 +432,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 +457,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 +483,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 +498,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 +612,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 +663,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 +843,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 +866,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 +915,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 +1023,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 +1040,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 +1213,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[] = {
@@ -1283,6 +1286,7 @@ int main(int argc, char **argv) {
     char         *defs     = NULL;
 
     con_init();
+    OPTS_OPTION_U16(OPTION_MEMDUMPCOLS) = 16;
 
     /*
      * Command line option parsing commences now We only need to support
@@ -1321,7 +1325,7 @@ int main(int argc, char **argv) {
     }
     con_change(redirout, redirerr);
     succeed = test_perform("tests", defs);
-    util_meminfo();
+    stat_info();
 
 
     return (succeed) ? EXIT_SUCCESS : EXIT_FAILURE;
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 c8d50f5..efed221 100644 (file)
--- a/util.c
+++ b/util.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-#include <stdarg.h>
-#include <errno.h>
-#include "gmqcc.h"
-
-/* TODO: remove globals ... */
-static uint64_t mem_ab = 0;
-static uint64_t mem_db = 0;
-static uint64_t mem_at = 0;
-static uint64_t mem_dt = 0;
-static uint64_t mem_pk = 0;
-static uint64_t mem_hw = 0;
-
-struct memblock_t {
-    const char  *file;
-    unsigned int line;
-    size_t       byte;
-    struct memblock_t *next;
-    struct memblock_t *prev;
-};
-
-#define PEAK_MEM             \
-    do {                     \
-        if (mem_hw > mem_pk) \
-            mem_pk = mem_hw; \
-    } while (0)
-
-static struct memblock_t *mem_start = NULL;
-
-void *util_memory_a(size_t byte, unsigned int line, const char *file) {
-    struct memblock_t *info = (struct memblock_t*)malloc(sizeof(struct memblock_t) + byte);
-    void              *data = (void*)(info+1);
-    if (!info) return NULL;
-    info->line = line;
-    info->byte = byte;
-    info->file = file;
-    info->prev = NULL;
-    info->next = mem_start;
-    if (mem_start)
-        mem_start->prev = info;
-    mem_start = info;
-
-    mem_at++;
-    mem_ab += info->byte;
-    mem_hw += info->byte;
-
-    PEAK_MEM;
-
-    return data;
-}
-
-void util_memory_d(void *ptrn) {
-    struct memblock_t *info = NULL;
-
-    if (!ptrn) return;
-    info = ((struct memblock_t*)ptrn - 1);
-
-    mem_db += info->byte;
-    mem_hw -= info->byte;
-    mem_dt++;
-
-    if (info->prev)
-        info->prev->next = info->next;
-    if (info->next)
-        info->next->prev = info->prev;
-    if (info == mem_start)
-        mem_start = info->next;
-
-    free(info);
-}
-
-void *util_memory_r(void *ptrn, size_t byte, unsigned int line, const char *file) {
-    struct memblock_t *oldinfo = NULL;
-
-    struct memblock_t *newinfo;
-
-    if (!ptrn)
-        return util_memory_a(byte, line, file);
-    if (!byte) {
-        util_memory_d(ptrn);
-        return NULL;
-    }
+#include <string.h>
+#include <ctype.h>
 
-    oldinfo = ((struct memblock_t*)ptrn - 1);
-    newinfo = ((struct memblock_t*)malloc(sizeof(struct memblock_t) + byte));
-
-    /* new data */
-    if (!newinfo) {
-        util_memory_d(oldinfo+1);
-        return NULL;
-    }
-
-    /* copy old */
-    memcpy(newinfo+1, oldinfo+1, oldinfo->byte);
-
-    /* free old */
-    if (oldinfo->prev)
-        oldinfo->prev->next = oldinfo->next;
-    if (oldinfo->next)
-        oldinfo->next->prev = oldinfo->prev;
-    if (oldinfo == mem_start)
-        mem_start = oldinfo->next;
-
-    /* fill info */
-    newinfo->line = line;
-    newinfo->byte = byte;
-    newinfo->file = file;
-    newinfo->prev = NULL;
-    newinfo->next = mem_start;
-    if (mem_start)
-        mem_start->prev = newinfo;
-    mem_start = newinfo;
-
-    mem_ab -= oldinfo->byte;
-    mem_hw -= oldinfo->byte;
-    mem_ab += newinfo->byte;
-    mem_hw += newinfo->byte;
-
-    PEAK_MEM;
-
-    free(oldinfo);
-
-    return newinfo+1;
-}
-
-static void util_dumpmem(struct memblock_t *memory, uint16_t cols) {
-    uint32_t i, j;
-    for (i = 0; i < memory->byte + ((memory->byte % cols) ? (cols - memory->byte % cols) : 0); i++) {
-        if (i % cols == 0)    con_out("    0x%06X: ", i);
-        if (i < memory->byte) con_out("%02X "   , 0xFF & ((char*)(memory + 1))[i]);
-        else                  con_out("    ");
-
-        if ((uint16_t)(i % cols) == (cols - 1)) {
-            for (j = i - (cols - 1); j <= i; j++) {
-                con_out("%c",
-                    (j >= memory->byte)
-                        ? ' '
-                        : (isprint(((char*)(memory + 1))[j]))
-                            ? 0xFF & ((char*)(memory + 1)) [j]
-                            : '.'
-                );
-            }
-            con_out("\n");
-        }
-    }
-}
-
-void util_meminfo() {
-    struct memblock_t *info;
-
-
-    if (OPTS_OPTION_BOOL(OPTION_DEBUG)) {
-        for (info = mem_start; info; info = info->next) {
-            con_out("lost: %u (bytes) at %s:%u\n",
-                info->byte,
-                info->file,
-                info->line);
-
-            util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS));
-        }
-    }
-
-    if (OPTS_OPTION_BOOL(OPTION_DEBUG) ||
-        OPTS_OPTION_BOOL(OPTION_MEMCHK)) {
-        con_out("Memory information:\n\
-            Total allocations:   %llu\n\
-            Total deallocations: %llu\n\
-            Total allocated:     %f (MB)\n\
-            Total deallocated:   %f (MB)\n\
-            Total peak memory:   %f (MB)\n\
-            Total leaked memory: %f (MB) in %llu allocations\n",
-                mem_at,
-                mem_dt,
-                (float)(mem_ab)           / 1048576.0f,
-                (float)(mem_db)           / 1048576.0f,
-                (float)(mem_pk)           / 1048576.0f,
-                (float)(mem_ab -  mem_db) / 1048576.0f,
-
-                /* could be more clever */
-                (mem_at -  mem_dt)
-        );
-    }
-}
-
-/*
- * Some string utility functions, because strdup uses malloc, and we want
- * to track all memory (without replacing malloc).
- */
-char *_util_Estrdup(const char *s, const char *file, size_t line) {
-    size_t  len = 0;
-    char   *ptr = NULL;
-
-    /* in case of -DNOTRACK */
-    (void)file;
-    (void)line;
-
-    if (!s)
-        return NULL;
-
-    if ((len = strlen(s)) && (ptr = (char*)mem_af(len+1, line, file))) {
-        memcpy(ptr, s, len);
-        ptr[len] = '\0';
-    }
-    return ptr;
-}
-
-char *_util_Estrdup_empty(const char *s, const char *file, size_t line) {
-    size_t  len = 0;
-    char   *ptr = NULL;
-
-    /* in case of -DNOTRACK */
-    (void)file;
-    (void)line;
-
-    if (!s)
-        return NULL;
-
-    len = strlen(s);
-    if ((ptr = (char*)mem_af(len+1, line, file))) {
-        memcpy(ptr, s, len);
-        ptr[len] = '\0';
-    }
-    return ptr;
-}
+#include "gmqcc.h"
 
 void util_debug(const char *area, const char *ms, ...) {
     va_list  va;
@@ -432,243 +213,6 @@ size_t util_strtononcmd(const char *in, char *out, size_t outsz) {
     return sz-1;
 }
 
-/* TODO: rewrite ... when I redo the ve cleanup */
-void _util_vec_grow(void **a, size_t i, size_t s) {
-    vector_t *d = vec_meta(*a);
-    size_t    m = *a ? 2 * d->allocated +i : i+1;
-    void     *p = mem_r((*a ? d : NULL), s * m + sizeof(vector_t));
-
-    if (!*a)
-        ((vector_t*)p)->used = 0;
-    *a = (vector_t*)p + 1;
-
-    vec_meta(*a)->allocated = m;
-}
-
-/*
- * Hash table for generic data, based on dynamic memory allocations
- * all around.  This is the internal interface, please look for
- * EXPOSED INTERFACE comment below
- */
-typedef struct hash_node_t {
-    char               *key;   /* the key for this node in table */
-    void               *value; /* pointer to the data as void*   */
-    struct hash_node_t *next;  /* next node (linked list)        */
-} hash_node_t;
-
-GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) {
-    const uint32_t       mix   = 0x5BD1E995;
-    const uint32_t       rot   = 24;
-    size_t               size  = strlen(key);
-    uint32_t             hash  = 0x1EF0 /* LICRC TAB */  ^ size;
-    uint32_t             alias = 0;
-    const unsigned char *data  = (const unsigned char*)key;
-
-    while (size >= 4) {
-        alias  = (data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));
-        alias *= mix;
-        alias ^= alias >> rot;
-        alias *= mix;
-
-        hash  *= mix;
-        hash  ^= alias;
-
-        data += 4;
-        size -= 4;
-    }
-
-    switch (size) {
-        case 3: hash ^= data[2] << 16;
-        case 2: hash ^= data[1] << 8;
-        case 1: hash ^= data[0];
-                hash *= mix;
-    }
-
-    hash ^= hash >> 13;
-    hash *= mix;
-    hash ^= hash >> 15;
-
-    return (size_t) (hash % ht->size);
-}
-
-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;
-
-    if (!(node->key = util_strdupe(key))) {
-        mem_d(node);
-        return NULL;
-    }
-
-    node->value = value;
-    node->next  = NULL;
-
-    return node;
-}
-
-/*
- * EXPOSED INTERFACE for the hashtable implementation
- * util_htnew(size)                             -- to make a new hashtable
- * util_htset(table, key, value, sizeof(value)) -- to set something in the table
- * util_htget(table, key)                       -- to get something from the table
- * util_htdel(table)                            -- to delete the table
- */
-hash_table_t *util_htnew(size_t size) {
-    hash_table_t *hashtable = NULL;
-    if (size < 1)
-        return NULL;
-
-    if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t))))
-        return NULL;
-
-    if (!(hashtable->table = (hash_node_t**)mem_a(sizeof(hash_node_t*) * size))) {
-        mem_d(hashtable);
-        return NULL;
-    }
-
-    hashtable->size = size;
-    memset(hashtable->table, 0, sizeof(hash_node_t*) * size);
-
-    return hashtable;
-}
-
-void util_htseth(hash_table_t *ht, const char *key, size_t bin, void *value) {
-    hash_node_t *newnode = NULL;
-    hash_node_t *next    = NULL;
-    hash_node_t *last    = NULL;
-
-    next = ht->table[bin];
-
-    while (next && next->key && strcmp(key, next->key) > 0)
-        last = next, next = next->next;
-
-    /* already in table, do a replace */
-    if (next && next->key && strcmp(key, next->key) == 0) {
-        next->value = value;
-    } else {
-        /* not found, grow a pair man :P */
-        newnode = _util_htnewpair(key, value);
-        if (next == ht->table[bin]) {
-            newnode->next  = next;
-            ht->table[bin] = newnode;
-        } else if (!next) {
-            last->next = newnode;
-        } else {
-            newnode->next = next;
-            last->next = newnode;
-        }
-    }
-}
-
-void util_htset(hash_table_t *ht, const char *key, void *value) {
-    util_htseth(ht, key, util_hthash(ht, key), value);
-}
-
-void *util_htgeth(hash_table_t *ht, const char *key, size_t bin) {
-    hash_node_t *pair = ht->table[bin];
-
-    while (pair && pair->key && strcmp(key, pair->key) > 0)
-        pair = pair->next;
-
-    if (!pair || !pair->key || strcmp(key, pair->key) != 0)
-        return NULL;
-
-    return pair->value;
-}
-
-void *util_htget(hash_table_t *ht, const char *key) {
-    return util_htgeth(ht, key, util_hthash(ht, key));
-}
-
-void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin) {
-    hash_node_t *pair;
-    size_t len, keylen;
-    int cmp;
-
-    keylen = strlen(key);
-
-    pair = ht->table[bin];
-    while (pair && pair->key) {
-        len = strlen(pair->key);
-        if (len < keylen) {
-            pair = pair->next;
-            continue;
-        }
-        if (keylen == len) {
-            cmp = strcmp(key, pair->key);
-            if (cmp == 0)
-                return pair->value;
-            if (cmp < 0)
-                return NULL;
-            pair = pair->next;
-            continue;
-        }
-        cmp = strcmp(key, pair->key + len - keylen);
-        if (cmp == 0) {
-            uintptr_t up = (uintptr_t)pair->value;
-            up += len - keylen;
-            return (void*)up;
-        }
-        pair = pair->next;
-    }
-    return NULL;
-}
-
-/*
- * Free all allocated data in a hashtable, this is quite the amount
- * of work.
- */
-void util_htrem(hash_table_t *ht, void (*callback)(void *data)) {
-    size_t i = 0;
-    for (; i < ht->size; i++) {
-        hash_node_t *n = ht->table[i];
-        hash_node_t *p;
-
-        /* free in list */
-        while (n) {
-            if (n->key)
-                mem_d(n->key);
-            if (callback)
-                callback(n->value);
-            p = n;
-            n = n->next;
-            mem_d(p);
-        }
-
-    }
-    /* free table */
-    mem_d(ht->table);
-    mem_d(ht);
-}
-
-void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) {
-    hash_node_t **pair = &ht->table[bin];
-    hash_node_t *tmp;
-
-    while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0)
-        pair = &(*pair)->next;
-
-    tmp = *pair;
-    if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0)
-        return;
-
-    if (cb)
-        (*cb)(tmp->value);
-
-    *pair = tmp->next;
-    mem_d(tmp->key);
-    mem_d(tmp);
-}
-
-void util_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)) {
-    util_htrmh(ht, key, util_hthash(ht, key), cb);
-}
-
-void util_htdel(hash_table_t *ht) {
-    util_htrem(ht, NULL);
-}
-
 /*
  * Portable implementation of vasprintf/asprintf. Assumes vsnprintf
  * exists, otherwise compiler error.
@@ -845,7 +389,7 @@ int util_asprintf(char **ret, const char *fmt, ...) {
 static uint32_t mt_state[MT_SIZE];
 static size_t   mt_index = 0;
 
-static GMQCC_INLINE void mt_generate() {
+static GMQCC_INLINE void mt_generate(void) {
     /*
      * The loop has been unrolled here: the original paper and implemenation
      * Called for the following code: