]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'master' into threading
authorDale Weiler <killfieldengine@gmail.com>
Fri, 26 Jul 2013 13:58:45 +0000 (13:58 +0000)
committerDale Weiler <killfieldengine@gmail.com>
Fri, 26 Jul 2013 13:58:45 +0000 (13:58 +0000)
Conflicts:
Makefile
gmqcc.h
ir.c
ir.h
opts.def
parser.c

1  2 
Makefile
gmqcc.h
ir.c
ir.h
main.c
opts.c
opts.def
parser.c

diff --combined Makefile
index 3a215f298d06a0971a428c3a1459e34fd04b6836,2e5c1eea8323b4cac1b55e9933f8d22014c7baa6..cd26b16860d3b2b4430be6a0feb66c5434f4deeb
+++ b/Makefile
@@@ -1,16 -1,20 +1,10 @@@
--DESTDIR :=
--OPTIONAL:=
--PREFIX  := /usr/local
--BINDIR  := $(PREFIX)/bin
--DATADIR := $(PREFIX)/share
--MANDIR  := $(DATADIR)/man
++include include.mk
  
  UNAME  ?= $(shell uname)
  CYGWIN  = $(findstring CYGWIN,  $(UNAME))
  MINGW   = $(findstring MINGW32, $(UNAME))
  
- CC     ?= clang
- CFLAGS += -Wall -Wextra -Werror -I. -fno-strict-aliasing -fsigned-char -pthread $(OPTIONAL)
 -CC      ?= clang
 -# linker flags and optional additional libraries if required
 -LDFLAGS +=
 -LIBS    += -lm
 -
+ CFLAGS  += -Wall -Wextra -Werror -fno-strict-aliasing $(OPTIONAL)
  ifneq ($(shell git describe --always 2>/dev/null),)
      CFLAGS += -DGMQCC_GITINFO="\"$(shell git describe --always)\""
  endif
@@@ -25,28 -29,33 +19,29 @@@ ifeq ($(CC), clang
            -Wno-conversion                    \
            -Wno-missing-prototypes            \
            -Wno-float-equal                   \
-           -Wno-missing-variable-declarations \
-           -Wno-unknown-warning-option
+           -Wno-unknown-warning-option        \
 +          -Wno-cast-align                    \
+           -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 -ffunction-sections -fdata-sections -Wl,-gc-sections
 -              CFLAGS += -Wstrict-prototypes -pedantic-errors
++              CFLAGS += -pedantic-errors
        else
                CFLAGS += -Wno-pointer-sign -fno-common
        endif
++      
++      #-Wstrict-prototypes is not valid in g++
++      ifneq ($(CC), g++)
++              CFLAGS += -Wstrict-prototypes
++      endif
  endif
  
--ifeq ($(track), no)
--      CFLAGS += -DNOTRACK
--endif
--
- OBJ_D = util.o code.o ast.o ir.o thread.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))
++DEPS := $(call RMDUP, $(OBJ_P) $(OBJ_T) $(OBJ_C) $(OBJ_X))
  
  ifneq ("$(CYGWIN)", "")
        #nullify the common variables that
@@@ -58,7 -67,7 +53,7 @@@
        QCVM      = qcvm.exe
        GMQCC     = gmqcc.exe
        TESTSUITE = testsuite.exe
--      PAK       = pak.exe
++      PAK       = gmqpak.exe
  else
  ifneq ("$(MINGW)", "")
        #nullify the common variables that
        QCVM      = qcvm.exe
        GMQCC     = gmqcc.exe
        TESTSUITE = testsuite.exe
-       PAK       = pak.exe
+       PAK       = gmqpak.exe
  else
-       #arm support for linux .. we need to allow unaligned accesses
-       #to memory otherwise we just segfault everywhere
-       ifneq (, $(findstring arm, $(shell uname -m)))
-               CFLAGS += -munaligned-access
-       endif
        QCVM      = qcvm
        GMQCC     = gmqcc
        TESTSUITE = testsuite
-       PAK       = pak
+       PAK       = gmqpak
  endif
  endif
  
--#gource flags
--GOURCEFLAGS=                  \
--    --date-format "%d %B, %Y" \
--    --seconds-per-day 0.01    \
--    --auto-skip-seconds 1     \
--    --title "GMQCC"           \
--    --key                     \
--    --camera-mode overview    \
--    --highlight-all-users     \
--    --file-idle-time 0        \
--    --hide progress,mouse     \
--    --stop-at-end             \
--    --max-files 99999999999   \
--    --max-file-lag 0.000001   \
--    --bloom-multiplier 1.3    \
 -    --logo doc/html/gmqcc.png \
--    -1280x720
--
--#ffmpeg flags for gource
--FFMPEGFLAGS=                  \
--    -y                        \
--    -r 60                     \
--    -f image2pipe             \
--    -vcodec ppm               \
--    -i -                      \
--    -vcodec libx264           \
--    -preset ultrafast         \
--    -crf 1                    \
--    -threads 0                \
--    -bf 0
--
--#splint flags
--SPLINTFLAGS =            \
--    -redef               \
--    -noeffect            \
--    -nullderef           \
--    -usedef              \
--    -type                \
--    -mustfreeonly        \
--    -nullstate           \
--    -varuse              \
--    -mustfreefresh       \
--    -compdestroy         \
--    -compmempass         \
--    -nullpass            \
--    -onlytrans           \
--    -predboolint         \
--    -boolops             \
-     -exportlocal         \
--    -incondefs           \
--    -macroredef          \
--    -retvalint           \
--    -nullret             \
--    -predboolothers      \
--    -globstate           \
--    -dependenttrans      \
--    -branchstate         \
--    -compdef             \
--    -temptrans           \
--    -usereleased         \
--    -warnposix           \
-     -shiftimplementation \
--    +charindex           \
--    -kepttrans           \
--    -unqualifiedtrans    \
--    +matchanyintegral    \
--    +voidabstract        \
--    -nullassign          \
--    -unrecog             \
--    -casebreak           \
--    -retvalbool          \
--    -retvalother         \
--    -mayaliasunique      \
--    -realcompare         \
--    -observertrans       \
-     -shiftnegative       \
-     -freshtrans          \
--    -abstract            \
--    -statictrans         \
--    -castfcnptr
--
  #standard rules
--default: all
  %.o: %.c
-       $(CC) -c $< -o $@ $(CFLAGS)
+       $(CC) -c $< -o $@ $(CPPFLAGS) $(CFLAGS)
  
  exec-standalone.o: exec.c
-       $(CC) -c $< -o $@ $(CFLAGS) -DQCVM_EXECUTOR=1
+       $(CC) -c $< -o $@ $(CPPFLAGS) $(CFLAGS) -DQCVM_EXECUTOR=1
  
  $(QCVM): $(OBJ_X)
-       $(CC) -o $@ $^ $(CFLAGS) -lm
+       $(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
  
  $(GMQCC): $(OBJ_C) $(OBJ_D)
-       $(CC) -o $@ $^ $(CFLAGS) -lm -pthread
+       $(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
  
  $(TESTSUITE): $(OBJ_T)
-       $(CC) -o $@ $^ $(CFLAGS) -lm
+       $(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
  
  $(PAK): $(OBJ_P)
-       $(CC) -o $@ $^ $(CFLAGS)
+       $(CC) -o $@ $^ $(LDFLAGS)
  
  all: $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK)
  
@@@ -193,7 -193,7 +101,7 @@@ test: al
        @ ./$(TESTSUITE)
  
  clean:
-       rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat gource.mp4
 -      rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat gource.mp4 *.exe
++      rm -rf *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat gource.mp4 *.exe gm-qcc.tgz ./cov-int
  
  splint:
        @  splint $(SPLINTFLAGS) *.c *.h
@@@ -205,65 -205,49 +113,48 @@@ gource-record
        @ gource $(GOURCEFLAGS) -o - | ffmpeg $(FFMPEGFLAGS) gource.mp4
  
  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))
++      @ makedepend -Y -w 65536 2> /dev/null $(subst .o,.c,$(DEPS))
++
++
++coverity:
++      @cov-build --dir cov-int $(MAKE)
++      @tar czf gm-qcc.tgz cov-int
++      @rm -rf cov-int
++      @echo gm-qcc.tgz generated, submit for analysis
  
  #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    -m755  $(GMQCC)     $(DESTDIR)$(BINDIR)/$(GMQCC)
  install-qcvm: $(QCVM)
        install -d -m755               $(DESTDIR)$(BINDIR)
-       install    -m755  $(QCVM)      $(DESTDIR)$(BINDIR)/qcvm
+       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/
- uninstall:
-       rm $(DESTDIR)$(BINDIR)/gmqcc
-       rm $(DESTDIR)$(BINDIR)/qcvm
-       rm $(DESTDIR)$(MANDIR)/man1/doc/gmqcc.1
-       rm $(DESTDIR)$(MANDIR)/man1/doc/qcvm.1
+       install    -m644  doc/gmqpak.1 $(DESTDIR)$(MANDIR)/man1/
  
 -uninstall:
 -      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
  
  util.o: gmqcc.h opts.def
--code.o: gmqcc.h opts.def
--ast.o: gmqcc.h opts.def ast.h ir.h
--ir.o: gmqcc.h opts.def ir.h
++fs.o: gmqcc.h opts.def
  conout.o: gmqcc.h opts.def
--ftepp.o: gmqcc.h opts.def lexer.h
  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
++stat.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
++code.o: gmqcc.h opts.def
++ast.o: gmqcc.h opts.def ast.h ir.h
++ir.o: gmqcc.h opts.def ir.h
++ftepp.o: gmqcc.h opts.def lexer.h
++utf8.o: gmqcc.h opts.def
++correct.o: gmqcc.h opts.def
++thread.o: gmqcc.h opts.def
diff --combined gmqcc.h
index a9599ac9075d57b97c1736a3b9bdd0da6e8ce33f,d6055dbeedf2d27ac8e8a9061744302027fcb515..9a3e432f16b9677f818aef9c57a9e5e593a8e0b5
+++ 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
@@@ -36,7 -32,6 +32,6 @@@
   */
  #ifdef _MSC_VER
  #   pragma warning(disable : 4244 ) /* conversion from 'int' to 'float', possible loss of data */
- #   pragma warning(disable : 4018 ) /* signed/unsigned mismatch                                */
  #endif /*! _MSC_VER */
  
  #define GMQCC_VERSION_MAJOR 0
  #define GMQCC_VERSION_TYPE_DEVEL
  
  /* Full version string in case we need it */
- #ifdef GMQCC_GITINFO
- #    define GMQCC_DEV_VERSION_STRING "git build: " GMQCC_GITINFO "\n"
- #elif defined(GMQCC_VERSION_TYPE_DEVEL)
- #    define GMQCC_DEV_VERSION_STRING "development build\n"
+ #ifdef GMQCC_VERSION_TYPE_DEVEL
+ #    ifdef GMQCC_GITINFO
+ #        define GMQCC_DEV_VERSION_STRING "git build: " GMQCC_GITINFO "\n"
+ #    elif defined(GMQCC_VERSION_TYPE_DEVEL)
+ #        define GMQCC_DEV_VERSION_STRING "development build\n"
+ #    else
+ #        define GMQCC_DEV_VERSION_STRING
+ #    endif /*! GMQCC_GITINGO */
  #else
  #    define GMQCC_DEV_VERSION_STRING
- #endif /*! GMQCC_GITINGO */
+ #endif
  
  #define GMQCC_STRINGIFY(x) #x
  #define GMQCC_IND_STRING(x) GMQCC_STRINGIFY(x)
@@@ -168,17 -167,6 +167,6 @@@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) 
      typedef __int64          int64_t;
  #endif /*! _MSC_VER */
  
- /* 
-  *windows makes these prefixed because they're C99
-  * TODO: utility versions that are type-safe and not
-  * just plain textual subsitution.
-  */
- #ifdef _MSC_VER
- #    define snprintf(X, Y, Z, ...) _snprintf(X, Y, Z, __VA_ARGS__)
-     /* strtof doesn't exist -> strtod does though :) */
- #    define strtof(X, Y)          (float)(strtod(X, Y))
- #endif /*! _MSC_VER */
  /*
   * Very roboust way at determining endianess at compile time: this handles
   * almost every possible situation.  Otherwise a runtime check has to be
   * On windows systems where we're not compiling with MING32 we need a
   * little extra help on dependinces for implementing our own dirent.h
   * in fs.c.
-  */   
+  */
  #if defined(_WIN32) && !defined(__MINGW32__)
  #   define _WIN32_LEAN_AND_MEAN
  #   include <windows.h>
          unsigned short     d_reclen;
          unsigned short     d_namlen;
          char               d_name[FILENAME_MAX];
-     }
+     };
  
      typedef struct {
          struct _finddata_t dd_dta;
          int                dd_stat;
          char               dd_name[1];
      } DIR;
+     /*
+      * Visual studio also lacks S_ISDIR for sys/stat.h, so we emulate this as well
+      * which is not hard at all.
+      */
+ #    ifdef S_ISDIR
+ #        undef  S_ISDIR
+ #    endif /*! S_ISDIR */
+ #   define S_ISDIR(X) ((X)&_S_IFDIR)
  #else
  #   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,26 -317,20 +317,20 @@@ size_t util_strtononcmd (const char *, 
  uint16_t util_crc16(uint16_t crc, const char *data, size_t len);
  
  void     util_seed(uint32_t);
- uint32_t util_rand();
- int util_vasprintf(char **ret, const char *fmt, va_list);
- int util_asprintf (char **ret, const char *fmt, ...);
+ uint32_t util_rand(void);
  
- #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__)
+ /*
+  * String functions (formatting, copying, concatenating, errors). These are wrapped
+  * to use the MSVC _safe_ versions when using MSVC, plus some implementations of
+  * these are non-conformant or don't exist such as asprintf and snprintf, which are
+  * not supported in C90, but do exist in C99.
+  */
+ int         util_vasprintf(char **ret, const char *fmt, va_list);
+ int         util_asprintf (char **ret, const char *fmt, ...);
+ int         util_snprintf (char *src,  size_t bytes, const char *format, ...);
+ 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);
  
  /*
   * A flexible vector implementation: all vector pointers contain some
@@@ -355,7 -355,7 +355,7 @@@ void _util_vec_grow(void **a, size_t i
  )
  
  /* exposed interface */
- #define vec_meta(A)       (((vector_t*)(A)) - 1)
+ #define vec_meta(A)       (((vector_t*)((void*)A)) - 1)
  #define vec_free(A)       ((void)((A) ? (mem_d((void*)vec_meta(A)), (A) = NULL) : 0))
  #define vec_push(A,V)     (GMQCC_VEC_WILLGROW((A),1), (A)[vec_meta(A)->used++] = (V))
  #define vec_size(A)       ((A) ? vec_meta(A)->used : 0)
@@@ -373,21 -373,13 +373,13 @@@ 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;
      struct hash_node_t **table;
  } hash_table_t, *ht;
  
- typedef struct hash_set_t {
-     size_t  bits;
-     size_t  mask;
-     size_t  capacity;
-     size_t *items;
-     size_t  total;
- } hash_set_t, *hs;
  /*
   * hashtable implementation:
   *
@@@ -430,49 -422,6 +422,11 @@@ void          util_htrm  (hash_table_t 
  void         *util_htget (hash_table_t *ht, const char *key);
  void         *util_htgeth(hash_table_t *ht, const char *key, size_t hash);
  
- /*
-  * hashset implementation:
-  *      This was designed for pointers:  you manage the life of the object yourself
-  *      if you do use this for non-pointers please be warned that the object may not
-  *      be valid if the duration of it exceeds (i.e on stack).  So you need to allocate
-  *      yourself, or put those in global scope to ensure duration is for the whole
-  *      runtime.
-  *
-  * util_hsnew()                             -- to make a new hashset
-  * util_hsadd(set, key)                     -- to add something in the set
-  * util_hshas(set, key)                     -- to check if something is in the set
-  * util_hsrem(set, key)                     -- to remove something in the set
-  * util_hsdel(set)                          -- to delete the set
-  *
-  * example of use:
-  * 
-  * hs    foo = util_hsnew();
-  * char *bar = "hello blub\n";
-  * char *baz = "hello dale\n";
-  *
-  * util_hsadd(foo, bar);
-  * util_hsadd(foo, baz);
-  * util_hsrem(foo, baz);
-  *
-  * printf("bar %d | baz %d\n",
-  *     util_hshas(foo, bar),
-  *     util_hshad(foo, baz)
-  * );
-  *
-  * util_hsdel(foo);  
-  */
- hash_set_t *util_hsnew(void);
- int         util_hsadd(hash_set_t *, void *);
- int         util_hshas(hash_set_t *, void *);
- int         util_hsrem(hash_set_t *, void *);
- void        util_hsdel(hash_set_t *);
 +/*===================================================================*/
 +/*=========================== thread.c ==============================*/
 +/*===================================================================*/
 +GMQCC_INLINE uint32_t util_atomic_xadd32(volatile uint32_t *x, uint32_t v);
 +
  /*===================================================================*/
  /*============================ file.c ===============================*/
  /*===================================================================*/
@@@ -483,7 -432,7 +437,7 @@@ int            fs_file_getc   (FILE *)
  int            fs_file_printf (FILE *, const char *, ...);
  int            fs_file_puts   (FILE *, const char *);
  int            fs_file_seek   (FILE *, long int, int);
- long int       fs_file_tell   (FILE *); 
+ long int       fs_file_tell   (FILE *);
  
  size_t         fs_file_read   (void *,        size_t, size_t, FILE *);
  size_t         fs_file_write  (const void *,  size_t, size_t, FILE *);
@@@ -545,9 -494,9 +499,9 @@@ enum 
  #define CV_VAR   -1
  #define CV_WRONG  0x8000 /* magic number to help parsing */
  
- extern const char *type_name        [TYPE_COUNT];
- extern uint16_t    type_store_instr [TYPE_COUNT];
- extern uint16_t    field_store_instr[TYPE_COUNT];
+ extern const char    *type_name        [TYPE_COUNT];
+ extern const uint16_t type_store_instr [TYPE_COUNT];
+ extern const uint16_t field_store_instr[TYPE_COUNT];
  
  /*
   * could use type_store_instr + INSTR_STOREP_F - INSTR_STORE_F
   * instruction set, the old ones are left untouched, thus the _I instructions
   * are at a seperate place.
   */
- extern uint16_t type_storep_instr[TYPE_COUNT];
- extern uint16_t type_eq_instr    [TYPE_COUNT];
- extern uint16_t type_ne_instr    [TYPE_COUNT];
- extern uint16_t type_not_instr   [TYPE_COUNT];
+ extern const uint16_t type_storep_instr[TYPE_COUNT];
+ extern const uint16_t type_eq_instr    [TYPE_COUNT];
+ extern const uint16_t type_ne_instr    [TYPE_COUNT];
+ extern const uint16_t type_not_instr   [TYPE_COUNT];
  
  typedef struct {
      uint32_t offset;      /* Offset in file of where data begins  */
@@@ -748,32 -697,40 +702,40 @@@ enum 
      VINSTR_NRCALL
  };
  
- /* TODO: cleanup this mess */
- extern prog_section_statement *code_statements;
- extern int                    *code_linenums;
- extern prog_section_def       *code_defs;
- extern prog_section_field     *code_fields;
- extern prog_section_function  *code_functions;
- extern int                    *code_globals;
- extern char                   *code_chars;
- extern uint16_t code_crc;
  /* uhh? */
  typedef float   qcfloat;
  typedef int32_t qcint;
  
+ typedef struct {
+     prog_section_statement *statements;
+     int                    *linenums;
+     prog_section_def       *defs;
+     prog_section_field     *fields;
+     prog_section_function  *functions;
+     int                    *globals;
+     char                   *chars;
+     uint16_t                crc;
+     uint32_t                entfields;
+     ht                      string_cache;
+     qcint                   string_cached_empty;
+ } code_t;
  /*
-  * code_write -- writes out the compiled file
-  * code_init  -- prepares the code file
+  * code_write          -- writes out the compiled file
+  * code_init           -- prepares the code file
+  * code_genstrin       -- generates string for code
+  * code_alloc_field    -- allocated a field
+  * code_push_statement -- keeps statements and linenumbers together
+  * code_pop_statement  -- keeps statements and linenumbers together 
   */
- bool     code_write       (const char *filename, const char *lno);
- void     code_init        ();
uint32_t code_genstring   (const char *string);
qcint    code_alloc_field (size_t qcsize);
- /* this function is used to keep statements and linenumbers together */
- void     code_push_statement(prog_section_statement *stmt, int linenum);
- void     code_pop_statement();
+ 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);
+ void      code_pop_statement (code_t *);
  
  /*
   * A shallow copy of a lex_file to remember where which ast node
  typedef struct {
      const char *file;
      size_t      line;
+     size_t      column;
  } lex_ctx;
  
  /*===================================================================*/
@@@ -805,17 -763,17 +768,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);
@@@ -832,7 -790,7 +795,7 @@@ void /********/ compile_error   (lex_ct
  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 =============================*/
@@@ -1026,7 -984,7 +989,7 @@@ void        prog_delete(qc_program *pro
  
  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);
@@@ -1037,8 -995,7 +1000,7 @@@ qcint             prog_tempstring(qc_pr
  /*===================== 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 *);
@@@ -1047,21 -1004,8 +1009,8 @@@ void             parser_cleanup       (
  /*===================================================================*/
  /*====================== ftepp.c commandline ========================*/
  /*===================================================================*/
- struct lex_file_s;
  struct ftepp_s;
- typedef struct {
-     const char  *name;
-     char      *(*func)(struct lex_file_s *);
- } ftepp_predef_t;
- /*
-  * line, file, counter, counter_last, random, random_last, date, time
-  * increment when items are added
-  */
- #define FTEPP_PREDEF_COUNT 8
- 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);
@@@ -1070,8 -1014,6 +1019,6 @@@ void            ftepp_flush            
  void            ftepp_add_define       (struct ftepp_s *ftepp, const char *source, const char *name);
  void            ftepp_add_macro        (struct ftepp_s *ftepp, const char *name,   const char *value);
  
- extern const ftepp_predef_t ftepp_predefs[FTEPP_PREDEF_COUNT];
  /*===================================================================*/
  /*======================= main.c commandline ========================*/
  /*===================================================================*/
@@@ -1123,10 -1065,10 +1070,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
@@@ -1211,7 -1153,7 +1158,7 @@@ typedef struct 
  
  extern opts_cmd_t opts;
  
- #define OPTS_GENERIC(f,i)    (!! (((f)[(i)/32]) & (1<< ((i)%32))))
+ #define OPTS_GENERIC(f,i)    (!! (((f)[(i)/32]) & (1<< (unsigned)((i)%32))))
  #define OPTS_FLAG(i)         OPTS_GENERIC(opts.flags,        (i))
  #define OPTS_WARN(i)         OPTS_GENERIC(opts.warn,         (i))
  #define OPTS_WERROR(i)       OPTS_GENERIC(opts.werror,       (i))
diff --combined ir.c
index a65b015e33e952dc26e68ba3d10768a529d9a452,fcf4caaf9decb7b66587c3a3f05f9b97bc3e01a6..5e885872876327ea17a9325b79a4a527800d9d67
--- 1/ir.c
--- 2/ir.c
+++ b/ir.c
@@@ -1,6 -1,7 +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 +23,7 @@@
   */
  #include <stdlib.h>
  #include <string.h>
  #include "gmqcc.h"
  #include "ir.h"
  
@@@ -48,7 -50,7 +50,7 @@@ const char *type_name[TYPE_COUNT] = 
      "<no-expression>"
  };
  
- size_t type_sizeof_[TYPE_COUNT] = {
+ static size_t type_sizeof_[TYPE_COUNT] = {
      1, /* TYPE_VOID     */
      1, /* TYPE_STRING   */
      1, /* TYPE_FLOAT    */
@@@ -66,7 -68,7 +68,7 @@@
      0, /* TYPE_NOESPR   */
  };
  
- uint16_t type_store_instr[TYPE_COUNT] = {
const uint16_t type_store_instr[TYPE_COUNT] = {
      INSTR_STORE_F, /* should use I when having integer support */
      INSTR_STORE_S,
      INSTR_STORE_F,
@@@ -90,7 -92,7 +92,7 @@@
      VINSTR_END, /* noexpr */
  };
  
- uint16_t field_store_instr[TYPE_COUNT] = {
const uint16_t field_store_instr[TYPE_COUNT] = {
      INSTR_STORE_FLD,
      INSTR_STORE_FLD,
      INSTR_STORE_FLD,
      VINSTR_END, /* noexpr */
  };
  
- uint16_t type_storep_instr[TYPE_COUNT] = {
const uint16_t type_storep_instr[TYPE_COUNT] = {
      INSTR_STOREP_F, /* should use I when having integer support */
      INSTR_STOREP_S,
      INSTR_STOREP_F,
      VINSTR_END, /* noexpr */
  };
  
- uint16_t type_eq_instr[TYPE_COUNT] = {
const uint16_t type_eq_instr[TYPE_COUNT] = {
      INSTR_EQ_F, /* should use I when having integer support */
      INSTR_EQ_S,
      INSTR_EQ_F,
      VINSTR_END, /* noexpr */
  };
  
- uint16_t type_ne_instr[TYPE_COUNT] = {
const uint16_t type_ne_instr[TYPE_COUNT] = {
      INSTR_NE_F, /* should use I when having integer support */
      INSTR_NE_S,
      INSTR_NE_F,
      VINSTR_END, /* noexpr */
  };
  
- uint16_t type_not_instr[TYPE_COUNT] = {
const uint16_t type_not_instr[TYPE_COUNT] = {
      INSTR_NOT_F, /* should use I when having integer support */
-     INSTR_NOT_S,
+     VINSTR_END,  /* not to be used, depends on string related -f flags */
      INSTR_NOT_F,
      INSTR_NOT_V,
      INSTR_NOT_ENT,
  };
  
  /* protos */
- static void      ir_gen_extparam      (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 void            ir_gen_extparam      (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, ...)
@@@ -237,7 -262,7 +262,7 @@@ static bool irwarning(lex_ctx ctx, int 
   * 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);
      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);
      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);
@@@ -308,7 -333,6 +333,6 @@@ ir_builder* ir_builder_new(const char *
      self->max_globaltemps         = 0;
      self->first_common_local      = 0;
      self->max_locals              = 0;
-     self->max_used_params         = 0;
  
      self->str_immediate = 0;
      self->name = NULL;
          return NULL;
      }
  
-     self->nil = ir_value_var("nil", store_global, TYPE_NIL);
+     self->nil = ir_value_var("nil", store_value, TYPE_NIL);
      self->nil->cvq = CV_CONST;
-     self->nil->untracked = true;
  
      self->reserved_va_count = NULL;
++    self->code              = code_init();
  
      return self;
  }
@@@ -341,6 -364,7 +365,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]);
      }
      vec_free(self->fields);
      vec_free(self->filenames);
      vec_free(self->filestrings);
++
++    code_cleanup(self->code);
      mem_d(self);
  }
  
@@@ -363,7 -387,7 +390,7 @@@ bool ir_builder_set_name(ir_builder *se
      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);
  }
@@@ -398,7 -422,7 +425,7 @@@ ir_function* ir_builder_create_function
      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);
  }
@@@ -423,14 -447,12 +450,12 @@@ ir_value* ir_builder_create_global(ir_b
  
  ir_value* ir_builder_get_va_count(ir_builder *self)
  {
-     if (!self->reserved_va_count) {
-         self->reserved_va_count = ir_builder_create_global(self, "reserved:va_count", TYPE_FLOAT);
-         self->reserved_va_count->untracked = true;
-     }
-     return self->reserved_va_count;
+     if (self->reserved_va_count)
+         return self->reserved_va_count;
+     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);
  }
@@@ -454,10 -476,10 +479,10 @@@ ir_value* ir_builder_create_field(ir_bu
   *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)
  {
@@@ -554,7 -576,7 +579,7 @@@ void ir_function_delete(ir_function *se
      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);
  }
@@@ -577,7 -599,7 +602,7 @@@ static bool instr_is_operation(uint16_
               (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;
  
      return true;
  }
  
- bool ir_function_pass_tailrecursion(ir_function *self)
static bool ir_function_pass_tailrecursion(ir_function *self)
  {
      size_t b, p;
  
      return true;
  }
  
- bool ir_function_optimize(ir_function *self)
+ bool ir_function_finalize(ir_function *self)
  {
+     size_t i;
      if (self->builtin)
          return true;
  
          irerror(self->context, "internal error: ir_function_naive_phi failed");
          return false;
      }
-     return true;
- }
- bool ir_function_finalize(ir_function *self)
- {
-     size_t i;
-     if (self->builtin)
-         return true;
  
      for (i = 0; i < vec_size(self->locals); ++i) {
          ir_value *v = self->locals[i];
@@@ -936,7 -951,7 +954,7 @@@ bool ir_block_set_label(ir_block *self
   *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));
@@@ -968,7 -983,7 +986,7 @@@ static void ir_instr_delete_quick(ir_in
      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
       */
      for (i = 0; i < vec_size(self->phi); ++i) {
          size_t idx;
-         if (self->phi[i].value->untracked)
-             continue;
          if (vec_ir_instr_find(self->phi[i].value->writes, self, &idx))
              vec_remove(self->phi[i].value->writes, idx, 1);
          if (vec_ir_instr_find(self->phi[i].value->reads, self, &idx))
      vec_free(self->phi);
      for (i = 0; i < vec_size(self->params); ++i) {
          size_t idx;
-         if (self->params[i]->untracked)
-             continue;
          if (vec_ir_instr_find(self->params[i]->writes, self, &idx))
              vec_remove(self->params[i]->writes, idx, 1);
          if (vec_ir_instr_find(self->params[i]->reads, self, &idx))
      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)
  {
-     ir_value *old = self->_ops[op];
-     if (old && !old->untracked) {
+     if (self->_ops[op]) {
          size_t idx;
-         if (writing && vec_ir_instr_find(old->writes, self, &idx))
-             vec_remove(old->writes, idx, 1);
-         else if (vec_ir_instr_find(old->reads, self, &idx))
-             vec_remove(old->reads, idx, 1);
+         if (writing && vec_ir_instr_find(self->_ops[op]->writes, self, &idx))
+             vec_remove(self->_ops[op]->writes, idx, 1);
+         else if (vec_ir_instr_find(self->_ops[op]->reads, self, &idx))
+             vec_remove(self->_ops[op]->reads, idx, 1);
      }
-     if (v && !v->untracked) {
+     if (v) {
          if (writing)
              vec_push(v->writes, self);
          else
   *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;
      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;
@@@ -1052,9 -1062,8 +1065,8 @@@ ir_value* ir_value_var(const char *name
      self->store = storetype;
      self->flags = 0;
  
-     self->reads     = NULL;
-     self->writes    = NULL;
-     self->untracked = false;
+     self->reads  = NULL;
+     self->writes = NULL;
  
      self->cvq          = CV_NONE;
      self->hasvalue     = false;
@@@ -1149,7 -1158,7 +1161,7 @@@ static GMQCC_INLINE size_t ir_value_siz
      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)
@@@ -1256,7 -1265,7 +1268,7 @@@ bool ir_value_lives(ir_value *self, siz
      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);
      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);
      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;
  
      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.
@@@ -1499,7 -1508,7 +1511,7 @@@ bool ir_block_create_store_op(ir_block 
      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;
@@@ -1661,8 -1670,7 +1673,7 @@@ void ir_phi_add(ir_instr* self, ir_bloc
  
      pe.value = v;
      pe.from = b;
-     if (!v->untracked)
-         vec_push(v->reads, self);
+     vec_push(v->reads, self);
      vec_push(self->phi, pe);
  }
  
@@@ -1712,15 -1720,8 +1723,8 @@@ ir_value* ir_call_value(ir_instr *self
  
  void ir_call_param(ir_instr* self, ir_value *v)
  {
-     size_t *maxparams, param;
      vec_push(self->params, v);
-     if (!v->untracked)
-         vec_push(v->reads, self);
-     param = vec_size(self->params);
-     maxparams = &self->owner->owner->owner->max_used_params;
-     if (param > *maxparams)
-         *maxparams = param;
+     vec_push(v->reads, self);
  }
  
  /* binary op related code */
@@@ -1796,14 -1797,14 +1800,33 @@@ ir_value* ir_block_create_binop(ir_bloc
              ot = TYPE_POINTER;
              break;
  #endif
++    /*
++     * after the following default case, the value of opcode can never
++     * be 1, 2, 3, 4, 5, 6, 7, 8, 9, 62, 63, 64, 65
++     */
          default:
              /* ranges: */
              /* boolean operations result in floats */
++            
++            /*
++             * opcode >= 10 takes true branch opcode is at least 10
++             * opcode <= 23 takes false branch opcode is at least 24
++             */
              if (opcode >= INSTR_EQ_F && opcode <= INSTR_GT)
                  ot = TYPE_FLOAT;
++                
++            /* 
++             * At condition "opcode <= 23", the value of "opcode" must be 
++             * at least 24.
++             * At condition "opcode <= 23", the value of "opcode" cannot be
++             * equal to any of {1, 2, 3, 4, 5, 6, 7, 8, 9, 62, 63, 64, 65}.
++             * The condition "opcode <= 23" cannot be true.
++             * 
++             * Thus ot=2 (TYPE_FLOAT) can never be true
++             */
++#if 0
              else if (opcode >= INSTR_LE && opcode <= INSTR_GT)
                  ot = TYPE_FLOAT;
--#if 0
              else if (opcode >= INSTR_LE_I && opcode <= INSTR_EQ_FI)
                  ot = TYPE_FLOAT;
  #endif
@@@ -1850,7 -1851,7 +1873,7 @@@ ir_value* ir_block_create_unary(ir_bloc
      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;
@@@ -2195,7 -2196,17 +2218,17 @@@ bool ir_function_allocate_locals(ir_fun
                  if (param < 8)
                      ir_value_code_setaddr(v, OFS_PARM0 + 3*param);
                  else {
-                     ir_value *ep = self->owner->extparam_protos[param-=8];
+                     size_t nprotos = vec_size(self->owner->extparam_protos);
+                     ir_value *ep;
+                     param -= 8;
+                     if (nprotos > param)
+                         ep = self->owner->extparam_protos[param];
+                     else
+                     {
+                         ep = ir_gen_extparam_proto(self->owner);
+                         while (++nprotos <= param)
+                             ep = ir_gen_extparam_proto(self->owner);
+                     }
                      ir_instr_op(v->writes[0], 0, ep, true);
                      call->params[param+8] = ep;
                  }
@@@ -2453,30 -2464,20 +2486,20 @@@ static bool ir_block_life_propagate(ir_
          if (instr->opcode == INSTR_MUL_VF)
          {
              value = instr->_ops[2];
-             if (value->store == store_value ||
-                 value->store == store_local ||
-                 value->store == store_param)
-             {
-                 /* the float source will get an additional lifetime */
-                 if (ir_value_life_merge(value, instr->eid+1))
-                     *changed = true;
-                 if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1))
-                     *changed = true;
-             }
+             /* the float source will get an additional lifetime */
+             if (ir_value_life_merge(value, instr->eid+1))
+                 *changed = true;
+             if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1))
+                 *changed = true;
          }
          else if (instr->opcode == INSTR_MUL_FV || instr->opcode == INSTR_LOAD_V)
          {
              value = instr->_ops[1];
-             if (value->store == store_value ||
-                 value->store == store_local ||
-                 value->store == store_param)
-             {
-                 /* the float source will get an additional lifetime */
-                 if (ir_value_life_merge(value, instr->eid+1))
-                     *changed = true;
-                 if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1))
-                     *changed = true;
-             }
+             /* the float source will get an additional lifetime */
+             if (ir_value_life_merge(value, instr->eid+1))
+                 *changed = true;
+             if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1))
+                 *changed = true;
          }
  
          for (o = 0; o < 3; ++o)
          for (p = 0; p < vec_size(instr->phi); ++p)
          {
              value = instr->phi[p].value;
-             if (value->store != store_value &&
-                 value->store != store_local &&
-                 value->store != store_param)
-                 continue;
              if (!vec_ir_value_find(self->living, value, NULL))
                  vec_push(self->living, value);
              /* reading adds the full vector */
          for (p = 0; p < vec_size(instr->params); ++p)
          {
              value = instr->params[p];
-             if (value->store != store_value &&
-                 value->store != store_local &&
-                 value->store != store_param)
-                 continue;
              if (!vec_ir_value_find(self->living, value, NULL))
                  vec_push(self->living, value);
              /* reading adds the full vector */
@@@ -2569,7 -2562,7 +2584,8 @@@ bool ir_function_calculate_liferanges(i
  
      /* parameters live at 0 */
      for (i = 0; i < vec_size(self->params); ++i)
--        ir_value_life_merge(self->locals[i], 0);
++        if (!ir_value_life_merge(self->locals[i], 0))
++            compile_error(self->context, "internal error: failed value-life merging");
  
      do {
          self->run_id++;
   *
   * Breaking conventions is annoying...
   */
 -static bool ir_builder_gen_global(code_t *, ir_builder *self, ir_value *global, bool islocal);
 +static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal);
  
- static bool gen_global_field(ir_value *global)
+ static bool gen_global_field(code_t *code, ir_value *global)
  {
      if (global->hasvalue)
      {
          }
  
          /* copy the field's value */
-         ir_value_code_setaddr(global, vec_size(code_globals));
-         vec_push(code_globals, fld->code.fieldaddr);
+         ir_value_code_setaddr(global, vec_size(code->globals));
+         vec_push(code->globals, fld->code.fieldaddr);
          if (global->fieldtype == TYPE_VECTOR) {
-             vec_push(code_globals, fld->code.fieldaddr+1);
-             vec_push(code_globals, fld->code.fieldaddr+2);
+             vec_push(code->globals, fld->code.fieldaddr+1);
+             vec_push(code->globals, fld->code.fieldaddr+2);
          }
      }
      else
      {
-         ir_value_code_setaddr(global, vec_size(code_globals));
-         vec_push(code_globals, 0);
+         ir_value_code_setaddr(global, vec_size(code->globals));
+         vec_push(code->globals, 0);
          if (global->fieldtype == TYPE_VECTOR) {
-             vec_push(code_globals, 0);
-             vec_push(code_globals, 0);
+             vec_push(code->globals, 0);
+             vec_push(code->globals, 0);
          }
      }
      if (global->code.globaladdr < 0)
      return true;
  }
  
- static bool gen_global_pointer(ir_value *global)
+ static bool gen_global_pointer(code_t *code, ir_value *global)
  {
      if (global->hasvalue)
      {
              return false;
          }
  
-         ir_value_code_setaddr(global, vec_size(code_globals));
-         vec_push(code_globals, target->code.globaladdr);
+         ir_value_code_setaddr(global, vec_size(code->globals));
+         vec_push(code->globals, target->code.globaladdr);
      }
      else
      {
-         ir_value_code_setaddr(global, vec_size(code_globals));
-         vec_push(code_globals, 0);
+         ir_value_code_setaddr(global, vec_size(code->globals));
+         vec_push(code->globals, 0);
      }
      if (global->code.globaladdr < 0)
          return false;
      return true;
  }
  
- static bool gen_blocks_recursive(ir_function *func, ir_block *block)
+ static bool gen_blocks_recursive(code_t *code, ir_function *func, ir_block *block)
  {
      prog_section_statement stmt;
      ir_instr *instr;
      size_t    i;
  
      block->generated = true;
-     block->code_start = vec_size(code_statements);
+     block->code_start = vec_size(code->statements);
      for (i = 0; i < vec_size(block->instr); ++i)
      {
          instr = block->instr[i];
               * yet, we generate them right here.
               */
              if (!target->generated)
-                 return gen_blocks_recursive(func, target);
+                 return gen_blocks_recursive(code, func, target);
  
              /* otherwise we generate a jump instruction */
              stmt.opcode = INSTR_GOTO;
-             stmt.o1.s1 = (target->code_start) - vec_size(code_statements);
+             stmt.o1.s1 = (target->code_start) - vec_size(code->statements);
              stmt.o2.s1 = 0;
              stmt.o3.s1 = 0;
              if (stmt.o1.s1 != 1)
-                 code_push_statement(&stmt, instr->context.line);
+                 code_push_statement(code, &stmt, instr->context.line);
  
              /* no further instructions can be in this block */
              return true;
  
              if (ontrue->generated) {
                  stmt.opcode = INSTR_IF;
-                 stmt.o2.s1 = (ontrue->code_start) - vec_size(code_statements);
+                 stmt.o2.s1 = (ontrue->code_start) - vec_size(code->statements);
                  if (stmt.o2.s1 != 1)
-                     code_push_statement(&stmt, instr->context.line);
+                     code_push_statement(code, &stmt, instr->context.line);
              }
              if (onfalse->generated) {
                  stmt.opcode = INSTR_IFNOT;
-                 stmt.o2.s1 = (onfalse->code_start) - vec_size(code_statements);
+                 stmt.o2.s1 = (onfalse->code_start) - vec_size(code->statements);
                  if (stmt.o2.s1 != 1)
-                     code_push_statement(&stmt, instr->context.line);
+                     code_push_statement(code, &stmt, instr->context.line);
              }
              if (!ontrue->generated) {
                  if (onfalse->generated)
-                     return gen_blocks_recursive(func, ontrue);
+                     return gen_blocks_recursive(code, func, ontrue);
              }
              if (!onfalse->generated) {
                  if (ontrue->generated)
-                     return gen_blocks_recursive(func, onfalse);
+                     return gen_blocks_recursive(code, func, onfalse);
              }
              /* neither ontrue nor onfalse exist */
              stmt.opcode = INSTR_IFNOT;
                  onfalse = ontrue;
                  ontrue = tmp;
              }
-             stidx = vec_size(code_statements);
-             code_push_statement(&stmt, instr->context.line);
+             stidx = vec_size(code->statements);
+             code_push_statement(code, &stmt, instr->context.line);
              /* on false we jump, so add ontrue-path */
-             if (!gen_blocks_recursive(func, ontrue))
+             if (!gen_blocks_recursive(code, func, ontrue))
                  return false;
              /* fixup the jump address */
-             code_statements[stidx].o2.s1 = vec_size(code_statements) - stidx;
+             code->statements[stidx].o2.s1 = vec_size(code->statements) - stidx;
              /* generate onfalse path */
              if (onfalse->generated) {
                  /* fixup the jump address */
-                 code_statements[stidx].o2.s1 = (onfalse->code_start) - (stidx);
-                 if (stidx+2 == vec_size(code_statements) && code_statements[stidx].o2.s1 == 1) {
-                     code_statements[stidx] = code_statements[stidx+1];
-                     if (code_statements[stidx].o1.s1 < 0)
-                         code_statements[stidx].o1.s1++;
-                     code_pop_statement();
+                 code->statements[stidx].o2.s1 = (onfalse->code_start) - (stidx);
+                 if (stidx+2 == vec_size(code->statements) && code->statements[stidx].o2.s1 == 1) {
+                     code->statements[stidx] = code->statements[stidx+1];
+                     if (code->statements[stidx].o1.s1 < 0)
+                         code->statements[stidx].o1.s1++;
+                     code_pop_statement(code);
                  }
-                 stmt.opcode = vec_last(code_statements).opcode;
+                 stmt.opcode = vec_last(code->statements).opcode;
                  if (stmt.opcode == INSTR_GOTO ||
                      stmt.opcode == INSTR_IF ||
                      stmt.opcode == INSTR_IFNOT ||
                  }
                  /* may have been generated in the previous recursive call */
                  stmt.opcode = INSTR_GOTO;
-                 stmt.o1.s1 = (onfalse->code_start) - vec_size(code_statements);
+                 stmt.o1.s1 = (onfalse->code_start) - vec_size(code->statements);
                  stmt.o2.s1 = 0;
                  stmt.o3.s1 = 0;
                  if (stmt.o1.s1 != 1)
-                     code_push_statement(&stmt, instr->context.line);
+                     code_push_statement(code, &stmt, instr->context.line);
                  return true;
              }
-             else if (stidx+2 == vec_size(code_statements) && code_statements[stidx].o2.s1 == 1) {
-                 code_statements[stidx] = code_statements[stidx+1];
-                 if (code_statements[stidx].o1.s1 < 0)
-                     code_statements[stidx].o1.s1++;
-                 code_pop_statement();
+             else if (stidx+2 == vec_size(code->statements) && code->statements[stidx].o2.s1 == 1) {
+                 code->statements[stidx] = code->statements[stidx+1];
+                 if (code->statements[stidx].o1.s1 < 0)
+                     code->statements[stidx].o1.s1++;
+                 code_pop_statement(code);
              }
              /* if not, generate now */
-             return gen_blocks_recursive(func, onfalse);
+             return gen_blocks_recursive(code, func, onfalse);
          }
  
          if ( (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8)
                      stmt.opcode = type_store_instr[param->vtype];
                  stmt.o1.u1 = ir_value_code_addr(param);
                  stmt.o2.u1 = OFS_PARM0 + 3 * p;
-                 code_push_statement(&stmt, instr->context.line);
+                 code_push_statement(code, &stmt, instr->context.line);
              }
              /* Now handle extparams */
              first = vec_size(instr->params);
                      continue;
  
                  if (p-8 >= vec_size(ir->extparams))
 -                    ir_gen_extparam(code, ir);
 +                    ir_gen_extparam(ir);
  
                  targetparam = ir->extparams[p-8];
  
                      stmt.opcode = type_store_instr[param->vtype];
                  stmt.o1.u1 = ir_value_code_addr(param);
                  stmt.o2.u1 = ir_value_code_addr(targetparam);
-                 code_push_statement(&stmt, instr->context.line);
+                 code_push_statement(code, &stmt, instr->context.line);
              }
  
              stmt.opcode = INSTR_CALL0 + vec_size(instr->params);
              stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
              stmt.o2.u1 = 0;
              stmt.o3.u1 = 0;
-             code_push_statement(&stmt, instr->context.line);
+             code_push_statement(code, &stmt, instr->context.line);
  
              retvalue = instr->_ops[0];
              if (retvalue && retvalue->store != store_return &&
                  stmt.o1.u1 = OFS_RETURN;
                  stmt.o2.u1 = ir_value_code_addr(retvalue);
                  stmt.o3.u1 = 0;
-                 code_push_statement(&stmt, instr->context.line);
+                 code_push_statement(code, &stmt, instr->context.line);
              }
              continue;
          }
              }
          }
  
-         code_push_statement(&stmt, instr->context.line);
+         code_push_statement(code, &stmt, instr->context.line);
      }
      return true;
  }
  
- static bool gen_function_code(ir_function *self)
+ static bool gen_function_code(code_t *code, ir_function *self)
  {
      ir_block *block;
      prog_section_statement stmt, *retst;
      if (block->generated)
          return true;
  
-     if (!gen_blocks_recursive(self, block)) {
+     if (!gen_blocks_recursive(code, self, block)) {
          irerror(self->context, "failed to generate blocks for '%s'", self->name);
          return false;
      }
  
      /* code_write and qcvm -disasm need to know that the function ends here */
-     retst = &vec_last(code_statements);
+     retst = &vec_last(code->statements);
      if (OPTS_OPTIMIZATION(OPTIM_VOID_RETURN) &&
          self->outtype == TYPE_VOID &&
          retst->opcode == INSTR_RETURN &&
          stmt.o1.u1 = 0;
          stmt.o2.u1 = 0;
          stmt.o3.u1 = 0;
-         code_push_statement(&stmt, vec_last(code_linenums));
+         code_push_statement(code, &stmt, vec_last(code->linenums));
      }
      return true;
  }
  
 -static qcint ir_builder_filestring(code_t *code, ir_builder *ir, const char *filename)
 +static qcint ir_builder_filestring(ir_builder *ir, const char *filename)
  {
      /* NOTE: filename pointers are copied, we never strdup them,
       * thus we can use pointer-comparison to find the string.
              return ir->filestrings[i];
      }
  
-     str = code_genstring(filename);
 -    str = code_genstring(code, filename);
++    str = code_genstring(ir->code, filename);
      vec_push(ir->filenames, filename);
      vec_push(ir->filestrings, str);
      return str;
  }
  
 -static bool gen_global_function(code_t *code, ir_builder *ir, ir_value *global)
 +static bool gen_global_function(ir_builder *ir, ir_value *global)
  {
      prog_section_function fun;
      ir_function          *irfun;
      irfun = global->constval.vfunc;
  
      fun.name    = global->code.name;
 -    fun.file    = ir_builder_filestring(code, ir, global->context.file);
 +    fun.file    = ir_builder_filestring(ir, global->context.file);
      fun.profile = 0; /* always 0 */
      fun.nargs   = vec_size(irfun->params);
      if (fun.nargs > 8)
      if (irfun->builtin)
          fun.entry = irfun->builtin+1;
      else {
-         irfun->code_function_def = vec_size(code_functions);
-         fun.entry = vec_size(code_statements);
 -        irfun->code_function_def = vec_size(code->functions);
 -        fun.entry                = vec_size(code->statements);
++        irfun->code_function_def = vec_size(ir->code->functions);
++        fun.entry                = vec_size(ir->code->statements);
      }
  
-     vec_push(code_functions, fun);
 -    vec_push(code->functions, fun);
++    vec_push(ir->code->functions, fun);
      return true;
  }
  
@@@ -3091,15 -3084,14 +3107,14 @@@ static ir_value* ir_gen_extparam_proto(
      ir_value *global;
      char      name[128];
  
-     snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos)));
+     util_snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos)));
      global = ir_value_var(name, store_global, TYPE_VECTOR);
-     global->untracked = true;
  
      vec_push(ir->extparam_protos, global);
      return global;
  }
  
 -static void ir_gen_extparam(code_t *code, ir_builder *ir)
 +static void ir_gen_extparam(ir_builder *ir)
  {
      prog_section_def def;
      ir_value        *global;
      else
          global = ir->extparam_protos[vec_size(ir->extparams)];
  
-     def.name = code_genstring(global->name);
-     def.type = TYPE_VECTOR;
-     def.offset = vec_size(code_globals);
 -    def.name   = code_genstring(code, global->name);
++    def.name   = code_genstring(ir->code, global->name);
+     def.type   = TYPE_VECTOR;
 -    def.offset = vec_size(code->globals);
++    def.offset = vec_size(ir->code->globals);
 -    vec_push(code->defs, def);
++    vec_push(ir->code->defs, def);
  
-     vec_push(code_defs, def);
      ir_value_code_setaddr(global, def.offset);
-     vec_push(code_globals, 0);
-     vec_push(code_globals, 0);
-     vec_push(code_globals, 0);
 -    vec_push(code->globals, 0);
 -    vec_push(code->globals, 0);
 -    vec_push(code->globals, 0);
++    vec_push(ir->code->globals, 0);
++    vec_push(ir->code->globals, 0);
++    vec_push(ir->code->globals, 0);
  
      vec_push(ir->extparams, global);
  }
  
- static bool gen_function_extparam_copy(ir_function *self)
+ static bool gen_function_extparam_copy(code_t *code, ir_function *self)
  {
      size_t i, ext, numparams;
  
      for (i = 8; i < numparams; ++i) {
          ext = i - 8;
          if (ext >= vec_size(ir->extparams))
 -            ir_gen_extparam(code, ir);
 +            ir_gen_extparam(ir);
  
          ep = ir->extparams[ext];
  
          }
          stmt.o1.u1 = ir_value_code_addr(ep);
          stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
-         code_push_statement(&stmt, self->context.line);
+         code_push_statement(code, &stmt, self->context.line);
      }
  
      return true;
  }
  
- static bool gen_function_varargs_copy(ir_function *self)
+ static bool gen_function_varargs_copy(code_t *code, ir_function *self)
  {
      size_t i, ext, numparams, maxparams;
  
          if (i < 8) {
              stmt.o1.u1 = OFS_PARM0 + 3*i;
              stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
-             code_push_statement(&stmt, self->context.line);
+             code_push_statement(code, &stmt, self->context.line);
              continue;
          }
          ext = i - 8;
          while (ext >= vec_size(ir->extparams))
 -            ir_gen_extparam(code, ir);
 +            ir_gen_extparam(ir);
  
          ep = ir->extparams[ext];
  
          stmt.o1.u1 = ir_value_code_addr(ep);
          stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
-         code_push_statement(&stmt, self->context.line);
+         code_push_statement(code, &stmt, self->context.line);
      }
  
      return true;
  }
  
 -static bool gen_function_locals(code_t *code, ir_builder *ir, ir_value *global)
 +static bool gen_function_locals(ir_builder *ir, ir_value *global)
  {
      prog_section_function *def;
      ir_function           *irfun;
      uint32_t               firstlocal, firstglobal;
  
      irfun = global->constval.vfunc;
-     def   = code_functions + irfun->code_function_def;
 -    def   = code->functions + irfun->code_function_def;
++    def   = ir->code->functions + irfun->code_function_def;
  
      if (OPTS_OPTION_BOOL(OPTION_G) ||
          !OPTS_OPTIMIZATION(OPTIM_OVERLAP_LOCALS)        ||
          (irfun->flags & IR_FLAG_MASK_NO_OVERLAP))
      {
-         firstlocal = def->firstlocal = vec_size(code_globals);
 -        firstlocal = def->firstlocal = vec_size(code->globals);
++        firstlocal = def->firstlocal = vec_size(ir->code->globals);
      } else {
          firstlocal = def->firstlocal = ir->first_common_local;
          ++opts_optimizationcount[OPTIM_OVERLAP_LOCALS];
  
      firstglobal = (OPTS_OPTIMIZATION(OPTIM_GLOBAL_TEMPS) ? ir->first_common_globaltemp : firstlocal);
  
-     for (i = vec_size(code_globals); i < firstlocal + irfun->allocated_locals; ++i)
-         vec_push(code_globals, 0);
 -    for (i = vec_size(code->globals); i < firstlocal + irfun->allocated_locals; ++i)
 -        vec_push(code->globals, 0);
++    for (i = vec_size(ir->code->globals); i < firstlocal + irfun->allocated_locals; ++i)
++        vec_push(ir->code->globals, 0);
      for (i = 0; i < vec_size(irfun->locals); ++i) {
          ir_value *v = irfun->locals[i];
          if (v->locked || !OPTS_OPTIMIZATION(OPTIM_GLOBAL_TEMPS)) {
              ir_value_code_setaddr(v, firstlocal + v->code.local);
 -            if (!ir_builder_gen_global(code, ir, irfun->locals[i], true)) {
 +            if (!ir_builder_gen_global(ir, irfun->locals[i], true)) {
                  irerror(irfun->locals[i]->context, "failed to generate local %s", irfun->locals[i]->name);
                  return false;
              }
      return true;
  }
  
 -static bool gen_global_function_code(code_t *code, ir_builder *ir, ir_value *global)
 +static bool gen_global_function_code(ir_builder *ir, ir_value *global)
  {
      prog_section_function *fundef;
      ir_function           *irfun;
          irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name);
          return false;
      }
-     fundef = &code_functions[irfun->code_function_def];
 -    fundef = &code->functions[irfun->code_function_def];
++    fundef = &ir->code->functions[irfun->code_function_def];
  
-     fundef->entry = vec_size(code_statements);
 -    fundef->entry = vec_size(code->statements);
 -    if (!gen_function_locals(code, ir, global)) {
++    fundef->entry = vec_size(ir->code->statements);
 +    if (!gen_function_locals(ir, global)) {
          irerror(irfun->context, "Failed to generate locals for function %s", irfun->name);
          return false;
      }
-     if (!gen_function_extparam_copy(irfun)) {
 -    if (!gen_function_extparam_copy(code, irfun)) {
++    if (!gen_function_extparam_copy(ir->code, irfun)) {
          irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name);
          return false;
      }
-     if (irfun->max_varargs && !gen_function_varargs_copy(irfun)) {
 -    if (irfun->max_varargs && !gen_function_varargs_copy(code, irfun)) {
++    if (irfun->max_varargs && !gen_function_varargs_copy(ir->code, irfun)) {
          irerror(irfun->context, "Failed to generate vararg-copy code for function %s", irfun->name);
          return false;
      }
-     if (!gen_function_code(irfun)) {
 -    if (!gen_function_code(code, irfun)) {
++    if (!gen_function_code(ir->code, irfun)) {
          irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
          return false;
      }
      return true;
  }
  
- static void gen_vector_defs(prog_section_def def, const char *name)
+ static void gen_vector_defs(code_t *code, prog_section_def def, const char *name)
  {
      char  *component;
      size_t len, i;
      component[len-1] = 'x';
  
      for (i = 0; i < 3; ++i) {
-         def.name = code_genstring(component);
-         vec_push(code_defs, def);
+         def.name = code_genstring(code, component);
+         vec_push(code->defs, def);
          def.offset++;
          component[len-1]++;
      }
      mem_d(component);
  }
  
- static void gen_vector_fields(prog_section_field fld, const char *name)
+ static void gen_vector_fields(code_t *code, prog_section_field fld, const char *name)
  {
      char  *component;
      size_t len, i;
      component[len-1] = 'x';
  
      for (i = 0; i < 3; ++i) {
-         fld.name = code_genstring(component);
-         vec_push(code_fields, fld);
+         fld.name = code_genstring(code, component);
+         vec_push(code->fields, fld);
          fld.offset++;
          component[len-1]++;
      }
      mem_d(component);
  }
  
 -static bool ir_builder_gen_global(code_t *code, ir_builder *self, ir_value *global, bool islocal)
 +static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal)
  {
      size_t           i;
      int32_t         *iptr;
      bool             pushdef = opts.optimizeoff;
  
      def.type   = global->vtype;
-     def.offset = vec_size(code_globals);
 -    def.offset = vec_size(code->globals);
++    def.offset = vec_size(self->code->globals);
      def.name   = 0;
      if (OPTS_OPTION_BOOL(OPTION_G) || !islocal)
      {
          if (pushdef && global->name) {
              if (global->name[0] == '#') {
                  if (!self->str_immediate)
-                     self->str_immediate = code_genstring("IMMEDIATE");
 -                    self->str_immediate = code_genstring(code, "IMMEDIATE");
++                    self->str_immediate = code_genstring(self->code, "IMMEDIATE");
                  def.name = global->code.name = self->str_immediate;
              }
              else
-                 def.name = global->code.name = code_genstring(global->name);
 -                def.name = global->code.name = code_genstring(code, global->name);
++                def.name = global->code.name = code_genstring(self->code, global->name);
          }
          else
              def.name   = 0;
          if (islocal) {
              def.offset = ir_value_code_addr(global);
-             vec_push(code_defs, def);
 -            vec_push(code->defs, def);
++            vec_push(self->code->defs, def);
              if (global->vtype == TYPE_VECTOR)
-                 gen_vector_defs(def, global->name);
 -                gen_vector_defs(code, def, global->name);
++                gen_vector_defs(self->code, def, global->name);
              else if (global->vtype == TYPE_FIELD && global->fieldtype == TYPE_VECTOR)
-                 gen_vector_defs(def, global->name);
 -                gen_vector_defs(code, def, global->name);
++                gen_vector_defs(self->code, def, global->name);
              return true;
          }
      }
           * Maybe this could be an -foption
           * fteqcc creates data for end_sys_* - of size 1, so let's do the same
           */
-         ir_value_code_setaddr(global, vec_size(code_globals));
-         vec_push(code_globals, 0);
 -        ir_value_code_setaddr(global, vec_size(code->globals));
 -        vec_push(code->globals, 0);
++        ir_value_code_setaddr(global, vec_size(self->code->globals));
++        vec_push(self->code->globals, 0);
          /* Add the def */
-         if (pushdef) vec_push(code_defs, def);
 -        if (pushdef) vec_push(code->defs, def);
++        if (pushdef) vec_push(self->code->defs, def);
          return true;
      case TYPE_POINTER:
-         if (pushdef) vec_push(code_defs, def);
-         return gen_global_pointer(global);
 -        if (pushdef) vec_push(code->defs, def);
 -        return gen_global_pointer(code, global);
++        if (pushdef) vec_push(self->code->defs, def);
++        return gen_global_pointer(self->code, global);
      case TYPE_FIELD:
          if (pushdef) {
-             vec_push(code_defs, def);
 -            vec_push(code->defs, def);
++            vec_push(self->code->defs, def);
              if (global->fieldtype == TYPE_VECTOR)
-                 gen_vector_defs(def, global->name);
 -                gen_vector_defs(code, def, global->name);
++                gen_vector_defs(self->code, def, global->name);
          }
-         return gen_global_field(global);
 -        return gen_global_field(code, global);
++        return gen_global_field(self->code, global);
      case TYPE_ENTITY:
          /* fall through */
      case TYPE_FLOAT:
      {
-         ir_value_code_setaddr(global, vec_size(code_globals));
 -        ir_value_code_setaddr(global, vec_size(code->globals));
++        ir_value_code_setaddr(global, vec_size(self->code->globals));
          if (global->hasvalue) {
              iptr = (int32_t*)&global->constval.ivec[0];
-             vec_push(code_globals, *iptr);
 -            vec_push(code->globals, *iptr);
++            vec_push(self->code->globals, *iptr);
          } else {
-             vec_push(code_globals, 0);
 -            vec_push(code->globals, 0);
++            vec_push(self->code->globals, 0);
          }
          if (!islocal && global->cvq != CV_CONST)
              def.type |= DEF_SAVEGLOBAL;
-         if (pushdef) vec_push(code_defs, def);
 -        if (pushdef) vec_push(code->defs, def);
++        if (pushdef) vec_push(self->code->defs, def);
  
          return global->code.globaladdr >= 0;
      }
      case TYPE_STRING:
      {
-         ir_value_code_setaddr(global, vec_size(code_globals));
 -        ir_value_code_setaddr(global, vec_size(code->globals));
++        ir_value_code_setaddr(global, vec_size(self->code->globals));
          if (global->hasvalue) {
-             vec_push(code_globals, code_genstring(global->constval.vstring));
 -            uint32_t load = code_genstring(code, global->constval.vstring);
 -            vec_push(code->globals, load);
++            uint32_t load = code_genstring(self->code, global->constval.vstring);
++            vec_push(self->code->globals, load);
          } else {
-             vec_push(code_globals, 0);
 -            vec_push(code->globals, 0);
++            vec_push(self->code->globals, 0);
          }
          if (!islocal && global->cvq != CV_CONST)
              def.type |= DEF_SAVEGLOBAL;
-         if (pushdef) vec_push(code_defs, def);
 -        if (pushdef) vec_push(code->defs, def);
++        if (pushdef) vec_push(self->code->defs, def);
          return global->code.globaladdr >= 0;
      }
      case TYPE_VECTOR:
      {
          size_t d;
-         ir_value_code_setaddr(global, vec_size(code_globals));
 -        ir_value_code_setaddr(global, vec_size(code->globals));
++        ir_value_code_setaddr(global, vec_size(self->code->globals));
          if (global->hasvalue) {
              iptr = (int32_t*)&global->constval.ivec[0];
-             vec_push(code_globals, iptr[0]);
 -            vec_push(code->globals, iptr[0]);
++            vec_push(self->code->globals, iptr[0]);
              if (global->code.globaladdr < 0)
                  return false;
              for (d = 1; d < type_sizeof_[global->vtype]; ++d) {
-                 vec_push(code_globals, iptr[d]);
 -                vec_push(code->globals, iptr[d]);
++                vec_push(self->code->globals, iptr[d]);
              }
          } else {
-             vec_push(code_globals, 0);
 -            vec_push(code->globals, 0);
++            vec_push(self->code->globals, 0);
              if (global->code.globaladdr < 0)
                  return false;
              for (d = 1; d < type_sizeof_[global->vtype]; ++d) {
-                 vec_push(code_globals, 0);
 -                vec_push(code->globals, 0);
++                vec_push(self->code->globals, 0);
              }
          }
          if (!islocal && global->cvq != CV_CONST)
              def.type |= DEF_SAVEGLOBAL;
  
          if (pushdef) {
-             vec_push(code_defs, def);
 -            vec_push(code->defs, def);
++            vec_push(self->code->defs, def);
              def.type &= ~DEF_SAVEGLOBAL;
-             gen_vector_defs(def, global->name);
 -            gen_vector_defs(code, def, global->name);
++            gen_vector_defs(self->code, def, global->name);
          }
          return global->code.globaladdr >= 0;
      }
      case TYPE_FUNCTION:
-         ir_value_code_setaddr(global, vec_size(code_globals));
 -        ir_value_code_setaddr(global, vec_size(code->globals));
++        ir_value_code_setaddr(global, vec_size(self->code->globals));
          if (!global->hasvalue) {
-             vec_push(code_globals, 0);
 -            vec_push(code->globals, 0);
++            vec_push(self->code->globals, 0);
              if (global->code.globaladdr < 0)
                  return false;
          } else {
-             vec_push(code_globals, vec_size(code_functions));
 -            vec_push(code->globals, vec_size(code->functions));
 -            if (!gen_global_function(code, self, global))
++            vec_push(self->code->globals, vec_size(self->code->functions));
 +            if (!gen_global_function(self, global))
                  return false;
          }
          if (!islocal && global->cvq != CV_CONST)
              def.type |= DEF_SAVEGLOBAL;
-         if (pushdef) vec_push(code_defs, def);
 -        if (pushdef) vec_push(code->defs, def);
++        if (pushdef) vec_push(self->code->defs, def);
          return true;
      case TYPE_VARIANT:
          /* assume biggest type */
-             ir_value_code_setaddr(global, vec_size(code_globals));
-             vec_push(code_globals, 0);
 -            ir_value_code_setaddr(global, vec_size(code->globals));
 -            vec_push(code->globals, 0);
++            ir_value_code_setaddr(global, vec_size(self->code->globals));
++            vec_push(self->code->globals, 0);
              for (i = 1; i < type_sizeof_[TYPE_VARIANT]; ++i)
-                 vec_push(code_globals, 0);
 -                vec_push(code->globals, 0);
++                vec_push(self->code->globals, 0);
              return true;
      default:
          /* refuse to create 'void' type or any other fancy business. */
      }
  }
  
- static void ir_builder_prepare_field(ir_value *field)
+ static GMQCC_INLINE void ir_builder_prepare_field(code_t *code, ir_value *field)
  {
-     field->code.fieldaddr = code_alloc_field(type_sizeof_[field->fieldtype]);
+     field->code.fieldaddr = code_alloc_field(code, type_sizeof_[field->fieldtype]);
  }
  
 -static bool ir_builder_gen_field(code_t *code, ir_builder *self, ir_value *field)
 +static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
  {
      prog_section_def def;
      prog_section_field fld;
      (void)self;
  
      def.type   = (uint16_t)field->vtype;
-     def.offset = (uint16_t)vec_size(code_globals);
 -    def.offset = (uint16_t)vec_size(code->globals);
++    def.offset = (uint16_t)vec_size(self->code->globals);
  
      /* create a global named the same as the field */
      if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
          memcpy(name+1, field->name, len); /* no strncpy - we used strlen above */
          name[len+1] = 0;
  
-         def.name = code_genstring(name);
 -        def.name = code_genstring(code, name);
++        def.name = code_genstring(self->code, name);
          fld.name = def.name + 1; /* we reuse that string table entry */
      } else {
          /* in plain QC, there cannot be a global with the same name,
           * FIXME: fteqcc should create a global as well
           * check if it actually uses the same name. Probably does
           */
-         def.name = code_genstring(field->name);
 -        def.name = code_genstring(code, field->name);
++        def.name = code_genstring(self->code, field->name);
          fld.name = def.name;
      }
  
      field->code.name = def.name;
  
-     vec_push(code_defs, def);
 -    vec_push(code->defs, def);
++    vec_push(self->code->defs, def);
  
      fld.type = field->fieldtype;
  
  
      fld.offset = field->code.fieldaddr;
  
-     vec_push(code_fields, fld);
 -    vec_push(code->fields, fld);
++    vec_push(self->code->fields, fld);
  
-     ir_value_code_setaddr(field, vec_size(code_globals));
-     vec_push(code_globals, fld.offset);
 -    ir_value_code_setaddr(field, vec_size(code->globals));
 -    vec_push(code->globals, fld.offset);
++    ir_value_code_setaddr(field, vec_size(self->code->globals));
++    vec_push(self->code->globals, fld.offset);
      if (fld.type == TYPE_VECTOR) {
-         vec_push(code_globals, fld.offset+1);
-         vec_push(code_globals, fld.offset+2);
 -        vec_push(code->globals, fld.offset+1);
 -        vec_push(code->globals, fld.offset+2);
++        vec_push(self->code->globals, fld.offset+1);
++        vec_push(self->code->globals, fld.offset+2);
      }
  
      if (field->fieldtype == TYPE_VECTOR) {
-         gen_vector_defs(def, field->name);
-         gen_vector_fields(fld, field->name);
 -        gen_vector_defs  (code, def, field->name);
 -        gen_vector_fields(code, fld, field->name);
++        gen_vector_defs  (self->code, def, field->name);
++        gen_vector_fields(self->code, fld, field->name);
      }
  
      return field->code.globaladdr >= 0;
  }
  
- bool ir_builder_prepare(ir_builder *self)
- {
-     size_t extparams = self->max_used_params;
-     if (extparams > 8) {
-         for (extparams -= 8; extparams; --extparams)
-             ir_gen_extparam_proto(self);
-     }
-     return true;
- }
 -bool ir_builder_generate(code_t *code, ir_builder *self, const char *filename)
 +bool ir_builder_generate(ir_builder *self, const char *filename)
  {
      prog_section_statement stmt;
      size_t i;
      char  *lnofile = NULL;
  
-     code_init();
      for (i = 0; i < vec_size(self->fields); ++i)
      {
-         ir_builder_prepare_field(self->fields[i]);
 -        ir_builder_prepare_field(code, self->fields[i]);
++        ir_builder_prepare_field(self->code, self->fields[i]);
      }
  
      for (i = 0; i < vec_size(self->globals); ++i)
      {
 -        if (!ir_builder_gen_global(code, self, self->globals[i], false)) {
 +        if (!ir_builder_gen_global(self, self->globals[i], false)) {
              return false;
          }
          if (self->globals[i]->vtype == TYPE_FUNCTION) {
  
      for (i = 0; i < vec_size(self->fields); ++i)
      {
 -        if (!ir_builder_gen_field(code, self, self->fields[i])) {
 +        if (!ir_builder_gen_field(self, self->fields[i])) {
              return false;
          }
      }
  
      /* generate nil */
-     ir_value_code_setaddr(self->nil, vec_size(code_globals));
-     vec_push(code_globals, 0);
-     vec_push(code_globals, 0);
-     vec_push(code_globals, 0);
 -    ir_value_code_setaddr(self->nil, vec_size(code->globals));
 -    vec_push(code->globals, 0);
 -    vec_push(code->globals, 0);
 -    vec_push(code->globals, 0);
++    ir_value_code_setaddr(self->nil, vec_size(self->code->globals));
++    vec_push(self->code->globals, 0);
++    vec_push(self->code->globals, 0);
++    vec_push(self->code->globals, 0);
  
      /* generate global temps */
-     self->first_common_globaltemp = vec_size(code_globals);
 -    self->first_common_globaltemp = vec_size(code->globals);
++    self->first_common_globaltemp = vec_size(self->code->globals);
      for (i = 0; i < self->max_globaltemps; ++i) {
-         vec_push(code_globals, 0);
 -        vec_push(code->globals, 0);
++        vec_push(self->code->globals, 0);
      }
      /* generate common locals */
-     self->first_common_local = vec_size(code_globals);
 -    self->first_common_local = vec_size(code->globals);
++    self->first_common_local = vec_size(self->code->globals);
      for (i = 0; i < self->max_locals; ++i) {
-         vec_push(code_globals, 0);
 -        vec_push(code->globals, 0);
++        vec_push(self->code->globals, 0);
      }
  
      /* generate function code */
      for (i = 0; i < vec_size(self->globals); ++i)
      {
          if (self->globals[i]->vtype == TYPE_FUNCTION) {
 -            if (!gen_global_function_code(code, self, self->globals[i])) {
 +            if (!gen_global_function_code(self, self->globals[i])) {
                  return false;
              }
          }
      }
  
-     if (vec_size(code_globals) >= 65536) {
 -    if (vec_size(code->globals) >= 65536) {
++    if (vec_size(self->code->globals) >= 65536) {
          irerror(vec_last(self->globals)->context, "This progs file would require more globals than the metadata can handle. Bailing out.");
          return false;
      }
  
      /* DP errors if the last instruction is not an INSTR_DONE. */
-     if (vec_last(code_statements).opcode != INSTR_DONE)
 -    if (vec_last(code->statements).opcode != INSTR_DONE)
++    if (vec_last(self->code->statements).opcode != INSTR_DONE)
      {
          stmt.opcode = INSTR_DONE;
          stmt.o1.u1 = 0;
          stmt.o2.u1 = 0;
          stmt.o3.u1 = 0;
-         code_push_statement(&stmt, vec_last(code_linenums));
 -        code_push_statement(code, &stmt, vec_last(code->linenums));
++        code_push_statement(self->code, &stmt, vec_last(self->code->linenums));
      }
  
      if (OPTS_OPTION_BOOL(OPTION_PP_ONLY))
          return true;
  
-     if (vec_size(code_statements) != vec_size(code_linenums)) {
 -    if (vec_size(code->statements) != vec_size(code->linenums)) {
++    if (vec_size(self->code->statements) != vec_size(self->code->linenums)) {
          con_err("Linecounter wrong: %lu != %lu\n",
-                 (unsigned long)vec_size(code_statements),
-                 (unsigned long)vec_size(code_linenums));
 -                (unsigned long)vec_size(code->statements),
 -                (unsigned long)vec_size(code->linenums));
++                (unsigned long)vec_size(self->code->statements),
++                (unsigned long)vec_size(self->code->linenums));
      } else if (OPTS_FLAG(LNO)) {
-         char *dot;
+         char  *dot;
          size_t filelen = strlen(filename);
  
          memcpy(vec_add(lnofile, filelen+1), filename, filelen+1);
          else
              con_out("writing '%s'\n", filename);
      }
-     if (!code_write(filename, lnofile)) {
 -    if (!code_write(code, filename, lnofile)) {
++    if (!code_write(self->code, filename, lnofile)) {
          vec_free(lnofile);
          return false;
      }
  #   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]) ))
@@@ -3774,7 -3757,7 +3780,7 @@@ void ir_function_dump(ir_function *f, c
          return;
      }
      oprintf("%sfunction %s\n", ind, f->name);
--    strncat(ind, "\t", IND_BUFSZ);
++    strncat(ind, "\t", IND_BUFSZ-1);
      if (vec_size(f->locals))
      {
          oprintf("%s%i locals:\n", ind, (int)vec_size(f->locals));
      }
      if (vec_size(f->blocks))
      {
-         oprintf("%slife passes: %i\n", ind, (int)f->run_id); 
+         oprintf("%slife passes: %i\n", ind, (int)f->run_id);
          for (i = 0; i < vec_size(f->blocks); ++i) {
              ir_block_dump(f->blocks[i], ind, oprintf);
          }
@@@ -3870,7 -3853,7 +3876,7 @@@ void ir_block_dump(ir_block* b, char *i
  {
      size_t i;
      oprintf("%s:%s\n", ind, b->label);
--    strncat(ind, "\t", IND_BUFSZ);
++    strncat(ind, "\t", IND_BUFSZ-1);
  
      if (b->instr && b->instr[0])
          oprintf("%s (%i) [entry]\n", ind, (int)(b->instr[0]->eid-1));
      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);
@@@ -3904,7 -3887,7 +3910,7 @@@ void ir_instr_dump(ir_instr *in, char *
          return;
      }
  
--    strncat(ind, "\t", IND_BUFSZ);
++    strncat(ind, "\t", IND_BUFSZ-1);
  
      if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) {
          ir_value_dump(in->_ops[0], oprintf);
      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 --combined ir.h
index 50fd0d94574f437f79b385b2f7eadb632c42d3b4,cd382957f022c34d82a0bdd2f1603bf1aa1ef7d9..f5b47da8dcf2e3d4dfc0f2191e097dc6b0ee89bb
--- 1/ir.h
--- 2/ir.h
+++ b/ir.h
@@@ -23,7 -23,6 +23,6 @@@
  #ifndef GMQCC_IR_HDR
  #define GMQCC_IR_HDR
  #include "gmqcc.h"
- /* ir_value */
  
  typedef struct
  {
@@@ -46,7 -45,6 +45,6 @@@ typedef struct ir_value_s 
      int       cvq;
      uint32_t  flags;
  
-     bool      untracked;
      struct ir_instr_s **reads;
      struct ir_instr_s **writes;
  
      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
@@@ -151,15 -126,6 +126,6 @@@ typedef struct ir_instr_
      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
  {
      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);
@@@ -227,10 -179,7 +179,7 @@@ bool GMQCC_WARN ir_block_create_if(ir_b
  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;
      /* 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)
  #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);
- bool GMQCC_WARN ir_function_optimize(ir_function*);
+ 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
@@@ -327,9 -260,6 +260,6 @@@ typedef struct ir_builder_
      uint32_t      first_common_local;
      uint32_t      first_common_globaltemp;
  
-     /* highest number of parameters */
-     size_t        max_used_params;
      const char **filenames;
      qcint       *filestrings;
      /* we cache the #IMMEDIATE string here */
      /* there should just be this one nil */
      ir_value    *nil;
      ir_value    *reserved_va_count;
++    
++    /* code generator */
++    code_t      *code;
  } 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);
 -bool         ir_builder_generate(code_t *, ir_builder *self, const char *filename);
+ 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(ir_builder *self, const char *filename);
+ void         ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...));
  
- 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_prepare(ir_builder *self);
- bool ir_builder_generate(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 */
- extern int check_int_and_float_size
- [ (sizeof(int32_t) == sizeof(qcfloat)) ? 1 : -1 ];
+ /*
+  * This code assumes 32 bit floats while generating binary
+  * Blub: don't use extern here, it's annoying and shows up in nm
 - * for some reason :P  
++ * for some reason :P
+  */
+ typedef int static_assert_is_32bit_float  [(sizeof(int32_t) == 4)?1:-1];
+ typedef int static_assert_is_32bit_integer[(sizeof(qcfloat) == 4)?1:-1];
  
  #endif
diff --combined main.c
index be4eaef3b9e9a1337ddf42cebed4770ad911fcaf,98de0e9176b4e9924e07757b536b41a6bee2446b..03da18f54bbbd1994c5e0e09930f4c7fbcdc907b
--- 1/main.c
--- 2/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,24 -47,20 +47,20 @@@ static ppitem  *ppems = NULL
  #define TYPE_ASM 1
  #define TYPE_SRC 2
  
  static const char *app_name;
  
- static void version() {
-     con_out("GMQCC %d.%d.%d Built %s %s\n",
+ static void version(void) {
+     con_out("GMQCC %d.%d.%d Built %s %s\n" GMQCC_DEV_VERSION_STRING,
          GMQCC_VERSION_MAJOR,
          GMQCC_VERSION_MINOR,
          GMQCC_VERSION_PATCH,
          __DATE__,
          __TIME__
      );
- #ifdef GMQCC_GITINFO
-     con_out("git build: %s\n", GMQCC_GITINFO);
- #elif defined(GMQCC_VERION_TYPE_DEVEL)
-     con_out("development build\n");
- #endif
  }
  
- 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"
@@@ -173,9 -175,12 +175,12 @@@ static bool options_parse(int argc, cha
                      opts_set(opts.flags, INITIALIZED_NONCONSTANTS,      true);
                      opts_set(opts.werror, WARN_INVALID_PARAMETER_COUNT, true);
                      opts_set(opts.werror, WARN_MISSING_RETURN_VALUES,   true);
+                     opts_set(opts.flags,  EXPRESSIONS_FOR_BUILTINS,     true);
+                     opts_set(opts.warn,   WARN_BREAKDEF,                true);
  
  
                      OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_GMQCC;
+                     OPTS_OPTION_BOOL(OPTION_STATISTICS) = true;
  
                  } else if (!strcmp(argarg, "qcc")) {
  
                      opts_set(opts.flags, ASSIGN_FUNCTION_TYPES,    true);
                      opts_set(opts.flags, CORRECT_TERNARY,          false);
                      opts_set(opts.warn, WARN_TERNARY_PRECEDENCE,   true);
+                     opts_set(opts.warn, WARN_BREAKDEF,             true);
  
                      OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_FTEQCC;
  
                  OPTS_OPTION_U16 (OPTION_FORCED_CRC) = strtol(argarg, NULL, 0);
                  continue;
              }
 +            if (options_long_gcc("jobs", &argc, &argv, &argarg)) {
 +
 +                OPTS_OPTION_U32 (OPTION_J) = strtol(argarg, NULL, 0);
 +                continue;
 +            }
              if (options_long_gcc("redirout", &argc, &argv, &redirout)) {
                  con_change(redirout, redirerr);
                  continue;
                      vec_push(items, item);
                      break;
  
 +                case 'j':
 +                    if (!options_witharg(&argc, &argv, &argarg)) {
 +                        con_out("option -j requires a parameter\n");
 +                        return false;
 +                    }
 +                    OPTS_OPTION_U32 (OPTION_J) = strtol(argarg, NULL, 0);
 +                    break;
 +
                  case '-':
                      if (!argv[0][2]) {
                          /* anything following -- is considered a non-option argument */
@@@ -656,9 -649,6 +662,6 @@@ int main(int argc, char **argv) 
          }
      }
  
-     if (OPTS_FLAG(TRUE_EMPTY_STRINGS))
-         type_not_instr[TYPE_STRING] = INSTR_NOT_F;
      util_debug("COM", "starting ...\n");
  
      /* add macros */
      }
  
      if (!vec_size(items)) {
-         FILE *src;
-         char *line;
+         FILE  *src;
+         char  *line    = NULL;
          size_t linelen = 0;
+         bool   hasline = false;
  
          progs_src = true;
  
              goto cleanup;
          }
  
-         line = NULL;
-         if (!progs_nextline(&line, &linelen, src) || !line[0]) {
-             con_err("illformatted progs.src file: expected output filename in first line\n");
-             retval = 1;
-             goto srcdone;
-         }
-         if (!opts_output_wasset) {
-             OPTS_OPTION_STR(OPTION_OUTPUT) = util_strdup(line);
-             opts_output_free = true;
-         }
          while (progs_nextline(&line, &linelen, src)) {
              argitem item;
              if (!line[0] || (line[0] == '/' && line[1] == '/'))
                  continue;
-             item.filename = util_strdup(line);
-             item.type     = TYPE_QC;
-             vec_push(items, item);
+                 
+             if (hasline) {
+                 item.filename = util_strdup(line);
+                 item.type     = TYPE_QC;
+                 vec_push(items, item);
+             } else if (!opts_output_wasset) {
+                 OPTS_OPTION_STR(OPTION_OUTPUT) = util_strdup(line);
+                 opts_output_free               = true;
+                 hasline                        = true;
+             }
          }
  
- srcdone:
          fs_file_close(src);
          mem_d(line);
      }
@@@ -814,6 -800,7 +813,7 @@@ cleanup
          mem_d((void*)operators);
  
      lex_cleanup();
-     util_meminfo();
+     stat_info();
      return retval;
  }
diff --combined opts.c
index c3d69aa9a884579aa501edb6d6aa06c5acbd6f71,e6ca420bb4a0b18ca41a1be97b12e237fc4f333b..97a3597df54e9c4c62e1305b33777b4521184f09
--- 1/opts.c
--- 2/opts.c
+++ b/opts.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * Copyright (C) 2012, 2013
   *     Wolfgang Bumiller
-  *     Dale Weiler 
+  *     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
   * 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;
  
@@@ -98,7 -103,6 +103,7 @@@ void opts_init(const char *output, int 
      OPTS_OPTION_U32(OPTION_STANDARD)       = standard;
      OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE) = arraysize;
      OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)    = 16;
 +    OPTS_OPTION_U32(OPTION_J)              = 2;
  }
  
  static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def *list, size_t listsize) {
@@@ -217,7 -221,7 +222,7 @@@ static size_t opts_ini_parse 
              /* section found */
              if (*(parse_end = opts_ini_next(parse_beg + 1, ']')) == ']') {
                  * parse_end = '\0'; /* terminate bro */
-                 strncpy(section_data, parse_beg + 1, sizeof(section_data));
+                 util_strncpy(section_data, parse_beg + 1, sizeof(section_data));
                  section_data[sizeof(section_data) - 1] = '\0';
                  *oldname_data                          = '\0';
              } else if (!error) {
                  opts_ini_rstrip(read_value);
  
                  /* valid name value pair, lets call down to handler */
-                 strncpy(oldname_data, read_name, sizeof(oldname_data));
+                 util_strncpy(oldname_data, read_name, sizeof(oldname_data));
                  oldname_data[sizeof(oldname_data) - 1] ='\0';
  
                  if ((*errorhandle = loadhandle(section_data, read_name, read_value)) && !error)
@@@ -270,7 -274,7 +275,7 @@@ static char *opts_ini_load(const char *
      /*
       * undef all of these because they may still be defined like in my
       * case they where.
-      */  
+      */
      #undef GMQCC_TYPE_FLAGS
      #undef GMQCC_TYPE_OPTIMIZATIONS
      #undef GMQCC_TYPE_WARNS
@@@ -348,7 -352,7 +353,7 @@@ void opts_ini_init(const char *file) 
      size_t     line;
      FILE       *ini;
  
-     
      if (!file) {
          /* try ini */
          if (!(ini = fs_file_open((file = "gmqcc.ini"), "r")))
  
      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);
      }
  
      fs_file_close(ini);
- }  
+ }
diff --combined opts.def
index 47f82eeb36835e8c4b7bae2ebe4645ae00b1925d,071b11a951373978388a5f967d4bb65b157408dd..7efe5317b0d94a391f92171ba064035cecf6be12
+++ b/opts.def
@@@ -50,6 -50,8 +50,8 @@@
      GMQCC_DEFINE_FLAG(PERMISSIVE)
      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 */
@@@ -87,6 -89,7 +89,7 @@@
      GMQCC_DEFINE_FLAG(DIFFERENT_ATTRIBUTES)
      GMQCC_DEFINE_FLAG(DEPRECATED)
      GMQCC_DEFINE_FLAG(PARENTHESIS)
+     GMQCC_DEFINE_FLAG(BREAKDEF)
  #endif
  
  #ifdef GMQCC_TYPE_OPTIMIZATIONS
      GMQCC_DEFINE_FLAG(MAX_ARRAY_SIZE)
      GMQCC_DEFINE_FLAG(ADD_INFO)
      GMQCC_DEFINE_FLAG(CORRECTION)
 +    GMQCC_DEFINE_FLAG(J)
+     GMQCC_DEFINE_FLAG(STATISTICS)
  #endif
  
  /* some cleanup so we don't have to */
diff --combined parser.c
index 325a03061f378ea1c94f64c14b234b38cdc3230e,8a7cf876948e06119fa1730340f5b0be22e6742b..8bf4086cf6b85f6879a8c51afa28361ece84a9e2
+++ b/parser.c
@@@ -2,7 -2,7 +2,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
   * the Software without restriction, including without limitation the rights to
   * 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 <pthread.h>
  
  #include "gmqcc.h"
  #include "lexer.h"
@@@ -40,6 -38,8 +39,8 @@@ typedef struct parser_s 
      lex_file *lex;
      int      tok;
  
+     bool     ast_cleaned;
      ast_expression **globals;
      ast_expression **fields;
      ast_function **functions;
  
      /* collected information */
      size_t     max_param_count;
+     /* code generator */
+     code_t     *code;
  } parser_t;
  
  static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1;
@@@ -183,7 -186,7 +187,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);
@@@ -218,6 -221,7 +222,7 @@@ static ast_value* parser_const_float(pa
      out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT);
      out->cvq      = CV_CONST;
      out->hasvalue = true;
+     out->isimm    = true;
      out->constval.vfloat = d;
      vec_push(parser->imm_float, out);
      return out;
@@@ -258,11 -262,12 +263,12 @@@ static ast_value* parser_const_string(p
  {
      size_t hash = util_hthash(parser->ht_imm_string, str);
      ast_value *out;
-     if ( (out = util_htgeth(parser->ht_imm_string, str, hash)) ) {
+     if ( (out = (ast_value*)util_htgeth(parser->ht_imm_string, str, hash)) ) {
          if (dotranslate && out->name[0] == '#') {
              char name[32];
-             snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
+             util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
              ast_value_set_name(out, name);
+             out->expression.flags |= AST_FLAG_INCLUDE_DEF;
          }
          return out;
      }
      */
      if (dotranslate) {
          char name[32];
-         snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
+         util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
          out = ast_value_new(parser_ctx(parser), name, TYPE_STRING);
+         out->expression.flags |= AST_FLAG_INCLUDE_DEF;
      } else
          out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING);
      out->cvq      = CV_CONST;
      out->hasvalue = true;
+     out->isimm    = true;
      out->constval.vstring = parser_strdup(str);
      vec_push(parser->imm_string, out);
      util_htseth(parser->ht_imm_string, str, hash, out);
@@@ -297,6 -304,7 +305,7 @@@ static ast_value* parser_const_vector(p
      out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_VECTOR);
      out->cvq      = CV_CONST;
      out->hasvalue = true;
+     out->isimm    = true;
      out->constval.vvec = v;
      vec_push(parser->imm_vector, out);
      return out;
@@@ -580,7 -588,7 +589,7 @@@ static bool parser_sy_apply_operator(pa
          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('.')))
          {
      }
  
  #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)
              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);
                      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;
              }
              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;
              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));
                      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));
                      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]))
                      {
                      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));
                      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)));
                      }
                      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)));
                              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);
                              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);
                              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);
                              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));
                              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));
                              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));
                      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 {
          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])) {
          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]))
          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('<','<','='):
                      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);
                              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);
              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);
              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) {
                      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);
          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;
          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;
              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));
                  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),
                      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));
                  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),
                      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;
                  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]);
                  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;
              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;
@@@ -1566,7 -1574,7 +1575,7 @@@ static bool parser_close_call(parser_t 
  
      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);
      /* 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",
                      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);
          }
      }
@@@ -1682,6 -1690,8 +1691,8 @@@ static bool parser_close_paren(parser_
  static void parser_reclassify_token(parser_t *parser)
  {
      size_t i;
+     if (parser->tok >= TOKEN_START)
+         return;
      for (i = 0; i < operator_count; ++i) {
          if (!strcmp(parser_tokval(parser), operators[i].op)) {
              parser->tok = TOKEN_OPERATOR;
@@@ -1783,6 -1793,9 +1794,9 @@@ static ast_expression* parse_vararg(par
      return out;
  }
  
+ /* not to be exposed */
+ extern bool ftepp_predef_exists(const char *name);
  static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
  {
      if (OPTS_FLAG(TRANSLATABLE_STRINGS) &&
              /* 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 {
                  vec_push(parser->labels, lbl);
              }
          }
+         if (!var && !strcmp(parser_tokval(parser), "__FUNC__"))
+             var = (ast_expression*)parser_const_string(parser, parser->function->name, false);
          if (!var) {
              /* intrinsics */
              if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
               */
              else if (!strncmp(parser_tokval(parser), "__builtin_", 10)) {
                  var = intrin_func(parser, parser_tokval(parser) + 10 /* skip __builtin */);
-             } else {
-                 var = intrin_func(parser, parser_tokval(parser));
              }
-                 
              if (!var) {
                  char *correct = NULL;
                  size_t i;
                   * i've done this thousands of times already myself.  Lets check for
                   * it in the predef table.  And diagnose it better :)
                   */
-                 if (!OPTS_FLAG(FTEPP_PREDEFS)) {
-                     for (i = 0; i < sizeof(ftepp_predefs)/sizeof(*ftepp_predefs); i++) {
-                         if (!strcmp(ftepp_predefs[i].name, parser_tokval(parser))) {
-                             parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
-                             return false;
-                         }
-                     }
+                 if (!OPTS_FLAG(FTEPP_PREDEFS) && ftepp_predef_exists(parser_tokval(parser))) {
+                     parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
+                     return false;
                  }
  
                  /*
                   * We should also consider adding correction tables for
                   * other things as well.
                   */
-                 if (OPTS_OPTION_BOOL(OPTION_CORRECTION)) {
+                 if (OPTS_OPTION_BOOL(OPTION_CORRECTION) && strlen(parser_tokval(parser)) <= 16) {
                      correction_t corr;
                      correct_init(&corr);
  
@@@ -2183,8 -2192,27 +2193,27 @@@ static ast_expression* parse_expression
              wantop = true;
          }
          else {
-             parseerror(parser, "expected operator or end of statement");
-             goto onerr;
+             /* in this case we might want to allow constant string concatenation */
+             bool concatenated = false;
+             if (parser->tok == TOKEN_STRINGCONST && vec_size(sy.out)) {
+                 ast_expression *lexpr = vec_last(sy.out).out;
+                 if (ast_istype(lexpr, ast_value)) {
+                     ast_value *last = (ast_value*)lexpr;
+                     if (last->isimm == true && last->cvq == CV_CONST &&
+                         last->hasvalue && last->expression.vtype == TYPE_STRING)
+                     {
+                         char *newstr = NULL;
+                         util_asprintf(&newstr, "%s%s", last->constval.vstring, parser_tokval(parser));
+                         vec_last(sy.out).out = (ast_expression*)parser_const_string(parser, newstr, false);
+                         mem_d(newstr);
+                         concatenated = true;
+                     }
+                 }
+             }
+             if (!concatenated) {
+                 parseerror(parser, "expected operator or end of statement");
+                 goto onerr;
+             }
          }
  
          if (!parser_next(parser)) {
      }
  
      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;
@@@ -2340,13 -2368,13 +2369,13 @@@ static ast_expression* process_conditio
      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);
          }
          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;
@@@ -2430,17 -2458,17 +2459,17 @@@ static bool parse_if(parser_t *parser, 
      /* 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)
          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;
          }
      }
@@@ -2553,23 -2581,23 +2582,23 @@@ static bool parse_while_go(parser_t *pa
      /* 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);
@@@ -2669,21 -2697,21 +2698,21 @@@ static bool parse_dowhile_go(parser_t *
      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;
      }
  
@@@ -2756,7 -2784,6 +2785,6 @@@ static bool parse_for_go(parser_t *pars
      ast_expression *initexpr, *cond, *increment, *ontrue;
      ast_value      *typevar;
  
-     bool retval = true;
      bool ifnot  = false;
  
      lex_ctx ctx = parser_ctx(parser);
      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);
          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;
@@@ -3652,7 -3741,7 +3742,7 @@@ static bool parse_statement(parser_t *p
              }
              return parse_typedef(parser);
          }
-         parseerror(parser, "Unexpected keyword");
+         parseerror(parser, "Unexpected keyword: `%s'", parser_tokval(parser));
          return false;
      }
      else if (parser->tok == '{')
@@@ -4043,9 -4132,9 +4133,9 @@@ static bool parse_function_body(parser_
              /* 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));
  
          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;
          }
          varargs->expression.flags |= AST_FLAG_IS_VARARG;
          varargs->expression.next = (ast_expression*)ast_value_new(ast_ctx(var), NULL, TYPE_VECTOR);
          varargs->expression.count = 0;
-         snprintf(name, sizeof(name), "%s##va##SET", var->name);
+         util_snprintf(name, sizeof(name), "%s##va##SET", var->name);
          if (!parser_create_array_setter_proto(parser, varargs, name)) {
              ast_delete(varargs);
              ast_block_delete(block);
              goto enderrfn;
          }
-         snprintf(name, sizeof(name), "%s##va##GET", var->name);
+         util_snprintf(name, sizeof(name), "%s##va##GET", var->name);
          if (!parser_create_array_getter_proto(parser, varargs, varargs->expression.next, name)) {
              ast_delete(varargs);
              ast_block_delete(block);
      }
  
      vec_push(func->blocks, block);
+     
  
      parser->function = old;
      if (!parser_leaveblock(parser))
@@@ -4330,7 -4420,7 +4421,7 @@@ static ast_expression *array_setter_nod
          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));
@@@ -4396,7 -4486,7 +4487,7 @@@ static ast_expression *array_field_sett
          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));
@@@ -4706,6 -4796,7 +4797,7 @@@ static ast_value *parse_parameter_list(
  
      /* 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;
      }
@@@ -4973,6 -5064,7 +5065,7 @@@ static ast_value *parse_typename(parser
          /* parse on */
          if (!parser_next(parser)) {
              ast_delete(var);
+             mem_d(name);
              parseerror(parser, "error after variable or field declaration");
              return NULL;
          }
      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 */
      while (parser->tok == '(') {
          var = parse_parameter_list(parser, var);
          if (!var) {
-             if (name)
-                 mem_d((void*)name);
+             if (name) mem_d(name);
              return NULL;
          }
      }
      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;
@@@ -5115,7 -5209,7 +5210,7 @@@ static bool parse_variable(parser_t *pa
      bool      cleanvar  = true;
      bool      wasarray  = false;
  
-     ast_member *me[3];
+     ast_member *me[3] = { NULL, NULL, NULL };
  
      if (!localblock && is_static)
          parseerror(parser, "`static` qualifier is not supported in global scope");
          /*
           * store the vstring back to var for alias and
           * deprecation messages.
-          */   
+          */
          if (var->expression.flags & AST_FLAG_DEPRECATED ||
              var->expression.flags & AST_FLAG_ALIAS)
              var->desc = vstring;
              {
                  /* 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)) {
                          ast_value_set_name(proto->expression.params[i], var->expression.params[i]->name);
                      if (!parser_check_qualifiers(parser, var, proto)) {
                          retval = false;
-                         if (proto->desc) 
+                         if (proto->desc)
                              mem_d(proto->desc);
                          proto = NULL;
                          goto cleanup;
              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) {
                              return false;
                          }
  
-                         if (var->expression.vtype != find->expression.vtype) {
+                         if (var->expression.vtype != find->vtype) {
                              char ty1[1024];
                              char ty2[1024];
  
                          /*
                           * add alias to aliases table and to corrector
                           * so corrections can apply for aliases as well.
-                          */  
+                          */
                          util_htset(parser->aliases, var->name, find);
  
                          /*
                           * add to corrector so corrections can work
                           * even for aliases too.
-                          */ 
+                          */
                          correct_add (
                               vec_last(parser->correct_variables),
                              &vec_last(parser->correct_variables_score),
                              /*
                               * add to corrector so corrections can work
                               * even for aliases too.
-                              */  
+                              */
                              correct_add (
                                   vec_last(parser->correct_variables),
                                  &vec_last(parser->correct_variables_score),
           */
          if (var->expression.vtype == TYPE_ARRAY) {
              char name[1024];
-             snprintf(name, sizeof(name), "%s##SET", var->name);
+             util_snprintf(name, sizeof(name), "%s##SET", var->name);
              if (!parser_create_array_setter(parser, var, name))
                  goto cleanup;
-             snprintf(name, sizeof(name), "%s##GET", var->name);
+             util_snprintf(name, sizeof(name), "%s##GET", var->name);
              if (!parser_create_array_getter(parser, var, var->expression.next, name))
                  goto cleanup;
          }
          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;
                  goto cleanup;
              }
  
-             snprintf(name, sizeof(name), "%s##SETF", var->name);
+             util_snprintf(name, sizeof(name), "%s##SETF", var->name);
              if (!parser_create_array_field_setter(parser, array, name))
                  goto cleanup;
  
              telem = ast_type_copy(ast_ctx(var), array->expression.next);
              tfield = ast_value_new(ast_ctx(var), "<.type>", TYPE_FIELD);
              tfield->expression.next = telem;
-             snprintf(name, sizeof(name), "%s##GETFP", var->name);
+             util_snprintf(name, sizeof(name), "%s##GETFP", var->name);
              if (!parser_create_array_getter(parser, array, (ast_expression*)tfield, name)) {
                  ast_delete(tfield);
                  goto cleanup;
@@@ -5600,10 -5694,18 +5695,18 @@@ 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;
+                 if (!strcmp(parser_tokval(parser), "break")) {
+                     if (!parser_next(parser)) {
+                         parseerror(parser, "error parsing break definition");
+                         break;
+                     }
+                     (void)!!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)");
+                 } else {
+                     parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser));
+                     break;
+                 }
              }
  
              if (!parser_next(parser)) {
          }
  
          if (parser->tok == '#') {
-             ast_function *func = NULL;
+             ast_function *func   = NULL;
+             ast_value    *number = NULL;
+             float         fractional;
+             float         integral;
+             int           builtin_num;
  
              if (localblock) {
                  parseerror(parser, "cannot declare builtins within functions");
                  parseerror(parser, "expected builtin number");
                  break;
              }
-             if (parser->tok != TOKEN_INTCONST) {
-                 parseerror(parser, "builtin number must be an integer constant");
-                 break;
-             }
-             if (parser_token(parser)->constval.i < 0) {
-                 parseerror(parser, "builtin number must be an integer greater than zero");
+             if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS)) {
+                 number = (ast_value*)parse_expression_leave(parser, true, false, false);
+                 if (!number) {
+                     parseerror(parser, "builtin number expected");
+                     break;
+                 }
+                 if (!ast_istype(number, ast_value) || !number->hasvalue || number->cvq != CV_CONST)
+                 {
+                     ast_unref(number);
+                     parseerror(parser, "builtin number must be a compile time constant");
+                     break;
+                 }
+                 if (number->expression.vtype == TYPE_INTEGER)
+                     builtin_num = number->constval.vint;
+                 else if (number->expression.vtype == TYPE_FLOAT)
+                     builtin_num = number->constval.vfloat;
+                 else {
+                     ast_unref(number);
+                     parseerror(parser, "builtin number must be an integer constant");
+                     break;
+                 }
+                 ast_unref(number);
+                 fractional = modff(builtin_num, &integral);
+                 if (builtin_num < 0 || fractional != 0) {
+                     parseerror(parser, "builtin number must be an integer greater than zero");
+                     break;
+                 }
+                 /* we only want the integral part anyways */
+                 builtin_num = integral;
+             } else if (parser->tok == TOKEN_INTCONST) {
+                 builtin_num = parser_token(parser)->constval.i;
+             } else {
+                 parseerror(parser, "builtin number must be a compile time constant");
                  break;
              }
  
                  }
                  vec_push(parser->functions, func);
  
-                 func->builtin = -parser_token(parser)->constval.i-1;
+                 func->builtin = -builtin_num-1;
              }
  
-             if (!parser_next(parser)) {
+             if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS)
+                     ? (parser->tok != ',' && parser->tok != ';')
+                     : (!parser_next(parser)))
+             {
                  parseerror(parser, "expected comma or semicolon");
                  if (func)
                      ast_function_delete(func);
                  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");
                  }
                  vec_free(sy.out);
                  vec_free(sy.ops);
+                 vec_free(sy.argc);
                  var->cvq = cvq;
              }
          }
@@@ -5908,7 -6063,7 +6064,7 @@@ static void generate_checksum(parser_t 
          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;
      }
      crc = progdefs_crc_both(crc, "} entvars_t;\n\n");
  
-     code_crc = crc;
+     parser->code->crc = crc;
  }
  
  parser_t *parser_create()
  
      memset(parser, 0, sizeof(*parser));
  
+     if (!(parser->code = code_init())) {
+         mem_d(parser);
+         return NULL;
+     }
      for (i = 0; i < operator_count; ++i) {
          if (operators[i].id == opid1('=')) {
              parser->assign_op = operators+i;
      return parser;
  }
  
- bool parser_compile(parser_t *parser)
static bool parser_compile(parser_t *parser)
  {
      /* initial lexer/parser state */
      parser->lex->flags.noops = true;
@@@ -6040,9 -6200,12 +6201,12 @@@ bool parser_compile_string(parser_t *pa
      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;
      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);
  }
  
-     threads = (pthread_t*)alloca(poolsize*sizeof(pthread_t));
 +static void function_finalize_worker_do(ast_function **list, size_t count, volatile uint32_t *counter, bool *failure)
 +{
 +    do {
 +        uint32_t idx = util_atomic_xadd32(counter, 1);
 +        if (idx >= count) {
 +            *counter = count;
 +            return;
 +        }
 +        if (!ir_function_finalize(list[idx]->ir_func)) {
 +            con_out("failed to finalize function %s\n", list[idx]->name);
 +            *failure = true;
 +            return;
 +        }
 +    } while (true);
 +}
 +
 +typedef struct {
 +    ast_function     **list;
 +    size_t             count;
 +    volatile uint32_t *counter;
 +    bool              *failure;
 +} function_finalize_worker_data;
 +static void* function_finalize_worker(void *_d) {
 +    function_finalize_worker_data *d = (function_finalize_worker_data*)_d;
 +    function_finalize_worker_do(d->list, d->count, d->counter, d->failure);
 +    return NULL;
 +}
 +
 +static bool function_finalize_all_threaded(ast_function **list, size_t count)
 +{
 +    volatile uint32_t counter = 0;
 +    function_finalize_worker_data wd;
 +
 +    size_t poolsize = OPTS_OPTION_U32(OPTION_J);
 +    bool   failure = false;
 +    size_t i, j;
 +
 +    pthread_t *threads;
 +
 +    if (!list || !count)
 +        return true;
 +
 +    wd.list    = list;
 +    wd.count   = count;
 +    wd.counter = &counter;
 +    wd.failure = &failure;
 +
-     for (i = 0; i < count; ++i) {
-         if (!ir_function_optimize(list[i]->ir_func)) {
-             con_out("failed to optimize function %s\n", list[i]->name);
-             return false;
-         }
-     }
++    threads = (pthread_t*)mem_a(poolsize*sizeof(pthread_t));
 +
 +    for (i = 0; i < poolsize; ++i) {
 +        if (pthread_create(threads+i, NULL, &function_finalize_worker, &wd) != 0)
 +            break;
 +    }
 +    if (i < poolsize) {
 +        con_out("failed to spawn worker threads\n");
 +        for (j = 0; j <= i; ++j)
 +            pthread_join(threads[j], NULL);
 +        return false;
 +    }
 +    for (i = 0; i < poolsize; ++i)
 +        pthread_join(threads[i], NULL);
 +    return !failure;
 +}
 +
 +bool function_finalize_all(ast_function **list, size_t count)
 +{
 +    size_t i;
 +    if (OPTS_OPTION_U32(OPTION_J) > 1)
 +        return function_finalize_all_threaded(list, count);
++
 +    for (i = 0; i < count; ++i) {
 +        if (!ir_function_finalize(list[i]->ir_func)) {
 +            con_out("failed to finalize function %s\n", list[i]->name);
 +            return false;
 +        }
 +    }
 +    return true;
 +}
 +
  bool parser_finish(parser_t *parser, const char *output)
  {
      size_t i;
              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);
          }
      }
      }
      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;
              return false;
          }
      }
+     generate_checksum(parser);
      if (OPTS_OPTION_BOOL(OPTION_DUMP))
          ir_builder_dump(ir, con_out);
-     if (!ir_builder_prepare(ir)) {
-         con_out("failed to prepare builder for output\n");
-         ir_builder_delete(ir);
-         return false;
-     }
 +
 +#if 0
      for (i = 0; i < vec_size(parser->functions); ++i) {
          if (!ir_function_finalize(parser->functions[i]->ir_func)) {
              con_out("failed to finalize function %s\n", parser->functions[i]->name);
              return false;
          }
      }
++
 +#else
 +    if (!function_finalize_all(parser->functions, vec_size(parser->functions))) {
 +        ir_builder_delete(ir);
 +        return false;
 +    }
 +#endif
 +
+     parser_remove_ast(parser);
      if (compile_Werrors) {
          con_out("*** there were warnings treated as errors\n");
          compile_show_werrors();
          if (OPTS_OPTION_BOOL(OPTION_DUMPFIN))
              ir_builder_dump(ir, con_out);
  
-         generate_checksum(parser);
 -        if (!ir_builder_generate(parser->code, ir, output)) {
 +        if (!ir_builder_generate(ir, output)) {
              con_out("*** failed to generate output file\n");
              ir_builder_delete(ir);
              return false;
          }
      }
      ir_builder_delete(ir);
      return retval;
  }