commit 1216df718969c0f856bce9e1adc64bce127eadd9
parent 29440403156f6afc4ace075d96407596dfea2daa
Author: Toby Goodwin <toby@paccrat.org>
Date: Fri, 23 Jun 2017 22:16:23 +0100
add parse tree dumper with --enable-develop
Diffstat:
5 files changed, 329 insertions(+), 2 deletions(-)
diff --git a/Makefile.am b/Makefile.am
@@ -19,6 +19,10 @@ else
SYSTEM = system.o
endif
+if AMC_DEVELOP
+DEVELOP = develop.o
+endif
+
bin_PROGRAMS = rc
noinst_PROGRAMS = mksignal mkstatval tripping $(HISTORY)
@@ -26,8 +30,8 @@ rc_SOURCES = builtins.c except.c exec.c fn.c footobar.c getopt.c glob.c glom.c h
EXTRA_rc_SOURCES = addon.c edit-edit.c edit-editline.c edit-null.c edit-readline.c edit-vrl.c execve.c system.c system-bsd.c
-rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM)
-rc_LDADD = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM)
+rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(DEVELOP) $(EDIT) $(EXECVE) $(SYSTEM)
+rc_LDADD = sigmsgs.o $(ADDON) $(DEVELOP) $(EDIT) $(EXECVE) $(SYSTEM)
noinst_HEADERS = edit.h getgroups.h input.h jbwrap.h parse.h proto.h rc.h rlimit.h stat.h wait.h
diff --git a/configure.ac b/configure.ac
@@ -145,6 +145,19 @@ yes) AC_CACHE_CHECK(extant directories for default path, rc_cv_def_path,[
;;
esac
+
+AC_ARG_ENABLE(develop,
+ [ --enable-develop Include extra code for developers],[
+ case "$enableval" in
+ yes)
+ rc_develop=true
+ AC_DEFINE([RC_DEVELOP], 1, [Enable developer options]) ;;
+ no) ;;
+ *) AC_MSG_ERROR([bad value $enableval for --enable-develop]) ;;
+ esac])
+AM_CONDITIONAL(AMC_DEVELOP, test "$rc_develop" = true)
+
+
AC_ARG_WITH(history,
[ --with-history Build history subprograms],[
case "$withval" in
diff --git a/develop.c b/develop.c
@@ -0,0 +1,303 @@
+#include "rc.h"
+
+#include "develop.h"
+
+void dump(Node *, int);
+
+/* dump a Node * as a tree */
+
+static void dump_1(char *p, Node *n, int indent) {
+ fprint(2, "%s:\n", p);
+ dump(n->u[0].p, indent + 1);
+}
+
+static void dump_2(char *p, Node *n, int indent) {
+ fprint(2, "%s:\n", p);
+ dump(n->u[0].p, indent + 1);
+ if (n->u[1].p != NULL)
+ dump(n->u[1].p, indent + 1);
+}
+
+static void dump_3(char *p, Node *n, int indent) {
+ fprint(2, "%s:\n", p);
+ dump(n->u[0].p, indent + 1);
+ if (n->u[1].p != NULL)
+ dump(n->u[1].p, indent + 1);
+ if (n->u[2].p != NULL)
+ dump(n->u[2].p, indent + 1);
+}
+
+static void dump_s(char *p, Node *n, int indent) {
+ fprint(2, "%s: %S\n", p, n->u[0].s);
+}
+
+static void dump_pipe(char *p, Node *n, int indent) {
+ int ifd = n->u[0].i, ofd = n->u[1].i;
+ fprint(2, "%s %d %d:\n", p, ifd, ofd);
+ dump(n->u[2].p, indent + 1);
+ dump(n->u[3].p, indent + 1);
+}
+
+static char *redir(int op) {
+ switch (op) {
+ case rCreate: return ">";
+ case rAppend: return ">>";
+ case rFrom: return "<";
+ case rHeredoc: return "<<";
+ case rHerestring: return "<<<";
+ default: return "?";
+ }
+}
+static void dump_dup(char *p, Node *n, int indent) {
+ fprint(2, "%s %s %d %d:\n", p, redir(n->u[0].i), n->u[1].i, n->u[2].i);
+}
+
+static void dump_redir(char *p, Node *n, int indent) {
+ fprint(2, "%s %s %d:\n", p, redir(n->u[0].i), n->u[1].i);
+ dump(n->u[2].p, indent + 1);
+}
+
+void dump(Node *n, int indent) {
+ int i;
+
+ if (n == NULL)
+ return;
+
+ for (i = 0; i < indent; ++i)
+ fprint(2, " ");
+
+ switch (n->type) {
+ case nAndalso:
+ dump_2("nAndalso", n, indent);
+ break;
+ case nArgs:
+ dump_2("nArgs", n, indent);
+ break;
+ case nAssign:
+ dump_2("nAassign", n, indent);
+ break;
+ case nBackq:
+ dump_1("nBackq", n, indent);
+ break;
+ case nBang:
+ dump_1("nBang", n, indent);
+ break;
+ case nBody:
+ dump_2("nBody", n, indent);
+ break;
+ case nBrace:
+ dump_1("nBrace", n, indent);
+ break;
+ case nCase:
+ dump_1("nCase", n, indent);
+ break;
+ case nCbody:
+ dump_2("nCbody", n, indent);
+ break;
+ case nConcat:
+ dump_2("nConcat", n, indent);
+ break;
+ case nCount:
+ dump_1("nCount", n, indent);
+ break;
+ case nDup:
+ dump_dup("nDup", n, indent);
+ break;
+ case nElse:
+ dump_2("nElse", n, indent);
+ break;
+ case nEpilog:
+ dump_2("nEpilog", n, indent);
+ break;
+ case nFlat:
+ dump_1("nFlat", n, indent);
+ break;
+ case nForin:
+ dump_3("nForin", n, indent);
+ break;
+ case nIf:
+ dump_2("nIf", n, indent);
+ break;
+ case nLappend:
+ dump_2("nLappend", n, indent);
+ break;
+ case nMatch:
+ dump_2("nMatch", n, indent);
+ break;
+ case nNewfn:
+ dump_2("nNewfn", n, indent);
+ break;
+ case nNmpipe:
+ dump_redir("nNowait", n, indent);
+ break;
+ case nNowait:
+ dump_1("nNowait", n, indent);
+ break;
+ case nOrelse:
+ dump_2("nNowait", n, indent);
+ break;
+ case nPipe:
+ dump_pipe("nPipe", n, indent);
+ break;
+ case nPre:
+ dump_2("nPre", n, indent);
+ break;
+ case nRedir:
+ dump_redir("nRedir", n, indent);
+ break;
+ case nRmfn:
+ dump_1("nRmfn", n, indent);
+ break;
+ case nSubshell:
+ dump_1("nSubshell", n, indent);
+ break;
+ case nSwitch:
+ dump_2("nSwitch", n, indent);
+ break;
+ case nVar:
+ dump_1("nVar", n, indent);
+ break;
+ case nVarsub:
+ dump_2("nVarsub", n, indent);
+ break;
+ case nWhile:
+ dump_2("nWhile", n, indent);
+ break;
+ case nWord:
+ dump_s("nWord", n, indent);
+ break;
+ default:
+ fprint(2, "unknown\n");
+ break;
+ }
+}
+
+void tree_dump(Node *f) {
+ dump(f, 0);
+}
+#if 0
+ bool dollar = f->flags & FMT_altform;
+ Node *n = va_arg(f->args, Node *);
+
+ if (n == NULL) {
+ fmtprint(f, "()");
+ return FALSE;
+ }
+ switch (n->type) {
+ case nBang: fmtprint(f, "!%X", n->u[0].p); break;
+ case nCase: fmtprint(f, "case %X", n->u[0].p); break;
+ case nNowait: fmtprint(f, "%X&", n->u[0].p); break;
+ case nRmfn: fmtprint(f, "fn %X", n->u[0].p); break;
+ case nSubshell: fmtprint(f, "@ %X", n->u[0].p); break;
+ case nAndalso: fmtprint(f, "%X&&%X", n->u[0].p, n->u[1].p); break;
+ case nAssign: fmtprint(f, "%X=%X", n->u[0].p, n->u[1].p); break;
+ case nConcat: fmtprint(f, "%X^%X", n->u[0].p, n->u[1].p); break;
+ case nElse: fmtprint(f, "{%X}else %X", n->u[0].p, n->u[1].p); break;
+ case nNewfn: fmtprint(f, "fn %X {%X}", n->u[0].p, n->u[1].p); break;
+ case nIf: fmtprint(f, "if(%X)%X", n->u[0].p, n->u[1].p); break;
+ case nOrelse: fmtprint(f, "%X||%X", n->u[0].p, n->u[1].p); break;
+ case nArgs: fmtprint(f, "nArgs: ");
+ Xconv(n->u[0].p, 4);
+ Xconv(n->u[1].p, 4); break;
+ case nSwitch: fmtprint(f, "switch(%X){%X}", n->u[0].p, n->u[1].p); break;
+ case nMatch: fmtprint(f, "~ %X %X", n->u[0].p, n->u[1].p); break;
+ case nWhile: fmtprint(f, "while(%X)%X", n->u[0].p, n->u[1].p); break;
+ case nForin: fmtprint(f, "for(%X in %X)%X", n->u[0].p, n->u[1].p, n->u[2].p); break;
+ case nVarsub: fmtprint(f, "$%X(%X)", n->u[0].p, n->u[1].p); break;
+ case nWord:
+ fmtprint(f, n->u[2].i && quotep(n->u[0].s, dollar) ?
+ "%#S" : "%S", n->u[0].s);
+ break;
+ case nLappend: {
+ static bool inlist;
+ if (!inlist) {
+ inlist = TRUE;
+ fmtprint(f, "(%X %X)", n->u[0].p, n->u[1].p);
+ inlist = FALSE;
+ } else {
+ fmtprint(f, "%X %X", n->u[0].p, n->u[1].p);
+ }
+ break;
+ }
+ case nCount: case nFlat: case nVar: {
+ char *lp = "", *rp = "";
+ Node *n0 = n->u[0].p;
+
+ if (n0->type != nWord)
+ lp = "(", rp = ")";
+
+ switch (n->type) {
+ default: panic("this can't happen"); break;
+ case nCount: fmtprint(f, "$#%s%#T%s", lp, n0, rp); break;
+ case nFlat: fmtprint(f, "$^%s%#T%s", lp, n0, rp); break;
+ case nVar: fmtprint(f, "$%s%#T%s", lp, n0, rp); break;
+ }
+ break;
+ }
+ case nDup:
+ if (n->u[2].i != -1)
+ fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i);
+ else
+ fmtprint(f, "%D[%d=]", n->u[0].i, n->u[1].i);
+ break;
+ case nBackq: {
+ Node *n0 = n->u[0].p, *n00;
+ if (n0 != NULL && n0->type == nVar
+ && (n00 = n0->u[0].p) != NULL && n00->type == nWord && streq(n00->u[0].s, "ifs"))
+ fmtprint(f, "`");
+ else
+ fmtprint(f, "``%X", n0);
+ fmtprint(f, "{%X}", n->u[1].p);
+ break;
+ }
+ case nCbody:
+ case nBody: {
+ Node *n0 = n->u[0].p;
+ if (n0 != NULL)
+ fmtprint(f, "%X", n->u[0].p);
+ if (n->u[1].p != NULL) {
+ if (n0 != NULL && n0->type != nNowait)
+ fmtprint(f, ";");
+ fmtprint(f, "%X", n->u[1].p);
+ }
+ break;
+ }
+ case nBrace:
+ fmtprint(f, "{%X}", n->u[0].p);
+ if (n->u[1].p != NULL)
+ fmtprint(f, "%X", n->u[1].p);
+ break;
+ case nEpilog:
+ case nPre:
+ fmtprint(f, "%X", n->u[0].p);
+ if (n->u[1].p != NULL)
+ fmtprint(f, " %X", n->u[1].p);
+ break;
+ case nPipe: {
+ int ofd = n->u[0].i, ifd = n->u[1].i;
+ fmtprint(f, "%X|", n->u[2].p);
+ if (ifd != 0)
+ fmtprint(f, "[%d=%d]", ofd, ifd);
+ else if (ofd != 1)
+ fmtprint(f, "[%d]", ofd);
+ fmtprint(f, "%X", n->u[3].p);
+ break;
+ }
+ case nRedir: {
+ int op = n->u[0].i;
+ fmtprint(f, "%D", op);
+ fmtprint(f, "[%d]", n->u[1].i);
+ fmtprint(f, "%X", n->u[2].p);
+ break;
+ }
+ case nNmpipe: {
+ int op = n->u[0].i;
+ fmtprint(f, "%D", op);
+ fmtprint(f, "[%d]", n->u[1].i);
+ fmtprint(f, "{%X}", n->u[2].p);
+ break;
+ }
+ }
+ return FALSE;
+}
+#endif
diff --git a/develop.h b/develop.h
@@ -0,0 +1,4 @@
+void tree_dump(Node *);
+#ifndef RC_DEVELOP
+#define RC_DEVELOP 0
+#endif
diff --git a/input.c b/input.c
@@ -4,6 +4,7 @@
#include <errno.h>
+#include "develop.h"
#include "edit.h"
#include "input.h"
#include "jbwrap.h"
@@ -306,6 +307,8 @@ extern Node *doit(bool clobberexecit) {
rc_raise(eError);
eof = (lastchar == EOF); /* "lastchar" can be clobbered during a walk() */
if (parsetree != NULL) {
+ if (RC_DEVELOP)
+ tree_dump(parsetree);
if (execit)
walk(parsetree, TRUE);
else if (dashex && dashen)