1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 2002-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <glenn.s.fowler@gmail.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * C expression library evaluator
23 *
24 * Glenn Fowler
25 * AT&T Research
26 */
27
28 #include "cxlib.h"
29
30 /*
31 * called once before the first cxeval()
32 * there can be multiple cxbeg ... cxeval ... cxend sequences
33 */
34
35 int
cxbeg(Cx_t * cx,register Cxexpr_t * expr,const char * method)36 cxbeg(Cx_t* cx, register Cxexpr_t* expr, const char* method)
37 {
38 Opt_t opt;
39 int r;
40 char* oid;
41 char* s;
42 char id[64];
43
44 if (expr->begun)
45 return 0;
46 expr->begun = 1;
47 if (expr->query->head)
48 goto head;
49 do
50 {
51 expr->queried = expr->selected = 0;
52 if (expr->pass && cxbeg(cx, expr->pass, method))
53 return -1;
54 if (expr->fail && cxbeg(cx, expr->fail, method))
55 return -1;
56 if (expr->group)
57 {
58 if (cxbeg(cx, expr->group, method))
59 return -1;
60 }
61 else if (method && expr->query->method && !strmatch(expr->query->method, method))
62 {
63 if (cx->disc->errorf)
64 (*cx->disc->errorf)(cx, cx->disc, 2, "%s: %s: method %s expected", expr->query->name, method, expr->query->method);
65 return -1;
66 }
67 else if (expr->query->beg)
68 {
69 head:
70 oid = error_info.id;
71 if (!(s = strchr(oid, ':')))
72 s = oid + strlen(oid);
73 sfsprintf(error_info.id = id, sizeof(id), "%-.*s::%s", s - oid, oid, expr->argv[0]);
74 opt = opt_info;
75 opt_info.index = 0;
76 cx->state->header = (Cxheader_t*)expr->query;
77 cx->expr = expr;
78 r = (*expr->query->beg)(cx, expr, expr->argv, cx->disc);
79 opt_info = opt;
80 error_info.id = oid;
81 if (r)
82 return -1;
83 if (expr->query->head)
84 return 0;
85 }
86 } while (expr = expr->next);
87 return 0;
88 }
89
90 /*
91 * called once after the last cxeval()
92 * there can be multiple cxbeg ... cxeval ... cxend sequences
93 */
94
95 int
cxend(Cx_t * cx,register Cxexpr_t * expr)96 cxend(Cx_t* cx, register Cxexpr_t* expr)
97 {
98 if (!expr->begun)
99 return 0;
100 expr->begun = 0;
101 do
102 {
103 if (expr->group)
104 {
105 if (cxend(cx, expr->group))
106 return -1;
107 }
108 else if (expr->query->end)
109 {
110 cx->expr = expr;
111 if ((*expr->query->end)(cx, expr, NiL, cx->disc))
112 return -1;
113 }
114 if (expr->pass && cxend(cx, expr->pass))
115 return -1;
116 if (expr->fail && cxend(cx, expr->fail))
117 return -1;
118 } while (expr = expr->next);
119 return 0;
120 }
121
122 /*
123 * execute program at pc
124 */
125
126 static int
execute(Cx_t * cx,Cxexpr_t * expr,register Cxinstruction_t * pc,void * data,Cxoperand_t * rv,Cxdisc_t * disc)127 execute(Cx_t* cx, Cxexpr_t* expr, register Cxinstruction_t* pc, void* data, Cxoperand_t* rv, Cxdisc_t* disc)
128 {
129 register Cxoperand_t* sp;
130 register Cxcallout_f f;
131 register Cxoperand_t* so;
132 Cxinstruction_t* pe = pc;
133 Cxoperand_t r;
134 int i;
135
136 sp = expr->stack + 1;
137 sp->type = (sp-1)->type = cx->state->type_void;
138 sp->refs = (sp-1)->refs = 0;
139 for (;;)
140 {
141 r.type = pc->type;
142 r.refs = 0;
143 cx->jump = 1;
144 if (cx->test & 0x0100)
145 cxcodetrace(cx, "eval", pc, pc - pe + 1, expr->stack, sp);
146 if ((i = (*pc->callout)(cx, pc, &r, sp-1, sp, data, disc)) < 0)
147 {
148 if (i < -1)
149 return -1;
150 break;
151 }
152 so = sp;
153 sp += pc->pp;
154 *sp = r;
155 if (expr->reclaim)
156 while (--so > sp)
157 if (!so->refs && (f = cxcallout(cx, CX_DEL, so->type, cx->state->type_void, disc)) && (*f)(cx, pc, &r, NiL, so, data, disc))
158 break;
159 pc += cx->jump;
160 }
161 if (cx->returnf && pc->op == CX_END && (pc-1)->op != CX_SET)
162 {
163 (*cx->returnf)(cx, pc, &r, sp-1, sp, data, disc);
164 if (expr->reclaim && !sp->refs && (f = cxcallout(cx, CX_DEL, sp->type, cx->state->type_void, disc)))
165 {
166 (*f)(cx, pc, &r, NiL, sp, data, disc);
167 sp->type = cx->state->type_number;
168 sp->value.number = 0;
169 }
170 }
171 *rv = *sp;
172 return rv->value.number > 0;
173 }
174
175 /*
176 * evaluate expr
177 */
178
179 static int
eval(Cx_t * cx,register Cxexpr_t * expr,void * data,Cxoperand_t * rv)180 eval(Cx_t* cx, register Cxexpr_t* expr, void* data, Cxoperand_t* rv)
181 {
182 int r;
183 int t;
184
185 r = 0;
186 do
187 {
188 expr->queried++;
189 cx->expr = expr;
190 if ((t = expr->group ? eval(cx, expr->group, data, rv) : expr->query->sel ? (*expr->query->sel)(cx, expr, data, cx->disc) : expr->query->prog ? execute(cx, expr, expr->query->prog, data, rv, cx->disc) : 1) < 0)
191 return t;
192 if (t)
193 {
194 expr->selected++;
195 cx->expr = expr;
196 if (expr->query->act && (t = (*expr->query->act)(cx, expr, data, cx->disc)) < 0)
197 return t;
198 if (expr->pass && (t = eval(cx, expr->pass, data, rv)) < 0)
199 return t;
200 }
201 else if (expr->fail && (t = eval(cx, expr->fail, data, rv)) < 0)
202 return t;
203 if (t)
204 r = 1;
205 } while (expr = expr->next);
206 return r;
207 }
208
209 /*
210 * evaluate expr
211 */
212
213 int
cxeval(Cx_t * cx,register Cxexpr_t * expr,void * data,Cxoperand_t * rv)214 cxeval(Cx_t* cx, register Cxexpr_t* expr, void* data, Cxoperand_t* rv)
215 {
216 int r;
217
218 if (!cx->evaluating++)
219 vmclear(cx->em);
220 if ((r = eval(cx, expr, data, rv)) < -1)
221 r = -(r + 2);
222 cx->evaluating--;
223 return r;
224 }
225