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