]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'master' into cooking
authorWolfgang Bumiller <blub@speed.at>
Sun, 3 Feb 2013 18:01:30 +0000 (19:01 +0100)
committerWolfgang Bumiller <blub@speed.at>
Sun, 3 Feb 2013 18:01:30 +0000 (19:01 +0100)
87 files changed:
.gitignore
AUTHORS
CHANGES
Makefile
ast.c
ast.h
code.c
correct.c
distro/arch/git/PKGBUILD [deleted file]
distro/arch/release/PKGBUILD [deleted file]
distro/archbsd/git/PKGBUILD [new file with mode: 0644]
distro/archbsd/release/PKGBUILD [new file with mode: 0644]
distro/archlinux/git/PKGBUILD [new file with mode: 0644]
distro/archlinux/release/PKGBUILD [new file with mode: 0644]
distro/archlinux/this/Makefile [new file with mode: 0644]
distro/deb/Makefile [new file with mode: 0644]
distro/deb/control [new file with mode: 0644]
doc/gmqcc.1
doc/qcvm.1
exec.c
ftepp.c
gmqcc.h
ir.c
lexer.c
lexer.h
main.c
opts.c
opts.def
parser.c
test.c
tests/arrays.qc
tests/bitnot.qc [new file with mode: 0644]
tests/bitnot.tmpl [new file with mode: 0644]
tests/break.qc
tests/builtin.qc
tests/builtin.tmpl
tests/calls.qc
tests/calls.tmpl
tests/correct-logic.qc
tests/correct-vs-short.qc
tests/defs.qh [new file with mode: 0644]
tests/enum.qc
tests/equality.qc
tests/equality.tmpl
tests/fieldparams.qc
tests/fieldparams.tmpl
tests/functions-as-params.qc
tests/functions-as-params.tmpl
tests/goto.qc
tests/goto.tmpl
tests/ifs.qc
tests/ifs.tmpl
tests/mul_vf.qc
tests/ngraphs.qc
tests/ngraphs.tmpl
tests/noreturn.qc
tests/noreturn1.tmpl
tests/noreturn2.tmpl
tests/noreturn3.tmpl
tests/noreturn4.tmpl
tests/operators.qc
tests/param8.qc
tests/param8.tmpl
tests/parens.qc [new file with mode: 0644]
tests/parens.tmpl [new file with mode: 0644]
tests/perl-logic.qc
tests/pmacros.qc
tests/pmacros.tmpl
tests/pointlife.qc
tests/pp_va_args.qc
tests/pp_va_args.tmpl
tests/short-logic.qc
tests/switch.qc
tests/ternary.qc
tests/truth-flags-2.qc
tests/truth.qc
tests/typedefs.qc
tests/typedefs.tmpl
tests/uninit.qc
tests/utf8.qc
tests/varargs.qc
tests/varargs.tmpl
tests/variadic.qc
tests/variadic.tmpl
tests/vec_ops.qc
tests/vector-init.qc
util.c

index 1a07cbe457c4b3ffb0b7ca28260615a2870660f0..8ccf6a5aa127fe88c83f9faf22af1e1703ddc857 100644 (file)
@@ -11,3 +11,6 @@ gmqcc
 distro/arch/*
 !distro/arch/git/PKGBUILD
 !distro/arch/release/PKGBUILD
+!distro/arch/bsd-release/PKGBUILD
+!distro/arch/bsd-git/PKGBUILD
+!distro/arch/this/Makefile
diff --git a/AUTHORS b/AUTHORS
index 08c040e31d697fa1e13e4cd71b8c1306bdc8ff96..472760fb07b3c91c525d1a9b58acb8a19afadc6a 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,3 +1,9 @@
-GMQCC brought to you by:
-    Dale Weiler
-    Wolfgang Bumiller
+Authors:
+    Dale Weiler       - Charismatic Visionary / Programmer
+    Wolfgang Bumiller - Main Programmer
+
+Thanks to:
+    Forest `LordHavoc` Hale        - Technical support and assistance
+    Rudolf `divVerent` Polzer      - Technical support and assistance
+    Matthias `matthiaskrgr` Krüger - Miscellaneous assistance
+    Samual  `Samual` Lenks         - Preprocessor assistance
diff --git a/CHANGES b/CHANGES
index e147a0c8bc7d0ba59a29de4634a9c40e76177640..7a0013b82223057a3e28e091d0f8a25c4ab8ca1f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -25,6 +25,10 @@ Release v0.2.4
         - Various optimizations and progs-size reductions.
         - A new spell-checking algorithm tries to hint you at existing
           variables on error.
+        - Some problems with VM related vector-instructions issues
+          have been solved in both DP and our own executor. A new
+          compatbility option (enabled by default) has been added for
+          now: -flegacy-vector-maths
     * qcvm:
         - Improved commandline argument handling.
         - More builtins: sqrt(), normalize()
index 33b77c9d9fe564193a0c5c83c1237d1ee4b844a9..e31c0987124ba0596fd39040d18a920c312cabfe 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,22 +9,24 @@ CYGWIN  = $(findstring CYGWIN,  $(UNAME))
 MINGW   = $(findstring MINGW32, $(UNAME))
 
 CC     ?= clang
-CFLAGS += -Wall -Wextra -I. -fno-strict-aliasing -fsigned-char
+CFLAGS += -Wall -Wextra -I. -fno-strict-aliasing -fsigned-char -Wno-overlength-strings
 ifneq ($(shell git describe --always 2>/dev/null),)
     CFLAGS += -DGMQCC_GITINFO="\"$(shell git describe --always)\""
 endif
 #turn on tons of warnings if clang is present
 # but also turn off the STUPID ONES
 ifeq ($(CC), clang)
-       CFLAGS +=                         \
-               -Weverything                  \
-               -Wno-padded                   \
-               -Wno-format-nonliteral        \
-               -Wno-disabled-macro-expansion \
-               -Wno-conversion               \
-               -Wno-missing-prototypes       \
-               -Wno-float-equal              \
-               -Wno-cast-align
+       CFLAGS +=                               \
+               -Weverything                       \
+               -Wno-padded                        \
+               -Wno-format-nonliteral             \
+               -Wno-disabled-macro-expansion      \
+               -Wno-conversion                    \
+               -Wno-missing-prototypes            \
+               -Wno-float-equal                   \
+               -Wno-cast-align                    \
+               -Wno-missing-variable-declarations \
+               -Wno-unknown-warning-option
 else
        #Tiny C Compiler doesn't know what -pedantic-errors is
        # and instead of ignoring .. just errors.
@@ -179,8 +181,14 @@ install-qcvm: $(QCVM)
        install    -m755  $(QCVM)      $(DESTDIR)$(BINDIR)/qcvm
 install-doc:
        install -d -m755               $(DESTDIR)$(MANDIR)/man1
-       install    -m755  doc/gmqcc.1  $(DESTDIR)$(MANDIR)/man1/
-       install    -m755  doc/qcvm.1   $(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
 
 # DO NOT DELETE
 
diff --git a/ast.c b/ast.c
index 5a553cfffbf3fe366084b9ba15e48d719853c03b..7f6841fb96aea414e5d7f6afa78922b4f7d995f3 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -348,7 +348,7 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
     self->getter = NULL;
     self->desc   = NULL;
 
-    self->argcounter = NULL;
+    self->argcounter  = NULL;
 
     return self;
 }
@@ -1083,8 +1083,9 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype)
     vtype->hasvalue = true;
     vtype->constval.vfunc = self;
 
-    self->varargs = NULL;
-    self->argc    = NULL;
+    self->varargs     = NULL;
+    self->argc        = NULL;
+    self->fixedparams = NULL;
 
     return self;
 }
@@ -1112,6 +1113,8 @@ void ast_function_delete(ast_function *self)
         ast_delete(self->varargs);
     if (self->argc)
         ast_delete(self->argc);
+    if (self->fixedparams)
+        ast_unref(self->fixedparams);
     mem_d(self);
 }
 
@@ -1121,8 +1124,12 @@ const char* ast_function_label(ast_function *self, const char *prefix)
     size_t len;
     char  *from;
 
-    if (!opts.dump && !opts.dumpfin && !opts.debug)
+    if (!OPTS_OPTION_BOOL(OPTION_DUMP)    &&
+        !OPTS_OPTION_BOOL(OPTION_DUMPFIN) &&
+        !OPTS_OPTION_BOOL(OPTION_DEBUG))
+    {
         return NULL;
+    }
 
     id  = (self->labelcount++);
     len = strlen(prefix);
@@ -1228,7 +1235,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
             }
 
             /* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
-            if (!array->expression.count || array->expression.count > opts.max_array_size)
+            if (!array->expression.count || array->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE))
                 compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
 
             elemtype = &array->expression.next->expression;
@@ -1290,7 +1297,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
         int vtype = elemtype->vtype;
 
         /* same as with field arrays */
-        if (!self->expression.count || self->expression.count > opts.max_array_size)
+        if (!self->expression.count || self->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE))
             compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
 
         v = ir_builder_create_global(ir, self->name, vtype);
@@ -1427,7 +1434,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
         }
 
         /* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
-        if (!self->expression.count || self->expression.count > opts.max_array_size) {
+        if (!self->expression.count || self->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE)) {
             compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
         }
 
@@ -1612,13 +1619,23 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
 
     if (self->argc) {
         ir_value *va_count;
+        ir_value *fixed;
+        ir_value *sub;
         if (!ast_local_codegen(self->argc, self->ir_func, true))
             return false;
         cgen = self->argc->expression.codegen;
         if (!(*cgen)((ast_expression*)(self->argc), self, false, &va_count))
             return false;
+        cgen = self->fixedparams->expression.codegen;
+        if (!(*cgen)((ast_expression*)(self->fixedparams), self, false, &fixed))
+            return false;
+        sub = ir_block_create_binop(self->curblock, ast_ctx(self),
+                                    ast_function_label(self, "va_count"), INSTR_SUB_F,
+                                    ir_builder_get_va_count(ir), fixed);
+        if (!sub)
+            return false;
         if (!ir_block_create_store_op(self->curblock, ast_ctx(self), INSTR_STORE_F,
-                                      va_count, ir_builder_get_va_count(ir)))
+                                      va_count, sub))
         {
             return false;
         }
@@ -1689,7 +1706,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu
     for (i = 0; i < vec_size(self->locals); ++i)
     {
         if (!ast_local_codegen(self->locals[i], func->ir_func, false)) {
-            if (opts.debug)
+            if (OPTS_OPTION_BOOL(OPTION_DEBUG))
                 compile_error(ast_ctx(self), "failed to generate local `%s`", self->locals[i]->name);
             return false;
         }
@@ -2817,7 +2834,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
         return true;
 
     cmpinstr = type_eq_instr[irop->vtype];
-    if (cmpinstr >= AINSTR_END) {
+    if (cmpinstr >= VINSTR_END) {
         ast_type_to_string(self->operand, typestr, sizeof(typestr));
         compile_error(ast_ctx(self), "invalid type to perform a switch on: %s", typestr);
         return false;
diff --git a/ast.h b/ast.h
index 2e9858fc85054ed6c6ff81dd7ebbe295d7bd7e77..94f388e596a36ee395788a29585799d83a49546d 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -648,6 +648,7 @@ struct ast_function_s
 
     ast_value   *varargs;
     ast_value   *argc;
+    ast_value   *fixedparams;
 };
 ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype);
 /* This will NOT delete the underlying ast_value */
diff --git a/code.c b/code.c
index 713d98dbad964cfc80ff2350dce40d5684d93206..43a34c9de78aec26749824fc03d436b502538c5c 100644 (file)
--- a/code.c
+++ b/code.c
@@ -137,8 +137,8 @@ bool code_write(const char *filename, const char *lnofile) {
     code_header.strings.offset    = code_header.globals.offset    + (sizeof(int32_t)                * vec_size(code_globals));
     code_header.strings.length    = vec_size(code_chars);
     code_header.version           = 6;
-    if (opts.forcecrc)
-        code_header.crc16         = opts.forced_crc;
+    if (OPTS_OPTION_BOOL(OPTION_FORCECRC))
+        code_header.crc16         = OPTS_OPTION_U16(OPTION_FORCED_CRC);
     else
         code_header.crc16         = code_crc;
     code_header.entfield          = code_entfields;
index aa94ee697081fb861f3fc438d3524f2cd0d70463..6f234b0a2e985608aa777127370bd65259fca927 100644 (file)
--- a/correct.c
+++ b/correct.c
  *   edit distance the smaller the error.  This usually causes some un-
  *   expected problems. e.g reciet->recite yields recipt.  For QuakeC
  *   this could become a problem when lots of identifiers are involved. 
- *
- *   Our control mechanisim could use a limit, i.e limit the number of
- *   sets of edits for distance X.  This would also increase execution
- *   speed considerably.
  */
 
 
@@ -217,7 +213,7 @@ correct_trie_t* correct_trie_new() {
     return t;
 }
 
-void correct_trie_del_sub(correct_trie_t *t) {
+static GMQCC_INLINE void correct_trie_del_sub(correct_trie_t *t) {
     size_t i;
     if (!t->entries)
         return;
@@ -227,7 +223,7 @@ void correct_trie_del_sub(correct_trie_t *t) {
     mem_d(t->entries);
 }
 
-void correct_trie_del(correct_trie_t *t) {
+static GMQCC_INLINE void correct_trie_del(correct_trie_t *t) {
     size_t i;
     if (t->entries) {
         for (i = 0; i < sizeof(correct_alpha)-1; ++i)
@@ -237,7 +233,7 @@ void correct_trie_del(correct_trie_t *t) {
     mem_d(t);
 }
 
-void* correct_trie_get(const correct_trie_t *t, const char *key) {
+static GMQCC_INLINE void* correct_trie_get(const correct_trie_t *t, const char *key) {
     const unsigned char *data = (const unsigned char*)key;
 
     while (*data) {
@@ -249,7 +245,7 @@ void* correct_trie_get(const correct_trie_t *t, const char *key) {
     return t->value;
 }
 
-void correct_trie_set(correct_trie_t *t, const char *key, void * const value) {
+static GMQCC_INLINE void correct_trie_set(correct_trie_t *t, const char *key, void * const value) {
     const unsigned char *data = (const unsigned char*)key;
     while (*data) {
         if (!t->entries) {
@@ -320,7 +316,7 @@ void correct_del(correct_trie_t* dictonary, size_t **data) {
  * need to take a size_t ** to carry it along (would all the argument
  * overhead be worth it?)  
  */
-static size_t correct_deletion(const char *ident, char **array) {
+static GMQCC_INLINE size_t correct_deletion(const char *ident, char **array) {
     size_t       itr = 0;
     const size_t len = strlen(ident);
 
@@ -334,7 +330,7 @@ static size_t correct_deletion(const char *ident, char **array) {
     return itr;
 }
 
-static size_t correct_transposition(const char *ident, char **array) {
+static GMQCC_INLINE size_t correct_transposition(const char *ident, char **array) {
     size_t       itr = 0;
     const size_t len = strlen(ident);
 
@@ -351,7 +347,7 @@ static size_t correct_transposition(const char *ident, char **array) {
     return itr;
 }
 
-static size_t correct_alteration(const char *ident, char **array) {
+static GMQCC_INLINE size_t correct_alteration(const char *ident, char **array) {
     size_t       itr = 0;
     size_t       jtr = 0;
     size_t       ktr = 0;
@@ -369,7 +365,7 @@ static size_t correct_alteration(const char *ident, char **array) {
     return ktr;
 }
 
-static size_t correct_insertion(const char *ident, char **array) {
+static GMQCC_INLINE size_t correct_insertion(const char *ident, char **array) {
     size_t       itr = 0;
     size_t       jtr = 0;
     const size_t len = strlen(ident);
@@ -399,11 +395,12 @@ static GMQCC_INLINE size_t correct_size(const char *ident) {
     return (len) + (len - 1) + (len * (sizeof(correct_alpha)-1)) + ((len + 1) * (sizeof(correct_alpha)-1));
 }
 
-static char **correct_edit(const char *ident) {
+static GMQCC_INLINE char **correct_edit(const char *ident, size_t **lens) {
     size_t next;
-    char **find = (char**)correct_pool_alloc(correct_size(ident) * sizeof(char*));
+    size_t size = correct_size(ident);
+    char **find = (char**)correct_pool_alloc(size * sizeof(char*));
 
-    if (!find)
+    if (!find || !(*lens = (size_t*)correct_pool_alloc(size * sizeof(size_t))))
         return NULL;
 
     next  = correct_deletion     (ident, find);
@@ -411,44 +408,21 @@ static char **correct_edit(const char *ident) {
     next += correct_alteration   (ident, find+next);
     /*****/ correct_insertion    (ident, find+next);
 
+    /* precompute lengths */
+    for (next = 0; next < size; next++)
+        (*lens)[next] = strlen(find[next]);
+
     return find;
 }
 
-/*
- * We could use a hashtable but the space complexity isn't worth it
- * since we're only going to determine the "did you mean?" identifier
- * on error.
- */
-static int correct_exist(char **array, size_t rows, char *ident) {
+static GMQCC_INLINE int correct_exist(char **array, register size_t *sizes, size_t rows, char *ident, register size_t len) {
     size_t itr;
-    /*
-     * As an experiment I tried the following assembly for memcmp here:
-     *
-     * correct_cmp_loop: 
-     * incl %eax            ; eax =  LHS
-     * incl %edx            ; edx =  LRS
-     * cmpl %eax, %ebx      ; ebx = &LHS[END_POS]
-     *
-     * jbe correct_cmp_eq
-     * movb (%edx), %cl     ; micro-optimized even on atoms :-)
-     * cmpb %cl, (%eax)     ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-     * jg  correct_cmp_gt
-     * jge correct_cmp_loop
-     * ...
-     *
-     * Despite how much optimization went in to this, the speed was
-     * being conflicted by the strlen(ident) used for &LHS[END_POS]
-     * If we could eliminate the strlen with what I suggested on line
-     * 311 ... we can accelerate this whole damn thing quite a bit.
-     *
-     * However there is still something we can do here that does give
-     * us a little more speed.  Although one more branch, we know for
-     * sure there is at least one byte to compare, if that one byte
-     * simply isn't the same we can skip the full check. Which means
-     * we skip a whole strlen call.
-     */
     for (itr = 0; itr < rows; itr++) {
-        if (!memcmp(array[itr], ident, strlen(ident)))
+        /*
+         * We can save tons of calls to memcmp if we simply ignore comparisions
+         * that we know cannot contain the same length.
+         */   
+        if (sizes[itr] == len && !memcmp(array[itr], ident, len))
             return 1;
     }
 
@@ -461,7 +435,7 @@ static GMQCC_INLINE char **correct_known_resize(char **res, size_t *allocated, s
     if (size < oldallocated)
         return res;
 
-    out = correct_pool_alloc(sizeof(*res) * oldallocated + 32);
+    out = (char**)correct_pool_alloc(sizeof(*res) * oldallocated + 32);
     memcpy(out, res, sizeof(*res) * oldallocated);
 
     *allocated += 32;
@@ -474,22 +448,25 @@ static char **correct_known(correction_t *corr, correct_trie_t* table, char **ar
     size_t len = 0;
     size_t row = 0;
     size_t nxt = 8;
-    char **res = correct_pool_alloc(sizeof(char *) * nxt);
-    char **end = NULL;
+    char   **res = (char**)correct_pool_alloc(sizeof(char *) * nxt);
+    char   **end = NULL;
+    size_t  *bit = NULL;
 
     for (; itr < rows; itr++) {
         if (!array[itr][0])
             continue;
-        if (vec_size(corr->edits) > itr+1)
+        if (vec_size(corr->edits) > itr+1) {
             end = corr->edits[itr+1];
-        else {
-            end = correct_edit(array[itr]);
+            bit = corr->lens [itr+1];
+        } else {
+            end = correct_edit(array[itr], &bit);
             vec_push(corr->edits, end);
+            vec_push(corr->lens,  bit);
         }
         row = correct_size(array[itr]);
 
         for (jtr = 0; jtr < row; jtr++) {
-            if (correct_find(table, end[jtr]) && !correct_exist(res, len, end[jtr])) {
+            if (correct_find(table, end[jtr]) && !correct_exist(res, bit, len, end[jtr], bit[jtr])) {
                 res        = correct_known_resize(res, &nxt, len+1);
                 res[len++] = end[jtr];
             }
@@ -500,7 +477,7 @@ static char **correct_known(correction_t *corr, correct_trie_t* table, char **ar
     return res;
 }
 
-static char *correct_maximum(correct_trie_t* table, char **array, size_t rows) {
+static GMQCC_INLINE char *correct_maximum(correct_trie_t* table, char **array, size_t rows) {
     char   *str = NULL;
     size_t *itm = NULL;
     size_t  itr = 0;
@@ -525,11 +502,13 @@ void correct_init(correction_t *c)
 {
     correct_pool_new();
     c->edits = NULL;
+    c->lens  = NULL;
 }
 
 void correct_free(correction_t *c)
 {
     vec_free(c->edits);
+    vec_free(c->lens);
     correct_pool_delete();
 }
 
@@ -540,6 +519,7 @@ char *correct_str(correction_t *corr, correct_trie_t* table, const char *ident)
     char  *e2ident = NULL;
     size_t e1rows  = 0;
     size_t e2rows  = 0;
+    size_t *bits   = NULL;
 
     /* needs to be allocated for free later */
     if (correct_find(table, ident))
@@ -549,8 +529,9 @@ char *correct_str(correction_t *corr, correct_trie_t* table, const char *ident)
         if (vec_size(corr->edits) > 0)
             e1 = corr->edits[0];
         else {
-            e1 = correct_edit(ident);
+            e1 = correct_edit(ident, &bits);
             vec_push(corr->edits, e1);
+            vec_push(corr->lens,  bits);
         }
 
         if ((e1ident = correct_maximum(table, e1, e1rows)))
diff --git a/distro/arch/git/PKGBUILD b/distro/arch/git/PKGBUILD
deleted file mode 100644 (file)
index a0cd450..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
-
-pkgname=gmqcc-git
-pkgver=20130110
-pkgrel=1
-pkgdesc="An Improved Quake C Compiler"
-arch=('i686' 'x86_64')
-depends=('glibc')
-conflicts=('gmqcc')
-provides=('gmqcc=0.2.4')
-makedepends=('git')
-url="https://github.com/graphitemaster/gmqcc.git"
-license=('MIT')
-
-_gitroot="git://github.com/graphitemaster/gmqcc.git"
-_gitname="gmqcc"
-
-build() {
-       cd $srcdir
-       msg "Connecting to the GIT server..."
-       if [[ -d $srcdir/$_gitname ]] ; then
-               cd $_gitname
-               msg "Removing build files..."
-               git clean -dfx
-               msg "Updating..."
-               git pull --no-tags
-               msg "The local files are updated."
-       else
-               msg "Cloning..."
-               git clone $_gitroot $_gitname --depth 1
-               msg "Clone done."
-       fi
-
-       msg "Starting compilation..."
-       cd "$srcdir"/"$_gitname"
-
-       msg "Compiling..."
-       make
-}
-
-check() {
-       cd "$srcdir"/"$_gitname"
-       make check
-}
-
-package() {
-       cd "$srcdir"/"$_gitname"
-       msg "Compiling and installing to pkgdir this time..."
-       make install DESTDIR=$pkgdir PREFIX=/usr
-       msg "Compiling done."
-
-       install -D LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
-}
diff --git a/distro/arch/release/PKGBUILD b/distro/arch/release/PKGBUILD
deleted file mode 100644 (file)
index 1f8f66e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
-
-pkgname=gmqcc
-pkgver=0.2.2
-pkgrel=1
-pkgdesc="An Improved Quake C Compiler"
-arch=('i686' 'x86_64')
-depends=('glibc')
-url="https://github.com/graphitemaster/gmqcc.git"
-license=('MIT')
-source=(gmqcc-$pkgver.zip::https://github.com/graphitemaster/gmqcc/zipball/$pkgver)
-sha1sums=('8cd91dc13f70cd9d3767602bf3eb47a1906d9353')
-
-_gitname=graphitemaster-gmqcc-de24486/
-
-build() {
-       msg "Starting compilation..."
-       cd "$srcdir"/"$_gitname"
-
-       msg "Compiling..."
-       make
-}
-
-check() {
-       cd "$srcdir"/"$_gitname"
-       make check
-}
-
-package() {
-       cd "$srcdir"/"$_gitname"
-       msg "Compiling and installing to pkgdir this time..."
-       make install DESTDIR=$pkgdir PREFIX=/usr
-       msg "Compiling done."
-
-       install -D LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
-}
diff --git a/distro/archbsd/git/PKGBUILD b/distro/archbsd/git/PKGBUILD
new file mode 100644 (file)
index 0000000..2144110
--- /dev/null
@@ -0,0 +1,55 @@
+# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
+# Contributor: Wolfgang Bumiller <blub@speed.at>
+
+pkgname=gmqcc-git
+pkgver=20130127
+pkgrel=1
+pkgdesc="An Improved Quake C Compiler"
+arch=('i686' 'x86_64')
+depends=()
+conflicts=('gmqcc')
+provides=('gmqcc=0.2.4')
+makedepends=('git')
+url="https://github.com/graphitemaster/gmqcc.git"
+license=('MIT')
+
+_gitroot="git://github.com/graphitemaster/gmqcc.git"
+_gitname="gmqcc"
+
+build() {
+       cd $srcdir
+       msg "Connecting to the GIT server..."
+       if [[ -d $srcdir/$_gitname ]] ; then
+               cd $_gitname
+               msg "Removing build files..."
+               git clean -dfx
+               msg "Updating..."
+               git pull --no-tags
+               msg "The local files are updated."
+       else
+               msg "Cloning..."
+               git clone $_gitroot $_gitname --depth 1
+               msg "Clone done."
+       fi
+
+       msg "Starting compilation..."
+       cd "$srcdir"/"$_gitname"
+
+       msg "Compiling..."
+       gmake
+}
+
+check() {
+       cd "$srcdir"/"$_gitname"
+       gmake check
+}
+
+package() {
+       cd "$srcdir"/"$_gitname"
+       msg "Compiling and installing to pkgdir this time..."
+       gmake install DESTDIR=$pkgdir PREFIX=/usr/local MANDIR=/usr/local/man
+       msg "Compiling done."
+
+       install -dm755 ${pkgdir}/usr/local/share/licenses/gmqcc
+       install -m644 LICENSE ${pkgdir}/usr/local/share/licenses/gmqcc/LICENSE
+}
diff --git a/distro/archbsd/release/PKGBUILD b/distro/archbsd/release/PKGBUILD
new file mode 100644 (file)
index 0000000..8c449c6
--- /dev/null
@@ -0,0 +1,38 @@
+# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
+# Contributor: Wolfgang Bumiller <blub@speed.at>
+
+pkgname=gmqcc
+pkgver=0.2.2
+pkgrel=1
+pkgdesc="An Improved Quake C Compiler"
+arch=('i686' 'x86_64')
+depends=()
+url="https://github.com/graphitemaster/gmqcc.git"
+license=('MIT')
+source=(gmqcc-$pkgver.zip::https://github.com/graphitemaster/gmqcc/zipball/$pkgver)
+sha1sums=('8cd91dc13f70cd9d3767602bf3eb47a1906d9353')
+
+_gitname=graphitemaster-gmqcc-de24486/
+
+build() {
+       msg "Starting compilation..."
+       cd "$srcdir"/"$_gitname"
+
+       msg "Compiling..."
+       gmake
+}
+
+check() {
+       cd "$srcdir"/"$_gitname"
+       gmake check
+}
+
+package() {
+       cd "$srcdir"/"$_gitname"
+       msg "Compiling and installing to pkgdir this time..."
+       gmake install DESTDIR=$pkgdir PREFIX=/usr/local MANDIR=/usr/local/man
+       msg "Compiling done."
+
+       install -dm755 ${pkgdir}/usr/local/share/licenses/gmqcc
+       install -m644 LICENSE ${pkgdir}/usr/local/share/licenses/gmqcc/LICENSE
+}
diff --git a/distro/archlinux/git/PKGBUILD b/distro/archlinux/git/PKGBUILD
new file mode 100644 (file)
index 0000000..4a9127c
--- /dev/null
@@ -0,0 +1,53 @@
+# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
+
+pkgname=gmqcc-git
+pkgver=20130127
+pkgrel=1
+pkgdesc="An Improved Quake C Compiler"
+arch=('i686' 'x86_64')
+depends=('glibc')
+conflicts=('gmqcc')
+provides=('gmqcc=0.2.4')
+makedepends=('git')
+url="https://github.com/graphitemaster/gmqcc.git"
+license=('MIT')
+
+_gitroot="git://github.com/graphitemaster/gmqcc.git"
+_gitname="gmqcc"
+
+build() {
+       cd $srcdir
+       msg "Connecting to the GIT server..."
+       if [[ -d $srcdir/$_gitname ]] ; then
+               cd $_gitname
+               msg "Removing build files..."
+               git clean -dfx
+               msg "Updating..."
+               git pull --no-tags
+               msg "The local files are updated."
+       else
+               msg "Cloning..."
+               git clone $_gitroot $_gitname --depth 1
+               msg "Clone done."
+       fi
+
+       msg "Starting compilation..."
+       cd "$srcdir"/"$_gitname"
+
+       msg "Compiling..."
+       make
+}
+
+check() {
+       cd "$srcdir"/"$_gitname"
+       make check
+}
+
+package() {
+       cd "$srcdir"/"$_gitname"
+       msg "Compiling and installing to pkgdir this time..."
+       make install DESTDIR=$pkgdir PREFIX=/usr
+       msg "Compiling done."
+
+       install -D LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
+}
diff --git a/distro/archlinux/release/PKGBUILD b/distro/archlinux/release/PKGBUILD
new file mode 100644 (file)
index 0000000..1f8f66e
--- /dev/null
@@ -0,0 +1,36 @@
+# Contributor: matthiaskrgr <matthiaskrgr _strange_curverd_character_ freedroid D0T org>
+
+pkgname=gmqcc
+pkgver=0.2.2
+pkgrel=1
+pkgdesc="An Improved Quake C Compiler"
+arch=('i686' 'x86_64')
+depends=('glibc')
+url="https://github.com/graphitemaster/gmqcc.git"
+license=('MIT')
+source=(gmqcc-$pkgver.zip::https://github.com/graphitemaster/gmqcc/zipball/$pkgver)
+sha1sums=('8cd91dc13f70cd9d3767602bf3eb47a1906d9353')
+
+_gitname=graphitemaster-gmqcc-de24486/
+
+build() {
+       msg "Starting compilation..."
+       cd "$srcdir"/"$_gitname"
+
+       msg "Compiling..."
+       make
+}
+
+check() {
+       cd "$srcdir"/"$_gitname"
+       make check
+}
+
+package() {
+       cd "$srcdir"/"$_gitname"
+       msg "Compiling and installing to pkgdir this time..."
+       make install DESTDIR=$pkgdir PREFIX=/usr
+       msg "Compiling done."
+
+       install -D LICENSE ${pkgdir}/usr/share/licenses/gmqcc/LICENSE
+}
diff --git a/distro/archlinux/this/Makefile b/distro/archlinux/this/Makefile
new file mode 100644 (file)
index 0000000..6d3b557
--- /dev/null
@@ -0,0 +1,40 @@
+BASEDIR := ../../../
+PREFIX  := /usr
+HEADER  := $(BASEDIR)/gmqcc.h
+MAJOR   := $(shell sed -n -e '/GMQCC_VERSION_MAJOR/{s/.* .* //;p;q;}' $(HEADER))
+MINOR   := $(shell sed -n -e '/GMQCC_VERSION_MINOR/{s/.* .* //;p;q;}' $(HEADER))
+PATCH   := $(shell sed -n -e '/GMQCC_VERSION_PATCH/{s/.* .* //;p;q;}' $(HEADER))
+PKGREL  := 1
+CARCH   := $(shell uname -m)
+PKGDIR  := gmqcc-$(MAJOR).$(MINOR).$(PATCH)-$(PKGREL)-$(CARCH)
+PKG     := $(PKGDIR).pkg.tar.xz
+PKGINFO := $(PKGDIR)/.PKGINFO
+
+base: clean
+       $(MAKE) -C $(BASEDIR) DESTDIR=distro/archlinux/this/$(PKGDIR) PREFIX=$(PREFIX) install
+       @echo "pkgname = gmqcc" > $(PKGINFO)
+       @echo "pkgver = $(MAJOR).$(MINOR).$(PATCH)-$(PKGREL)" >> $(PKGINFO)
+       @echo "pkgdesc = An Improved Quake C Compiler" >> $(PKGINFO)
+       @echo "url = https://github.com/graphitemaster/gmqcc.git" >> $(PKGINFO)
+       @echo "builddate = `date -u \"+%s\"`" >> $(PKGINFO)
+       @echo "packager = Unknown Packager" >> $(PKGINFO)
+       @echo "size = `du -sk $(PKGDIR) | awk '{print $$1 * 1024}'`" >> $(PKGINFO)
+       @echo "arch = $(CARCH)" >> $(PKGINFO)
+       @echo "license = MIT" >> $(PKGINFO)
+       @echo "conflict = gmqcc" >> $(PKGINFO)
+       @echo "depend = glibc" >> $(PKGINFO)
+       @echo "makepkgopt = strip" >> $(PKGINFO)
+       @echo "makepkgopt = docs" >> $(PKGINFO)
+       @echo "makepkgopt = libtool" >> $(PKGINFO)
+       @echo "makepkgopt = emptydirs" >> $(PKGINFO)
+       @echo "makepkgopt = zipman" >> $(PKGINFO)
+       @echo "makepkgopt = purge" >> $(PKGINFO)
+       @echo "makepkgopt = !upx" >> $(PKGINFO)
+       @tar -cJvf $(PKG) -C $(PKGDIR)/ .PKGINFO usr/
+       @rm -rf $(PKGDIR)
+
+clean:
+       @rm -f  $(PKG)
+
+
+all: base
diff --git a/distro/deb/Makefile b/distro/deb/Makefile
new file mode 100644 (file)
index 0000000..535cf1c
--- /dev/null
@@ -0,0 +1,23 @@
+BASEDIR := ../..
+PREFIX  := /usr
+HEADER  := $(BASEDIR)/gmqcc.h
+MAJOR   := `sed -n -e '/GMQCC_VERSION_MAJOR/{s/.* .* //;p;q;}' $(HEADER)`
+MINOR   := `sed -n -e '/GMQCC_VERSION_MINOR/{s/.* .* //;p;q;}' $(HEADER)`
+PATCH   := `sed -n -e '/GMQCC_VERSION_PATCH/{s/.* .* //;p;q;}' $(HEADER)`
+DEBDIR  := gmqcc-$(MAJOR).$(MINOR).$(PATCH)
+DEB     := $(DEBDIR).deb
+
+base:
+       $(MAKE) -C $(BASEDIR) DESTDIR=distro/deb/$(DEBDIR) PREFIX=$(PREFIX) install
+       @install -d -m755 $(DEBDIR)/DEBIAN
+       @cp       control $(DEBDIR)/DEBIAN/control
+       @tar czf data.tar.gz -C $(DEBDIR)/ . --exclude=DEBIAN
+       @tar czf control.tar.gz -C $(DEBDIR)/DEBIAN/ .
+       @echo 2.0 > debian-binary
+       @ar r $(DEB) debian-binary control.tar.gz data.tar.gz
+       @rm -rf debian-binary control.tar.gz data.tar.gz $(DEBDIR)
+clean:
+       @rm -f $(DEB)
+
+
+all: base
diff --git a/distro/deb/control b/distro/deb/control
new file mode 100644 (file)
index 0000000..57cde3a
--- /dev/null
@@ -0,0 +1,13 @@
+Package: gmqcc
+Version: 0.3.0
+Section: user/hidden
+Priority: optional
+Architecture: i386
+Installed-Size: `du -ks usr|cut -f 1`
+Maintainer: Dale Weiler <killfieldengine@gmail.com>
+Description: An improved Quake C Compiler
+   For an enduring period of time the options for a decent compiler for the Quake C programming language
+   were confined to a specific compiler known as QCC. Attempts were made to extend and improve upon the
+   design of QCC, but many foreseen the consequences of building on a broken foundation. The solution
+   was obvious, a new compiler; one born from the NIH realm of sarcastic wit. We welcome you. You won't
+   find a better Quake C compiler.
index 74cdda4f72e7fdd9a876a0669f0db1b13a8640fd..59afdb99dd85abc5bce9239c2697ecbe2e968cf0 100644 (file)
-.\" Process with groff -man -Tascii file.3
-.TH GMQCC 1 2012-07-12 "" "gmqcc Manual"
-.SH NAME
-gmqcc \- A Quake C compiler built from the NIH realm of sarcastic wit
-.SH SYNOPSIS
-.B gmqcc
-[\fIOPTIONS\fR] [\fIfiles...\fR]
-.SH DESCRIPTION
-Traditionally, a QC compiler reads the file \fIprogs.src\fR which
-in its first line contains the output filename, and the rest is a
+.\"mdoc
+.Dd January 24, 2013
+.Dt GMQCC 1 PRM
+.Os
+.Sh NAME
+.Nm gmqcc
+.Nd A Quake C compiler built from the NIH realm of sarcastic wit
+.Sh SYNOPSIS
+.Nm gmqcc
+.Op Cm options
+.Op Ar files...
+.Sh DESCRIPTION
+Traditionally, a QC compiler reads the file
+.Pa progs.src
+which in its first line contains the output filename, and the rest is a
 list of QC source files that are to be compiled in order.
-\fBgmqcc\fR optionally takes options to specify the output and
+.Nm gmqcc
+optionally takes options to specify the output and
 input files on the commandline, and also accepts assembly files.
-.SH OPTIONS
-\fBgmqcc\fR mostly tries to mimic gcc's commandline handling, though
+.Sh OPTIONS
+.Nm gmqcc
+mostly tries to mimic gcc's commandline handling, though
 there are also traditional long-options available.
-.TP
-.B "-h, --help"
+.Bl -tag -width Ds
+.It Fl h , Fl -help
 Show a usage message and exit.
-.TP
-.B "-debug"
+.It Fl "debug"
 Turn on some compiler debugging mechanisms.
-.TP
-.B "-memchk"
+.It Fl memchk
 Turn on compiler mem-check. (Shows allocations and checks for leaks.)
-.TP
-.BI "-o, --output=" filename
+.It Fl o , Fl -output= Ns Ar filename
 Specify the output filename. Defaults to progs.dat. This will overwrite
-the output file listed in a \fIprogs.src\fR file in case such a file is used.
-.TP
-.BI "-O" number
+the output file listed in a
+.Pa progs.src
+file in case such a file is used.
+.Bl -tag -width indent
+.It Fl O Ns Ar number
 Specify the optimization level
-.RS
-.IP 3
+.It Ar 3
 Highest optimization level
-.IP 2
+.It Ar 2
 Default optimization level
-.IP 1
+.It Ar 1
 Minimal optimization level
-.IP 0
+.It Ar 0
 Disable optimization entirely
-.RE
-.TP
-.BI "-O" name "\fR, " "" -Ono- name
+.El
+.Pp
+.It Fl O Ns Ar name Fl Ono- Ns Ar name
 Enable or disable a specific optimization. Note that these options
 must be used after setting the optimization level, otherwise they'll
 be overwritten.
-.TP
-.B -Ohelp
+.It Fl O Ns Cm help
 List all possible optimizations and the optimization level they're
 activated at.
-.TP
-.BR -q ", " --quiet
+.It Fl q , Fl -quiet
 Be less verbose. In particular removes the messages about which files
 are being processed, and which compilation mode is being used, and
 some others. Warnings and errors will of course still be displayed.
-.TP
-.B "-E"
-Run only the preprocessor as if -fftepp was used and print the
-preprocessed code to stdout.
-.TP
-.BI -W warning "\fR, " "" -Wno- warning
+.It Fl E
+Run only the preprocessor as if
+.Fl f Ns Cm ftepp
+was used and print the preprocessed code to stdout.
+.It Fl W Ns Ar warning , Fl Wno- Ns Ar warning
 Enable or disable a warning.
-.TP
-.B -Wall
-Enable almost all warnings. Overrides preceding -W parameters.
-.sp
-The following warnings will \fBnot\fR be anbled:
-.in +4
-.nf
--Wuninitialized-global
-.fi
-.in
-.TP
-.BR -Werror ", " -Wno-error
+.It Fl W Ns Cm all
+Enable almost all warnings. Overrides preceding
+.Fl W
+parameters.
+.Pp
+The following warnings will
+.Em not
+be enabled:
+.Bl -tag -width indent -offset indent
+.It Fl W Ns Cm uninitialized-global
+.El
+.It Fl W Ns Cm error , Fl Wno- Ns Cm error
 Controls whether or not all warnings should be treated as errors.
-.TP
-.BI -Werror- warning "\fR, " "" -Wno-error- warning
+.It Fl Werror- Ns Ar warning , Fl Wno-error- Ns Ar warning
 Controls whether a specific warning should be an error.
-.TP
-.B -Whelp
+.It Fl W Ns Cm help
 List all possible warn flags.
-.TP
-.BI -f flag "\fR, " "" -fno- flag
+.It Fl f Ns Ar flag , Fl fno- Ns Ar flag
 Enable or disable a specific compile flag. See the list of flags
 below.
-.TP
-.B -fhelp
+.It Fl f Ns Cm help
 List all possible compile flags.
-.TP
-.B -nocolor
+.It Fl nocolor
 Disables colored output
-.TP
-.BI -config= file
-Use an ini file to read all the -O, -W and -f flag from. See the
-CONFIG section about the file format.
-.TP
-.BI "-redirout=" file
-Redirects standard output to a \fIfile\fR
-.TP
-.BI "-redirerr=" file
-Redirects standard error to a \fIfile\fR
-.TP
-.BI "-std=" standard
+.It Fl config= Ns Ar file
+Use an ini file to read all the
+.Fl O , Fl W
+and
+.Fl f
+flag from. See the
+.Sx CONFIG
+section about the file format.
+.It Fl redirout= Ns Ar file
+Redirects standard output to a
+.Ar file
+.It Fl redirerr= Ns Ar file
+Redirects standard error to a
+.Ar file
+.It Fl std= Ns Ar standard
 Use the specified standard for parsing QC code. The following standards
 are available:
-.IR gmqcc , qcc , fteqcc
-Selecting a standard also implies some -f options and behaves as if
-those options have been written right after the -std option, meaning
-if you changed them before the -std option, you're now overwriting
-them.
-.sp
-.BR -std=gmqcc " includes:"
-.in +4
-.nf
--fadjust-vector-fields
--fcorrect-logic
--ftrue-empty-strings
--floop-labels
--finitialized-nonconstants
--ftranslatable-strings
--f\fIno-\fRfalse-empty-strings
--Winvalid-parameter-count
--Wmissing-returnvalues
--fcorrect-ternary (cannot be turned off)
-.fi
-.in
-.sp
-.BR -std=qcc " includes:"
-.in +4
-.nf
--fassign-function-types
--f\fIno-\fRadjust-vector-fields
-.fi
-.in
-.sp
-.BR -std=fteqcc " includes:"
-.in +4
-.nf
--fftepp
--ftranslatable-strings
--fassign-function-types
--Wternary-precedence
--f\fIno-\fRadjust-vector-fields
--f\fIno-\fRcorrect-ternary
-.fi
-.in
-.TP
-.B "--add-info"
+.Ar gmqcc , Ar qcc , Ar fteqcc
+Selecting a standard also implies some
+.Fl f
+options and behaves as if
+those options have been written right after the
+.Fl std
+option, meaning
+if you changed them before the
+.Fl -std
+option, you're now overwriting them.
+.Pp
+.Fl std= Ns Cm gmqcc No includes:
+.Bl -tag -width indent -compact -offset Ds
+.It Fl f Ns Cm adjust-vector-fields
+.It Fl f Ns Cm correct-logic
+.It Fl f Ns Cm true-empty-strings
+.It Fl f Ns Cm loop-labels
+.It Fl f Ns Cm initialized-nonconstants
+.It Fl f Ns Cm translatable-strings
+.It Fl fno- Ns Cm false-empty-strings
+.It Fl W Ns Cm invalid-parameter-count
+.It Fl W Ns Cm missing-returnvalues
+.It Fl f Ns Cm correct-ternary Li (cannot be turned off)
+.El
+.Pp
+.Fl std= Ns Cm qcc No includes:
+.Bl -tag -width indent -compact -offset Ds
+.It Fl f Ns Cm assign-function-types
+.It Fl fIno- Ns Cm adjust-vector-fields
+.El
+.Pp
+.Fl std= Ns Cm fteqcc No includes:
+.Bl -tag -width indent -compact -offset Ds
+.It Fl f Ns Cm ftepp
+.It Fl f Ns Cm translatable-strings
+.It Fl f Ns Cm assign-function-types
+.It Fl W Ns Cm ternary-precedence
+.It Fl fno- Ns Cm adjust-vector-fields
+.It Fl fno- Ns Cm correct-ternary
+.El
+.It Fl -add-info
 Adds compiler information to the generated binary file. Currently
 this includes the following globals:
-.RS
-.IP "reserved:version"
+.Bl -tag -width indent -compact
+.It Li reserved:version
 String containing the compiler version as printed by the --version
 parameter.
-.RE
-.TP
-.BR "--correct" ", " "--no-correct"
+.El
+.It Fl -correct , Fl -no-correct
 When enabled, errors about undefined values try to suggest an existing
 value via spell checking.
-.TP
-.B "-dump"
+.It Fl dump
 DEBUG OPTION. Print the code's intermediate representation before the
 optimization and finalization passes to stdout before generating the
 binary.
-.TP
-.B "-dumpfin"
+.It Fl dumpfin
 DEBUG OPTION. Print the code's intermediate representation after the
 optimization and finalization passes to stdout before generating the
 binary. The instructions will be enumerated, and values will contain a
 list of liferanges.
-.SH COMPILE WARNINGS
-.TP
-.B -Wunused-variable
+.El
+.Sh COMPILE WARNINGS
+.Bl -tag -width Ds
+.It Fl W Ns Cm unused-variable
 Generate a warning about variables which are declared but never used.
-This can be avoided by adding the \fInoref\fR keyword in front of the
+This can be avoided by adding the
+.Ql noref
+keyword in front of the
 variable declaration. Additionally a complete section of unreferenced
-variables can be opened using \fI#pragma noref 1\fR, and closed via
-\fI#pragma noref 0\fR.
-.TP
-.B -Wused-uninitialized
+variables can be opened using
+.Ql #pragma noref 1
+and closed via
+.Ql #pragma noref 0 Ns .
+.It Fl W Ns Cm used-uninitialized
 Generate a warning if it is possible that a variable can be used
 without prior initialization. Note that this warning is not
 necessarily reliable if the initialization happens only under certain
-conditions. The other way is \fInot\fR possible: that the warning is
-\fInot\fR generated when uninitialized use \fIis possible\fR.
-.TP
-.B -Wunknown-control-sequence
+conditions. The other way is
+.Em not
+possible: that the warning is
+.Em not
+generated when uninitialized use
+.Em is
+possible.
+.It Fl W Ns Cm unknown-control-sequence
 Generate an error when an unrecognized control sequence in a string is
 used. Meaning: when there's a character after a backslash in a string
 which has no known meaning.
-.TP
-.B -Wextensions
+.It Fl W Ns Cm extensions
 Warn when using special extensions which are not part of the selected
 standard.
-.TP
-.B -Wfield-redeclared
+.It Fl W Ns Cm field-redeclared
 Generally QC compilers ignore redeclaration of fields. Here you can
 optionally enable a warning.
-.TP
-.B -Wmissing-return-values
-Functions which aren't of type \fIvoid\fR will warn if it possible to
+.It Fl W Ns Cm missing-return-values
+Functions which aren't of type
+.Ft void
+will warn if it possible to
 reach the end without returning an actual value.
-.TP
-.B -Winvalid-parameter-count
+.It Fl W Ns Cm invalid-parameter-count
 Warn about a function call with an invalid number of parameters.
-.TP
-.B -Wlocal-shadows
+.It Fl W Ns Cm local-shadows
 Warn when a locally declared variable shadows variable.
-.TP
-.B -Wlocal-constants
+.It Fl W Ns Cm local-constants
 Warn when the initialization of a local variable turns the variable
 into a constant. This is default behaviour unless
-\fI-finitialized-nonconstants\fR is used.
-.TP
-.B -Wvoid-variables
-There are only 2 known global variables of type void: end_sys_globals
-and end_sys_fields. Any other void-variable will warn.
-.TP
-.B -Wimplicit-function-pointer
-A global function which is not declared with the \fIvar\fR keyword is
+.Fl f Ns Cm initialized-nonconstants
+is used.
+.It Fl W Ns Cm void-variables
+There are only 2 known global variables of type void:
+.Ql end_sys_globals
+and
+.Ql end_sys_fields Ns .
+Any other void-variable will warn.
+.It Fl W Ns Cm implicit-function-pointer
+A global function which is not declared with the
+.Ql var
+keyword is
 expected to have an implementing body, or be a builtin. If neither is
 the case, it implicitly becomes a function pointer, and a warning is
 generated.
-.TP
-.B -Wvariadic-function
+.It Fl W Ns Cm variadic-function
 Currently there's no way for an in QC implemented function to access
 variadic parameters. If a function with variadic parameters has an
 implementing body, a warning will be generated.
-.TP
-.B -Wframe-macros
-Generate warnings about \fI$frame\fR commands, for instance about
+.It Fl W Ns Cm frame-macros
+Generate warnings about
+.Ql $frame
+commands, for instance about
 duplicate frame definitions.
-.TP
-.B -Weffectless-statement
+.It Fl W Ns Cm effectless-statement
 Warn about statements which have no effect. Any expression which does
 not call a function or assigns a variable.
-.TP
-.B -Wend-sys-fields
-The \fIend_sys_fields\fR variable is supposed to be a global variable
-of type \fIvoid\fR. It is also recognized as a \fIfield\fR but this
+.It Fl W Ns Cm end-sys-fields
+The
+.Ql end_sys_fields
+variable is supposed to be a global variable
+of type
+.Ft void Ns .
+It is also recognized as a \fIfield\fR but this
 will generate a warning.
-.TP
-.B -Wassign-function-types
+.It Fl W Ns Cm assign-function-types
 Warn when assigning to a function pointer with an unmatching
 signature. This usually happens in cases like assigning the null
 function to an entity's .think function pointer.
-.TP
-.B -Wpreprocessor
-Enable warnings coming from the preprocessor. Like duplicate macro
-declarations. This warning triggers when there's a problem with the
-way the preprocessor has been used, it will \fBnot\fR affect warnings
-generated with the '#warning' directive. See -Wcpp.
-.TP
-.B -Wcpp
+.It Fl W Ns Cm cpp
 Show warnings created using the preprocessor's '#warning' directive.
-.TP
-.B -Wmultifile-if
+.It Fl W Ns Cm multifile-if
 Warn if there's a preprocessor \fI#if\fR spanning across several
 files.
-.TP
-.B -Wdouble-declaration
+.It Fl W Ns Cm double-declaration
 Warn about multiple declarations of globals. This seems pretty common
 in QC code so you probably do not want this unless you want to clean
 up your code.
-.TP
-.B -Wconst-var
+.It Fl W Ns Cm const-var
 The combination of \fIconst\fR and \fIvar\fR is not illegal, however
 different compilers may handle them differently. We were told, the
 intention is to create a function-pointer which is not assignable.
 This is exactly how we interpret it. However for this interpretation
-the \fIvar\fR keyword is considered superfluous (and philosophically
+the
+.Ql var
+keyword is considered superfluous (and philosophically
 wrong), so it is possible to generate a warning about this.
-.TP
-.B -Wmultibyte-character
+.It Fl W Ns Cm multibyte-character
 Warn about multibyte character constants, they do not work right now.
-.TP
-.B -Wternary-precedence
+.It Fl W Ns Cm ternary-precedence
 Warn if a ternary expression which contains a comma operator is used
 without enclosing parenthesis, since this is most likely not what you
-actually want. We recommend the \fI-fcorrect-ternary\fR option.
-.TP
-.B -Wunknown-pragmas
-Warn when encountering an unrecognized \fI#pragma\fR line.
-.TP
-.B -Wunreachable-code
+actually want. We recommend the
+.Fl f Ns Cm correct-ternary
+option.
+.It Fl W Ns Cm unknown-pragmas
+Warn when encountering an unrecognized
+.Ql #pragma
+line.
+.It Fl W Ns Cm unreachable-code
 Warn about unreachable code. That is: code after a return statement,
 or code after a call to a function marked as 'noreturn'.
-.TP
-.B -Wdebug
+.It Fl W Ns Cm debug
 Enable some warnings added in order to help debugging in the compiler.
 You won't need this.
-.B -Wunknown-attribute
+.It Fl W Ns Cm unknown-attribute
 Warn on an unknown attribute. The warning will inlclude only the first
 token inside the enclosing attribute-brackets. This may change when
 the actual attribute syntax is better defined.
-.TP
-.B -Wreserved-names
-Warn when using reserved names such as 'nil'.
-.TP
-.B -Wuninitialized-constant
-Warn about global constants (using the 'const' keyword) with no
+.It Fl W Ns Cm reserved-names
+Warn when using reserved names such as
+.Ql nil Ns .
+.It Fl W Ns Cm uninitialized-constant
+Warn about global constants (using the
+.Ql const
+keyword) with no
 assigned value.
-.TP
-.B -Wuninitialized-global
+.It Fl W Ns Cm uninitialized-global
 Warn about global variables with no initializing value. This is off by
 default, and is added mostly to help find null-values which are
 supposed to be replaced by the untyped 'nil' constant.
-.TP
-.B -Wdifferent-qualifiers
+.It Fl W Ns Cm different-qualifiers
 Warn when a variables is redeclared with a different qualifier. For
 example when redeclaring a variable as \'var\' which was previously
 marked \'const\'.
-.TP
-.B -Wdifferent-attributes
-Similar to the above but for attributes like "[[noreturn]]".
-.TP
-.B -Wdeprecated
+.It Fl W Ns Cm different-attributes
+Similar to the above but for attributes like
+.Ql [[noreturn]] Ns .
+.It Fl W Ns Cm deprecated
 Warn when a function is marked with the attribute
 "[[deprecated]]". This flag enables a warning on calls to functions
 marked as such.
-.TP
-.B -Wparenthesis
+.It Fl W Ns Cm parenthesis
 Warn about possible mistakes caused by missing or wrong parenthesis,
 like an assignment in an 'if' condition when there's no additional set
 of parens around the assignment.
-.SH COMPILE FLAGS
-.TP
-.B -fdarkplaces-string-table-bug
+.El
+.Sh COMPILE FLAGS
+.Bl -tag -width Ds
+.It Fl f Ns Cm darkplaces-string-table-bug
 Add some additional characters to the string table in order to
 compensate for a wrong boundcheck in some specific version of the
 darkplaces engine.
-.TP
-.B -fadjust-vector-fields
+.It Fl f Ns Cm adjust-vector-fields
 When assigning to field pointers of type \fI.vector\fR the common
 behaviour in compilers like \fIfteqcc\fR is to only assign the
 x-component of the pointer. This means that you can use the vector as
 such, but you cannot use its y and z components directly. This flag
 fixes this behaviour. Before using it make sure your code does not
 depend on the buggy behaviour.
-.TP
-.B -fftepp
+.It Fl f Ns Cm ftepp
 Enable a partially fteqcc-compatible preprocessor. It supports all the
 features used in the Xonotic codebase. If you need more, write a
 ticket.
-.TP
-.B -fftepp-predefs
+.It Fl f Ns Cm ftepp-predefs
 Enable some predefined macros. This only works in combination with
 \'-fftepp' and is currently not included by '-std=fteqcc'. The
 following macros will be added:
-.in +4
-.nf
+.Bd -literal -offset indent
 __LINE__
 __FILE__
 __COUNTER__
@@ -358,97 +347,88 @@ __RANDOM__
 __RANDOM_LAST__
 __DATE__
 __TIME__
-.fi
-.in
-Note that fteqcc also defines __NULL__ which is not implemented yet.
-(See -funtyped-nil about gmqcc's alternative to __NULL__).
-.TP
-.B -frelaxed-switch
+.Ed
+.Pp
+Note that fteqcc also defines
+.Li __NULL__
+which is not implemented yet.
+(See
+.Fl f Ns Cm untyped-nil
+about gmqcc's alternative to
+.Li __NULL__ Ns ).
+.It Fl f Ns Cm relaxed-switch
 Allow switch cases to use non constant variables.
-.TP
-.B -fshort-logic
+.It Fl f Ns Cm short-logic
 Perform early out in logical AND and OR expressions. The final result
 will be either a 0 or a 1, see the next flag for more possibilities.
-.TP
-.B -fperl-logic
+.It Fl f Ns Cm perl-logic
 In many languages, logical expressions perform early out in a special
 way: If the left operand of an AND yeilds true, or the one of an OR
 yields false, the complete expression evaluates to the right side.
-Thus \fItrue && 5\fI evaluates to 5 rather than 1.
-.TP
-.B -ftranslatable-strings
-Enable the underscore intrinsic: Using \fI_("A string constant")\fR
+Thus
+.Ql true && 5
+evaluates to 5 rather than 1.
+.It Fl f Ns Cm translatable-strings
+Enable the underscore intrinsic: Using
+.Ql _("A string constant")
 will cause the string immediate to get a name with a "dotranslate_"
 prefix. The darkplaces engine recognizes these and translates them in
 a way similar to how gettext works.
-.TP
-.B -finitialized-nonconstants
+.It Fl f Ns Cm initialized-nonconstants
 Don't implicitly convert initialized variables to constants. With this
 flag, the \fIconst\fR keyword is required to make a constant.
-.TP
-.B -fassign-function-types
+.It Fl f Ns Cm assign-function-types
 If this flag is not set, (and it is set by default in the qcc and
 fteqcc standards), assigning function pointers of mismatching
 signatures will result in an error rather than a warning.
-.TP
-.B -flno
+.It Fl f Ns Cm lno
 Produce a linenumber file along with the output .dat file.
-.TP
-.B -fcorrect-ternary
+.It Fl f Ns Cm correct-ternary
 Use C's operator precedence for ternary expressions. Unless your code
 depends on fteqcc-compatible behaviour, you'll want to use thi
 soption.
-.TP
-.B -fsingle-vector-defs
+.It Fl f Ns Cm single-vector-defs
 Normally vectors generate 4 defs, once for the vector, and once for
 its components with _x, _y, _z suffixes. This option
 prevents components from being listed.
-.TP
-.B -fcorrect-logic
-Most QC compilers translate if(a_vector) directly as an IF on the
-vector, which means only the x-component is checked. This causes
+.It Fl f Ns Cm correct-logic
+Most QC compilers translate
+.Ql if(a_vector)
+directly as an IF on the
+vector, which means only the x-component is checked. This option causes
 vectors to be cast to actual booleans via a NOT_V and, if necessary, a
 NOT_F chained to it.
-.in +4
-.nf
+.Bd -literal -offset indent
 if (a_vector) // becomes
 if not(!a_vector)
 // likewise
 a = a_vector && a_float // becomes
 a = !!a_vector && a_float
-.fi
-.in
-.TP
-.B -ftrue-empty-strings
+.Ed
+.It Fl f Ns Cm true-empty-strings
 An empty string is considered to be true everywhere. The NOT_S
 instruction usually considers an empty string to be false, this option
 effectively causes the unary not in strings to use NOT_F instead.
-.TP
-.B -ffalse-empty-strings
+.It Fl f Ns Cm false-empty-strings
 An empty string is considered to be false everywhere. This means loops
 and if statements which depend on a string will perform a NOT_S
 instruction on the string before using it.
-.TP
-.B -futf8
+.It Fl f Ns Cm utf8
 Enable utf8 characters. This allows utf-8 encoded character constants,
 and escape sequence codepoints in the valid utf-8 range. Effectively
 enabling escape sequences like '\\{x2211}'.
-.TP
-.B -fbail-on-werror
+.It Fl f Ns Cm bail-on-werror
 When a warning is treated as an error, and this option is set (which
 it is by default), it is like any other error and will cause
 compilation to stop. When disabling this flag by using
 \-fno-bail-on-werror, compilation will continue until the end, but no
 output is generated. Instead the first such error message's context is
 shown.
-.TP
-.B -floop-labels
+.It Fl f Ns Cm loop-labels
 Allow loops to be labeled, and allow 'break' and 'continue' to take an
 optional label to decide which loop to actually jump out of or
 continue.
-.sp
-.in +4
-.nf
+.Bd -literal -offset indent
 for :outer (i = 0; i < n; ++i) {
     while (inner) {
         ...;
@@ -456,10 +436,8 @@ for :outer (i = 0; i < n; ++i) {
             continue outer;
     }
 }
-.fi
-.in
-.TP
-.B -funtyped-nil
+.Ed
+.It Fl f Ns Cm untyped-nil
 Adds a global named 'nil' which is of no type and can be assigned to
 anything. No typechecking will be performed on assignments. Assigning
 to it is forbidden, using it in any other kind of expression is also
@@ -477,47 +455,42 @@ components.
 In that gmqcc the nil global is an actual global filled with zeroes,
 and can be assigned to anything including fields, vectors or function
 pointers, and they end up becoming zeroed.
-.TP
-.B -fpermissive
+.It Fl f Ns Cm permissive
 Various effects, usually to weaken some conditions.
-.RS
-.IP "with -funtyped-nil"
-Allow local variables named 'nil'. (This will not allow declaring a
-global of that name.)
-.RE
-.TP
-.B -fvariadic-args
+.Bl -tag -width indent -offset indent
+.It with Fl f Ns Cm untyped-nil
+Allow local variables named
+.Ql nil Ns .
+(This will not allow declaring a global of that name.)
+.El
+.It Fl f Ns Cm variadic-args
 Allow variadic parameters to be accessed by QC code. This can be
 achieved via the '...' function, which takes a parameter index and a
 typename.
-
+.Pp
 Example:
-.sp
-.in +4
-.nf
+.Bd -literal -offset indent
 void vafunc(string...count) {
     float i;
     for (i = 0; i < count; ++i)
         print(...(i, string), "\\n");
 }
-.fi
-.in
-.TP -flegacy-vector-maths
+.Ed
+.It Fl f Ns Cm legacy-vector-maths
 Most Quake VMs, including the one from FTEQW or up till recently
 Darkplaces, do not cope well with vector instructions with overlapping
 input and output. This option will avoid producing such code.
-.SH OPTIMIZATIONS
-.TP
-.B -Opeephole
+.El
+.Sh OPTIMIZATIONS
+.Bl -tag -width Ds
+.It Fl O Ns Cm peephole
 Some general peephole optimizations. For instance the code `a = b + c`
 typically generates 2 instructions, an ADD and a STORE. This
 optimization removes the STORE and lets the ADD write directly into A.
-.TP
-.B -Otail-recursion
+.It Fl O Ns Cm tail-recursion
 Tail recursive function calls will be turned into loops to avoid the
 overhead of the CALL and RETURN instructions.
-.TP
-.B -Ooverlap-locals
+.It Fl O Ns Cm overlap-locals
 Make all functions which use neither local arrays nor have locals
 which are seen as possibly uninitialized use the same local section.
 This should be pretty safe compared to other compilers which do not
@@ -528,44 +501,37 @@ as long as the functions cannot be called in a recursive manner. Since
 it's hard to know whether or not an array is actually fully
 initialized, especially when initializing it via a loop, we assume
 functions with arrays to be too dangerous for this optimization.
-.TP
-.B -Olocal-temps
+.It Fl O Ns Cm local-temps
 This promotes locally declared variables to "temps". Meaning when a
 temporary result of an operation has to be stored somewhere, a local
 variable which is not 'alive' at that point can be used to keep the
 result. This can reduce the size of the global section.
 This will not have declared variables overlap, even if it was
 possible.
-.TP
-.B -Oglobal-temps
+.It Fl O Ns Cm global-temps
 Causes temporary values which do not need to be backed up on a CALL to
 not be stored in the function's locals-area. With this, a CALL to a
 function may need to back up fewer values and thus execute faster.
-.TP
-.B -Ostrip-constant-names
+.It Fl O Ns Cm strip-constant-names
 Don't generate defs for immediate values or even declared constants.
 Meaning variables which are implicitly constant or qualified as such
 using the 'const' keyword.
-.TP
-.B -Ooverlap-strings
+.It Fl O Ns Cm overlap-strings
 Aggressively reuse strings in the string section. When a string should
 be added which is the trailing substring of an already existing
 string, the existing string's tail will be returned instead of the new
 string being added.
-
+.Pp
 For example the following code will only generate 1 string:
-
-.in +4
-.nf
+.Bd -literal -offset indent
 print("Hell you!\\n");
 print("you!\\n"); // trailing substring of "Hello you!\\n"
-.fi
-.in
+.Ed
+.Pp
 There's however one limitation. Strings are still processed in order,
 so if the above print statements were reversed, this optimization
 would not happen.
-.TP
-.B -Ocall-stores
+.It Fl O Ns Cm call-stores
 By default, all parameters of a CALL are copied into the
 parameter-globals right before the CALL instructions. This is the
 easiest and safest way to translate calls, but also adds a lot of
@@ -573,39 +539,48 @@ unnecessary copying and unnecessary temporary values. This
 optimization makes operations which are used as a parameter evaluate
 directly into the parameter-global if that is possible, which is when
 there's no other CALL instruction in between.
-.TP
-.B -Ovoid-return
+.It Fl O Ns Cm void-return
 Usually an empty RETURN instruction is added to the end of a void
 typed function. However, additionally after every function a DONE
 instruction is added for several reasons. (For example the qcvm's
 disassemble switch uses it to know when the function ends.). This
 optimization replaces that last RETURN with DONE rather than adding
 the DONE additionally.
-.TP
-.B -Ovector-components
+.It Fl O Ns Cm vector-components
 Because traditional QC code doesn't allow you to access individual
 vector components of a computed vector without storing it in a local
-first, sometimes people multiply it by a constant like '0 1 0' to get,
+first, sometimes people multiply it by a constant like
+.Ql '0 1 0'
+to get,
 in this case, the y component of a vector. This optimization will turn
 such a multiplication into a direct component access. If the factor is
 anything other than 1, a float-multiplication will be added, which is
 still faster than a vector multiplication.
-.SH CONFIG
+.El
+.Sh CONFIG
 The configuration file is similar to regular .ini files. Comments
 start with hashtags or semicolons, sections are written in square
 brackets and in each section there can be arbitrary many key-value
 pairs.
-.sp
+.Pp
 There are 3 sections currently:
-.IR flags ", " warnings ", and " optimizations .
-They contain a list of boolean values of the form `VARNAME = true` or
-`VARNAME = false`. The variable names are the same as for the
-corresponding -W, -f or -O flag written with only capital letters and
+.Ql flags Ns ,
+.Ql warnings Ns ,
+.Ql optimizations Ns .
+They contain a list of boolean values of the form
+.Ql VARNAME = true
+or
+.Ql VARNAME = false Ns .
+The variable names are the same as for the
+corresponding
+.Fl W , Fl f
+or
+.Fl O
+flag written with only capital letters and
 dashes replaced by underscores.
-.sp
+.Pp
 Here's an example:
-.in +4
-.nf
+.Bd -literal -offset indent
 # a GMQCC configuration file
 [flags]
     FTEPP = true
@@ -619,20 +594,19 @@ Here's an example:
 [optimizations]
     PEEPHOLE = true
     TAIL_RECURSION = true
-.fi
-.in
-.SH BUGS
+.Ed
+.Sh FILES
+.Bl -tag -width Ds
+.It gmqcc.ini.example
+A documented example for a gmqcc.ini file.
+.El
+.Sh SEE ALSO
+.Xr qcvm 1
+.Sh AUTHOR
+See <http://graphitemaster.github.com/gmqcc>.
+.Sh BUGS
 Currently the '-fftepp-predefs' flag is not included by '-std=fteqcc',
 partially because it is not entirely conformant to fteqcc.
-.sp
-
+.Pp
 Please report bugs on <http://github.com/graphitemaster/gmqcc/issues>,
 or see <http://graphitemaster.github.com/gmqcc> on how to contact us.
-.SH FILES
-.TP 20
-.B gmqcc.ini.example
-A documented example for a gmqcc.ini file.
-.SH SEE ALSO
-.IR qcvm (1)
-.SH AUTHOR
-See <http://graphitemaster.github.com/gmqcc>.
index de8633ffedff0e58c1088c1cc4a4c61f0a96cb8b..3a0562f0f4b357f2e753484660cabad5dc9e83d8 100644 (file)
-.\" Process with groff -man -Tascii file.3
-.TH QCVM 1 2012-18-12 "" "gmqcc Manual"
-.SH NAME
-qcvm \- A standalone QuakeC VM binary executor.
-.SH SYNOPSIS
-.B qcvm
-[\fIOPTIONS\fR] [\fIPARAMS\fR] [\fIfile\fR]
-.SH DESCRIPTION
-qcvm is an executor for QuakeC VM binary files created using a QC
+.\" qcvm mdoc manpage
+.Dd January 31, 2013
+.Dt QCVM 1 PRM
+.Os
+.Sh NAME
+.Nm qcvm
+.Nd A standalone QuakeC VM binary executor
+.Sh SYNOPSIS
+.Nm qcvm
+.Op Cm options
+.Op Cm parameters
+.Ar program-file
+.Sh DESCRIPTION
+.Nm qcvm
+is an executor for QuakeC VM binary files created using a QC
 compiler such as gmqcc(1) or fteqcc. It provides a small set of
-builtin functions, and by default executes the \fImain\fR function if
-there is one. Some options useful for debugging are available as well.
-.SH OPTIONS
+builtin functions, and by default executes the
+.Fn main
+function if there is one. Some options useful for debugging are
+available as well.
+.Sh OPTIONS
 There are 2 types of options. Options for the executor, and parameter
 options used to add parameters which are passed to the main function
 on execution.
-.TP
-.B "-h, --help"
+.Bl -tag -width Ds
+.It Fl h , Fl -help
 Show a usage message and exit.
-.TP
-.B "-trace"
+.It Fl trace
 Trace the execution. Each instruction will be printed to stdout before
 executing it.
-.TP
-.B "-profile"
+.It Fl profile
 Perform some profiling. This is currently not really implemented, the
 option is available nonetheless.
-.TP
-.B "-info"
+.It Fl info
 Print information from the program's header instead of executing.
-.TP
-.B "-disasm"
+.It Fl disasm
 Disassemble the program by function instead of executing.
-.TP
-.BI "-disasm-func" function
+.It Fl disasm-func Ar function
 Search for and disassemble the given function.
-.TP
-.B "-printdefs"
+.It Fl printdefs
 List all entries from the program's defs-section. Effectively
 listing all the global variables of the program.
 This option disables execution.
-.TP
-.B "-printfields"
+.It Fl printfields
 List all entries from the program's fields-section. Listing all
 entity-fields declared in the program.
 This option disables execution.
-.TP
-.B "-printfuns"
+.It Fl printfuns
 List functions and some information about their parameters.
 This option disables execution. With a verbosity level of 1, builtin
 numbers are printed. With a verbosity of 2, the function's sizes are
 printed as well. This takes a little longer since the size is found by
-searching for a DONE instruction in the code.
-.TP
-.B "-v"
+searching for a
+.Ql DONE
+instruction in the code.
+.It Fl v
 Increase verbosity level, can be used multiple times.
-.TP
-.BI "-vector """ "x y z" """"
-Append a vector parameter to be passed to \fImain\fR.
-.TP
-.BI "-float " number
-Append a float parameter to be passed to \fImain\fR.
-.TP
-.BI "-string """ "text" """"
-Append a string parameter to be passed to \fImain\fR.
-.SH BUILTINS
+.It Fl vector Ar 'x y z'
+Append a vector parameter to be passed to
+.Fn main Ns .
+.It Fl float Ar number
+Append a float parameter to be passed to
+.Fn main Ns .
+.It Fl string Ar 'text'
+Append a string parameter to be passed to
+.Fn main Ns .
+.El
+.Sh BUILTINS
 The following builtin functions are available:
-.fi
-
-.RI "1) " void " print(" string... ") = " "#1" ;
-.in +8
-Print the passed strings to stdout. At most 8 strings are allowed.
-.in
-
-.RI "2) " string " ftos(" float ") = " "#2" ;
-.in +8
-Convert a float to a string.
-.in
-
-.RI "3) " entity " spawn() = " "#3" ;
-.in +8
-Spawn an entity.
-.in
-
-.RI "4) " void " remove(" entity ") = " "#4" ;
-.in +8
-Remove an entity.
-.in
-
-.RI "5) " string " vtos(" vector ") = " "#5" ;
-.in +8
-Convert a vector to a string.
-.in
-
-.RI "6) " void " error(" string... ") = " "#6" ;
-.in +8
-Print at most 8 strings to stdout and then exit with an error.
-.in
-
-.RI "7) " float " vlen(" vector ") = " "#7" ;
-.in +8
-Get the length of a vector.
-.in
-
-.RI "8) " string " etos(" entity ") = " "#8" ;
-.in +8
-Get the entity ID as string.
-.in
-
-.RI "9) " float " stof(" string ") = " "#9" ;
-.in +8
-Convert a string to a float.
-.in
-
-.RI "10) " string " strcat(" string ", " string ") = " "#10" ;
-.in +8
-Concatenate two strings, returning a tempstring.
-.in
-
-.RI "11) " float " strcmp (" string ", " string ") = " "#11" ;
-.fi
-.RI "    " float " strncmp(" string ", " string ", " float ") = " "#11" ;
-.in +8
-Compare two strings. Returns the same as the corresponding C functions.
-.in
-
-.RI "12) " vector " normalize (" vector ") = " "#12" ;
-.in +8
-Normalize a vector so its length is 1.
-.in
-
-.RI "13) " float " sqrt (" float ") = " "#13" ;
-.in +8
-Get a value's square root.
-.in
-.SH BUGS
+.Bl -ohang
+.It Li 1) void print(string...) = #1;
+.D1 Print the passed strings to stdout. At most 8 strings are allowed.
+.It Li 2) string ftos(float) = #2;
+.D1 Convert a float to a string.
+.It Li 3) entity spawn() = #3;
+.D1 Spawn an entity.
+.It Li 4) void remove(entity) = #4;
+.D1 Remove an entity.
+.It Li 5) string vtos(vector) = #5;
+.D1 Convert a vector to a string.
+.It Li 6) void error(string...) = #6;
+.D1 Print at most 8 strings to stdout and then exit with an error.
+.It Li 7) float vlen(vector) = #7;
+.D1 Get the length of a vector.
+.It Li 8) string etos(entity) = #8;
+.D1 Get the entity ID as string.
+.It Li 9) float stof(string) = #9;
+.D1 Convert a string to a float.
+.It Li 10) string strcat(string, string) = #10;
+.D1 Concatenate two strings, returning a tempstring.
+.It Li 11) float strcmp(string, string) = #11;
+.Li 12) float strncmp(string, string, float) = #11;
+.D1 Compare two strings. Returns the same as the corresponding C functions.
+.It Li 12) vector normalize(vector) = #12;
+.D1 Normalize a vector so its length is 1.
+.It Li 13) float sqrt(float) = #13;
+.D1 Get a value's square root.
+.El
+.Sh SEE ALSO
+.Xr gmqcc 1
+.Sh AUTHOR
+See <http://graphitemaster.github.com/gmqcc>.
+.Sh BUGS
 Please report bugs on <http://github.com/graphitemaster/gmqcc/issues>,
 or see <http://graphitemaster.github.com/gmqcc> on how to contact us.
-.SH SEE ALSO
-.IR gmqcc (1)
-.SH AUTHOR
-See <http://graphitemaster.github.com/gmqcc>.
diff --git a/exec.c b/exec.c
index f4c9ecf458f1a5a21d3247ad5f6ffee121d993fc..d5448153072039287445a609555ad11fed39bf84 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -51,7 +51,7 @@ static void qcvmerror(qc_program *prog, const char *fmt, ...)
     putchar('\n');
 }
 
-qc_program* prog_load(const char *filename)
+qc_program* prog_load(const char *filename, bool skipversion)
 {
     qc_program   *prog;
     prog_header   header;
@@ -66,7 +66,7 @@ qc_program* prog_load(const char *filename)
         return NULL;
     }
 
-    if (header.version != 6) {
+    if (!skipversion && header.version != 6) {
         loaderror("header says this is a version %i progs, we need version 6\n", header.version);
         file_close(file);
         return NULL;
@@ -75,7 +75,7 @@ qc_program* prog_load(const char *filename)
     prog = (qc_program*)mem_a(sizeof(qc_program));
     if (!prog) {
         file_close(file);
-        printf("failed to allocate program data\n");
+        fprintf(stderr, "failed to allocate program data\n");
         return NULL;
     }
     memset(prog, 0, sizeof(*prog));
@@ -199,7 +199,7 @@ qcany* prog_getedict(qc_program *prog, qcint e)
 {
     if (e >= (qcint)vec_size(prog->entitypool)) {
         prog->vmerror++;
-        printf("Accessing out of bounds edict %i\n", (int)e);
+        fprintf(stderr, "Accessing out of bounds edict %i\n", (int)e);
         e = 0;
     }
     return (qcany*)(prog->entitydata + (prog->entityfields * e));
@@ -227,17 +227,17 @@ void prog_free_entity(qc_program *prog, qcint e)
 {
     if (!e) {
         prog->vmerror++;
-        printf("Trying to free world entity\n");
+        fprintf(stderr, "Trying to free world entity\n");
         return;
     }
     if (e >= (qcint)vec_size(prog->entitypool)) {
         prog->vmerror++;
-        printf("Trying to free out of bounds entity\n");
+        fprintf(stderr, "Trying to free out of bounds entity\n");
         return;
     }
     if (!prog->entitypool[e]) {
         prog->vmerror++;
-        printf("Double free on entity\n");
+        fprintf(stderr, "Double free on entity\n");
         return;
     }
     prog->entitypool[e] = false;
@@ -631,7 +631,7 @@ qcvm_parameter *main_params = NULL;
 #define CheckArgs(num) do {                                                    \
     if (prog->argc != (num)) {                                                 \
         prog->vmerror++;                                                       \
-        printf("ERROR: invalid number of arguments for %s: %i, expected %i\n", \
+        fprintf(stderr, "ERROR: invalid number of arguments for %s: %i, expected %i\n", \
         __FUNCTION__, prog->argc, (num));                                      \
         return -1;                                                             \
     }                                                                          \
@@ -660,7 +660,7 @@ static int qc_print(qc_program *prog)
 
 static int qc_error(qc_program *prog)
 {
-    printf("*** VM raised an error:\n");
+    fprintf(stderr, "*** VM raised an error:\n");
     qc_print(prog);
     prog->vmerror++;
     return -1;
@@ -808,7 +808,7 @@ static int qc_strcmp(qc_program *prog)
     qcany out;
 
     if (prog->argc != 2 && prog->argc != 3) {
-        printf("ERROR: invalid number of arguments for strcmp/strncmp: %i, expected 2 or 3\n",
+        fprintf(stderr, "ERROR: invalid number of arguments for strcmp/strncmp: %i, expected 2 or 3\n",
                prog->argc);
         return -1;
     }
@@ -907,7 +907,7 @@ static void prog_main_setparams(qc_program *prog)
                 arg->string = prog_tempstring(prog, main_params[i].value);
                 break;
             default:
-                printf("error: unhandled parameter type: %i\n", main_params[i].vtype);
+                fprintf(stderr, "error: unhandled parameter type: %i\n", main_params[i].vtype);
                 break;
         }
     }
@@ -1052,7 +1052,7 @@ int main(int argc, char **argv)
         }
         else if (argv[1][0] != '-') {
             if (progsfile) {
-                printf("only 1 program file may be specified\n");
+                fprintf(stderr, "only 1 program file may be specified\n");
                 usage();
                 exit(1);
             }
@@ -1062,7 +1062,7 @@ int main(int argc, char **argv)
         }
         else
         {
-            printf("unknown parameter: %s\n", argv[1]);
+            fprintf(stderr, "unknown parameter: %s\n", argv[1]);
             usage();
             exit(1);
         }
@@ -1075,14 +1075,14 @@ int main(int argc, char **argv)
     }
 
     if (!progsfile) {
-        printf("must specify a program to execute\n");
+        fprintf(stderr, "must specify a program to execute\n");
         usage();
         exit(1);
     }
 
-    prog = prog_load(progsfile);
+    prog = prog_load(progsfile, noexec);
     if (!prog) {
-        printf("failed to load program '%s'\n", progsfile);
+        fprintf(stderr, "failed to load program '%s'\n", progsfile);
         exit(1);
     }
 
@@ -1128,11 +1128,33 @@ int main(int argc, char **argv)
     }
     if (opts_printdefs) {
         for (i = 0; i < vec_size(prog->defs); ++i) {
-            printf("Global: %8s %-16s at %u%s\n",
+            printf("Global: %8s %-16s at %u%s",
                    type_name[prog->defs[i].type & DEF_TYPEMASK],
                    prog_getstring(prog, prog->defs[i].name),
                    (unsigned int)prog->defs[i].offset,
                    ((prog->defs[i].type & DEF_SAVEGLOBAL) ? " [SAVE]" : ""));
+            if (opts_v) {
+                switch (prog->defs[i].type & DEF_TYPEMASK) {
+                    case TYPE_FLOAT:
+                        printf(" [init: %g]", ((qcany*)(prog->globals + prog->defs[i].offset))->_float);
+                        break;
+                    case TYPE_INTEGER:
+                        printf(" [init: %i]", (int)( ((qcany*)(prog->globals + prog->defs[i].offset))->_int ));
+                        break;
+                    case TYPE_ENTITY:
+                    case TYPE_FUNCTION:
+                    case TYPE_FIELD:
+                    case TYPE_POINTER:
+                        printf(" [init: %u]", (unsigned)( ((qcany*)(prog->globals + prog->defs[i].offset))->_int ));
+                        break;
+                    case TYPE_STRING:
+                        printf(" [init: `%s`]", prog_getstring(prog, ((qcany*)(prog->globals + prog->defs[i].offset))->string ));
+                        break;
+                    default:
+                        break;
+                }
+            }
+            printf("\n");
         }
     }
     if (opts_printfields) {
@@ -1193,7 +1215,7 @@ int main(int argc, char **argv)
             prog_exec(prog, &prog->functions[fnmain], xflags, VM_JUMPS_DEFAULT);
         }
         else
-            printf("No main function found\n");
+            fprintf(stderr, "No main function found\n");
     }
 
     prog_delete(prog);
diff --git a/ftepp.c b/ftepp.c
index e3e91e7ccdc72d887b409135cdca49d283dff64e..88705512ac44c0985966afbc4a97c6f5a612a291 100644 (file)
--- a/ftepp.c
+++ b/ftepp.c
@@ -82,7 +82,7 @@ static uint32_t ftepp_predef_randval  = 0;
 char *ftepp_predef_date(lex_file *context) {
     struct tm *itime;
     time_t     rtime;
-    char      *value = mem_a(82);
+    char      *value = (char*)mem_a(82);
     /* 82 is enough for strftime but we also have " " in our string */
 
     (void)context;
@@ -100,7 +100,7 @@ char *ftepp_predef_date(lex_file *context) {
 char *ftepp_predef_time(lex_file *context) {
     struct tm *itime;
     time_t     rtime;
-    char      *value = mem_a(82);
+    char      *value = (char*)mem_a(82);
     /* 82 is enough for strftime but we also have " " in our string */
 
     (void)context;
@@ -408,11 +408,55 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
 {
     pptoken *ptok;
     while (ftepp->token != TOKEN_EOL && ftepp->token < TOKEN_EOF) {
-        if (macro->variadic && !strcmp(ftepp_tokval(ftepp), "__VA_ARGS__"))
-            ftepp->token = TOKEN_VA_ARGS;
-        ptok = pptoken_make(ftepp);
-        vec_push(macro->output, ptok);
-        ftepp_next(ftepp);
+        bool   subscript = false;
+        size_t index     = 0;
+        if (macro->variadic && !strcmp(ftepp_tokval(ftepp), "__VA_ARGS__")) {
+            subscript = !!(ftepp_next(ftepp) == '#');
+
+            if (subscript && ftepp_next(ftepp) != '#') {
+                ftepp_error(ftepp, "expected `##` in __VA_ARGS__ for subscripting");
+                return false;
+            } else if (subscript) {
+                if (ftepp_next(ftepp) == '[') {
+                    if (ftepp_next(ftepp) != TOKEN_INTCONST) {
+                        ftepp_error(ftepp, "expected index for __VA_ARGS__ subscript");
+                        return false;
+                    }
+
+                    index = atoi(ftepp_tokval(ftepp));
+
+                    if (ftepp_next(ftepp) != ']') {
+                        ftepp_error(ftepp, "expected `]` in __VA_ARGS__ subscript");
+                        return false;
+                    }
+
+                    /*
+                     * mark it as an array to be handled later as such and not
+                     * as traditional __VA_ARGS__
+                     */
+                    ftepp->token = TOKEN_VA_ARGS_ARRAY;
+                    ptok = pptoken_make(ftepp);
+                    ptok->constval.i = index;
+                    vec_push(macro->output, ptok);
+                    ftepp_next(ftepp);
+                } else {
+                    ftepp_error(ftepp, "expected `[` for subscripting of __VA_ARGS__");
+                    return false;
+                }
+            } else {
+                int old = ftepp->token;
+                ftepp->token = TOKEN_VA_ARGS;
+                ptok = pptoken_make(ftepp);
+                vec_push(macro->output, ptok);
+                ftepp->token = old;
+            }
+        }
+        else
+        {
+            ptok = pptoken_make(ftepp);
+            vec_push(macro->output, ptok);
+            ftepp_next(ftepp);
+        }
     }
     /* recursive expansion can cause EOFs here */
     if (ftepp->token != TOKEN_EOL && ftepp->token != TOKEN_EOF) {
@@ -437,7 +481,7 @@ static bool ftepp_define(ftepp_t *ftepp)
         case TOKEN_KEYWORD:
             macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp));
             if (macro && ftepp->output_on) {
-                if (ftepp_warn(ftepp, WARN_PREPROCESSOR, "redefining `%s`", ftepp_tokval(ftepp)))
+                if (ftepp_warn(ftepp, WARN_CPP, "redefining `%s`", ftepp_tokval(ftepp)))
                     return false;
                 ftepp_macro_delete(ftepp, ftepp_tokval(ftepp));
             }
@@ -673,6 +717,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
                 }
                 if (!varargs)
                     break;
+
                 pi = 0;
                 ftepp_param_out(ftepp, &params[pi + vararg_start]);
                 for (++pi; pi < varargs; ++pi) {
@@ -680,6 +725,17 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
                     ftepp_param_out(ftepp, &params[pi + vararg_start]);
                 }
                 break;
+
+            case TOKEN_VA_ARGS_ARRAY:
+                if ((size_t)out->constval.i >= varargs) {
+                    ftepp_error(ftepp, "subscript of `[%u]` is out of bounds for `__VA_ARGS__`", out->constval.i);
+                    vec_free(old_string);
+                    return false;
+                }
+
+                ftepp_param_out(ftepp, &params[out->constval.i + vararg_start]);
+                break;
+
             case TOKEN_IDENT:
             case TOKEN_TYPENAME:
             case TOKEN_KEYWORD:
@@ -955,7 +1011,7 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
 
         default:
             ftepp_error(ftepp, "junk in #if: `%s` ...", ftepp_tokval(ftepp));
-            if (opts.debug)
+            if (OPTS_OPTION_BOOL(OPTION_DEBUG))
                 ftepp_error(ftepp, "internal: token %i\n", ftepp->token);
             return false;
     }
@@ -1262,6 +1318,30 @@ static void ftepp_directive_error(ftepp_t *ftepp) {
     ftepp_error(ftepp, "#error %s", ftepp_tokval(ftepp));
 }
 
+static void ftepp_directive_message(ftepp_t *ftepp) {
+    char *message = NULL;
+
+    if (!ftepp_skipspace(ftepp))
+        return;
+
+    /* handle the odd non string constant case so it works like C */
+    if (ftepp->token != TOKEN_STRINGCONST) {
+        vec_upload(message, "#message", 8);
+        ftepp_next(ftepp);
+        while (ftepp->token != TOKEN_EOL) {
+            vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp)));
+            ftepp_next(ftepp);
+        }
+        vec_push(message, '\0');
+        con_cprintmsg(&ftepp->lex->tok.ctx, LVL_MSG, "message", message);
+        vec_free(message);
+        return;
+    }
+
+    unescape     (ftepp_tokval(ftepp), ftepp_tokval(ftepp));
+    con_cprintmsg(&ftepp->lex->tok.ctx, LVL_MSG, "message",  ftepp_tokval(ftepp));
+}
+
 /**
  * Include a file.
  * FIXME: do we need/want a -I option?
@@ -1465,6 +1545,10 @@ static bool ftepp_hash(ftepp_t *ftepp)
                 ftepp_directive_error(ftepp);
                 break;
             }
+            else if (!strcmp(ftepp_tokval(ftepp), "message")) {
+                ftepp_directive_message(ftepp);
+                break;
+            }
             else {
                 if (ftepp->output_on) {
                     ftepp_error(ftepp, "unrecognized preprocessor directive: `%s`", ftepp_tokval(ftepp));
@@ -1671,7 +1755,7 @@ bool ftepp_init()
 
     /* set the right macro based on the selected standard */
     ftepp_add_define(NULL, "GMQCC");
-    if (opts.standard == COMPILER_FTEQCC) {
+    if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC) {
         ftepp_add_define(NULL, "__STD_FTEQCC__");
         /* 1.00 */
         major[0] = '"';
@@ -1681,15 +1765,15 @@ bool ftepp_init()
         minor[0] = '"';
         minor[1] = '0';
         minor[2] = '"';
-    } else if (opts.standard == COMPILER_GMQCC) {
+    } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
         ftepp_add_define(NULL, "__STD_GMQCC__");
         sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR);
         sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR);
-    } else if (opts.standard == COMPILER_QCCX) {
+    } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCCX) {
         ftepp_add_define(NULL, "__STD_QCCX__");
         sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR);
         sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR);
-    } else if (opts.standard == COMPILER_QCC) {
+    } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
         ftepp_add_define(NULL, "__STD_QCC__");
         /* 1.0 */
         major[0] = '"';
diff --git a/gmqcc.h b/gmqcc.h
index a6053a6d1cd60e5a21efb74534ed58183ddc1a6e..51c2dccbdc1dc41a8e7d5b4916292d79f7dc14f5 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -102,8 +102,10 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
  */
 #if defined(__GNUC__) || defined(__CLANG__)
 #   define GMQCC_WARN __attribute__((warn_unused_result))
+#   define GMQCC_USED __attribute__((used))
 #else
 #   define GMQCC_WARN
+#   define GMQCC_USED
 #endif
 /*
  * This is a hack to silent clang regarding empty
@@ -451,7 +453,8 @@ GMQCC_INLINE FILE   *file_open   (const char *, const char *);
 /*=========================== correct.c =============================*/
 /*===================================================================*/
 typedef struct {
-    char ***edits;
+    char   ***edits;
+    size_t  **lens;
 } correction_t;
 
 void  correct_del (correct_trie_t*, size_t **);
@@ -681,17 +684,11 @@ enum {
     INSTR_BITAND,
     INSTR_BITOR,
 
-    /*
-     * Virtual instructions used by the assembler
-     * keep at the end but before virtual instructions
-     * for the IR below.
-     */
-    AINSTR_END,
-
     /*
      * Virtual instructions used by the IR
      * Keep at the end!
      */
+    VINSTR_END,
     VINSTR_PHI,
     VINSTR_JUMP,
     VINSTR_COND,
@@ -975,7 +972,7 @@ typedef struct qc_program_s {
     int    argc; /* current arg count for debugging */
 } qc_program;
 
-qc_program* prog_load(const char *filename);
+qc_program* prog_load(const char *filename, bool ignoreversion);
 void        prog_delete(qc_program *prog);
 
 bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps);
@@ -1061,6 +1058,7 @@ int     u8_fromchar(uchar_t w,   char *to,     size_t maxlen);
 typedef struct {
     const char *name;
     longbit     bit;
+    const char *description;
 } opts_flag_def;
 
 bool opts_setflag  (const char *, bool);
@@ -1081,48 +1079,64 @@ void opts_restore_non_Werror_all();
 
 enum {
 # define GMQCC_TYPE_FLAGS
-# define GMQCC_DEFINE_FLAG(X) X,
+# define GMQCC_DEFINE_FLAG(X, Y) X,
 #  include "opts.def"
     COUNT_FLAGS
 };
 static const opts_flag_def opts_flag_list[] = {
 # define GMQCC_TYPE_FLAGS
-# define GMQCC_DEFINE_FLAG(X) { #X, LONGBIT(X) },
+# define GMQCC_DEFINE_FLAG(X, Y) { #X, LONGBIT(X), Y},
 #  include "opts.def"
-    { NULL, LONGBIT(0) }
+    { NULL, LONGBIT(0), "" }
 };
 
 enum {
 # define GMQCC_TYPE_WARNS
-# define GMQCC_DEFINE_FLAG(X) WARN_##X,
+# define GMQCC_DEFINE_FLAG(X, Y) WARN_##X,
 #  include "opts.def"
     COUNT_WARNINGS
 };
 static const opts_flag_def opts_warn_list[] = {
 # define GMQCC_TYPE_WARNS
-# define GMQCC_DEFINE_FLAG(X) { #X, LONGBIT(WARN_##X) },
+# define GMQCC_DEFINE_FLAG(X, Y) { #X, LONGBIT(WARN_##X), Y },
 #  include "opts.def"
-    { NULL, LONGBIT(0) }
+    { NULL, LONGBIT(0), "" }
 };
 
 enum {
 # define GMQCC_TYPE_OPTIMIZATIONS
-# define GMQCC_DEFINE_FLAG(NAME, MIN_O) OPTIM_##NAME,
+# define GMQCC_DEFINE_FLAG(NAME, MIN_O, Y) OPTIM_##NAME,
 #  include "opts.def"
     COUNT_OPTIMIZATIONS
 };
 static const opts_flag_def opts_opt_list[] = {
 # define GMQCC_TYPE_OPTIMIZATIONS
-# define GMQCC_DEFINE_FLAG(NAME, MIN_O) { #NAME, LONGBIT(OPTIM_##NAME) },
+# define GMQCC_DEFINE_FLAG(NAME, MIN_O, Y) { #NAME, LONGBIT(OPTIM_##NAME), Y},
 #  include "opts.def"
-    { NULL, LONGBIT(0) }
+    { NULL, LONGBIT(0), "" }
 };
 static const unsigned int opts_opt_oflag[] = {
 # define GMQCC_TYPE_OPTIMIZATIONS
-# define GMQCC_DEFINE_FLAG(NAME, MIN_O) MIN_O,
+# define GMQCC_DEFINE_FLAG(NAME, MIN_O, Y) MIN_O,
 #  include "opts.def"
     0
 };
+
+enum {
+#   define GMQCC_TYPE_OPTIONS
+#   define GMQCC_DEFINE_FLAG(X, Y) OPTION_##X,
+#   include "opts.def"
+    OPTION_COUNT
+};
+
+
+GMQCC_USED static const char *opts_options_descriptions[] = {
+#   define GMQCC_TYPE_OPTIONS
+#   define GMQCC_DEFINE_FLAG(X, Y) Y,
+#   include "opts.def"
+    ""
+};
+
 extern unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS];
 
 /* other options: */
@@ -1133,30 +1147,22 @@ typedef enum {
     COMPILER_GMQCC    /* this   QuakeC */
 } opts_std_t;
 
-/* TODO: cleanup this */
+typedef union {
+    bool     B;
+    uint16_t U16;
+    uint32_t U32;
+    char    *STR;
+} opt_value_t;
+
+
 typedef struct {
-    uint32_t    O;              /* -Ox           */
-    const char *output;         /* -o file       */
-    bool        quiet;          /* -q --quiet    */
-    bool        g;              /* -g            */
-    opts_std_t  standard;       /* -std=         */
-    bool        debug;          /* -debug        */
-    bool        memchk;         /* -memchk       */
-    bool        dumpfin;        /* -dumpfin      */
-    bool        dump;           /* -dump         */
-    bool        forcecrc;       /* --force-crc=  */
-    uint16_t    forced_crc;     /* --force-crc=  */
-    bool        pp_only;        /* -E            */
-    size_t      max_array_size; /* --max-array=  */
-    bool        add_info;       /* --add-info    */
-    bool        correction;     /* --correct     */
-
-    uint32_t flags        [1 + (COUNT_FLAGS         / 32)];
-    uint32_t warn         [1 + (COUNT_WARNINGS      / 32)];
-    uint32_t werror       [1 + (COUNT_WARNINGS      / 32)];
-    uint32_t warn_backup  [1 + (COUNT_WARNINGS      / 32)];
-    uint32_t werror_backup[1 + (COUNT_WARNINGS      / 32)];
-    uint32_t optimization [1 + (COUNT_OPTIMIZATIONS / 32)];
+    opt_value_t  options      [OPTION_COUNT];
+    uint32_t     flags        [1 + (COUNT_FLAGS         / 32)];
+    uint32_t     warn         [1 + (COUNT_WARNINGS      / 32)];
+    uint32_t     werror       [1 + (COUNT_WARNINGS      / 32)];
+    uint32_t     warn_backup  [1 + (COUNT_WARNINGS      / 32)];
+    uint32_t     werror_backup[1 + (COUNT_WARNINGS      / 32)];
+    uint32_t     optimization [1 + (COUNT_OPTIMIZATIONS / 32)];
 } opts_cmd_t;
 
 extern opts_cmd_t opts;
@@ -1166,5 +1172,9 @@ extern opts_cmd_t opts;
 #define OPTS_WARN(i)         OPTS_GENERIC(opts.warn,         (i))
 #define OPTS_WERROR(i)       OPTS_GENERIC(opts.werror,       (i))
 #define OPTS_OPTIMIZATION(i) OPTS_GENERIC(opts.optimization, (i))
+#define OPTS_OPTION_BOOL(X) (opts.options[X].B)
+#define OPTS_OPTION_U16(X)  (opts.options[X].U16)
+#define OPTS_OPTION_U32(X)  (opts.options[X].U32)
+#define OPTS_OPTION_STR(X)  (opts.options[X].STR)
 
 #endif
diff --git a/ir.c b/ir.c
index 897c60269835f7969ded3cfabb979c07b23ca078..5d8085a18947e6fddbf3998b565afe71394c5eaa 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -83,11 +83,11 @@ uint16_t type_store_instr[TYPE_COUNT] = {
 
     INSTR_STORE_V, /* variant, should never be accessed */
 
-    AINSTR_END, /* struct */
-    AINSTR_END, /* union  */
-    AINSTR_END, /* array  */
-    AINSTR_END, /* nil    */
-    AINSTR_END, /* noexpr */
+    VINSTR_END, /* struct */
+    VINSTR_END, /* union  */
+    VINSTR_END, /* array  */
+    VINSTR_END, /* nil    */
+    VINSTR_END, /* noexpr */
 };
 
 uint16_t field_store_instr[TYPE_COUNT] = {
@@ -107,11 +107,11 @@ uint16_t field_store_instr[TYPE_COUNT] = {
 
     INSTR_STORE_V, /* variant, should never be accessed */
 
-    AINSTR_END, /* struct */
-    AINSTR_END, /* union  */
-    AINSTR_END, /* array  */
-    AINSTR_END, /* nil    */
-    AINSTR_END, /* noexpr */
+    VINSTR_END, /* struct */
+    VINSTR_END, /* union  */
+    VINSTR_END, /* array  */
+    VINSTR_END, /* nil    */
+    VINSTR_END, /* noexpr */
 };
 
 uint16_t type_storep_instr[TYPE_COUNT] = {
@@ -131,11 +131,11 @@ uint16_t type_storep_instr[TYPE_COUNT] = {
 
     INSTR_STOREP_V, /* variant, should never be accessed */
 
-    AINSTR_END, /* struct */
-    AINSTR_END, /* union  */
-    AINSTR_END, /* array  */
-    AINSTR_END, /* nil    */
-    AINSTR_END, /* noexpr */
+    VINSTR_END, /* struct */
+    VINSTR_END, /* union  */
+    VINSTR_END, /* array  */
+    VINSTR_END, /* nil    */
+    VINSTR_END, /* noexpr */
 };
 
 uint16_t type_eq_instr[TYPE_COUNT] = {
@@ -155,11 +155,11 @@ uint16_t type_eq_instr[TYPE_COUNT] = {
 
     INSTR_EQ_V, /* variant, should never be accessed */
 
-    AINSTR_END, /* struct */
-    AINSTR_END, /* union  */
-    AINSTR_END, /* array  */
-    AINSTR_END, /* nil    */
-    AINSTR_END, /* noexpr */
+    VINSTR_END, /* struct */
+    VINSTR_END, /* union  */
+    VINSTR_END, /* array  */
+    VINSTR_END, /* nil    */
+    VINSTR_END, /* noexpr */
 };
 
 uint16_t type_ne_instr[TYPE_COUNT] = {
@@ -179,11 +179,11 @@ uint16_t type_ne_instr[TYPE_COUNT] = {
 
     INSTR_NE_V, /* variant, should never be accessed */
 
-    AINSTR_END, /* struct */
-    AINSTR_END, /* union  */
-    AINSTR_END, /* array  */
-    AINSTR_END, /* nil    */
-    AINSTR_END, /* noexpr */
+    VINSTR_END, /* struct */
+    VINSTR_END, /* union  */
+    VINSTR_END, /* array  */
+    VINSTR_END, /* nil    */
+    VINSTR_END, /* noexpr */
 };
 
 uint16_t type_not_instr[TYPE_COUNT] = {
@@ -203,11 +203,11 @@ uint16_t type_not_instr[TYPE_COUNT] = {
 
     INSTR_NOT_V, /* variant, should never be accessed */
 
-    AINSTR_END, /* struct */
-    AINSTR_END, /* union  */
-    AINSTR_END, /* array  */
-    AINSTR_END, /* nil    */
-    AINSTR_END, /* noexpr */
+    VINSTR_END, /* struct */
+    VINSTR_END, /* union  */
+    VINSTR_END, /* array  */
+    VINSTR_END, /* nil    */
+    VINSTR_END, /* noexpr */
 };
 
 /* protos */
@@ -2257,18 +2257,22 @@ bool ir_function_allocate_locals(ir_function *self)
                     irerror(call->context, "internal error: unlocked parameter %s not found", v->name);
                     goto error;
                 }
-
                 ++opts_optimizationcount[OPTIM_CALL_STORES];
                 v->callparam = true;
                 if (param < 8)
                     ir_value_code_setaddr(v, OFS_PARM0 + 3*param);
                 else {
+                    size_t nprotos = vec_size(self->owner->extparam_protos);
                     ir_value *ep;
                     param -= 8;
-                    if (vec_size(self->owner->extparam_protos) <= param)
-                        ep = ir_gen_extparam_proto(self->owner);
-                    else
+                    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;
                 }
@@ -3113,7 +3117,7 @@ static ir_value* ir_gen_extparam_proto(ir_builder *ir)
     ir_value *global;
     char      name[128];
 
-    snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos)+8));
+    snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos)));
     global = ir_value_var(name, store_global, TYPE_VECTOR);
 
     vec_push(ir->extparam_protos, global);
@@ -3224,9 +3228,12 @@ static bool gen_function_locals(ir_builder *ir, ir_value *global)
     irfun = global->constval.vfunc;
     def   = code_functions + irfun->code_function_def;
 
-    if (opts.g || !OPTS_OPTIMIZATION(OPTIM_OVERLAP_LOCALS) || (irfun->flags & IR_FLAG_MASK_NO_OVERLAP))
+    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);
-    else {
+    else {
         firstlocal = def->firstlocal = ir->first_common_local;
         ++opts_optimizationcount[OPTIM_OVERLAP_LOCALS];
     }
@@ -3372,7 +3379,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
     def.type   = global->vtype;
     def.offset = vec_size(code_globals);
     def.name   = 0;
-    if (opts.g || !islocal)
+    if (OPTS_OPTION_BOOL(OPTION_G) || !islocal)
     {
         pushdef = true;
 
@@ -3548,7 +3555,7 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
     def.offset = (uint16_t)vec_size(code_globals);
 
     /* create a global named the same as the field */
-    if (opts.standard == COMPILER_GMQCC) {
+    if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
         /* in our standard, the global gets a dot prefix */
         size_t len = strlen(field->name);
         char name[1024];
@@ -3686,7 +3693,7 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
         code_push_statement(&stmt, vec_last(code_linenums));
     }
 
-    if (opts.pp_only)
+    if (OPTS_OPTION_BOOL(OPTION_PP_ONLY))
         return true;
 
     if (vec_size(code_statements) != vec_size(code_linenums)) {
@@ -3707,7 +3714,7 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
         memcpy(vec_add(lnofile, 5), ".lno", 5);
     }
 
-    if (!opts.quiet) {
+    if (!OPTS_OPTION_BOOL(OPTION_QUIET)) {
         if (lnofile)
             con_out("writing '%s' and '%s'...\n", filename, lnofile);
         else
diff --git a/lexer.c b/lexer.c
index 3781496927cdbc5b31209f92389130148ca0c72e..42b21a1a6cd7de46bd45aa21b227cc412a4fbdec 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -1288,10 +1288,11 @@ int lex_do(lex_file *lex)
     }
 
     if (ch == '+' || ch == '-' || /* ++, --, +=, -=  and -> as well! */
-        ch == '>' || ch == '<' || /* <<, >>, <=, >= */
-        ch == '=' || ch == '!' || /* ==, != */
-        ch == '&' || ch == '|')   /* &&, ||, &=, |= */
-    {
+        ch == '>' || ch == '<' || /* <<, >>, <=, >=                  */
+        ch == '=' || ch == '!' || /* ==, !=                          */
+        ch == '&' || ch == '|' || /* &&, ||, &=, |=                  */
+        ch == '~'                 /* ~=, ~                           */
+    )  {
         lex_tokench(lex, ch);
 
         nextch = lex_getch(lex);
@@ -1387,7 +1388,7 @@ int lex_do(lex_file *lex)
                 if (!strcmp(v, keywords_qc[kw]))
                     return (lex->tok.ttype = TOKEN_KEYWORD);
             }
-            if (opts.standard != COMPILER_QCC) {
+            if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_QCC) {
                 for (kw = 0; kw < num_keywords_fg; ++kw) {
                     if (!strcmp(v, keywords_fg[kw]))
                         return (lex->tok.ttype = TOKEN_KEYWORD);
@@ -1484,6 +1485,6 @@ int lex_do(lex_file *lex)
         return (lex->tok.ttype = ch);
     }
 
-    lexerror(lex, "unknown token");
+    lexerror(lex, "unknown token: `%s`", lex->tok.value);
     return (lex->tok.ttype = TOKEN_ERROR);
 }
diff --git a/lexer.h b/lexer.h
index 71ff198eed024b66c1932830d26148cd45e0d514..75fb83e9320fc159d432819c408b3abf339270c7 100644 (file)
--- a/lexer.h
+++ b/lexer.h
@@ -75,6 +75,7 @@ enum {
     TOKEN_ATTRIBUTE_CLOSE, /* ]] */
 
     TOKEN_VA_ARGS, /* for the ftepp only */
+    TOKEN_VA_ARGS_ARRAY, /* for the ftepp only */
 
     TOKEN_STRINGCONST, /* not the typename but an actual "string" */
     TOKEN_CHARCONST,
diff --git a/main.c b/main.c
index 2b055d2210f35bf59d556053f366e27c7c12e3d8..6132978f41d9aa9eca20492849b04e38a03f0204 100644 (file)
--- a/main.c
+++ b/main.c
@@ -172,13 +172,16 @@ static bool options_parse(int argc, char **argv) {
                     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.standard = COMPILER_GMQCC;
+
+
+                    OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_GMQCC;
 
                 } else if (!strcmp(argarg, "qcc")) {
 
                     opts_set(opts.flags, ADJUST_VECTOR_FIELDS,  false);
                     opts_set(opts.flags, ASSIGN_FUNCTION_TYPES, true);
-                    opts.standard = COMPILER_QCC;
+
+                    OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_QCC;
 
                 } else if (!strcmp(argarg, "fte") || !strcmp(argarg, "fteqcc")) {
 
@@ -188,12 +191,13 @@ static bool options_parse(int argc, char **argv) {
                     opts_set(opts.flags, ASSIGN_FUNCTION_TYPES,    true);
                     opts_set(opts.flags, CORRECT_TERNARY,          false);
                     opts_set(opts.warn, WARN_TERNARY_PRECEDENCE,   true);
-                    opts.standard = COMPILER_FTEQCC;
+
+                    OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_FTEQCC;
 
                 } else if (!strcmp(argarg, "qccx")) {
 
                     opts_set(opts.flags, ADJUST_VECTOR_FIELDS,  false);
-                    opts.standard = COMPILER_QCCX;
+                    OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_QCCX;
 
                 } else {
                     con_out("Unknown standard: %s\n", argarg);
@@ -202,8 +206,9 @@ static bool options_parse(int argc, char **argv) {
                 continue;
             }
             if (options_long_gcc("force-crc", &argc, &argv, &argarg)) {
-                opts.forcecrc   = true;
-                opts.forced_crc = strtol(argarg, NULL, 0);
+
+                OPTS_OPTION_BOOL(OPTION_FORCECRC)   = true;
+                OPTS_OPTION_U16 (OPTION_FORCED_CRC) = strtol(argarg, NULL, 0);
                 continue;
             }
             if (options_long_gcc("redirout", &argc, &argv, &redirout)) {
@@ -243,19 +248,19 @@ static bool options_parse(int argc, char **argv) {
             }
 
             if (!strcmp(argv[0]+1, "debug")) {
-                opts.debug = true;
+                OPTS_OPTION_BOOL(OPTION_DEBUG) = true;
                 continue;
             }
             if (!strcmp(argv[0]+1, "dump")) {
-                opts.dump = true;
+                OPTS_OPTION_BOOL(OPTION_DUMP)  = true;
                 continue;
             }
             if (!strcmp(argv[0]+1, "dumpfin")) {
-                opts.dumpfin = true;
+                OPTS_OPTION_BOOL(OPTION_DUMPFIN) = true;
                 continue;
             }
             if (!strcmp(argv[0]+1, "memchk")) {
-                opts.memchk = true;
+                OPTS_OPTION_BOOL(OPTION_MEMCHK) = true;
                 continue;
             }
             if (!strcmp(argv[0]+1, "nocolor")) {
@@ -275,18 +280,18 @@ static bool options_parse(int argc, char **argv) {
                     exit(0);
 
                 case 'E':
-                    opts.pp_only = true;
+                    OPTS_OPTION_BOOL(OPTION_PP_ONLY) = true;
                     opts_set(opts.flags, FTEPP_PREDEFS, true); /* predefs on for -E */
                     break;
 
                 /* debug turns on -flno */
                 case 'g':
                     opts_setflag("LNO", true);
-                    opts.g = true;
+                    OPTS_OPTION_BOOL(OPTION_G) = true;
                     break;
 
                 case 'q':
-                    opts.quiet = true;
+                    OPTS_OPTION_BOOL(OPTION_QUIET) = true;
                     break;
 
                 case 'D':
@@ -310,10 +315,10 @@ static bool options_parse(int argc, char **argv) {
                 case 'f':
                     util_strtocmd(argv[0]+2, argv[0]+2, strlen(argv[0]+2)+1);
                     if (!strcmp(argv[0]+2, "HELP") || *(argv[0]+2) == '?') {
-                        con_out("Possible flags:\n");
+                        con_out("Possible flags:\n\n");
                         for (itr = 0; itr < COUNT_FLAGS; ++itr) {
                             util_strtononcmd(opts_flag_list[itr].name, buffer, sizeof(buffer));
-                            con_out(" -f%s\n", buffer);
+                            con_out(" -f%s:\n%s\n\n", buffer, opts_flag_list[itr].description);
                         }
                         exit(0);
                     }
@@ -334,7 +339,7 @@ static bool options_parse(int argc, char **argv) {
                         con_out("Possible warnings:\n");
                         for (itr = 0; itr < COUNT_WARNINGS; ++itr) {
                             util_strtononcmd(opts_warn_list[itr].name, buffer, sizeof(buffer));
-                            con_out(" -W%s\n", buffer);
+                            con_out(" -W%s:\n%s\n\n\n", buffer, opts_warn_list[itr].description);
                         }
                         exit(0);
                     }
@@ -396,20 +401,21 @@ static bool options_parse(int argc, char **argv) {
                         return false;
                     }
                     if (isdigit(argarg[0])) {
-                        opts.O = atoi(argarg);
-                        opts_setoptimlevel(opts.O);
+                        uint32_t val = atoi(argarg);
+                        OPTS_OPTION_U32(OPTION_O) = val;
+                        opts_setoptimlevel(val);
                     } else {
                         util_strtocmd(argarg, argarg, strlen(argarg)+1);
                         if (!strcmp(argarg, "HELP")) {
                             con_out("Possible optimizations:\n");
                             for (itr = 0; itr < COUNT_OPTIMIZATIONS; ++itr) {
                                 util_strtononcmd(opts_opt_list[itr].name, buffer, sizeof(buffer));
-                                con_out(" -O%-20s (-O%u)\n", buffer, opts_opt_oflag[itr]);
+                                con_out(" -O%-20s (-O%u):\n%s\n\n", buffer, opts_opt_oflag[itr], opts_opt_list[itr].description);
                             }
                             exit(0);
                         }
                         else if (!strcmp(argarg, "ALL"))
-                            opts_setoptimlevel(opts.O = 9999);
+                            opts_setoptimlevel(OPTS_OPTION_U32(OPTION_O) = 9999);
                         else if (!strncmp(argarg, "NO_", 3)) {
                             if (!opts_setoptim(argarg+3, false)) {
                                 con_out("unknown optimization: %s\n", argarg+3);
@@ -430,7 +436,7 @@ static bool options_parse(int argc, char **argv) {
                         con_out("option -o requires an argument: the output file name\n");
                         return false;
                     }
-                    opts.output = argarg;
+                    OPTS_OPTION_STR(OPTION_OUTPUT) = argarg;
                     opts_output_wasset = true;
                     break;
 
@@ -454,7 +460,13 @@ static bool options_parse(int argc, char **argv) {
                     }
             /* All long options without arguments */
                     else if (!strcmp(argv[0]+2, "help")) {
-                        usage();
+                        /* TODO .. map name back .. prittery print of
+                         * options and their associations.
+                         */  
+                        for (itr = 0; itr < OPTION_COUNT; itr++) {
+                            con_out("%s\n\n", opts_options_descriptions[itr]);
+                        }
+
                         exit(0);
                     }
                     else if (!strcmp(argv[0]+2, "version")) {
@@ -462,25 +474,25 @@ static bool options_parse(int argc, char **argv) {
                         exit(0);
                     }
                     else if (!strcmp(argv[0]+2, "quiet")) {
-                        opts.quiet = true;
+                        OPTS_OPTION_BOOL(OPTION_QUIET) = true;
                         break;
                     }
                     else if (!strcmp(argv[0]+2, "correct")) {
-                        opts.correction = true;
+                        OPTS_OPTION_BOOL(OPTION_CORRECTION) = true;
                         break;
                     }
                     else if (!strcmp(argv[0]+2, "no-correct")) {
-                        opts.correction = false;
+                        OPTS_OPTION_BOOL(OPTION_CORRECTION) = false;
                         break;
                     }
                     else if (!strcmp(argv[0]+2, "add-info")) {
-                        opts.add_info = true;
+                        OPTS_OPTION_BOOL(OPTION_ADD_INFO) = true;
                         break;
                     }
                     else {
             /* All long options with arguments */
                         if (options_long_witharg("output", &argc, &argv, &argarg)) {
-                            opts.output = argarg;
+                            OPTS_OPTION_STR(OPTION_OUTPUT) = argarg;
                             opts_output_wasset = true;
                         } else {
                             con_out("Unknown parameter: %s\n", argv[0]);
@@ -556,10 +568,10 @@ int main(int argc, char **argv) {
     }
 
     /* the standard decides which set of operators to use */
-    if (opts.standard == COMPILER_GMQCC) {
+    if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
         operators      = c_operators;
         operator_count = c_operator_count;
-    } else if (opts.standard == COMPILER_FTEQCC) {
+    } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC) {
         operators      = fte_operators;
         operator_count = fte_operator_count;
     } else {
@@ -587,22 +599,22 @@ int main(int argc, char **argv) {
         }
     }
 
-    if (opts.dump) {
+    if (OPTS_OPTION_BOOL(OPTION_DUMP)) {
         for (itr = 0; itr < COUNT_FLAGS; ++itr)
             con_out("Flag %s = %i\n",    opts_flag_list[itr].name, OPTS_FLAG(itr));
         for (itr = 0; itr < COUNT_WARNINGS; ++itr)
             con_out("Warning %s = %i\n", opts_warn_list[itr].name, OPTS_WARN(itr));
 
-        con_out("output             = %s\n", opts.output);
-        con_out("optimization level = %d\n", opts.O);
-        con_out("standard           = %i\n", opts.standard);
+        con_out("output             = %s\n", OPTS_OPTION_STR(OPTION_OUTPUT));
+        con_out("optimization level = %u\n", OPTS_OPTION_U32(OPTION_O));
+        con_out("standard           = %u\n", OPTS_OPTION_U32(OPTION_STANDARD));
     }
 
-    if (opts.pp_only) {
+    if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
         if (opts_output_wasset) {
-            outfile = file_open(opts.output, "wb");
+            outfile = file_open(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
             if (!outfile) {
-                con_err("failed to open `%s` for writing\n", opts.output);
+                con_err("failed to open `%s` for writing\n", OPTS_OPTION_STR(OPTION_OUTPUT));
                 retval = 1;
                 goto cleanup;
             }
@@ -612,7 +624,7 @@ int main(int argc, char **argv) {
         }
     }
 
-    if (!opts.pp_only) {
+    if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
         if (!parser_init()) {
             con_err("failed to initialize parser\n");
             retval = 1;
@@ -620,7 +632,7 @@ int main(int argc, char **argv) {
         }
     }
 
-    if (opts.pp_only || OPTS_FLAG(FTEPP)) {
+    if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
         if (!ftepp_init()) {
             con_err("failed to initialize parser\n");
             retval = 1;
@@ -634,7 +646,7 @@ int main(int argc, char **argv) {
     util_debug("COM", "starting ...\n");
 
     /* add macros */
-    if (opts.pp_only || OPTS_FLAG(FTEPP)) {
+    if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
         for (itr = 0; itr < vec_size(ppems); itr++) {
             ftepp_add_macro(ppems[itr].name, ppems[itr].value);
             mem_d(ppems[itr].name);
@@ -667,7 +679,7 @@ int main(int argc, char **argv) {
         }
 
         if (!opts_output_wasset) {
-            opts.output = util_strdup(line);
+            OPTS_OPTION_STR(OPTION_OUTPUT) = util_strdup(line);
             opts_output_free = true;
         }
 
@@ -689,12 +701,16 @@ srcdone:
         goto cleanup;
 
     if (vec_size(items)) {
-        if (!opts.quiet && !opts.pp_only) {
+        if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
+            !OPTS_OPTION_BOOL(OPTION_PP_ONLY))
+        {
             con_out("Mode: %s\n", (progs_src ? "progs.src" : "manual"));
             con_out("There are %lu items to compile:\n", (unsigned long)vec_size(items));
         }
         for (itr = 0; itr < vec_size(items); ++itr) {
-            if (!opts.quiet && !opts.pp_only) {
+            if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
+                !OPTS_OPTION_BOOL(OPTION_PP_ONLY))
+            {
                 con_out("  item: %s (%s)\n",
                        items[itr].filename,
                        ( (items[itr].type == TYPE_QC ? "qc" :
@@ -703,7 +719,7 @@ srcdone:
                          ("unknown"))))));
             }
 
-            if (opts.pp_only) {
+            if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
                 const char *out;
                 if (!ftepp_preprocess_file(items[itr].filename)) {
                     retval = 1;
@@ -745,8 +761,8 @@ srcdone:
         }
 
         ftepp_finish();
-        if (!opts.pp_only) {
-            if (!parser_finish(opts.output)) {
+        if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
+            if (!parser_finish(OPTS_OPTION_STR(OPTION_OUTPUT))) {
                 retval = 1;
                 goto cleanup;
             }
@@ -754,7 +770,9 @@ srcdone:
     }
 
     /* stuff */
-    if (!opts.quiet && !opts.pp_only) {
+    if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
+        !OPTS_OPTION_BOOL(OPTION_PP_ONLY))
+    {
         for (itr = 0; itr < COUNT_OPTIMIZATIONS; ++itr) {
             if (opts_optimizationcount[itr]) {
                 con_out("%s: %u\n", opts_opt_list[itr].name, (unsigned int)opts_optimizationcount[itr]);
@@ -769,10 +787,10 @@ cleanup:
     vec_free(items);
     vec_free(ppems);
 
-    if (!opts.pp_only)
+    if (!OPTS_OPTION_BOOL(OPTION_PP_ONLY))
         parser_cleanup();
     if (opts_output_free)
-        mem_d((char*)opts.output);
+        mem_d(OPTS_OPTION_STR(OPTION_OUTPUT));
     if (operators_free)
         mem_d((void*)operators);
 
diff --git a/opts.c b/opts.c
index 1c68a39a8d7dbcfd96c54bbb527eb946ea56d684..5cb0ad6edaddd193e049033bfb95f7721c961769 100644 (file)
--- a/opts.c
+++ b/opts.c
@@ -27,7 +27,7 @@ opts_cmd_t   opts; /* command lien options */
 
 static void opts_setdefault() {
     memset(&opts, 0, sizeof(opts_cmd_t));
-    opts.correction = true;
+    OPTS_OPTION_BOOL(OPTION_CORRECTION) = true;
 
     /* warnings */
     opts_set(opts.warn,  WARN_UNUSED_VARIABLE,           true);
@@ -37,7 +37,6 @@ static void opts_setdefault() {
     opts_set(opts.warn,  WARN_FIELD_REDECLARED,          true);
     opts_set(opts.warn,  WARN_MISSING_RETURN_VALUES,     true);
     opts_set(opts.warn,  WARN_INVALID_PARAMETER_COUNT,   true);
-    opts_set(opts.warn,  WARN_LOCAL_SHADOWS,             false);
     opts_set(opts.warn,  WARN_LOCAL_CONSTANTS,           true);
     opts_set(opts.warn,  WARN_VOID_VARIABLES,            true);
     opts_set(opts.warn,  WARN_IMPLICIT_FUNCTION_POINTER, true);
@@ -46,24 +45,21 @@ static void opts_setdefault() {
     opts_set(opts.warn,  WARN_EFFECTLESS_STATEMENT,      true);
     opts_set(opts.warn,  WARN_END_SYS_FIELDS,            true);
     opts_set(opts.warn,  WARN_ASSIGN_FUNCTION_TYPES,     true);
-    opts_set(opts.warn,  WARN_PREPROCESSOR,              true);
+    opts_set(opts.warn,  WARN_CPP,                       true);
     opts_set(opts.warn,  WARN_MULTIFILE_IF,              true);
     opts_set(opts.warn,  WARN_DOUBLE_DECLARATION,        true);
     opts_set(opts.warn,  WARN_CONST_VAR,                 true);
     opts_set(opts.warn,  WARN_MULTIBYTE_CHARACTER,       true);
     opts_set(opts.warn,  WARN_UNKNOWN_PRAGMAS,           true);
     opts_set(opts.warn,  WARN_UNREACHABLE_CODE,          true);
-    opts_set(opts.warn,  WARN_CPP,                       true);
     opts_set(opts.warn,  WARN_UNKNOWN_ATTRIBUTE,         true);
     opts_set(opts.warn,  WARN_RESERVED_NAMES,            true);
     opts_set(opts.warn,  WARN_UNINITIALIZED_CONSTANT,    true);
-    opts_set(opts.warn,  WARN_UNINITIALIZED_GLOBAL,      false);
     opts_set(opts.warn,  WARN_DEPRECATED,                true);
     opts_set(opts.warn,  WARN_PARENTHESIS,               true);
+
     /* flags */
     opts_set(opts.flags, ADJUST_VECTOR_FIELDS,           true);
-    opts_set(opts.flags, FTEPP,                          false);
-    opts_set(opts.flags, FTEPP_PREDEFS,                  false);
     opts_set(opts.flags, CORRECT_TERNARY,                true);
     opts_set(opts.flags, BAIL_ON_WERROR,                 true);
     opts_set(opts.flags, LEGACY_VECTOR_MATHS,            true);
@@ -97,9 +93,9 @@ void opts_restore_non_Werror_all() {
 void opts_init(const char *output, int standard, size_t arraysize) {
     opts_setdefault();
 
-    opts.output         = output;
-    opts.standard       = (opts_std_t)standard; /* C++ ... y u no like me? */
-    opts.max_array_size = arraysize;
+    OPTS_OPTION_STR(OPTION_OUTPUT)         = (char*)output;
+    OPTS_OPTION_U32(OPTION_STANDARD)       = standard;
+    OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE) = arraysize;
 }
 
 static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def *list, size_t listsize) {
@@ -108,17 +104,12 @@ static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const o
     for (i = 0; i < listsize; ++i) {
         if (!strcmp(name, list[i].name)) {
             longbit lb = list[i].bit;
-#if 1
+
             if (on)
                 flags[lb.idx] |= (1<<(lb.bit));
             else
                 flags[lb.idx] &= ~(1<<(lb.bit));
-#else
-            if (on)
-                flags[0] |= (1<<lb);
-            else
-                flags[0] &= ~(1<<(lb));
-#endif
+
             return true;
         }
     }
@@ -140,17 +131,11 @@ bool opts_setoptim (const char *name, bool on) {
 void opts_set(uint32_t *flags, size_t idx, bool on) {
     longbit lb;
     LONGBIT_SET(lb, idx);
-#if 1
+
     if (on)
         flags[lb.idx] |= (1<<(lb.bit));
     else
         flags[lb.idx] &= ~(1<<(lb.bit));
-#else
-    if (on)
-        flags[0] |= (1<<(lb));
-    else
-        flags[0] &= ~(1<<(lb));
-#endif
 }
 
 void opts_setoptimlevel(unsigned int level) {
@@ -286,7 +271,7 @@ static char *opts_ini_load(const char *section, const char *name, const char *va
 
     /* flags */
     #define GMQCC_TYPE_FLAGS
-    #define GMQCC_DEFINE_FLAG(X)                                       \
+    #define GMQCC_DEFINE_FLAG(X, Y)                                    \
     if (!strcmp(section, "flags") && !strcmp(name, #X)) {              \
         opts_set(opts.flags, X, opts_ini_bool(value));                 \
         found = true;                                                  \
@@ -295,7 +280,7 @@ static char *opts_ini_load(const char *section, const char *name, const char *va
 
     /* warnings */
     #define GMQCC_TYPE_WARNS
-    #define GMQCC_DEFINE_FLAG(X)                                       \
+    #define GMQCC_DEFINE_FLAG(X, Y)                                    \
     if (!strcmp(section, "warnings") && !strcmp(name, #X)) {           \
         opts_set(opts.warn, WARN_##X, opts_ini_bool(value));           \
         found = true;                                                  \
@@ -304,7 +289,7 @@ static char *opts_ini_load(const char *section, const char *name, const char *va
 
     /* Werror-individuals */
     #define GMQCC_TYPE_WARNS
-    #define GMQCC_DEFINE_FLAG(X)                                       \
+    #define GMQCC_DEFINE_FLAG(X, Y)                                    \
     if (!strcmp(section, "errors") && !strcmp(name, #X)) {             \
         opts_set(opts.werror, WARN_##X, opts_ini_bool(value));         \
         found = true;                                                  \
@@ -313,7 +298,7 @@ static char *opts_ini_load(const char *section, const char *name, const char *va
 
     /* optimizations */
     #define GMQCC_TYPE_OPTIMIZATIONS
-    #define GMQCC_DEFINE_FLAG(X,Y)                                     \
+    #define GMQCC_DEFINE_FLAG(X,Y,Z)                                   \
     if (!strcmp(section, "optimizations") && !strcmp(name, #X)) {      \
         opts_set(opts.optimization, OPTIM_##X, opts_ini_bool(value));  \
         found = true;                                                  \
index dc6869e89288e2511458698c18e7b5a5fee51cee..d04af570df840de90feaf365c992d9b0a88e086e 100644 (file)
--- a/opts.def
+++ b/opts.def
  * SOFTWARE.
  */
 #ifndef GMQCC_DEFINE_FLAG
-#   define GMQCC_DEFINE_FLAG(x)
+#   ifdef GMQCC_TYPE_OPTIMIZATIONS
+#       define GMQCC_DEFINE_FLAG(X, Y, Z)
+#   else
+#       define GMQCC_DEFINE_FLAG(X, Y)
+#   endif /* !GMQCC_TYPE_OPTIMIZATIONS */
 #endif
 
 /* codegen flags */
 #ifdef GMQCC_TYPE_FLAGS
-    GMQCC_DEFINE_FLAG(DARKPLACES_STRING_TABLE_BUG)
-    GMQCC_DEFINE_FLAG(ADJUST_VECTOR_FIELDS)
-    GMQCC_DEFINE_FLAG(FTEPP)
-    GMQCC_DEFINE_FLAG(FTEPP_PREDEFS)
-    GMQCC_DEFINE_FLAG(RELAXED_SWITCH)
-    GMQCC_DEFINE_FLAG(SHORT_LOGIC)
-    GMQCC_DEFINE_FLAG(PERL_LOGIC)
-    GMQCC_DEFINE_FLAG(TRANSLATABLE_STRINGS)
-    GMQCC_DEFINE_FLAG(INITIALIZED_NONCONSTANTS)
-    GMQCC_DEFINE_FLAG(ASSIGN_FUNCTION_TYPES)
-    GMQCC_DEFINE_FLAG(LNO)
-    GMQCC_DEFINE_FLAG(CORRECT_TERNARY)
-    GMQCC_DEFINE_FLAG(SINGLE_VECTOR_DEFS)
-    GMQCC_DEFINE_FLAG(CORRECT_LOGIC)
-    GMQCC_DEFINE_FLAG(TRUE_EMPTY_STRINGS)
-    GMQCC_DEFINE_FLAG(FALSE_EMPTY_STRINGS)
-    GMQCC_DEFINE_FLAG(UTF8)
-    GMQCC_DEFINE_FLAG(BAIL_ON_WERROR)
-    GMQCC_DEFINE_FLAG(LOOP_LABELS)
-    GMQCC_DEFINE_FLAG(UNTYPED_NIL)
-    GMQCC_DEFINE_FLAG(PERMISSIVE)
-    GMQCC_DEFINE_FLAG(VARIADIC_ARGS)
-    GMQCC_DEFINE_FLAG(LEGACY_VECTOR_MATHS)
+    GMQCC_DEFINE_FLAG (
+        DARKPLACES_STRING_TABLE_BUG,
+
+        "Add some additional characters to the string table in order to\n"
+        "compensate for a wrong boundcheck in some specific version of the\n"
+        "darkplaces engine."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        ADJUST_VECTOR_FIELDS,
+
+        "When assigning to field pointers of type .vector the common be\n"
+        "haviour in compilers like fteqcc is to only assign the x-compo-\n"
+        "nent of the pointer. This means that you can use the vector as\n"
+        "such, but you cannot use its y and z components directly. This\n"
+        "flag fixes this behaviour. Before using it make sure your code\n"
+        "does not depend on the buggy behaviour."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        FTEPP,
+
+        "Enable a partially fteqcc-compatible preprocessor. It supports\n"
+        "all the features used in the Xonotic codebase. If you need more,\n"
+        "write a ticket."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        FTEPP_PREDEFS,
+
+        "Enable some predefined macros. This only works in combination\n"
+        "with '-fftepp' and is currently not included by '-std=fteqcc'.\n"
+        "The following macros will be added:\n\n"
+        "    __LINE__\n"
+        "    __FILE__\n"
+        "    __COUNTER__\n"
+        "    __COUNTER_LAST__\n"
+        "    __RANDOM__\n"
+        "    __RANDOM_LAST__\n"
+        "    __DATE__\n"
+        "    __TIME__\n\n"
+        "Note that fteqcc also defines __NULL__ which is not implemented\n"
+        "yet.  (See -funtyped-nil about gmqcc's alternative to __NULL__)."
+    )
+
+
+    GMQCC_DEFINE_FLAG (
+        RELAXED_SWITCH,
+
+        "Allow switch cases to use non constant variables."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        SHORT_LOGIC,
+
+        "Perform early out in logical AND and OR expressions. The final\n"
+        "result will be either a 0 or a 1, see the next flag for more pos-\n"
+        "sibilities."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        PERL_LOGIC,
+
+        "In many languages, logical expressions perform early out in a\n"
+        "special way: If the left operand of an AND yeilds true, or the\n"
+        "one of an OR yields false, the complete expression evaluates to\n"
+        "the right side.  Thus ‘true && 5’ evaluates to 5 rather than 1."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        TRANSLATABLE_STRINGS,
+
+        "Enable the underscore intrinsic: Using ‘_(\"A string constant\")’\n"
+        "will cause the string immediate to get a name with a \"dotrans-\n"
+        "late_\" prefix. The darkplaces engine recognizes these and trans-\n"
+        "lates them in a way similar to how gettext works."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        INITIALIZED_NONCONSTANTS,
+
+        "Don't implicitly convert initialized variables to constants. With\n"
+        "this flag, the const keyword is required to make a constant."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        ASSIGN_FUNCTION_TYPES,
+
+        "If this flag is not set, (and it is set by default in the qcc and\n"
+        "fteqcc standards), assigning function pointers of mismatching\n"
+        "signatures will result in an error rather than a warning."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        LNO,
+
+        "Produce a linenumber file along with the output .dat file."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        CORRECT_TERNARY,
+
+        "Use C's operator precedence for ternary expressions. Unless\n"
+        "code depends on fteqcc-compatible behaviour, you'll want to use\n"
+        "this option."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        SINGLE_VECTOR_DEFS,
+
+        "Normally vectors generate 4 defs, once for the vector, and once\n"
+        "for its components with _x, _y, _z suffixes. This option prevents\n"
+        "components from being listed."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        CORRECT_LOGIC,
+
+        "Most QC compilers translate ‘if(a_vector)’ directly as an IF on\n"
+        "the vector, which means only the x-component is checked. This\n"
+        "option causes vectors to be cast to actual booleans via a NOT_V\n"
+        "and, if necessary, a NOT_F chained to it."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        TRUE_EMPTY_STRINGS,
+
+        "An empty string is considered to be true everywhere. The NOT_S\n"
+        "instruction usually considers an empty string to be false, this\n"
+        "option effectively causes the unary not in strings to use NOT_F\n"
+        "instead."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        FALSE_EMPTY_STRINGS,
+
+        "An empty string is considered to be false everywhere. This means\n"
+        "loops and if statements which depend on a string will perform a\n"
+        "NOT_S instruction on the string before using it."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        UTF8,
+
+        "Enable utf8 characters. This allows utf-8 encoded character con-\n"
+        "stants, and escape sequence codepoints in the valid utf-8 range.\n"
+        "Effectively enabling escape sequences like '\\{x2211}'."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        BAIL_ON_WERROR,
+
+        "When a warning is treated as an error, and this option is set\n"
+        "(which it is by default), it is like any other error and will\n"
+        "cause compilation to stop. When disabling this flag by using\n"
+        "-fno-bail-on-werror, compilation will continue until the end, but\n"
+        "no output is generated. Instead the first such error message's\n"
+        "context is shown."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        LOOP_LABELS,
+
+        "Allow loops to be labeled, and allow 'break' and 'continue' to\n"
+        "take an optional label to decide which loop to actually jump out\n"
+        "of or continue.\n\n"
+        "   for :outer (i = 0; i < n; ++i) {\n"
+        "       while (inner) {\n"
+        "           ...;\n"
+        "           if (something)\n"
+        "               continue outer;\n"
+        "       }\n"
+        "   }"
+    )
+
+    GMQCC_DEFINE_FLAG (
+        UNTYPED_NIL,
+
+        "Adds a global named 'nil' which is of no type and can be assigned\n"
+        "to anything. No typechecking will be performed on assignments.\n"
+        "Assigning to it is forbidden, using it in any other kind of\n"
+        "expression is also not allowed.\n\n"
+        "Note that this is different from fteqcc's __NULL__: In fteqcc,\n"
+        "__NULL__ maps to the integer written as '0i'. It's can be\n"
+        "assigned to function pointers and integers, but it'll error about\n"
+        "invalid instructions when assigning it to floats without enabling\n"
+        "the FTE instruction set. There's also a bug which allows it to be\n"
+        "assigned to vectors, for which the source will be the global at\n"
+        "offset 0, meaning the vector's y and z components will contain\n"
+        "the OFS_RETURN x and y components.\n\n"
+        "In that gmqcc the nil global is an actual global filled with\n"
+        "zeroes, and can be assigned to anything including fields, vectors\n"
+        "or function pointers, and they end up becoming zeroed."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        PERMISSIVE,
+
+        "Various effects, usually to weaken some conditions.\n\n"
+        "   with -funtyped-nil\n"
+        "       Allow local variables named ‘nil’.  (This will not\n"
+        "       allow declaring a global of that name.)"
+    )
+
+    GMQCC_DEFINE_FLAG (
+        VARIADIC_ARGS,
+
+        "Allow variadic parameters to be accessed by QC code. This can be\n"
+        "achieved via the '...' function, which takes a parameter index\n"
+        "and a typename.\n\n"
+        "Example:\n"
+        "   void vafunc(string...count) {\n"
+        "       float i;\n"
+        "       for (i = 0; i < count; ++i)\n"
+        "           print(...(i, string), \"\\n\");\n"
+        "   }"
+    )
+
+    GMQCC_DEFINE_FLAG (
+        LEGACY_VECTOR_MATHS,
+
+        "Most Quake VMs, including the one from FTEQW or up till recently\n"
+        "Darkplaces, do not cope well with vector instructions with over‐\n"
+        "lapping input and output. This option will avoid producing such\n"
+        "code."
+    )
 #endif
 
 /* warning flags */
 #ifdef GMQCC_TYPE_WARNS
-    GMQCC_DEFINE_FLAG(UNINITIALIZED_GLOBAL)
-    GMQCC_DEFINE_FLAG(DEBUG)
-    GMQCC_DEFINE_FLAG(UNUSED_VARIABLE)
-    GMQCC_DEFINE_FLAG(USED_UNINITIALIZED)
-    GMQCC_DEFINE_FLAG(UNKNOWN_CONTROL_SEQUENCE)
-    GMQCC_DEFINE_FLAG(EXTENSIONS)
-    GMQCC_DEFINE_FLAG(FIELD_REDECLARED)
-    GMQCC_DEFINE_FLAG(MISSING_RETURN_VALUES)
-    GMQCC_DEFINE_FLAG(INVALID_PARAMETER_COUNT)
-    GMQCC_DEFINE_FLAG(LOCAL_SHADOWS)
-    GMQCC_DEFINE_FLAG(LOCAL_CONSTANTS)
-    GMQCC_DEFINE_FLAG(VOID_VARIABLES)
-    GMQCC_DEFINE_FLAG(IMPLICIT_FUNCTION_POINTER)
-    GMQCC_DEFINE_FLAG(VARIADIC_FUNCTION)
-    GMQCC_DEFINE_FLAG(FRAME_MACROS)
-    GMQCC_DEFINE_FLAG(EFFECTLESS_STATEMENT)
-    GMQCC_DEFINE_FLAG(END_SYS_FIELDS)
-    GMQCC_DEFINE_FLAG(ASSIGN_FUNCTION_TYPES)
-    GMQCC_DEFINE_FLAG(PREPROCESSOR)
-    GMQCC_DEFINE_FLAG(MULTIFILE_IF)
-    GMQCC_DEFINE_FLAG(DOUBLE_DECLARATION)
-    GMQCC_DEFINE_FLAG(CONST_VAR)
-    GMQCC_DEFINE_FLAG(MULTIBYTE_CHARACTER)
-    GMQCC_DEFINE_FLAG(TERNARY_PRECEDENCE)
-    GMQCC_DEFINE_FLAG(UNKNOWN_PRAGMAS)
-    GMQCC_DEFINE_FLAG(UNREACHABLE_CODE)
-    GMQCC_DEFINE_FLAG(CPP)
-    GMQCC_DEFINE_FLAG(UNKNOWN_ATTRIBUTE)
-    GMQCC_DEFINE_FLAG(RESERVED_NAMES)
-    GMQCC_DEFINE_FLAG(UNINITIALIZED_CONSTANT)
-    GMQCC_DEFINE_FLAG(DIFFERENT_QUALIFIERS)
-    GMQCC_DEFINE_FLAG(DIFFERENT_ATTRIBUTES)
-    GMQCC_DEFINE_FLAG(DEPRECATED)
-    GMQCC_DEFINE_FLAG(PARENTHESIS)
+    GMQCC_DEFINE_FLAG (
+        UNUSED_VARIABLE,
+        
+        "Generate a warning about variables which are declared but never"
+        "used.  This can be avoided by adding the ‘noref’ keyword in front"
+        "of the variable declaration. Additionally a complete section of"
+        "unreferenced variables can be opened using ‘#pragma noref 1’ and"
+        "closed via ‘#pragma noref 0’."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        USED_UNINITIALIZED,
+
+        "Generate a warning if it is possible that a variable can be used"
+         "without prior initialization. Note that this warning is not nec"
+         "essarily reliable if the initialization happens only under cer"
+         "tain conditions. The other way is not possible: that the warning"
+         "is not generated when uninitialized use is possible."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        UNKNOWN_CONTROL_SEQUENCE,
+
+         "Generate an error when an unrecognized control sequence in a"
+         "string is used. Meaning: when there's a character after a back-"
+         "slash in a string which has no known meaning."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        EXTENSIONS,
+
+        "Warn when using special extensions which are not part of the"
+        "selected standard."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        FIELD_REDECLARED,
+
+        "Generally QC compilers ignore redeclaration of fields. Here you"
+        "can optionally enable a warning."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        MISSING_RETURN_VALUES,
+
+        "Functions which aren't of type void will warn if it possible to"
+        "reach the end without returning an actual value."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        INVALID_PARAMETER_COUNT,
+
+        "Warn about a function call with an invalid number of parameters."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        LOCAL_SHADOWS,
+
+        "Warn when a locally declared variable shadows variable."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        LOCAL_CONSTANTS,
+
+        " Warn when the initialization of a local variable turns the vari"
+        "able into a constant. This is default behaviour unless"
+        "-finitialized-nonconstants is used."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        VOID_VARIABLES,
+
+        "There are only 2 known global variables of type void:"
+        "‘end_sys_globals’ and ‘end_sys_fields’.  Any other void-variable"
+        "will warn."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        IMPLICIT_FUNCTION_POINTER,
+
+        "A global function which is not declared with the ‘var’ keyword is"
+        "expected to have an implementing body, or be a builtin. If nei"
+        "ther is the case, it implicitly becomes a function pointer, and a"
+        "warning is generated."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        VARIADIC_FUNCTION,
+
+        "Currently there's no way for an in QC implemented function to"
+        "access variadic parameters. If a function with variadic parame"
+        "ters has an implementing body, a warning will be generated."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        FRAME_MACROS,
+
+        "Generate warnings about ‘$frame’ commands, for instance about"
+        "duplicate frame definitions."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        EFFECTLESS_STATEMENT,
+
+        "Warn about statements which have no effect. Any expression which"
+        "does not call a function or assigns a variable."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        END_SYS_FIELDS,
+
+        "The ‘end_sys_fields’ variable is supposed to be a global variable"
+        "of type void.  It is also recognized as a field but this will"
+        "generate a warning."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        ASSIGN_FUNCTION_TYPES,
+
+        "Warn when assigning to a function pointer with an unmatching sig"
+        "nature. This usually happens in cases like assigning the null"
+        "function to an entity's .think function pointer."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        CPP,
+
+        "Enable warnings coming from the preprocessor. Like duplicate"
+        "macro declarations. This warning triggers when there's a problem"
+        "with the way the preprocessor has been used."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        MULTIFILE_IF,
+
+        "Warn if there's a preprocessor #if spanning across several files."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        DOUBLE_DECLARATION,
+
+        "Warn about multiple declarations of globals. This seems pretty"
+        "common in QC code so you probably do not want this unless you"
+        "want to clean up your code."
+    )
+    GMQCC_DEFINE_FLAG (
+        CONST_VAR,
+
+        "The combination of const and var is not illegal, however differ"
+        "ent compilers may handle them differently. We were told, the"
+        "intention is to create a function-pointer which is not assigna"
+        "ble.  This is exactly how we interpret it. However for this"
+        "interpretation the ‘var’ keyword is considered superfluous (and"
+        "philosophically wrong), so it is possible to generate a warning"
+        "about this."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        MULTIBYTE_CHARACTER,
+
+        "Warn about multibyte character constants, they do not work right"
+        "now."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        TERNARY_PRECEDENCE,
+
+        "Warn if a ternary expression which contains a comma operator is"
+        "used without enclosing parenthesis, since this is most likely not"
+        "what you actually want. We recommend the -fcorrect-ternary"
+        "option."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        UNKNOWN_PRAGMAS,
+
+        "Warn when encountering an unrecognized ‘#pragma’ line."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        UNREACHABLE_CODE,
+
+        "Warn about unreachable code. That is: code after a return state"
+        "ment, or code after a call to a function marked as 'noreturn'."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        DEBUG,
+
+        "Enable some warnings added in order to help debugging in the com"
+        "piler.  You won't need this."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        UNKNOWN_ATTRIBUTE,
+
+        "Warn on an unknown attribute. The warning will inlclude only the"
+        "first token inside the enclosing attribute-brackets. This may"
+        "change when the actual attribute syntax is better defined."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        RESERVED_NAMES,
+
+        "Warn when using reserved names such as ‘nil’."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        UNINITIALIZED_CONSTANT,
+
+        "Warn about global constants (using the ‘const’ keyword) with no"
+        "assigned value."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        UNINITIALIZED_GLOBAL,
+
+        "Warn about global variables with no initializing value. This is"
+        "off by default, and is added mostly to help find null-values"
+        "which are supposed to be replaced by the untyped 'nil' constant."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        DIFFERENT_QUALIFIERS,
+
+        "Warn when a variables is redeclared with a different qualifier."
+        "For example when redeclaring a variable as 'var' which was previ"
+        "ously marked 'const'."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        DIFFERENT_ATTRIBUTES,
+
+        "Similar to qualifiers but for attributes like ‘[[noreturn]]’."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        DEPRECATED,
+
+        "Warn when a function is marked with the attribute \"[[depre"
+        "cated]]\". This flag enables a warning on calls to functions"
+        "marked as such."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        PARENTHESIS,
+
+        "Warn about possible mistakes caused by missing or wrong parenthe"
+        "sis, like an assignment in an 'if' condition when there's no"
+        "additional set of parens around the assignment."
+    )
 #endif
 
 #ifdef GMQCC_TYPE_OPTIMIZATIONS
-    GMQCC_DEFINE_FLAG(PEEPHOLE,             1)
-    GMQCC_DEFINE_FLAG(LOCAL_TEMPS,          3)
-    GMQCC_DEFINE_FLAG(GLOBAL_TEMPS,         3)
-    GMQCC_DEFINE_FLAG(TAIL_RECURSION,       1)
-    GMQCC_DEFINE_FLAG(TAIL_CALLS,           2)
-    GMQCC_DEFINE_FLAG(OVERLAP_LOCALS,       3)
-    GMQCC_DEFINE_FLAG(STRIP_CONSTANT_NAMES, 1)
-    GMQCC_DEFINE_FLAG(OVERLAP_STRINGS,      2)
-    GMQCC_DEFINE_FLAG(CALL_STORES,          4)
-    GMQCC_DEFINE_FLAG(VOID_RETURN,          1)
-    GMQCC_DEFINE_FLAG(VECTOR_COMPONENTS,    1)
+    GMQCC_DEFINE_FLAG (
+        PEEPHOLE,             1,
+
+        "Some general peephole optimizations. For instance the code `a = b\n"
+        "+ c` typically generates 2 instructions, an ADD and a STORE. This\n"
+        "optimization removes the STORE and lets the ADD write directly\n"
+        "into A."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        TAIL_RECURSION,       1,
+
+        "Tail recursive function calls will be turned into loops to avoid\n"
+        "the overhead of the CALL and RETURN instructions."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        OVERLAP_LOCALS,       3,
+
+        "Make all functions which use neither local arrays nor have locals\n"
+        "which are seen as possibly uninitialized use the same local sec‐\n"
+        "tion.  This should be pretty safe compared to other compilers\n"
+        "which do not check for uninitialized values properly. The problem\n"
+        "is that there's QC code out there which really doesn't initialize\n"
+        "some values. This is fine as long as this kind of optimization\n"
+        "isn't used, but also, only as long as the functions cannot be\n"
+        "called in a recursive manner. Since it's hard to know whether or\n"
+        "not an array is actually fully initialized, especially when ini‐\n"
+        "tializing it via a loop, we assume functions with arrays to be\n"
+        "too dangerous for this optimization."
+    )
+
+
+    GMQCC_DEFINE_FLAG (
+        LOCAL_TEMPS,          3,
+
+        "This promotes locally declared variables to \"temps\". Meaning when\n"
+        "a temporary result of an operation has to be stored somewhere, a\n"
+        "local variable which is not 'alive' at that point can be used to\n"
+        "keep the result. This can reduce the size of the global section.\n"
+        "This will not have declared variables overlap, even if it was\n"
+        "possible."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        GLOBAL_TEMPS,         3,
+
+        "Causes temporary values which do not need to be backed up on a\n"
+        "CALL to not be stored in the function's locals-area. With this, a\n"
+        "CALL to a function may need to back up fewer values and thus exe‐\n"
+        "cute faster."
+    )
+
+
+    GMQCC_DEFINE_FLAG (
+        STRIP_CONSTANT_NAMES, 1,
+
+        "Don't generate defs for immediate values or even declared con‐\n"
+        "stants.  Meaning variables which are implicitly constant or qual‐\n"
+        "ified as such using the 'const' keyword."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        OVERLAP_STRINGS,      2,
+
+        "Aggressively reuse strings in the string section. When a string\n"
+        "should be added which is the trailing substring of an already\n"
+        "existing string, the existing string's tail will be returned\n"
+        "instead of the new string being added.\n\n"
+        "For example the following code will only generate 1 string:\n\n"
+        "   print(\"Hell you!\\n\");\n"
+        "   print(\"you!\n\"); // trailing substring of \"Hello you!\\n\"\n\n"
+        "There's however one limitation. Strings are still processed in\n"
+        "order, so if the above print statements were reversed, this opti‐\n"
+        "mization would not happen."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        CALL_STORES,          3,
+
+        "By default, all parameters of a CALL are copied into the parame‐\n"
+        "ter-globals right before the CALL instructions. This is the easi‐\n"
+        "est and safest way to translate calls, but also adds a lot of\n"
+        "unnecessary copying and unnecessary temporary values. This opti‐\n"
+        "mization makes operations which are used as a parameter evaluate\n"
+        "directly into the parameter-global if that is possible, which is\n"
+        "when there's no other CALL instruction in between."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        VOID_RETURN,          1,
+
+        "Usually an empty RETURN instruction is added to the end of a void\n"
+        "typed function. However, additionally after every function a DONE\n"
+        "instruction is added for several reasons. (For example the qcvm's\n"
+        "disassemble switch uses it to know when the function ends.). This\n"
+        "optimization replaces that last RETURN with DONE rather than\n"
+        "adding the DONE additionally."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        VECTOR_COMPONENTS,    1,
+
+        "Because traditional QC code doesn't allow you to access individ‐\n"
+        "ual vector components of a computed vector without storing it in\n"
+        "a local first, sometimes people multiply it by a constant like\n"
+        "‘'0 1 0'’ to get, in this case, the y component of a vector. This\n"
+        "optimization will turn such a multiplication into a direct compo‐\n"
+        "nent access. If the factor is anything other than 1, a float-mul‐\n"
+        "tiplication will be added, which is still faster than a vector"
+        "multiplication."
+    )
+#endif
+
+#ifdef GMQCC_TYPE_OPTIONS
+    GMQCC_DEFINE_FLAG (
+        O,
+
+        "Specify the optimization level\n"
+        "3        Highest optimization level\n"
+        "2        Default optimization level\n"
+        "1        Minimal optimization level\n"
+        "0        Disable optimization entirely"
+    )
+    GMQCC_DEFINE_FLAG (
+        OUTPUT,
+
+        "Specify the output file name. Defaults to progs.dat. This will\n"
+        "overwrite the output file listed in a progs.src file in case such\n"
+        "a file is used."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        QUIET,
+
+        "Be less verbose. In particular removes the messages about which\n"
+        "files are being processed, and which compilation mode is being\n"
+        "used, and some others. Warnings and errors will of course still\n"
+        "be displayed."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        G,
+
+        ""
+    )
+
+    GMQCC_DEFINE_FLAG (
+        STANDARD,
+
+        "Use the specified standard for parsing QC code. The following\n"
+        "standards are available: gmqcc, qcc, fteqcc Selecting a standard\n"
+        "also implies some -f options and behaves as if those options have\n"
+        "been written right after the -std option, meaning if you changed\n"
+        "them before the --std option, you're now overwriting them.\n\n"
+        "-std=gmqcc includes:\n"
+        "   -fadjust-vector-fields\n"
+        "   -fcorrect-logic\n"
+        "   -ftrue-empty-strings\n"
+        "   -floop-labels\n"
+        "   -finitialized-nonconstants\n"
+        "   -ftranslatable-strings\n"
+        "   -fno-false-empty-strings\n"
+        "   -Winvalid-parameter-count\n"
+        "   -Wmissing-returnvalues\n"
+        "   -fcorrect-ternary (cannot be turned off)\n\n"
+        "-std=qcc includes:\n"
+        "   -fassign-function-types\n"
+        "   -fIno-adjust-vector-fields\n\n"
+        "-std=fteqcc includes:\n"
+        "   -fftepp\n"
+        "   -ftranslatable-strings\n"
+        "   -fassign-function-types\n"
+        "   -Wternary-precedence\n"
+        "   -fno-adjust-vector-fields\n"
+        "   -fno-correct-ternary"
+    )
+
+    GMQCC_DEFINE_FLAG (
+        DEBUG,
+
+        "Turn on some compiler debuggin mechanisms"
+    )
+
+    GMQCC_DEFINE_FLAG (
+        MEMCHK,
+
+        "Turn on compiler mem-chk. (Shows allocations and checks for\n"
+        "leaks.)"
+    )
+
+    GMQCC_DEFINE_FLAG (
+        DUMPFIN,
+
+        "DEBUG OPTION. Print the code's intermediate representation after\n"
+        "the optimization and finalization passes to stdout before gener‐\n"
+        "ating the binary. The instructions will be enumerated, and values\n"
+        "will contain a list of liferanges."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        DUMP,
+
+        "DEBUG OPTION. Print the code's intermediate representation before\n"
+        "the optimization and finalization passes to stdout before gener‐\n"
+        "ating the binary."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        FORCECRC,
+
+        "When enabled allows forcing a specific CRC16 for the generated\n"
+        "progs.dat"
+    )
+
+    GMQCC_DEFINE_FLAG (
+        FORCED_CRC,
+
+        "Value which represents the CRC to force into the progs.dat"
+    )
+
+    GMQCC_DEFINE_FLAG (
+        PP_ONLY,
+
+        "Run only the preprocessor as if -fftepp was used and print the\n"
+        "preprocessed code to stdout."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        MAX_ARRAY_SIZE,
+
+        "Maximum allowed one-dimensional array size.  Arrays are expensive\n"
+        "since binary search trees are generated for each set/get of an array\n"
+        "the more elements in an array (the larger it is), the longer it will\n"
+        "take to set/get elements."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        ADD_INFO,
+
+        "Adds compiler information to the generated binary file. Currently\n"
+        "this includes the following globals:\n"
+        "   reserved:version\n"
+        "       String containing the compiler version as printed by the\n"
+        "       --version parameter."
+    )
+
+    GMQCC_DEFINE_FLAG (
+        CORRECTION,
+
+        "When enabled, errors about undefined values try to suggest an\n"
+        "existing value via spell checking."
+    )
 #endif
 
 /* some cleanup so we don't have to */
 #undef GMQCC_TYPE_FLAGS
 #undef GMQCC_TYPE_WARNS
+#undef GMQCC_TYPE_OPTIONS
 #undef GMQCC_TYPE_OPTIMIZATIONS
 #undef GMQCC_DEFINE_FLAG
index 2616081a1b52d0d7263494b03f57356d5dbc729f..90d73bae931ec3c9ceb4ea531c008edd8fc2c353 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -34,7 +34,6 @@
 #define PARSER_HT_SIZE    128
 #define TYPEDEF_HT_SIZE   16
 
-enum parser_pot { POT_PAREN, POT_TERNARY1, POT_TERNARY2 };
 typedef struct {
     lex_file *lex;
     int      tok;
@@ -52,7 +51,10 @@ typedef struct {
 
     ast_value *imm_float_zero;
     ast_value *imm_float_one;
+    ast_value *imm_float_neg_one;
+
     ast_value *imm_vector_zero;
+
     ast_value *nil;
     ast_value *reserved_version;
 
@@ -89,12 +91,6 @@ typedef struct {
     /* we store the '=' operator info */
     const oper_info *assign_op;
 
-    /* Keep track of our ternary vs parenthesis nesting state.
-     * If we reach a 'comma' operator in a ternary without a paren,
-     * we shall trigger -Wternary-precedence.
-     */
-    enum parser_pot *pot;
-
     /* magic values */
     ast_value *const_vec[3];
 
@@ -142,16 +138,6 @@ static bool GMQCC_WARN parsewarning(parser_t *parser, int warntype, const char *
     return r;
 }
 
-static bool GMQCC_WARN genwarning(lex_ctx ctx, int warntype, const char *fmt, ...)
-{
-    bool    r;
-    va_list ap;
-    va_start(ap, fmt);
-    r = vcompile_warning(ctx, warntype, fmt, ap);
-    va_end(ap);
-    return r;
-}
-
 /**********************************************************************
  * some maths used for constant folding
  */
@@ -239,6 +225,12 @@ static ast_value* parser_const_float_0(parser_t *parser)
     return parser->imm_float_zero;
 }
 
+static ast_value* parser_const_float_neg1(parser_t *parser) {
+    if (!parser->imm_float_neg_one)
+        parser->imm_float_neg_one = parser_const_float(parser, -1);
+    return parser->imm_float_neg_one;
+}
+
 static ast_value* parser_const_float_1(parser_t *parser)
 {
     if (!parser->imm_float_one)
@@ -386,23 +378,28 @@ static ast_value* parser_find_typedef(parser_t *parser, const char *name, size_t
 typedef struct
 {
     size_t etype; /* 0 = expression, others are operators */
-    int             paren;
+    bool            isparen;
     size_t          off;
     ast_expression *out;
     ast_block      *block; /* for commas and function calls */
     lex_ctx ctx;
 } sy_elem;
+
+enum {
+    PAREN_EXPR,
+    PAREN_FUNC,
+    PAREN_INDEX,
+    PAREN_TERNARY1,
+    PAREN_TERNARY2
+};
 typedef struct
 {
-    sy_elem *out;
-    sy_elem *ops;
+    sy_elem        *out;
+    sy_elem        *ops;
+    size_t         *argc;
+    unsigned int   *paren;
 } shunt;
 
-#define SY_PAREN_EXPR '('
-#define SY_PAREN_FUNC 'f'
-#define SY_PAREN_INDEX '['
-#define SY_PAREN_TERNARY '?'
-
 static sy_elem syexp(lex_ctx ctx, ast_expression *v) {
     sy_elem e;
     e.etype = 0;
@@ -410,7 +407,7 @@ static sy_elem syexp(lex_ctx ctx, ast_expression *v) {
     e.out   = v;
     e.block = NULL;
     e.ctx   = ctx;
-    e.paren = 0;
+    e.isparen = false;
     return e;
 }
 
@@ -421,7 +418,7 @@ static sy_elem syblock(lex_ctx ctx, ast_block *v) {
     e.out   = (ast_expression*)v;
     e.block = v;
     e.ctx   = ctx;
-    e.paren = 0;
+    e.isparen = false;
     return e;
 }
 
@@ -432,27 +429,21 @@ static sy_elem syop(lex_ctx ctx, const oper_info *op) {
     e.out   = NULL;
     e.block = NULL;
     e.ctx   = ctx;
-    e.paren = 0;
+    e.isparen = false;
     return e;
 }
 
-static sy_elem syparen(lex_ctx ctx, int p, size_t off) {
+static sy_elem syparen(lex_ctx ctx, size_t off) {
     sy_elem e;
     e.etype = 0;
     e.off   = off;
     e.out   = NULL;
     e.block = NULL;
     e.ctx   = ctx;
-    e.paren = p;
+    e.isparen = true;
     return e;
 }
 
-#ifdef DEBUGSHUNT
-# define DEBUGSHUNTDO(x) x
-#else
-# define DEBUGSHUNTDO(x)
-#endif
-
 /* With regular precedence rules, ent.foo[n] is the same as (ent.foo)[n],
  * so we need to rotate it to become ent.(foo[n]).
  */
@@ -537,7 +528,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
         return false;
     }
 
-    if (vec_last(sy->ops).paren) {
+    if (vec_last(sy->ops).isparen) {
         parseerror(parser, "unmatched parenthesis");
         return false;
     }
@@ -545,8 +536,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
     op = &operators[vec_last(sy->ops).etype - 1];
     ctx = vec_last(sy->ops).ctx;
 
-    DEBUGSHUNTDO(con_out("apply %s\n", op->op));
-
     if (vec_size(sy->out) < op->operands) {
         compile_error(ctx, "internal error: not enough operands: %i (operator %s (%i))", vec_size(sy->out),
                       op->op, (int)op->id);
@@ -650,7 +639,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             {
 #if 0
                 /* This is not broken in fteqcc anymore */
-                if (opts.standard != COMPILER_GMQCC) {
+                if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_GMQCC) {
                     /* this error doesn't need to make us bail out */
                     (void)!parsewarning(parser, WARN_EXTENSIONS,
                                         "accessing array-field members of an entity without parenthesis\n"
@@ -661,6 +650,12 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             break;
 
         case opid1(','):
+            if (vec_size(sy->paren) && vec_last(sy->paren) == PAREN_FUNC) {
+                vec_push(sy->out, syexp(ctx, exprs[0]));
+                vec_push(sy->out, syexp(ctx, exprs[1]));
+                vec_last(sy->argc)++;
+                return true;
+            }
             if (blocks[0]) {
                 if (!ast_block_add_expr(blocks[0], exprs[1]))
                     return false;
@@ -1052,11 +1047,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             break;
 
         case opid2('?',':'):
-            if (vec_last(parser->pot) != POT_TERNARY2) {
+            if (vec_last(sy->paren) != PAREN_TERNARY2) {
                 compile_error(ctx, "mismatched parenthesis/ternary");
                 return false;
             }
-            vec_pop(parser->pot);
+            vec_pop(sy->paren);
             if (!ast_compare_type(exprs[1], exprs[2])) {
                 ast_type_to_string(exprs[1], ty1, sizeof(ty1));
                 ast_type_to_string(exprs[2], ty2, sizeof(ty2));
@@ -1115,7 +1110,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                 }
                 else
                     assignop = type_storep_instr[exprs[0]->expression.vtype];
-                if (assignop == AINSTR_END || !ast_compare_type(field->expression.next, exprs[1]))
+                if (assignop == VINSTR_END || !ast_compare_type(field->expression.next, exprs[1]))
                 {
                     ast_type_to_string(field->expression.next, ty1, sizeof(ty1));
                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
@@ -1142,7 +1137,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                     assignop = type_store_instr[exprs[0]->expression.vtype];
                 }
 
-                if (assignop == AINSTR_END) {
+                if (assignop == VINSTR_END) {
                     ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                     compile_error(ctx, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
@@ -1360,15 +1355,28 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             asbinstore->keep_dest = true;
             out = (ast_expression*)asbinstore;
             break;
+
+        case opid2('~', 'P'):
+            if (exprs[0]->expression.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;
+            }
+
+            if(CanConstFold1(exprs[0]))
+                out = (ast_expression*)parser_const_float(parser, ~(qcint)ConstF(0));
+            else
+                out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]);
+            break;
+            
     }
 #undef NotSameType
 
     if (!out) {
-        compile_error(ctx, "failed to apply operand %s", op->op);
+        compile_error(ctx, "failed to apply operator %s", op->op);
         return false;
     }
 
-    DEBUGSHUNTDO(con_out("applied %s\n", op->op));
     vec_push(sy->out, syexp(ctx, out));
     return true;
 }
@@ -1381,20 +1389,27 @@ static bool parser_close_call(parser_t *parser, shunt *sy)
     ast_call       *call;
 
     size_t          fid;
-    size_t          paramcount;
+    size_t          paramcount, i;
 
+    fid = vec_last(sy->ops).off;
     vec_shrinkby(sy->ops, 1);
-    fid = sy->ops[vec_size(sy->ops)].off;
 
     /* out[fid] is the function
      * everything above is parameters...
-     * 0 params = nothing
-     * 1 params = ast_expression
-     * more = ast_block
      */
+    if (!vec_size(sy->argc)) {
+        parseerror(parser, "internal error: no argument counter available");
+        return false;
+    }
+
+    paramcount = vec_last(sy->argc);
+    vec_pop(sy->argc);
 
-    if (vec_size(sy->out) < 1 || vec_size(sy->out) <= fid) {
-        parseerror(parser, "internal error: function call needs function and parameter list...");
+    if (vec_size(sy->out) < fid) {
+        parseerror(parser, "internal error: broken function call%lu < %lu+%lu\n",
+                   (unsigned long)vec_size(sy->out),
+                   (unsigned long)fid,
+                   (unsigned long)paramcount);
         return false;
     }
 
@@ -1420,42 +1435,28 @@ static bool parser_close_call(parser_t *parser, shunt *sy)
     if (!call)
         return false;
 
-    if (fid+1 == vec_size(sy->out)) {
-        /* no arguments */
-        paramcount = 0;
-    } else if (fid+2 == vec_size(sy->out)) {
-        ast_block *params;
-        vec_shrinkby(sy->out, 1);
-        params = sy->out[vec_size(sy->out)].block;
-        if (!params) {
-            /* 1 param */
-            paramcount = 1;
-            vec_push(call->params, sy->out[vec_size(sy->out)].out);
-        } else {
-            paramcount = vec_size(params->exprs);
-            call->params = params->exprs;
-            params->exprs = NULL;
-            ast_delete(params);
-        }
-        if (parser->max_param_count < paramcount)
-            parser->max_param_count = paramcount;
-        (void)!ast_call_check_types(call);
-    } else {
-        parseerror(parser, "invalid function call");
+    if (fid+1 < vec_size(sy->out))
+        ++paramcount;
+
+    if (fid+1 + paramcount != vec_size(sy->out)) {
+        parseerror(parser, "internal error: parameter count mismatch: (%lu+1+%lu), %lu",
+                   (unsigned long)fid, (unsigned long)paramcount, (unsigned long)vec_size(sy->out));
         return false;
     }
 
+    for (i = 0; i < paramcount; ++i)
+        vec_push(call->params, sy->out[fid+1 + i].out);
+    vec_shrinkby(sy->out, paramcount);
+    (void)!ast_call_check_types(call);
+    if (parser->max_param_count < paramcount)
+        parser->max_param_count = paramcount;
+
     if (ast_istype(fun, ast_value)) {
         funval = (ast_value*)fun;
         if ((fun->expression.flags & AST_FLAG_VARIADIC) &&
             !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin))
         {
-            size_t va_count;
-            if (paramcount < vec_size(fun->expression.params))
-                va_count = 0;
-            else
-                va_count = paramcount - vec_size(fun->expression.params);
-            call->va_count = (ast_expression*)parser_const_float(parser, (double)va_count);
+            call->va_count = (ast_expression*)parser_const_float(parser, (double)paramcount);
         }
     }
 
@@ -1516,54 +1517,48 @@ static bool parser_close_call(parser_t *parser, shunt *sy)
     return true;
 }
 
-static bool parser_close_paren(parser_t *parser, shunt *sy, bool functions_only)
+static bool parser_close_paren(parser_t *parser, shunt *sy)
 {
     if (!vec_size(sy->ops)) {
         parseerror(parser, "unmatched closing paren");
         return false;
     }
-    /* this would for bit a + (x) because there are no operators inside (x)
-    if (sy->ops[vec_size(sy->ops)-1].paren == 1) {
-        parseerror(parser, "empty parenthesis expression");
-        return false;
-    }
-    */
+
     while (vec_size(sy->ops)) {
-        if (vec_last(sy->ops).paren == SY_PAREN_FUNC) {
-            if (!parser_close_call(parser, sy))
-                return false;
-            break;
-        }
-        if (vec_last(sy->ops).paren == SY_PAREN_EXPR) {
-            if (!vec_size(sy->out)) {
-                compile_error(vec_last(sy->ops).ctx, "empty paren expression");
+        if (vec_last(sy->ops).isparen) {
+            if (vec_last(sy->paren) == PAREN_FUNC) {
+                vec_pop(sy->paren);
+                if (!parser_close_call(parser, sy))
+                    return false;
+                break;
+            }
+            if (vec_last(sy->paren) == PAREN_EXPR) {
+                vec_pop(sy->paren);
+                if (!vec_size(sy->out)) {
+                    compile_error(vec_last(sy->ops).ctx, "empty paren expression");
+                    vec_shrinkby(sy->ops, 1);
+                    return false;
+                }
                 vec_shrinkby(sy->ops, 1);
-                return false;
+                break;
             }
-            vec_shrinkby(sy->ops, 1);
-            return !functions_only;
-        }
-        if (vec_last(sy->ops).paren == SY_PAREN_INDEX) {
-            if (functions_only)
-                return false;
-            /* pop off the parenthesis */
-            vec_shrinkby(sy->ops, 1);
-            /* then apply the index operator */
-            if (!parser_sy_apply_operator(parser, sy))
-                return false;
-            return true;
-        }
-        if (vec_last(sy->ops).paren == SY_PAREN_TERNARY) {
-            if (functions_only)
-                return false;
-            if (vec_last(parser->pot) != POT_TERNARY1) {
-                parseerror(parser, "mismatched colon in ternary expression (missing closing paren?)");
-                return false;
+            if (vec_last(sy->paren) == PAREN_INDEX) {
+                vec_pop(sy->paren);
+                /* pop off the parenthesis */
+                vec_shrinkby(sy->ops, 1);
+                /* then apply the index operator */
+                if (!parser_sy_apply_operator(parser, sy))
+                    return false;
+                break;
             }
-            vec_last(parser->pot) = POT_TERNARY2;
-            /* pop off the parenthesis */
-            vec_shrinkby(sy->ops, 1);
-            return true;
+            if (vec_last(sy->paren) == PAREN_TERNARY1) {
+                vec_last(sy->paren) = PAREN_TERNARY2;
+                /* pop off the parenthesis */
+                vec_shrinkby(sy->ops, 1);
+                break;
+            }
+            compile_error(vec_last(sy->ops).ctx, "invalid parenthesis");
+            return false;
         }
         if (!parser_sy_apply_operator(parser, sy))
             return false;
@@ -1664,323 +1659,227 @@ static ast_expression* parse_vararg_do(parser_t *parser)
 
 static ast_expression* parse_vararg(parser_t *parser)
 {
-    bool             old_noops = parser->lex->flags.noops;
-    enum parser_pot *old_pot   = parser->pot;
+    bool           old_noops = parser->lex->flags.noops;
 
     ast_expression *out;
 
-    parser->pot = NULL;
     parser->lex->flags.noops = true;
     out = parse_vararg_do(parser);
 
-    parser->pot              = old_pot;
     parser->lex->flags.noops = old_noops;
     return out;
 }
 
-static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels)
+static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
 {
-    ast_expression *expr = NULL;
-    shunt sy;
-    size_t i;
-    bool wantop = false;
-    /* only warn once about an assignment in a truth value because the current code
-     * would trigger twice on: if(a = b && ...), once for the if-truth-value, once for the && part
-     */
-    bool warn_truthvalue = true;
-
-    /* count the parens because an if starts with one, so the
-     * end of a condition is an unmatched closing paren
-     */
-    int parens = 0;
-    int ternaries = 0;
-
-    sy.out = NULL;
-    sy.ops = NULL;
-
-    parser->lex->flags.noops = false;
-
-    parser_reclassify_token(parser);
-
-    while (true)
+    if (OPTS_FLAG(TRANSLATABLE_STRINGS) &&
+        parser->tok == TOKEN_IDENT &&
+        !strcmp(parser_tokval(parser), "_"))
     {
-        if (OPTS_FLAG(TRANSLATABLE_STRINGS) &&
-            parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "_"))
-        {
-            /* a translatable string */
-            ast_value *val;
-
-            if (wantop) {
-                parseerror(parser, "expected operator or end of statement, got constant");
-                goto onerr;
-            }
+        /* a translatable string */
+        ast_value *val;
 
-            parser->lex->flags.noops = true;
-            if (!parser_next(parser) || parser->tok != '(') {
-                parseerror(parser, "use _(\"string\") to create a translatable string constant");
-                goto onerr;
-            }
-            parser->lex->flags.noops = false;
-            if (!parser_next(parser) || parser->tok != TOKEN_STRINGCONST) {
-                parseerror(parser, "expected a constant string in translatable-string extension");
-                goto onerr;
-            }
-            val = parser_const_string(parser, parser_tokval(parser), true);
-            wantop = true;
-            if (!val)
-                return NULL;
-            vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
-            DEBUGSHUNTDO(con_out("push string\n"));
+        parser->lex->flags.noops = true;
+        if (!parser_next(parser) || parser->tok != '(') {
+            parseerror(parser, "use _(\"string\") to create a translatable string constant");
+            return false;
+        }
+        parser->lex->flags.noops = false;
+        if (!parser_next(parser) || parser->tok != TOKEN_STRINGCONST) {
+            parseerror(parser, "expected a constant string in translatable-string extension");
+            return false;
+        }
+        val = parser_const_string(parser, parser_tokval(parser), true);
+        if (!val)
+            return false;
+        vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val));
 
-            if (!parser_next(parser) || parser->tok != ')') {
-                parseerror(parser, "expected closing paren after translatable string");
-                goto onerr;
-            }
+        if (!parser_next(parser) || parser->tok != ')') {
+            parseerror(parser, "expected closing paren after translatable string");
+            return false;
         }
-        else if (parser->tok == TOKEN_DOTS)
+        return true;
+    }
+    else if (parser->tok == TOKEN_DOTS)
+    {
+        ast_expression *va;
+        if (!OPTS_FLAG(VARIADIC_ARGS)) {
+            parseerror(parser, "cannot access varargs (try -fvariadic-args)");
+            return false;
+        }
+        va = parse_vararg(parser);
+        if (!va)
+            return false;
+        vec_push(sy->out, syexp(parser_ctx(parser), va));
+        return true;
+    }
+    else if (parser->tok == TOKEN_FLOATCONST) {
+        ast_value *val;
+        val = parser_const_float(parser, (parser_token(parser)->constval.f));
+        if (!val)
+            return false;
+        vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val));
+        return true;
+    }
+    else if (parser->tok == TOKEN_INTCONST || parser->tok == TOKEN_CHARCONST) {
+        ast_value *val;
+        val = parser_const_float(parser, (double)(parser_token(parser)->constval.i));
+        if (!val)
+            return false;
+        vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val));
+        return true;
+    }
+    else if (parser->tok == TOKEN_STRINGCONST) {
+        ast_value *val;
+        val = parser_const_string(parser, parser_tokval(parser), false);
+        if (!val)
+            return false;
+        vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val));
+        return true;
+    }
+    else if (parser->tok == TOKEN_VECTORCONST) {
+        ast_value *val;
+        val = parser_const_vector(parser, parser_token(parser)->constval.v);
+        if (!val)
+            return false;
+        vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val));
+        return true;
+    }
+    else if (parser->tok == TOKEN_IDENT)
+    {
+        const char     *ctoken = parser_tokval(parser);
+        ast_expression *prev = vec_size(sy->out) ? vec_last(sy->out).out : NULL;
+        ast_expression *var;
+        /* a_vector.{x,y,z} */
+        if (!vec_size(sy->ops) ||
+            !vec_last(sy->ops).etype ||
+            operators[vec_last(sy->ops).etype-1].id != opid1('.') ||
+            (prev >= intrinsic_debug_typestring &&
+             prev <= intrinsic_debug_typestring))
         {
-            ast_expression *va;
-            if (!OPTS_FLAG(VARIADIC_ARGS)) {
-                parseerror(parser, "cannot access varargs (try -fvariadic-args)");
-                goto onerr;
-            }
-            if (wantop) {
-                parseerror(parser, "expected operator or end of statement");
-                goto onerr;
-            }
-            wantop = true;
-            va = parse_vararg(parser);
-            if (!va)
-                goto onerr;
-            vec_push(sy.out, syexp(parser_ctx(parser), va));
-            DEBUGSHUNTDO(con_out("push `...`\n"));
+            /* When adding more intrinsics, fix the above condition */
+            prev = NULL;
         }
-        else if (parser->tok == TOKEN_IDENT)
+        if (prev && prev->expression.vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1])
         {
-            const char     *ctoken = parser_tokval(parser);
-            ast_expression *prev = vec_size(sy.out) ? vec_last(sy.out).out : NULL;
-            ast_expression *var;
-            if (wantop) {
-                parseerror(parser, "expected operator or end of statement");
-                goto onerr;
+            var = (ast_expression*)parser->const_vec[ctoken[0]-'x'];
+        } else {
+            var = parser_find_var(parser, parser_tokval(parser));
+            if (!var)
+                var = parser_find_field(parser, parser_tokval(parser));
+        }
+        if (!var && with_labels) {
+            var = (ast_expression*)parser_find_label(parser, parser_tokval(parser));
+            if (!with_labels) {
+                ast_label *lbl = ast_label_new(parser_ctx(parser), parser_tokval(parser), true);
+                var = (ast_expression*)lbl;
+                vec_push(parser->labels, lbl);
             }
-            wantop = true;
-            /* a_vector.{x,y,z} */
-            if (!vec_size(sy.ops) ||
-                !vec_last(sy.ops).etype ||
-                operators[vec_last(sy.ops).etype-1].id != opid1('.') ||
-                (prev >= intrinsic_debug_typestring &&
-                 prev <= intrinsic_debug_typestring))
-            {
-                /* When adding more intrinsics, fix the above condition */
-                prev = NULL;
+        }
+        if (!var) {
+            /* intrinsics */
+            if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
+                var = (ast_expression*)intrinsic_debug_typestring;
             }
-            if (prev && prev->expression.vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1])
+            else
             {
-                var = (ast_expression*)parser->const_vec[ctoken[0]-'x'];
-            } else {
-                var = parser_find_var(parser, parser_tokval(parser));
-                if (!var)
-                    var = parser_find_field(parser, parser_tokval(parser));
-            }
-            if (!var && with_labels) {
-                var = (ast_expression*)parser_find_label(parser, parser_tokval(parser));
-                if (!with_labels) {
-                    ast_label *lbl = ast_label_new(parser_ctx(parser), parser_tokval(parser), true);
-                    var = (ast_expression*)lbl;
-                    vec_push(parser->labels, lbl);
-                }
-            }
-            if (!var) {
-                /* intrinsics */
-                if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
-                    var = (ast_expression*)intrinsic_debug_typestring;
-                }
-                else
-                {
-                    char *correct = NULL;
-
-                    /*
-                     * sometimes people use preprocessing predefs without enabling them
-                     * 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));
-                                goto onerr;
-                            }
+                char *correct = NULL;
+                size_t i;
+
+                /*
+                 * sometimes people use preprocessing predefs without enabling them
+                 * 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;
                         }
                     }
+                }
 
-                    /*
-                     * TODO: determine the best score for the identifier: be it
-                     * a variable, a field.
-                     *
-                     * We should also consider adding correction tables for
-                     * other things as well.
-                     */
-                    if (opts.correction) {
-                        correction_t corr;
-                        correct_init(&corr);
-
-                        for (i = 0; i < vec_size(parser->correct_variables); i++) {
-                            correct = correct_str(&corr, parser->correct_variables[i], parser_tokval(parser));
-                            if (strcmp(correct, parser_tokval(parser))) {
-                                break;
-                            } else if (correct) {
-                                mem_d(correct);
-                                correct = NULL;
-                            }
-                        }
-                        correct_free(&corr);
-
-                        if (correct) {
-                            parseerror(parser, "unexpected ident: %s (did you mean %s?)", parser_tokval(parser), correct);
+                /*
+                 * TODO: determine the best score for the identifier: be it
+                 * a variable, a field.
+                 *
+                 * We should also consider adding correction tables for
+                 * other things as well.
+                 */
+                if (OPTS_OPTION_BOOL(OPTION_CORRECTION)) {
+                    correction_t corr;
+                    correct_init(&corr);
+
+                    for (i = 0; i < vec_size(parser->correct_variables); i++) {
+                        correct = correct_str(&corr, parser->correct_variables[i], parser_tokval(parser));
+                        if (strcmp(correct, parser_tokval(parser))) {
+                            break;
+                        } else if (correct) {
                             mem_d(correct);
-                            goto onerr;
+                            correct = NULL;
                         }
                     }
-                    parseerror(parser, "unexpected ident: %s", parser_tokval(parser));
-                    goto onerr;
-                }
-            }
-            else
-            {
-                if (ast_istype(var, ast_value)) {
-                    ((ast_value*)var)->uses++;
-                }
-                else if (ast_istype(var, ast_member)) {
-                    ast_member *mem = (ast_member*)var;
-                    if (ast_istype(mem->owner, ast_value))
-                        ((ast_value*)(mem->owner))->uses++;
+                    correct_free(&corr);
+
+                    if (correct) {
+                        parseerror(parser, "unexpected ident: %s (did you mean %s?)", parser_tokval(parser), correct);
+                        mem_d(correct);
+                        return false;
+                    }
                 }
+                parseerror(parser, "unexpected ident: %s", parser_tokval(parser));
+                return false;
             }
-            vec_push(sy.out, syexp(parser_ctx(parser), var));
-            DEBUGSHUNTDO(con_out("push %s\n", parser_tokval(parser)));
-        }
-        else if (parser->tok == TOKEN_FLOATCONST) {
-            ast_value *val;
-            if (wantop) {
-                parseerror(parser, "expected operator or end of statement, got constant");
-                goto onerr;
-            }
-            wantop = true;
-            val = parser_const_float(parser, (parser_token(parser)->constval.f));
-            if (!val)
-                return NULL;
-            vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
-            DEBUGSHUNTDO(con_out("push %g\n", parser_token(parser)->constval.f));
-        }
-        else if (parser->tok == TOKEN_INTCONST || parser->tok == TOKEN_CHARCONST) {
-            ast_value *val;
-            if (wantop) {
-                parseerror(parser, "expected operator or end of statement, got constant");
-                goto onerr;
-            }
-            wantop = true;
-            val = parser_const_float(parser, (double)(parser_token(parser)->constval.i));
-            if (!val)
-                return NULL;
-            vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
-            DEBUGSHUNTDO(con_out("push %i\n", parser_token(parser)->constval.i));
-        }
-        else if (parser->tok == TOKEN_STRINGCONST) {
-            ast_value *val;
-            if (wantop) {
-                parseerror(parser, "expected operator or end of statement, got constant");
-                goto onerr;
-            }
-            wantop = true;
-            val = parser_const_string(parser, parser_tokval(parser), false);
-            if (!val)
-                return NULL;
-            vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
-            DEBUGSHUNTDO(con_out("push string\n"));
-        }
-        else if (parser->tok == TOKEN_VECTORCONST) {
-            ast_value *val;
-            if (wantop) {
-                parseerror(parser, "expected operator or end of statement, got constant");
-                goto onerr;
-            }
-            wantop = true;
-            val = parser_const_vector(parser, parser_token(parser)->constval.v);
-            if (!val)
-                return NULL;
-            vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
-            DEBUGSHUNTDO(con_out("push '%g %g %g'\n",
-                                parser_token(parser)->constval.v.x,
-                                parser_token(parser)->constval.v.y,
-                                parser_token(parser)->constval.v.z));
-        }
-        else if (parser->tok == '(') {
-            parseerror(parser, "internal error: '(' should be classified as operator");
-            goto onerr;
         }
-        else if (parser->tok == '[') {
-            parseerror(parser, "internal error: '[' should be classified as operator");
-            goto onerr;
-        }
-        else if (parser->tok == ')') {
-            if (wantop) {
-                DEBUGSHUNTDO(con_out("do[op] )\n"));
-                --parens;
-                if (parens < 0)
-                    break;
-                /* we do expect an operator next */
-                /* closing an opening paren */
-                if (!parser_close_paren(parser, &sy, false))
-                    goto onerr;
-                if (vec_last(parser->pot) != POT_PAREN) {
-                    parseerror(parser, "mismatched parentheses (closing paren during ternary expression?)");
-                    goto onerr;
-                }
-                vec_pop(parser->pot);
-            } else {
-                DEBUGSHUNTDO(con_out("do[nop] )\n"));
-                --parens;
-                if (parens < 0)
-                    break;
-                /* allowed for function calls */
-                if (!parser_close_paren(parser, &sy, true))
-                    goto onerr;
-                if (vec_last(parser->pot) != POT_PAREN) {
-                    parseerror(parser, "mismatched parentheses (closing paren during ternary expression?)");
-                    goto onerr;
-                }
-                vec_pop(parser->pot);
+        else
+        {
+            if (ast_istype(var, ast_value)) {
+                ((ast_value*)var)->uses++;
             }
-            wantop = true;
-        }
-        else if (parser->tok == ']') {
-            if (!wantop)
-                parseerror(parser, "operand expected");
-            --parens;
-            if (parens < 0)
-                break;
-            if (!parser_close_paren(parser, &sy, false))
-                goto onerr;
-            if (vec_last(parser->pot) != POT_PAREN) {
-                parseerror(parser, "mismatched parentheses (closing paren during ternary expression?)");
-                goto onerr;
+            else if (ast_istype(var, ast_member)) {
+                ast_member *mem = (ast_member*)var;
+                if (ast_istype(mem->owner, ast_value))
+                    ((ast_value*)(mem->owner))->uses++;
             }
-            vec_pop(parser->pot);
-            wantop = true;
         }
-        else if (parser->tok == TOKEN_TYPENAME) {
+        vec_push(sy->out, syexp(parser_ctx(parser), var));
+        return true;
+    }
+    parseerror(parser, "unexpected token `%s`", parser_tokval(parser));
+    return false;
+}
+
+static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels)
+{
+    ast_expression *expr = NULL;
+    shunt sy;
+    size_t i;
+    bool wantop = false;
+    /* only warn once about an assignment in a truth value because the current code
+     * would trigger twice on: if(a = b && ...), once for the if-truth-value, once for the && part
+     */
+    bool warn_truthvalue = true;
+
+    /* count the parens because an if starts with one, so the
+     * end of a condition is an unmatched closing paren
+     */
+    int ternaries = 0;
+
+    memset(&sy, 0, sizeof(sy));
+
+    parser->lex->flags.noops = false;
+
+    parser_reclassify_token(parser);
+
+    while (true)
+    {
+        if (parser->tok == TOKEN_TYPENAME) {
             parseerror(parser, "unexpected typename");
             goto onerr;
         }
-        else if (parser->tok != TOKEN_OPERATOR) {
-            if (wantop) {
-                parseerror(parser, "expected operator or end of statement");
-                goto onerr;
-            }
-            break;
-        }
-        else
+
+        if (parser->tok == TOKEN_OPERATOR)
         {
             /* classify the operator */
             const oper_info *op;
@@ -2002,7 +1901,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             op = &operators[o];
 
             /* when declaring variables, a comma starts a new variable */
-            if (op->id == opid1(',') && !parens && stopatcomma) {
+            if (op->id == opid1(',') && !vec_size(sy.paren) && stopatcomma) {
                 /* fixup the token */
                 parser->tok = ',';
                 break;
@@ -2015,12 +1914,12 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             }
 
             if (op->id == opid1(',')) {
-                if (vec_size(parser->pot) && vec_last(parser->pot) == POT_TERNARY2) {
+                if (vec_size(sy.paren) && vec_last(sy.paren) == PAREN_TERNARY2) {
                     (void)!parsewarning(parser, WARN_TERNARY_PRECEDENCE, "suggesting parenthesis around ternary expression");
                 }
             }
 
-            if (vec_size(sy.ops) && !vec_last(sy.ops).paren)
+            if (vec_size(sy.ops) && !vec_last(sy.ops).isparen)
                 olast = &operators[vec_last(sy.ops).etype-1];
 
 #define IsAssignOp(x) (\
@@ -2037,7 +1936,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             if (warn_truthvalue) {
                 if ( (olast && IsAssignOp(olast->id) && (op->id == opid2('&','&') || op->id == opid2('|','|'))) ||
                      (olast && IsAssignOp(op->id) && (olast->id == opid2('&','&') || olast->id == opid2('|','|'))) ||
-                     (truthvalue && !vec_size(parser->pot) && IsAssignOp(op->id))
+                     (truthvalue && !vec_size(sy.paren) && IsAssignOp(op->id))
                    )
                 {
                     (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around assignment used as truth value");
@@ -2051,7 +1950,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             {
                 if (!parser_sy_apply_operator(parser, &sy))
                     goto onerr;
-                if (vec_size(sy.ops) && !vec_last(sy.ops).paren)
+                if (vec_size(sy.ops) && !vec_last(sy.ops).isparen)
                     olast = &operators[vec_last(sy.ops).etype-1];
                 else
                     olast = NULL;
@@ -2060,14 +1959,13 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             if (op->id == opid1('(')) {
                 if (wantop) {
                     size_t sycount = vec_size(sy.out);
-                    DEBUGSHUNTDO(con_out("push [op] (\n"));
-                    ++parens; vec_push(parser->pot, POT_PAREN);
                     /* we expected an operator, this is the function-call operator */
-                    vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_FUNC, sycount-1));
+                    vec_push(sy.paren, PAREN_FUNC);
+                    vec_push(sy.ops, syparen(parser_ctx(parser), sycount-1));
+                    vec_push(sy.argc, 0);
                 } else {
-                    ++parens; vec_push(parser->pot, POT_PAREN);
-                    vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_EXPR, 0));
-                    DEBUGSHUNTDO(con_out("push [nop] (\n"));
+                    vec_push(sy.paren, PAREN_EXPR);
+                    vec_push(sy.ops, syparen(parser_ctx(parser), 0));
                 }
                 wantop = false;
             } else if (op->id == opid1('[')) {
@@ -2075,42 +1973,104 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
                     parseerror(parser, "unexpected array subscript");
                     goto onerr;
                 }
-                ++parens; vec_push(parser->pot, POT_PAREN);
+                vec_push(sy.paren, PAREN_INDEX);
                 /* push both the operator and the paren, this makes life easier */
                 vec_push(sy.ops, syop(parser_ctx(parser), op));
-                vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_INDEX, 0));
+                vec_push(sy.ops, syparen(parser_ctx(parser), 0));
                 wantop = false;
             } else if (op->id == opid2('?',':')) {
                 vec_push(sy.ops, syop(parser_ctx(parser), op));
-                vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_TERNARY, 0));
+                vec_push(sy.ops, syparen(parser_ctx(parser), 0));
                 wantop = false;
                 ++ternaries;
-                vec_push(parser->pot, POT_TERNARY1);
+                vec_push(sy.paren, PAREN_TERNARY1);
             } else if (op->id == opid2(':','?')) {
-                if (!vec_size(parser->pot)) {
+                if (!vec_size(sy.paren)) {
                     parseerror(parser, "unexpected colon outside ternary expression (missing parenthesis?)");
                     goto onerr;
                 }
-                if (vec_last(parser->pot) != POT_TERNARY1) {
+                if (vec_last(sy.paren) != PAREN_TERNARY1) {
                     parseerror(parser, "unexpected colon outside ternary expression (missing parenthesis?)");
                     goto onerr;
                 }
-                if (!parser_close_paren(parser, &sy, false))
+                if (!parser_close_paren(parser, &sy))
                     goto onerr;
                 vec_push(sy.ops, syop(parser_ctx(parser), op));
                 wantop = false;
                 --ternaries;
             } else {
-                DEBUGSHUNTDO(con_out("push operator %s\n", op->op));
                 vec_push(sy.ops, syop(parser_ctx(parser), op));
                 wantop = !!(op->flags & OP_SUFFIX);
             }
         }
+        else if (parser->tok == ')') {
+            while (vec_size(sy.paren) && vec_last(sy.paren) == PAREN_TERNARY2) {
+                if (!parser_sy_apply_operator(parser, &sy))
+                    goto onerr;
+            }
+            if (!vec_size(sy.paren))
+                break;
+            if (wantop) {
+                if (vec_last(sy.paren) == PAREN_TERNARY1) {
+                    parseerror(parser, "mismatched parentheses (closing paren in ternary expression?)");
+                    goto onerr;
+                }
+                if (!parser_close_paren(parser, &sy))
+                    goto onerr;
+            } else {
+                /* must be a function call without parameters */
+                if (vec_last(sy.paren) != PAREN_FUNC) {
+                    parseerror(parser, "closing paren in invalid position");
+                    goto onerr;
+                }
+                if (!parser_close_paren(parser, &sy))
+                    goto onerr;
+            }
+            wantop = true;
+        }
+        else if (parser->tok == '(') {
+            parseerror(parser, "internal error: '(' should be classified as operator");
+            goto onerr;
+        }
+        else if (parser->tok == '[') {
+            parseerror(parser, "internal error: '[' should be classified as operator");
+            goto onerr;
+        }
+        else if (parser->tok == ']') {
+            while (vec_size(sy.paren) && vec_last(sy.paren) == PAREN_TERNARY2) {
+                if (!parser_sy_apply_operator(parser, &sy))
+                    goto onerr;
+            }
+            if (!vec_size(sy.paren))
+                break;
+            if (vec_last(sy.paren) != PAREN_INDEX) {
+                parseerror(parser, "mismatched parentheses, unexpected ']'");
+                goto onerr;
+            }
+            if (!parser_close_paren(parser, &sy))
+                goto onerr;
+            wantop = true;
+        }
+        else if (!wantop) {
+            if (!parse_sya_operand(parser, &sy, with_labels))
+                goto onerr;
+#if 0
+            if (vec_size(sy.paren) && vec_last(sy.ops).isparen && vec_last(sy.paren) == PAREN_FUNC)
+                vec_last(sy.argc)++;
+#endif
+            wantop = true;
+        }
+        else {
+            parseerror(parser, "expected operator or end of statement");
+            goto onerr;
+        }
+
         if (!parser_next(parser)) {
             goto onerr;
         }
         if (parser->tok == ';' ||
-            (!parens && (parser->tok == ']' || parser->tok == ')' || parser->tok == '}')))
+            ((!vec_size(sy.paren) || (vec_size(sy.paren) == 1 && vec_last(sy.paren) == PAREN_TERNARY2)) &&
+            (parser->tok == ']' || parser->tok == ')' || parser->tok == '}')))
         {
             break;
         }
@@ -2129,12 +2089,12 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
         expr = sy.out[0].out;
     vec_free(sy.out);
     vec_free(sy.ops);
-    DEBUGSHUNTDO(con_out("shunt done\n"));
-    if (vec_size(parser->pot)) {
-        parseerror(parser, "internal error: vec_size(parser->pot) = %lu", (unsigned long)vec_size(parser->pot));
+    if (vec_size(sy.paren)) {
+        parseerror(parser, "internal error: vec_size(sy.paren) = %lu", (unsigned long)vec_size(sy.paren));
         return NULL;
     }
-    vec_free(parser->pot);
+    vec_free(sy.paren);
+    vec_free(sy.argc);
     return expr;
 
 onerr:
@@ -2145,6 +2105,8 @@ onerr:
     }
     vec_free(sy.out);
     vec_free(sy.ops);
+    vec_free(sy.paren);
+    vec_free(sy.argc);
     return NULL;
 }
 
@@ -2256,6 +2218,12 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond,
     ast_unary *unary;
     ast_expression *prev;
 
+    if (cond->expression.vtype == TYPE_VOID || cond->expression.vtype >= TYPE_VARIANT) {
+        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)
     {
         prev = cond;
@@ -2690,7 +2658,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou
 
     if (typevar || parser->tok == TOKEN_TYPENAME) {
 #if 0
-        if (opts.standard != COMPILER_GMQCC) {
+        if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_GMQCC) {
             if (parsewarning(parser, WARN_EXTENSIONS,
                              "current standard does not allow variable declarations in for-loop initializers"))
                 goto onerr;
@@ -2735,11 +2703,12 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou
 
     /* parse the incrementor */
     if (parser->tok != ')') {
+        lex_ctx condctx = parser_ctx(parser);
         increment = parse_expression_leave(parser, false, false, false);
         if (!increment)
             goto onerr;
         if (!ast_side_effects(increment)) {
-            if (genwarning(ast_ctx(increment), WARN_EFFECTLESS_STATEMENT, "statement has no effect"))
+            if (compile_warning(condctx, WARN_EFFECTLESS_STATEMENT, "statement has no effect"))
                 goto onerr;
         }
     }
@@ -3419,7 +3388,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
             parseerror(parser, "cannot declare a variable from here");
             return false;
         }
-        if (opts.standard == COMPILER_QCC) {
+        if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
             if (parsewarning(parser, WARN_EXTENSIONS, "missing 'local' keyword when declaring a local variable"))
                 return false;
         }
@@ -3486,7 +3455,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
         }
         else if (!strcmp(parser_tokval(parser), "for"))
         {
-            if (opts.standard == COMPILER_QCC) {
+            if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
                 if (parsewarning(parser, WARN_EXTENSIONS, "for loops are not recognized in the original Quake C standard, to enable try an alternate standard --std=?"))
                     return false;
             }
@@ -3585,12 +3554,13 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
     }
     else
     {
+        lex_ctx ctx = parser_ctx(parser);
         ast_expression *exp = parse_expression(parser, false, false);
         if (!exp)
             return false;
         *out = exp;
         if (!ast_side_effects(exp)) {
-            if (genwarning(ast_ctx(exp), WARN_EFFECTLESS_STATEMENT, "statement has no effect"))
+            if (compile_warning(ctx, WARN_EFFECTLESS_STATEMENT, "statement has no effect"))
                 return false;
         }
         return true;
@@ -4065,6 +4035,8 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
             goto enderrfn;
         }
         func->varargs = varargs;
+
+        func->fixedparams = parser_const_float(parser, vec_size(var->expression.params));
     }
 
     parser->function = func;
@@ -4085,7 +4057,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
 
     if (parser->tok == ';')
         return parser_next(parser);
-    else if (opts.standard == COMPILER_QCC)
+    else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC)
         parseerror(parser, "missing semicolon after function body (mandatory with -std=qcc)");
     return retval;
 
@@ -4601,7 +4573,7 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
         vec_free(params);
 
     /* sanity check */
-    if (vec_size(params) > 8 && opts.standard == COMPILER_QCC)
+    if (vec_size(params) > 8 && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC)
         (void)!parsewarning(parser, WARN_EXTENSIONS, "more than 8 parameters are not supported by this standard");
 
     /* parse-out */
@@ -4815,7 +4787,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
     }
 
     /* now there may be function parens again */
-    if (parser->tok == '(' && opts.standard == COMPILER_QCC)
+    if (parser->tok == '(' && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC)
         parseerror(parser, "C-style function syntax is not allowed in -std=qcc");
     if (parser->tok == '(' && wasarray)
         parseerror(parser, "arrays as part of a return type is not supported");
@@ -4954,7 +4926,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
 
         /* Part 0: finish the type */
         if (parser->tok == '(') {
-            if (opts.standard == COMPILER_QCC)
+            if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC)
                 parseerror(parser, "C-style function syntax is not allowed in -std=qcc");
             var = parse_parameter_list(parser, var);
             if (!var) {
@@ -4977,7 +4949,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
         }
         /* for functions returning functions */
         while (parser->tok == '(') {
-            if (opts.standard == COMPILER_QCC)
+            if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC)
                 parseerror(parser, "C-style function syntax is not allowed in -std=qcc");
             var = parse_parameter_list(parser, var);
             if (!var) {
@@ -5047,7 +5019,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                     goto cleanup;
                     */
                 }
-                if ((opts.standard == COMPILER_QCC || opts.standard == COMPILER_FTEQCC) &&
+                if ((OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC || OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC) &&
                     (old = parser_find_global(parser, var->name)))
                 {
                     parseerror(parser, "cannot declare a field and a global of the same name with -std=qcc");
@@ -5119,7 +5091,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                         ast_delete(var);
                         var = proto;
                     }
-                    if (opts.standard == COMPILER_QCC &&
+                    if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC &&
                         (old = parser_find_field(parser, var->name)))
                     {
                         parseerror(parser, "cannot declare a field and a global of the same name with -std=qcc");
@@ -5150,7 +5122,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                     retval = false;
                     goto cleanup;
                 }
-                if (opts.standard != COMPILER_GMQCC) {
+                if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_GMQCC) {
                     ast_delete(var);
                     var = NULL;
                     goto skipvar;
@@ -5330,7 +5302,7 @@ skipvar:
             break;
         }
 
-        if (localblock && opts.standard == COMPILER_QCC) {
+        if (localblock && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
             if (parsewarning(parser, WARN_LOCAL_CONSTANTS,
                              "initializing expression turns variable `%s` into a constant in this standard",
                              var->name) )
@@ -5350,7 +5322,7 @@ skipvar:
                 break;
             }
         }
-        else if (opts.standard == COMPILER_QCC) {
+        else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
             parseerror(parser, "expected '=' before function body in this standard");
         }
 
@@ -5461,7 +5433,7 @@ skipvar:
                 }
             } else {
                 int cvq;
-                shunt sy = { NULL, NULL };
+                shunt sy = { NULL, NULL, NULL, NULL };
                 cvq = var->cvq;
                 var->cvq = CV_NONE;
                 vec_push(sy.out, syexp(ast_ctx(var), (ast_expression*)var));
@@ -5582,7 +5554,7 @@ static bool parser_global_statement(parser_t *parser)
     }
     else
     {
-        parseerror(parser, "unexpected token: %s", parser->lex->tok.value);
+        parseerror(parser, "unexpected token: `%s`", parser->lex->tok.value);
         return false;
     }
     return true;
@@ -5711,7 +5683,7 @@ bool parser_init()
     parser->const_vec[1] = ast_value_new(empty_ctx, "<vector.y>", TYPE_NOEXPR);
     parser->const_vec[2] = ast_value_new(empty_ctx, "<vector.z>", TYPE_NOEXPR);
 
-    if (opts.add_info) {
+    if (OPTS_OPTION_BOOL(OPTION_ADD_INFO)) {
         parser->reserved_version = ast_value_new(empty_ctx, "reserved:version", TYPE_STRING);
         parser->reserved_version->cvq = CV_CONST;
         parser->reserved_version->hasvalue = true;
@@ -5896,8 +5868,8 @@ bool parser_finish(const char *output)
             continue;
         asvalue = (ast_value*)(parser->globals[i]);
         if (!asvalue->uses && !asvalue->hasvalue && asvalue->expression.vtype != TYPE_FUNCTION) {
-            retval = retval && !genwarning(ast_ctx(asvalue), WARN_UNUSED_VARIABLE,
-                                           "unused global: `%s`", asvalue->name);
+            retval = retval && !compile_warning(ast_ctx(asvalue), WARN_UNUSED_VARIABLE,
+                                                "unused global: `%s`", asvalue->name);
         }
         if (!ast_global_codegen(asvalue, ir, false)) {
             con_out("failed to generate global %s\n", asvalue->name);
@@ -6000,7 +5972,7 @@ bool parser_finish(const char *output)
             return false;
         }
     }
-    if (opts.dump)
+    if (OPTS_OPTION_BOOL(OPTION_DUMP))
         ir_builder_dump(ir, con_out);
     for (i = 0; i < vec_size(parser->functions); ++i) {
         if (!ir_function_finalize(parser->functions[i]->ir_func)) {
@@ -6017,7 +5989,7 @@ bool parser_finish(const char *output)
     }
 
     if (retval) {
-        if (opts.dumpfin)
+        if (OPTS_OPTION_BOOL(OPTION_DUMPFIN))
             ir_builder_dump(ir, con_out);
 
         generate_checksum(parser);
diff --git a/test.c b/test.c
index 8c8a80ec68600a432480d11711418f42f77550f2..5e99df404063de4b7d638cd3e6217107414f5f36 100644 (file)
--- a/test.c
+++ b/test.c
@@ -294,14 +294,6 @@ int task_pclose(FILE **handles) {
  *          Used to set a description of the current test, this must be
  *          provided, this tag is NOT optional.
  *
- *      F:
- *          Used to set a failure message, this message will be displayed
- *          if the test fails, this tag is optional
- *
- *      S:
- *          Used to set a success message, this message will be displayed
- *          if the test succeeds, this tag is optional.
- *
  *      T:
  *          Used to set the procedure for the given task, there are two
  *          options for this:
@@ -319,6 +311,9 @@ int task_pclose(FILE **handles) {
  *          Used to set the compilation flags for the given task, this
  *          must be provided, this tag is NOT optional.
  *
+ *      F:  Used to set some test suite flags, currently the only option
+ *          is -no-defs (to including of defs.qh)
+ *
  *      E:
  *          Used to set the execution flags for the given task. This tag
  *          must be provided if T == -execute, otherwise it's erroneous
@@ -351,21 +346,22 @@ int task_pclose(FILE **handles) {
  */
 typedef struct {
     char  *description;
-    char  *failuremessage;
-    char  *successmessage;
     char  *compileflags;
     char  *executeflags;
     char  *proceduretype;
     char  *sourcefile;
     char  *tempfilename;
     char **comparematch;
+    char  *rulesfile;
+    char  *testflags;
 } task_template_t;
 
 /*
  * This is very much like a compiler code generator :-).  This generates
  * a value from some data observed from the compiler.
  */
-bool task_template_generate(task_template_t *template, char tag, const char *file, size_t line, const char *value) {
+bool task_template_generate(task_template_t *template, char tag, const char *file, size_t line, const char *value, size_t *pad) {
+    size_t desclen = 0;
     char **destval = NULL;
 
     if (!template)
@@ -373,12 +369,11 @@ bool task_template_generate(task_template_t *template, char tag, const char *fil
 
     switch(tag) {
         case 'D': destval = &template->description;    break;
-        case 'F': destval = &template->failuremessage; break;
-        case 'S': destval = &template->successmessage; break;
         case 'T': destval = &template->proceduretype;  break;
         case 'C': destval = &template->compileflags;   break;
         case 'E': destval = &template->executeflags;   break;
         case 'I': destval = &template->sourcefile;     break;
+        case 'F': destval = &template->testflags;      break;
         default:
             con_printmsg(LVL_ERROR, __FILE__, __LINE__, "internal error",
                 "invalid tag `%c:` during code generation\n",
@@ -421,10 +416,20 @@ bool task_template_generate(task_template_t *template, char tag, const char *fil
      */
     *destval = util_strdup(value);
 
+
+    if (*destval == template->description) {
+        /*
+         * Create some padding for the description to align the
+         * printing of the rules file.
+         */  
+        if ((desclen = strlen(template->description)) > pad[0])
+            pad[0] = desclen;
+    }
+
     return true;
 }
 
-bool task_template_parse(const char *file, task_template_t *template, FILE *fp) {
+bool task_template_parse(const char *file, task_template_t *template, FILE *fp, size_t *pad) {
     char  *data = NULL;
     char  *back = NULL;
     size_t size = 0;
@@ -471,12 +476,11 @@ bool task_template_parse(const char *file, task_template_t *template, FILE *fp)
              * it to.
              */
             case 'D':
-            case 'F':
-            case 'S':
             case 'T':
             case 'C':
             case 'E':
             case 'I':
+            case 'F':
                 if (data[1] != ':') {
                     con_printmsg(LVL_ERROR, file, line, "template parse error",
                         "expected `:` after `%c`",
@@ -484,7 +488,7 @@ bool task_template_parse(const char *file, task_template_t *template, FILE *fp)
                     );
                     goto failure;
                 }
-                if (!task_template_generate(template, *data, file, line, &data[3])) {
+                if (!task_template_generate(template, *data, file, line, &data[3], pad)) {
                     con_printmsg(LVL_ERROR, file, line, "template compile error",
                         "failed to generate for given task\n"
                     );
@@ -556,29 +560,39 @@ void task_template_nullify(task_template_t *template) {
         return;
 
     template->description    = NULL;
-    template->failuremessage = NULL;
-    template->successmessage = NULL;
     template->proceduretype  = NULL;
     template->compileflags   = NULL;
     template->executeflags   = NULL;
     template->comparematch   = NULL;
     template->sourcefile     = NULL;
     template->tempfilename   = NULL;
+    template->rulesfile      = NULL;
+    template->testflags      = NULL;
 }
 
-task_template_t *task_template_compile(const char *file, const char *dir) {
+task_template_t *task_template_compile(const char *file, const char *dir, size_t *pad) {
     /* a page should be enough */
     char             fullfile[4096];
+    size_t           filepadd = 0;
     FILE            *tempfile = NULL;
     task_template_t *template = NULL;
 
     memset  (fullfile, 0, sizeof(fullfile));
     snprintf(fullfile,    sizeof(fullfile), "%s/%s", dir, file);
 
-    tempfile = file_open(fullfile, "r");
-    template = mem_a(sizeof(task_template_t));
+    tempfile            = file_open(fullfile, "r");
+    template            = mem_a(sizeof(task_template_t));
     task_template_nullify(template);
 
+    /*
+     * Create some padding for the printing to align the
+     * printing of the rules file to the console.
+     */  
+    if ((filepadd = strlen(fullfile)) > pad[1])
+        pad[1] = filepadd;
+
+    template->rulesfile = util_strdup(fullfile);
+
     /*
      * Esnure the file even exists for the task, this is pretty useless
      * to even do.
@@ -590,7 +604,7 @@ task_template_t *task_template_compile(const char *file, const char *dir) {
         goto failure;
     }
 
-    if (!task_template_parse(file, template, tempfile)) {
+    if (!task_template_parse(file, template, tempfile, pad)) {
         con_err("template parse error: error during parsing\n");
         goto failure;
     }
@@ -670,12 +684,12 @@ void task_template_destroy(task_template_t **template) {
         return;
 
     if ((*template)->description)    mem_d((*template)->description);
-    if ((*template)->failuremessage) mem_d((*template)->failuremessage);
-    if ((*template)->successmessage) mem_d((*template)->successmessage);
     if ((*template)->proceduretype)  mem_d((*template)->proceduretype);
     if ((*template)->compileflags)   mem_d((*template)->compileflags);
     if ((*template)->executeflags)   mem_d((*template)->executeflags);
     if ((*template)->sourcefile)     mem_d((*template)->sourcefile);
+    if ((*template)->rulesfile)      mem_d((*template)->rulesfile);
+    if ((*template)->testflags)      mem_d((*template)->testflags);
 
     /*
      * Delete all allocated string for task template then destroy the
@@ -716,7 +730,7 @@ task_t *task_tasks = NULL;
  * Read a directory and searches for all template files in it
  * which is later used to run all tests.
  */
-bool task_propagate(const char *curdir) {
+bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
     bool             success = true;
     DIR             *dir;
     struct dirent   *files;
@@ -744,7 +758,7 @@ bool task_propagate(const char *curdir) {
          * actually a directory, so it must be a file :)
          */
         if (strcmp(files->d_name + strlen(files->d_name) - 5, ".tmpl") == 0) {
-            task_template_t *template = task_template_compile(files->d_name, curdir);
+            task_template_t *template = task_template_compile(files->d_name, curdir, pad);
             char             buf[4096]; /* one page should be enough */
             char            *qcflags = NULL;
             task_t           task;
@@ -776,22 +790,47 @@ bool task_propagate(const char *curdir) {
              */
             memset (buf,0,sizeof(buf));
             if (qcflags) {
-                snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s",
-                    task_bins[TASK_COMPILE],
-                    curdir,
-                    template->sourcefile,
-                    qcflags,
-                    template->compileflags,
-                    template->tempfilename
-                );
+                if (template->testflags && !strcmp(template->testflags, "-no-defs")) {
+                    snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s",
+                        task_bins[TASK_COMPILE],
+                        curdir,
+                        template->sourcefile,
+                        qcflags,
+                        template->compileflags,
+                        template->tempfilename
+                    );
+                } else {
+                    snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s %s -o %s",
+                        task_bins[TASK_COMPILE],
+                        curdir,
+                        defs,
+                        curdir,
+                        template->sourcefile,
+                        qcflags,
+                        template->compileflags,
+                        template->tempfilename
+                    );
+                }
             } else {
-                snprintf(buf, sizeof(buf), "%s %s/%s %s -o %s",
-                    task_bins[TASK_COMPILE],
-                    curdir,
-                    template->sourcefile,
-                    template->compileflags,
-                    template->tempfilename
-                );
+                if (template->testflags && !strcmp(template->testflags, "-no-defs")) {
+                    snprintf(buf, sizeof(buf), "%s %s/%s %s -o %s",
+                        task_bins[TASK_COMPILE],
+                        curdir,
+                        template->sourcefile,
+                        template->compileflags,
+                        template->tempfilename
+                    );
+                } else {
+                    snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s -o %s",
+                        task_bins[TASK_COMPILE],
+                        curdir,
+                        defs,
+                        curdir,
+                        template->sourcefile,
+                        template->compileflags,
+                        template->tempfilename
+                    );
+                }
             }
 
             /*
@@ -958,10 +997,9 @@ bool task_execute(task_template_t *template, char ***line) {
         size_t compare = 0;
         while (file_getline(&data, &size, execute) != EOF) {
             if (!strcmp(data, "No main function found\n")) {
-                con_err("test failure: `%s` [%s] (No main function found)\n",
+                con_err("test failure: `%s` (No main function found) [%s]\n",
                     template->description,
-                    (template->failuremessage) ?
-                    template->failuremessage : "unknown"
+                    template->rulesfile
                 );
                 pclose(execute);
                 return false;
@@ -1004,7 +1042,7 @@ bool task_execute(task_template_t *template, char ***line) {
  * execution this takes more work since a task needs to be generated
  * from thin air and executed INLINE.
  */
-void task_schedualize() {
+void task_schedualize(size_t *pad) {
     bool   execute  = false;
     char  *data     = NULL;
     char **match    = NULL;
@@ -1061,21 +1099,22 @@ void task_schedualize() {
         }
 
         if (!task_tasks[i].compiled && strcmp(task_tasks[i].template->proceduretype, "-fail")) {
-            con_err("test failure: `%s` [%s] (failed to compile) see %s.stdout and %s.stderr\n",
+            con_err("test failure: `%s` (failed to compile) see %s.stdout and %s.stderr [%s]\n",
                 task_tasks[i].template->description,
-                (task_tasks[i].template->failuremessage) ?
-                task_tasks[i].template->failuremessage : "unknown",
                 task_tasks[i].template->tempfilename,
-                task_tasks[i].template->tempfilename
+                task_tasks[i].template->tempfilename,
+                task_tasks[i].template->rulesfile
             );
             continue;
         }
 
         if (!execute) {
-            con_out("test succeeded: `%s` [%s]\n",
-                 task_tasks[i].template->description,
-                (task_tasks[i].template->successmessage) ?
-                 task_tasks[i].template->successmessage  : "unknown"
+            con_out("test succeeded: `%s` %*s\n",
+                task_tasks[i].template->description,
+                (pad[0] + pad[1] - strlen(task_tasks[i].template->description)) +
+                (strlen(task_tasks[i].template->rulesfile) - pad[1]),
+                task_tasks[i].template->rulesfile
+                
             );
             continue;
         }
@@ -1087,10 +1126,9 @@ void task_schedualize() {
         if (!task_execute(task_tasks[i].template, &match)) {
             size_t d = 0;
 
-            con_err("test failure: `%s` [%s] (invalid results from execution)\n",
-                 task_tasks[i].template->description,
-                (task_tasks[i].template->failuremessage) ?
-                 task_tasks[i].template->failuremessage : "unknown"
+            con_err("test failure: `%s` (invalid results from execution) [%s]\n",
+                task_tasks[i].template->description,
+                task_tasks[i].template->rulesfile
             );
 
             /*
@@ -1135,10 +1173,12 @@ void task_schedualize() {
             mem_d(match[j]);
         vec_free(match);
 
-        con_out("test succeeded: `%s` [%s]\n",
-             task_tasks[i].template->description,
-            (task_tasks[i].template->successmessage) ?
-             task_tasks[i].template->successmessage  : "unknown"
+        con_out("test succeeded: `%s` %*s\n",
+            task_tasks[i].template->description,
+            (pad[0] + pad[1] - strlen(task_tasks[i].template->description)) +
+            (strlen(task_tasks[i].template->rulesfile) - pad[1]),
+            task_tasks[i].template->rulesfile
+            
         );
     }
     mem_d(data);
@@ -1158,9 +1198,24 @@ void task_schedualize() {
  *
  * It expects con_init() was called before hand.
  */
-bool test_perform(const char *curdir) {
+GMQCC_WARN bool test_perform(const char *curdir, const char *defs) {
+    static const char *default_defs = "defs.qh";
+
+    size_t pad[] = {
+        0, 0
+    };
+
+    /*
+     * If the default definition file isn't set to anything.  We will
+     * use the default_defs here, which is "defs.qc"
+     */   
+    if (!defs) {
+        defs = default_defs;
+    }
+        
+
     task_precleanup(curdir);
-    if (!task_propagate(curdir)) {
+    if (!task_propagate(curdir, pad, defs)) {
         con_err("error: failed to propagate tasks\n");
         task_destroy();
         return false;
@@ -1172,7 +1227,7 @@ bool test_perform(const char *curdir) {
      * it's designed to prevent lock contention, and possible syncronization
      * issues.
      */
-    task_schedualize();
+    task_schedualize(pad);
     task_destroy();
 
     return true;
@@ -1209,8 +1264,10 @@ static bool parsecmd(const char *optname, int *argc_, char ***argv_, char **out,
 }
 
 int main(int argc, char **argv) {
+    bool          succeed  = false;
     char         *redirout = (char*)stdout;
     char         *redirerr = (char*)stderr;
+    char         *defs     = NULL;
 
     con_init();
 
@@ -1227,15 +1284,17 @@ int main(int argc, char **argv) {
                 continue;
             if (parsecmd("redirerr", &argc, &argv, &redirerr, 1, false))
                 continue;
+            if (parsecmd("defs",     &argc, &argv, &defs,     1, false))
+                continue;
 
             con_change(redirout, redirerr);
 
             if (!strcmp(argv[0]+1, "debug")) {
-                opts.debug = true;
+                OPTS_OPTION_BOOL(OPTION_DEBUG) = true;
                 continue;
             }
             if (!strcmp(argv[0]+1, "memchk")) {
-                opts.memchk = true;
+                OPTS_OPTION_BOOL(OPTION_MEMCHK) = true;
                 continue;
             }
             if (!strcmp(argv[0]+1, "nocolor")) {
@@ -1248,7 +1307,9 @@ int main(int argc, char **argv) {
         }
     }
     con_change(redirout, redirerr);
-    test_perform("tests");
+    succeed = test_perform("tests", defs);
     util_meminfo();
-    return 0;
+
+
+    return (succeed) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
index a3a84c17e9ba8d27c0a6629fbdb8f60b1e4cf955..2c8f9fe533921ca98ce2bb8d2155414f49709aa6 100644 (file)
@@ -1,7 +1,3 @@
-void     print(...)   = #1;
-string   ftos (float) = #2;
-entity() spawn = #3;
-
 float  glob[7];
 
 .float above;
diff --git a/tests/bitnot.qc b/tests/bitnot.qc
new file mode 100644 (file)
index 0000000..c6e875d
--- /dev/null
@@ -0,0 +1,14 @@
+void main() {
+    float a; a = 1;
+    float b; b = 1;
+    float c; c = 1;
+    float d; d = 1;
+
+    a &~= 1; // 0
+    b &= ~1; // 0
+    c &= ~d; // 0
+
+    print("a: ", ftos(a), "\nb: ",
+                 ftos(b), "\nc: ",
+                 ftos(c), "\n");
+}
diff --git a/tests/bitnot.tmpl b/tests/bitnot.tmpl
new file mode 100644 (file)
index 0000000..75ae64a
--- /dev/null
@@ -0,0 +1,9 @@
+# used to test the builtins
+I: bitnot.qc
+D: test bitwise not operators
+T: -execute
+C: -std=gmqcc
+E: $null
+M: a: 0
+M: b: 0
+M: c: 0
index 1a0fed1a98997a6fb29b42d3de5e5aa8186dd737..46f1805bda18c81d595017cb80ba873be62e3b69 100644 (file)
@@ -1,6 +1,3 @@
-void   print(...)   = #1;
-string ftos (float) = #2;
-
 void test(float brkat, float contat) {
     float i;
 
index 6e586443c4bf818555ac8dacc2fc56d5446a2496..06a1846e50a55c44193d1781f955dc70165fea45 100644 (file)
@@ -1,5 +1,3 @@
-void(string) print = #1;
-
 void() main = {
     print("hello world");
 }
index d81cad92e6ebac62195b832c5d19048316484b62..cc14cafdd3ddc596376ebe11570291a2c644896f 100644 (file)
@@ -4,6 +4,4 @@ D: test builtin functions
 T: -execute
 C: -std=gmqcc
 E: $null
-F: builtins failed
-S: builtins worked
 M: hello world
index e230dc46adfaffe7fede589f9393c169deae7a38..7b09f11e0737abcc288403d8e530f3e909f63243 100644 (file)
@@ -1,6 +1,3 @@
-void(string, ...) print = #1;
-string(float) ftos = #2;
-
 float(float x, float y, float z) sum = {
     return x + y + z;
 };
index 3c551af2e506e7575532149272fc6aa020c85378..c159aa2ab38cd88bcbca11a9b2d0b0ca976678b2 100644 (file)
@@ -3,6 +3,4 @@ D: test calls
 T: -execute
 C: -std=gmqcc
 E: -float 100 -float 200 -float 300
-F: calls failed
-S: calls worked
 M: 4600
index cb9a38d0219067f15f18dc386b32136c813de24b..a8684247ed6cfb315938e6cf3220f8d358194815 100644 (file)
@@ -1,6 +1,3 @@
-void   print(...)   = #1;
-string ftos (float) = #2;
-
 float test_s_not  (vector s)           { return !s; }
 float test_s_and  (vector s, vector t) { return s && t; }
 float test_s_or   (vector s, vector t) { return s || t; }
index 81f9b7aa35d6e131a49936166a3b871baac55b22..e7cd2dcc73528cf7b5811bd32799f26279b57edd 100644 (file)
@@ -1,6 +1,3 @@
-void   print(...)   = #1;
-string ftos (float) = #2;
-
 void test(vector a, vector b) {
     print(ftos((a && b) + (a && b)), " ");
     print(ftos((a || b) + (a || b)), " ");
diff --git a/tests/defs.qh b/tests/defs.qh
new file mode 100644 (file)
index 0000000..830692c
--- /dev/null
@@ -0,0 +1,18 @@
+// builtins for the standalone qcvm included with gmqcc
+// in exec.c  These should be updated to reflect the new
+// builtins.  I no event shall you even consider adding
+// these individually per test.
+
+void   (string, ...)    print     = #1;
+string (float)          ftos      = #2;
+entity ()               spawn     = #3;
+void   (entity)         kill      = #4;
+string (vector)         vtos      = #5;
+void   (string)         error     = #6;
+float  (vector)         vlen      = #7;
+string (entity)         etos      = #8;
+float  (string)         stof      = #9;
+string (...)            strcat    = #10;
+float  (string, string) strcmp    = #11;
+vector (vector)         normalize = #12;
+float  (float)          sqrt      = #13;
index 521863357694f66e77f3edcdb06576b1353b786b..da08ceee128aa2a0da962a5f9c1f852ed89b51a5 100644 (file)
@@ -27,8 +27,6 @@ enum {
     N
 };
 
-void (string, ...) print = #1;
-string (float)  ftos = #2;
 void main() {
     print(ftos(A), "\n");
     print(ftos(B), "\n");
index bc134b0d1b6c93295f85137c8d05bfcd9a572db1..95eccb824f292caa90976e8198cba7c3566e2d22 100644 (file)
@@ -1,6 +1,3 @@
-void(string, ...) print = #1;
-string(float) ftos = #2;
-
 void(float a, float b) main = {
     if (a == b) print("eq,");
     if (a != b) print("ne,");
index 18c3750bb08806576260eb03ca9fe6fd9c496098..536e18fbd60facb49f1eb097fe7c502b721970e1 100644 (file)
@@ -3,6 +3,4 @@ D: test equality
 T: -execute
 C: -std=gmqcc
 E: -float 100 -float 200
-F: equality failed
-S: equality worked
 M: ne,lt,le,
index 8e5cb031772457a30fd9f698ae6740b002b592b2..eed2ed614c0234013d477addd59caa79f1afa6e8 100644 (file)
@@ -1,6 +1,3 @@
-void(string, string) print = #1;
-entity() spawn = #3;
-
 .string a;
 .string b;
 ..string ps;
index 5e1af6eaef94864685fa2af69fd0096863736b0c..e49ee6a8e261e9bcd7a64e36876f911318a67395 100644 (file)
@@ -3,7 +3,5 @@ D: test field paramaters
 T: -execute
 C: -std=qcc
 E: $null
-F: field paramaters fail
-S: field paramaters work
 M: bar
 M: foo
index 7790e64ed0044e4bc6e740206400e1d67ca3f94e..22136b7ab3d6c1d3e37b926c782d55604088309a 100644 (file)
@@ -1,5 +1,3 @@
-void(string, string) print = #1;
-
 string() getter = {
     return "correct";
 };
index 2c4504c91e33c8c969b5f17c5045963786049faa..495e7b8bc0c90e02a2017079b848ad0aa192eb94 100644 (file)
@@ -3,6 +3,4 @@ D: test functions as paramaters
 T: -execute
 C: -std=gmqcc
 E: $null
-F: functions as paramaters failed
-S: functions as paramaters passed
 M: correct
index 7c9f297739f4cd127ba507fdb702d7142aac440e..9e6f30bb2abeedbb491773a77f114a6290e345d1 100644 (file)
@@ -1,5 +1,3 @@
-void(string, ...) print = #1;
-
 // correct execution order:
 // label_3
 // label_2
index 4acf179c469c9bbb01ddfe825f778619a8074ccd..a935bd835469e211c45bdd79e8dc2f24a203d20f 100644 (file)
@@ -2,8 +2,6 @@ I: goto.qc
 D: test goto (both normal and computed)
 T: -execute
 C: -std=gmqcc
-F: goto failed
-S: goto worked
 M: label_3
 M: label_2
 M: label_4
index d3089ce4d24aa51705dc4bc3e9e14a2253f4a1d1..7a7f13cf91ef81683818444211ba4eb1f46c90f8 100644 (file)
@@ -1,5 +1,3 @@
-void(string, ...) print = #1;
-
 void(float c) main = {
     if (c == 1)
         print("One\n");
index 8ba64e372c48b04c1ab300f1f0a94333300e5c27..c587ba5f2a74739e1b33c53ee99d35ba015d309d 100644 (file)
@@ -3,6 +3,4 @@ D: test if statement
 T: -execute
 C: -std=gmqcc
 E: -float 2
-F: if statement failed
-S: if statement passed
 M: Two
index 3e60e2385214c197eb667e97cc7750c54353c019..0e8df52cd0e6c12f659962ac72d15c833562dbe0 100644 (file)
@@ -1,6 +1,3 @@
-void print(...) = #1;
-string vtos(vector) = #5;
-
 // getter to work around future -O
 vector get(vector v) {
     return v;
index 330d625e4803ec295b279ee2b77927ec64d5c50b..6e1a9570f9c239ab99bd851ff4bc2a3c64498ea0 100644 (file)
@@ -1,5 +1,3 @@
-void(...) print = %:1;
-
 void() main = ??<
        print("??=??'??(??)??!??<??>??-??/??/%>|");
        print("#^[]|{}~\\%>\n");
index f0c6f94ff3883c631f2903bcb19129b6e11b504c..d8af70726d93568f38998e8e5206c3efb79f8409 100644 (file)
@@ -3,6 +3,4 @@ D: test digraphs and trigraphs
 T: -execute
 C: -std=gmqcc
 E: $null
-F: digraphs and trigraphs failed
-S: digraphs and trigraphs passed
 M: #^[]|{}~\%>|#^[]|{}~\%>
index e56cc8810059c346211642e1653a6f98332cb389..ae614e77b5f27177728cf088d303baefb20e702c 100644 (file)
@@ -2,8 +2,10 @@
 #define NORETURN [[noreturn]]
 #endif
 
-void          print(...)  = #1;
-string        ftos(float) = #2;
+void   (...)            print     = #1;
+string (float)          ftos      = #2;
+
+
 NORETURN void error(...)  = #6;
 
 #if TEST == 1
index 0f6aad138a292c0c283a489a09367a10b38d3546..f662da4911e569b33f515bb05b5389effbf1ec1f 100644 (file)
@@ -2,3 +2,4 @@ I: noreturn.qc
 D: noreturn keyword - should work
 T: -compile
 C: -std=fteqcc -Wall -Werror -DTEST=1 -DNORETURN=[[noreturn]]
+F: -no-defs
index 8d7ad09c55f572f8c7a1808e80ad227fbfbfbfda..d328c4f65b79df5c808d414bfb3fcf2d6d162461 100644 (file)
@@ -2,3 +2,4 @@ I: noreturn.qc
 D: noreturn keyword - should fail
 T: -compile
 C: -std=fteqcc -Wall -Werror -DTEST=2 -DNORETURN=[[noreturn]]
+F: -no-defs
index 56c28b51754d34d0803d6b29b304acf1f2b1fc61..653bd8afd4e01ffb42671c3e3e6781a49fb36b6f 100644 (file)
@@ -2,3 +2,4 @@ I: noreturn.qc
 D: noreturn keyword - should work
 T: -fail
 C: -std=fteqcc -Wall -Werror -DTEST=1 -DNORETURN
+F: -no-defs
index 18dc275789a3e5b6b05823d48899a88ac14dc7e3..4d87c9417226466c0f5da0aa23caf89545d308b6 100644 (file)
@@ -2,3 +2,4 @@ I: noreturn.qc
 D: noreturn keyword - should fail
 T: -fail
 C: -std=fteqcc -Wall -Werror -DTEST=2 -DNORETURN
+F: -no-defs
index 1ca6f67caa0e5cf56ecf2516b82f487af3ba750d..46bd6bbeb81c2268edb8de30f86f74e18fad9b32 100644 (file)
@@ -1,8 +1,3 @@
-void   print(...)    = #1;
-string ftos (float)  = #2;
-string vtos (vector) = #5;
-entity spawn()       = #3;
-
 .float mem;
 
 void main() {
index 68e96f721982097d4ca8344749605def2a6192ea..bdb868a21db0f3932639a461021b5c89966161d1 100644 (file)
@@ -1,6 +1,3 @@
-void   print(...) = #1;
-string ftos(float) = #2;
-
 void p10(float a, float b, float c, float d, float e, float f, float g, float h,
          float e1, float e2)
 {
index 9a02f65720f8bfdd2e0856d38c8f3b12432ad4c9..26b1fae46e37af7b7bad13c59fee4418d88019cb 100644 (file)
@@ -2,8 +2,6 @@ I: param8.qc
 D: test extended parameters
 T: -execute
 C: -std=fteqcc
-F: extended parameters failed
-S: extended parameters worked
 M: 10 20 30 40 50 60 70 80 90 100
 M: 1 1 1 1 1 1 1 1 1 1
 M: 10 20 30 40 50 60 70 80 90 100
diff --git a/tests/parens.qc b/tests/parens.qc
new file mode 100644 (file)
index 0000000..c4a369a
--- /dev/null
@@ -0,0 +1,41 @@
+float arr[2];
+
+string gets() { return "S\n"; }
+void main(float x) {
+    string s;
+
+    s = gets();                // 0 params
+    print(s);                  // 1 param
+    print("A ", "B\n");        // 2 params
+    print("A ", "B ", "C\n");  // more params
+    print(gets());             // 0-param call in call
+    print(gets(), "next\n");   // 0-param call and another
+    print("-> ", gets());      // param + 0-param call
+    print(ftos(x), "\n");      // param-call + another
+    print(x ? "xA\n" : "xB\n");      // ternary in PAREN_FUNC
+    print(!x ? "xA\n" : "xB\n");      // ternary in PAREN_FUNC
+    // PAREN_INDEX
+    arr[0] = 10;
+    arr[1] = 11;
+    // PAREN_TERNARY + PAREN_INDEX
+    arr[x ? 0 : 1] += 100;
+    print(ftos(arr[0]), "\n");
+    print(ftos(arr[1]), "\n");
+    print(ftos(arr[x ? 0 : 1]), "\n");
+    print(ftos(arr[!x ? 0 : 1]), "\n");
+
+    // loops with comma operators
+    float i, j;
+    for (i = 0, j = 0; i < x; ++i)
+        print("-");
+    print("\n");
+
+    // if + PAREN_TERNARY2
+    if (x ? 1 : 0)
+        print("OK\n");
+    if (x ? 0 : 1)
+        print("NO\n");
+
+    // PAREN_FUNC in PAREN_EXPR
+    print(("Is this wrong ", "now?\n"));
+}
diff --git a/tests/parens.tmpl b/tests/parens.tmpl
new file mode 100644 (file)
index 0000000..504082f
--- /dev/null
@@ -0,0 +1,22 @@
+I: parens.qc
+D: parentheses, SYA stuff
+T: -execute
+C: -std=fteqcc
+E: -float 4
+M: S
+M: A B
+M: A B C
+M: S
+M: S
+M: next
+M: -> S
+M: 4
+M: xA
+M: xB
+M: 110
+M: 11
+M: 110
+M: 11
+M: ----
+M: OK
+M: now?
index 5b56c45e293fca00e9fb6960470181b85602ec5d..5c7f16b64abd498f2c2f926a299ecd21a6f78fd8 100644 (file)
@@ -1,5 +1,3 @@
-void print(...) = #1;
-
 void main() {
     vector va, vb;
     string sa, sb;
index 1ecee8c3a673094771981f6a3f1a3fd95ebd9007..1ec0780ae24443cac920cddd0d190618e93bd1d9 100644 (file)
@@ -28,7 +28,6 @@
 
 #   define ABC ALPHA(a)##ALPHA(b)##ALPHA(c)
 
-    void(string, ...) print = #1;
     void() main = {
         if (ABC == "abc")
             print("ABC\n");
index 3f6849c99eb6f3b42a248cf478041a5e3c7e64fe..da1cb4202c3a67532830fd396aa5a21584cc5b0b 100644 (file)
@@ -2,7 +2,5 @@ I: pmacros.qc
 D: test preprocessor
 T: -execute
 C: -std=fteqcc
-F: preprocessor failed
-S: preprocessor works
 M: ABC
 M: 123
index b37e62abfd5b95560e141637c0a2e77b7a7ddff1..13bbde71eab0b53623504b8a4ab6d1a4fb42ab56 100644 (file)
@@ -1,5 +1,3 @@
-void print(...) = #1;
-
 var float foo = 0;
 
 void funcall() {}
index f73372cd8af784d0f20c1381ed3950457bc6d6ec..a42e1927938e2c1e499d81f64444ff9da92aea01 100644 (file)
@@ -1,9 +1,22 @@
-void print(...) = #1;
+// method 0
+#define METHOD__(...) __VA_ARGS__
+#define METHOD_0(F,A) F METHOD__(A)
 
-#define NOPARENS(...) __VA_ARGS__
-#define callem(func, args) func(NOPARENS args)
+// method 1
+#define METHOD_1(F,A) F(METHOD__ A)
+
+// method 2
+#define METHOD_2(F,...) F __VA_ARGS__##[0]
+
+// method 3
+#define METHOD_3(F,...) F __VA_ARGS__
+
+// selector
+#define METHOD(I, F, ...) METHOD_##I (F, __VA_ARGS__)
 
 void main() {
-    print(NOPARENS("hello ", "world\n"));
-    callem(print, ("Yay", ", there\n"));
+    METHOD(0, print, ("Method", " <zero>\n"));
+    METHOD(1, print, ("Method", " <one>\n"));
+    METHOD(2, print, ("Method", " <two>\n"));
+    METHOD(3, print, ("Method", " <three>\n"));
 }
index cf6ed161e89e40510d3c23cb5076a373f23e24b0..b3f30f6a9867d01891f63fe258f4fe99034c8948 100644 (file)
@@ -2,5 +2,7 @@ I: pp_va_args.qc
 D: __VA_ARGS__
 T: -execute
 C: -std=fteqcc
-M: hello world
-M: Yay, there
+M: Method <zero>
+M: Method <one>
+M: Method <two>
+M: Method <three>
index a62ed79b170ea0c1b0c8487eecd55b18f31c9509..9dd0550d5b7f0959617d735658b4b311515fcd83 100644 (file)
@@ -1,6 +1,3 @@
-void   print(...) = #1;
-string ftos(float) = #2;
-
 float glob1;
 float glob2;
 float glob3;
index 1758c8af759ae002de99da948b970c1f44db8bd5..2e9cf8edd5f7db3e24769e1db90ca16ff1f2f39c 100644 (file)
@@ -1,6 +1,3 @@
-void print(...) = #1;
-string ftos(float) = #2;
-
 void test(float param, float p2) {
     float i;
     float c80 = 80;
index 242a2404d54f3668a0f707f16cf7f71895250dc0..bdac5264191d8ed88442ee98cd278df77d35fb41 100644 (file)
@@ -1,6 +1,3 @@
-void     print(...)   = #1;
-string   ftos (float) = #2;
-
 void test(float cond, float v1, float v2, float a) {
     print(ftos(cond ? v1 : v2), " ");
     print( (cond ? v1 : v2) ? ( (a == 1) ? "a=1"
index 0c10708029cc004a004066ae1539ff9f1ddebf1f..7ac93a58379c3c1f8697319b80bef5e4180b5a0e 100644 (file)
@@ -1,6 +1,3 @@
-void   print(...)   = #1;
-string ftos (float) = #2;
-
 float test_s_not  (string s)           { return !s; }
 float test_s_and  (string s, string t) { return s && t; }
 float test_s_or   (string s, string t) { return s || t; }
index e08bde84cfd0cebbfb32e3b91e34850603a13264..9df6217bbe3569ab155e4c9e0c86ba7c2ecc03cd 100644 (file)
@@ -1,6 +1,3 @@
-void   print(...)   = #1;
-string ftos (float) = #2;
-
 void test(string s) {
     print(ftos(!s));
     if (s)   print(" on");
index 79143fd80bfe54f1767860503cf18c160cb090c8..e9bc13b1b48efbabee4a2de9c3f0a8c3f60079a7 100644 (file)
@@ -1,4 +1,4 @@
-typedef void(string, ...) ptype;
+typedef void(...)     ptype;
 typedef string(float) funcsf;
 
 ptype print = #1;
index 8c22ca4f304c8629fd23dd9e6addbafdfe6e3d01..2eb2253f797f724f45f2d04e063fed2ef316eea1 100644 (file)
@@ -3,3 +3,4 @@ D: typedefs
 T: -execute
 C: -std=fteqcc
 M: A typedeffed function, 0=0
+F: -no-defs
index 3d75f07173c137aae898460149f64c26296ee16e..d71721c32f22844eb000cd5a30103c5027602247 100644 (file)
@@ -1,7 +1,3 @@
-void   print(...)    = #1;
-string ftos (float)  = #2;
-string vtos (vector) = #5;
-
 vector main(float a, vector vin) {
     vector v;
 
index 4ca03483bd1a461857fdce235a9f23ae274df42c..f5a9255f057105135caf8bd38da59c55287d2241 100644 (file)
@@ -1,6 +1,3 @@
-void   print(...)   = #1;
-string ftos (float) = #2;
-
 void main() {
     print("Sum: \{x2211} ");
     print("\{8721} ");
index ffe7d1b6b34b152ffa9b2a12751f6302464a0f70..4b0d80686e079be78b63f3c0a2f95e0768062a83 100644 (file)
@@ -1,6 +1,3 @@
-void(string...)   print  = #1;
-string(float)     ftos   = #2;
-
 void nbva(float a, string...count) {
     print("You gave me ", ftos(count), " additional parameters\n");
     print("First: ", ...(0, string), "\n");
@@ -9,6 +6,15 @@ void nbva(float a, string...count) {
         print("Vararg ", ftos(a), " = ", ...(a, string), "\n");
 }
 
+var void unstable(...);
+void stability(float a, float b, ...count)
+{
+    print("Got: ", ftos(count), "\n");
+}
+
 void main() {
     nbva(1, "Hello", "You", "There");
+    stability(1, 2, 3, 4, 5);
+    unstable = stability;
+    unstable(1, 2, 3, 4, 5);
 }
index d8130a83ba083644d79183d271f7e23518c16aaa..29de939ea8a4ad9ee2f16ac01ae08dbbe02a18f2 100644 (file)
@@ -8,3 +8,5 @@ M: You chose: You
 M: Vararg 0 = Hello
 M: Vararg 1 = You
 M: Vararg 2 = There
+M: Got: 3
+M: Got: 3
index 27d938fc92f650b8562ebaab527ad0608cc59c83..26f301b1df83289a8756c73fdc0d0194a0960c4b 100644 (file)
@@ -1,5 +1,3 @@
-void(...) print = #1;
-
 void() main = {
     print("hello", " world");
 }
index bba49202b01734533aef42b08b52d9388a8c3134..9d1a9458dc0046546a78d272cf1e23b8289b5e81 100644 (file)
@@ -3,6 +3,4 @@ D: test variadic arguments
 T: -execute
 C: -std=gmqcc
 E: $null
-F: variadic arguments failed
-S: variadic arguments worked
 M: hello world
index a5c80c9ac8b1c0c7ff55c8abd2f416cac7ce5adf..ac84ffcc7768b1cd9b794ea96b9fce55cf6c0ec2 100644 (file)
@@ -1,6 +1,3 @@
-void print(string...) = #1;
-string vtos(vector)   = #5;
-
 void main(vector v) {
     print(vtos(v), "\n");
     v /= 2;
index 880bc3945120cbfe3e7df985ea0e87af0e4e5f39..41df059bc4ceb8047f1157fcabc500cd42698ce3 100644 (file)
@@ -1,7 +1,3 @@
-void   print(...)    = #1;
-string ftos (float)  = #2;
-string vtos (vector) = #5;
-
 void main() {
     vector v;
 
diff --git a/util.c b/util.c
index d427c38fbf273a92ea24de3da9f39f9ccf8def58..004b69b0d5daef6215a2e85d16a408607d8ea07c 100644 (file)
--- a/util.c
+++ b/util.c
@@ -132,7 +132,7 @@ void *util_memory_r(void *ptrn, size_t byte, unsigned int line, const char *file
 void util_meminfo() {
     struct memblock_t *info;
 
-    if (!opts.memchk)
+    if (!OPTS_OPTION_BOOL(OPTION_MEMCHK))
         return;
 
     for (info = mem_start; info; info = info->next) {
@@ -175,10 +175,10 @@ char *util_strdup(const char *s) {
 
 void util_debug(const char *area, const char *ms, ...) {
     va_list  va;
-    if (!opts.debug)
+    if (!OPTS_OPTION_BOOL(OPTION_DEBUG))
         return;
 
-    if (!strcmp(area, "MEM") && !opts.memchk)
+    if (!strcmp(area, "MEM") && !OPTS_OPTION_BOOL(OPTION_MEMCHK))
         return;
 
     va_start(va, ms);
@@ -616,7 +616,7 @@ static void util_hsupdate(hash_set_t *set) {
         set->bits ++;
         set->capacity = (size_t)(1 << set->bits);
         set->mask     = set->capacity - 1;
-        set->items    = mem_a(set->capacity * sizeof(size_t));
+        set->items    = (size_t*)mem_a(set->capacity * sizeof(size_t));
         set->total    = 0;
 
         /*assert(set->items);*/
@@ -680,14 +680,14 @@ int util_hshas(hash_set_t *set, void *item) {
 hash_set_t *util_hsnew(void) {
     hash_set_t *set;
 
-    if (!(set = mem_a(sizeof(hash_set_t))))
+    if (!(set = (hash_set_t*)mem_a(sizeof(hash_set_t))))
         return NULL;
 
     set->bits     = 3;
     set->total    = 0;
     set->capacity = (size_t)(1 << set->bits);
     set->mask     = set->capacity - 1;
-    set->items    = mem_a(set->capacity * sizeof(size_t));
+    set->items    = (size_t*)mem_a(set->capacity * sizeof(size_t));
 
     if (!set->items) {
         util_hsdel(set);
@@ -760,7 +760,7 @@ int util_vasprintf(char **dat, const char *fmt, va_list args) {
         }
 
         /* not large enough ... */
-        tmp = mem_a(len + 1);
+        tmp = (char*)mem_a(len + 1);
         if ((ret = vsnprintf(tmp, len + 1, fmt, args)) != len) {
             mem_d(tmp);
             *dat = NULL;