fix long-standing parenthesēs problem: ((foo) || bar) is now parsed corr.

This commit is contained in:
tg 2009-10-04 12:45:23 +00:00
parent c2e5737fca
commit 5f58261287
3 changed files with 129 additions and 27 deletions

86
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.317 2009/10/04 12:44:18 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.318 2009/10/04 12:45:21 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 $
@ -6488,3 +6488,87 @@ expected-stdout:
4 127 .
5 127 .
---
name: better-parens-1a
description:
Check support for (()) and $(()) vs () and $()
stdin:
if ( (echo fubar) | tr u x); then
echo ja
else
echo nein
fi
expected-stdout:
fxbar
ja
---
name: better-parens-1b
description:
Check support for (()) and $(()) vs () and $()
stdin:
echo $( (echo fubar) | tr u x) $?
expected-stdout:
fxbar 0
---
name: better-parens-2a
description:
Check support for (()) and $(()) vs () and $()
stdin:
if ((echo fubar) | tr u x); then
echo ja
else
echo nein
fi
expected-stdout:
fxbar
ja
---
name: better-parens-2b
description:
Check support for (()) and $(()) vs () and $()
stdin:
echo $((echo fubar) | tr u x) $?
expected-stdout:
fxbar 0
---
name: better-parens-3a
description:
Check support for (()) and $(()) vs () and $()
stdin:
if ( (echo fubar) | (tr u x)); then
echo ja
else
echo nein
fi
expected-stdout:
fxbar
ja
---
name: better-parens-3b
description:
Check support for (()) and $(()) vs () and $()
stdin:
echo $( (echo fubar) | (tr u x)) $?
expected-stdout:
fxbar 0
---
name: better-parens-4a
description:
Check support for (()) and $(()) vs () and $()
stdin:
if ((echo fubar) | (tr u x)); then
echo ja
else
echo nein
fi
expected-stdout:
fxbar
ja
---
name: better-parens-4b
description:
Check support for (()) and $(()) vs () and $()
stdin:
echo $((echo fubar) | (tr u x)) $?
expected-stdout:
fxbar 0
---

50
lex.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.99 2009/10/04 12:44:19 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.100 2009/10/04 12:45:22 tg Exp $");
/*
* states while lexing word
@ -39,7 +39,7 @@ __RCSID("$MirOS: src/bin/mksh/lex.c,v 1.99 2009/10/04 12:44:19 tg Exp $");
#define SHEREDELIM 9 /* parsing <<,<<- delimiter */
#define SHEREDQUOTE 10 /* parsing " in <<,<<- delimiter */
#define SPATTERN 11 /* parsing *(...|...) pattern (*+?@!) */
#define STBRACE 12 /* parsing ${..[#%]..} */
#define STBRACE 12 /* parsing ${...[#%]...} */
#define SLETARRAY 13 /* inside =( ), just copy */
#define SADELIM 14 /* like SBASE, looking for delimiter */
#define SHERESTRING 15 /* parsing <<< string */
@ -477,7 +477,7 @@ yylex(int cf)
*wp++ = COMSUB;
/* Need to know if we are inside double quotes
* since sh/AT&T-ksh translate the \" to " in
* "`..\"..`".
* "`...\"...`".
* This is not done in POSIX mode (section
* 3.2.3, Double Quotes: "The backquote shall
* retain its special meaning introducing the
@ -568,10 +568,10 @@ yylex(int cf)
goto Subst;
break;
case SCSPAREN: /* $( .. ) */
case SCSPAREN: /* $( ... ) */
/* todo: deal with $(...) quoting properly
* kludge to partly fake quoting inside $(..): doesn't
* really work because nested $(..) or ${..} inside
* kludge to partly fake quoting inside $(...): doesn't
* really work because nested $(...) or ${...} inside
* double quotes aren't dealt with.
*/
switch (statep->ls_scsparen.csstate) {
@ -622,10 +622,9 @@ yylex(int cf)
*wp++ = c;
break;
case SASPAREN: /* $(( .. )) */
/* todo: deal with $((...); (...)) properly */
case SASPAREN: /* $(( ... )) */
/* XXX should nest using existing state machine
* (embed "..", $(...), etc.) */
* (embed "...", $(...), etc.) */
if (c == '(')
statep->ls_sasparen.nparen++;
else if (c == ')') {
@ -642,7 +641,7 @@ yylex(int cf)
ungetsc(c2);
/* mismatched parenthesis -
* assume we were really
* parsing a $(..) expression
* parsing a $(...) expression
*/
s = Xrestpos(ws, wp,
statep->ls_sasparen.start);
@ -722,13 +721,27 @@ yylex(int cf)
if (c == ')') {
if (statep->ls_sletparen.nparen > 0)
--statep->ls_sletparen.nparen;
/*(*/
else if ((c2 = getsc()) == ')') {
else if ((c2 = getsc()) == /*(*/ ')') {
c = 0;
*wp++ = CQUOTE;
goto Done;
} else
} else {
Source *s;
ungetsc(c2);
/* mismatched parenthesis -
* assume we were really
* parsing a $(...) expression
*/
*wp = EOS;
sp = Xstring(ws, wp);
dp = wdstrip(sp, true, false);
s = pushs(SREREAD, source->areap);
s->start = s->str = s->u.freeme = dp;
s->next = source;
source = s;
return ('('/*)*/);
}
} else if (c == '(')
/* parenthesis inside quotes and backslashes
* are lost, but AT&T ksh doesn't count them
@ -787,12 +800,12 @@ yylex(int cf)
case SHEREDELIM: /* <<,<<- delimiter */
/* XXX chuck this state (and the next) - use
* the existing states ($ and \`..` should be
* the existing states ($ and \`...` should be
* stripped of their specialness after the
* fact).
*/
/* here delimiters need a special case since
* $ and `..` are not to be treated specially
* $ and `...` are not to be treated specially
*/
if (c == '\\') {
c = getsc();
@ -945,11 +958,6 @@ yylex(int cf)
c = (c == ';') ? BREAK :
(c == '|') ? LOGOR :
(c == '&') ? LOGAND :
/*
* this is the place where
* ((...); (...))
* and similar is broken
*/
/* c == '(' ) */ MDPAREN;
else if (c == '|' && c2 == '&')
c = COPROC;
@ -1363,7 +1371,7 @@ getsc_line(Source *s)
/* flush any unwanted input so other programs/builtins
* can read it. Not very optimal, but less error prone
* than flushing else where, dealing with redirections,
* etc..
* etc.
* todo: reduce size of shf buffer (~128?) if SSTDIN
*/
if (s->type == SSTDIN)

20
syn.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.45 2009/10/02 18:08:37 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.46 2009/10/04 12:45:23 tg Exp $");
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
@ -348,8 +348,8 @@ get_command(int cf)
Leave:
break;
Subshell:
case '(':
Subshell:
t = nested(TPAREN, '(', ')');
break;
@ -358,16 +358,26 @@ get_command(int cf)
break;
case MDPAREN: {
int lno;
static const char let_cmd[] = {
CHAR, 'l', CHAR, 'e',
CHAR, 't', EOS
};
/* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
t = newtp(TCOM);
t->lineno = source->line;
lno = source->line;
ACCEPT;
switch (token(LETEXPR)) {
case LWORD:
break;
case '(': /* ) */
goto Subshell;
default:
syntaxerr(NULL);
}
t = newtp(TCOM);
t->lineno = lno;
XPput(args, wdcopy(let_cmd, ATEMP));
musthave(LWORD,LETEXPR);
XPput(args, yylval.cp);
break;
}