1 /*
2 * cook - file construction tool
3 * Copyright (C) 1990-1994, 1997, 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 * This file contains the functions for manipulating statement trees,
21 * allocating, interpreting and releasing.
22 */
23
24 #include <cook/desist.h>
25 #include <cook/match.h>
26 #include <common/mem.h>
27 #include <cook/opcode/context.h>
28 #include <cook/opcode/list.h>
29 #include <cook/option.h>
30 #include <common/star.h>
31 #include <cook/stmt.h>
32 #include <common/trace.h>
33
34
35 /*
36 * NAME
37 * stmt_private_new - allocate a statement structure
38 *
39 * SYNOPSIS
40 * stmt_ty *stmt_private_new(stmt_method_ty *);
41 *
42 * DESCRIPTION
43 * Allocates a new statement instance.
44 *
45 * RETURNS
46 * A pointer to the dynamically allocated space is returned.
47 *
48 * CAVEAT
49 * It is the responsibility of the caller to ensure that the space is
50 * freed when finished with, by a call to stmt_delete().
51 */
52
53 stmt_ty *
stmt_private_new(stmt_method_ty * mp)54 stmt_private_new(stmt_method_ty *mp)
55 {
56 stmt_ty *sp;
57
58 trace(("stmt_private_new()\n{\n"));
59 sp = mem_alloc(mp->size);
60 sp->method = mp;
61 sp->s_references = 1;
62 trace(("return %08lX;\n", sp));
63 trace(("}\n"));
64 return sp;
65 }
66
67
68 /*
69 * NAME
70 * stmt_copy - copy statement tree
71 *
72 * SYNOPSIS
73 * stmt_ty *stmt_copy(stmt_ty *);
74 *
75 * DESCRIPTION
76 * The stmt_copy function is used to make a copy of a statement tree.
77 *
78 * RETURNS
79 * stmt_ty* - pointer to the root of the copied statement tree in dynamic
80 * memory.
81 *
82 * CAVEAT
83 * Use the stmt_delete function to release the tree when finished with.
84 */
85
86 stmt_ty *
stmt_copy(stmt_ty * sp)87 stmt_copy(stmt_ty *sp)
88 {
89 trace(("stmt_copy(sp = %08X)\n{\n", sp));
90 assert(sp);
91 assert(sp->s_references > 0);
92 sp->s_references++;
93 trace(("return %08X;\n", sp));
94 trace(("}\n"));
95 return sp;
96 }
97
98
99 /*
100 * NAME
101 * stmt_delete - delete a statement instance
102 *
103 * SYNOPSIS
104 * void stmt_delete(stmt_ty *sp);
105 *
106 * DESCRIPTION
107 * Frees a statement structure after it has been executed.
108 *
109 * CAVEAT
110 * It is assumed that the statement tree is in dynamic memory.
111 */
112
113 void
stmt_delete(stmt_ty * sp)114 stmt_delete(stmt_ty *sp)
115 {
116 trace(("stmt_delete(sp = %08X)\n{\n", sp));
117 assert(sp);
118 assert(sp->s_references > 0);
119 sp->s_references--;
120 if (sp->s_references <= 0)
121 {
122 if (sp->method->destructor)
123 sp->method->destructor(sp);
124 sp->method = 0; /* paranoia */
125 mem_free(sp);
126 }
127 trace(("}\n"));
128 }
129
130
131 /*
132 * NAME
133 * stmt_evaluate - evaluate a statement node
134 *
135 * SYNOPSIS
136 * stmt_result_ty stmt_evaluate(stmt_ty *sp);
137 *
138 * DESCRIPTION
139 * Stmt_eval is used to evaluate a statement tree.
140 * It performs the actions so implied.
141 *
142 * RETURNS
143 * The value returned indicates why the statement evaluation terminated.
144 * STMT_OK normal termination, success
145 * STMT_LSTOP a loopstop statement was encountered
146 * STMT_ERROR an execution error in a command was encountered
147 * There is also the posibility of internal subroutines;
148 * If an when this happens, an additional STMT_RET value could be returned.
149 */
150
151 stmt_result_ty
stmt_evaluate(stmt_ty * sp,const match_ty * mp)152 stmt_evaluate(stmt_ty *sp, const match_ty *mp)
153 {
154 stmt_result_ty status;
155 opcode_list_ty *olp;
156
157 trace(("stmt_evaluate(sp = %08X)\n{\n", sp));
158 assert(sp);
159 olp = stmt_compile(sp);
160 if (olp)
161 {
162 opcode_context_ty *ocp;
163 opcode_status_ty istatus;
164
165 ocp = opcode_context_new(olp, mp);
166 istatus = opcode_context_execute_nowait(ocp);
167 opcode_context_delete(ocp);
168 opcode_list_delete(olp);
169 if (istatus == opcode_status_success)
170 status = STMT_OK;
171 else
172 status = STMT_ERROR;
173 }
174 else
175 status = STMT_ERROR;
176 trace(("return %d;\n", status));
177 trace(("}\n"));
178 return status;
179 }
180
181
182 /*
183 * NAME
184 * stmt_compile
185 *
186 * SYNOPSIS
187 * opcode_list_ty *stmt_compile(stmt_ty *);
188 *
189 * DESCRIPTION
190 * The stmt_compile function is used to compile the given statement
191 * into an opcode list.
192 *
193 * RETURNS
194 * opcode_list_ty *; the null pointer on error
195 */
196
197 opcode_list_ty *
stmt_compile(stmt_ty * sp)198 stmt_compile(stmt_ty *sp)
199 {
200 opcode_list_ty *olp;
201 stmt_result_ty status;
202
203 trace(("stmt_compile(sp = %08X)\n{\n", sp));
204 assert(sp);
205 olp = opcode_list_new();
206 status = stmt_code_generate(sp, olp);
207 if (status != STMT_OK)
208 {
209 opcode_list_delete(olp);
210 olp = 0;
211 }
212 else
213 {
214 /*
215 * This option is not documented.
216 * It is only for debugging purposes.
217 */
218 if (option_test(OPTION_DISASSEMBLE))
219 opcode_list_disassemble(olp);
220 }
221 trace(("return %08lX;\n", (long)olp));
222 trace(("}\n"));
223 return olp;
224 }
225
226
227 /*
228 * NAME
229 * stmt_code_generate
230 *
231 * SYNOPSIS
232 * stmt_result_ty stmt_code_generate(stmt_ty *, struct opcode_list_ty *);
233 *
234 * DESCRIPTION
235 * The stmt_code_generate function is used to generate the opcdes
236 * for the given statement.
237 */
238
239 stmt_result_ty
stmt_code_generate(stmt_ty * sp,struct opcode_list_ty * olp)240 stmt_code_generate(stmt_ty *sp, struct opcode_list_ty *olp)
241 {
242 stmt_result_ty status;
243
244 trace(("stmt_code_generate(sp = %08lX, olp = %08lX)\n{\n",
245 (long)sp, (long)olp));
246 assert(sp);
247 assert(sp->method);
248 assert(sp->method->code_generate);
249 status = sp->method->code_generate(sp, olp);
250 trace(("return %d;\n", status));
251 trace(("}\n"));
252 return status;
253 }
254