summaryrefslogtreecommitdiff
path: root/tree.c
diff options
context:
space:
mode:
authorToby Goodwin <toby@paccrat.org>2018-03-19 20:55:56 +0000
committerToby Goodwin <toby@paccrat.org>2018-03-19 20:55:56 +0000
commit7a643120366f1ea24eac5ccb759d4df616e7789b (patch)
tree17faf7ba3be5e185b8262cfcbafbe23a9f64260a /tree.c
parent2dd0aa249c9bac4e5c616d1f386dc4271fdbab46 (diff)
implement desugaring version (again, lost due to git problem)
Diffstat (limited to 'tree.c')
-rw-r--r--tree.c47
1 files changed, 40 insertions, 7 deletions
diff --git a/tree.c b/tree.c
index 6a79bbc..d167a7c 100644
--- a/tree.c
+++ b/tree.c
@@ -2,9 +2,47 @@
#include "rc.h"
+/* convert if followed by ifnot to else */
+static Node *desugar_ifnot(Node *n) {
+ if (n->type == nBody && n->u[1].p && n->u[1].p->type == nIfnot) {
+ /* (body (if c x) (if-not y)) => (body (if c (else x y))) */
+ if (n->u[0].p->type == nIf) {
+ Node *yes = n->u[0].p;
+ Node *no = n->u[1].p;
+ Node *els = nalloc(offsetof(Node, u[2]));
+ els->type = nElse;
+ els->u[1].p = no->u[0].p;
+ els->u[0].p = yes->u[1].p;
+ yes->u[1].p = els;
+ n->u[1].p = NULL;
+ } else goto fail;
+ } else if (n->type == nBody &&
+ n->u[1].p && n->u[1].p->type == nBody &&
+ n->u[1].p->u[0].p &&
+ n->u[1].p->u[0].p->type == nIfnot) {
+ /* (body (if c x) (body (if-not y) z)) =>
+ (body (if c (else x y)) z) */
+ if (n->u[0].p->type == nIf) {
+ Node *yes = n->u[0].p;
+ Node *no = n->u[1].p->u[0].p;
+ Node *els = nalloc(offsetof(Node, u[2]));
+ els->type = nElse;
+ els->u[1].p = no->u[0].p;
+ els->u[0].p = yes->u[1].p;
+ yes->u[1].p = els;
+ n->u[1].p = n->u[1].p->u[1].p;
+ } else goto fail;
+ }
+
+ return n;
+fail:
+ rc_error("`if not' must follow `if'");
+ return NULL;
+}
+
/* make a new node, pass it back to yyparse. Used to generate the parsetree. */
-extern Node *mk(int /*nodetype*/ t,...) {
+extern Node *mk(enum nodetype t,...) {
va_list ap;
Node *n;
va_start(ap, t);
@@ -60,13 +98,8 @@ extern Node *mk(int /*nodetype*/ t,...) {
break;
}
n->type = t;
- if (t == nBody && n->u[1].p && n->u[1].p->type == nIfnot) {
- if (n->u[0].p->type == nIf) {
- fprint(2, "here i am!\n");
- } else
- rc_error("`if not' must follow `if'");
- }
+ n = desugar_ifnot(n);
va_end(ap);
return n;
}