move more parser code to c++, fix crashes with gcc
[xonotic/gmqcc.git] / main.cpp
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "gmqcc.h"
5 #include "lexer.h"
6 #include "parser.h"
7
8 /* TODO: cleanup this whole file .. it's a fuckign mess */
9
10 /* set by the standard */
11 const oper_info *operators = nullptr;
12 size_t operator_count = 0;
13 static bool opts_output_wasset = false;
14 struct argitem { char *filename; int type; };
15 struct ppitem { char *name; char *value; };
16 static argitem *items = nullptr;
17 static ppitem  *ppems = nullptr;
18
19 #define TYPE_QC  0
20 #define TYPE_ASM 1
21 #define TYPE_SRC 2
22
23 static const char *app_name;
24
25 static void version(void) {
26     con_out("GMQCC %d.%d.%d Built %s %s\n" GMQCC_DEV_VERSION_STRING,
27         GMQCC_VERSION_MAJOR,
28         GMQCC_VERSION_MINOR,
29         GMQCC_VERSION_PATCH,
30         __DATE__,
31         __TIME__
32     );
33 }
34
35 static int usage(void) {
36     con_out("usage: %s [options] [files...]", app_name);
37     con_out("options:\n"
38             "  -h, --help             show this help message\n"
39             "  -debug                 turns on compiler debug messages\n");
40     con_out("  -o, --output=file      output file, defaults to progs.dat\n"
41             "  -s filename            add a progs.src file to be used\n");
42     con_out("  -E                     stop after preprocessing\n");
43     con_out("  -q, --quiet            be less verbose\n");
44     con_out("  -config file           use the specified ini file\n");
45     con_out("  -std=standard          select one of the following standards\n"
46             "       -std=qcc          original QuakeC\n"
47             "       -std=fteqcc       fteqcc QuakeC\n"
48             "       -std=gmqcc        this compiler (default)\n");
49     con_out("  -f<flag>               enable a flag\n"
50             "  -fno-<flag>            disable a flag\n"
51             "  -fhelp                 list possible flags\n");
52     con_out("  -W<warning>            enable a warning\n"
53             "  -Wno-<warning>         disable a warning\n"
54             "  -Wall                  enable all warnings\n");
55     con_out("  -Werror                treat warnings as errors\n"
56             "  -Werror-<warning>      treat a warning as error\n"
57             "  -Wno-error-<warning>   opposite of the above\n");
58     con_out("  -Whelp                 list possible warnings\n");
59     con_out("  -O<number>             optimization level\n"
60             "  -O<name>               enable specific optimization\n"
61             "  -Ono-<name>            disable specific optimization\n"
62             "  -Ohelp                 list optimizations\n");
63     con_out("  -force-crc=num         force a specific checksum into the header\n");
64     con_out("  -state-fps=num         emulate OP_STATE with the specified FPS\n");
65     con_out("  -coverage              add coverage support\n");
66     return -1;
67 }
68
69 /* command line parsing */
70 static bool options_witharg(int *argc_, char ***argv_, char **out) {
71     int  argc   = *argc_;
72     char **argv = *argv_;
73
74     if (argv[0][2]) {
75         *out = argv[0]+2;
76         return true;
77     }
78     /* eat up the next */
79     if (argc < 2) /* no parameter was provided */
80         return false;
81
82     *out = argv[1];
83     --*argc_;
84     ++*argv_;
85     return true;
86 }
87
88 static bool options_long_witharg_all(const char *optname, int *argc_, char ***argv_, char **out, int ds, bool split) {
89     int  argc   = *argc_;
90     char **argv = *argv_;
91
92     size_t len = strlen(optname);
93
94     if (strncmp(argv[0]+ds, optname, len))
95         return false;
96
97     /* it's --optname, check how the parameter is supplied */
98     if (argv[0][ds+len] == '=') {
99         /* using --opt=param */
100         *out = argv[0]+ds+len+1;
101         return true;
102     }
103
104     if (!split || argc < ds) /* no parameter was provided, or only single-arg form accepted */
105         return false;
106
107     /* using --opt param */
108     *out = argv[1];
109     --*argc_;
110     ++*argv_;
111     return true;
112 }
113 static bool options_long_witharg(const char *optname, int *argc_, char ***argv_, char **out) {
114     return options_long_witharg_all(optname, argc_, argv_, out, 2, true);
115 }
116 static bool options_long_gcc(const char *optname, int *argc_, char ***argv_, char **out) {
117     return options_long_witharg_all(optname, argc_, argv_, out, 1, false);
118 }
119
120 static bool options_parse(int argc, char **argv) {
121     bool argend = false;
122     size_t itr;
123     char buffer[1024];
124     char *config = nullptr;
125
126     while (!argend && argc > 1) {
127         char *argarg;
128         argitem item;
129         ppitem macro;
130
131         ++argv;
132         --argc;
133
134         if (argv[0][0] == '-') {
135             /* All gcc-type long options */
136             if (options_long_gcc("std", &argc, &argv, &argarg)) {
137                 if (!strcmp(argarg, "gmqcc") || !strcmp(argarg, "default")) {
138
139                     opts_set(opts.flags, ADJUST_VECTOR_FIELDS,          true);