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