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