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