better parsing for x=(…) – bug noted by Frank Terbeck

This commit is contained in:
tg 2011-06-04 16:11:20 +00:00
parent e0a913181b
commit b3d38f9cdf
4 changed files with 62 additions and 75 deletions

33
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.457 2011/05/29 16:38:58 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.458 2011/06/04 16:11:16 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 $
@ -6132,7 +6132,7 @@ stdin:
expected-stdout:
5|a|$v|c d|$v|b|
---
name: arrays-2
name: arrays-2a
description:
Check if bash-style arrays work as expected
category: !smksh
@ -6143,6 +6143,33 @@ stdin:
expected-stdout:
5|a|$v|c d|$v|b|
---
name: arrays-2b
description:
Check if bash-style arrays work as expected, with newlines
category: !smksh
stdin:
test -n "$ZSH_VERSION" && setopt KSH_ARRAYS
v="e f"
foo=(a
bc
d \$v "$v" '$v' g
)
printf '%s|' "${#foo[*]}" "${foo[0]}" "${foo[1]}" "${foo[2]}" "${foo[3]}" "${foo[4]}" "${foo[5]}" "${foo[6]}"; echo
foo=(a\
bc
d \$v "$v" '$v' g
)
printf '%s|' "${#foo[*]}" "${foo[0]}" "${foo[1]}" "${foo[2]}" "${foo[3]}" "${foo[4]}" "${foo[5]}" "${foo[6]}"; echo
foo=(a\
bc\\
d \$v "$v" '$v'
g)
printf '%s|' "${#foo[*]}" "${foo[0]}" "${foo[1]}" "${foo[2]}" "${foo[3]}" "${foo[4]}" "${foo[5]}" "${foo[6]}"; echo
expected-stdout:
7|a|bc|d|$v|e f|$v|g|
7|a|bc|d|$v|e f|$v|g|
6|abc\|d|$v|e f|$v|g||
---
name: arrays-3
description:
Check if array bounds are uint32_t
@ -7675,7 +7702,7 @@ expected-stdout:
a+=b
;|
(*)
eval set -A c+ -- d e
set -A c+ -- d e
;;
esac
}

50
lex.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.152 2011/05/29 06:19:27 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.153 2011/06/04 16:11:18 tg Exp $");
/*
* states while lexing word
@ -41,9 +41,8 @@ __RCSID("$MirOS: src/bin/mksh/lex.c,v 1.152 2011/05/29 06:19:27 tg Exp $");
#define SHEREDQUOTE 11 /* parsing " in <<,<<- delimiter */
#define SPATTERN 12 /* parsing *(...|...) pattern (*+?@!) */
#define STBRACE 13 /* parsing ${...[#%]...} */
#define SLETARRAY 14 /* inside =( ), just copy */
#define SADELIM 15 /* like SBASE, looking for delimiter */
#define SHERESTRING 16 /* parsing <<< string */
#define SADELIM 14 /* like SBASE, looking for delimiter */
#define SHERESTRING 15 /* parsing <<< string */
#define SINVALID 255 /* invalid state */
struct sretrace_info {
@ -220,12 +219,6 @@ yylex(int cf)
*wp++ = OQUOTE;
state = SLETPAREN;
statep->nparen = 0;
#ifndef MKSH_SMALL
} else if (cf & LETARRAY) {
state = SLETARRAY;
statep->nparen = 0;
PUSH_SRETRACE();
#endif
} else {
/* normal lexing */
state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
@ -245,7 +238,7 @@ yylex(int cf)
cf |= ALIAS;
}
/* Initial state: one of SWORD SLETPAREN SLETARRAY SHEREDELIM SBASE */
/* Initial state: one of SWORD SLETPAREN SHEREDELIM SBASE */
statep->type = state;
/* check for here string */
@ -779,30 +772,6 @@ yylex(int cf)
++statep->nparen;
goto Sbase2;
#ifndef MKSH_SMALL
/* LETARRAY: =( ... ) */
case SLETARRAY:
if (c == '('/*)*/)
++statep->nparen;
else if (c == /*(*/')') {
if (statep->nparen-- == 0) {
POP_SRETRACE();
/* drop trailing paren */
c = strlen(dp = sp) - 1;
XcheckN(ws, wp, c * 2);
while (c--) {
*wp++ = CHAR;
*wp++ = *dp++;
}
afree(sp, ATEMP);
/* assert: c == 0 */
goto Done;
}
}
/* reuse existing state machine */
goto Sbase2;
#endif
/* <<< delimiter */
case SHERESTRING:
if (c == '\\') {
@ -934,11 +903,6 @@ yylex(int cf)
/* XXX figure out what is missing */
yyerror("no closing quote\n");
#ifndef MKSH_SMALL
if (state == SLETARRAY && statep->nparen != -1)
yyerror("%s: %s\n", T_synerr, "missing )");
#endif
/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
if (state == SHEREDELIM || state == SHERESTRING)
state = SBASE;
@ -1046,11 +1010,7 @@ yylex(int cf)
*wp++ = EOS;
yylval.cp = Xclose(ws, wp);
if (state == SWORD || state == SLETPAREN
/* XXX ONEWORD? */
#ifndef MKSH_SMALL
|| state == SLETARRAY
#endif
)
/* XXX ONEWORD? */)
return (LWORD);
/* unget terminator */

5
sh.h
View File

@ -151,7 +151,7 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.471 2011/05/29 16:31:42 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.472 2011/06/04 16:11:19 tg Exp $");
#endif
#define MKSH_VERSION "R40 2011/05/29"
@ -1413,9 +1413,8 @@ typedef union {
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
#define LQCHAR BIT(10) /* source string contains QCHAR */
#define HEREDOC BIT(11) /* parsing a here document */
#define LETARRAY BIT(12) /* copy expression inside =( ) */
#define HERES 10 /* max << in line */
#define HERES 10 /* max number of << in line */
#undef CTRL
#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */

49
syn.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.65 2011/05/29 02:18:57 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.66 2011/06/04 16:11:20 tg Exp $");
extern short subshell_nesting_level;
@ -292,6 +292,11 @@ get_command(int cf)
break;
case '(':
#ifndef MKSH_SMALL
if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
XPsize(vars) == 1 && is_wdvarassign(yylval.cp))
goto is_wdarrassign;
#endif
/*
* Check for "> foo (echo hi)" which AT&T ksh
* allows (not POSIX, but not disallowed)
@ -301,11 +306,7 @@ get_command(int cf)
ACCEPT;
goto Subshell;
}
#ifndef MKSH_SMALL
if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
XPsize(vars) == 1 && is_wdvarassign(yylval.cp))
goto is_wdarrassign;
#endif
/* must be a function */
if (iopn != 0 || XPsize(args) != 1 ||
XPsize(vars) != 0)
@ -318,37 +319,37 @@ get_command(int cf)
is_wdarrassign:
{
static const char set_cmd0[] = {
CHAR, 'e', CHAR, 'v',
CHAR, 'a', CHAR, 'l', EOS
CHAR, 's', CHAR, 'e',
CHAR, 't', EOS
};
static const char set_cmd1[] = {
CHAR, 's', CHAR, 'e',
CHAR, 't', CHAR, ' ',
CHAR, '-', CHAR, 'A', EOS
};
static const char set_cmd2[] = {
CHAR, '-', CHAR, '-', EOS
};
char *tcp;
XPfree(vars);
XPinit(vars, 16);
/*
* we know (or rather hope) that yylval.cp
* contains a string "varname="
*/
tcp = wdcopy(yylval.cp, ATEMP);
tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
/* now make an array assignment command */
t = newtp(TCOM);
t->lineno = source->line;
ACCEPT;
/* manipulate the vars string */
tcp = *(--vars.cur);
/* 'varname=' -> 'varname' */
tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
/* construct new args strings */
XPput(args, wdcopy(set_cmd0, ATEMP));
XPput(args, wdcopy(set_cmd1, ATEMP));
XPput(args, tcp);
XPput(args, wdcopy(set_cmd2, ATEMP));
musthave(LWORD,LETARRAY);
XPput(args, yylval.cp);
break;
/* slurp in words till closing paren */
while (token(CONTIN) == LWORD)
XPput(args, yylval.cp);
if (symbol != /*(*/ ')')
syntaxerr(NULL);
goto Leave;
}
#endif