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