]> git.xonotic.org Git - xonotic/gmqcc.git/blob - lexer.h
Stuff
[xonotic/gmqcc.git] / lexer.h
1 #ifndef GMQCC_LEXER_HDR
2 #define GMQCC_LEXER_HDR
3
4 #include "gmqcc.h"
5
6 #define TOKENS(X) \
7     /* Other tokens which we can return: */ \
8     X(NONE, =0) \
9     X(CR, = '\r') \
10     X(LF, = '\n') \
11     X(WS, = ' ') \
12     X(BACKSLASH, = '\\') \
13     X(HASH, = '#') \
14     X(DOLLAR, = '$') \
15     X(DOT, = '.') \
16     X(COMMA, = ',') \
17     X(COLON, = ':') \
18     X(SEMICOLON, = ';') \
19     X(AND, = '&') \
20     X(OR, = '|') \
21     X(XOR, = '^') \
22     X(BITNOT, = '~') \
23     X(NOT, = '!') \
24     X(LT, = '<') \
25     X(GT, = '>') \
26     X(EQ, = '=') \
27     X(MUL, = '*') \
28     X(DIV, = '/') \
29     X(MOD, = '%') \
30     X(ADD, = '+') \
31     X(SUB, = '-') \
32     X(QUOT_SINGLE, = '\'') \
33     X(QUOT_DOUBLE, = '"') \
34     X(QUESTION, = '?') \
35     X(BRACE_OPEN, = '{') \
36     X(BRACE_CLOSE, = '}') \
37     X(BRACKET_OPEN, = '[') \
38     X(BRACKET_CLOSE, = ']') \
39     X(PAREN_OPEN, = '(') \
40     X(PAREN_CLOSE, = ')') \
41     X(START, = 128) \
42     X(IDENT, ) \
43     X(TYPENAME, ) \
44     X(OPERATOR, ) \
45     X(OP_AND, ) \
46     X(OP_CROSS, ) \
47     X(OP_LE, ) \
48     X(OP_GE, ) \
49     X(OP_LSH, ) \
50     X(OP_RSH, ) \
51     /* loop */ \
52     X(KEYWORD, ) \
53     /* 3 dots, ... */ \
54     X(DOTS, ) \
55     /* [[ */ \
56     X(ATTRIBUTE_OPEN, ) \
57     /* ]] */ \
58     X(ATTRIBUTE_CLOSE, ) \
59     /* for the ftepp only */ \
60     X(VA_ARGS, ) \
61     /* for the ftepp only */ \
62     X(VA_ARGS_ARRAY, ) \
63     /* to get the count of vaargs */ \
64     X(VA_COUNT, ) \
65     /* not the typename but an actual "string" */ \
66     X(STRINGCONST, ) \
67     X(CHARCONST, ) \
68     X(VECTORCONST, ) \
69     X(INTCONST, ) \
70     X(FLOATCONST, ) \
71     X(WHITE, ) \
72     X(EOL, ) \
73     /* if we add additional tokens before this, the exposed API \
74      * should not be broken anyway, but EOF/ERROR/... should \
75      * still be at the bottom \
76      */ \
77     X(END, = 1024) \
78     /* We use '< ERROR', so FATAL must come after it and any \
79      * other error related tokens as well \
80      */ \
81     X(ERROR, ) \
82     /* internal error, eg out of memory */ \
83     X(FATAL, ) \
84     /**/
85
86 enum Token : int { // todo: enum class
87 #define X(id, val) id val,
88     TOKENS(X)
89 #undef X
90 };
91
92 inline const char *TokenName(Token t) {
93     switch (t) {
94         default:
95             return "UNKNOWN";
96 #define X(id, val) case Token::id: return #id;
97         TOKENS(X)
98 #undef X
99     }
100 }
101
102 struct cvec {
103     std::string value;
104
105     explicit cvec() = default;
106
107     char *mut() {
108         return &value[0];
109     }
110
111     const char *c_str() {
112         return value.c_str();
113     }
114
115     void shrinkto(size_t i) {
116         value.resize(i);
117     }
118
119     void shrinkby(size_t i) {
120         value.resize(value.size() - i);
121     }
122
123     void push(char it) {
124         value.push_back(it);
125     }
126 };
127
128 struct token {
129     Token ttype;
130     cvec value;
131     union {
132         vec3_t v;
133         int i;
134         qcfloat_t f;
135         qc_type t; /* type */
136     } constval;
137     lex_ctx_t ctx;
138 };
139
140 struct frame_macro {
141     std::string name;
142     int value;
143 };
144
145 struct lex_file {
146     FILE *file;
147     const char *open_string;
148     size_t open_string_length;
149     size_t open_string_pos;
150
151     char *name;
152     size_t line;
153     size_t sline; /* line at the start of a token */
154     size_t column;
155
156     std::array<Token, 256> peek;
157     size_t peekpos;
158
159     bool eof;
160
161     token tok; /* not a pointer anymore */
162
163     struct {
164         bool noops:1;
165         bool nodigraphs:1; /* used when lexing string constants */
166         bool preprocessing:1; /* whitespace and EOLs become actual tokens */
167         bool mergelines:1; /* backslash at the end of a line escapes the newline */
168     } flags; /* sizeof == 1 */
169
170     int framevalue;
171     frame_macro *frames;
172     std::string modelname;
173
174     size_t push_line;
175 };
176
177 lex_file *lex_open(const char *file);
178
179 lex_file *lex_open_string(const char *str, size_t len, const char *name);
180
181 void lex_close(lex_file *lex);
182
183 Token lex_do(lex_file *lex);
184
185 void lex_cleanup();
186
187 /* Parser
188  *
189  */
190
191 enum {
192     ASSOC_LEFT,
193     ASSOC_RIGHT
194 };
195
196 #define OP_SUFFIX 1
197 #define OP_PREFIX 2
198
199 struct oper_info {
200     const char *op;
201     unsigned int operands;
202     unsigned int id;
203     unsigned int assoc;
204     signed int prec;
205     unsigned int flags;
206     bool folds;
207 };
208
209 /*
210  * Explicit uint8_t casts since the left operand of shift operator cannot
211  * be negative, even though it won't happen, this supresses the future
212  * possibility.
213  */
214 #define opid1(a)     ((uint8_t)a)
215 #define opid2(a, b)   (((uint8_t)a<<8) |(uint8_t)b)
216 #define opid3(a, b, c) (((uint8_t)a<<16)|((uint8_t)b<<8)|(uint8_t)c)
217
218 static const oper_info c_operators[] = {
219         {"(",       0, opid1('('),           ASSOC_LEFT,  99, OP_PREFIX, false}, /* paren expression - non function call */
220         {"_length", 1, opid3('l', 'e', 'n'), ASSOC_RIGHT, 98, OP_PREFIX, true},
221
222         {"++",      1, opid3('S', '+', '+'), ASSOC_LEFT,  17, OP_SUFFIX, false},
223         {"--",      1, opid3('S', '-', '-'), ASSOC_LEFT,  17, OP_SUFFIX, false},
224         {".",       2, opid1('.'),           ASSOC_LEFT,  17, 0,         false},
225         {"(",       0, opid1('('),           ASSOC_LEFT,  17, 0,         false}, /* function call */
226         {"[",       2, opid1('['),           ASSOC_LEFT,  17, 0,         false}, /* array subscript */
227
228         {"++",      1, opid3('+', '+', 'P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
229         {"--",      1, opid3('-', '-', 'P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
230
231         {"**",      2, opid2('*', '*'),      ASSOC_RIGHT, 14, 0,         true},
232         {"!",       1, opid2('!', 'P'),      ASSOC_RIGHT, 14, OP_PREFIX, true},
233         {"~",       1, opid2('~', 'P'),      ASSOC_RIGHT, 14, OP_PREFIX, true},
234         {"+",       1, opid2('+', 'P'),      ASSOC_RIGHT, 14, OP_PREFIX, false},
235         {"-",       1, opid2('-', 'P'),      ASSOC_RIGHT, 14, OP_PREFIX, true},
236 /*  { "&",      1, opid2('&','P'),     ASSOC_RIGHT, 14, OP_PREFIX, false}, */
237
238         {"*",       2, opid1('*'),           ASSOC_LEFT,  13, 0,         true},
239         {"/",       2, opid1('/'),           ASSOC_LEFT,  13, 0,         true},
240         {"%",       2, opid1('%'),           ASSOC_LEFT,  13, 0,         true},
241         {"><",      2, opid2('>', '<'),      ASSOC_LEFT,  13, 0,         true},
242
243         {"+",       2, opid1('+'),           ASSOC_LEFT,  12, 0,         true},
244         {"-",       2, opid1('-'),           ASSOC_LEFT,  12, 0,         true},
245
246         {"<<",      2, opid2('<', '<'),      ASSOC_LEFT,  11, 0,         true},
247         {">>",      2, opid2('>', '>'),      ASSOC_LEFT,  11, 0,         true},
248
249         {"<",       2, opid1('<'),           ASSOC_LEFT,  10, 0,         false},
250         {">",       2, opid1('>'),           ASSOC_LEFT,  10, 0,         false},
251         {"<=>",     2, opid3('<', '=', '>'), ASSOC_LEFT,  10, 0,         true},
252         {"<=",      2, opid2('<', '='),      ASSOC_LEFT,  10, 0,         false},
253         {">=",      2, opid2('>', '='),      ASSOC_LEFT,  10, 0,         false},
254
255         {"==",      2, opid2('=', '='),      ASSOC_LEFT,  9,  0,         true},
256         {"!=",      2, opid2('!', '='),      ASSOC_LEFT,  9,  0,         true},
257
258         {"&",       2, opid1('&'),           ASSOC_LEFT,  8,  0,         true},
259
260         {"^",       2, opid1('^'),           ASSOC_LEFT,  7,  0,         true},
261
262         {"|",       2, opid1('|'),           ASSOC_LEFT,  6,  0,         true},
263
264         {"&&",      2, opid2('&', '&'),      ASSOC_LEFT,  5,  0,         true},
265
266         {"||",      2, opid2('|', '|'),      ASSOC_LEFT,  4,  0,         true},
267
268         {"?",       3, opid2('?', ':'),      ASSOC_RIGHT, 3,  0,         true},
269
270         {"=",       2, opid1('='),           ASSOC_RIGHT, 2,  0,         false},
271         {"+=",      2, opid2('+', '='),      ASSOC_RIGHT, 2,  0,         false},
272         {"-=",      2, opid2('-', '='),      ASSOC_RIGHT, 2,  0,         false},
273         {"*=",      2, opid2('*', '='),      ASSOC_RIGHT, 2,  0,         false},
274         {"/=",      2, opid2('/', '='),      ASSOC_RIGHT, 2,  0,         false},
275         {"%=",      2, opid2('%', '='),      ASSOC_RIGHT, 2,  0,         false},
276         {">>=",     2, opid3('>', '>', '='), ASSOC_RIGHT, 2,  0,         false},
277         {"<<=",     2, opid3('<', '<', '='), ASSOC_RIGHT, 2,  0,         false},
278         {"&=",      2, opid2('&', '='),      ASSOC_RIGHT, 2,  0,         false},
279         {"^=",      2, opid2('^', '='),      ASSOC_RIGHT, 2,  0,         false},
280         {"|=",      2, opid2('|', '='),      ASSOC_RIGHT, 2,  0,         false},
281
282         {":",       0, opid2(':', '?'),      ASSOC_RIGHT, 1,  0,         false},
283
284         {",",       2, opid1(','),           ASSOC_LEFT,  0,  0,         false}
285 };
286
287 static const oper_info fte_operators[] = {
288         {"(",   0, opid1('('),           ASSOC_LEFT,  99, OP_PREFIX, false}, /* paren expression - non function call */
289
290         {"++",  1, opid3('S', '+', '+'), ASSOC_LEFT,  15, OP_SUFFIX, false},
291         {"--",  1, opid3('S', '-', '-'), ASSOC_LEFT,  15, OP_SUFFIX, false},
292         {".",   2, opid1('.'),           ASSOC_LEFT,  15, 0,         false},
293         {"(",   0, opid1('('),           ASSOC_LEFT,  15, 0,         false}, /* function call */
294         {"[",   2, opid1('['),           ASSOC_LEFT,  15, 0,         false}, /* array subscript */
295
296         {"!",   1, opid2('!', 'P'),      ASSOC_RIGHT, 14, OP_PREFIX, true},
297         {"+",   1, opid2('+', 'P'),      ASSOC_RIGHT, 14, OP_PREFIX, false},
298         {"-",   1, opid2('-', 'P'),      ASSOC_RIGHT, 14, OP_PREFIX, true},
299         {"++",  1, opid3('+', '+', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
300         {"--",  1, opid3('-', '-', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
301
302         {"*",   2, opid1('*'),           ASSOC_LEFT,  13, 0,         true},
303         {"/",   2, opid1('/'),           ASSOC_LEFT,  13, 0,         true},
304         {"&",   2, opid1('&'),           ASSOC_LEFT,  13, 0,         true},
305         {"|",   2, opid1('|'),           ASSOC_LEFT,  13, 0,         true},
306
307         {"+",   2, opid1('+'),           ASSOC_LEFT,  12, 0,         true},
308         {"-",   2, opid1('-'),           ASSOC_LEFT,  12, 0,         true},
309
310         {"<<",  2, opid2('<', '<'),      ASSOC_LEFT,  11, 0,         true},
311         {">>",  2, opid2('>', '>'),      ASSOC_LEFT,  11, 0,         true},
312
313         {"<",   2, opid1('<'),           ASSOC_LEFT,  10, 0,         false},
314         {">",   2, opid1('>'),           ASSOC_LEFT,  10, 0,         false},
315         {"<=",  2, opid2('<', '='),      ASSOC_LEFT,  10, 0,         false},
316         {">=",  2, opid2('>', '='),      ASSOC_LEFT,  10, 0,         false},
317         {"==",  2, opid2('=', '='),      ASSOC_LEFT,  10, 0,         true},
318         {"!=",  2, opid2('!', '='),      ASSOC_LEFT,  10, 0,         true},
319
320         {"?",   3, opid2('?', ':'),      ASSOC_RIGHT, 9,  0,         true},
321
322         {"=",   2, opid1('='),           ASSOC_RIGHT, 8,  0,         false},
323         {"+=",  2, opid2('+', '='),      ASSOC_RIGHT, 8,  0,         false},
324         {"-=",  2, opid2('-', '='),      ASSOC_RIGHT, 8,  0,         false},
325         {"*=",  2, opid2('*', '='),      ASSOC_RIGHT, 8,  0,         false},
326         {"/=",  2, opid2('/', '='),      ASSOC_RIGHT, 8,  0,         false},
327         {"%=",  2, opid2('%', '='),      ASSOC_RIGHT, 8,  0,         false},
328         {"&=",  2, opid2('&', '='),      ASSOC_RIGHT, 8,  0,         false},
329         {"|=",  2, opid2('|', '='),      ASSOC_RIGHT, 8,  0,         false},
330         {"&~=", 2, opid3('&', '~', '='), ASSOC_RIGHT, 8,  0,         false},
331
332         {"&&",  2, opid2('&', '&'),      ASSOC_LEFT,  5,  0,         true},
333         {"||",  2, opid2('|', '|'),      ASSOC_LEFT,  5,  0,         true},
334
335         /* Leave precedence 3 for : with -fcorrect-ternary */
336         {",",   2, opid1(','),           ASSOC_LEFT,  2,  0,         false},
337         {":",   0, opid2(':', '?'),      ASSOC_RIGHT, 1,  0,         false}
338 };
339
340 static const oper_info qcc_operators[] = {
341         {"(",  0, opid1('('),      ASSOC_LEFT,  99, OP_PREFIX, false}, /* paren expression - non function call */
342
343         {".",  2, opid1('.'),      ASSOC_LEFT,  15, 0,         false},
344         {"(",  0, opid1('('),      ASSOC_LEFT,  15, 0,         false}, /* function call */
345         {"[",  2, opid1('['),      ASSOC_LEFT,  15, 0,         false}, /* array subscript */
346
347         {"!",  1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true},
348         {"+",  1, opid2('+', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
349         {"-",  1, opid2('-', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true},
350
351         {"*",  2, opid1('*'),      ASSOC_LEFT,  13, 0,         true},
352         {"/",  2, opid1('/'),      ASSOC_LEFT,  13, 0,         true},
353         {"&",  2, opid1('&'),      ASSOC_LEFT,  13, 0,         true},
354         {"|",  2, opid1('|'),      ASSOC_LEFT,  13, 0,         true},
355
356         {"+",  2, opid1('+'),      ASSOC_LEFT,  12, 0,         true},
357         {"-",  2, opid1('-'),      ASSOC_LEFT,  12, 0,         true},
358
359         {"<",  2, opid1('<'),      ASSOC_LEFT,  10, 0,         false},
360         {">",  2, opid1('>'),      ASSOC_LEFT,  10, 0,         false},
361         {"<=", 2, opid2('<', '='), ASSOC_LEFT,  10, 0,         false},
362         {">=", 2, opid2('>', '='), ASSOC_LEFT,  10, 0,         false},
363         {"==", 2, opid2('=', '='), ASSOC_LEFT,  10, 0,         true},
364         {"!=", 2, opid2('!', '='), ASSOC_LEFT,  10, 0,         true},
365
366         {"=",  2, opid1('='),      ASSOC_RIGHT, 8,  0,         false},
367         {"+=", 2, opid2('+', '='), ASSOC_RIGHT, 8,  0,         false},
368         {"-=", 2, opid2('-', '='), ASSOC_RIGHT, 8,  0,         false},
369         {"*=", 2, opid2('*', '='), ASSOC_RIGHT, 8,  0,         false},
370         {"/=", 2, opid2('/', '='), ASSOC_RIGHT, 8,  0,         false},
371         {"%=", 2, opid2('%', '='), ASSOC_RIGHT, 8,  0,         false},
372         {"&=", 2, opid2('&', '='), ASSOC_RIGHT, 8,  0,         false},
373         {"|=", 2, opid2('|', '='), ASSOC_RIGHT, 8,  0,         false},
374
375         {"&&", 2, opid2('&', '&'), ASSOC_LEFT,  5,  0,         true},
376         {"||", 2, opid2('|', '|'), ASSOC_LEFT,  5,  0,         true},
377
378         {",",  2, opid1(','),      ASSOC_LEFT,  2,  0,         false},
379 };
380 extern const oper_info *operators;
381 extern size_t operator_count;
382
383 #endif