+bool code_write (const char *filename, const char *lno);
+void code_init ();
+uint32_t code_genstring (const char *string);
+qcint code_alloc_field (size_t qcsize);
+
+/* this function is used to keep statements and linenumbers together */
+void code_push_statement(prog_section_statement *stmt, int linenum);
+void code_pop_statement();
+
+/*
+ * A shallow copy of a lex_file to remember where which ast node
+ * came from.
+ */
+typedef struct {
+ const char *file;
+ size_t line;
+} lex_ctx;
+
+/*===================================================================*/
+/*============================ con.c ================================*/
+/*===================================================================*/
+enum {
+ CON_BLACK = 30,
+ CON_RED,
+ CON_GREEN,
+ CON_BROWN,
+ CON_BLUE,
+ CON_MAGENTA,
+ CON_CYAN ,
+ CON_WHITE
+};
+
+/* message level */
+enum {
+ LVL_MSG,
+ LVL_WARNING,
+ LVL_ERROR
+};
+
+FILE *con_default_out();
+FILE *con_default_err();
+
+void con_vprintmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap);
+void con_printmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, ...);
+void con_cvprintmsg(void *ctx, int lvl, const char *msgtype, const char *msg, va_list ap);
+void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ...);
+
+void con_close ();
+void con_init ();
+void con_reset ();
+void con_color (int);
+int con_change(const char *, const char *);
+int con_verr (const char *, va_list);
+int con_vout (const char *, va_list);
+int con_err (const char *, ...);
+int con_out (const char *, ...);
+
+/* error/warning interface */
+extern size_t compile_errors;
+extern size_t compile_Werrors;
+extern size_t compile_warnings;
+
+void /********/ compile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, ...);
+void /********/ vcompile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, va_list ap);
+bool GMQCC_WARN compile_warning (lex_ctx ctx, int warntype, const char *fmt, ...);
+bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap);
+void compile_show_werrors();
+
+/*===================================================================*/
+/*========================= assembler.c =============================*/
+/*===================================================================*/
+/* TODO: remove this ... */
+static const struct {
+ const char *m; /* menomic */
+ const size_t o; /* operands */
+ const size_t l; /* menomic len */
+} asm_instr[] = {
+ { "DONE" , 1, 4 },
+ { "MUL_F" , 3, 5 },
+ { "MUL_V" , 3, 5 },
+ { "MUL_FV" , 3, 6 },
+ { "MUL_VF" , 3, 6 },
+ { "DIV" , 0, 3 },
+ { "ADD_F" , 3, 5 },
+ { "ADD_V" , 3, 5 },
+ { "SUB_F" , 3, 5 },
+ { "SUB_V" , 3, 5 },
+ { "EQ_F" , 0, 4 },
+ { "EQ_V" , 0, 4 },
+ { "EQ_S" , 0, 4 },
+ { "EQ_E" , 0, 4 },
+ { "EQ_FNC" , 0, 6 },
+ { "NE_F" , 0, 4 },
+ { "NE_V" , 0, 4 },
+ { "NE_S" , 0, 4 },
+ { "NE_E" , 0, 4 },
+ { "NE_FNC" , 0, 6 },
+ { "LE" , 0, 2 },
+ { "GE" , 0, 2 },
+ { "LT" , 0, 2 },
+ { "GT" , 0, 2 },
+ { "FIELD_F" , 0, 7 },
+ { "FIELD_V" , 0, 7 },
+ { "FIELD_S" , 0, 7 },
+ { "FIELD_ENT" , 0, 9 },
+ { "FIELD_FLD" , 0, 9 },
+ { "FIELD_FNC" , 0, 9 },
+ { "ADDRESS" , 0, 7 },
+ { "STORE_F" , 0, 7 },
+ { "STORE_V" , 0, 7 },
+ { "STORE_S" , 0, 7 },
+ { "STORE_ENT" , 0, 9 },
+ { "STORE_FLD" , 0, 9 },
+ { "STORE_FNC" , 0, 9 },
+ { "STOREP_F" , 0, 8 },
+ { "STOREP_V" , 0, 8 },
+ { "STOREP_S" , 0, 8 },
+ { "STOREP_ENT", 0, 10},
+ { "STOREP_FLD", 0, 10},
+ { "STOREP_FNC", 0, 10},
+ { "RETURN" , 0, 6 },
+ { "NOT_F" , 0, 5 },
+ { "NOT_V" , 0, 5 },
+ { "NOT_S" , 0, 5 },
+ { "NOT_ENT" , 0, 7 },
+ { "NOT_FNC" , 0, 7 },
+ { "IF" , 0, 2 },
+ { "IFNOT" , 0, 5 },
+ { "CALL0" , 1, 5 },
+ { "CALL1" , 2, 5 },
+ { "CALL2" , 3, 5 },
+ { "CALL3" , 4, 5 },
+ { "CALL4" , 5, 5 },
+ { "CALL5" , 6, 5 },
+ { "CALL6" , 7, 5 },
+ { "CALL7" , 8, 5 },
+ { "CALL8" , 9, 5 },
+ { "STATE" , 0, 5 },
+ { "GOTO" , 0, 4 },
+ { "AND" , 0, 3 },
+ { "OR" , 0, 2 },
+ { "BITAND" , 0, 6 },
+ { "BITOR" , 0, 5 },
+
+ { "END" , 0, 3 } /* virtual assembler instruction */
+};
+/*===================================================================*/
+/*============================= ir.c ================================*/
+/*===================================================================*/
+
+enum store_types {
+ store_global,
+ store_local, /* local, assignable for now, should get promoted later */
+ store_param, /* parameters, they are locals with a fixed position */
+ store_value, /* unassignable */
+ store_return /* unassignable, at OFS_RETURN */
+};
+
+typedef struct {
+ qcfloat x, y, z;
+} vector;
+
+vector vec3_add (vector, vector);
+vector vec3_sub (vector, vector);
+qcfloat vec3_mulvv(vector, vector);
+vector vec3_mulvf(vector, float);
+
+/*===================================================================*/
+/*============================= exec.c ==============================*/
+/*===================================================================*/
+
+/* TODO: cleanup */
+/*
+ * Darkplaces has (or will have) a 64 bit prog loader
+ * where the 32 bit qc program is autoconverted on load.
+ * Since we may want to support that as well, let's redefine
+ * float and int here.
+ */
+typedef union {
+ qcint _int;
+ qcint string;
+ qcint function;
+ qcint edict;
+ qcfloat _float;
+ qcfloat vector[3];
+ qcint ivector[3];
+} qcany;
+
+typedef char qcfloat_size_is_correct [sizeof(qcfloat) == 4 ?1:-1];
+typedef char qcint_size_is_correct [sizeof(qcint) == 4 ?1:-1];
+
+enum {
+ VMERR_OK,
+ VMERR_TEMPSTRING_ALLOC,
+
+ VMERR_END
+};
+
+#define VM_JUMPS_DEFAULT 1000000
+
+/* execute-flags */
+#define VMXF_DEFAULT 0x0000 /* default flags - nothing */
+#define VMXF_TRACE 0x0001 /* trace: print statements before executing */
+#define VMXF_PROFILE 0x0002 /* profile: increment the profile counters */
+
+struct qc_program_s;
+
+typedef int (*prog_builtin)(struct qc_program_s *prog);
+
+typedef struct {
+ qcint stmt;
+ size_t localsp;
+ prog_section_function *function;
+} qc_exec_stack;
+
+typedef struct qc_program_s {
+ char *filename;
+
+ prog_section_statement *code;
+ prog_section_def *defs;
+ prog_section_def *fields;
+ prog_section_function *functions;
+ char *strings;
+ qcint *globals;
+ qcint *entitydata;
+ bool *entitypool;
+
+ const char* *function_stack;
+
+ uint16_t crc16;
+
+ size_t tempstring_start;
+ size_t tempstring_at;
+
+ qcint vmerror;
+
+ size_t *profile;
+
+ prog_builtin *builtins;
+ size_t builtins_count;
+
+ /* size_t ip; */
+ qcint entities;
+ size_t entityfields;
+ bool allowworldwrites;
+
+ qcint *localstack;
+ qc_exec_stack *stack;
+ size_t statement;
+
+ size_t xflags;
+
+ int argc; /* current arg count for debugging */
+} qc_program;
+
+qc_program* prog_load(const char *filename);
+void prog_delete(qc_program *prog);
+
+bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps);
+
+char* prog_getstring (qc_program *prog, qcint str);
+prog_section_def* prog_entfield (qc_program *prog, qcint off);
+prog_section_def* prog_getdef (qc_program *prog, qcint off);
+qcany* prog_getedict (qc_program *prog, qcint e);
+qcint prog_tempstring(qc_program *prog, const char *_str);
+
+
+/*===================================================================*/
+/*===================== parser.c commandline ========================*/
+/*===================================================================*/
+
+bool parser_init ();
+bool parser_compile_file (const char *);
+bool parser_compile_string(const char *, const char *, size_t);
+bool parser_finish (const char *);
+void parser_cleanup ();
+
+/*===================================================================*/
+/*====================== ftepp.c commandline ========================*/
+/*===================================================================*/
+bool ftepp_init ();
+bool ftepp_preprocess_file (const char *filename);
+bool ftepp_preprocess_string(const char *name, const char *str);
+void ftepp_finish ();
+const char *ftepp_get ();
+void ftepp_flush ();
+void ftepp_add_define (const char *source, const char *name);
+void ftepp_add_macro (const char *name, const char *value);
+
+/*===================================================================*/
+/*======================= main.c commandline ========================*/
+/*===================================================================*/
+
+#if 1
+/* Helpers to allow for a whole lot of flags. Otherwise we'd limit
+ * to 32 or 64 -f options...
+ */
+typedef struct {
+ size_t idx; /* index into an array of 32 bit words */
+ uint8_t bit; /* bit index for the 8 bit group idx points to */
+} longbit;
+#define LONGBIT(bit) { ((bit)/32), ((bit)%32) }
+#define LONGBIT_SET(B, I) ((B).idx = (I)/32, (B).bit = ((I)%32))
+#else
+typedef uint32_t longbit;
+#define LONGBIT(bit) (bit)
+#define LONGBIT_SET(B, I) ((B) = (I))
+#endif
+
+/*===================================================================*/
+/*=========================== utf8lib.c =============================*/
+/*===================================================================*/
+typedef uint32_t uchar_t;
+
+bool u8_analyze (const char *_s, size_t *_start, size_t *_len, uchar_t *_ch, size_t _maxlen);
+size_t u8_strlen (const char*);
+size_t u8_strnlen (const char*, size_t);
+uchar_t u8_getchar (const char*, const char**);
+uchar_t u8_getnchar(const char*, const char**, size_t);
+int u8_fromchar(uchar_t w, char *to, size_t maxlen);
+
+/*===================================================================*/
+/*============================= opts.c ==============================*/
+/*===================================================================*/
+typedef struct {
+ const char *name;
+ longbit bit;
+} opts_flag_def;
+
+bool opts_setflag (const char *, bool);
+bool opts_setwarn (const char *, bool);
+bool opts_setwerror(const char *, bool);
+bool opts_setoptim (const char *, bool);
+
+void opts_init (const char *, int, size_t);
+void opts_set (uint32_t *, size_t, bool);
+void opts_setoptimlevel(unsigned int);
+void opts_ini_init (const char *);
+
+enum {
+# define GMQCC_TYPE_FLAGS
+# define GMQCC_DEFINE_FLAG(X) 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) },
+# include "opts.def"
+ { NULL, LONGBIT(0) }
+};
+
+enum {
+# define GMQCC_TYPE_WARNS
+# define GMQCC_DEFINE_FLAG(X) 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) },
+# include "opts.def"
+ { NULL, LONGBIT(0) }
+};
+
+enum {
+# define GMQCC_TYPE_OPTIMIZATIONS
+# define GMQCC_DEFINE_FLAG(NAME, MIN_O) 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) },
+# include "opts.def"
+ { NULL, LONGBIT(0) }
+};
+static const unsigned int opts_opt_oflag[] = {
+# define GMQCC_TYPE_OPTIMIZATIONS
+# define GMQCC_DEFINE_FLAG(NAME, MIN_O) MIN_O,
+# include "opts.def"
+ 0
+};
+extern unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS];
+
+/* other options: */
+typedef enum {
+ COMPILER_QCC, /* circa QuakeC */
+ COMPILER_FTEQCC, /* fteqcc QuakeC */
+ COMPILER_QCCX, /* qccx QuakeC */
+ COMPILER_GMQCC /* this QuakeC */
+} opts_std_t;
+
+/* TODO: cleanup this */
+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= */
+
+ uint32_t flags [1 + (COUNT_FLAGS / 32)];
+ uint32_t warn [1 + (COUNT_WARNINGS / 32)];
+ uint32_t werror [1 + (COUNT_WARNINGS / 32)];
+ uint32_t optimization[1 + (COUNT_OPTIMIZATIONS / 32)];
+} opts_cmd_t;
+
+extern opts_cmd_t opts;
+
+#define OPTS_FLAG(i) (!! (opts.flags [(i)/32] & (1<< ((i)%32))))
+#define OPTS_WARN(i) (!! (opts.warn [(i)/32] & (1<< ((i)%32))))
+#define OPTS_WERROR(i) (!! (opts.werror [(i)/32] & (1<< ((i)%32))))
+#define OPTS_OPTIMIZATION(i) (!! (opts.optimization[(i)/32] & (1<< ((i)%32))))
+