]> git.xonotic.org Git - xonotic/gmqcc.git/blob - parse.c
Cleaups and README
[xonotic/gmqcc.git] / parse.c
1 /*
2  * Copyright (C) 2012 
3  *      Dale Weiler
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is furnished to do
10  * so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 #include <limits.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "gmqcc.h"
27
28 /*
29  * These are not lexical tokens:  These are parse tree types.  Most people
30  * perform tokenizing on language punctuation which is wrong.  That stuff
31  * is technically already tokenized, it just needs to be parsed into a tree
32  */
33 #define PARSE_TYPE_DO       0
34 #define PARSE_TYPE_ELSE     1
35 #define PARSE_TYPE_IF       2
36 #define PARSE_TYPE_WHILE    3
37 #define PARSE_TYPE_BREAK    4
38 #define PARSE_TYPE_CONTINUE 5
39 #define PARSE_TYPE_RETURN   6
40 #define PARSE_TYPE_GOTO     7
41 #define PARSE_TYPE_FOR      8   // extension
42 #define PARSE_TYPE_VOID     9
43 #define PARSE_TYPE_STRING   10
44 #define PARSE_TYPE_FLOAT    11
45 #define PARSE_TYPE_VECTOR   12
46 #define PARSE_TYPE_ENTITY   13
47 #define PARSE_TYPE_LAND     14
48 #define PARSE_TYPE_LOR      15
49 #define PARSE_TYPE_LTEQ     16
50 #define PARSE_TYPE_GTEQ     17
51 #define PARSE_TYPE_EQEQ     18
52 #define PARSE_TYPE_LNEQ     19
53 #define PARSE_TYPE_COMMA    20
54 #define PARSE_TYPE_LNOT     21
55 #define PARSE_TYPE_STAR     22
56 #define PARSE_TYPE_DIVIDE   23
57 #define PARSE_TYPE_LPARTH   24
58 #define PARSE_TYPE_RPARTH   25
59 #define PARSE_TYPE_MINUS    26
60 #define PARSE_TYPE_ADD      27
61 #define PARSE_TYPE_EQUAL    28
62 #define PARSE_TYPE_LSS      29 // left subscript
63 #define PARSE_TYPE_RSS      30
64 #define PARSE_TYPE_LBS      31 // left  bracket scope
65 #define PARSE_TYPE_RBS      32 // right bracket scope
66 #define PARSE_TYPE_ELIP     33 // ...
67 #define PARSE_TYPE_DOT      34
68 #define PARSE_TYPE_LT       35
69 #define PARSE_TYPE_GT       36
70 #define PARSE_TYPE_BAND     37
71 #define PARSE_TYPE_BOR      38
72 #define PARSE_TYPE_DONE     39 // finished statement
73
74 /*
75  * Adds a parse type to the parse tree, this is where all the hard
76  * work actually begins.
77  */
78 #define PARSE_TREE_ADD(X)                                        \
79         do {                                                         \
80                 parsetree->next       = mem_a(sizeof(struct parsenode)); \
81                 parsetree->next->next = NULL;                            \
82                 parsetree->next->type = (X);                             \
83                 parsetree             = parsetree->next;                 \
84         } while (0)
85
86 static const char *const parse_punct[] = {
87         "&&", "||", "<=", ">=", "==", "!=", ";", ",", "!", "*",
88         "/" , "(" , ")" , "-" , "+" , "=" , "[" , "]", "{", "}", "...",
89         "." , "<" , ">" , "&" , "|" , NULL
90 };
91
92 #define STORE(X) {     \
93         printf(X);         \
94         break;             \
95 }
96
97 void parse_debug(struct parsenode *tree) {
98         while (tree && tree->next != NULL) {
99                 /* skip blanks */
100                 if (tree->type == 0) {
101                         tree = tree->next;
102                         continue;
103                 }
104                         
105                 switch (tree->type) {
106                         case PARSE_TYPE_ADD:       STORE("ADD    \n");
107                         case PARSE_TYPE_BAND:      STORE("BITAND \n");
108                         case PARSE_TYPE_BOR:       STORE("BITOR  \n");
109                         case PARSE_TYPE_BREAK:     STORE("BREAK  \n");
110                         case PARSE_TYPE_COMMA:     STORE("SEPERATOR\n");
111                         case PARSE_TYPE_CONTINUE:  STORE("CONTINUE\n");
112                         case PARSE_TYPE_DIVIDE:    STORE("DIVIDE\n");
113                         case PARSE_TYPE_EQUAL:     STORE("ASSIGNMENT\n");
114                         case PARSE_TYPE_GOTO:      STORE("GOTO\n");
115                         case PARSE_TYPE_DOT:       STORE("DOT\n");
116
117
118                         case PARSE_TYPE_ELIP:      STORE("DECLTYPE: VALIST\n");
119                         case PARSE_TYPE_ENTITY:    STORE("DECLTYPE: ENTITY\n");
120                         case PARSE_TYPE_FLOAT:     STORE("DECLTYPE: FLOAT\n");
121                         
122                         case PARSE_TYPE_GT:        STORE("TEST:     GREATER THAN\n");
123                         case PARSE_TYPE_LT:        STORE("TEST:     LESS THAN\n");
124                         case PARSE_TYPE_GTEQ:      STORE("TEST:     GREATER THAN OR EQUAL\n");
125                         case PARSE_TYPE_LTEQ:      STORE("TEST:     LESS THAN OR EQUAL\n");
126                         case PARSE_TYPE_LNEQ:      STORE("TEST:     NOT EQUAL\n");
127                         case PARSE_TYPE_EQEQ:      STORE("TEST:     EQUAL-EQUAL\n");
128                         
129                         case PARSE_TYPE_LBS:       break;
130                         case PARSE_TYPE_RBS:       break;
131                         
132                         case PARSE_TYPE_LAND:      STORE("LOGICAL:  AND\n");
133                         case PARSE_TYPE_LNOT:      STORE("LOGICAL:  NOT\n");
134                         case PARSE_TYPE_LOR:       STORE("LOGICAL:  OR\n");
135                         case PARSE_TYPE_LPARTH:    STORE("PARTH:    END\n");
136                         case PARSE_TYPE_RPARTH:    STORE("PARTH:    BEG\n");
137                         
138                         case PARSE_TYPE_FOR:       STORE("LOOP:     FOR\n");
139                         case PARSE_TYPE_DO:        STORE("LOOP:     DO\n");
140                         case PARSE_TYPE_ELSE:      STORE("BLOCK:    ELSE\n");
141                         case PARSE_TYPE_IF:        STORE("BLOCK:    IF\n");
142                 }
143                 tree = tree->next;
144         }
145 }
146
147 /*
148  * This just skips the token and throws it in the parse tree for later
149  * checking / optimization / codegen, it doesn't do anything with it
150  * like syntax check for legal use -- like it should as it's a TODO item
151  * which is not implemented
152  */
153 #define PARSE_TODO(X) {       \
154         token = lex_token(file);  \
155         PARSE_TREE_ADD(X);        \
156         break;                    \
157 }
158
159 int parse(struct lex_file *file) {
160         struct parsenode *parsetree = NULL;
161         struct parsenode *parseroot = NULL;
162         
163         /*
164          * Allocate memory for our parse tree:
165          * the parse tree is just a singly linked list which will contain
166          * all the data for code generation.
167          */
168         if (!parseroot) {
169                 parseroot = mem_a(sizeof(struct parsenode));
170                 if (!parseroot)
171                         return error(ERROR_INTERNAL, "Ran out of memory", " ");
172                 parsetree = parseroot;
173                 parsetree = parseroot;
174         }
175         
176         int     token = 0;
177         while ((token = lex_token(file)) != ERROR_LEX      && \
178                     token                    != ERROR_COMPILER && \
179                     token                    != ERROR_INTERNAL && \
180                     token                    != ERROR_PARSE    && \
181                     token                    != ERROR_PREPRO   && file->length >= 0) {
182                 switch (token) {
183                         case TOKEN_IF:
184                                 token = lex_token(file);
185                                 while ((token == ' ' || token == '\n') && file->length >= 0)
186                                         token = lex_token(file);
187                                         
188                                 if (token != '(')
189                                         error(ERROR_PARSE, "Expected `(` after if\n", "");
190                                         
191                                 PARSE_TREE_ADD(PARSE_TYPE_IF);
192                                 break;
193                         case TOKEN_ELSE:
194                                 token = lex_token(file);
195                                 while ((token == ' ' || token == '\n') && file->length >= 0)
196                                         token = lex_token(file);
197                                         
198                                 PARSE_TREE_ADD(PARSE_TYPE_ELSE);
199                                 break;
200                         case TOKEN_FOR:
201                                 token = lex_token(file);
202                                 while ((token == ' ' || token == '\n') && file->length >= 0)
203                                         token = lex_token(file);
204                                         
205                                 PARSE_TREE_ADD(PARSE_TYPE_FOR);
206                                 break;
207                                 
208                         case LEX_IDENT:
209                                 token = lex_token(file);
210                                 printf("FOO: %s\n", file->lastok);
211                                 break;
212                                 
213                         case TOKEN_TYPEDEF: {
214                                 char *f = NULL;
215                                 char *t = NULL;
216                                 token = lex_token(file); 
217                                 token = lex_token(file); f = strdup(file->lastok);
218                                 token = lex_token(file); 
219                                 token = lex_token(file); t = strdup(file->lastok);
220                                 
221                                 typedef_add(f, t);
222                                 
223                                 /* free new strings */
224                                 mem_d(f);
225                                 mem_d(t);
226                                 break;
227                         }
228                                 
229                                 
230                         case TOKEN_DO:        PARSE_TODO(PARSE_TYPE_DO);
231                         case TOKEN_WHILE:     PARSE_TODO(PARSE_TYPE_WHILE);
232                         case TOKEN_BREAK:     PARSE_TODO(PARSE_TYPE_BREAK);
233                         case TOKEN_CONTINUE:  PARSE_TODO(PARSE_TYPE_CONTINUE);
234                         case TOKEN_RETURN:    PARSE_TODO(PARSE_TYPE_RETURN);
235                         case TOKEN_GOTO:      PARSE_TODO(PARSE_TYPE_GOTO);
236                         case TOKEN_VOID:      PARSE_TODO(PARSE_TYPE_VOID);
237                         case TOKEN_STRING:    PARSE_TODO(PARSE_TYPE_STRING);
238                         case TOKEN_FLOAT:     PARSE_TODO(PARSE_TYPE_FLOAT);
239                         case TOKEN_VECTOR:    PARSE_TODO(PARSE_TYPE_VECTOR);
240                         case TOKEN_ENTITY:    PARSE_TODO(PARSE_TYPE_ENTITY);
241                                 
242                         /*
243                          * From here down is all language punctuation:  There is no
244                          * need to actual create tokens from these because they're already
245                          * tokenized as these individual tokens (which are in a special area
246                          * of the ascii table which doesn't conflict with our other tokens
247                          * which are higer than the ascii table.
248                          */
249                         case '&':               /* &  */
250                                 token = lex_token(file);
251                                 if (token == '&') { /* && */
252                                         token = lex_token(file);
253                                         PARSE_TREE_ADD(PARSE_TYPE_LAND);
254                                         break;
255                                 }
256                                 PARSE_TREE_ADD(PARSE_TYPE_BAND);
257                                 break;
258                         case '|':               /* |  */
259                                 token = lex_token(file);
260                                 if (token == '|') { /* || */
261                                         token = lex_token(file);
262                                         PARSE_TREE_ADD(PARSE_TYPE_LOR);
263                                         break;
264                                 }
265                                 PARSE_TREE_ADD(PARSE_TYPE_BOR);
266                                 break;
267                         case '!':
268                                 token = lex_token(file);
269                                 if (token == '=') { /* != */
270                                         token = lex_token(file);
271                                         PARSE_TREE_ADD(PARSE_TYPE_LNEQ);
272                                         break;
273                                 }
274                                 PARSE_TREE_ADD(PARSE_TYPE_LNOT);
275                                 break;
276                         case '<':               /* <  */
277                                 token = lex_token(file);
278                                 if (token == '=') { /* <= */
279                                         token = lex_token(file);
280                                         PARSE_TREE_ADD(PARSE_TYPE_LTEQ);
281                                         break;
282                                 }
283                                 PARSE_TREE_ADD(PARSE_TYPE_LT);
284                                 break;
285                         case '>':               /* >  */
286                                 token = lex_token(file);
287                                 if (token == '=') { /* >= */
288                                         token = lex_token(file);
289                                         PARSE_TREE_ADD(PARSE_TYPE_GTEQ);
290                                         break;
291                                 }
292                                 PARSE_TREE_ADD(PARSE_TYPE_GT);
293                                 break;
294                         case '=':
295                                 token = lex_token(file);
296                                 if (token == '=') { /* == */
297                                         token = lex_token(file);
298                                         PARSE_TREE_ADD(PARSE_TYPE_EQEQ);
299                                         break;
300                                 }
301                                 PARSE_TREE_ADD(PARSE_TYPE_EQUAL);
302                                 break;
303                         case ';':
304                                 token = lex_token(file);
305                                 PARSE_TREE_ADD(PARSE_TYPE_DONE);
306                                 break;
307                         case '-':
308                                 token = lex_token(file);
309                                 PARSE_TREE_ADD(PARSE_TYPE_MINUS);
310                                 break;
311                         case '+':
312                                 token = lex_token(file);
313                                 PARSE_TREE_ADD(PARSE_TYPE_ADD);
314                                 break;
315                         case '(':
316                                 token = lex_token(file);
317                                 PARSE_TREE_ADD(PARSE_TYPE_LPARTH);
318                                 break;
319                         case ')':
320                                 token = lex_token(file);
321                                 PARSE_TREE_ADD(PARSE_TYPE_RPARTH);
322                                 break;
323                         case '{':
324                                 token = lex_token(file);
325                                 PARSE_TREE_ADD(PARSE_TYPE_LBS);
326                                 break;
327                         case '}':
328                                 token = lex_token(file);
329                                 PARSE_TREE_ADD(PARSE_TYPE_RBS);
330                                 break;
331                 }
332         }
333         parse_debug(parseroot);
334         lex_reset(file);
335         
336         return 1;
337 }