Mercurial > hg > index.cgi
annotate lwcc/cc-parse.c @ 560:dba08c7dff96
Fix off by one handling MOD directive optional arguments
Fixes an off by one in handling the optional arguments to the MOD directive
as of changeset 928c033c0cd0.
Thanks to Alex Evans <varmfskii@gmail.com> for reporting the problem and a
suggested fix. This fix is different but should be more stable should the
rest of the parsing code be refactored in the future.
author | William Astle <lost@l-w.ca> |
---|---|
date | Fri, 22 Sep 2023 12:15:09 -0600 |
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 } |