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

20
syn.c
View File

@@ -22,7 +22,7 @@
#include "sh.h" #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 { struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */ int start_token; /* token than began nesting (eg, FOR) */
@@ -348,8 +348,8 @@ get_command(int cf)
Leave: Leave:
break; break;
Subshell:
case '(': case '(':
Subshell:
t = nested(TPAREN, '(', ')'); t = nested(TPAREN, '(', ')');
break; break;
@@ -358,16 +358,26 @@ get_command(int cf)
break; break;
case MDPAREN: { case MDPAREN: {
int lno;
static const char let_cmd[] = { static const char let_cmd[] = {
CHAR, 'l', CHAR, 'e', CHAR, 'l', CHAR, 'e',
CHAR, 't', EOS CHAR, 't', EOS
}; };
/* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */ /* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
t = newtp(TCOM); lno = source->line;
t->lineno = source->line;
ACCEPT; 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)); XPput(args, wdcopy(let_cmd, ATEMP));
musthave(LWORD,LETEXPR);
XPput(args, yylval.cp); XPput(args, yylval.cp);
break; break;
} }