rc: allow unquoted = in command arguments

dd fans rejoice!

Also helps with commands like go test -run=x.
This commit is contained in:
Russ Cox 2020-05-04 23:31:59 -04:00
parent 7d6a248f2c
commit ff74f7cdda
3 changed files with 28 additions and 11 deletions

View file

@ -109,7 +109,7 @@ The simplest kind of argument is the unquoted word:
a sequence of one or more characters none of which is a blank, tab, a sequence of one or more characters none of which is a blank, tab,
newline, or any of the following: newline, or any of the following:
.EX .EX
# ; & | ^ $ = ` ' { } ( ) < > # ; & | ^ $ ` ' { } ( ) < >
.EE .EE
An unquoted word that contains any of the characters An unquoted word that contains any of the characters
.B * .B *

View file

@ -14,7 +14,7 @@ static int iswordtok(int tok);
static tree* line(int tok, int *ptok); static tree* line(int tok, int *ptok);
static tree* paren(int tok); static tree* paren(int tok);
static tree* yyredir(int tok, int *ptok); static tree* yyredir(int tok, int *ptok);
static tree* yyword(int tok, int *ptok); static tree* yyword(int tok, int *ptok, int eqok);
static tree* word1(int tok, int *ptok); static tree* word1(int tok, int *ptok);
static tree* words(int tok, int *ptok); static tree* words(int tok, int *ptok);
@ -186,7 +186,7 @@ yyredir(int tok, int *ptok)
break; break;
case REDIR: case REDIR:
r = yylval.tree; r = yylval.tree;
w = yyword(yylex(), &tok); w = yyword(yylex(), &tok, 1);
*ptok = dropsp(tok); *ptok = dropsp(tok);
r = mung1(r, r->rtype==HERE?heredoc(w):w); r = mung1(r, r->rtype==HERE?heredoc(w):w);
break; break;
@ -276,7 +276,7 @@ cmd4(int tok, int *ptok)
tok = dropsp(yylex()); tok = dropsp(yylex());
if(tok != '(') if(tok != '(')
syntax(tok); syntax(tok);
t2 = yyword(yylex(), &tok); t2 = yyword(yylex(), &tok, 1);
switch(tok) { switch(tok) {
default: default:
syntax(tok); syntax(tok);
@ -305,7 +305,7 @@ cmd4(int tok, int *ptok)
case SWITCH: case SWITCH:
// | SWITCH word {skipnl();} brace // | SWITCH word {skipnl();} brace
// {$$=tree2(SWITCH, $2, $4);} // {$$=tree2(SWITCH, $2, $4);}
t1 = yyword(yylex(), &tok); t1 = yyword(yylex(), &tok, 1);
tok = dropnl(tok); // doesn't work in yacc grammar but works here! tok = dropnl(tok); // doesn't work in yacc grammar but works here!
t2 = brace(tok); t2 = brace(tok);
*ptok = dropsp(yylex()); *ptok = dropsp(yylex());
@ -328,7 +328,7 @@ cmd4(int tok, int *ptok)
case TWIDDLE: case TWIDDLE:
// | TWIDDLE word words {$$=mung2($1, $2, $3);} // | TWIDDLE word words {$$=mung2($1, $2, $3);}
t1 = yylval.tree; t1 = yylval.tree;
t2 = yyword(yylex(), &tok); t2 = yyword(yylex(), &tok, 1);
t3 = words(tok, ptok); t3 = words(tok, ptok);
return mung2(t1, t2, t3); return mung2(t1, t2, t3);
@ -369,11 +369,11 @@ cmd4(int tok, int *ptok)
// but all those keywords have been picked off in the switch above. // but all those keywords have been picked off in the switch above.
// Except NOT, but disallowing that in yacc was likely a mistake anyway: // Except NOT, but disallowing that in yacc was likely a mistake anyway:
// there's no ambiguity in not=1 or not x y z. // there's no ambiguity in not=1 or not x y z.
t1 = yyword(tok, &tok); t1 = yyword(tok, &tok, 0);
if(tok == '=') { if(tok == '=') {
// assignment // assignment
// Note: cmd3: {x=1 true | echo $x} echoes 1. // Note: cmd3: {x=1 true | echo $x} echoes 1.
t1 = tree2('=', t1, yyword(yylex(), &tok)); t1 = tree2('=', t1, yyword(yylex(), &tok, 1));
t2 = cmd3(tok, ptok); t2 = cmd3(tok, ptok);
return mung3(t1, t1->child[0], t1->child[1], t2); return mung3(t1, t1->child[0], t1->child[1], t2);
} }
@ -385,7 +385,7 @@ cmd4(int tok, int *ptok)
if(tok == REDIR || tok == DUP) { if(tok == REDIR || tok == DUP) {
t1 = tree2(ARGLIST, t1, yyredir(tok, &tok)); t1 = tree2(ARGLIST, t1, yyredir(tok, &tok));
} else if(iswordtok(tok)) { } else if(iswordtok(tok)) {
t1 = tree2(ARGLIST, t1, yyword(tok, &tok)); t1 = tree2(ARGLIST, t1, yyword(tok, &tok, 1));
} else { } else {
break; break;
} }
@ -405,13 +405,13 @@ words(int tok, int *ptok)
t = nil; t = nil;
tok = dropsp(tok); tok = dropsp(tok);
while(iswordtok(tok)) while(iswordtok(tok))
t = tree2(WORDS, t, yyword(tok, &tok)); t = tree2(WORDS, t, yyword(tok, &tok, 1));
*ptok = tok; *ptok = tok;
return t; return t;
} }
static tree* static tree*
yyword(int tok, int *ptok) yyword(int tok, int *ptok, int eqok)
{ {
tree *t; tree *t;
@ -436,6 +436,8 @@ yyword(int tok, int *ptok)
// word1: keyword | comword // word1: keyword | comword
t = word1(tok, &tok); t = word1(tok, &tok);
if(tok == '=' && !eqok)
goto out;
for(;;) { for(;;) {
if(iswordtok(tok)) { if(iswordtok(tok)) {
t = tree2('^', t, word1(tok, &tok)); t = tree2('^', t, word1(tok, &tok));
@ -448,6 +450,7 @@ yyword(int tok, int *ptok)
} }
break; break;
} }
out:
*ptok = dropsp(tok); *ptok = dropsp(tok);
return t; return t;
} }
@ -480,6 +483,10 @@ word1(int tok, int *ptok)
*ptok = yylex(); *ptok = yylex();
return t; return t;
case '=':
*ptok = yylex();
return token("=", WORD);
case '$': case '$':
// comword: '$' word1 {$$=tree1('$', $2);} // comword: '$' word1 {$$=tree1('$', $2);}
// | '$' word1 SUB words ')' {$$=tree2(SUB, $2, $4);} // | '$' word1 SUB words ')' {$$=tree2(SUB, $2, $4);}
@ -547,6 +554,7 @@ iswordtok(int tok)
case '`': case '`':
case '(': case '(':
case REDIRW: case REDIRW:
case '=':
return 1; return 1;
} }
return 0; return 0;

View file

@ -74,3 +74,12 @@ OPTIONS=$OPTIONS' /axescount '^`{echo $1 | sed s/-a//}^' def'
# bug in old printfont script - expected more free carats # bug in old printfont script - expected more free carats
# OPTIONS=$OPTIONS' /axescount '`{echo $1 | sed s/-a//}' def' # OPTIONS=$OPTIONS' /axescount '`{echo $1 | sed s/-a//}' def'
(x) = y
x=y
x = y
# works now!
# x y=z
# x =y
# x -flag=y