Mercurial > hg > index.cgi
annotate lwbasic/parser.c @ 32:49d608aecc4d
Framework for handling local stack frame and/or variables
author | lost@l-w.ca |
---|---|
date | Thu, 03 Feb 2011 22:00:47 -0700 |
parents | 574931d87abd |
children | 890a8f688889 |
rev | line source |
---|---|
25 | 1 /* |
2 compiler.c | |
3 | |
4 Copyright © 2011 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 /* | |
23 This is the actual compiler bit; it drives the parser and code generation | |
24 */ | |
25 | |
26 #include <stdio.h> | |
27 | |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
28 #include <lw_alloc.h> |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
29 #include <lw_string.h> |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
30 |
25 | 31 #include "lwbasic.h" |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
32 #include "symtab.h" |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
33 |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
34 |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
35 /* size of a type */ |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
36 static int sizeof_type(int type) |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
37 { |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
38 /* everything is an "int" right now; 2 bytes */ |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
39 return 2; |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
40 } |
25 | 41 |
42 /* parse a type; the next token will be acquired as a result */ | |
43 /* the token advancement is to provide consistency */ | |
44 static int parse_type(cstate *state) | |
45 { | |
46 int pt = -1; | |
47 | |
48 switch (state -> lexer_token) | |
49 { | |
50 case token_kw_integer: | |
51 pt = 1; | |
52 break; | |
53 | |
54 default: | |
55 lwb_error("Invalid type specification"); | |
56 } | |
57 lexer(state); | |
58 /* look for "unsigned" modifier for integer types */ | |
59 return pt; | |
60 } | |
61 | |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
62 static void parse_decls(cstate *state) |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
63 { |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
64 /* declarations */ |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
65 switch (state -> lexer_token) |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
66 { |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
67 default: |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
68 return; |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
69 } |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
70 } |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
71 |
25 | 72 |
73 /* issub means RETURNS is not allowed; !issub means RETURNS is required */ | |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
74 |
25 | 75 static void parse_subfunc(cstate *state, int issub) |
76 { | |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
77 int pt, rt; |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
78 char *subname, *pn; |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
79 int vis = 0; |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
80 symtab_entry_t *se; |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
81 int paramsize = 0; |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
82 |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
83 state -> local_syms = symtab_init(); |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
84 state -> framesize = 0; |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
85 |
25 | 86 lexer(state); |
87 if (state -> lexer_token != token_identifier) | |
88 { | |
89 lwb_error("Invalid sub name '%s'", state -> lexer_token_string); | |
90 } | |
91 | |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
92 subname = lw_strdup(state -> lexer_token_string); |
25 | 93 |
94 lexer(state); | |
95 if (state -> lexer_token == token_kw_public || state -> lexer_token == token_kw_private) | |
96 { | |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
97 if (state -> lexer_token == token_kw_public) |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
98 vis = 1; |
25 | 99 lexer(state); |
100 } | |
101 | |
102 /* ignore the "PARAMS" keyword if present */ | |
103 if (state -> lexer_token == token_kw_params) | |
104 lexer(state); | |
105 | |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
106 if (state -> lexer_token == token_eol || state -> lexer_token == token_kw_returns) |
25 | 107 goto noparms; |
108 | |
109 paramagain: | |
110 if (state -> lexer_token != token_identifier) | |
111 { | |
31
574931d87abd
Created a function to prettyprint the current lexer token
lost@l-w.ca
parents:
30
diff
changeset
|
112 lwb_error("Parameter name expected, got %s\n", lexer_return_token(state)); |
25 | 113 } |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
114 pn = lw_strdup(state -> lexer_token_string); |
25 | 115 lexer(state); |
116 | |
117 if (state -> lexer_token != token_kw_as) | |
118 lwb_error("Expecting AS\n"); | |
119 lexer(state); | |
120 | |
121 pt = parse_type(state); | |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
122 |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
123 se = symtab_find(state -> local_syms, pn); |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
124 if (se) |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
125 { |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
126 lwb_error("Duplicate parameter name %s\n", pn); |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
127 } |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
128 symtab_register(state -> local_syms, pn, paramsize, symtype_param, NULL); |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
129 paramsize += sizeof_type(pt); |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
130 lw_free(pn); |
25 | 131 |
132 if (state -> lexer_token == token_char && state -> lexer_token_string[0] == ',') | |
133 { | |
134 lexer(state); | |
135 goto paramagain; | |
136 } | |
137 | |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
138 noparms: |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
139 rt = -1; |
25 | 140 if (!issub) |
141 { | |
142 if (state -> lexer_token != token_kw_returns) | |
143 { | |
144 lwb_error("FUNCTION must have RETURNS\n"); | |
145 } | |
146 lexer(state); | |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
147 /* if (state -> lexer_token == token_identifier) |
25 | 148 { |
149 printf("Return value named: %s\n", state -> lexer_token_string); | |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
150 |
25 | 151 lexer(state); |
152 if (state -> lexer_token != token_kw_as) | |
153 lwb_error("Execting AS after RETURNS"); | |
154 lexer(state); | |
155 } | |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
156 */ |
25 | 157 rt = parse_type(state); |
158 } | |
159 else | |
160 { | |
161 if (state -> lexer_token == token_kw_returns) | |
162 { | |
163 lwb_error("SUB cannot specify RETURNS\n"); | |
164 } | |
165 } | |
166 | |
167 | |
168 if (state -> lexer_token != token_eol) | |
169 { | |
31
574931d87abd
Created a function to prettyprint the current lexer token
lost@l-w.ca
parents:
30
diff
changeset
|
170 lwb_error("EOL expected; found %s\n", lexer_return_token(state)); |
25 | 171 } |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
172 |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
173 |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
174 se = symtab_find(state -> global_syms, subname); |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
175 if (se) |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
176 { |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
177 lwb_error("Multiply defined symbol %s\n", subname); |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
178 } |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
179 |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
180 symtab_register(state -> global_syms, subname, -1, issub ? symtype_sub : symtype_func, NULL); |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
181 |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
182 state -> currentsub = subname; |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
183 state -> returntype = rt; |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
184 /* consume EOL */ |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
185 lexer(state); |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
186 |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
187 /* variable declarations */ |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
188 parse_decls(state); |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
189 |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
190 /* output function/sub prolog */ |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
191 emit_prolog(state, vis); |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
192 |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
193 /* parse statement block */ |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
194 /* parse_statements(state); */ |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
195 |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
196 if (issub) |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
197 { |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
198 if (state -> lexer_token != token_kw_endsub) |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
199 { |
31
574931d87abd
Created a function to prettyprint the current lexer token
lost@l-w.ca
parents:
30
diff
changeset
|
200 lwb_error("Expecting ENDSUB, got %s\n", lexer_return_token(state)); |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
201 } |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
202 } |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
203 else |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
204 { |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
205 if (state -> lexer_token != token_kw_endfunction) |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
206 { |
31
574931d87abd
Created a function to prettyprint the current lexer token
lost@l-w.ca
parents:
30
diff
changeset
|
207 lwb_error("Expecting ENDFUNCTION, got %s\n", lexer_return_token(state)); |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
208 } |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
209 } |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
210 /* output function/sub epilog */ |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
211 emit_epilog(state); |
26
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
212 |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
213 lw_free(state -> currentsub); |
26aa76da75ad
Additional parsing in function/sub; emission of prolog/epilog code
lost@l-w.ca
parents:
25
diff
changeset
|
214 state -> currentsub = NULL; |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
215 symtab_destroy(state -> local_syms); |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
216 state -> local_syms = NULL; |
25 | 217 } |
218 | |
30
bcd532a90e53
Renamed "compiler" to "parser" for more consistent terminology
lost@l-w.ca
parents:
27
diff
changeset
|
219 void parser(cstate *state) |
25 | 220 { |
221 state -> lexer_curchar = -1; | |
32
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
222 state -> global_syms = symtab_init(); |
49d608aecc4d
Framework for handling local stack frame and/or variables
lost@l-w.ca
parents:
31
diff
changeset
|
223 |
25 | 224 /* now look for a global declaration */ |
225 for (;;) | |
226 { | |
227 state -> parser_state = parser_state_global; | |
228 lexer(state); | |
229 switch (state -> lexer_token) | |
230 { | |
231 case token_kw_function: | |
232 printf("Function\n"); | |
233 parse_subfunc(state, 0); | |
234 break; | |
235 | |
236 case token_kw_sub: | |
237 printf("Sub\n"); | |
238 parse_subfunc(state, 1); | |
239 break; | |
240 | |
241 /* blank lines are allowed */ | |
242 case token_eol: | |
243 continue; | |
244 | |
245 /* EOF is allowed - end of parsing */ | |
246 case token_eof: | |
247 return; | |
248 | |
249 default: | |
31
574931d87abd
Created a function to prettyprint the current lexer token
lost@l-w.ca
parents:
30
diff
changeset
|
250 lwb_error("Invalid token '%s' in global state\n", lexer_return_token(state)); |
25 | 251 } |
252 } | |
253 } |