URI: 
       trc: allow unquoted = in command arguments - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit ff74f7cdda7b08da6fe7c8bbcca990305fd6b547
   DIR parent 7d6a248f2c68d70f58387afc69e73e695c3d940c
  HTML Author: Russ Cox <rsc@swtch.com>
       Date:   Mon,  4 May 2020 23:31:59 -0400
       
       rc: allow unquoted = in command arguments
       
       dd fans rejoice!
       
       Also helps with commands like go test -run=x.
       
       Diffstat:
         M man/man1/rc.1                       |       2 +-
         M src/cmd/rc/parse.c                  |      28 ++++++++++++++++++----------
         M src/cmd/rc/test.rc                  |       9 +++++++++
       
       3 files changed, 28 insertions(+), 11 deletions(-)
       ---
   DIR diff --git a/man/man1/rc.1 b/man/man1/rc.1
       t@@ -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,
        newline, or any of the following:
        .EX
       -        # ; & | ^ $ = ` ' { } ( ) < >
       +        # ; & | ^ $ ` ' { } ( ) < >
        .EE
        An unquoted word that contains any of the characters
        .B *
   DIR diff --git a/src/cmd/rc/parse.c b/src/cmd/rc/parse.c
       t@@ -14,7 +14,7 @@ static int        iswordtok(int tok);
        static tree*        line(int tok, int *ptok);
        static tree*        paren(int tok);
        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*        words(int tok, int *ptok);
        
       t@@ -186,7 +186,7 @@ yyredir(int tok, int *ptok)
                        break;
                case REDIR:
                        r = yylval.tree;
       -                w = yyword(yylex(), &tok);
       +                w = yyword(yylex(), &tok, 1);
                        *ptok = dropsp(tok);
                        r = mung1(r, r->rtype==HERE?heredoc(w):w);
                        break;
       t@@ -276,7 +276,7 @@ cmd4(int tok, int *ptok)
                        tok = dropsp(yylex());
                        if(tok != '(')
                                syntax(tok);
       -                t2 = yyword(yylex(), &tok);
       +                t2 = yyword(yylex(), &tok, 1);
                        switch(tok) {
                        default:
                                syntax(tok);
       t@@ -305,7 +305,7 @@ cmd4(int tok, int *ptok)
                case SWITCH:
                        // |        SWITCH word {skipnl();} brace
                        //                {$$=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!
                        t2 = brace(tok);
                        *ptok = dropsp(yylex());
       t@@ -328,7 +328,7 @@ cmd4(int tok, int *ptok)
                case TWIDDLE:
                        // |        TWIDDLE word words        {$$=mung2($1, $2, $3);}
                        t1 = yylval.tree;
       -                t2 = yyword(yylex(), &tok);
       +                t2 = yyword(yylex(), &tok, 1);
                        t3 = words(tok, ptok);
                        return mung2(t1, t2, t3);
        
       t@@ -369,11 +369,11 @@ cmd4(int tok, int *ptok)
                // but all those keywords have been picked off in the switch above.
                // Except NOT, but disallowing that in yacc was likely a mistake anyway:
                // there's no ambiguity in not=1 or not x y z.
       -        t1 = yyword(tok, &tok);
       +        t1 = yyword(tok, &tok, 0);
                if(tok == '=') {
                        // assignment
                        // 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);
                        return mung3(t1, t1->child[0], t1->child[1], t2);
                }
       t@@ -385,7 +385,7 @@ cmd4(int tok, int *ptok)
                        if(tok == REDIR || tok == DUP) {
                                t1 = tree2(ARGLIST, t1, yyredir(tok, &tok));
                        } else if(iswordtok(tok)) {
       -                        t1 = tree2(ARGLIST, t1, yyword(tok, &tok));
       +                        t1 = tree2(ARGLIST, t1, yyword(tok, &tok, 1));
                        } else {
                                break;
                        }
       t@@ -405,13 +405,13 @@ words(int tok, int *ptok)
                t = nil;
                tok = dropsp(tok);
                while(iswordtok(tok))
       -                t = tree2(WORDS, t, yyword(tok, &tok));
       +                t = tree2(WORDS, t, yyword(tok, &tok, 1));
                *ptok = tok;
                return t;
        }
        
        static tree*
       -yyword(int tok, int *ptok)
       +yyword(int tok, int *ptok, int eqok)
        {
                tree *t;
        
       t@@ -436,6 +436,8 @@ yyword(int tok, int *ptok)
                // word1: keyword | comword
        
                t = word1(tok, &tok);
       +        if(tok == '=' && !eqok)
       +                goto out;
                for(;;) {
                        if(iswordtok(tok)) {
                                t = tree2('^', t, word1(tok, &tok));
       t@@ -448,6 +450,7 @@ yyword(int tok, int *ptok)
                        }
                        break;
                }
       +out:
                *ptok = dropsp(tok);
                return t;
        }
       t@@ -480,6 +483,10 @@ word1(int tok, int *ptok)
                        *ptok = yylex();
                        return t;
        
       +        case '=':
       +                *ptok = yylex();
       +                return token("=", WORD);
       +
                case '$':
                        // comword: '$' word1                {$$=tree1('$', $2);}
                        // |        '$' word1 SUB words ')'        {$$=tree2(SUB, $2, $4);}
       t@@ -547,6 +554,7 @@ iswordtok(int tok)
                case '`':
                case '(':
                case REDIRW:
       +        case '=':
                        return 1;
                }
                return 0;
   DIR diff --git a/src/cmd/rc/test.rc b/src/cmd/rc/test.rc
       t@@ -74,3 +74,12 @@ OPTIONS=$OPTIONS' /axescount '^`{echo $1 | sed s/-a//}^' def'
        
        # bug in old printfont script - expected more free carats
        # 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