rc

[fork] interactive rc shell
Log | Files | Refs | README | LICENSE

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:
MMakefile.am | 8++++++--
Mconfigure.ac | 13+++++++++++++
Adevelop.c | 303+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adevelop.h | 4++++
Minput.c | 3+++
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)