1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 2002-2012 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 <gsf@research.att.com>                  *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * C expression library parser
23  *
24  * recursive descent parser snarfed from libast strexpr()
25  * which was snarfed from ksh83
26  *
27  * Glenn Fowler
28  * AT&T Research
29  */
30 
31 #include "cxlib.h"
32 
33 /*
34  * clear the current input line
35  */
36 
37 static void
clear(Cx_t * cx)38 clear(Cx_t* cx)
39 {
40 	if (cx->include)
41 		cx->include->next = cx->include->last = cx->include->base = 0;
42 }
43 
44 /*
45  * return next input character and advance
46  */
47 
48 static int
next(Cx_t * cx)49 next(Cx_t* cx)
50 {
51 	int	c;
52 
53 	if (cx->eof || !cx->include)
54 		return 0;
55 	for (;;)
56 	{
57 		while (cx->include->next >= cx->include->last)
58 		{
59 			if (cx->include->newline > 1)
60 			{
61 				cx->include->newline--;
62 				return '\n';
63 			}
64 			if (cx->include->prompt)
65 			{
66 				if (cx->include->head)
67 				{
68 					cx->include->head = 0;
69 					sfputr(sfstderr, cx->disc->ps1, -1);
70 				}
71 				else
72 					sfputr(sfstderr, cx->disc->ps2 ? cx->disc->ps2 : "> ", -1);
73 			}
74 			if ((cx->include->base = sfgetr(cx->include->sp, '\n', 0)) && !(cx->include->newline = 0) || (cx->include->base = sfgetr(cx->include->sp, '\n', -1)) && (cx->include->newline = 2))
75 			{
76 				cx->include->next = cx->include->base;
77 				cx->include->last = cx->include->base + sfvalue(cx->include->sp);
78 				error_info.line++;
79 				if (cx->flags & (CX_DEBUG|CX_TRACE))
80 					sfprintf(sfstderr, "+%d+ %-.*s%s", error_info.line, cx->include->last - cx->include->next, cx->include->base, cx->include->newline ? "\n" : "");
81 			}
82 			else if (cx->include->final || !cx->include->pop)
83 			{
84 				cx->include->eof = 1;
85 				return 0;
86 			}
87 			else if (cxpop(cx, cx->include) <= 0)
88 				return 0;
89 		}
90 		for (;;)
91 		{
92 			/*
93 			 * NOTE: sgi.mips3 gets memory fault here if
94 			 *	 cx->include->last is on the boundary of an
95 			 *	 unreadable page -- we caught one of
96 			 *	 these on the 3b2 in 85
97 			 */
98 
99 #ifdef __sgi
100 			c = *cx->include->next;
101 			cx->include->next++;
102 			if (c != '\\' || cx->include->next >= cx->include->last)
103 #else
104 			if ((c = *cx->include->next++) != '\\' || cx->include->next >= cx->include->last)
105 #endif
106 				return c;
107 			if (*cx->include->next == '\r' && ++cx->include->next >= cx->include->last)
108 				break;
109 			if (*cx->include->next != '\n')
110 				return c;
111 			if (++cx->include->next >= cx->include->last)
112 				break;
113 		}
114 	}
115 }
116 
117 #if 0
118 
119 static int
120 _trace_next(Cx_t* cx)
121 {
122 	int	c;
123 	char	buf[2];
124 
125 	c = next(cx);
126 	buf[0] = c;
127 	buf[1] = 0;
128 	error(-2, "cxcomp next include=%p eof=%d '%s'", cx->include, cx->include->eof, c ? fmtesc(buf) : "\\0");
129 	return c;
130 }
131 
132 #define next(p)		_trace_next(p)
133 
134 #endif
135 
136 /*
137  * push back last input character
138  */
139 
140 static void
back(Cx_t * cx)141 back(Cx_t* cx)
142 {
143 	if (cx->include->next > cx->include->base)
144 	{
145 		if (cx->include && cx->include->newline == 1)
146 			cx->include->newline++;
147 		else
148 			cx->include->next--;
149 	}
150 }
151 
152 /*
153  * peek next input character
154  */
155 
156 static int
peek(Cx_t * cx,int span)157 peek(Cx_t* cx, int span)
158 {
159 	int	c;
160 
161 	while (isspace(c = next(cx)) && (c != '\n' || span));
162 	if (c)
163 		back(cx);
164 	return c;
165 }
166 
167 /*
168  * return current input line context
169  */
170 
171 char*
cxcontext(Cx_t * cx)172 cxcontext(Cx_t* cx)
173 {
174 	char*	s;
175 	char*	t;
176 
177 	for (t = cx->include->next; t > cx->include->base && *(t-1) == '\n'; t--);
178 	if ((t - cx->include->base) < 40)
179 		sfprintf(cx->tp, "%-.*s<<<", t - cx->include->base, cx->include->base);
180 	else
181 	{
182 		for (s = t - 30; s > cx->include->base && (cx->ctype[*(unsigned char*)s] & (CX_CTYPE_ALPHA|CX_CTYPE_DIGIT)); s--);
183 		sfprintf(cx->tp, ">>>%-.*s<<<", t - s, s);
184 	}
185 	if (!(s = sfstruse(cx->tp)))
186 		s = "out of space";
187 	return s;
188 }
189 
190 /*
191  * return operator name for code
192  */
193 
194 char*
cxcodename(int code)195 cxcodename(int code)
196 {
197 	register char*	s;
198 	char*		b;
199 	int		n;
200 	int		i;
201 
202 	static char	name[sizeof(CX_OPNAME)] = CX_OPNAME;
203 
204 	b = s = fmtbuf(n = 16);
205 	i = code >> CX_ATTR;
206 	if (i >= (elementsof(name) - 1))
207 		sfsprintf(b, n, "<%d:%o>", i + 1, code & ((1<<CX_ATTR)-1));
208 	else
209 	{
210 		switch (name[i])
211 		{
212 		case 'C':
213 			s = strcopy(s, "CALL");
214 			break;
215 		case 'D':
216 			s = strcopy(s, "DEL");
217 			break;
218 		case 'G':
219 			s = strcopy(s, "GET");
220 			break;
221 		case 'J':
222 			s = strcopy(s, "JMP");
223 			break;
224 		case 'L':
225 			s = strcopy(s, "LOG");
226 			break;
227 		case 'R':
228 			s = strcopy(s, "RET");
229 			break;
230 		case 'S':
231 			s = strcopy(s, code == CX_CAST ? "CAST" : (code & CX_X2) ? "==" : "SET");
232 			break;
233 		case 'e':
234 			s = strcopy(s, "END");
235 			break;
236 		case 'n':
237 			s = strcopy(s, "NUM");
238 			break;
239 		case 'p':
240 			s = strcopy(s, "POP");
241 			break;
242 		case 's':
243 			s = strcopy(s, "STR");
244 			break;
245 		case 't':
246 			s = strcopy(s, "TST");
247 			break;
248 		case '0':
249 			s = strcopy(s, "NOP");
250 			break;
251 		case '~':
252 			if (code == CX_NOMATCH)
253 				*s++ = '!';
254 			else
255 			{
256 				code &= ~CX_ASSIGN;
257 				*s++ = '=';
258 			}
259 			/*FALLTHROUGH*/
260 		default:
261 			*s++ = name[i];
262 			if (code & CX_X2)
263 				*s++ = name[i];
264 			if ((code & CX_ASSIGN) && code != CX_SET)
265 				*s++ = '=';
266 			break;
267 		}
268 		*s = 0;
269 	}
270 	return b;
271 }
272 
273 /*
274  * trace instruction at pc to the standard error
275  */
276 
277 void
cxcodetrace(Cx_t * cx,const char * fun,Cxinstruction_t * pc,unsigned int offset,Cxoperand_t * bp,Cxoperand_t * sp)278 cxcodetrace(Cx_t* cx, const char* fun, Cxinstruction_t* pc, unsigned int offset, Cxoperand_t* bp, Cxoperand_t* sp)
279 {
280 	char*	o;
281 	char	val[64];
282 	char	a[64];
283 	char	b[64];
284 
285 	o = cxcodename(pc->op);
286 	if ((*o == 'G' || *o == 'S') && *(o + 1) == 'E')
287 		sfsprintf(val, sizeof(val), "  %s", pc->data.variable->name);
288 	else if (*o == 'C')
289 	{
290 		if (pc->data.pointer)
291 			sfsprintf(val, sizeof(val), "  %s", ((Cxedit_t*)pc->data.pointer)->name);
292 	}
293 	else if (pc->type == cx->state->type_string)
294 		sfsprintf(val, sizeof(val), "  \"%-.6s\"", pc->data.string);
295 	else if (pc->type == cx->state->type_number)
296 		sfsprintf(val, sizeof(val), "  %8.4Lf", pc->data.number);
297 	else if (pc->type != cx->state->type_void)
298 		sfsprintf(val, sizeof(val), "  %p", pc->data.pointer);
299 	else
300 		val[0] = 0;
301 	if (bp)
302 	{
303 		if ((sp-1)->type == cx->state->type_string)
304 			sfsprintf(a, sizeof(a), "  [%d]\"%-.6s\"", (sp-1) - bp, (sp-1)->value.string.data);
305 		else if ((sp-1)->type == cx->state->type_number)
306 			sfsprintf(a, sizeof(a), "  [%d]%8.4Lf", (sp-1) - bp, (sp-1)->value.number);
307 		else if ((sp-1)->type != cx->state->type_void)
308 			sfsprintf(a, sizeof(a), "  [%d]%p", (sp-1) - bp, (sp-1)->value.pointer);
309 		else
310 			a[0] = 0;
311 		if (sp->type == cx->state->type_string)
312 			sfsprintf(b, sizeof(b), "  [%d]\"%-.6s\"", sp - bp, sp->value.string.data);
313 		else if (sp->type == cx->state->type_number)
314 			sfsprintf(b, sizeof(b), "  [%d]%8.4Lf", sp - bp, sp->value.number);
315 		else if (sp->type != cx->state->type_void)
316 			sfsprintf(b, sizeof(b), "  [%d]%p", sp - bp, sp->value.pointer);
317 		else
318 			b[0] = 0;
319 	}
320 	else
321 	{
322 		a[0] = 0;
323 		b[0] = 0;
324 	}
325 	error(0, "%s %04u %8s %-12s  pp %2d%s%s%s", fun, offset, o, pc->type->name, pc->pp, val, a, b);
326 }
327 
328 /*
329  * return operator name
330  */
331 
332 char*
cxopname(int code,Cxtype_t * type1,Cxtype_t * type2)333 cxopname(int code, Cxtype_t* type1, Cxtype_t* type2)
334 {
335 	char*	b;
336 	char*	o;
337 	int	n;
338 
339 	o = cxcodename(code);
340 	if (!type1 || streq(type1->name, "void"))
341 		return o;
342 	b = fmtbuf(n = 32);
343 	if ((code & CX_UNARY) || !type2)
344 		sfsprintf(b, n, "%s %s", o, type1->name);
345 	else
346 		sfsprintf(b, n, "%s %s %s", type1->name, o, type2->name);
347 	return b;
348 }
349 
350 /*
351  * push file or string on the include stack
352  */
353 
354 void*
cxpush(Cx_t * cx,const char * file,Sfio_t * sp,const char * buf,ssize_t len,Cxflags_t flags)355 cxpush(Cx_t* cx, const char* file, Sfio_t* sp, const char* buf, ssize_t len, Cxflags_t flags)
356 {
357 	char*		path;
358 	Cxinclude_t*	ip;
359 	int		prompt;
360 	int		retain;
361 	char		tmp[PATH_MAX];
362 
363 	if (sp)
364 	{
365 		retain = 1;
366 		if (buf && cx->disc->errorf)
367 			(*cx->disc->errorf)(NiL, cx->disc, 1, "both file and buffer specified -- buffer ignored");
368 	}
369 	else
370 	{
371 		retain = 0;
372 		if (buf && (!(sp = sfstropen()) || sfstrbuf(sp, (char*)buf, len >= 0 ? len : strlen(buf) + 1, 0)))
373 		{
374 			if (sp)
375 				sfclose(sp);
376 			if (cx->disc->errorf)
377 				(*cx->disc->errorf)(NiL, cx->disc, 2, "out of space");
378 			return 0;
379 		}
380 	}
381 	if (!file || streq(file, "-"))
382 	{
383 		path = 0;
384 		if (!sp)
385 		{
386 			sp = sfstdin;
387 			retain = 1;
388 		}
389 		prompt = cx->disc->ps1 && isatty(sffileno(sp));
390 	}
391 	else
392 	{
393 		if (sp)
394 			path = (char*)file;
395 		else if (!(path = pathfind(file, cx->id, NiL, tmp, sizeof(tmp))))
396 		{
397 			if (cx->disc->errorf)
398 				(*cx->disc->errorf)(NiL, cx->disc, 2, "%s: include file not found", file);
399 			return 0;
400 		}
401 		else if (!(sp = sfopen(NiL, path, "r")))
402 		{
403 			if (cx->disc->errorf)
404 				(*cx->disc->errorf)(NiL, cx->disc, 2, "%s: cannot read", path);
405 			return 0;
406 		}
407 		prompt = 0;
408 	}
409 	if (!(ip = vmnewof(cx->vm, 0, Cxinclude_t, 1, path ? strlen(path) : 0)))
410 	{
411 		if (!retain)
412 			sfclose(sp);
413 		if (cx->disc->errorf)
414 			(*cx->disc->errorf)(NiL, cx->disc, 2, "out of space");
415 		return 0;
416 	}
417 	ip->sp = sp;
418 	ip->final = !(flags & CX_INCLUDE);
419 	ip->retain = retain;
420 	ip->ofile = error_info.file;
421 	error_info.file = path ? strcpy(ip->file, path) : (char*)0;
422 	ip->oline = error_info.line;
423 	error_info.line = 0;
424 	ip->eof = cx->eof;
425 	cx->eof = 0;
426 	ip->interactive = cx->interactive;
427 	cx->interactive = ip->prompt = prompt;
428 	ip->pop = cx->include;
429 	cx->include = ip;
430 	return ip;
431 }
432 
433 /*
434  * pop the top file off the include stack until and including matching cxpush() pop
435  * pop==0 pops everything
436  * 1 returned if there are more items on the stack after the pop
437  * 0 returned if the stack is empty after the pop
438  * -1 returned if the stack is empty before the pop
439  */
440 
441 int
cxpop(Cx_t * cx,void * pop)442 cxpop(Cx_t* cx, void* pop)
443 {
444 	Cxinclude_t*	pp = (Cxinclude_t*)pop;
445 	Cxinclude_t*	ip;
446 
447 	if (!(ip = cx->include))
448 	{
449 		cx->eof = 1;
450 		return -1;
451 	}
452 	do
453 	{
454 		if (!ip->retain)
455 			sfclose(ip->sp);
456 		cx->include = ip->pop;
457 		error_info.file = ip->ofile;
458 		error_info.line = ip->oline;
459 		cx->interactive = ip->interactive;
460 		vmfree(cx->vm, ip);
461 	} while (ip != pp && (ip = cx->include));
462 	cx->eof = !cx->include;
463 	return cx->include ? 1 : 0;
464 }
465 
466 /*
467  * add (*donef)(cx,data,disc) to the list to be called at cxfree(cx,expr)
468  * donef==0 pops the list
469  */
470 
471 int
cxatfree(Cx_t * cx,Cxexpr_t * expr,Cxdone_f donef,void * data)472 cxatfree(Cx_t* cx, Cxexpr_t* expr, Cxdone_f donef, void* data)
473 {
474 	register Cxdone_t*	dp;
475 
476 	if (donef)
477 	{
478 		if (!(dp = vmnewof(expr->vm, 0, Cxdone_t, 1, 0)))
479 		{
480 			if (cx->disc->errorf)
481 				(*cx->disc->errorf)(cx, cx->disc, 2, "out of space");
482 			return -1;
483 		}
484 		dp->donef = donef;
485 		dp->data = data;
486 		dp->next = expr->done;
487 		expr->done = dp;
488 	}
489 	else
490 	{
491 		for (dp = expr->done; dp; dp = dp->next)
492 			(*dp->donef)(cx, dp->data, cx->disc);
493 		expr->done = 0;
494 	}
495 	return 0;
496 }
497 
498 /*
499  * parse and return identifier with first char c if c!=0
500  * results placed in operand r
501  * r->refs == 1 if identifier has :: library binding
502  */
503 
504 static int
identifier(Cx_t * cx,Cxcompile_t * cc,register int c,Cxoperand_t * r)505 identifier(Cx_t* cx, Cxcompile_t* cc, register int c, Cxoperand_t* r)
506 {
507 	r->refs = 0;
508 	if (!c)
509 		c = next(cx);
510 	if (!cx->referencef)
511 	{
512 		if (cx->disc->errorf)
513 			(*cx->disc->errorf)(cx, cx->disc, 2, "%s variables not supported", cxcontext(cx));
514 		return -1;
515 	}
516 	if (c == '.')
517 		sfputc(cx->tp, c);
518 	else
519 	{
520 		for (;;)
521 		{
522 			do
523 			{
524 				sfputc(cx->tp, c);
525 			} while (cx->ctype[c = next(cx)] & (CX_CTYPE_ALPHA|CX_CTYPE_DIGIT));
526 			if (c != ':' || r->refs)
527 				break;
528 			if (next(cx) != ':')
529 			{
530 				back(cx);
531 				break;
532 			}
533 			r->refs = 1;
534 			sfputc(cx->tp, c);
535 		}
536 		back(cx);
537 	}
538 	r->type = cx->state->type_string;
539 	r->value.string.size = sfstrtell(cx->tp);
540 	r->value.string.data = sfstruse(cx->tp);
541 	return 0;
542 }
543 
544 /*
545  * parse and return variable with first char c if c!=0
546  */
547 
548 static Cxvariable_t*
variable(Cx_t * cx,Cxcompile_t * cc,int c,Cxtype_t * m,Cxtype_t ** type)549 variable(Cx_t* cx, Cxcompile_t* cc, int c, Cxtype_t* m, Cxtype_t** type)
550 {
551 	Cxoperand_t	r;
552 	Cxoperand_t	a;
553 	Cxoperand_t	b;
554 
555 	if (identifier(cx, cc, c, &a))
556 		return 0;
557 	b.type = m;
558 	if (a.refs)
559 	{
560 		if (!(r.value.variable = cxfunction(cx, a.value.string.data, cx->disc)))
561 			return 0;
562 	}
563 	else
564 	{
565 		a.refs = 0;
566 		if (type && (*type = (Cxtype_t*)dtmatch(cx->types, a.value.string.data)) || (*cx->referencef)(cx, NiL, &r, &b, &a, NiL, cx->disc))
567 			return 0;
568 	}
569 	return r.value.variable;
570 }
571 
572 /*
573  * eval time cast
574  */
575 
576 static int
cast(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)577 cast(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
578 {
579 	if ((*r->type->internalf)(cx, r->type, NiL, &r->type->format, r, r->value.string.data, r->value.string.size, cx->em, cx->disc) < 0)
580 	{
581 		(*cx->disc->errorf)(cx, cx->disc, 2, "cannot cast from %s to %s", r->type->name, r->type->fundamental->name);
582 		return -1;
583 	}
584 	return 0;
585 }
586 
587 /*
588  * eval time edit
589  */
590 
591 static int
edit(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)592 edit(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
593 {
594 	return cxsuball(cx, (Cxpart_t*)pc->data.pointer, r);
595 }
596 
597 /*
598  * output cast instruction
599  */
600 
601 static int
codecast(Cx_t * cx,Cxcompile_t * cc,Cxtype_t * t,Cxcallout_f cast,void * pointer)602 codecast(Cx_t* cx, Cxcompile_t* cc, Cxtype_t* t, Cxcallout_f cast, void* pointer)
603 {
604 	Cxinstruction_t		c;
605 
606 	c.callout = cast;
607 	c.op = CX_CAST;
608 	c.type = t;
609 	c.data.pointer = pointer;
610 	c.pp = 0;
611 	if ((cx->flags & CX_DEBUG) && sfstrtell(cc->xp))
612 		cxcodetrace(cx, "comp", &c, (unsigned int)sfstrtell(cc->xp) / sizeof(c), 0, 0);
613 	sfwrite(cc->xp, &c, sizeof(c));
614 	return 0;
615 }
616 
617 /*
618  * encode and output instruction
619  */
620 
621 static Cxtype_t*
code(Cx_t * cx,Cxcompile_t * cc,Cxexpr_t * expr,int op,int pp,Cxtype_t * type1,Cxtype_t * type2,void * pointer,Cxnumber_t number,Cxvariable_t * ref)622 code(Cx_t* cx, Cxcompile_t* cc, Cxexpr_t* expr, int op, int pp, Cxtype_t* type1, Cxtype_t* type2, void* pointer, Cxnumber_t number, Cxvariable_t* ref)
623 {
624 	Cxinstruction_t*	i1;
625 	Cxinstruction_t*	i2;
626 	Cxvariable_t*		v1;
627 	Cxvariable_t*		v2;
628 	Cxinstruction_t		x;
629 	Cxinstruction_t		c;
630 	Cxinstruction_t		t;
631 	Cxoperand_t		r;
632 	Cxrecode_f		f;
633 	Cxunsigned_t		m;
634 	char*			s;
635 
636 	static Cxformat_t	format;
637 
638 	x.op = op;
639 	x.type = cx->table->comparison[op] ? cx->state->type_number : type1;
640 	x.pp = pp;
641 	if ((cc->pp += pp) > cc->depth)
642 		cc->depth = cc->pp;
643 	if (!pointer)
644 		x.data.number = number;
645 	else if (op == CX_GET || op == CX_SET || op == CX_REF || op == CX_CALL || !cxisstring(type1))
646 		x.data.pointer = pointer;
647 	else
648 		x.data.string.size = strlen(x.data.string.data = (char*)pointer);
649 	x.callout = 0;
650 	if (op == CX_REF || op == CX_GET)
651 	{
652 		if (((f = cxrecode(cx, op, type1, type2, cx->disc)) || (f = cxrecode(cx, op, cx->state->type_void, cx->state->type_void, cx->disc))) && (*f)(cx, expr, &x, NiL, NiL, NiL, cx->disc))
653 			return 0;
654 		if (op == CX_GET && ((Cxvariable_t*)pointer)->member)
655 		{
656 			x.callout = ((Cxvariable_t*)pointer)->member->member->getf;
657 			x.pp--;
658 		}
659 		i1 = i2 = (Cxinstruction_t*)(sfstrseek(cc->xp, 0, SEEK_CUR) - 1 * sizeof(Cxinstruction_t));
660 		v1 = v2 = i1->data.variable;
661 		if (op != CX_REF)
662 			type1 = type2 = i1->type;
663 	}
664 	else
665 	{
666 		i1 = (Cxinstruction_t*)(sfstrseek(cc->xp, 0, SEEK_CUR) - 2 * sizeof(Cxinstruction_t));
667 		i2 = i1 + 1;
668 		if ((i1->op == CX_GET || i1->op == CX_CAST && (i1 - 1)->op == CX_GET) && (f = cxrecode(cx, op, type1, type2, cx->disc)))
669 		{
670 			expr->vm = cc->vm;
671 			expr->done = cc->done;
672 			if ((*f)(cx, expr, &x, i1, i2, NiL, cx->disc))
673 				return 0;
674 			cc->done = expr->done;
675 			i1 = (Cxinstruction_t*)(sfstrseek(cc->xp, 0, SEEK_CUR) - 2 * sizeof(Cxinstruction_t));
676 			i2 = i1 + 1;
677 			type1 = i1->type;
678 			type2 = i2->type;
679 		}
680 		v1 = ref ? ref : i1->op == CX_GET ? i1->data.variable : (Cxvariable_t*)0;
681 		v2 = i2->op == CX_GET ? i2->data.variable : (Cxvariable_t*)0;
682 	}
683 	if (x.callout)
684 		goto done;
685 	if (x.callout = cxcallout(cx, op, type1, type2, cx->disc))
686 		goto done;
687 	if (type1 == type2 || (op &CX_UNARY))
688 	{
689 		type1 = type2 = type1->fundamental;
690 		if (x.callout = cxcallout(cx, op, type1, type2, cx->disc))
691 			goto done;
692 	}
693 	if (type1 != type2)
694 	{
695 		if (v1 && (c.callout = cxcallout(cx, CX_CAST, type1, type2, cx->disc)) && (x.callout = cxcallout(cx, op, type2, type2, cx->disc)))
696 		{
697 			t = *(Cxinstruction_t*)(sfstrseek(cc->xp, -sizeof(Cxinstruction_t), SEEK_CUR));
698 			c.op = CX_CAST;
699 			c.type = type2;
700 			c.data.number = 0;
701 			c.pp = 0;
702 			if ((cx->flags & CX_DEBUG) && sfstrtell(cc->xp))
703 				cxcodetrace(cx, "comp", &c, (unsigned int)sfstrtell(cc->xp) / sizeof(c), 0, 0);
704 			sfwrite(cc->xp, &c, sizeof(c));
705 			if ((cx->flags & CX_DEBUG) && sfstrtell(cc->xp))
706 				cxcodetrace(cx, "comp", &t, (unsigned int)sfstrtell(cc->xp) / sizeof(c), 0, 0);
707 			sfwrite(cc->xp, &t, sizeof(t));
708 			goto done;
709 		}
710 		if (x.callout = cxcallout(cx, op, type1, type1, cx->disc))
711 		{
712 			if (v1 && v1->format.map && cxisstring(type2) && !cxstr2num(cx, &v1->format, i2->data.string.data, i2->data.string.size, &m))
713 			{
714 				i2->op = CX_NUM;
715 				i2->type = cx->state->type_number;
716 				i2->data.number = (Cxinteger_t)m;
717 				goto done;
718 			}
719 			if (v2 && v2->format.map && cxisstring(type1) && !cxstr2num(cx, &v2->format, i1->data.string.data, i1->data.string.size, &m))
720 			{
721 				i1->op = CX_NUM;
722 				i1->type = cx->state->type_number;
723 				i1->data.number = (Cxinteger_t)m;
724 				goto done;
725 			}
726 			if (cxisstring(type2))
727 			{
728 				if (cxisnumber(type1) && i2->op == CX_STR && i2->data.string.size == 1)
729 				{
730 					i2->op = CX_NUM;
731 					i2->type = cx->state->type_number;
732 					i2->data.number = i2->data.string.data[0];
733 					goto done;
734 				}
735 				if (type1->internalf)
736 				{
737 					if ((*type1->internalf)(cx, type1, NiL, &format, &r, i2->data.string.data, i2->data.string.size, cc->vm, cx->disc) < 0)
738 						return 0;
739 					i2->op = CX_NUM;
740 					i2->type = cx->state->type_number;
741 					i2->data.number = r.value.number;
742 					goto done;
743 				}
744 			}
745 			if (cxisnumber(type2) && cxisstring(type1))
746 			{
747 				if (i1->op == CX_STR && i1->data.string.size == 1 && (x.callout = cxcallout(cx, op, type2, type2, cx->disc)))
748 				{
749 					i1->op = CX_NUM;
750 					i1->type = cx->state->type_number;
751 					i1->data.number = i1->data.string.data[0];
752 					goto done;
753 				}
754 			}
755 		}
756 		if (type1->fundamental == type2->fundamental && (x.callout = cxcallout(cx, op, type1->fundamental, type1->fundamental, cx->disc)))
757 			goto done;
758 		if (v1 && cxisstring(type1) && !v2 && cxisnumber(type2) && (x.callout = cxcallout(cx, op, type1->fundamental, type1->fundamental, cx->disc)) && !cxnum2str(cx, &v1->format, i2->data.number, &s))
759 		{
760 			i2->op = CX_STR;
761 			i2->type = type1->fundamental;
762 			if (!(i2->data.string.data = vmstrdup(cc->vm, s)))
763 			{
764 				if (cx->disc->errorf)
765 					(*cx->disc->errorf)(cx, cx->disc, 2, "out of space");
766 				return 0;
767 			}
768 			i2->data.string.size = strlen(s);
769 			goto done;
770 		}
771 		if (v2 && cxisstring(type2) && !v1 && cxisnumber(type1) && (x.callout = cxcallout(cx, op, type2->fundamental, type2->fundamental, cx->disc)) && !cxnum2str(cx, &v2->format, i1->data.number, &s))
772 		{
773 			i1->op = CX_STR;
774 			i1->type = type2->fundamental;
775 			if (!(i1->data.string.data = vmstrdup(cc->vm, s)))
776 			{
777 				if (cx->disc->errorf)
778 					(*cx->disc->errorf)(cx, cx->disc, 2, "out of space");
779 				return 0;
780 			}
781 			i1->data.string.size = strlen(s);
782 			goto done;
783 		}
784 		if (cxisstring(type2) && type1->internalf && (x.callout = cxcallout(cx, op, type1->fundamental, type1->fundamental, cx->disc)))
785 		{
786 			if (cxisnumber(type1) && v1 && v1->format.map && !cxstr2num(cx, &v1->format, i2->data.string.data, i2->data.string.size, &m))
787 			{
788 				i2->op = CX_NUM;
789 				i2->type = type1->fundamental;
790 				i2->data.number = (Cxinteger_t)m;
791 				goto done;
792 			}
793 			if (!v2)
794 			{
795 				r.type = type1->fundamental;
796 				if ((*type1->internalf)(cx, type1, NiL, &format, &r, i2->data.string.data, i2->data.string.size, cc->vm, cx->disc) < 0)
797 					return 0;
798 				i2->op = CX_NUM;
799 				i2->type = r.type;
800 				i2->data = r.value;
801 				goto done;
802 			}
803 		}
804 		if (cxisstring(type1) && type2->internalf && (x.callout = cxcallout(cx, op, type2->fundamental, type2, cx->disc)))
805 		{
806 			if (cxisnumber(type2) && v2 && v2->format.map && !cxstr2num(cx, &v2->format, i1->data.string.data, i1->data.string.size, &m))
807 			{
808 				i1->op = CX_NUM;
809 				i1->type = type2->fundamental;
810 				i1->data.number = (Cxinteger_t)m;
811 				goto done;
812 			}
813 			if (!v1)
814 			{
815 				r.type = type2->fundamental;
816 				if ((*type2->internalf)(cx, type2, NiL, &format, &r, i1->data.string.data, i1->data.string.size, cc->vm, cx->disc) < 0)
817 					return 0;
818 				i1->op = CX_NUM;
819 				i1->type = r.type;
820 				i1->data = r.value;
821 				goto done;
822 			}
823 		}
824 	}
825 	if (x.callout = cxcallout(cx, op, cx->state->type_void, cx->state->type_void, cx->disc))
826 		goto done;
827 	if (cx->disc->errorf)
828 		(*cx->disc->errorf)(cx, cx->disc, 2, "%s %s not supported [%d:%d] %p", cxcontext(cx), cxopname(op, type1, type2), cxrepresentation(type1), cxrepresentation(type2), cxcallout(cx, op, cx->state->type_string, cx->state->type_string, cx->disc));
829 	return 0;
830  done:
831 	if ((cx->flags & CX_DEBUG) && sfstrtell(cc->xp))
832 		cxcodetrace(cx, "comp", &x, (unsigned int)sfstrtell(cc->xp) / sizeof(x), 0, 0);
833 	if (sfwrite(cc->xp, &x, sizeof(x)) != sizeof(x))
834 	{
835 		if (cx->disc->errorf)
836 			(*cx->disc->errorf)(cx, cx->disc, 2, "out of space");
837 		return 0;
838 	}
839 	if (op == CX_GET && (v1 = (Cxvariable_t*)pointer) && cxisstring(v1->type) && v1->format.map && v1->format.map->part && v1->format.map->part->edit)
840 		codecast(cx, cc, v1->type, edit, v1->format.map->part);
841 	return cc->type = x.type;
842 }
843 
844 /*
845  * return the next expected argument type for v
846  * return:
847  *	>0 ok
848  *	=0 no more arguments
849  *	<0 error
850  */
851 
852 static int
prototype(Cx_t * cx,Cxcompile_t * cc,Cxvariable_t * v,Cxtype_t ** tp,char ** sp,char ** ep,int * op)853 prototype(Cx_t* cx, Cxcompile_t* cc, Cxvariable_t* v, Cxtype_t** tp, char** sp, char** ep, int* op)
854 {
855 	char*		s;
856 	char*		e;
857 	char*		u;
858 	Cxtype_t*	t;
859 	int		c;
860 	int		o;
861 	int		r;
862 	char		buf[256];
863 
864 	s = *sp;
865 	e = *ep;
866 	o = *op;
867 	t = 0;
868 	r = 0;
869 	for (;;)
870 	{
871 		if ((c = *s++) == 0)
872 		{
873 			s--;
874 			break;
875 		}
876 		else if (c == '[')
877 			o++;
878 		else if (c == ']')
879 			o--;
880 		else if (c == '.')
881 		{
882 			if (!e)
883 			{
884 				e = s;
885 				o = 0;
886 				while (--e > (char*)v->prototype)
887 				{
888 					if ((c = *e) == '[' || !o--)
889 						break;
890 					else if (c == ']')
891 						o++;
892 				}
893 				o = 1;
894 			}
895 			s = e;
896 			if (*s == '.')
897 			{
898 				t = cx->state->type_void;
899 				r = 1;
900 				break;
901 			}
902 		}
903 		else if (c == '*')
904 		{
905 			t = cx->state->type_void;
906 			r = 1;
907 			break;
908 		}
909 		else if (c == '&' && (cx->ctype[*(unsigned char*)s] & CX_CTYPE_ALPHA) || (cx->ctype[c] & CX_CTYPE_ALPHA))
910 		{
911 			if (c != '&')
912 				s--;
913 			for (u = buf; (cx->ctype[*(unsigned char*)s] & (CX_CTYPE_ALPHA|CX_CTYPE_DIGIT)); s++)
914 				if (u < &buf[sizeof(buf)-1])
915 					*u++ = *s;
916 			*u = 0;
917 			if (t = cxtype(cx, buf, cx->disc))
918 			{
919 				if (c == '&')
920 					t = cx->state->type_reference;
921 				r = 1;
922 			}
923 			else
924 			{
925 				if (cx->disc->errorf)
926 					(*cx->disc->errorf)(cx, cx->disc, 2, "%s %s: unknown prototype type name", cxcontext(cx), buf);
927 				r = -1;
928 			}
929 			break;
930 		}
931 	}
932 	*sp = s;
933 	*ep = e;
934 	*op = o;
935 	*tp = t;
936 	return r;
937 }
938 
939 /*
940  * parse the next (sub)expression
941  */
942 
943 static Cxtype_t*
parse(Cx_t * cx,Cxcompile_t * cc,Cxexpr_t * expr,int precedence,Cxvariable_t ** ref)944 parse(Cx_t* cx, Cxcompile_t* cc, Cxexpr_t* expr, int precedence, Cxvariable_t** ref)
945 {
946 	register int	c;
947 	register int	p;
948 	char*		s;
949 	char*		e;
950 	Cxtype_t*	g;
951 	Cxtype_t*	m;
952 	Cxtype_t*	t;
953 	Cxtype_t*	u;
954 	Cxvariable_t*	f;
955 	Cxvariable_t*	h;
956 	Cxvariable_t*	v;
957 	int		i;
958 	int		k;
959 	int		o;
960 	int		x;
961 	int		q;
962 	int		r;
963 	long		z;
964 	double		n;
965 	Cxoperand_t	w;
966 
967 	cc->level++;
968  again:
969 	t = cx->state->type_void;
970 	g = 0;
971 	h = 0;
972 	m = 0;
973 	x = 0;
974 	v = 0;
975 	while (c = next(cx))
976 	{
977 		if (o = cx->table->opcode[c])
978 		{
979 			i = 0;
980 			if ((p = next(cx)) == c)
981 			{
982 				p = next(cx);
983 				o |= CX_X2;
984 				i++;
985 			}
986 			if (p == '~')
987 			{
988 				if (c == '=')
989 				{
990 					o = CX_MATCH;
991 					i++;
992 				}
993 				else if (c == '!')
994 				{
995 					o = CX_NOMATCH;
996 					i++;
997 				}
998 				else
999 					back(cx);
1000 			}
1001 			else if (p == '=' && !(o & CX_ASSIGN))
1002 			{
1003 				o |= CX_ASSIGN;
1004 				o &= ~CX_UNARY;
1005 				i++;
1006 			}
1007 			else
1008 				back(cx);
1009 			if (o == CX_ADDADD || o == CX_SUBSUB)
1010 			{
1011 				if (!v)
1012 				{
1013 					if (x)
1014 					{
1015 						if (cx->disc->errorf)
1016 							(*cx->disc->errorf)(cx, cx->disc, 2, "%s operator requires lvalue", cxcontext(cx));
1017 						goto bad;
1018 					}
1019 					if (!(v = variable(cx, cc, 0, m, 0)))
1020 						goto bad;
1021 					h = v;
1022 					m = 0;
1023 					if (cxisvoid(v->type))
1024 						goto undefined;
1025 				}
1026 				if (!code(cx, cc, expr, CX_GET, 1, v->type, cx->state->type_void, v, 0, NiL))
1027 					goto bad;
1028 				if (!code(cx, cc, expr, CX_NUM, 1, cx->state->type_number, cx->state->type_void, NiL, 1.0, NiL))
1029 					goto bad;
1030 				if (!code(cx, cc, expr, o & ~CX_X2, -1, v->type, cx->state->type_number, NiL, 0, NiL))
1031 					goto bad;
1032 				if (!code(cx, cc, expr, CX_SET, 0, cx->state->type_void, v->type, v, 0, NiL))
1033 					goto bad;
1034 				if (x)
1035 				{
1036 					if (!code(cx, cc, expr, CX_NUM, 1, cx->state->type_number, cx->state->type_void, NiL, -1.0, NiL))
1037 						goto bad;
1038 					if (!code(cx, cc, expr, o & ~CX_X2, -1, v->type, cx->state->type_number, NiL, 0, NiL))
1039 						goto bad;
1040 				}
1041 				v = 0;
1042 				x = 1;
1043 				continue;
1044 			}
1045 			if (!x)
1046 				o |= CX_UNARY;
1047 			if (o == CX_AND && precedence == cx->table->precedence[CX_CALL])
1048 			{
1049 				while (i--)
1050 					back(cx);
1051 				goto done;
1052 			}
1053 			if ((o & CX_ASSIGN) && !cx->table->comparison[o])
1054 			{
1055 				if (!v)
1056 				{
1057 					if (cx->disc->errorf)
1058 						(*cx->disc->errorf)(cx, cx->disc, 2, "%s assignment requires lvalue", cxcontext(cx));
1059 					goto bad;
1060 				}
1061 				p = cx->table->precedence[CX_SET];
1062 				if (o != CX_SET)
1063 				{
1064 					if (cxisvoid(v->type))
1065 						goto undefined;
1066 					o &= ~CX_ASSIGN;
1067 					if (!code(cx, cc, expr, CX_GET, 1, v->type, cx->state->type_void, v, 0, NiL))
1068 						goto bad;
1069 				}
1070 			}
1071 			else if (o == CX_REF)
1072 			{
1073 				if (!(v = variable(cx, cc, 0, m, 0)))
1074 					goto bad;
1075 				m = 0;
1076 				if (!code(cx, cc, expr, CX_REF, 1, cx->state->type_reference, cx->state->type_void, v, 0, NiL))
1077 					goto bad;
1078 				v = 0;
1079 				x = 1;
1080 				continue;
1081 			}
1082 			else
1083 			{
1084 				if (x == 2)
1085 				{
1086 					if (!code(cx, cc, expr, CX_NUM, 1, cx->state->type_type_t, cx->state->type_void, t, 0, NiL))
1087 						goto bad;
1088 				}
1089 				else if (v)
1090 				{
1091 					if (cxisvoid(v->type))
1092 						goto undefined;
1093 					if (!code(cx, cc, expr, CX_GET, 1, v->type, cx->state->type_void, v, 0, NiL))
1094 						goto bad;
1095 					v = 0;
1096 				}
1097 				p = cx->table->precedence[o];
1098 			}
1099 			if (!p)
1100 			{
1101 				if ((o & CX_UNARY) && c == '/')
1102 					goto quote;
1103 				if (cx->disc->errorf)
1104 				{
1105 					if (o & CX_UNARY)
1106 						(*cx->disc->errorf)(cx, cx->disc, 2, "%s operand expected [o=%04x]", cxcontext(cx), o);
1107 					else
1108 						(*cx->disc->errorf)(cx, cx->disc, 2, "%s unknown operator", cxcontext(cx));
1109 				}
1110 				goto bad;
1111 			}
1112 			if (o & CX_UNARY)
1113 			{
1114 				if (x)
1115 					goto operator_expected;
1116 			}
1117 			else
1118 			{
1119 				if (!x)
1120 					goto operand_expected;
1121 			}
1122 			if (precedence >= p && o != CX_SET)
1123 			{
1124 				while (i--)
1125 					back(cx);
1126 				goto done;
1127 			}
1128 			z = 0;
1129 			if (!(o & CX_UNARY) && cx->table->logical[o])
1130 			{
1131 				if (cc->type != cx->state->type_number && !code(cx, cc, expr, CX_LOG, 0, cc->type, cx->state->type_void, NiL, 0, NiL))
1132 					goto bad;
1133 				if (o == CX_ANDAND || o == CX_OROR)
1134 				{
1135 					z = sfstrtell(cc->xp);
1136 					if (!code(cx, cc, expr, (o == CX_ANDAND) ? CX_SC0 : CX_SC1, 0, cx->state->type_number, cx->state->type_void, NiL, 0, NiL))
1137 						goto bad;
1138 				}
1139 			}
1140 			t = cc->type;
1141 			if (parse(cx, cc, expr, p, NiL) != cx->state->type_void || cx->error)
1142 				goto bad;
1143 			if (cx->table->logical[o] && cc->type != cx->state->type_number && !code(cx, cc, expr, CX_LOG, 0, cc->type, cx->state->type_void, NiL, 0, NiL))
1144 				goto bad;
1145 			if (o != CX_SET && ((o & CX_UNARY) ? !code(cx, cc, expr, o, 0, cc->type, cx->state->type_void, NiL, 0, NiL) : !code(cx, cc, expr, o, -1, t, cc->type, NiL, 0, h)))
1146 				goto bad;
1147 			if (cx->table->comparison[o] || cx->table->logical[o])
1148 				h = 0;
1149 			if (v)
1150 			{
1151 				if (v->type != cc->type)
1152 				{
1153 					if (v->type != cx->state->type_void)
1154 					{
1155 						if (cx->disc->errorf)
1156 							(*cx->disc->errorf)(cx, cx->disc, 2, "%s cannot assign %s to %s", cxcontext(cx), cc->type->name, v->type->name);
1157 						goto bad;
1158 					}
1159 					v->type = cc->type;
1160 				}
1161 				if (!code(cx, cc, expr, CX_SET, 0, cx->state->type_void, cc->type, v, 0, NiL))
1162 					goto bad;
1163 				v = 0;
1164 			}
1165 			if (z)
1166 				((Cxinstruction_t*)(sfstrbase(cc->xp) + z))->data.number = (sfstrtell(cc->xp) - z) / sizeof(Cxinstruction_t);
1167 			x = 1;
1168 		}
1169 		else if (cx->ctype[c] & CX_CTYPE_DIGIT)
1170 		{
1171 			if (x)
1172 				goto operator_expected;
1173 			i = 0;
1174 			sfputc(cx->tp, c);
1175 			while (cx->ctype[c = next(cx)] & (CX_CTYPE_ALPHA|CX_CTYPE_DIGIT|CX_CTYPE_FLOAT))
1176 			{
1177 				sfputc(cx->tp, c);
1178 				switch (c)
1179 				{
1180 				case '#':
1181 					i = 4;
1182 					break;
1183 				case '.':
1184 					i = 1;
1185 					break;
1186 				case 'e':
1187 				case 'E':
1188 					if (i < 3)
1189 					{
1190 						i = 3;
1191 						if ((c = next(cx)) == '-' || c == '+')
1192 							sfputc(cx->tp, c);
1193 						else
1194 							back(cx);
1195 					}
1196 					break;
1197 				}
1198 			}
1199 			back(cx);
1200 			s = sfstruse(cx->tp);
1201 			if (!(i &= 1))
1202 				n = (double)strtonll(s, &e, NiL, 0);
1203 			if (i || *e)
1204 				n = strtod(s, &e);
1205 			if (*e)
1206 			{
1207 				if (cx->disc->errorf)
1208 					(*cx->disc->errorf)(cx, cx->disc, 2, "%s: invalid numeric constant", s);
1209 				goto bad;
1210 			}
1211 			if (!code(cx, cc, expr, CX_NUM, 1, cx->state->type_number, cx->state->type_void, NiL, n, NiL))
1212 				goto bad;
1213 			x = 1;
1214 		}
1215 		else if ((cx->ctype[c] & CX_CTYPE_ALPHA) && c != '.')
1216 		{
1217 			if (x)
1218 				goto operator_expected;
1219 		alpha:
1220 			if (!(v = variable(cx, cc, c, m, &t)))
1221 			{
1222 				if (t)
1223 				{
1224 					x = 2;
1225 					continue;
1226 				}
1227 				goto bad;
1228 			}
1229 			h = v;
1230 			m = 0;
1231 			while ((c = next(cx)) == ' ' || c == '\t' || c == '\r');
1232 			if (v->function)
1233 			{
1234 				i = 0;
1235 				if (c == '(')
1236 					p = q = ')';
1237 				else
1238 				{
1239 					p = '\n';
1240 					q = ';';
1241 					if (c && c != p && c != q)
1242 						back(cx);
1243 				}
1244 				while (c == ' ' || c == '\t' || c == '\r')
1245 					c = next(cx);
1246 				if (v->type != cx->state->type_void && !code(cx, cc, expr, CX_NUM, 1, cx->state->type_number, cx->state->type_void, NiL, 0, NiL))
1247 					goto bad;
1248 				o = 0;
1249 				s = (char*)v->prototype;
1250 				e = 0;
1251 				if ((r = prototype(cx, cc, v, &t, &s, &e, &o)) < 0)
1252 					goto bad;
1253 				if (c != p && c != q)
1254 				{
1255 					cc->collecting++;
1256 					k = cc->paren;
1257 					cc->paren = p == ')';
1258 					for (;;)
1259 					{
1260 						z = sfstrtell(cc->xp);
1261 						if (parse(cx, cc, expr, cx->table->precedence[CX_CALL], NiL) != cx->state->type_void || cx->error)
1262 						{
1263 							cc->collecting--;
1264 							cc->paren = k;
1265 							goto bad;
1266 						}
1267 						if (sfstrtell(cc->xp) != z)
1268 						{
1269 							i++;
1270 							while (cc->type != t && t != cx->state->type_void)
1271 							{
1272 								if (o && r > 0 && (r = prototype(cx, cc, v, &t, &s, &e, &o)) > 0)
1273 									continue;
1274 								if (r < 0)
1275 								{
1276 									cc->collecting--;
1277 									cc->paren = k;
1278 									goto bad;
1279 								}
1280 								if (cx->disc->errorf)
1281 								{
1282 									if (r < 0)
1283 										(*cx->disc->errorf)(cx, cx->disc, 2, "%s too many arguments for %s(%s)", cxcontext(cx), v->name, v->prototype);
1284 									else
1285 										(*cx->disc->errorf)(cx, cx->disc, 2, "%s argument type mismatch for %s(%s)", cxcontext(cx), v->name, v->prototype);
1286 								}
1287 								cc->collecting--;
1288 								cc->paren = k;
1289 								goto bad;
1290 							}
1291 							if ((r = prototype(cx, cc, v, &t, &s, &e, &o)) < 0)
1292 							{
1293 								cc->collecting--;
1294 								cc->paren = k;
1295 								goto bad;
1296 							}
1297 						}
1298 						if (!(c = next(cx)))
1299 						{
1300 							if (cx->disc->errorf)
1301 								(*cx->disc->errorf)(cx, cx->disc, 2, "%s EOF in formal argument list", cxcontext(cx));
1302 							cc->collecting--;
1303 							cc->paren = k;
1304 							goto bad;
1305 						}
1306 						if (c == p || c == q)
1307 							break;
1308 						if (c != ',')
1309 							back(cx);
1310 					}
1311 					cc->collecting--;
1312 					cc->paren = k;
1313 					if (c != p && c != q)
1314 					{
1315 						if (cx->disc->errorf)
1316 							(*cx->disc->errorf)(cx, cx->disc, 2, "%s missing %s in formal argument list", cxcontext(cx), p == '\n' ? "statement terminator" : ")");
1317 						goto bad;
1318 					}
1319 				}
1320 				if (r > 0 && !o)
1321 				{
1322 					if (cx->disc->errorf)
1323 						(*cx->disc->errorf)(cx, cx->disc, 2, "%s not enough arguments for %s(%s)", cxcontext(cx), v->name, v->prototype);
1324 					goto bad;
1325 				}
1326 				if (c == '\n')
1327 					back(cx);
1328 				if (!code(cx, cc, expr, CX_CALL, -i, v->type, cx->state->type_void, v, 0, NiL))
1329 					goto bad;
1330 				if (g)
1331 				{
1332 					if (codecast(cx, cc, g, cast, NiL))
1333 						goto bad;
1334 					g = 0;
1335 				}
1336 				v = 0;
1337 			}
1338 			else if (c == '(')
1339 			{
1340 				if (cx->disc->errorf)
1341 					(*cx->disc->errorf)(cx, cx->disc, 2, "%s: unknown function", v->name);
1342 				goto bad;
1343 			}
1344 			else
1345 				back(cx);
1346 			x = 1;
1347 		}
1348 		else
1349 			switch (c)
1350 			{
1351 			case 0:
1352 				goto done;
1353 			case '.':
1354 				if (!x && !v && (v = variable(cx, cc, c, m, 0)))
1355 					x = 1;
1356 				if (!x || !v ||
1357 				    (!(m = v->type) || !m->member || !m->member->members) &&
1358 				    (!(m = v->type->base) || !m->member || !m->member->members))
1359 				{
1360 					if (cx->disc->errorf)
1361 						(*cx->disc->errorf)(cx, cx->disc, 2, "%s struct or union variable expected", cxcontext(cx));
1362 					goto bad;
1363 				}
1364 				if (!code(cx, cc, expr, CX_GET, 1, v->type, cx->state->type_void, v, 0, NiL))
1365 					goto bad;
1366 				x = 0;
1367 				v = 0;
1368 				continue;
1369 			case ',':
1370 				if (cc->collecting)
1371 				{
1372 					next(cx);
1373 					goto done;
1374 				}
1375 				if (!code(cx, cc, expr, CX_POP, -1, cx->state->type_void, cx->state->type_void, NiL, 0, NiL))
1376 					goto bad;
1377 				goto again;
1378 			case ';':
1379 				if (cc->collecting)
1380 					x = 1;
1381 				else
1382 					precedence = 0;
1383 				goto done;
1384 			case '#':
1385 				clear(cx);
1386 				goto done;
1387 			case '\n':
1388 				if (cc->collecting)
1389 				{
1390 					if (!cc->paren)
1391 						goto done;
1392 				}
1393 				else if (precedence <= cx->table->precedence[CX_CALL] || precedence > cx->table->precedence[CX_PAREN] && x)
1394 					goto done;
1395 				continue;
1396 			case ' ':
1397 			case '\t':
1398 			case '\r':
1399 				continue;
1400 			case '(':
1401 				if (x)
1402 					goto operator_expected;
1403 				e = cx->include->next;
1404 				if (cx->ctype[c = next(cx)] & CX_CTYPE_ALPHA)
1405 				{
1406 					if (!identifier(cx, cc, c, &w) && (c = next(cx)) == ')' && ((c = next(cx)) == '(' || (cx->ctype[c] & CX_CTYPE_ALPHA)))
1407 					{
1408 						if (!(g = cxtype(cx, w.value.string.data, cx->disc)))
1409 						{
1410 							if (cx->disc->errorf)
1411 								(*cx->disc->errorf)(cx, cx->disc, 2, "%s unknown type cast", cxcontext(cx), w.value.string.data);
1412 							goto bad;
1413 						}
1414 						if (c != '(')
1415 							goto alpha;
1416 					}
1417 					else
1418 						cx->include->next = e;
1419 				}
1420 				else
1421 					cx->include->next = e;
1422 				x = 1;
1423 				k = cc->balanced;
1424 				cc->balanced = 0;
1425 				o = cc->collecting;
1426 				cc->collecting = 0;
1427 				u = parse(cx, cc, expr, cx->table->precedence[CX_PAREN], &f);
1428 				h = f;
1429 				cc->collecting = o;
1430 				cc->balanced = k;
1431 				if (u != cx->state->type_void || cx->error)
1432 					goto bad;
1433 				for (;;)
1434 				{
1435 					switch (next(cx))
1436 					{
1437 					case ' ':
1438 					case '\n':
1439 					case '\r':
1440 					case '\t':
1441 						continue;
1442 					case ')':
1443 						if (k)
1444 							goto keep;
1445 						do
1446 						{
1447 							if (!(c = next(cx)) || c == ';' || c == '\n')
1448 							{
1449 								if (cc->level > 0)
1450 									goto done;
1451 								goto keep;
1452 							}
1453 						} while (isspace(c));
1454 						s = cx->include->next;
1455 						back(cx);
1456 						if (c == '|' || c == '?')
1457 							do
1458 							{
1459 								if (s >= cx->include->last || *s == '{')
1460 									goto keep;
1461 							} while (isspace(*s++));
1462 						break;
1463 					default:
1464 						back(cx);
1465 						if (cx->disc->errorf)
1466 							(*cx->disc->errorf)(cx, cx->disc, 2, "%s closing ) expected", cxcontext(cx));
1467 						goto bad;
1468 					}
1469 					break;
1470 				}
1471 				if (g)
1472 				{
1473 					if (cx->disc->errorf)
1474 						(*cx->disc->errorf)(cx, cx->disc, 2, "%s cast not implemented yet", cxcontext(cx));
1475 					g = 0;
1476 				}
1477 				break;
1478 			case ')':
1479 				if (!precedence)
1480 				{
1481 					if (cx->disc->errorf)
1482 						(*cx->disc->errorf)(cx, cx->disc, 2, "%s too many )'s", cxcontext(cx));
1483 					goto bad;
1484 				}
1485 				goto done;
1486 			case '?':
1487 				if (!x)
1488 					goto operand_expected;
1489 				if (precedence >= cx->table->precedence[CX_TST])
1490 					goto done;
1491 				if ((c = next(cx)) != ':')
1492 				{
1493 					back(cx);
1494 					if (parse(cx, cc, expr, cx->table->precedence[CX_TST], NiL) != cx->state->type_void || cx->error)
1495 						goto bad;
1496 					if (next(cx) != ':')
1497 					{
1498 						back(cx);
1499 						if (cx->disc->errorf)
1500 							(*cx->disc->errorf)(cx, cx->disc, 2, "%s : expected for ? operator", cxcontext(cx));
1501 						goto bad;
1502 					}
1503 				}
1504 				else if (!code(cx, cc, expr, CX_NOP, 0, cx->state->type_void, cx->state->type_void, NiL, 0, NiL))
1505 					goto bad;
1506 				if (parse(cx, cc, expr, cx->table->precedence[CX_TST], NiL) != cx->state->type_void || cx->error)
1507 					goto bad;
1508 				if (!code(cx, cc, expr, CX_TST, 0, cx->state->type_void, cx->state->type_void, NiL, 0, NiL))
1509 					goto bad;
1510 				break;
1511 			case ':':
1512 				goto done;
1513 			case '"':
1514 			case '\'':
1515 			case '/':
1516 			quote:
1517 				if (x)
1518 					goto operator_expected;
1519 				while ((p = next(cx)) != c)
1520 				{
1521 					if (!p)
1522 					{
1523 						if (cx->disc->errorf)
1524 							(*cx->disc->errorf)(cx, cx->disc, 2, "%s EOF in string literal", cxcontext(cx));
1525 						goto bad;
1526 					}
1527 					sfputc(cx->tp, p);
1528 					if (p == '\\' && (p = next(cx)))
1529 						sfputc(cx->tp, p);
1530 				}
1531 				stresc(s = sfstruse(cx->tp));
1532 				if (!(s = vmstrdup(cc->vm, s)))
1533 				{
1534 					if (cx->disc->errorf)
1535 						(*cx->disc->errorf)(cx, cx->disc, 2, "out of space");
1536 					goto bad;
1537 				}
1538 				if (!code(cx, cc, expr, CX_STR, 1, cx->state->type_string, cx->state->type_void, s, 0, NiL))
1539 					goto bad;
1540 				x = 1;
1541 				break;
1542 			default:
1543 				if (cx->disc->errorf)
1544 					(*cx->disc->errorf)(cx, cx->disc, 2, "syntax error: '%c' not expected: %s", c, cxcontext(cx));
1545 				goto bad;
1546 			}
1547 	}
1548 	if (!x)
1549 	{
1550 		if (ref)
1551 			*ref = h;
1552 		cc->level--;
1553 		return t;
1554 	}
1555  keep:
1556 	c = 0;
1557  done:
1558 	if (!x && precedence > cx->table->precedence[CX_CALL])
1559 		goto operand_expected;
1560 	if (c && (precedence || c != '\n' && c != ';'))
1561 		back(cx);
1562 	if (x == 2)
1563 	{
1564 		if (!code(cx, cc, expr, CX_NUM, 1, cx->state->type_type_t, cx->state->type_void, t, 0, NiL))
1565 			goto bad;
1566 	}
1567 	else if (v)
1568 	{
1569 		if (cxisvoid(v->type))
1570 			goto undefined;
1571 		if (!code(cx, cc, expr, CX_GET, 1, v->type, cx->state->type_void, v, 0, NiL))
1572 			goto bad;
1573 		if (g && codecast(cx, cc, g, cast, NiL))
1574 			goto bad;
1575 	}
1576 	if (ref)
1577 		*ref = h;
1578 	cc->level--;
1579 	return cx->state->type_void;
1580  undefined:
1581 	if (cx->disc->errorf)
1582 		(*cx->disc->errorf)(cx, cx->disc, 2, "%s undefined variable", cxcontext(cx));
1583 	goto bad;
1584  operator_expected:
1585 	if (cc->collecting)
1586 		goto done;
1587 	if (cx->disc->errorf)
1588 		(*cx->disc->errorf)(cx, cx->disc, 2, "%s operator expected", cxcontext(cx));
1589 	goto bad;
1590  operand_expected:
1591 	if (cx->disc->errorf)
1592 		(*cx->disc->errorf)(cx, cx->disc, 2, "%s operand expected", cxcontext(cx));
1593  bad:
1594 	cx->error = cxtell(cx);
1595 	if (precedence)
1596 		back(cx);
1597 	else
1598 		clear(cx);
1599 	cc->level--;
1600 	return 0;
1601 }
1602 
1603 /*
1604  * allocate an expression node
1605  */
1606 
1607 static Cxexpr_t*
node(Cx_t * cx,Cxcompile_t * cc,size_t n)1608 node(Cx_t* cx, Cxcompile_t* cc, size_t n)
1609 {
1610 	Cxexpr_t*	expr;
1611 
1612 	if (!(expr = vmnewof(cc->vm, 0, Cxexpr_t, 1, n)))
1613 	{
1614 		if (cx->disc->errorf)
1615 			(*cx->disc->errorf)(NiL, cx->disc, 2, "out of space");
1616 		return 0;
1617 	}
1618 	return expr;
1619 }
1620 
1621 /*
1622  * compile the next complete expression
1623  */
1624 
1625 static Cxexpr_t*
compile(Cx_t * cx,Cxcompile_t * cc,int balanced)1626 compile(Cx_t* cx, Cxcompile_t* cc, int balanced)
1627 {
1628 	Cxexpr_t*		expr;
1629 	size_t			pos;
1630 	size_t			n;
1631 
1632 	cc->pp = 4;
1633 	cc->balanced = balanced;
1634 	cc->type = cx->state->type_void;
1635 	if (!(expr = node(cx, cc, sizeof(Cxquery_t))))
1636 		return 0;
1637 	expr->query = (Cxquery_t*)(expr + 1);
1638 	sfstrseek(cc->xp, 0, SEEK_SET);
1639 	if (!code(cx, cc, expr, CX_END, 0, cx->state->type_void, cx->state->type_void, NiL, 0, NiL))
1640 		return 0;
1641 	pos = sfstrtell(cc->xp);
1642 	if (parse(cx, cc, expr, 0, NiL) != cx->state->type_void || cx->error)
1643 		return 0;
1644 #if 0
1645 	/*
1646 	 * this is a failed attempt at a logical cast for naked variable tests
1647 	 */
1648 
1649 	{
1650 		Cxinstruction_t*	pc;
1651 
1652 		pc = (Cxinstruction_t*)(sfstrseek(cc->xp, 0, SEEK_CUR) - 1 * sizeof(Cxinstruction_t));
1653 		if (pc->op == CX_GET && !code(cx, cc, expr, CX_LOG, 0, pc->type, cx->state->type_void, NiL, 0, NiL))
1654 			return 0;
1655 	}
1656 #endif
1657 	if (!code(cx, cc, expr, CX_END, 0, cx->state->type_void, cx->state->type_void, NiL, 0, NiL))
1658 		return 0;
1659 	n = sfstrtell(cc->xp) - pos;
1660 	if (!(expr->query->prog = vmnewof(cc->vm, 0, Cxinstruction_t, n / sizeof(Cxinstruction_t), 0)))
1661 	{
1662 		if (cx->disc->errorf)
1663 			(*cx->disc->errorf)(NiL, cx->disc, 2, "out of space");
1664 		return 0;
1665 	}
1666 	memcpy(expr->query->prog, sfstrbase(cc->xp) + pos, n);
1667 	if (cc->depth > cc->stacksize)
1668 	{
1669 		cc->stacksize = roundof(cc->depth, 64);
1670 		if (!(cc->stack = vmnewof(cc->vm, cc->stack, Cxoperand_t, cc->stacksize, 0)))
1671 		{
1672 			if (cx->disc->errorf)
1673 				(*cx->disc->errorf)(cx, cx->disc, 2, "out of space");
1674 			return 0;
1675 		}
1676 	}
1677 	return expr;
1678 }
1679 
1680 /*
1681  * compose dynamic and interpreted queries
1682  */
1683 
1684 static Cxexpr_t*
compose(Cx_t * cx,Cxcompile_t * cc,int prec)1685 compose(Cx_t* cx, Cxcompile_t* cc, int prec)
1686 {
1687 	Cxexpr_t*	fp;
1688 	Cxexpr_t*	rp;
1689 	Cxexpr_t*	gp;
1690 	int*		x;
1691 	char**		v;
1692 	char*		f;
1693 	char*		r;
1694 	char*		s;
1695 	int		c;
1696 	int		m;
1697 	int		n;
1698 	int		p;
1699 	int		q;
1700 	unsigned long	o;
1701 
1702 	fp = 0;
1703 	rp = 0;
1704 	p = 0;
1705 	q = 0;
1706 	r = 0;
1707 	o = sfstrtell(cc->tp);
1708 	for (;;)
1709 	{
1710 		switch (c = next(cx))
1711 		{
1712 		case '"':
1713 		case '\'':
1714 			if (c == q)
1715 				q = 0;
1716 			else if (!q)
1717 				q = c;
1718 			else
1719 				sfputc(cc->tp, c);
1720 			continue;
1721 		case '\\':
1722 			if (!(c = next(cx)))
1723 				break;
1724 			sfputc(cc->tp, c);
1725 			continue;
1726 		case '{':
1727 			if (q)
1728 				sfputc(cc->tp, c);
1729 			else if (sfstrtell(cc->tp) != o)
1730 				goto syntax;
1731 			else
1732 			{
1733 				if (!(fp = compose(cx, cc, '}')))
1734 					return 0;
1735 				if (next(cx) != '}')
1736 				{
1737 					if (cx->disc->errorf)
1738 						(*cx->disc->errorf)(cx, cx->disc, 2, "unbalanced {...}: %s", cxcontext(cx));
1739 					return 0;
1740 				}
1741 				while (isspace(c = next(cx)));
1742 				back(cx);
1743 				if (c != 0 && c != '|' && c != '?' && c != ':' && c != ';' && c != ',' && c != '}' && c != '>')
1744 				{
1745 					if (cx->disc->errorf)
1746 						(*cx->disc->errorf)(NiL, cx->disc, 2, "operator expected: %s", cxcontext(cx));
1747 					return 0;
1748 				}
1749 				if (fp->next || fp->pass || fp->fail)
1750 				{
1751 					gp = fp;
1752 					if (!(fp = node(cx, cc, 0)))
1753 						return 0;
1754 					fp->group = gp;
1755 				}
1756 			}
1757 			continue;
1758 		case '(':
1759 			if (q)
1760 				sfputc(cc->tp, c);
1761 			else if (sfstrtell(cc->tp) != o)
1762 				goto syntax;
1763 			else
1764 			{
1765 				back(cx);
1766 				if (!(fp = compile(cx, cc, 0)))
1767 					return 0;
1768 				if (!(c = next(cx)))
1769 					return fp;
1770 				back(cx);
1771 			}
1772 			continue;
1773 		case ')':
1774 			if (q)
1775 				sfputc(cc->tp, c);
1776 			else
1777 				goto syntax;
1778 			continue;
1779 		case ':':
1780 			if (next(cx) == c)
1781 			{
1782 				sfputc(cc->tp, c);
1783 				sfputc(cc->tp, c);
1784 				continue;
1785 			}
1786 			back(cx);
1787 			/*FALLTHROUGH*/
1788 		case ',':
1789 			if (c == ',')
1790 				o = sfstrtell(cc->tp);
1791 			/*FALLTHROUGH*/
1792 		case 0:
1793 		case ' ':
1794 		case '\n':
1795 		case '\r':
1796 		case '\t':
1797 		case '>':
1798 		case '|':
1799 		case '?':
1800 		case ';':
1801 		case '}':
1802 			if (q)
1803 			{
1804 				if (c)
1805 					sfputc(cc->tp, c);
1806 				else
1807 				{
1808 					if (cx->disc->errorf)
1809 						(*cx->disc->errorf)(cx, cx->disc, 2, "unterminated %c quote: %s", q, cxcontext(cx));
1810 					return 0;
1811 				}
1812 			}
1813 			else
1814 			{
1815 				if (sfstrtell(cc->tp) != p)
1816 				{
1817 					sfputc(cc->tp, 0);
1818 					if (r)
1819 					{
1820 						s = sfstrbase(cc->tp) + p;
1821 						if (!*s)
1822 							goto syntax;
1823 						if (!(f = (char*)vmstrdup(cc->vm, s)))
1824 						{
1825 							if (cx->disc->errorf)
1826 								(*cx->disc->errorf)(NiL, cx->disc, 2, "out of space");
1827 							return 0;
1828 						}
1829 						sfstrseek(cc->tp, p, SEEK_SET);
1830 					}
1831 					else
1832 					{
1833 						sfwrite(cx->tp, &p, sizeof(p));
1834 						p = sfstrtell(cc->tp);
1835 					}
1836 				}
1837 				if (c == '>')
1838 				{
1839 					if (r)
1840 						goto syntax;
1841 					else if (next(cx) == '>')
1842 						r = "a";
1843 					else
1844 					{
1845 						back(cx);
1846 						r = "w";
1847 					}
1848 				}
1849 				else if (!isspace(c))
1850 				{
1851 					if (!(n = sfstrtell(cc->tp)) && prec == '}')
1852 					{
1853 						back(cx);
1854 						return node(cx, cc, 0);
1855 					}
1856 					if (!fp)
1857 					{
1858 						if (!n)
1859 							goto syntax;
1860 						m = sfstrtell(cx->tp) / sizeof(p);
1861 						if (!(fp = node(cx, cc, (m + 1) * sizeof(char*) + n)))
1862 							return 0;
1863 						fp->argv = v = (char**)(fp + 1);
1864 						s = (char*)(v + m + 1);
1865 						memcpy(s, sfstrseek(cc->tp, 0, SEEK_SET), n);
1866 						x = (int*)sfstrseek(cx->tp, 0, SEEK_SET);
1867 						while (m-- > 0)
1868 							*v++ = s + *x++;
1869 						*v = 0;
1870 						if (!(fp->query = cxquery(cx, s, cx->disc)) && !(cx->test & 0x00000400))
1871 						{
1872 							if (cx->disc->errorf)
1873 								(*cx->disc->errorf)(cx, cx->disc, 2, "%s: query not found", s);
1874 							return 0;
1875 						}
1876 						if (fp->query->ref && (*fp->query->ref)(cx, fp, fp->argv, cx->disc))
1877 							return 0;
1878 					}
1879 					else if (n)
1880 						goto syntax;
1881 					if (r)
1882 					{
1883 						if (!(fp->op = sfopen(NiL, f, r)))
1884 						{
1885 							if (cx->disc->errorf)
1886 								(*cx->disc->errorf)(cx, cx->disc, ERROR_SYSTEM|2, "%s: cannot write", f);
1887 							return 0;
1888 						}
1889 						fp->file = f;
1890 						r = 0;
1891 					}
1892 					if (!rp)
1893 						rp = fp;
1894 					if (c == 0)
1895 						break;
1896 					if (prec == '|' || prec == '?' || prec == ';')
1897 					{
1898 						if (c == ';' || c == '}')
1899 						{
1900 							back(cx);
1901 							break;
1902 						}
1903 					}
1904 					else if (prec == '}')
1905 					{
1906 						if (c == '}')
1907 						{
1908 							back(cx);
1909 							break;
1910 						}
1911 					}
1912 					if (c == ':')
1913 					{
1914 						back(cx);
1915 						break;
1916 					}
1917 					else if (c == ';' || c == ',')
1918 					{
1919 						if (!(fp = fp->next = compose(cx, cc, c)))
1920 							return 0;
1921 					}
1922 					else if (c == '?')
1923 					{
1924 						if (peek(cx, 1) != ':' && !(fp->pass = compose(cx, cc, c)))
1925 							return 0;
1926 						if (peek(cx, 1) == ':')
1927 						{
1928 							next(cx);
1929 							if (!(fp->fail = compose(cx, cc, c)))
1930 								return 0;
1931 						}
1932 					}
1933 					else if (!(fp->pass = compose(cx, cc, c)))
1934 						return 0;
1935 					p = 0;
1936 				}
1937 			}
1938 			continue;
1939 		default:
1940 			sfputc(cc->tp, c);
1941 			continue;
1942 		}
1943 		break;
1944 	}
1945 	return rp;
1946  syntax:
1947 	if (cx->disc->errorf)
1948 	{
1949 		if (c)
1950 			(*cx->disc->errorf)(cx, cx->disc, 2, "syntax error: '%c' not expected: %s", c, cxcontext(cx));
1951 		else
1952 			(*cx->disc->errorf)(cx, cx->disc, 2, "syntax error: unterminated expression: %s", cxcontext(cx));
1953 	}
1954 	return 0;
1955 }
1956 
1957 /*
1958  * propagate expression defaults
1959  */
1960 
1961 static void
defaults(register Cxcompile_t * cc,register Cxexpr_t * expr,Cxexpr_t * parent,Sfio_t * op)1962 defaults(register Cxcompile_t* cc, register Cxexpr_t* expr, Cxexpr_t* parent, Sfio_t* op)
1963 {
1964 	static Cxquery_t	null;
1965 
1966 	do
1967 	{
1968 		expr->vm = cc->vm;
1969 		expr->done = cc->done;
1970 		expr->stack = cc->stack;
1971 		expr->stacksize = cc->stacksize;
1972 		expr->reclaim = cc->reclaim;
1973 		expr->parent = parent;
1974 		if (!expr->query)
1975 			expr->query = &null;
1976 		if (!expr->op)
1977 			expr->op = op;
1978 		if (expr->group)
1979 			defaults(cc, expr->group, parent, expr->op);
1980 		if (expr->pass)
1981 			defaults(cc, expr->pass, expr, expr->op);
1982 		if (expr->fail)
1983 			defaults(cc, expr->fail, expr, expr->op);
1984 	} while (expr = expr->next);
1985 }
1986 
1987 /*
1988  * cxlist helper
1989  */
1990 
1991 static void
list(Sfio_t * sp,Cxexpr_t * expr)1992 list(Sfio_t* sp, Cxexpr_t* expr)
1993 {
1994 	register Cxinstruction_t*	pc;
1995 	char**				v;
1996 
1997 	for (;;)
1998 	{
1999 		if (expr->group)
2000 		{
2001 			sfputc(sp, '{');
2002 			list(sp, expr->group);
2003 			sfputc(sp, '}');
2004 		}
2005 		else if (expr->argv)
2006 			for (v = expr->argv; *v; v++)
2007 				sfputr(sp, *v, *(v + 1) ? ' ' : -1);
2008 		else if (pc = expr->query->prog)
2009 		{
2010 			sfputc(sp, '(');
2011 			while (pc->op != CX_END)
2012 			{
2013 				sfprintf(sp, "%s %s %d ", cxcodename(pc->op), pc->type->name, pc->pp > 0 ? pc->pp : pc->pp - 1);
2014 				if (pc->op == CX_GET || pc->op == CX_SET || pc->op == CX_REF || pc->op == CX_CALL)
2015 					sfprintf(sp, "%s", pc->data.variable->name);
2016 				else
2017 					sfprintf(sp, "%I*g", sizeof(pc->data.number), pc->data.number);
2018 				sfputc(sp, ';');
2019 				pc++;
2020 			}
2021 			sfputc(sp, ')');
2022 		}
2023 		else
2024 			sfprintf(sp, "()");
2025 		if (expr->file)
2026 			sfprintf(sp, ">%s", expr->file);
2027 		if (expr->fail)
2028 		{
2029 			sfputc(sp, '?');
2030 			if (expr->pass)
2031 				list(sp, expr->pass);
2032 			sfputc(sp, ':');
2033 			list(sp, expr->fail);
2034 		}
2035 		else if (expr->pass)
2036 		{
2037 			sfputc(sp, '|');
2038 			list(sp, expr->pass);
2039 		}
2040 		if (!(expr = expr->next))
2041 			break;
2042 		sfputc(sp, ';');
2043 	}
2044 }
2045 
2046 /*
2047  * list query expression
2048  */
2049 
2050 int
cxlist(Cx_t * cx,Cxexpr_t * expr,Sfio_t * sp)2051 cxlist(Cx_t* cx, Cxexpr_t* expr, Sfio_t* sp)
2052 {
2053 	list(sp, expr);
2054 	sfputc(sp, '\n');
2055 	return sfsync(sp);
2056 }
2057 
2058 /*
2059  * compile the next expression/query
2060  */
2061 
2062 Cxexpr_t*
cxcomp(Cx_t * cx)2063 cxcomp(Cx_t* cx)
2064 {
2065 	Cxcompile_t*	cc;
2066 	Cxexpr_t*	expr;
2067 	int		c;
2068 
2069 	error(-1, "cxcomp push include=%p file=%s eof=%d", cx->include, cx->include ? cx->include->file : 0, cx->eof);
2070 	if (cx->eof || !cx->include && (cx->eof = 1))
2071 		return 0;
2072 	expr = 0;
2073 	if (!(cc = vmnewof(cx->vm, 0, Cxcompile_t, 1, 0)) || !(cc->tp = sfstropen()) || !(cc->xp = sfstropen()))
2074 		goto nospace;
2075 	cx->error = 0;
2076 	cc->reclaim = !!(cx->deletef = cxcallout(cx, CX_DEL, cx->state->type_void, cx->state->type_void, cx->disc));
2077 	cx->returnf = cxcallout(cx, CX_RET, cx->state->type_void, cx->state->type_void, cx->disc);
2078 	cx->referencef = cxcallout(cx, CX_REF, cx->state->type_string, cx->state->type_void, cx->disc);
2079 	if (sfsync(cx->op) < 0)
2080 	{
2081 		if (cx->disc->errorf)
2082 			(*cx->disc->errorf)(cx, cx->disc, 2, "write error");
2083 		goto done;
2084 	}
2085 	if (!(cc->vm = vmopen(Vmdcheap, Vmlast, 0)))
2086 		goto nospace;
2087 	cx->include->head = 1;
2088 	if (!(c = peek(cx, !cx->interactive)))
2089 	{
2090 		if (!cx->include->pop)
2091 			cx->eof = 1;
2092 		goto done;
2093 	}
2094 	else if (c == '{' || c == '(')
2095 	{
2096 		if (!(expr = compose(cx, cc, 0)))
2097 			goto done;
2098 		clear(cx);
2099 	}
2100 	else if (!(expr = compile(cx, cc, cx->flags & CX_BALANCED)))
2101 		goto done;
2102 	defaults(cc, expr, expr, sfstdout);
2103 	cc->vm = 0;
2104  	goto done;
2105  nospace:
2106 	if (cx->disc->errorf)
2107 		(*cx->disc->errorf)(cx, cx->disc, ERROR_SYSTEM|2, "out of space");
2108  done:
2109 	if (!cx->include && !(cx->flags & CX_BALANCED))
2110 		cx->eof = 1;
2111 	if (cc)
2112 	{
2113 		if (cc->tp)
2114 			sfstrclose(cc->tp);
2115 		if (cc->xp)
2116 			sfstrclose(cc->xp);
2117 		if (cc->vm)
2118 			vmclose(cc->vm);
2119 		vmfree(cx->vm, cc);
2120 	}
2121 	error(-1, "cxcomp done include=%p file=%s eof=%d", cx->include, cx->include ? cx->include->file : 0, cx->eof);
2122 	return expr;
2123 }
2124 
2125 /*
2126  * free a cxcomp() expr
2127  */
2128 
2129 int
cxfree(Cx_t * cx,Cxexpr_t * expr)2130 cxfree(Cx_t* cx, Cxexpr_t* expr)
2131 {
2132 	if (!expr->vm)
2133 		return -1;
2134 	cxatfree(cx, expr, NiL, NiL);
2135 	vmclose(expr->vm);
2136 	expr->vm = 0;
2137 	return 0;
2138 }
2139 
2140 ssize_t
cxtell(Cx_t * cx)2141 cxtell(Cx_t* cx)
2142 {
2143 	Cxinclude_t*	ip;
2144 
2145 	if (cx->eof)
2146 		return -1;
2147 	if (cx->error)
2148 		return cx->error;
2149 	if (!(ip = cx->include))
2150 		return -1;
2151 	if (ip->next >= ip->last)
2152 		return -1;
2153 	return ip->next - ip->base;
2154 }
2155