Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libdss/cxcomp.c
1808 views
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 <[email protected]> *
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
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
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
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
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*
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*
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
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*
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*
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
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
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
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*
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
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
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
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*
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
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*
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*
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*
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*
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
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
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
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*
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
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
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
2156