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