excc.c 16 KB

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