1 /*
2 * cook - file construction tool
3 * Copyright (C) 1997, 1998, 2006, 2007 Peter Miller;
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <common/error_intl.h>
22 #include <cook/expr/position.h>
23 #include <cook/opcode/goto.h>
24 #include <cook/opcode/label.h>
25 #include <cook/opcode/list.h>
26 #include <cook/stmt.h>
27 #include <cook/stmt/loop.h>
28 #include <common/trace.h>
29
30
31 typedef struct stmt_loop_ty stmt_loop_ty;
32 struct stmt_loop_ty
33 {
34 stmt_ty inherited;
35 stmt_ty *body;
36 };
37
38
39 /*
40 * NAME
41 * destructor - free a loop statement node
42 *
43 * SYNOPSIS
44 * void destructor(stmt_ty *sp);
45 *
46 * DESCRIPTION
47 * The destructor function releases the resources held by a loop
48 * statement instance after it is finished with.
49 *
50 * CAVEAT
51 * Do not free the node itself, this the the destructor, not
52 * delete.
53 */
54
55 static void
destructor(stmt_ty * sp)56 destructor(stmt_ty *sp)
57 {
58 stmt_loop_ty *this;
59
60 trace(("stmt_loop::destructor(sp = %08X)\n{\n", sp));
61 assert(sp);
62 /* assert(sp->method == &method); */
63 this = (stmt_loop_ty *) sp;
64 assert(this->body);
65 stmt_delete(this->body);
66 trace(("}\n"));
67 }
68
69
70 /*
71 * NAME
72 * code_generate
73 *
74 * SYNOPSIS
75 * stmt_result_ty code_generate(stmt_ty *sp, opcode_list_ty *olp);
76 *
77 * DESCRIPTION
78 * The code_generate function is used to generate the opcodes for
79 * this statement node.
80 *
81 * RETURNS
82 * The value returned indicates why the code generation terminated.
83 */
84
85 static stmt_result_ty
code_generate(stmt_ty * sp,opcode_list_ty * olp)86 code_generate(stmt_ty *sp, opcode_list_ty *olp)
87 {
88 stmt_loop_ty *this;
89 stmt_result_ty status;
90 opcode_label_ty *continue_hold;
91 opcode_label_ty *break_hold;
92
93 trace(("stmt_loop::code_generate(sp = %08X)\n{\n", sp));
94 assert(sp);
95 this = (stmt_loop_ty *)sp;
96 assert(this->body);
97
98 continue_hold = olp->continue_label;
99 break_hold = olp->break_label;
100
101 olp->continue_label = opcode_label_new();
102 olp->break_label = opcode_label_new();
103
104 opcode_label_define(olp->continue_label, olp->length);
105 status = stmt_code_generate(this->body, olp);
106 opcode_list_append(olp, opcode_goto_new(olp->continue_label));
107 opcode_label_define(olp->break_label, olp->length);
108 opcode_label_delete(olp->continue_label);
109 opcode_label_delete(olp->break_label);
110 olp->continue_label = continue_hold;
111 olp->break_label = break_hold;
112
113 trace(("return %d;\n", status));
114 trace(("}\n"));
115 return status;
116 }
117
118
119 /*
120 * NAME
121 * method - class method table
122 *
123 * DESCRIPTION
124 * This is the class method table. It contains a description of
125 * the class, its name, size and pointers to its virtual methods.
126 *
127 * CAVEAT
128 * This symbol is NOT to be exported from this file scope.
129 */
130
131 static stmt_method_ty method =
132 {
133 "loop",
134 sizeof(stmt_loop_ty),
135 destructor,
136 code_generate,
137 };
138
139
140 /*
141 * NAME
142 * stmt_loop_new - create a new loop statement node
143 *
144 * SYNOPSIS
145 * stmt_ty *stmt_loop_new(string_ty *);
146 *
147 * DESCRIPTION
148 * The stmt_loop_new function is used to create a new instance
149 * of a loop statement node.
150 *
151 * RETURNS
152 * stmt_ty *; pointer to polymorphic statement instance.
153 *
154 * CAVEAT
155 * This function allocates data in dynamic memory. It is the
156 * caller's responsibility to free this data, using stmt_delete,
157 * when it is no longer required.
158 */
159
160 stmt_ty *
stmt_loop_new(stmt_ty * body)161 stmt_loop_new(stmt_ty *body)
162 {
163 stmt_ty *sp;
164 stmt_loop_ty *this;
165
166 trace(("stmt_loop_new(body = %08lX)\n{\n", (long)body));
167 sp = stmt_private_new(&method);
168 this = (stmt_loop_ty *)sp;
169 this->body = stmt_copy(body);
170 assert(this->body);
171 trace(("return %8.8lX;\n", (long)sp));
172 trace(("}\n"));
173 return sp;
174 }
175
176
177 typedef struct stmt_loopstop_ty stmt_loopstop_ty;
178 struct stmt_loopstop_ty
179 {
180 stmt_ty inherited;
181 expr_position_ty pos;
182 };
183
184
185 /*
186 * NAME
187 * destructor - free a loopstop statement node
188 *
189 * SYNOPSIS
190 * void destructor(stmt_ty *sp);
191 *
192 * DESCRIPTION
193 * The destructor function releases the resources held by a loopstop
194 * statement instance after it is finished with.
195 *
196 * CAVEAT
197 * Do not free the node itself, this the the destructor, not
198 * delete.
199 */
200
201 static void
loopstop_destructor(stmt_ty * sp)202 loopstop_destructor(stmt_ty *sp)
203 {
204 stmt_loopstop_ty *this;
205
206 trace(("stmt_loopstop::destructor(sp = %08X)\n{\n", sp));
207 assert(sp);
208 /* assert(sp->method == &loopstop_method); */
209 this = (stmt_loopstop_ty *)sp;
210 expr_position_destructor(&this->pos);
211 trace(("}\n"));
212 }
213
214
215 /*
216 * NAME
217 * code_generate
218 *
219 * SYNOPSIS
220 * stmt_result_ty code_generate(stmt_ty *sp, opcode_list_ty *olp);
221 *
222 * DESCRIPTION
223 * The code_generate function is used to generate the opcodes for
224 * this statement node.
225 *
226 * RETURNS
227 * The value returned indicates why the code generation terminated.
228 */
229
230 static stmt_result_ty
loopstop_code_generate(stmt_ty * sp,opcode_list_ty * olp)231 loopstop_code_generate(stmt_ty *sp, opcode_list_ty *olp)
232 {
233 stmt_loopstop_ty *this;
234 stmt_result_ty status;
235
236 trace(("stmt_loopstop::code_generate(sp = %08X)\n{\n", sp));
237 assert(sp);
238 this = (stmt_loopstop_ty *)sp;
239 status = STMT_OK;
240 if (olp->break_label)
241 opcode_list_append(olp, opcode_goto_new(olp->break_label));
242 else
243 {
244 error_with_position
245 (
246 &this->pos,
247 0,
248 i18n("'loopstop' encountered outside a loop")
249 );
250 status = STMT_ERROR;
251 }
252 trace(("return %d;\n", status));
253 trace(("}\n"));
254 return status;
255 }
256
257
258 /*
259 * NAME
260 * method - class method table
261 *
262 * DESCRIPTION
263 * This is the class method table. It contains a description of
264 * the class, its name, size and pointers to its virtual methods.
265 *
266 * CAVEAT
267 * This symbol is NOT to be exported from this file scope.
268 */
269
270 static stmt_method_ty loopstop_method =
271 {
272 "loopstop",
273 sizeof(stmt_loopstop_ty),
274 loopstop_destructor,
275 loopstop_code_generate,
276 };
277
278
279 /*
280 * NAME
281 * stmt_loopstop_new - create a new loopstop statement node
282 *
283 * SYNOPSIS
284 * stmt_ty *stmt_loopstop_new(string_ty *);
285 *
286 * DESCRIPTION
287 * The stmt_loopstop_new function is used to create a new instance
288 * of a loopstop statement node.
289 *
290 * RETURNS
291 * stmt_ty *; pointer to polymorphic statement instance.
292 *
293 * CAVEAT
294 * This function allocates data in dynamic memory. It is the
295 * caller's responsibility to free this data, using stmt_delete,
296 * when it is no longer required.
297 */
298
299 stmt_ty *
stmt_loopstop_new(expr_position_ty * pp)300 stmt_loopstop_new(expr_position_ty *pp)
301 {
302 stmt_ty *sp;
303 stmt_loopstop_ty *this;
304
305 trace(("stmt_loopstop_new()\n{\n"));
306 sp = stmt_private_new(&loopstop_method);
307 this = (stmt_loopstop_ty *)sp;
308 expr_position_copy_constructor(&this->pos, pp);
309 trace(("return %8.8lX;\n", (long)sp));
310 trace(("}\n"));
311 return sp;
312 }
313