]> git.xonotic.org Git - xonotic/gmqcc.git/blob - lexer.h
index operator actually has 2 operands, not 0
[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         MEM_VECTOR_MAKE(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 static const char *_tokennames[] = {
73     "TOKEN_START",
74     "TOKEN_IDENT",
75     "TOKEN_TYPENAME",
76     "TOKEN_OPERATOR",
77     "TOKEN_KEYWORD",
78     "TOKEN_DOTS",
79     "TOKEN_STRINGCONST",
80     "TOKEN_CHARCONST",
81     "TOKEN_VECTORCONST",
82     "TOKEN_INTCONST",
83     "TOKEN_FLOATCONST",
84     "TOKEN_WHITE",
85     "TOKEN_EOL",
86     "TOKEN_EOF",
87     "TOKEN_ERROR",
88     "TOKEN_FATAL",
89 };
90 typedef int
91 _all_tokennames_added_[
92         ((TOKEN_FATAL - TOKEN_START + 1) ==
93          (sizeof(_tokennames)/sizeof(_tokennames[0])))
94         ? 1 : -1];
95
96 typedef struct {
97     char *name;
98     int   value;
99 } frame_macro;
100
101 typedef struct {
102         FILE   *file;
103         char   *name;
104         size_t  line;
105         size_t  sline; /* line at the start of a token */
106
107         char    peek[256];
108         size_t  peekpos;
109
110         bool    eof;
111
112         token   tok; /* not a pointer anymore */
113
114         struct {
115             bool noops;
116             bool nodigraphs; /* used when lexing string constants */
117             bool preprocessing; /* whitespace and EOLs become actual tokens */
118         } flags;
119
120     int framevalue;
121         MEM_VECTOR_MAKE(frame_macro, frames);
122         char *modelname;
123 } lex_file;
124
125 MEM_VECTOR_PROTO(lex_file, char, token);
126
127 lex_file* lex_open (const char *file);
128 void      lex_close(lex_file   *lex);
129 int       lex_do   (lex_file   *lex);
130 void      lex_cleanup(void);
131
132 /* Parser
133  *
134  */
135
136 enum {
137     ASSOC_LEFT,
138     ASSOC_RIGHT
139 };
140
141 #define OP_SUFFIX 1
142 #define OP_PREFIX 2
143
144 typedef struct {
145     const char   *op;
146     unsigned int operands;
147     unsigned int id;
148     unsigned int assoc;
149     unsigned int prec;
150     unsigned int flags;
151 } oper_info;
152
153 #define opid1(a) (a)
154 #define opid2(a,b) ((a<<8)|b)
155 #define opid3(a,b,c) ((a<<16)|(b<<8)|c)
156
157 static const oper_info c_operators[] = {
158     { "(",   0, opid1('('),         ASSOC_LEFT,  99, OP_PREFIX}, /* paren expression - non function call */
159
160     { "++",  1, opid3('S','+','+'), ASSOC_LEFT,  16, OP_SUFFIX},
161     { "--",  1, opid3('S','-','-'), ASSOC_LEFT,  16, OP_SUFFIX},
162
163     { ".",   2, opid1('.'),         ASSOC_LEFT,  15, 0 },
164     { "(",   0, opid1('('),         ASSOC_LEFT,  15, 0 }, /* function call */
165     { "[",   2, opid1('['),         ASSOC_LEFT,  15, 0 }, /* array subscript */
166
167     { "!",   1, opid2('!', 'P'),    ASSOC_RIGHT, 14, OP_PREFIX },
168     { "~",   1, opid2('~', 'P'),    ASSOC_RIGHT, 14, OP_PREFIX },
169     { "+",   1, opid2('+','P'),     ASSOC_RIGHT, 14, OP_PREFIX },
170     { "-",   1, opid2('-','P'),     ASSOC_RIGHT, 14, OP_PREFIX },
171     { "++",  1, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX },
172     { "--",  1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX },
173 /*  { "&",   1, opid2('&','P'),     ASSOC_RIGHT, 14, OP_PREFIX }, */
174
175     { "*",   2, opid1('*'),         ASSOC_LEFT,  13, 0 },
176     { "/",   2, opid1('/'),         ASSOC_LEFT,  13, 0 },
177     { "%",   2, opid1('%'),         ASSOC_LEFT,  13, 0 },
178
179     { "+",   2, opid1('+'),         ASSOC_LEFT,  12, 0 },
180     { "-",   2, opid1('-'),         ASSOC_LEFT,  12, 0 },
181
182     { "<<",  2, opid2('<','<'),     ASSOC_LEFT,  11, 0 },
183     { ">>",  2, opid2('>','>'),     ASSOC_LEFT,  11, 0 },
184
185     { "<",   2, opid1('<'),         ASSOC_LEFT,  10, 0 },
186     { ">",   2, opid1('>'),         ASSOC_LEFT,  10, 0 },
187     { "<=",  2, opid2('<','='),     ASSOC_LEFT,  10, 0 },
188     { ">=",  2, opid2('>','='),     ASSOC_LEFT,  10, 0 },
189
190     { "==",  2, opid2('=','='),     ASSOC_LEFT,  9,  0 },
191     { "!=",  2, opid2('!','='),     ASSOC_LEFT,  9,  0 },
192
193     { "&",   2, opid1('&'),         ASSOC_LEFT,  8,  0 },
194
195     { "^",   2, opid1('^'),         ASSOC_LEFT,  7,  0 },
196
197     { "|",   2, opid1('|'),         ASSOC_LEFT,  6,  0 },
198
199     { "&&",  2, opid2('&','&'),     ASSOC_LEFT,  5,  0 },
200
201     { "||",  2, opid2('|','|'),     ASSOC_LEFT,  4,  0 },
202
203     { "?",   3, opid2('?',':'),     ASSOC_RIGHT, 3,  0 },
204
205     { "=",   2, opid1('='),         ASSOC_RIGHT, 2,  0 },
206     { "+=",  2, opid2('+','='),     ASSOC_RIGHT, 2,  0 },
207     { "-=",  2, opid2('-','='),     ASSOC_RIGHT, 2,  0 },
208     { "*=",  2, opid2('*','='),     ASSOC_RIGHT, 2,  0 },
209     { "/=",  2, opid2('/','='),     ASSOC_RIGHT, 2,  0 },
210     { "%=",  2, opid2('%','='),     ASSOC_RIGHT, 2,  0 },
211     { ">>=", 2, opid3('>','>','='), ASSOC_RIGHT, 2,  0 },
212     { "<<=", 2, opid3('<','<','='), ASSOC_RIGHT, 2,  0 },
213     { "&=",  2, opid2('&','='),     ASSOC_RIGHT, 2,  0 },
214     { "^=",  2, opid2('^','='),     ASSOC_RIGHT, 2,  0 },
215     { "|=",  2, opid2('|','='),     ASSOC_RIGHT, 2,  0 },
216
217     { ",",   2, opid1(','),         ASSOC_LEFT,  1,  0 }
218 };
219 static const size_t c_operator_count = (sizeof(c_operators) / sizeof(c_operators[0]));
220
221 static const oper_info qcc_operators[] = {
222     { "(",   0, opid1('('),         ASSOC_LEFT,  99, OP_PREFIX}, /* paren expression - non function call */
223
224     { ".",   2, opid1('.'),         ASSOC_LEFT,  15, 0 },
225     { "(",   0, opid1('('),         ASSOC_LEFT,  15, 0 }, /* function call */
226     { "[",   2, opid1('['),         ASSOC_LEFT,  15, 0 }, /* array subscript */
227
228     { "!",   1, opid2('!', 'P'),    ASSOC_RIGHT, 14, OP_PREFIX },
229     { "+",   1, opid2('+','P'),     ASSOC_RIGHT, 14, OP_PREFIX },
230     { "-",   1, opid2('-','P'),     ASSOC_RIGHT, 14, OP_PREFIX },
231
232     { "*",   2, opid1('*'),         ASSOC_LEFT,  13, 0 },
233     { "/",   2, opid1('/'),         ASSOC_LEFT,  13, 0 },
234     { "&",   2, opid1('&'),         ASSOC_LEFT,  13, 0 },
235     { "|",   2, opid1('|'),         ASSOC_LEFT,  13, 0 },
236
237     { "+",   2, opid1('+'),         ASSOC_LEFT,  12, 0 },
238     { "-",   2, opid1('-'),         ASSOC_LEFT,  12, 0 },
239
240     { "<",   2, opid1('<'),         ASSOC_LEFT,  10, 0 },
241     { ">",   2, opid1('>'),         ASSOC_LEFT,  10, 0 },
242     { "<=",  2, opid2('<','='),     ASSOC_LEFT,  10, 0 },
243     { ">=",  2, opid2('>','='),     ASSOC_LEFT,  10, 0 },
244     { "==",  2, opid2('=','='),     ASSOC_LEFT,  10,  0 },
245     { "!=",  2, opid2('!','='),     ASSOC_LEFT,  10,  0 },
246
247     { "=",   2, opid1('='),         ASSOC_RIGHT, 8,  0 },
248     { "+=",  2, opid2('+','='),     ASSOC_RIGHT, 8,  0 },
249     { "-=",  2, opid2('-','='),     ASSOC_RIGHT, 8,  0 },
250     { "*=",  2, opid2('*','='),     ASSOC_RIGHT, 8,  0 },
251     { "/=",  2, opid2('/','='),     ASSOC_RIGHT, 8,  0 },
252     { "%=",  2, opid2('%','='),     ASSOC_RIGHT, 8,  0 },
253     { "&=",  2, opid2('&','='),     ASSOC_RIGHT, 8,  0 },
254     { "|=",  2, opid2('|','='),     ASSOC_RIGHT, 8,  0 },
255
256     { "&&",  2, opid2('&','&'),     ASSOC_LEFT,  5,  0 },
257     { "||",  2, opid2('|','|'),     ASSOC_LEFT,  5,  0 },
258
259     { ",",   2, opid1(','),         ASSOC_LEFT,  1,  0 }
260 };
261 static const size_t qcc_operator_count = (sizeof(qcc_operators) / sizeof(qcc_operators[0]));
262
263 extern const oper_info *operators;
264 extern size_t           operator_count;
265 void lexerror(lex_file*, const char *fmt, ...);
266
267 #endif