• add a tree debugging dumper #ifdef DEBUG

• use shf_putc (macro), shf_putchar (function) ipv tputc
• replace shf_putchar(x,y) calls for side-effect-less x with shf_putc
• plug another bug in the tree code – '\' → "\\" (backslashes must be
  escaped inside double quotes, too)
• adjust testsuite (and, I _had_ wondered…)
This commit is contained in:
tg 2011-03-08 18:49:51 +00:00
parent 6894618bb9
commit f8659785ac
3 changed files with 325 additions and 56 deletions

10
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.417 2011/03/07 20:32:48 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.418 2011/03/08 18:49:48 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
@ -25,7 +25,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout:
@(#)MIRBSD KSH R39 2011/03/07
@(#)MIRBSD KSH R39 2011/03/08
description:
Check version of shell.
stdin:
@ -7434,7 +7434,7 @@ expected-stdout:
inline_QCHAR_OQUOTE_CQUOTE() {
echo fo\ob\"a\`r\'b\$az
echo "fo\ob\"a\`r\'b\$az"
echo "fo\ob\\"a\\`r"\'"b\\$az"
echo "fo\\ob\\\"a\\\`r"\'"b\\\$az"
}
function comsub_QCHAR_OQUOTE_CQUOTE { x=$(
echo fo\ob\"a\`r\'b\$az
@ -7442,7 +7442,7 @@ expected-stdout:
echo 'fo\ob\"a\`r'\''b\$az'
); }
function comsub_QCHAR_OQUOTE_CQUOTE {
x=$(echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\ob\\"a\\`r"\'"b\\$az" )
x=$(echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" )
}
function reread_QCHAR_OQUOTE_CQUOTE { x=$((
echo fo\ob\"a\`r\'b\$az
@ -7450,7 +7450,7 @@ expected-stdout:
echo 'fo\ob\"a\`r'\''b\$az'
)|tr u x); }
function reread_QCHAR_OQUOTE_CQUOTE {
x=$(( echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\ob\\"a\\`r"\'"b\\$az" ) | tr u x )
x=$(( echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" ) | tr u x )
}
inline_OSUBST_CSUBST_OPAT_SPAT_CPAT() {
[[ ${foo#blub} = @(bar|baz) ]]

5
sh.h
View File

@ -154,9 +154,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.440 2011/03/07 20:32:50 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.441 2011/03/08 18:49:50 tg Exp $");
#endif
#define MKSH_VERSION "R39 2011/03/07"
#define MKSH_VERSION "R39 2011/03/08"
#ifndef MKSH_INCLUDES_ONLY
@ -1752,6 +1752,7 @@ char *wdcopy(const char *, Area *);
const char *wdscan(const char *, int);
char *wdstrip(const char *, bool, bool);
void tfree(struct op *, Area *);
void dumptree(struct shf *, struct op *);
void vistree(char *, size_t, struct op *)
MKSH_A_BOUNDED(string, 1, 2);
void fpFUNCTf(struct shf *, int, bool, const char *, struct op *);

366
tree.c
View File

@ -22,11 +22,10 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.36 2011/03/06 17:08:14 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.37 2011/03/08 18:49:51 tg Exp $");
#define INDENT 8
#define tputc(c, shf) shf_putchar(c, shf);
static void ptree(struct op *, int, struct shf *);
static void pioact(struct shf *, int, struct ioword *);
static void tputS(const char *, struct shf *);
@ -202,7 +201,7 @@ ptree(struct op *t, int indent, struct shf *shf)
if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc &&
/* iop->delim[1] == '<' means here string */
(!iop->delim || iop->delim[1] != '<')) {
tputc('\n', shf);
shf_putc('\n', shf);
shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s",
evalstr(iop->delim, 0));
@ -215,7 +214,7 @@ ptree(struct op *t, int indent, struct shf *shf)
* worth worrying about)
*/
if (need_nl)
tputc('\n', shf);
shf_putc('\n', shf);
}
}
@ -258,7 +257,7 @@ pioact(struct shf *shf, int indent, struct ioword *iop)
if (iop->delim)
fptreef(shf, indent, "%S ", iop->delim);
else
tputc(' ', shf);
shf_putc(' ', shf);
} else if (iop->name)
fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
iop->name);
@ -285,57 +284,56 @@ tputS(const char *wp, struct shf *shf)
return;
case ADELIM:
case CHAR:
tputc(*wp++, shf);
shf_putchar(*wp++, shf);
break;
case QCHAR:
c = *wp++;
if (!quotelevel || (c == '"' || c == '`' || c == '$'))
tputc('\\', shf);
tputc(c, shf);
if (!quotelevel ||
(c == '"' || c == '`' || c == '$' || c == '\\'))
shf_putc('\\', shf);
shf_putc(c, shf);
break;
case COMSUB:
shf_puts("$(", shf);
while (*wp != 0)
tputc(*wp++, shf);
tputc(')', shf);
wp++;
while ((c = *wp++) != 0)
shf_putc(c, shf);
shf_putc(')', shf);
break;
case EXPRSUB:
shf_puts("$((", shf);
while (*wp != 0)
tputc(*wp++, shf);
while ((c = *wp++) != 0)
shf_putc(c, shf);
shf_puts("))", shf);
wp++;
break;
case OQUOTE:
quotelevel++;
tputc('"', shf);
shf_putc('"', shf);
break;
case CQUOTE:
if (quotelevel)
quotelevel--;
tputc('"', shf);
shf_putc('"', shf);
break;
case OSUBST:
tputc('$', shf);
shf_putc('$', shf);
if (*wp++ == '{')
tputc('{', shf);
shf_putc('{', shf);
while ((c = *wp++) != 0)
tputc(c, shf);
shf_putc(c, shf);
break;
case CSUBST:
if (*wp++ == '}')
tputc('}', shf);
shf_putc('}', shf);
break;
case OPAT:
tputc(*wp++, shf);
tputc('(', shf);
shf_putchar(*wp++, shf);
shf_putc('(', shf);
break;
case SPAT:
tputc('|', shf);
shf_putc('|', shf);
break;
case CPAT:
tputc(')', shf);
shf_putc(')', shf);
break;
}
}
@ -382,7 +380,7 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
switch ((c = *fmt++)) {
case 'c':
/* character (octet, probably) */
tputc(va_arg(va, int), shf);
shf_putchar(va_arg(va, int), shf);
break;
case 's':
/* string */
@ -410,19 +408,19 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
/* newline or space */
if (shf->flags & SHF_STRING) {
if (c == ';' && !prevent_semicolon)
tputc(';', shf);
tputc(' ', shf);
shf_putc(';', shf);
shf_putc(' ', shf);
} else {
int i;
tputc('\n', shf);
shf_putc('\n', shf);
i = indent;
while (i >= 8) {
tputc('\t', shf);
shf_putc('\t', shf);
i -= 8;
}
while (i--)
tputc(' ', shf);
shf_putc(' ', shf);
}
break;
case 'R':
@ -430,11 +428,11 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
pioact(shf, indent, va_arg(va, struct ioword *));
break;
default:
tputc(c, shf);
shf_putc(c, shf);
break;
}
} else
tputc(c, shf);
shf_putc(c, shf);
prevent_semicolon = false;
dont_trash_prevent_semicolon:
;
@ -593,20 +591,20 @@ wdstrip(const char *wp, bool keepq, bool make_magic)
c = *wp++;
if (make_magic && (ISMAGIC(c) || c == '[' || c == NOT ||
c == '-' || c == ']' || c == '*' || c == '?'))
shf_putchar(MAGIC, &shf);
shf_putchar(c, &shf);
shf_putc(MAGIC, &shf);
shf_putc(c, &shf);
break;
case QCHAR:
c = *wp++;
if (keepq && (c == '"' || c == '`' || c == '$' || c == '\\'))
shf_putchar('\\', &shf);
shf_putchar(c, &shf);
shf_putc('\\', &shf);
shf_putc(c, &shf);
break;
case COMSUB:
shf_puts("$(", &shf);
while (*wp != 0)
shf_putchar(*wp++, &shf);
shf_putchar(')', &shf);
shf_putc(')', &shf);
break;
case EXPRSUB:
shf_puts("$((", &shf);
@ -619,34 +617,34 @@ wdstrip(const char *wp, bool keepq, bool make_magic)
case CQUOTE:
break;
case OSUBST:
shf_putchar('$', &shf);
shf_putc('$', &shf);
if (*wp++ == '{')
shf_putchar('{', &shf);
shf_putc('{', &shf);
while ((c = *wp++) != 0)
shf_putchar(c, &shf);
shf_putc(c, &shf);
break;
case CSUBST:
if (*wp++ == '}')
shf_putchar('}', &shf);
shf_putc('}', &shf);
break;
case OPAT:
if (make_magic) {
shf_putchar(MAGIC, &shf);
shf_putc(MAGIC, &shf);
shf_putchar(*wp++ | 0x80, &shf);
} else {
shf_putchar(*wp++, &shf);
shf_putchar('(', &shf);
shf_putc('(', &shf);
}
break;
case SPAT:
if (make_magic)
shf_putchar(MAGIC, &shf);
shf_putchar('|', &shf);
shf_putc(MAGIC, &shf);
shf_putc('|', &shf);
break;
case CPAT:
if (make_magic)
shf_putchar(MAGIC, &shf);
shf_putchar(')', &shf);
shf_putc(MAGIC, &shf);
shf_putc(')', &shf);
break;
}
}
@ -774,3 +772,273 @@ vistree(char *dst, size_t sz, struct op *t)
*dst = '\0';
afree(buf, ATEMP);
}
#ifdef DEBUG
static void
dumpchar(struct shf *shf, int c)
{
if (((c & 0x60) == 0) || ((c & 0x7F) == 0x7F)) {
/* C0 or C1 control character or DEL */
shf_putc((c & 0x80) ? '$' : '^', shf);
c = (c & 0x7F) ^ 0x40;
}
shf_putc(c, shf);
}
/* see: tputS */
static void
dumpwdvar(struct shf *shf, const char *wp)
{
int c, quotelevel = 0;
while (1) {
switch(*wp++) {
case EOS:
shf_puts("EOS", shf);
return;
case ADELIM:
shf_puts("ADELIM=", shf);
dumpchar:
dumpchar(shf, *wp++);
break;
case CHAR:
shf_puts("CHAR=", shf);
goto dumpchar;
case QCHAR:
shf_puts("QCHAR<", shf);
c = *wp++;
if (!quotelevel ||
(c == '"' || c == '`' || c == '$' || c == '\\'))
shf_putc('\\', shf);
dumpchar(shf, c);
goto closeandout;
case COMSUB:
shf_puts("COMSUB<", shf);
dumpsub:
while ((c = *wp++) != 0)
dumpchar(shf, c);
closeandout:
shf_putc('>', shf);
break;
case EXPRSUB:
shf_puts("EXPRSUB<", shf);
goto dumpsub;
case OQUOTE:
shf_fprintf(shf, "OQUOTE{%d", ++quotelevel);
break;
case CQUOTE:
shf_fprintf(shf, "%d}CQUOTE", quotelevel);
if (quotelevel)
quotelevel--;
else
shf_puts("(err)", shf);
break;
case OSUBST:
shf_puts("OSUBST(", shf);
dumpchar(shf, *wp++);
shf_puts(")[", shf);
while ((c = *wp++) != 0)
dumpchar(shf, c);
break;
case CSUBST:
shf_puts("]CSUBST(", shf);
dumpchar(shf, *wp++);
shf_putc(')', shf);
break;
case OPAT:
shf_puts("OPAT=", shf);
dumpchar(shf, *wp++);
break;
case SPAT:
shf_puts("SPAT", shf);
break;
case CPAT:
shf_puts("CPAT", shf);
break;
default:
shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]);
break;
}
shf_putc(' ', shf);
}
}
void
dumptree(struct shf *shf, struct op *t)
{
int i;
const char **w, *name;
struct op *t1;
static int nesting = 0;
for (i = 0; i < nesting; ++i)
shf_putc('\t', shf);
++nesting;
shf_puts("{tree:" /*}*/, shf);
if (t == NULL) {
name = "(null)";
goto out;
}
switch (t->type) {
#define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/
OPEN(TCOM)
if (t->vars) {
i = 0;
w = (const char **)t->vars;
while (*w) {
shf_putc('\n', shf);
for (int j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " var%d<", i++);
dumpwdvar(shf, *w++);
shf_putc('>', shf);
}
} else
shf_puts(" #no-vars#", shf);
if (t->args) {
i = 0;
w = t->args;
while (*w) {
shf_putc('\n', shf);
for (int j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " arg%d<", i++);
dumpwdvar(shf, *w++);
shf_putc('>', shf);
}
} else
shf_puts(" #no-args#", shf);
break;
OPEN(TEXEC)
dumpleftandout:
t = t->left;
dumpandout:
shf_putc('\n', shf);
dumptree(shf, t);
break;
OPEN(TPAREN)
goto dumpleftandout;
OPEN(TPIPE)
dumpleftmidrightandout:
shf_putc('\n', shf);
dumptree(shf, t->left);
// middumprightandout:
shf_fprintf(shf, "/%s:", name);
dumprightandout:
t = t->right;
goto dumpandout;
OPEN(TLIST)
goto dumpleftmidrightandout;
OPEN(TOR)
goto dumpleftmidrightandout;
OPEN(TAND)
goto dumpleftmidrightandout;
OPEN(TBANG)
goto dumprightandout;
OPEN(TDBRACKET)
i = 0;
w = t->args;
while (*w) {
shf_putc('\n', shf);
for (int j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " arg%d<", i++);
dumpwdvar(shf, *w++);
shf_putc('>', shf);
}
break;
OPEN(TFOR)
dumpfor:
shf_fprintf(shf, " str<%s>", t->str);
if (t->vars != NULL) {
i = 0;
w = (const char **)t->vars;
while (*w) {
shf_putc('\n', shf);
for (int j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " var%d<", i++);
dumpwdvar(shf, *w++);
shf_putc('>', shf);
}
}
goto dumpleftandout;
OPEN(TSELECT)
goto dumpfor;
OPEN(TCASE)
shf_fprintf(shf, " str<%s>", t->str);
i = 0;
for (t1 = t->left; t1 != NULL; t1 = t1->right) {
shf_putc('\n', shf);
for (int j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " sub%d[(", i);
w = (const char **)t1->vars;
while (*w) {
dumpwdvar(shf, *w);
if (w[1] != NULL)
shf_putc('|', shf);
++w;
}
shf_putc(')', shf);
shf_putc('\n', shf);
dumptree(shf, t1->left);
shf_fprintf(shf, " /%d]", i++);
}
break;
OPEN(TWHILE)
goto dumpleftmidrightandout;
OPEN(TUNTIL)
goto dumpleftmidrightandout;
OPEN(TBRACE)
goto dumpleftandout;
OPEN(TCOPROC)
goto dumpleftandout;
OPEN(TASYNC)
goto dumpleftandout;
OPEN(TFUNCT)
shf_fprintf(shf, " str<%s> ksh<%s>", t->str,
t->u.ksh_func ? "yes" : "no");
goto dumpleftandout;
OPEN(TTIME)
goto dumpleftandout;
OPEN(TIF)
dumpif:
shf_putc('\n', shf);
dumptree(shf, t->left);
t = t->right;
if (t->left != NULL) {
shf_puts(" /TTHEN:\n", shf);
dumptree(shf, t->left);
}
if (t->right && t->right->type == TELIF) {
shf_puts(" /TELIF:", shf);
t = t->right;
goto dumpif;
}
if (t->right != NULL) {
shf_puts(" /TELSE:\n", shf);
dumptree(shf, t->right);
}
break;
OPEN(TEOF)
dumpunexpected:
shf_puts("unexpected", shf);
break;
OPEN(TELIF)
goto dumpunexpected;
OPEN(TPAT)
goto dumpunexpected;
default:
name = "TINVALID";
shf_fprintf(shf, "{T<%d>:" /*}*/, t->type);
goto dumpunexpected;
#undef OPEN
}
out:
shf_fprintf(shf, /*{*/ " /%s}\n", name);
--nesting;
}
#endif