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