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