1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=4: */
3
4 /*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17
18
19 /*
20 * grammar support routines
21 * stuffed in a header so exparse.y can work
22 * with both yacc and bison
23 * sometimes free stuff can cost a lot
24 */
25
26 #if !defined(_EXGRAM_H)
27 #define _EXGRAM_H
28
29 #if !defined(_EXPARSE_H)
30 #define _EXPARSE_H
31 #endif
32
33 #include "exlib.h"
34 #include <string.h>
35
36 #define exlex() extoken_fn(expr.program)
37
38 #define ALLOCATE(p,x) (x*)exalloc(p,sizeof(x))
39 #define QUALIFY(r,s) ((r)&&(expr.program->disc->flags&EX_QUALIFY)?qualify(r,s):(s))
40
41 static int a2t[] = { 0, FLOATING, INTEGER, STRING };
42 static Switch_t swstate;
43
44 Exstate_t expr;
45
T(int t)46 static int T(int t)
47 {
48 if (expr.program->disc->types)
49 return expr.program->disc->types[t & TMASK];
50 else
51 return a2t[t & TMASK];
52 }
53
54 /*
55 * allocate and initialize a new expression node in the current program
56 */
57
58 Exnode_t*
exnewnode(Expr_t * p,int op,int binary,int type,Exnode_t * left,Exnode_t * right)59 exnewnode(Expr_t* p, int op, int binary, int type, Exnode_t* left, Exnode_t* right)
60 {
61 register Exnode_t* x;
62
63 x = ALLOCATE(p, Exnode_t);
64 x->op = op;
65 x->type = type;
66 x->binary = binary;
67 x->local.number = 0;
68 x->local.pointer = 0;
69 x->data.operand.left = left;
70 x->data.operand.right = right;
71 return x;
72 }
73
74 /*
75 * free node x and its children
76 */
77
78 void
exfreenode(Expr_t * p,register Exnode_t * x)79 exfreenode(Expr_t* p, register Exnode_t* x)
80 {
81 register Print_t* pr;
82 register Exref_t* r;
83 Print_t* pn;
84 Exref_t* rn;
85 int i;
86
87 switch (x->op)
88 {
89 case CALL:
90 if (x->data.call.args)
91 exfreenode(p, x->data.call.args);
92 break;
93 case CONSTANT:
94 break;
95 case DEFAULT:
96 if (x->data.select.next)
97 exfreenode(p, x->data.select.next);
98 break;
99 case DYNAMIC:
100 if (x->data.variable.index)
101 exfreenode(p, x->data.variable.index);
102 if (x->data.variable.symbol->local.pointer)
103 {
104 dtclose((Dt_t*)x->data.variable.symbol->local.pointer);
105 x->data.variable.symbol->local.pointer = 0;
106 }
107 break;
108 case '#':
109 if (x->data.variable.symbol->local.pointer) {
110 dtclose((Dt_t *) x->data.variable.symbol->local.pointer);
111 x->data.variable.symbol->local.pointer = 0;
112 }
113 break;
114 // case IN_OP:
115 case UNSET:
116 if (x->data.variable.index)
117 exfreenode(p, x->data.variable.index);
118 if (x->data.variable.symbol->local.pointer) {
119 dtclose((Dt_t *) x->data.variable.symbol->local.pointer);
120 x->data.variable.symbol->local.pointer = 0;
121 }
122 break;
123 case ITERATE:
124 case ITERATER:
125 if (x->data.generate.statement)
126 exfreenode(p, x->data.generate.statement);
127 break;
128 case ID:
129 rn = x->data.variable.reference;
130 while ((r = rn))
131 {
132 rn = r->next;
133 vmfree(p->vm, r);
134 }
135 if (x->data.variable.index)
136 exfreenode(p, x->data.variable.index);
137 break;
138 case GSUB:
139 case SUB:
140 case SUBSTR:
141 exfreenode(p, x->data.string.base);
142 exfreenode(p, x->data.string.pat);
143 if (x->data.string.repl)
144 exfreenode(p, x->data.string.repl);
145 break;
146 case TOKENS:
147 case SPLIT:
148 if (x->data.split.seps)
149 exfreenode(p, x->data.split.seps);
150 exfreenode(p, x->data.split.string);
151 if (x->data.split.array->local.pointer) {
152 dtclose((Dt_t *) x->data.split.array->local.pointer);
153 x->data.split.array->local.pointer = 0;
154 }
155 break;
156 case PRINT:
157 exfreenode(p, x->data.operand.left);
158 break;
159 case PRINTF:
160 case SPRINTF:
161 if (x->data.print.descriptor)
162 exfreenode(p, x->data.print.descriptor);
163 pn = x->data.print.args;
164 while ((pr = pn))
165 {
166 for (i = 0; i < elementsof(pr->param) && pr->param[i]; i++)
167 exfreenode(p, pr->param[i]);
168 if (pr->arg)
169 exfreenode(p, pr->arg);
170 pn = pr->next;
171 vmfree(p->vm, pr);
172 }
173 break;
174 default:
175 if (x->data.operand.left)
176 exfreenode(p, x->data.operand.left);
177 if (x->data.operand.right)
178 exfreenode(p, x->data.operand.right);
179 break;
180 }
181 vmfree(p->vm, x);
182 }
183
184 /* extract:
185 * Given an argument list, extract first argument,
186 * check its type, reset argument list, and
187 * return first argument.
188 * Return 0 on failure.
189 */
extract(Expr_t * p,Exnode_t ** argp,int type)190 static Exnode_t *extract(Expr_t * p, Exnode_t ** argp, int type) {
191 Exnode_t *args = *argp;
192 Exnode_t *left;
193
194 if (!args || (type != args->data.operand.left->type))
195 return 0;
196 *argp = args->data.operand.right;
197 left = args->data.operand.left;
198 args->data.operand.left = args->data.operand.right = 0;
199 exfreenode(p, args);
200 return left;
201 }
202
203 /* exnewsplit:
204 * Generate split/tokens node.
205 * Fifth argument is optional.
206 */
exnewsplit(Expr_t * p,int op,Exid_t * dyn,Exnode_t * s,Exnode_t * seps)207 static Exnode_t *exnewsplit(Expr_t * p, int op, Exid_t* dyn, Exnode_t * s, Exnode_t* seps) {
208 Exnode_t *ss = 0;
209
210 if (dyn->local.pointer == 0)
211 exerror("cannot use non-array %s in %s", dyn->name, exopname(op));
212 if ((dyn->index_type > 0) && (dyn->index_type != INTEGER))
213 exerror("in %s, array %s must have integer index type, not %s",
214 exopname(op), dyn->name, extypename(p, s->type));
215 if (dyn->type != STRING)
216 exerror("in %s, array %s entries must have string type, not %s",
217 exopname(op), dyn->name, extypename(p, s->type));
218 if (s->type != STRING)
219 exerror("first argument to %s must have string type, not %s",
220 exopname(op), extypename(p, s->type));
221 if (seps && (seps->type != STRING))
222 exerror("third argument to %s must have string type, not %s",
223 exopname(op), extypename(p, seps->type));
224 ss = exnewnode(p, op, 0, INTEGER, NiL, NiL);
225 ss->data.split.array = dyn;
226 ss->data.split.string = s;
227 ss->data.split.seps = seps;
228 return ss;
229 }
230
231 /* exnewsub:
232 * Generate sub node.
233 * Third argument is optional.
234 */
exnewsub(Expr_t * p,Exnode_t * args,int op)235 static Exnode_t *exnewsub(Expr_t * p, Exnode_t * args, int op) {
236 Exnode_t *base;
237 Exnode_t *pat;
238 Exnode_t *repl;
239 Exnode_t *ss = 0;
240
241 base = extract(p, &args, STRING);
242 if (!base)
243 exerror("invalid first argument to sub operator");
244 pat = extract(p, &args, STRING);
245 if (!pat)
246 exerror("invalid second argument to sub operator");
247 if (args) {
248 repl = extract(p, &args, STRING);
249 if (!repl)
250 exerror("invalid third argument to sub operator");
251 } else
252 repl = 0;
253 if (args)
254 exerror("too many arguments to sub operator");
255 ss = exnewnode(p, op, 0, STRING, NiL, NiL);
256 ss->data.string.base = base;
257 ss->data.string.pat = pat;
258 ss->data.string.repl = repl;
259 return ss;
260 }
261
262 /* exnewsubstr:
263 * Generate substr node.
264 */
exnewsubstr(Expr_t * p,Exnode_t * args)265 static Exnode_t *exnewsubstr(Expr_t * p, Exnode_t * args) {
266 Exnode_t *base;
267 Exnode_t *pat;
268 Exnode_t *repl;
269 Exnode_t *ss = 0;
270
271 base = extract(p, &args, STRING);
272 if (!base)
273 exerror("invalid first argument to substr operator");
274 pat = extract(p, &args, INTEGER);
275 if (!pat)
276 exerror("invalid second argument to substr operator");
277 if (args) {
278 repl = extract(p, &args, INTEGER);
279 if (!repl)
280 exerror("invalid third argument to substr operator");
281 } else
282 repl = 0;
283 if (args)
284 exerror("too many arguments to substr operator");
285 ss = exnewnode(p, SUBSTR, 0, STRING, NiL, NiL);
286 ss->data.string.base = base;
287 ss->data.string.pat = pat;
288 ss->data.string.repl = repl;
289 return ss;
290 }
291
292 /* exstringOf:
293 * Cast x to type STRING
294 * Assume x->type != STRING
295 */
exstringOf(Expr_t * p,register Exnode_t * x)296 static Exnode_t *exstringOf(Expr_t * p, register Exnode_t * x) {
297 int type = x->type;
298 int cvt = 0;
299
300 if (!type) {
301 x->type = STRING;
302 return x;
303 }
304 if (!BUILTIN(type) && !p->disc->stringof)
305 exerror("cannot convert %s to STRING", extypename(p, type));
306 if (x->op != CONSTANT) {
307 if (!BUILTIN(type)) {
308 if ((*p->disc->stringof) (p, x, 1, p->disc) < 0) {
309 exerror("cannot convert %s to STRING",
310 extypename(p, type));
311 }
312 cvt = XPRINT;
313 } else
314 switch (type) {
315 case FLOATING:
316 cvt = F2S;
317 break;
318 case INTEGER:
319 cvt = I2S;
320 break;
321 }
322 x = exnewnode(p, cvt, 0, STRING, x, 0);
323 } else if (!BUILTIN(type)) {
324 if ((*p->disc->stringof) (p, x, 0, p->disc) < 0)
325 exerror("cannot convert constant %s to STRING",
326 extypename(p, x->type));
327 } else
328 switch (type) {
329 case FLOATING:
330 sfprintf(p->tmp, "%g", x->data.constant.value.floating);
331 x->data.constant.value.string =
332 vmstrdup(p->vm, sfstruse(p->tmp));
333 break;
334 case INTEGER:
335 sfprintf(p->tmp, "%I*d",
336 sizeof(x->data.constant.value.integer),
337 x->data.constant.value.integer);
338 x->data.constant.value.string =
339 vmstrdup(p->vm, sfstruse(p->tmp));
340 break;
341 default:
342 exerror("internal error: %d: unknown type", type);
343 break;
344 }
345 x->type = STRING;
346 return x;
347 }
348
349 /* exprint:
350 * Generate argument list of strings.
351 */
exprint(Expr_t * p,Exid_t * ex,Exnode_t * args)352 static Exnode_t *exprint(Expr_t * p, Exid_t * ex, Exnode_t * args) {
353 Exnode_t *arg = args;
354 Exnode_t *pr;
355
356 while (arg) {
357 if (arg->data.operand.left->type != STRING)
358 arg->data.operand.left =
359 exstringOf(p, arg->data.operand.left);
360 arg = arg->data.operand.right;
361 }
362 pr = exnewnode(p, ex->index, 1, ex->type, args, NiL);
363 return pr;
364 }
365
366 /* makeVar:
367 *
368 * Create variable from s[idx].refs
369 * If s is DYNAMIC, refs is non-empty and dyna represents s[idx].
370 * The rightmost element in s[idx].refs becomes the dominant symbol,
371 * and the prefix gets stored in refs. (This format is used to simplify
372 * the yacc parser.)
373 */
makeVar(Expr_t * prog,Exid_t * s,Exnode_t * idx,Exnode_t * dyna,Exref_t * refs)374 static Exnode_t *makeVar(Expr_t * prog, Exid_t * s, Exnode_t * idx,
375 Exnode_t * dyna, Exref_t * refs) {
376 Exnode_t *nn;
377 int kind;
378 Exid_t *sym;
379
380 /* parse components */
381 if (refs) {
382 if (refs->next) {
383 sym = refs->next->symbol;
384 refs->next->symbol = refs->symbol;
385 } else
386 sym = refs->symbol;
387 refs->symbol = s;
388 refs->index = idx;
389 } else
390 sym = s;
391
392 if (sym->type)
393 kind = sym->type;
394 else
395 kind = STRING;
396
397 nn = exnewnode(prog, ID, 0, kind, NiL, NiL);
398 nn->data.variable.symbol = sym;
399 nn->data.variable.reference = refs;
400 nn->data.variable.index = 0;
401 nn->data.variable.dyna = dyna;
402 if (!prog->disc->getf)
403 exerror("%s: identifier references not supported", sym->name);
404 else if (expr.program->disc->reff)
405 (*expr.program->disc->reff) (prog, nn,
406 nn->data.variable.symbol, refs,
407 NiL, EX_SCALAR, prog->disc);
408
409 return nn;
410 }
411
412 /*
413 * cast x to type
414 */
415
416 static char* typename[] =
417 {
418 "external", "integer", "unsigned", "char", "float", "string"
419 };
420
421 static int typecast[6][6] =
422 {
423 {X2X, X2I, X2I, X2I, X2F, X2S},
424 {I2X, 0, 0, 0, I2F, I2S},
425 {I2X, 0, 0, 0, I2F, I2S},
426 {I2X, 0, 0, 0, I2F, I2S},
427 {F2X, F2I, F2I, F2I, 0, F2S},
428 {S2X, S2I, S2I, S2I, S2F, 0},
429 };
430
431 #define TYPEINDEX(t) (((t)>=INTEGER&&(t)<=STRING)?((t)-INTEGER+1):0)
432 #define TYPENAME(t) typename[TYPEINDEX(t)]
433 #define TYPECAST(f,t) typecast[TYPEINDEX(f)][TYPEINDEX(t)]
434
435 #define EXTERNAL(t) ((t)>=F2X)
436
extypename(Expr_t * p,int type)437 char *extypename(Expr_t * p, int type) {
438 if (BUILTIN(type))
439 return TYPENAME(type);
440 return (p->disc->typename) (p, type);
441 }
442
443 /* exnoncast:
444 * Return first non-cast node.
445 */
exnoncast(register Exnode_t * x)446 Exnode_t *exnoncast(register Exnode_t * x) {
447 while (x && (x->op >= F2I) && (x->op <= X2X))
448 x = x->data.operand.left;
449 return x;
450 }
451
452 Exnode_t*
excast(Expr_t * p,register Exnode_t * x,register int type,register Exnode_t * xref,int arg)453 excast(Expr_t* p, register Exnode_t* x, register int type, register Exnode_t* xref, int arg)
454 {
455 register int t2t;
456 char* s;
457 char* e;
458
459 if (x && x->type != type && type && type != VOIDTYPE)
460 {
461 if (!x->type)
462 {
463 x->type = type;
464 return x;
465 }
466 if (!(t2t = TYPECAST(x->type, type)))
467 return x;
468 if (EXTERNAL(t2t) && !p->disc->convertf)
469 exerror("cannot convert %s to %s", extypename(p, x->type), extypename(p, type));
470 if (x->op != CONSTANT) {
471 Exid_t *sym = (xref ? xref->data.variable.symbol : NiL);
472 if (EXTERNAL(t2t)) {
473 int a = (arg ? arg : 1);
474 if ((*p->disc->convertf) (p, x, type, sym, a, p->disc) < 0) {
475 if (xref) {
476 if ((sym->lex == FUNCTION) && arg)
477 exerror ("%s: cannot use value of type %s as argument %d in function %s",
478 sym->name, extypename(p, x->type),
479 arg, sym->name);
480 else
481 exerror("%s: cannot convert %s to %s",
482 xref->data.variable.symbol->name,
483 extypename(p, x->type),
484 extypename(p, type));
485 } else {
486 exerror("cannot convert %s to %s",
487 extypename(p, x->type), extypename(p, type));
488 }
489 }
490 }
491 x = exnewnode(p, t2t, 0, type, x, xref);
492 }
493 else switch (t2t)
494 {
495 case F2X:
496 case I2X:
497 case S2X:
498 case X2F:
499 case X2I:
500 case X2S:
501 case X2X:
502 if (xref && xref->op == ID)
503 {
504 if ((*p->disc->convertf)(p, x, type, xref->data.variable.symbol, arg, p->disc) < 0)
505 exerror("%s: cannot cast constant %s to %s", xref->data.variable.symbol->name, extypename(p, x->type), extypename(p, type));
506 }
507 else if ((*p->disc->convertf)(p, x, type, NiL, arg, p->disc) < 0)
508 exerror("cannot cast constant %s to %s", extypename(p, x->type), extypename(p, type));
509 break;
510 case F2I:
511 x->data.constant.value.integer = x->data.constant.value.floating;
512 break;
513 case F2S:
514 sfprintf(p->tmp, "%g", x->data.constant.value.floating);
515 x->data.constant.value.string = exstash(p->tmp, p->vm);
516 break;
517 case I2F:
518 x->data.constant.value.floating = x->data.constant.value.integer;
519 break;
520 case I2S:
521 sfprintf(p->tmp, "%I*d", sizeof(x->data.constant.value.integer), x->data.constant.value.integer);
522 x->data.constant.value.string = exstash(p->tmp, p->vm);
523 break;
524 case S2F:
525 s = x->data.constant.value.string;
526 x->data.constant.value.integer = strtod(s, &e);
527 if (*e)
528 x->data.constant.value.floating = (*s != 0);
529 break;
530 case S2I:
531 s = x->data.constant.value.string;
532 x->data.constant.value.integer = strtoll(s, &e, 0);
533 if (*e)
534 x->data.constant.value.integer = (*s != 0);
535 break;
536 default:
537 exerror("internal error: %d: unknown cast op", t2t);
538 break;
539 }
540 x->type = type;
541 }
542 return x;
543 }
544
545 #if 0
546
547 /*
548 * convert value v from type from to type to
549 * string data placed in buf
550 */
551
552 Extype_t
553 exconvert(Expr_t* p, Extype_t v, int from, int to, char* buf, size_t size)
554 {
555 register int t2t;
556 int n;
557 Exnode_t tmp;
558
559 if (from && (t2t = TYPECAST(from, to)))
560 {
561 if (EXTERNAL(t2t) && !p->disc->convertf)
562 exerror("cannot cast %s to %s", TYPENAME(from), TYPENAME(to));
563 switch (t2t)
564 {
565 case F2X:
566 case I2X:
567 case S2X:
568 case X2F:
569 case X2I:
570 case X2S:
571 tmp.type = from;
572 tmp.name = "*INTERNAL*";
573 tmp.data.constant.value = v;
574 if ((*p->disc->convertf)(p, &tmp, to, NiL, -1, p->disc) < 0)
575 exerror("cannot convert %s to %s", TYPENAME(from), TYPENAME(to));
576 if (t2t == X2S)
577 {
578 n = strlen(tmp.data.constant.value.string);
579 if (n >= size)
580 n = size - 1;
581 memcpy(buf, tmp.data.constant.value.string, n);
582 buf[n] = 0;
583 vmfree(p->vm, tmp.data.constant.value.string);
584 tmp.data.constant.value.string = buf;
585 }
586 return tmp.data.constant.value;
587 case F2I:
588 v.integer = (type == UNSIGNED) ? (Sfulong_t)v.floating : v.floating;
589 break;
590 case F2S:
591 sfsprintf(buf, size, "%g", v.floating);
592 v.string = buf;
593 break;
594 case I2F:
595 v.floating = (from == UNSIGNED) ? (Sfulong_t)v.integer : v.integer;
596 break;
597 case I2S:
598 sfsprintf(buf, size, "%I*d", sizeof(v.integer), v.integer);
599 v.string = buf;
600 break;
601 case S2F:
602 v.floating = *v.string != 0;
603 break;
604 case S2I:
605 v.integer = *v.string != 0;
606 break;
607 default:
608 exerror("internal error: %d: unknown conversion op", t2t);
609 break;
610 }
611 }
612 return v;
613 }
614
615 #endif
616
617 /*
618 * force ref . sym qualification
619 */
620
621 static Exid_t*
qualify(register Exref_t * ref,register Exid_t * sym)622 qualify(register Exref_t* ref, register Exid_t* sym)
623 {
624 register Exid_t* x;
625 char* s;
626
627 while (ref->next)
628 ref = ref->next;
629 sfprintf(expr.program->tmp, "%s.%s", ref->symbol->name, sym->name);
630 s = exstash(expr.program->tmp, NiL);
631 if (!(x = (Exid_t*)dtmatch(expr.program->symbols, s)))
632 {
633 if ((x = newof(0, Exid_t, 1, strlen(s) - EX_NAMELEN + 1)))
634 {
635 memcpy(x, sym, sizeof(Exid_t) - EX_NAMELEN);
636 strcpy(x->name, s);
637 dtinsert(expr.program->symbols, x);
638 }
639 else
640 {
641 exnospace();
642 x = sym;
643 }
644 }
645 return x;
646 }
647
648 /*
649 * check function call arg types and count
650 * return function identifier node
651 */
652
653 static Exnode_t*
call(Exref_t * ref,register Exid_t * fun,register Exnode_t * args)654 call(Exref_t* ref, register Exid_t* fun, register Exnode_t* args)
655 {
656 register int t;
657 register int type;
658 Exnode_t* x;
659 int num;
660
661 x = exnewnode(expr.program, ID, 0, 0, NiL, NiL);
662 t = fun->type;
663 x->data.variable.symbol = fun = QUALIFY(ref, fun);
664 x->data.variable.reference = ref;
665 num = 0;
666 N(t);
667 while ((type = T(t)))
668 {
669 if (!args)
670 {
671 exerror("%s: not enough args", fun->name);
672 return args;
673 }
674 num++;
675 if (type != args->data.operand.left->type)
676 args->data.operand.left = excast(expr.program, args->data.operand.left, type, NiL, num);
677 args = args->data.operand.right;
678 N(t);
679 }
680 if (args)
681 exerror("%s: too many args", fun->name);
682 return x;
683 }
684
685 /*
686 * precompile a printf/scanf call
687 */
688
689 static Print_t*
preprint(register Exnode_t * args)690 preprint(register Exnode_t* args)
691 {
692 register Print_t* x;
693 register char* s;
694 register int c;
695 int t;
696 int i;
697 int n;
698 char* e;
699 char* f;
700 Print_t* p = 0;
701 Print_t* q;
702
703 if (!args || args->data.operand.left->type != STRING)
704 exerror("format string argument expected");
705 if (args->data.operand.left->op != CONSTANT)
706 {
707 x = ALLOCATE(expr.program, Print_t);
708 memzero(x, sizeof(*x));
709 x->arg = args;
710 return x;
711 }
712 f = args->data.operand.left->data.constant.value.string;
713 args = args->data.operand.right;
714 for (s = f; *s; s++)
715 {
716 sfputc(expr.program->tmp, *s);
717 if (*s == '%')
718 {
719 if (!*++s)
720 exerror("%s: trailing %% in format", f);
721 if (*s != '%')
722 break;
723 if (args)
724 sfputc(expr.program->tmp, '%');
725 }
726 }
727 x = 0;
728 for (;;)
729 {
730 q = ALLOCATE(expr.program, Print_t);
731 if (x)
732 x->next = q;
733 else
734 p = q;
735 x = q;
736 memzero(x, sizeof(*x));
737 if (*s)
738 {
739 i = 0;
740 t = INTEGER;
741 for (;;)
742 {
743 switch (c = *s++)
744 {
745 case 0:
746 exerror("unterminated %%... in format");
747 goto done;
748 case '*':
749 if (i >= elementsof(x->param))
750 {
751 *s = 0;
752 exerror("format %s has too many * arguments", f);
753 goto done;
754 }
755 if (!args)
756 {
757 *s = 0;
758 exerror("format %s * argument expected", f);
759 goto done;
760 }
761 x->param[i++] = args->data.operand.left;
762 args = args->data.operand.right;
763 break;
764 case '(':
765 n = 1;
766 for (;;)
767 {
768 sfputc(expr.program->tmp, c);
769 switch (c = *s++)
770 {
771 case 0:
772 s--;
773 break;
774 case '(':
775 n++;
776 continue;
777 case ')':
778 if (--n <= 0)
779 break;
780 continue;
781 default:
782 continue;
783 }
784 break;
785 }
786 break;
787 case 'c':
788 case 'd':
789 goto specified;
790 case 'e':
791 case 'f':
792 case 'g':
793 t = FLOATING;
794 goto specified;
795 case 'h':
796 exerror("short formats not supported");
797 goto done;
798 case 'l':
799 t = INTEGER;
800 break;
801 case 'o':
802 case 'u':
803 case 'x':
804 case 'T':
805 t = UNSIGNED;
806 goto specified;
807 case 's':
808 case 'S':
809 t = STRING;
810 goto specified;
811 default:
812 if (isalpha(c))
813 goto specified;
814 break;
815 }
816 sfputc(expr.program->tmp, c);
817 }
818 specified:
819 sfputc(expr.program->tmp, c);
820 for (e = s; *s; s++)
821 {
822 if (*s == '%')
823 {
824 if (!*++s)
825 {
826 *e = 0;
827 exerror("%s: trailing %% in format", f);
828 goto done;
829 }
830 if (*s != '%')
831 {
832 s--;
833 break;
834 }
835 }
836 sfputc(expr.program->tmp, *s);
837 }
838 if (!args)
839 {
840 *e = 0;
841 exerror("%s format argument expected", f);
842 goto done;
843 }
844 x->arg = args->data.operand.left;
845 switch (t)
846 {
847 case FLOATING:
848 if (x->arg->type != FLOATING)
849 x->arg = exnewnode(expr.program, x->arg->type == STRING ? S2F : INTEGRAL(x->arg->type) ? I2F : X2F, 0, FLOATING, x->arg, x->arg->op == ID ? x->arg : (Exnode_t*)0);
850 break;
851 case INTEGER:
852 case UNSIGNED:
853 if (!INTEGRAL(x->arg->type))
854 x->arg = exnewnode(expr.program, x->arg->type == STRING ? S2I : x->arg->type == FLOATING ? F2I : X2I, 0, INTEGER, x->arg, x->arg->op == ID ? x->arg : (Exnode_t*)0);
855 x->arg->type = t;
856 break;
857 case STRING:
858 if (x->arg->type != STRING)
859 {
860 if (x->arg->op == CONSTANT && x->arg->data.constant.reference && expr.program->disc->convertf)
861 {
862 if ((*expr.program->disc->convertf)(expr.program, x->arg, STRING, x->arg->data.constant.reference, 0, expr.program->disc) < 0)
863 exerror("cannot convert string format argument");
864 else x->arg->data.constant.value.string = vmstrdup(expr.program->vm, x->arg->data.constant.value.string);
865 }
866 else if (!expr.program->disc->convertf || (x->arg->op != ID && x->arg->op != DYNAMIC && x->arg->op != F2X && x->arg->op != I2X && x->arg->op != S2X))
867 exerror("string format argument expected");
868 else
869 x->arg = exnewnode(expr.program, x->arg->type == FLOATING ? F2S : INTEGRAL(x->arg->type) ? I2S : X2S, 0, STRING, x->arg, x->arg->op == ID ? x->arg : (Exnode_t*)0);
870 }
871 break;
872 }
873 args = args->data.operand.right;
874 }
875 x->format = exstash(expr.program->tmp, expr.program->vm);
876 if (!*s)
877 break;
878 f = s;
879 }
880 if (args)
881 exerror("too many format arguments");
882 done:
883 sfstrseek(expr.program->tmp, 0, SEEK_SET);
884 return p;
885 }
886
887 /*
888 * push a new input stream and program
889 */
890
891 int
expush(Expr_t * p,const char * name,int line,const char * sp,Sfio_t * fp)892 expush(Expr_t* p, const char* name, int line, const char* sp, Sfio_t* fp)
893 {
894 register Exinput_t* in;
895 register char* s;
896 char buf[PATH_MAX];
897
898 if (!(in = newof(0, Exinput_t, 1, 0)))
899 {
900 exnospace();
901 return -1;
902 }
903 if (!p->input)
904 p->input = &expr.null;
905 if (!(in->bp = in->sp = (char*)sp))
906 {
907 if ((in->fp = fp))
908 in->close = 0;
909 else if (name)
910 {
911 if (!(s = pathfind(name, p->disc->lib, p->disc->type, buf, sizeof(buf))) || !(in->fp = sfopen(NiL, s, "r")))
912 {
913 exerror("%s: file not found", name);
914 in->bp = in->sp = "";
915 }
916 else
917 {
918 name = (const char*)vmstrdup(p->vm, s);
919 in->close = 1;
920 }
921 }
922 }
923 else in->fp = 0;
924 if (!(in->next = p->input)->next)
925 {
926 p->errors = 0;
927 if (!(p->disc->flags & EX_INTERACTIVE))
928 {
929 if (line >= 0)
930 error_info.line = line;
931 }
932 else if (!error_info.line)
933 error_info.line = 1;
934 }
935 else if (line >= 0)
936 error_info.line = line;
937 setcontext(p);
938 p->eof = 0;
939 p->input = in;
940 in->file = error_info.file;
941 if (line >= 0)
942 error_info.file = (char*)name;
943 in->line = error_info.line;
944 in->nesting = 0;
945 in->unit = !name && !line;
946 p->program = expr.program;
947 expr.program = p;
948 return 0;
949 }
950
951 /*
952 * pop the current input stream
953 */
954
955 int
expop(register Expr_t * p)956 expop(register Expr_t* p)
957 {
958 register int c;
959 register Exinput_t* in;
960
961 if (!(in = p->input) || !in->next || in->unit)
962 return -1;
963 if (in->nesting)
964 exerror("unbalanced quote or nesting construct");
965 error_info.file = in->file;
966 if (in->next->next)
967 error_info.line = in->line;
968 else
969 {
970 if (p->errors && in->fp && p->linep != p->line)
971 while ((c = sfgetc(in->fp)) != EOF)
972 if (c == '\n')
973 {
974 error_info.line++;
975 break;
976 }
977 if (!(p->disc->flags & EX_INTERACTIVE))
978 error_info.line = in->line;
979 }
980 if (in->fp && in->close)
981 sfclose(in->fp);
982 if (in->pushback)
983 free(in->pushback);
984 p->input = in->next;
985 free(in);
986 setcontext(p);
987 if (p->program)
988 expr.program = p->program;
989 return 0;
990 }
991
992 /*
993 * clear global state of stale pointers
994 */
995
exinit(void)996 void exinit(void) {
997 memset (&expr, 0, sizeof(Exstate_t));
998 }
999
1000 /*
1001 * compile the expression in [sf]p
1002 */
1003
1004 int
excomp(register Expr_t * p,const char * name,int line,const char * sp,Sfio_t * fp)1005 excomp(register Expr_t* p, const char* name, int line, const char* sp, Sfio_t* fp)
1006 {
1007 Exid_t* v;
1008 int eof;
1009
1010 p->more = 0;
1011 eof = p->eof;
1012 if (!sp && !fp)
1013 {
1014 if (!p->input)
1015 return -1;
1016 }
1017 else if (expush(p, name, line, sp, fp))
1018 return -1;
1019 else
1020 p->input->unit = line >= 0;
1021 exparse();
1022 p->input->unit = 0;
1023 expop(p);
1024 p->eof = eof;
1025 if (expr.statics)
1026 {
1027 for (v = (Exid_t*)dtfirst(p->symbols); v; v = (Exid_t*)dtnext(p->symbols, v))
1028 if (v->isstatic)
1029 {
1030 dtdelete(p->symbols, v);
1031 if (!--expr.statics)
1032 break;
1033 }
1034 expr.statics = 0;
1035 }
1036 return 0;
1037 }
1038
1039 /*
1040 * free the program p
1041 */
1042
1043 void
exclose(register Expr_t * p,int all)1044 exclose(register Expr_t* p, int all)
1045 {
1046 register int i;
1047 register Exinput_t* in;
1048
1049 if (p)
1050 {
1051 if (all)
1052 {
1053 for (i = 3; i < elementsof(p->file); i++)
1054 if (p->file[i])
1055 sfclose(p->file[i]);
1056 if (p->vm)
1057 vmclose(p->vm);
1058 if (p->ve)
1059 vmclose(p->ve);
1060 if (p->symbols)
1061 dtclose(p->symbols);
1062 if (p->tmp)
1063 sfclose(p->tmp);
1064 while ((in = p->input))
1065 {
1066 if (in->pushback)
1067 free(in->pushback);
1068 if (in->fp && in->close)
1069 sfclose(in->fp);
1070 if ((p->input = in->next))
1071 free(in);
1072 }
1073 free(p);
1074 }
1075 else
1076 {
1077 vmclear(p->ve);
1078 p->main.value = 0;
1079 }
1080 }
1081 }
1082
1083 /* checkBinary:
1084 * See if application wants to allow the given expression
1085 * combination. l and r give the operands; the operator
1086 * is given by ex. r may be NULL.
1087 */
1088 static void
checkBinary(Expr_t * p,Exnode_t * l,Exnode_t * ex,Exnode_t * r)1089 checkBinary(Expr_t * p, Exnode_t * l, Exnode_t * ex, Exnode_t * r)
1090 {
1091 if ((*p->disc->binaryf) (p, l, ex, r, 1, p->disc) < 0) {
1092 if (r)
1093 exerror
1094 ("cannot apply operator %s to expressions of types %s and %s",
1095 exopname(ex->op), extypename(p, l->type),
1096 extypename(p, r->type));
1097 else
1098 exerror
1099 ("cannot apply operator %s to expression of type %s",
1100 exopname(ex->op), extypename(p, l->type));
1101 }
1102 }
1103
1104 /* checkName:
1105 * We allow parser to accept any name in a declaration, in
1106 * order to check that the name is undeclared and give a better
1107 * error message if it isn't.
1108 */
checkName(Exid_t * id)1109 static void checkName(Exid_t * id)
1110 {
1111 switch (id->lex) {
1112 case DYNAMIC:
1113 exerror("Variable \"%s\" already declared", id->name);
1114 break;
1115 case FUNCTION:
1116 exerror("Name \"%s\" already used as a function", id->name);
1117 break;
1118 case ID:
1119 exerror("Name \"%s\" already used as a keyword", id->name);
1120 break;
1121 case NAME:
1122 break;
1123 default:
1124 error(ERROR_PANIC,
1125 "Unexpected token \"%s\" as name in dcl_item", id->name);
1126 break;
1127 }
1128 }
1129
1130 static int
cmpKey(Dt_t * d,Extype_t * key1,Extype_t * key2,Dtdisc_t * disc)1131 cmpKey(Dt_t * d, Extype_t * key1, Extype_t * key2, Dtdisc_t * disc)
1132 {
1133 if (key1->integer < key2->integer)
1134 return -1;
1135 else if (key1->integer > key2->integer)
1136 return 1;
1137 else
1138 return 0;
1139 }
1140
1141 int
exisAssign(Exnode_t * n)1142 exisAssign(Exnode_t * n)
1143 {
1144 return ((n->op == '=') && (n->subop == '='));
1145 }
1146
1147 #endif
1148
1149 #ifdef __cplusplus
1150 }
1151 #endif
1152