]> git.xonotic.org Git - xonotic/gmqcc.git/blob - lexer.h
Remove license headers. The LICENSE file is sufficent
[xonotic/gmqcc.git] / lexer.h
1 #ifndef GMQCC_LEXER_HDR
2 #define GMQCC_LEXER_HDR
3 #include "gmqcc.h"
4
5 typedef struct token_s token;
6
7 struct token_s {
8     int ttype;
9
10     char *value;
11
12     union {
13         vec3_t    v;
14         int       i;
15         qcfloat_t f;
16         int       t; /* type */
17     } constval;
18
19     lex_ctx_t ctx;
20 };
21
22 /* Lexer
23  *
24  */
25 enum {
26     /* Other tokens which we can return: */
27     TOKEN_NONE = 0,
28     TOKEN_START = 128,
29
30     TOKEN_IDENT,
31
32     TOKEN_TYPENAME,
33
34     TOKEN_OPERATOR,
35
36     TOKEN_KEYWORD, /* loop */
37
38     TOKEN_DOTS, /* 3 dots, ... */
39
40     TOKEN_ATTRIBUTE_OPEN,  /* [[ */
41     TOKEN_ATTRIBUTE_CLOSE, /* ]] */
42
43     TOKEN_VA_ARGS, /* for the ftepp only */
44     TOKEN_VA_ARGS_ARRAY, /* for the ftepp only */
45     TOKEN_VA_COUNT,     /* to get the count of vaargs */
46
47     TOKEN_STRINGCONST, /* not the typename but an actual "string" */
48     TOKEN_CHARCONST,
49     TOKEN_VECTORCONST,
50     TOKEN_INTCONST,
51     TOKEN_FLOATCONST,
52
53     TOKEN_WHITE,
54     TOKEN_EOL,
55
56     /* if we add additional tokens before this, the exposed API
57      * should not be broken anyway, but EOF/ERROR/... should
58      * still be at the bottom
59      */
60     TOKEN_EOF = 1024,
61
62     /* We use '< TOKEN_ERROR', so TOKEN_FATAL must come after it and any
63      * other error related tokens as well
64      */
65     TOKEN_ERROR,
66     TOKEN_FATAL /* internal error, eg out of memory */
67 };
68
69 typedef struct {
70     char *name;
71     int   value;
72 } frame_macro;
73
74 typedef struct lex_file_s {
75     FILE  *file;
76     const char *open_string;
77     size_t      open_string_length;
78     size_t      open_string_pos;
79
80     char   *name;
81     size_t  line;
82     size_t  sline; /* line at the start of a token */
83     size_t  column;
84
85     int     peek[256];
86     size_t  peekpos;
87
88     bool    eof;
89
90     token   tok; /* not a pointer anymore */
91
92     struct {
93         unsigned noops:1;
94         unsigned nodigraphs:1; /* used when lexing string constants */
95         unsigned preprocessing:1; /* whitespace and EOLs become actual tokens */
96         unsigned mergelines:1; /* backslash at the end of a line escapes the newline */
97     } flags; /* sizeof == 1 */
98
99     int framevalue;
100     frame_macro *frames;
101     char *modelname;
102
103     size_t push_line;
104 } lex_file;
105
106 lex_file* lex_open (const char *file);
107 lex_file* lex_open_string(const char *str, size_t len, const char *name);
108 void      lex_close(lex_file   *lex);
109 int       lex_do   (lex_file   *lex);
110 void      lex_cleanup(void);
111
112 /* Parser
113  *
114  */
115
116 enum {
117     ASSOC_LEFT,
118     ASSOC_RIGHT
119 };
120
121 #define OP_SUFFIX 1
122 #define OP_PREFIX 2
123
124 typedef struct {
125     const char   *op;
126     unsigned int operands;
127     unsigned int id;
128     unsigned int assoc;
129     signed int   prec;
130     unsigned int flags;
131     bool         folds;
132 } oper_info;
133
134 /*
135  * Explicit uint8_t casts since the left operand of shift operator cannot
136  * be negative, even though it won't happen, this supresses the future
137  * possibility.
138  */
139 #define opid1(a)     ((uint8_t)a)
140 #define opid2(a,b)   (((uint8_t)a<<8) |(uint8_t)b)
141 #define opid3(a,b,c) (((uint8_t)a<<16)|((uint8_t)b<<8)|(uint8_t)c)
142
143 static const oper_info c_operators[] = {
144     { "(",       0, opid1('('),         ASSOC_LEFT,  99, OP_PREFIX, false}, /* paren expression - non function call */
145     { "_length", 1, opid3('l','e','n'), ASSOC_RIGHT, 98, OP_PREFIX, true},
146
147     { "++",     1, opid3('S','+','+'), ASSOC_LEFT,  17, OP_SUFFIX, false},
148     { "--",     1, opid3('S','-','-'), ASSOC_LEFT,  17, OP_SUFFIX, false},
149     { ".",      2, opid1('.'),         ASSOC_LEFT,  17, 0,         false},
150     { "(",      0, opid1('('),         ASSOC_LEFT,  17, 0,         false}, /* function call */
151     { "[",      2, opid1('['),         ASSOC_LEFT,  17, 0,         false}, /* array subscript */
152
153     { "++",     1, opid3('+','+','P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
154     { "--",     1, opid3('-','-','P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
155
156     { "**",     2, opid2('*','*'),     ASSOC_RIGHT, 14, 0,         true},
157     { "!",      1, opid2('!','P'),     ASSOC_RIGHT, 14, OP_PREFIX, true},
158     { "~",      1, opid2('~','P'),     ASSOC_RIGHT, 14, OP_PREFIX, true},
159     { "+",      1, opid2('+','P'),     ASSOC_RIGHT, 14, OP_PREFIX, false},
160     { "-",      1, opid2('-','P'),     ASSOC_RIGHT, 14, OP_PREFIX, true},
161 /*  { "&",      1, opid2('&','P'),     ASSOC_RIGHT, 14, OP_PREFIX, false}, */
162
163     { "*",      2, opid1('*'),         ASSOC_LEFT,  13, 0,         true},
164     { "/",      2, opid1('/'),         ASSOC_LEFT,  13, 0,         true},
165     { "%",      2, opid1('%'),         ASSOC_LEFT,  13, 0,         true},
166     { "><",     2, opid2('>','<'),     ASSOC_LEFT,  13, 0,         true},
167
168     { "+",      2, opid1('+'),         ASSOC_LEFT,  12, 0,         true},
169     { "-",      2, opid1('-'),         ASSOC_LEFT,  12, 0,         true},
170
171     { "<<",     2, opid2('<','<'),     ASSOC_LEFT,  11, 0,         true},
172     { ">>",     2, opid2('>','>'),     ASSOC_LEFT,  11, 0,         true},
173
174     { "<",      2, opid1('<'),         ASSOC_LEFT,  10, 0,         false},
175     { ">",      2, opid1('>'),         ASSOC_LEFT,  10, 0,         false},
176     { "<=>",    2, opid3('<','=','>'), ASSOC_LEFT,  10, 0,         true},
177     { "<=",     2, opid2('<','='),     ASSOC_LEFT,  10, 0,         false},
178     { ">=",     2, opid2('>','='),     ASSOC_LEFT,  10, 0,         false},
179
180     { "==",     2, opid2('=','='),     ASSOC_LEFT,  9,  0,         true},
181     { "!=",     2, opid2('!','='),     ASSOC_LEFT,  9,  0,         true},
182
183     { "&",      2, opid1('&'),         ASSOC_LEFT,  8,  0,         true},
184
185     { "^",      2, opid1('^'),         ASSOC_LEFT,  7,  0,         true},
186
187     { "|",      2, opid1('|'),         ASSOC_LEFT,  6,  0,         true},
188
189     { "&&",     2, opid2('&','&'),     ASSOC_LEFT,  5,  0,         true},
190
191     { "||",     2, opid2('|','|'),     ASSOC_LEFT,  4,  0,         true},
192
193     { "?",      3, opid2('?',':'),     ASSOC_RIGHT, 3,  0,         true},
194
195     { "=",      2, opid1('='),         ASSOC_RIGHT, 2,  0,         false},
196     { "+=",     2, opid2('+','='),     ASSOC_RIGHT, 2,  0,         false},
197     { "-=",     2, opid2('-','='),     ASSOC_RIGHT, 2,  0,         false},
198     { "*=",     2, opid2('*','='),     ASSOC_RIGHT, 2,  0,         false},
199     { "/=",     2, opid2('/','='),     ASSOC_RIGHT, 2,  0,         false},
200     { "%=",     2, opid2('%','='),     ASSOC_RIGHT, 2,  0,         false},
201     { ">>=",    2, opid3('>','>','='), ASSOC_RIGHT, 2,  0,         false},
202     { "<<=",    2, opid3('<','<','='), ASSOC_RIGHT, 2,  0,         false},
203     { "&=",     2, opid2('&','='),     ASSOC_RIGHT, 2,  0,         false},
204     { "^=",     2, opid2('^','='),     ASSOC_RIGHT, 2,  0,         false},
205     { "|=",     2, opid2('|','='),     ASSOC_RIGHT, 2,  0,         false},
206
207     { ":",      0, opid2(':','?'),     ASSOC_RIGHT, 1,  0,         false},
208
209     { ",",      2, opid1(','),         ASSOC_LEFT,  0,  0,         false}
210 };
211
212 static const oper_info fte_operators[] = {
213     { "(",   0, opid1('('),         ASSOC_LEFT,  99, OP_PREFIX, false}, /* paren expression - non function call */
214
215     { "++",  1, opid3('S','+','+'), ASSOC_LEFT,  15, OP_SUFFIX, false},
216     { "--",  1, opid3('S','-','-'), ASSOC_LEFT,  15, OP_SUFFIX, false},
217     { ".",   2, opid1('.'),         ASSOC_LEFT,  15, 0,         false},
218     { "(",   0, opid1('('),         ASSOC_LEFT,  15, 0,         false}, /* function call */
219     { "[",   2, opid1('['),         ASSOC_LEFT,  15, 0,         false}, /* array subscript */
220
221     { "!",   1, opid2('!','P'),     ASSOC_RIGHT, 14, OP_PREFIX, true},
222     { "+",   1, opid2('+','P'),     ASSOC_RIGHT, 14, OP_PREFIX, false},
223     { "-",   1, opid2('-','P'),     ASSOC_RIGHT, 14, OP_PREFIX, true},
224     { "++",  1, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
225     { "--",  1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
226
227     { "*",   2, opid1('*'),         ASSOC_LEFT,  13, 0,         true},
228     { "/",   2, opid1('/'),         ASSOC_LEFT,  13, 0,         true},
229     { "&",   2, opid1('&'),         ASSOC_LEFT,  13, 0,         true},
230     { "|",   2, opid1('|'),         ASSOC_LEFT,  13, 0,         true},
231
232     { "+",   2, opid1('+'),         ASSOC_LEFT,  12, 0,         true},
233     { "-",   2, opid1('-'),         ASSOC_LEFT,  12, 0,         true},
234
235     { "<<",  2, opid2('<','<'),     ASSOC_LEFT,  11, 0,         true},
236     { ">>",  2, opid2('>','>'),     ASSOC_LEFT,  11, 0,         true},
237
238     { "<",   2, opid1('<'),         ASSOC_LEFT,  10, 0,         false},
239     { ">",   2, opid1('>'),         ASSOC_LEFT,  10, 0,         false},
240     { "<=",  2, opid2('<','='),     ASSOC_LEFT,  10, 0,         false},
241     { ">=",  2, opid2('>','='),     ASSOC_LEFT,  10, 0,         false},
242     { "==",  2, opid2('=','='),     ASSOC_LEFT,  10, 0,         true},
243     { "!=",  2, opid2('!','='),     ASSOC_LEFT,  10, 0,         true},
244
245     { "?",   3, opid2('?',':'),     ASSOC_RIGHT, 9,  0,         true},
246
247     { "=",   2, opid1('='),         ASSOC_RIGHT, 8,  0,         false},
248     { "+=",  2, opid2('+','='),     ASSOC_RIGHT, 8,  0,         false},
249     { "-=",  2, opid2('-','='),     ASSOC_RIGHT, 8,  0,         false},
250     { "*=",  2, opid2('*','='),     ASSOC_RIGHT, 8,  0,         false},
251     { "/=",  2, opid2('/','='),     ASSOC_RIGHT, 8,  0,         false},
252     { "%=",  2, opid2('%','='),     ASSOC_RIGHT, 8,  0,         false},
253     { "&=",  2, opid2('&','='),     ASSOC_RIGHT, 8,  0,         false},
254     { "|=",  2, opid2('|','='),     ASSOC_RIGHT, 8,  0,         false},
255     { "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 8,  0,         false},
256
257     { "&&",  2, opid2('&','&'),     ASSOC_LEFT,  5,  0,         true},
258     { "||",  2, opid2('|','|'),     ASSOC_LEFT,  5,  0,         true},
259
260     /* Leave precedence 3 for : with -fcorrect-ternary */
261     { ",",   2, opid1(','),         ASSOC_LEFT,  2,  0,         false},
262     { ":",   0, opid2(':','?'),     ASSOC_RIGHT, 1,  0,         false}
263 };
264
265 static const oper_info qcc_operators[] = {
266     { "(",   0, opid1('('),         ASSOC_LEFT,  99, OP_PREFIX, false}, /* paren expression - non function call */
267
268     { ".",   2, opid1('.'),         ASSOC_LEFT,  15, 0,         false},
269     { "(",   0, opid1('('),         ASSOC_LEFT,  15, 0,         false}, /* function call */
270     { "[",   2, opid1('['),         ASSOC_LEFT,  15, 0,         false}, /* array subscript */
271
272     { "!",   1, opid2('!','P'),     ASSOC_RIGHT, 14, OP_PREFIX, true},
273     { "+",   1, opid2('+','P'),     ASSOC_RIGHT, 14, OP_PREFIX, false},
274     { "-",   1, opid2('-','P'),     ASSOC_RIGHT, 14, OP_PREFIX, true},
275
276     { "*",   2, opid1('*'),         ASSOC_LEFT,  13, 0,         true},
277     { "/",   2, opid1('/'),         ASSOC_LEFT,  13, 0,         true},
278     { "&",   2, opid1('&'),         ASSOC_LEFT,  13, 0,         true},
279     { "|",   2, opid1('|'),         ASSOC_LEFT,  13, 0,         true},
280
281     { "+",   2, opid1('+'),         ASSOC_LEFT,  12, 0,         true},
282     { "-",   2, opid1('-'),         ASSOC_LEFT,  12, 0,         true},
283
284     { "<",   2, opid1('<'),         ASSOC_LEFT,  10, 0,         false},
285     { ">",   2, opid1('>'),         ASSOC_LEFT,  10, 0,         false},
286     { "<=",  2, opid2('<','='),     ASSOC_LEFT,  10, 0,         false},
287     { ">=",  2, opid2('>','='),     ASSOC_LEFT,  10, 0,         false},
288     { "==",  2, opid2('=','='),     ASSOC_LEFT,  10, 0,         true},
289     { "!=",  2, opid2('!','='),     ASSOC_LEFT,  10, 0,         true},
290
291     { "=",   2, opid1('='),         ASSOC_RIGHT, 8,  0,         false},
292     { "+=",  2, opid2('+','='),     ASSOC_RIGHT, 8,  0,         false},
293     { "-=",  2, opid2('-','='),     ASSOC_RIGHT, 8,  0,         false},
294     { "*=",  2, opid2('*','='),     ASSOC_RIGHT, 8,  0,         false},
295     { "/=",  2, opid2('/','='),     ASSOC_RIGHT, 8,  0,         false},
296     { "%=",  2, opid2('%','='),     ASSOC_RIGHT, 8,  0,         false},
297     { "&=",  2, opid2('&','='),     ASSOC_RIGHT, 8,  0,         false},
298     { "|=",  2, opid2('|','='),     ASSOC_RIGHT, 8,  0,         false},
299
300     { "&&",  2, opid2('&','&'),     ASSOC_LEFT,  5,  0,         true},
301     { "||",  2, opid2('|','|'),     ASSOC_LEFT,  5,  0,         true},
302
303     { ",",   2, opid1(','),         ASSOC_LEFT,  2,  0,         false},
304 };
305 extern const oper_info *operators;
306 extern size_t           operator_count;
307
308 #endif