Mercurial > hg > index.cgi
annotate lwcc/cc-parse.c @ 544:f12c767c363e
Fix typo in manual.
I wonder just what "pneumonics" are....
author | William Astle <lost@l-w.ca> |
---|---|
date | Mon, 14 Nov 2022 18:01:32 -0700 |
parents | 7e8298f7bc0a |
children |
rev | line source |
---|---|
498 | 1 /* |
2 lwcc/cc-parse.c | |
3 | |
4 Copyright © 2019 William Astle | |
5 | |
6 This file is part of LWTOOLS. | |
7 | |
8 LWTOOLS is free software: you can redistribute it and/or modify it under the | |
9 terms of the GNU General Public License as published by the Free Software | |
10 Foundation, either version 3 of the License, or (at your option) any later | |
11 version. | |
12 | |
13 This program is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 more details. | |
17 | |
18 You should have received a copy of the GNU General Public License along with | |
19 this program. If not, see <http://www.gnu.org/licenses/>. | |
20 */ | |
21 | |
22 #include <string.h> | |
23 | |
24 #include <lw_alloc.h> | |
25 #include <lw_string.h> | |
26 | |
27 #include "cpp.h" | |
28 #include "tree.h" | |
29 | |
30 #define TOK_KW_IF -1 | |
31 #define TOK_KW_ELSE -2 | |
32 #define TOK_KW_WHILE -3 | |
33 #define TOK_KW_DO -4 | |
34 #define TOK_KW_FOR -5 | |
35 #define TOK_KW_VOID -6 | |
36 #define TOK_KW_INT -7 | |
37 #define TOK_KW_CHAR -8 | |
38 #define TOK_KW_SHORT -9 | |
39 #define TOK_KW_LONG -10 | |
40 #define TOK_KW_UNSIGNED -11 | |
41 #define TOK_KW_SIGNED -12 | |
42 #define TOK_KW_FLOAT -13 | |
43 #define TOK_KW_DOUBLE -14 | |
44 #define TOK_KW_STRUCT -15 | |
45 #define TOK_KW_UNION -16 | |
46 #define TOK_KW_TYPEDEF -17 | |
47 #define TOK_KW_STATIC -18 | |
48 #define TOK_KW_SWITCH -19 | |
49 #define TOK_KW_CASE -20 | |
50 #define TOK_KW_DEFAULT -21 | |
51 #define TOK_KW_BREAK -22 | |
52 #define TOK_KW_CONTINUE -23 | |
53 #define TOK_KW_CONST -24 | |
54 #define TOK_KW_AUTO -25 | |
55 #define TOK_KW_ENUM -26 | |
56 #define TOK_KW_REGISTER -27 | |
57 #define TOK_KW_SIZEOF -28 | |
58 #define TOK_KW_VOLATILE -29 | |
59 #define TOK_KW_RETURN -30 | |
60 #define TOK_KW_EXTERN -31 | |
61 #define TOK_KW_GOTO -32 | |
62 #define TOK_TYPENAME -100 | |
63 #define TOK_CONST_INT -150 | |
64 | |
65 static struct { int tok; char *word; } keyword_list[] = { | |
66 { TOK_KW_IF, "if" }, | |
67 { TOK_KW_ELSE, "else" }, | |
68 { TOK_KW_WHILE, "while" }, | |
69 { TOK_KW_DO, "do" }, | |
70 { TOK_KW_FOR, "for" }, | |
71 { TOK_KW_VOID, "void" }, | |
72 { TOK_KW_INT, "int" }, | |
73 { TOK_KW_CHAR, "char" }, | |
74 { TOK_KW_SHORT, "short" }, | |
75 { TOK_KW_LONG, "long" }, | |
76 { TOK_KW_UNSIGNED, "unsigned" }, | |
77 { TOK_KW_SIGNED, "signed" }, | |
78 { TOK_KW_FLOAT, "float" }, | |
79 { TOK_KW_DOUBLE, "double" }, | |
80 { TOK_KW_STRUCT, "struct" }, | |
81 { TOK_KW_UNION, "union" }, | |
82 { TOK_KW_TYPEDEF, "typedef" }, | |
83 { TOK_KW_STATIC, "static" }, | |
84 { TOK_KW_SWITCH, "switch" }, | |
85 { TOK_KW_CASE, "case" }, | |
86 { TOK_KW_DEFAULT, "default" }, | |
87 { TOK_KW_BREAK, "break" }, | |
88 { TOK_KW_CONTINUE, "continue" }, | |
89 { TOK_KW_CONST, "const" }, | |
90 { TOK_KW_AUTO, "auto" }, | |
91 { TOK_KW_ENUM, "enum" }, | |
92 { TOK_KW_REGISTER, "register" }, | |
93 { TOK_KW_SIZEOF, "sizeof" }, | |
94 { TOK_KW_VOLATILE, "volatile" }, | |
95 { TOK_KW_RETURN, "return" }, | |
96 { TOK_KW_EXTERN, "extern" }, | |
97 { TOK_KW_GOTO, "goto" }, | |
98 { TOK_NONE, "" } | |
99 }; | |
100 | |
101 | |
102 struct parser_state | |
103 { | |
104 struct preproc_info *pp; // preprocessor data | |
105 struct token *curtok; // the current token | |
106 }; | |
107 | |
108 | |
109 struct token *parse_next(struct parser_state *ps) | |
110 { | |
111 struct token *tok; | |
112 int i; | |
113 | |
114 for (;;) | |
115 { | |
116 tok = preproc_next(ps -> pp); | |
117 if (tok -> ttype == TOK_WSPACE) | |
118 continue; | |
119 if (tok -> ttype == TOK_EOL) | |
120 continue; | |
121 if (tok -> ttype == TOK_CHAR) | |
122 { | |
123 // random character | |
124 fprintf(stderr, "Random character %02x\n", tok -> strval[0]); | |
125 if (tok -> strval[0] < 32 || tok -> strval[0] > 126) | |
126 continue; | |
127 } | |
128 break; | |
129 } | |
130 if (tok -> ttype == TOK_IDENT) | |
131 { | |
132 // convert identifier tokens to their respective meanings | |
133 for (i = 0; keyword_list[i].tok != TOK_NONE; i++) | |
134 { | |
135 if (strcmp(keyword_list[i].word, tok -> strval) == 0) | |
136 { | |
137 tok -> ttype = keyword_list[i].tok; | |
138 goto out; | |
139 } | |
140 } | |
141 // check for registered types here | |
142 } | |
143 else if (tok -> ttype == TOK_NUMBER) | |
144 { | |
145 // look for anything that isn't 0-9 | |
146 for (i = 0; tok -> strval[i]; i++) | |
147 { | |
148 if (tok -> strval[i] < '0' || tok -> strval[i] > '9') | |
149 break; | |
150 } | |
151 if (tok -> strval[i] == 0) | |
152 tok -> ttype = TOK_CONST_INT; | |
153 } | |
154 out: | |
155 fprintf(stderr, "Lexed: "); | |
156 token_print(tok, stderr); | |
157 fprintf(stderr, " (%d)\n", tok -> ttype); | |
158 if (ps -> curtok) | |
159 token_free(ps -> curtok); | |
160 ps -> curtok = tok; | |
161 return tok; | |
162 } | |
163 | |
164 void parse_generr(struct parser_state *ps, char *tag) | |
165 { | |
166 fprintf(stderr, "(%s) Unexpected token (%d): ", tag, ps -> curtok -> ttype); | |
167 token_print(ps -> curtok, stderr); | |
168 fprintf(stderr, "\n"); | |
169 | |
170 } | |
171 | |
502 | 172 node_t *parse_expr_real(struct parser_state *ps, int prec); |
173 | |
506
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
174 // parse an elementary type (int, etc.) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
175 node_t *parse_elem_type(struct parser_state *ps) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
176 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
177 int sgn = -1; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
178 int nt = -1; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
179 int nn = 1; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
180 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
181 if (ps -> curtok -> ttype == TOK_KW_SIGNED) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
182 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
183 sgn = 1; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
184 parse_next(ps); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
185 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
186 else if (ps -> curtok -> ttype == TOK_KW_UNSIGNED) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
187 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
188 sgn = 0; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
189 parse_next(ps); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
190 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
191 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
192 switch (ps -> curtok -> ttype) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
193 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
194 // NOTE: char is unsigned by default |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
195 case TOK_KW_CHAR: |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
196 if (sgn == -1 || sgn == 0) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
197 nt = NODE_TYPE_UCHAR; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
198 else |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
199 nt = NODE_TYPE_CHAR; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
200 break; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
201 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
202 case TOK_KW_SHORT: |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
203 nt = sgn ? NODE_TYPE_SHORT : NODE_TYPE_USHORT; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
204 break; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
205 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
206 case TOK_KW_INT: |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
207 nt = sgn ? NODE_TYPE_INT : NODE_TYPE_UINT; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
208 break; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
209 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
210 case TOK_KW_LONG: |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
211 parse_next(ps); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
212 if (ps -> curtok -> ttype == TOK_KW_LONG) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
213 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
214 nt = sgn ? NODE_TYPE_LONGLONG : NODE_TYPE_ULONGLONG; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
215 break; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
216 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
217 nn = 0; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
218 nt = sgn ? NODE_TYPE_LONG : NODE_TYPE_ULONG; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
219 break; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
220 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
221 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
222 if (nt == -1) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
223 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
224 if (sgn == -1) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
225 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
226 return NULL; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
227 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
228 else |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
229 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
230 nt = sgn ? NODE_TYPE_INT : NODE_TYPE_UINT; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
231 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
232 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
233 else if (nn) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
234 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
235 parse_next(ps); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
236 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
237 return node_create(nt); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
238 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
239 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
240 // if ident is non-zero, accept an identifier as part of the type; otherwise |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
241 // do not accept an identifier; currently a stub |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
242 node_t *parse_type(struct parser_state *ps, int ident) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
243 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
244 node_t *rv; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
245 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
246 // see if we have an elementary type |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
247 rv = parse_elem_type(ps); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
248 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
249 // look for "struct", etc. |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
250 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
251 // look for pointer indicator(s) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
252 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
253 // look for identifier if wanted/allowed |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
254 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
255 // look for array indicator or function parameter list |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
256 return rv; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
257 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
258 |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
259 node_t *parse_term_real(struct parser_state *ps) |
498 | 260 { |
506
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
261 node_t *rv, *rv2; |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
262 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
263 switch (ps -> curtok -> ttype) |
498 | 264 { |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
265 case TOK_CONST_INT: |
498 | 266 rv = node_create(NODE_CONST_INT, ps -> curtok -> strval); |
267 parse_next(ps); | |
268 return rv; | |
506
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
269 |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
270 // opening paren: either grouping or type cast |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
271 case TOK_OPAREN: |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
272 parse_next(ps); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
273 // parse a type without an identifier |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
274 rv2 = parse_type(ps, 0); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
275 if (rv2) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
276 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
277 if (ps -> curtok -> ttype != TOK_CPAREN) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
278 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
279 node_destroy(rv2); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
280 parse_generr(ps, "missing ) on type cast"); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
281 return NULL; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
282 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
283 parse_next(ps); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
284 // detect C99 compound literal here |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
285 rv = parse_expr_real(ps, 175); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
286 if (!rv) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
287 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
288 node_destroy(rv); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
289 return NULL; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
290 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
291 return node_create(NODE_TYPECAST, rv2, rv); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
292 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
293 // grouping |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
294 rv = parse_expr_real(ps, 0); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
295 if (ps -> curtok -> ttype != TOK_CPAREN) |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
296 { |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
297 node_destroy(rv); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
298 parse_generr(ps, "missing ) on expression grouping"); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
299 return NULL; |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
300 } |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
301 parse_next(ps); |
7e8298f7bc0a
Add basic syntax for typecasting
William Astle <lost@l-w.ca>
parents:
502
diff
changeset
|
302 return rv; |
498 | 303 } |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
304 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
305 parse_generr(ps, "term"); |
498 | 306 return NULL; |
307 } | |
308 | |
502 | 309 node_t *parse_expr_fncall(struct parser_state *ps, node_t *term1) |
310 { | |
311 if (ps -> curtok -> ttype != TOK_CPAREN) | |
312 { | |
313 node_destroy(term1); | |
314 parse_generr(ps, "missing )"); | |
315 return NULL; | |
316 } | |
317 parse_next(ps); | |
318 return node_create(NODE_OPER_FNCALL, term1, NULL); | |
319 } | |
320 | |
321 node_t *parse_expr_postinc(struct parser_state *ps, node_t *term1) | |
322 { | |
323 return node_create(NODE_OPER_POSTINC, term1); | |
324 } | |
325 | |
326 node_t *parse_expr_postdec(struct parser_state *ps, node_t *term1) | |
327 { | |
328 return node_create(NODE_OPER_POSTDEC, term1); | |
329 } | |
330 | |
331 node_t *parse_expr_subscript(struct parser_state *ps, node_t *term1) | |
332 { | |
333 node_t *term2; | |
334 term2 = parse_expr_real(ps, 0); | |
335 if (!term2) | |
336 { | |
337 node_destroy(term1); | |
338 return NULL; | |
339 } | |
340 if (ps -> curtok -> ttype != TOK_CSQUARE) | |
341 { | |
342 node_destroy(term2); | |
343 node_destroy(term1); | |
344 parse_generr(ps, "missing ]"); | |
345 return NULL; | |
346 } | |
347 parse_next(ps); | |
348 return node_create(NODE_OPER_SUBSCRIPT, term1, term2); | |
349 } | |
350 | |
351 node_t *parse_expr_cond(struct parser_state *ps, node_t *term1) | |
352 { | |
353 node_t *term2, *term3; | |
354 // conditional operator | |
355 // NOTE: the middle operand is evaluated as though it is its own | |
356 // independent expression because the : must appear. The third | |
357 // operand is evaluated at the ternary operator precedence so that | |
358 // subsequent operand binding behaves correctly (if surprisingly). This | |
359 // would be less confusing if the ternary operator was fully bracketed | |
360 // (that is, had a terminator) | |
361 term2 = parse_expr_real(ps, 0); | |
362 if (!term2) | |
363 { | |
364 node_destroy(term1); | |
365 return NULL; | |
366 } | |
367 if (ps -> curtok -> ttype == TOK_COLON) | |
368 { | |
369 parse_next(ps); | |
370 term3 = parse_expr_real(ps, 25); | |
371 if (!term3) | |
372 { | |
373 node_destroy(term1); | |
374 node_destroy(term2); | |
375 return NULL; | |
376 } | |
377 return node_create(NODE_OPER_COND, term1, term2, term3); | |
378 } | |
379 else | |
380 { | |
381 node_destroy(term1); | |
382 node_destroy(term2); | |
383 parse_generr(ps, "missing :"); | |
384 return NULL; | |
385 } | |
386 } | |
387 | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
388 node_t *parse_expr_real(struct parser_state *ps, int prec) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
389 { |
502 | 390 static struct { int tok; int nodetype; int prec; int ra; node_t *(*spec)(struct parser_state *, node_t *); } operlist[] = { |
391 // { TOK_OPAREN, NODE_OPER_FNCALL, 200, 0, parse_expr_fncall }, | |
392 // { TOK_OSQUARE, NODE_OPER_SUBSCRIPT, 200, 0, parse_expr_subscript }, | |
393 // { TOK_ARROW, NODE_OPER_PTRMEM, 200, 0 }, | |
394 // { TOK_DOT, NODE_OPER_OBJMEM, 200, 0 }, | |
395 // { TOK_DBLADD, NODE_OPER_POSTINC, 200, 0, parse_expr_postinc }, | |
396 // { TOK_DBLSUB, NODE_OPER_POSTDEC, 200, 0, parse_expr_postdec }, | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
397 { TOK_STAR, NODE_OPER_TIMES, 150 }, |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
398 { TOK_DIV, NODE_OPER_DIVIDE, 150 }, |
502 | 399 { TOK_MOD, NODE_OPER_MOD, 150 }, |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
400 { TOK_ADD, NODE_OPER_PLUS, 100 }, |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
401 { TOK_SUB, NODE_OPER_MINUS, 100 }, |
502 | 402 { TOK_LSH, NODE_OPER_LSH, 90 }, |
403 { TOK_RSH, NODE_OPER_RSH, 90 }, | |
404 { TOK_LT, NODE_OPER_LT, 80 }, | |
405 { TOK_LE, NODE_OPER_LE, 80 }, | |
406 { TOK_GT, NODE_OPER_GT, 80 }, | |
407 { TOK_GE, NODE_OPER_GE, 80 }, | |
408 { TOK_EQ, NODE_OPER_EQ, 70 }, | |
409 { TOK_NE, NODE_OPER_NE, 70 }, | |
410 { TOK_BWAND, NODE_OPER_BWAND, 60}, | |
411 { TOK_XOR, NODE_OPER_BWXOR, 55 }, | |
412 { TOK_BWOR, NODE_OPER_BWOR, 50 }, | |
413 { TOK_BAND, NODE_OPER_BAND, 40 }, | |
414 { TOK_BOR, NODE_OPER_BOR, 35 }, | |
415 { TOK_QMARK, NODE_OPER_COND, 25, 1, parse_expr_cond }, | |
416 // { TOK_ASS, NODE_OPER_ASS, 20, 1 }, | |
417 // { TOK_ADDASS, NODE_OPER_ADDASS, 20, 1 }, | |
418 // { TOK_SUBASS, NODE_OPER_SUBASS, 20, 1 }, | |
419 // { TOK_MULASS, NODE_OPER_MULASS, 20, 1 }, | |
420 // { TOK_DIVASS, NODE_OPER_DIVASS, 20, 1 }, | |
421 // { TOK_MODASS, NODE_OPER_MODASS, 20, 1 }, | |
422 // { TOK_LSHASS, NODE_OPER_LSHASS, 20, 1 }, | |
423 // { TOK_RSHASS, NODE_OPER_RSHASS, 20, 1 }, | |
424 // { TOK_BWANDASS, NODE_OPER_BWANDASS, 20, 1}, | |
425 // { TOK_BWORASS, NODE_OPER_BWORASS, 20, 1 }, | |
426 // { TOK_XORASS, NODE_OPER_BWXORASS, 20, 1 }, | |
427 { TOK_COMMA, NODE_OPER_COMMA, 1 }, | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
428 { 0, 0, 0 } |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
429 }; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
430 node_t *term1, *term2; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
431 int i; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
432 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
433 term1 = parse_term_real(ps); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
434 if (!term1) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
435 return NULL; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
436 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
437 nextoper: |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
438 for (i = 0; operlist[i].tok; i++) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
439 if (operlist[i].tok == ps -> curtok -> ttype) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
440 break; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
441 fprintf(stderr, "Matched operator: %d, %d\n", operlist[i].tok, operlist[i].prec); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
442 // if we hit the end of the expression, return |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
443 if (operlist[i].tok == 0) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
444 return term1; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
445 |
502 | 446 // is previous operation higher precedence? If so, just return the first term |
447 if (operlist[i].prec < prec) | |
448 return term1; | |
449 | |
450 // is this operator left associative and previous operation is same precedence? | |
451 // if so, just return the first term | |
452 if (operlist[i].ra == 0 && operlist[i].prec == prec) | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
453 return term1; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
454 |
502 | 455 // consume the operator |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
456 parse_next(ps); |
502 | 457 |
458 // special handling | |
459 if (operlist[i].spec) | |
460 { | |
461 term2 = (operlist[i].spec)(ps, term1); | |
462 if (!term2) | |
463 { | |
464 node_destroy(term1); | |
465 return NULL; | |
466 } | |
467 term1 = term2; | |
468 goto nextoper; | |
469 } | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
470 term2 = parse_expr_real(ps, operlist[i].prec); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
471 if (!term2) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
472 { |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
473 parse_generr(ps, "expr"); |
502 | 474 node_destroy(term1); |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
475 } |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
476 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
477 term1 = node_create(operlist[i].nodetype, term1, term2); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
478 term2 = NULL; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
479 goto nextoper; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
480 } |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
481 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
482 node_t *parse_expr(struct parser_state *ps) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
483 { |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
484 return parse_expr_real(ps, 0); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
485 } |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
486 |
498 | 487 node_t *parse_statement(struct parser_state *ps) |
488 { | |
489 node_t *rv; | |
490 node_t *n; | |
491 | |
492 switch (ps -> curtok -> ttype) | |
493 { | |
494 case TOK_KW_RETURN: | |
495 parse_next(ps); | |
496 n = parse_expr(ps); | |
497 if (!n) | |
498 { | |
499 parse_generr(ps, "statement"); | |
500 return NULL; | |
501 } | |
502 rv = node_create(NODE_STMT_RETURN); | |
503 node_addchild(rv, n); | |
504 break; | |
505 | |
506 default: | |
507 return NULL; | |
508 } | |
509 | |
510 if (ps -> curtok -> ttype != TOK_EOS) | |
511 parse_generr(ps, "statement"); | |
512 else | |
513 parse_next(ps); | |
514 return rv; | |
515 } | |
516 | |
517 node_t *parse_globaldecl(struct parser_state *ps) | |
518 { | |
519 node_t *rv = NULL; | |
520 node_t *stmt; | |
521 char *fnname = NULL; | |
522 if (ps -> curtok -> ttype == TOK_KW_INT) | |
523 { | |
524 // variable name | |
525 parse_next(ps); | |
526 if (ps -> curtok -> ttype != TOK_IDENT) | |
527 goto error; | |
528 fnname = lw_strdup(ps -> curtok -> strval); | |
529 parse_next(ps); | |
530 if (ps -> curtok -> ttype != TOK_OPAREN) | |
531 goto error; | |
532 parse_next(ps); | |
533 if (ps -> curtok -> ttype != TOK_CPAREN) | |
534 goto error; | |
535 parse_next(ps); | |
536 if (ps -> curtok -> ttype != TOK_OBRACE) | |
537 goto error; | |
538 parse_next(ps); | |
539 stmt = parse_statement(ps); | |
540 if (!stmt) | |
541 goto error; | |
542 rv = node_create(NODE_FUNDEF, node_create(NODE_TYPE_INT), node_create(NODE_IDENT, fnname), node_create(NODE_FUNARGS), stmt); | |
543 if (ps -> curtok -> ttype != TOK_CBRACE) | |
544 goto error; | |
545 parse_next(ps); | |
546 lw_free(fnname); | |
547 return rv; | |
548 } | |
549 | |
550 | |
551 error: | |
552 if (fnname) | |
553 lw_free(fnname); | |
554 parse_generr(ps, "globaldecl"); | |
555 return rv; | |
556 } | |
557 | |
558 node_t *parse_program(struct preproc_info *pp) | |
559 { | |
560 node_t *rv; | |
561 node_t *node; | |
562 struct parser_state ps; | |
563 | |
564 ps.pp = pp; | |
565 ps.curtok = NULL; | |
566 | |
567 rv = node_create(NODE_PROGRAM); | |
568 | |
569 // prime the parser | |
570 parse_next(&ps); | |
571 while (ps.curtok -> ttype != TOK_EOF) | |
572 { | |
573 node = parse_globaldecl(&ps); | |
574 if (!node) | |
575 break; | |
576 node_addchild(rv, node); | |
577 } | |
578 | |
579 return rv; | |
580 } |