Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
excc.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11/*
12 * Glenn Fowler
13 * AT&T Research
14 *
15 * expression library C program generator
16 */
17
18#include <expr/exlib.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <util/agxbuf.h>
23#include <util/exit.h>
24
26typedef struct {
27 Expr_t* expr; /* exopen() state */
28 Exdisc_t* disc; /* exopen() discipline */
29 int tmp; /* temp var index */
31} Excc_t;
32
33static const char quote[] = "\"";
34
35static void gen(Excc_t*, Exnode_t*);
36
37/*
38 * return C name for op
39 */
40
41char *exopname(long op) {
42 static char buf[16];
43
44 switch (op)
45 {
46 case '!':
47 return "!";
48 case '%':
49 return "%";
50 case '&':
51 return "&";
52 case '(':
53 return "(";
54 case '*':
55 return "*";
56 case '+':
57 return "+";
58 case ',':
59 return ",";
60 case '-':
61 return "-";
62 case '/':
63 return "/";
64 case ':':
65 return ":";
66 case '<':
67 return "<";
68 case '=':
69 return "=";
70 case '>':
71 return ">";
72 case '?':
73 return "?";
74 case '^':
75 return "^";
76 case '|':
77 return "|";
78 case '~':
79 return "~";
80 case AND:
81 return "&&";
82 case EQ:
83 return "==";
84 case GE:
85 return ">=";
86 case LE:
87 return "<=";
88 case LSH:
89 return "<<";
90 case NE:
91 return "!=";
92 case OR:
93 return "||";
94 case RSH:
95 return ">>";
96 default:
97 break;
98 }
99 snprintf(buf, sizeof(buf) - 1, "(OP=%03lo)", op);
100 return buf;
101}
102
103/*
104 * generate printf()
105 */
106
107static void print(Excc_t *cc, Exnode_t *exnode) {
108 Print_t* x;
109
110 if ((x = exnode->data.print.args))
111 {
112 char *quoted = fmtesq(x->format, quote);
113 agxbprint(cc->text, "sfprintf(%s, \"%s", exnode->data.print.descriptor->op == CONSTANT && exnode->data.print.descriptor->data.constant.value.integer == 2 ? "sfstderr" : "sfstdout", quoted);
114 free(quoted);
115 while ((x = x->next)) {
116 quoted = fmtesq(x->format, quote);
117 agxbput(cc->text, quoted);
118 free(quoted);
119 }
120 agxbputc(cc->text, '"');
121 for (x = exnode->data.print.args; x; x = x->next)
122 {
123 if (x->arg)
124 {
125 for (size_t i = 0; i < elementsof(x->param) && x->param[i]; i++)
126 {
127 agxbput(cc->text, ", (");
128 gen(cc, x->param[i]);
129 agxbputc(cc->text, ')');
130 }
131 agxbput(cc->text, ", (");
132 gen(cc, x->arg);
133 agxbputc(cc->text, ')');
134 }
135 }
136 agxbput(cc->text, ");\n");
137 }
138}
139
140/*
141 * generate scanf()
142 */
143
144static void scan(Excc_t *cc, Exnode_t *exnode) {
145 Print_t* x;
146
147 if ((x = exnode->data.print.args))
148 {
149 char *quoted = fmtesq(x->format, quote);
150 agxbprint(cc->text, "sfscanf(sfstdin, \"%s", quoted);
151 free(quoted);
152 while ((x = x->next)) {
153 quoted = fmtesq(x->format, quote);
154 agxbput(cc->text, quoted);
155 free(quoted);
156 }
157 agxbputc(cc->text, '"');
158 for (x = exnode->data.print.args; x; x = x->next)
159 {
160 if (x->arg)
161 {
162 for (size_t i = 0; i < elementsof(x->param) && x->param[i]; i++)
163 {
164 agxbput(cc->text, ", &(");
165 gen(cc, x->param[i]);
166 agxbputc(cc->text, ')');
167 }
168 agxbput(cc->text, ", &(");
169 gen(cc, x->arg);
170 agxbputc(cc->text, ')');
171 }
172 }
173 agxbput(cc->text, ");\n");
174 }
175}
176
177/*
178 * internal excc
179 */
180
181static void gen(Excc_t *cc, Exnode_t *exnode) {
182 Exnode_t* x;
183 Exnode_t* y;
184 int n;
185 int m;
186 char* s;
187 Extype_t* v;
188 Extype_t** p;
189
190 if (!exnode)
191 return;
192 if (exnode->op == CALL) {
193 agxbprint(cc->text, "%s(", exnode->data.call.procedure->name);
194 if (exnode->data.call.args)
195 gen(cc, exnode->data.call.args);
196 agxbputc(cc->text, ')');
197 return;
198 }
199 x = exnode->data.operand.left;
200 switch (exnode->op)
201 {
202 case BREAK:
203 agxbput(cc->text, "break;\n");
204 return;
205 case CONTINUE:
206 agxbput(cc->text, "continue;\n");
207 return;
208 case CONSTANT:
209 switch (exnode->type)
210 {
211 case FLOATING:
212 agxbprint(cc->text, "%g", exnode->data.constant.value.floating);
213 break;
214 case STRING: {
215 char *quoted = fmtesq(exnode->data.constant.value.string, quote);
216 agxbprint(cc->text, "\"%s\"", quoted);
217 free(quoted);
218 break;
219 }
220 case UNSIGNED:
221 agxbprint(cc->text, "%llu",
222 (long long unsigned)exnode->data.constant.value.integer);
223 break;
224 default:
225 agxbprint(cc->text, "%lld", exnode->data.constant.value.integer);
226 break;
227 }
228 return;
229 case DEC:
230 agxbprint(cc->text, "%s--", x->data.variable.symbol->name);
231 return;
232 case DYNAMIC:
233 agxbput(cc->text, exnode->data.variable.symbol->name);
234 return;
235 case EXIT:
236 agxbput(cc->text, "exit(");
237 gen(cc, x);
238 agxbput(cc->text, ");\n");
239 return;
240 case FUNCTION:
241 gen(cc, x);
242 agxbputc(cc->text, '(');
243 if ((y = exnode->data.operand.right)) {
244 gen(cc, y);
245 }
246 agxbputc(cc->text, ')');
247 return;
248 case RAND:
249 agxbput(cc->text, "rand();\n");
250 return;
251 case SRAND:
252 if (exnode->binary) {
253 agxbput(cc->text, "srand(");
254 gen(cc, x);
255 agxbput(cc->text, ");\n");
256 } else
257 agxbput(cc->text, "srand();\n");
258 return;
259 case GSUB:
260 case SUB:
261 case SUBSTR:
262 s = (exnode->op == GSUB ? "gsub(" : exnode->op == SUB ? "sub(" : "substr(");
263 agxbput(cc->text, s);
264 gen(cc, exnode->data.string.base);
265 agxbput(cc->text, ", ");
266 gen(cc, exnode->data.string.pat);
267 if (exnode->data.string.repl) {
268 agxbput(cc->text, ", ");
269 gen(cc, exnode->data.string.repl);
270 }
271 agxbputc(cc->text, ')');
272 return;
273 case IN_OP:
274 gen(cc, exnode->data.variable.index);
275 agxbprint(cc->text, " in %s", exnode->data.variable.symbol->name);
276 return;
277 case IF:
278 agxbput(cc->text, "if (");
279 gen(cc, x);
280 agxbput(cc->text, ") {\n");
281 gen(cc, exnode->data.operand.right->data.operand.left);
282 if (exnode->data.operand.right->data.operand.right)
283 {
284 agxbput(cc->text, "} else {\n");
285 gen(cc, exnode->data.operand.right->data.operand.right);
286 }
287 agxbput(cc->text, "}\n");
288 return;
289 case FOR:
290 agxbput(cc->text, "for (;");
291 gen(cc, x);
292 agxbput(cc->text, ");");
293 if (exnode->data.operand.left)
294 {
295 agxbputc(cc->text, '(');
296 gen(cc, exnode->data.operand.left);
297 agxbputc(cc->text, ')');
298 }
299 agxbput(cc->text, ") {");
300 if (exnode->data.operand.right)
301 gen(cc, exnode->data.operand.right);
302 agxbputc(cc->text, '}');
303 return;
304 case ID:
305 agxbput(cc->text, exnode->data.variable.symbol->name);
306 return;
307 case INC:
308 agxbprint(cc->text, "%s++", x->data.variable.symbol->name);
309 return;
310 case ITERATE:
311 case ITERATOR:
312 if (exnode->op == DYNAMIC)
313 {
314 agxbprint(cc->text, "{ Exassoc_t* tmp_%d;", ++cc->tmp);
315 agxbprint(cc->text, "for (tmp_%d = (Exassoc_t*)dtfirst(%s); tmp_%d && (%s = tmp_%d->name); tmp_%d = (Exassoc_t*)dtnext(%s, tmp_%d)) {", cc->tmp, exnode->data.generate.array->data.variable.symbol->name, cc->tmp, exnode->data.generate.index->name, cc->tmp, cc->tmp, exnode->data.generate.array->data.variable.symbol->name, cc->tmp);
316 gen(cc, exnode->data.generate.statement);
317 agxbput(cc->text, "} }");
318 }
319 return;
320 case PRINT:
321 agxbput(cc->text, "print");
322 if (x)
323 gen(cc, x);
324 else
325 agxbput(cc->text, "()");
326 return;
327 case PRINTF:
328 print(cc, exnode);
329 return;
330 case RETURN:
331 agxbput(cc->text, "return(");
332 gen(cc, x);
333 agxbput(cc->text, ");\n");
334 return;
335 case SCANF:
336 scan(cc, exnode);
337 return;
338 case SPLIT:
339 case TOKENS:
340 if (exnode->op == SPLIT)
341 agxbput(cc->text, "split (");
342 else
343 agxbput(cc->text, "tokens (");
344 gen(cc, exnode->data.split.string);
345 agxbprint(cc->text, ", %s", exnode->data.split.array->name);
346 if (exnode->data.split.seps) {
347 agxbputc(cc->text, ',');
348 gen(cc, exnode->data.split.seps);
349 }
350 agxbputc(cc->text, ')');
351 return;
352 case SWITCH: {
353 long t = x->type;
354 agxbprint(cc->text, "{ %s tmp_%d = ", extype(t), ++cc->tmp);
355 gen(cc, x);
356 agxbputc(cc->text, ';');
357 x = exnode->data.operand.right;
358 y = x->data.select.statement;
359 n = 0;
360 while ((x = x->data.select.next))
361 {
362 if (n)
363 agxbput(cc->text, "else ");
364 if (!(p = x->data.select.constant))
365 y = x->data.select.statement;
366 else
367 {
368 m = 0;
369 while ((v = *p++))
370 {
371 if (m)
372 agxbput(cc->text, "||");
373 else
374 {
375 m = 1;
376 agxbput(cc->text, "if (");
377 }
378 if (t == STRING) {
379 char *quoted = fmtesq(v->string, quote);
380 agxbprint(cc->text, "strmatch(tmp_%d, \"%s\")", cc->tmp, quoted);
381 free(quoted);
382 } else {
383 agxbprint(cc->text, "tmp_%d == ", cc->tmp);
384 switch (t)
385 {
386 case INTEGER:
387 case UNSIGNED:
388 agxbprint(cc->text, "%llu",
389 (unsigned long long)v->integer);
390 break;
391 default:
392 agxbprint(cc->text, "%g", v->floating);
393 break;
394 }
395 }
396 }
397 agxbput(cc->text, ") {");
398 gen(cc, x->data.select.statement);
399 agxbputc(cc->text, '}');
400 }
401 }
402 if (y)
403 {
404 if (n)
405 agxbput(cc->text, "else ");
406 agxbputc(cc->text, '{');
407 gen(cc, y);
408 agxbputc(cc->text, '}');
409 }
410 agxbputc(cc->text, '}');
411 return;
412 }
413 case UNSET:
414 agxbprint(cc->text, "unset(%s", exnode->data.variable.symbol->name);
415 if (exnode->data.variable.index) {
416 agxbputc(cc->text, ',');
417 gen(cc, exnode->data.variable.index);
418 }
419 agxbputc(cc->text, ')');
420 return;
421 case WHILE:
422 agxbput(cc->text, "while (");
423 gen(cc, x);
424 agxbput(cc->text, ") {");
425 if (exnode->data.operand.right)
426 gen(cc, exnode->data.operand.right);
427 agxbputc(cc->text, '}');
428 return;
429 case '#':
430 agxbprint(cc->text, "# %s", exnode->data.variable.symbol->name);
431 return;
432 case '=':
433 agxbprint(cc->text, "(%s%s=", x->data.variable.symbol->name, exnode->subop == '=' ? "" : exopname(exnode->subop));
434 gen(cc, exnode->data.operand.right);
435 agxbputc(cc->text, ')');
436 return;
437 case ';':
438 for (;;)
439 {
440 if (!(x = exnode->data.operand.right))
441 switch (exnode->data.operand.left->op)
442 {
443 case FOR:
444 case IF:
445 case PRINTF:
446 case PRINT:
447 case RETURN:
448 case WHILE:
449 break;
450 default:
451 agxbput(cc->text, "_value=");
452 break;
453 }
454 gen(cc, exnode->data.operand.left);
455 agxbput(cc->text, ";\n");
456 if (!(exnode = x))
457 break;
458 switch (exnode->op)
459 {
460 case ';':
461 continue;
462 case FOR:
463 case IF:
464 case PRINTF:
465 case PRINT:
466 case RETURN:
467 case WHILE:
468 break;
469 default:
470 agxbput(cc->text, "_%svalue=");
471 break;
472 }
473 gen(cc, exnode);
474 agxbput(cc->text, ";\n");
475 break;
476 }
477 return;
478 case ',':
479 agxbputc(cc->text, '(');
480 gen(cc, x);
481 while ((exnode = exnode->data.operand.right) && exnode->op == ',')
482 {
483 agxbput(cc->text, "), (");
484 gen(cc, exnode->data.operand.left);
485 }
486 if (exnode)
487 {
488 agxbput(cc->text, "), (");
489 gen(cc, exnode);
490 }
491 agxbputc(cc->text, ')');
492 return;
493 case '?':
494 agxbputc(cc->text, '(');
495 gen(cc, x);
496 agxbput(cc->text, ") ? (");
497 gen(cc, exnode->data.operand.right->data.operand.left);
498 agxbput(cc->text, ") : (");
499 gen(cc, exnode->data.operand.right->data.operand.right);
500 agxbputc(cc->text, ')');
501 return;
502 case AND:
503 agxbputc(cc->text, '(');
504 gen(cc, x);
505 agxbput(cc->text, ") && (");
506 gen(cc, exnode->data.operand.right);
507 agxbputc(cc->text, ')');
508 return;
509 case OR:
510 agxbputc(cc->text, '(');
511 gen(cc, x);
512 agxbput(cc->text, ") || (");
513 gen(cc, exnode->data.operand.right);
514 agxbputc(cc->text, ')');
515 return;
516 case F2I:
517 agxbprint(cc->text, "(%s)(", extype(INTEGER));
518 gen(cc, x);
519 agxbputc(cc->text, ')');
520 return;
521 case I2F:
522 agxbprint(cc->text, "(%s)(", extype(FLOATING));
523 gen(cc, x);
524 agxbputc(cc->text, ')');
525 return;
526 case S2I:
527 agxbput(cc->text, "strtoll(");
528 gen(cc, x);
529 agxbput(cc->text, ",(char**)0,0)");
530 return;
531 case X2I:
532 agxbput(cc->text, "X2I(");
533 gen(cc, x);
534 agxbputc(cc->text, ')');
535 return;
536 case X2X:
537 agxbput(cc->text, "X2X(");
538 gen(cc, x);
539 agxbputc(cc->text, ')');
540 return;
541 }
542 y = exnode->data.operand.right;
543 if (x->type == STRING)
544 {
545 switch (exnode->op)
546 {
547 case S2B:
548 agxbput(cc->text, "*(");
549 gen(cc, x);
550 agxbput(cc->text, ")!=0");
551 return;
552 case S2F:
553 agxbput(cc->text, "strtod(");
554 gen(cc, x);
555 agxbput(cc->text, ",0)");
556 return;
557 case S2I:
558 agxbput(cc->text, "strtol(");
559 gen(cc, x);
560 agxbput(cc->text, ",0,0)");
561 return;
562 case S2X:
563 agxbput(cc->text, "** cannot convert string value to external **");
564 return;
565 case NE:
566 agxbputc(cc->text, '!');
567 /*FALLTHROUGH*/
568 case EQ:
569 agxbput(cc->text, "strmatch(");
570 gen(cc, x);
571 agxbputc(cc->text, ',');
572 gen(cc, y);
573 agxbputc(cc->text, ')');
574 return;
575 case '+':
576 case '|':
577 case '&':
578 case '^':
579 case '%':
580 case '*':
581 agxbput(cc->text, "** string bits not supported **");
582 return;
583 }
584 switch (exnode->op)
585 {
586 case '<':
587 s = "<0";
588 break;
589 case LE:
590 s = "<=0";
591 break;
592 case GE:
593 s = ">=0";
594 break;
595 case '>':
596 s = ">0";
597 break;
598 default:
599 s = "** unknown string op **";
600 break;
601 }
602 agxbput(cc->text, "strcoll(");
603 gen(cc, x);
604 agxbputc(cc->text, ',');
605 gen(cc, y);
606 agxbprint(cc->text, ")%s", s);
607 return;
608 }
609 else
610 {
611 if (!y)
612 agxbput(cc->text, exopname(exnode->op));
613 agxbputc(cc->text, '(');
614 gen(cc, x);
615 if (y)
616 {
617 agxbprint(cc->text, ")%s(", exopname(exnode->op));
618 gen(cc, y);
619 }
620 agxbputc(cc->text, ')');
621 }
622 return;
623}
624
625/*
626 * dump an expression tree to a buffer
627 */
628
629void exdump(Expr_t *ex, Exnode_t *node, agxbuf *xb) {
630 Excc_t cc = {.expr = ex, .disc = ex->disc, .text = xb};
631 if (node)
632 gen(&cc, node);
633 else
634 for (Exid_t *sym = dtfirst(ex->symbols); sym; sym = dtnext(ex->symbols, sym))
635 if (sym->lex == PROCEDURE && sym->value)
636 {
637 agxbprint(xb, "%s:\n", sym->name);
638 gen(&cc, sym->value->data.procedure.body);
639 }
640 agxbputc(xb, '\n');
641}
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:277
char * fmtesq(const char *, const char *)
Definition fmtesc.c:123
#define elementsof(x)
Definition ast.h:33
#define dtnext(d, o)
Definition cdt.h:180
#define dtfirst(d)
Definition cdt.h:179
char * exopname(long op)
Definition excc.c:41
static void scan(Excc_t *cc, Exnode_t *exnode)
Definition excc.c:144
static void print(Excc_t *cc, Exnode_t *exnode)
Definition excc.c:107
static const char quote[]
Definition excc.c:33
static void gen(Excc_t *, Exnode_t *)
Definition excc.c:181
void exdump(Expr_t *ex, Exnode_t *node, agxbuf *xb)
Definition excc.c:629
#define UNSIGNED
Definition exparse.c:237
#define DYNAMIC
Definition exparse.c:251
#define SCANF
Definition exparse.c:273
#define RSH
Definition exparse.c:306
#define OR
Definition exparse.c:299
#define GE
Definition exparse.c:304
#define S2X
Definition exparse.c:293
#define WHILE
Definition exparse.c:283
#define ITERATE
Definition exparse.c:257
#define NE
Definition exparse.c:302
#define SRAND
Definition exparse.c:276
#define S2I
Definition exparse.c:290
#define SUB
Definition exparse.c:278
#define LSH
Definition exparse.c:305
#define FLOATING
Definition exparse.c:239
#define FOR
Definition exparse.c:254
#define IN_OP
Definition exparse.c:307
#define SUBSTR
Definition exparse.c:279
#define TOKENS
Definition exparse.c:281
#define ITERATOR
Definition exparse.c:258
#define RAND
Definition exparse.c:271
#define PRINT
Definition exparse.c:267
#define I2F
Definition exparse.c:286
#define CONSTANT
Definition exparse.c:247
#define LE
Definition exparse.c:303
#define S2B
Definition exparse.c:288
#define CALL
Definition exparse.c:245
#define GSUB
Definition exparse.c:256
#define UNSET
Definition exparse.c:282
#define CONTINUE
Definition exparse.c:248
#define F2I
Definition exparse.c:284
#define SPLIT
Definition exparse.c:274
#define EQ
Definition exparse.c:301
#define BREAK
Definition exparse.c:244
#define S2F
Definition exparse.c:289
#define IF
Definition exparse.c:260
#define PROCEDURE
Definition exparse.c:269
#define SWITCH
Definition exparse.c:280
#define AND
Definition exparse.c:300
#define X2X
Definition exparse.c:297
#define EXIT
Definition exparse.c:253
#define X2I
Definition exparse.c:295
#define PRINTF
Definition exparse.c:268
#define FUNCTION
Definition exparse.c:255
#define INC
Definition exparse.c:309
#define DEC
Definition exparse.c:310
char * extype(long int)
Definition extype.c:24
#define ID
Definition gmlparse.c:376
#define STRING
Definition gmlparse.c:375
#define INTEGER
Definition gmlparse.c:373
void free(void *)
agxbput(xb, staging)
#define RETURN(v)
Definition strmatch.c:144
excc() state
Definition excc.c:26
Exdisc_t * disc
Definition excc.c:28
agxbuf * text
result of dumping
Definition excc.c:30
int tmp
Definition excc.c:29
Expr_t * expr
Definition excc.c:27
Definition expr.h:93
char name[EX_NAMELEN]
Definition expr.h:102
long op
operator
Definition expr.h:152
long type
value type
Definition expr.h:151
bool binary
data.operand.{left,right} ok
Definition expr.h:153
Exdata_t data
Definition expr.h:160
Definition expr.h:200
Dt_t * symbols
Definition expr.h:202
struct Exnode_s * param[3]
Definition exlib.h:47
char * format
Definition exlib.h:46
struct Exnode_s * arg
Definition exlib.h:48
struct Print_s * next
Definition exlib.h:45
char * string
Definition exparse.c:326
long long integer
Definition exparse.c:324
double floating
Definition exparse.c:321
struct Exdata_u::@87 variable
Exnode_t * left
Definition expr.h:123
struct Exdata_u::@84 constant
Exnode_t * right
Definition expr.h:124
Exnode_t * next
Definition expr.h:131
Exnode_t * statement
Definition expr.h:130
Exid_t * symbol
Definition expr.h:137
struct Exdata_u::@85 operand
struct Exdata_u::@86 select
Extype_t value
Definition expr.h:117
Exnode_t * index
Definition expr.h:139
Definition grammar.c:93