From 52aeb9aaeb4799b760138a7c34b18ede4b47242a Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 18 May 2015 09:56:00 +0100 Subject: 35168: Improve parsing of case patterns. "|" is now found properly by looking for words that come from the lexical analyser, rather than hacking a pattern returned in one dollop. Update some completion functions that need extra quoting as a result. Add test for new parsing. Update version number to 5.0.8-dev-3 because of wordcode incompatibility. --- Src/lex.c | 2 ++ Src/loop.c | 88 +++++++++++++++++++++++++++++++++++------------------------- Src/parse.c | 89 ++++++++++++++++--------------------------------------------- Src/text.c | 28 +++++++++++++------ 4 files changed, 96 insertions(+), 111 deletions(-) (limited to 'Src') diff --git a/Src/lex.c b/Src/lex.c index 841fb0b86..87b0cd3af 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -761,6 +761,8 @@ gettok(void) lexstop = 0; return BAR; case LX1_INPAR: + if (incasepat == 2) + return INPAR; d = hgetc(); if (d == '(') { if (infor) { diff --git a/Src/loop.c b/Src/loop.c index d025fbb9f..e4e8e2df8 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -545,7 +545,7 @@ execcase(Estate state, int do_exec) Wordcode end, next; wordcode code = state->pc[-1]; char *word, *pat; - int npat, save; + int npat, save, nalts, ialt, patok; Patprog *spprog, pprog; end = state->pc + WC_CASE_SKIP(code); @@ -561,60 +561,74 @@ execcase(Estate state, int do_exec) if (wc_code(code) != WC_CASE) break; - pat = NULL; - pprog = NULL; save = 0; - npat = state->pc[1]; - spprog = state->prog->pats + npat; - next = state->pc + WC_CASE_SKIP(code); + nalts = *state->pc++; + ialt = patok = 0; if (isset(XTRACE)) { - char *opat; - - pat = dupstring(opat = ecrawstr(state->prog, state->pc, NULL)); - singsub(&pat); - save = (!(state->prog->flags & EF_HEAP) && - !strcmp(pat, opat) && *spprog != dummy_patprog2); - printprompt4(); fprintf(xtrerr, "case %s (", word); - quote_tokenized_output(pat, xtrerr); - fprintf(xtrerr, ")\n"); - fflush(xtrerr); } - state->pc += 2; - if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2) - pprog = *spprog; - - if (!pprog) { - if (!pat) { - char *opat; + while (!patok && nalts) { + npat = state->pc[1]; + spprog = state->prog->pats + npat; + pprog = NULL; + pat = NULL; + + if (isset(XTRACE)) { int htok = 0; - - pat = dupstring(opat = ecrawstr(state->prog, - state->pc - 2, &htok)); + pat = dupstring(ecrawstr(state->prog, state->pc, &htok)); if (htok) singsub(&pat); - save = (!(state->prog->flags & EF_HEAP) && - !strcmp(pat, opat) && *spprog != dummy_patprog2); + + if (ialt++) + fprintf(stderr, " | "); + quote_tokenized_output(pat, xtrerr); } - if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC), - NULL))) - zerr("bad pattern: %s", pat); - else if (save) - *spprog = pprog; + + if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2) + pprog = *spprog; + + if (!pprog) { + if (!pat) { + char *opat; + int htok = 0; + + pat = dupstring(opat = ecrawstr(state->prog, + state->pc, &htok)); + if (htok) + singsub(&pat); + save = (!(state->prog->flags & EF_HEAP) && + !strcmp(pat, opat) && *spprog != dummy_patprog2); + } + if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC), + NULL))) + zerr("bad pattern: %s", pat); + else if (save) + *spprog = pprog; + } + if (pprog && pattry(pprog, word)) + patok = 1; + state->pc += 2; + nalts--; + } + state->pc += 2 * nalts; + if (isset(XTRACE)) { + fprintf(xtrerr, ")\n"); + fflush(xtrerr); } - if (pprog && pattry(pprog, word)) { + if (patok) { execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && do_exec)); while (!retflag && wc_code(code) == WC_CASE && WC_CASE_TYPE(code) == WC_CASE_AND) { state->pc = next; - code = *state->pc; - state->pc += 3; - next = state->pc + WC_CASE_SKIP(code) - 2; + code = *state->pc++; + next = state->pc + WC_CASE_SKIP(code); + nalts = *state->pc++; + state->pc += 2 * nalts; execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && do_exec)); } diff --git a/Src/parse.c b/Src/parse.c index 985eb8e71..c938d2dce 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -349,9 +349,8 @@ ecadd(wordcode c) eclen += a; } ecbuf[ecused] = c; - ecused++; - return ecused - 1; + return ecused++; } /* Delete a wordcode. */ @@ -1128,7 +1127,7 @@ par_for(int *cmplx) static void par_case(int *cmplx) { - int oecused = ecused, brflag, p, pp, n = 1, type; + int oecused = ecused, brflag, p, pp, palts, type, nalts; int ona, onc; p = ecadd(0); @@ -1153,7 +1152,7 @@ par_case(int *cmplx) YYERRORV(oecused); } brflag = (tok == INBRACE); - incasepat = 1; + incasepat = 2; incmdpos = 0; noaliases = ona; nocorrect = onc; @@ -1166,8 +1165,10 @@ par_case(int *cmplx) zshlex(); if (tok == OUTBRACE) break; - if (tok == INPAR) + if (tok == INPAR) { + incasepat = 1; zshlex(); + } if (tok != STRING) YYERRORV(oecused); if (!strcmp(tokstr, "esac")) @@ -1176,89 +1177,45 @@ par_case(int *cmplx) incasepat = 0; incmdpos = 1; type = WC_CASE_OR; + pp = ecadd(0); + palts = ecadd(0); + nalts = 0; for (;;) { + ecstr(str); + ecadd(ecnpats++); + nalts++; + zshlex(); if (tok == OUTPAR) { incasepat = 0; incmdpos = 1; zshlex(); break; - } else if (tok == BAR) { - char *str2; - int sl = strlen(str); - - incasepat = 1; - incmdpos = 0; - str2 = hcalloc(sl + 2); - strcpy(str2, str); - str2[sl] = Bar; - str2[sl+1] = '\0'; - str = str2; - } else { - int sl = strlen(str); - - if (!sl || str[sl - 1] != Bar) { - /* POSIX allows (foo*) patterns */ - int pct; - char *s; - - for (s = str, pct = 0; *s; s++) { - if (*s == Inpar) - pct++; - if (!pct) - break; - if (pct == 1) { - if (*s == Bar || *s == Inpar) - while (iblank(s[1])) - chuck(s+1); - if (*s == Bar || *s == Outpar) - while (iblank(s[-1]) && - (s < str + 1 || s[-2] != Meta)) - chuck(--s); - } - if (*s == Outpar) - pct--; - } - if (*s || pct || s == str) - YYERRORV(oecused); - /* Simplify pattern by removing surrounding (...) */ - sl = strlen(str); - DPUTS(*str != Inpar || str[sl - 1] != Outpar, - "BUG: strange case pattern"); - str[sl - 1] = '\0'; - chuck(str); - break; - } else { - char *str2; - - if (tok != STRING) - YYERRORV(oecused); - str2 = hcalloc(sl + strlen(tokstr) + 1); - strcpy(str2, str); - strcpy(str2 + sl, tokstr); - str = str2; - } - } + } else if (tok != BAR) + YYERRORV(oecused); + + zshlex(); + if (tok != STRING) + YYERRORV(oecused); + str = dupstring(tokstr); } - pp = ecadd(0); - ecstr(str); - ecadd(ecnpats++); par_save_list(cmplx); - n++; if (tok == SEMIAMP) type = WC_CASE_AND; else if (tok == SEMIBAR) type = WC_CASE_TESTAND; ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp); + ecbuf[palts] = nalts; if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag)) break; if (tok != DSEMI && tok != SEMIAMP && tok != SEMIBAR) YYERRORV(oecused); - incasepat = 1; + incasepat = 2; incmdpos = 0; zshlex(); } incmdpos = 1; + incasepat = 0; zshlex(); ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p); diff --git a/Src/text.c b/Src/text.c index b58c2516d..958303c68 100644 --- a/Src/text.c +++ b/Src/text.c @@ -602,6 +602,7 @@ gettext2(Estate state) case WC_CASE: if (!s) { Wordcode end = state->pc + WC_CASE_SKIP(code); + wordcode nalts; taddstr("case "); taddstr(ecgetstr(state, EC_NODUP, NULL)); @@ -622,8 +623,13 @@ gettext2(Estate state) taddchr(' '); taddstr("("); code = *state->pc++; - taddstr(ecgetstr(state, EC_NODUP, NULL)); - state->pc++; + nalts = *state->pc++; + while (nalts--) { + taddstr(ecgetstr(state, EC_NODUP, NULL)); + state->pc++; + if (nalts) + taddstr(" | "); + } taddstr(") "); tindent++; n = tpush(code, 0); @@ -631,6 +637,7 @@ gettext2(Estate state) n->pop = (state->pc - 2 + WC_CASE_SKIP(code) >= end); } } else if (state->pc < s->u._case.end) { + wordcode nalts; dec_tindent(); switch (WC_CASE_TYPE(code)) { case WC_CASE_OR: @@ -638,11 +645,11 @@ gettext2(Estate state) break; case WC_CASE_AND: - taddstr(";&"); + taddstr(" ;&"); break; default: - taddstr(";|"); + taddstr(" ;|"); break; } if (tnewlins) @@ -651,8 +658,13 @@ gettext2(Estate state) taddchr(' '); taddstr("("); code = *state->pc++; - taddstr(ecgetstr(state, EC_NODUP, NULL)); - state->pc++; + nalts = *state->pc++; + while (nalts--) { + taddstr(ecgetstr(state, EC_NODUP, NULL)); + state->pc++; + if (nalts) + taddstr(" | "); + } taddstr(") "); tindent++; s->code = code; @@ -666,11 +678,11 @@ gettext2(Estate state) break; case WC_CASE_AND: - taddstr(";&"); + taddstr(" ;&"); break; default: - taddstr(";|"); + taddstr(" ;|"); break; } dec_tindent(); -- cgit 1.4.1