better parsing for x=(…) – bug noted by Frank Terbeck
This commit is contained in:
parent
e0a913181b
commit
b3d38f9cdf
33
check.t
33
check.t
@ -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: 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: 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 $
|
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
|
||||||
@ -6132,7 +6132,7 @@ stdin:
|
|||||||
expected-stdout:
|
expected-stdout:
|
||||||
5|a|$v|c d|$v|b|
|
5|a|$v|c d|$v|b|
|
||||||
---
|
---
|
||||||
name: arrays-2
|
name: arrays-2a
|
||||||
description:
|
description:
|
||||||
Check if bash-style arrays work as expected
|
Check if bash-style arrays work as expected
|
||||||
category: !smksh
|
category: !smksh
|
||||||
@ -6143,6 +6143,33 @@ stdin:
|
|||||||
expected-stdout:
|
expected-stdout:
|
||||||
5|a|$v|c d|$v|b|
|
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
|
name: arrays-3
|
||||||
description:
|
description:
|
||||||
Check if array bounds are uint32_t
|
Check if array bounds are uint32_t
|
||||||
@ -7675,7 +7702,7 @@ expected-stdout:
|
|||||||
a+=b
|
a+=b
|
||||||
;|
|
;|
|
||||||
(*)
|
(*)
|
||||||
eval set -A c+ -- d e
|
set -A c+ -- d e
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
50
lex.c
50
lex.c
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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
|
* 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 SHEREDQUOTE 11 /* parsing " in <<,<<- delimiter */
|
||||||
#define SPATTERN 12 /* parsing *(...|...) pattern (*+?@!) */
|
#define SPATTERN 12 /* parsing *(...|...) pattern (*+?@!) */
|
||||||
#define STBRACE 13 /* parsing ${...[#%]...} */
|
#define STBRACE 13 /* parsing ${...[#%]...} */
|
||||||
#define SLETARRAY 14 /* inside =( ), just copy */
|
#define SADELIM 14 /* like SBASE, looking for delimiter */
|
||||||
#define SADELIM 15 /* like SBASE, looking for delimiter */
|
#define SHERESTRING 15 /* parsing <<< string */
|
||||||
#define SHERESTRING 16 /* parsing <<< string */
|
|
||||||
#define SINVALID 255 /* invalid state */
|
#define SINVALID 255 /* invalid state */
|
||||||
|
|
||||||
struct sretrace_info {
|
struct sretrace_info {
|
||||||
@ -220,12 +219,6 @@ yylex(int cf)
|
|||||||
*wp++ = OQUOTE;
|
*wp++ = OQUOTE;
|
||||||
state = SLETPAREN;
|
state = SLETPAREN;
|
||||||
statep->nparen = 0;
|
statep->nparen = 0;
|
||||||
#ifndef MKSH_SMALL
|
|
||||||
} else if (cf & LETARRAY) {
|
|
||||||
state = SLETARRAY;
|
|
||||||
statep->nparen = 0;
|
|
||||||
PUSH_SRETRACE();
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
/* normal lexing */
|
/* normal lexing */
|
||||||
state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
|
state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
|
||||||
@ -245,7 +238,7 @@ yylex(int cf)
|
|||||||
cf |= ALIAS;
|
cf |= ALIAS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initial state: one of SWORD SLETPAREN SLETARRAY SHEREDELIM SBASE */
|
/* Initial state: one of SWORD SLETPAREN SHEREDELIM SBASE */
|
||||||
statep->type = state;
|
statep->type = state;
|
||||||
|
|
||||||
/* check for here string */
|
/* check for here string */
|
||||||
@ -779,30 +772,6 @@ yylex(int cf)
|
|||||||
++statep->nparen;
|
++statep->nparen;
|
||||||
goto Sbase2;
|
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 */
|
/* <<< delimiter */
|
||||||
case SHERESTRING:
|
case SHERESTRING:
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
@ -934,11 +903,6 @@ yylex(int cf)
|
|||||||
/* XXX figure out what is missing */
|
/* XXX figure out what is missing */
|
||||||
yyerror("no closing quote\n");
|
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 */
|
/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
|
||||||
if (state == SHEREDELIM || state == SHERESTRING)
|
if (state == SHEREDELIM || state == SHERESTRING)
|
||||||
state = SBASE;
|
state = SBASE;
|
||||||
@ -1046,11 +1010,7 @@ yylex(int cf)
|
|||||||
*wp++ = EOS;
|
*wp++ = EOS;
|
||||||
yylval.cp = Xclose(ws, wp);
|
yylval.cp = Xclose(ws, wp);
|
||||||
if (state == SWORD || state == SLETPAREN
|
if (state == SWORD || state == SLETPAREN
|
||||||
/* XXX ONEWORD? */
|
/* XXX ONEWORD? */)
|
||||||
#ifndef MKSH_SMALL
|
|
||||||
|| state == SLETARRAY
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
return (LWORD);
|
return (LWORD);
|
||||||
|
|
||||||
/* unget terminator */
|
/* unget terminator */
|
||||||
|
5
sh.h
5
sh.h
@ -151,7 +151,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EXTERN
|
#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
|
#endif
|
||||||
#define MKSH_VERSION "R40 2011/05/29"
|
#define MKSH_VERSION "R40 2011/05/29"
|
||||||
|
|
||||||
@ -1413,9 +1413,8 @@ typedef union {
|
|||||||
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
|
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
|
||||||
#define LQCHAR BIT(10) /* source string contains QCHAR */
|
#define LQCHAR BIT(10) /* source string contains QCHAR */
|
||||||
#define HEREDOC BIT(11) /* parsing a here document */
|
#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
|
#undef CTRL
|
||||||
#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */
|
#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */
|
||||||
|
49
syn.c
49
syn.c
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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;
|
extern short subshell_nesting_level;
|
||||||
|
|
||||||
@ -292,6 +292,11 @@ get_command(int cf)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '(':
|
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
|
* Check for "> foo (echo hi)" which AT&T ksh
|
||||||
* allows (not POSIX, but not disallowed)
|
* allows (not POSIX, but not disallowed)
|
||||||
@ -301,11 +306,7 @@ get_command(int cf)
|
|||||||
ACCEPT;
|
ACCEPT;
|
||||||
goto Subshell;
|
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 */
|
/* must be a function */
|
||||||
if (iopn != 0 || XPsize(args) != 1 ||
|
if (iopn != 0 || XPsize(args) != 1 ||
|
||||||
XPsize(vars) != 0)
|
XPsize(vars) != 0)
|
||||||
@ -318,37 +319,37 @@ get_command(int cf)
|
|||||||
is_wdarrassign:
|
is_wdarrassign:
|
||||||
{
|
{
|
||||||
static const char set_cmd0[] = {
|
static const char set_cmd0[] = {
|
||||||
CHAR, 'e', CHAR, 'v',
|
CHAR, 's', CHAR, 'e',
|
||||||
CHAR, 'a', CHAR, 'l', EOS
|
CHAR, 't', EOS
|
||||||
};
|
};
|
||||||
static const char set_cmd1[] = {
|
static const char set_cmd1[] = {
|
||||||
CHAR, 's', CHAR, 'e',
|
|
||||||
CHAR, 't', CHAR, ' ',
|
|
||||||
CHAR, '-', CHAR, 'A', EOS
|
CHAR, '-', CHAR, 'A', EOS
|
||||||
};
|
};
|
||||||
static const char set_cmd2[] = {
|
static const char set_cmd2[] = {
|
||||||
CHAR, '-', CHAR, '-', EOS
|
CHAR, '-', CHAR, '-', EOS
|
||||||
};
|
};
|
||||||
char *tcp;
|
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;
|
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_cmd0, ATEMP));
|
||||||
XPput(args, wdcopy(set_cmd1, ATEMP));
|
XPput(args, wdcopy(set_cmd1, ATEMP));
|
||||||
XPput(args, tcp);
|
XPput(args, tcp);
|
||||||
XPput(args, wdcopy(set_cmd2, ATEMP));
|
XPput(args, wdcopy(set_cmd2, ATEMP));
|
||||||
musthave(LWORD,LETARRAY);
|
|
||||||
XPput(args, yylval.cp);
|
/* slurp in words till closing paren */
|
||||||
break;
|
while (token(CONTIN) == LWORD)
|
||||||
|
XPput(args, yylval.cp);
|
||||||
|
if (symbol != /*(*/ ')')
|
||||||
|
syntaxerr(NULL);
|
||||||
|
|
||||||
|
goto Leave;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user