trc: clean up parser levels, disallow free carats on lists - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 601e07b63653d0fed91594ebba261b733d017653
 (DIR) parent ff74f7cdda7b08da6fe7c8bbcca990305fd6b547
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Tue,  5 May 2020 08:29:45 -0400
       
       rc: clean up parser levels, disallow free carats on lists
       
       Diffstat:
         M src/cmd/rc/checkparse               |      13 ++++++++++---
         M src/cmd/rc/lex.c                    |       2 +-
         M src/cmd/rc/parse.c                  |      45 +++++++++++++-------------------
         M src/cmd/rc/test.rc                  |       8 ++++++++
       
       4 files changed, 37 insertions(+), 31 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/rc/checkparse b/src/cmd/rc/checkparse
       t@@ -1,16 +1,23 @@
        #!/bin/bash
        
       +aflag=false
       +if [ "$1" = -a ]; then
       +        aflag=true
       +        shift
       +fi
       +
        files="$@"
        if [ $# = 0 ]; then
                files=$(echo ./test.rc;
                        grep -l '^#!/usr/local/plan9/bin/rc' /usr/local/plan9/bin/{*,*/*} 2>/dev/null;
       -                grep -l '^#!/bin/rc' $HOME/pub/plan9/rc/bin/{*,*/*} 2>/dev/null)
       +                grep -R -l '^#!/bin/rc' $HOME/pub/plan9 | egrep -v 'plan9/(lib/(oui|pci)|sys/man|sys/lib/man|sys/lib/scsicodes)' 2>/dev/null)
        fi
        
        for i in $files
        do
                if ! diff <(./o.rc -DY $i 2>&1) <(./o.rc -D $i 2>&1); then
       -                echo '#' $i
       -                exit 1
       +                echo '^^^' $i
       +                ! $aflag && exit 1
                fi
        done
       +
 (DIR) diff --git a/src/cmd/rc/lex.c b/src/cmd/rc/lex.c
       t@@ -206,7 +206,7 @@ yylex(void)
                        lastword = 0;
                        if(d=='('){
                                advance();
       -                        strcpy(tok, "( [SUB]");
       +                        strcpy(tok, "(");
                                return SUB;
                        }
                        if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
 (DIR) diff --git a/src/cmd/rc/parse.c b/src/cmd/rc/parse.c
       t@@ -7,7 +7,6 @@ static tree*        brace(int tok);
        static tree*        cmd(int tok, int *ptok);
        static tree*        cmd2(int tok, int *ptok);
        static tree*        cmd3(int tok, int *ptok);
       -static tree*        cmd4(int tok, int *ptok);
        static tree*        cmds(int tok, int *ptok, int nlok);
        static tree*        epilog(int tok, int *ptok);
        static int        iswordtok(int tok);
       t@@ -39,9 +38,8 @@ dropsp(int tok)
        static void
        syntax(int tok)
        {
       -        char buf[100];
       -        snprint(buf, sizeof buf, "syntax error %d", tok);
       -        yyerror(buf);
       +        USED(tok);
       +        yyerror("syntax error");
                longjmp(yyjmp, 1);
        }
        
       t@@ -197,27 +195,17 @@ yyredir(int tok, int *ptok)
        static tree*
        cmd(int tok, int *ptok)
        {
       -        tok = dropsp(tok);
       -        switch(tok) {
       -        default:
       -                return cmd2(tok, ptok);
       -
       -        }
       -}
       -
       -static tree*
       -cmd2(int tok, int *ptok)
       -{
                int op;
                tree *t1, *t2;
        
                // |        cmd ANDAND cmd                {$$=tree2(ANDAND, $1, $3);}
                // |        cmd OROR cmd                {$$=tree2(OROR, $1, $3);}
        
       -        t1 = cmd3(tok, &tok);
       +        tok = dropsp(tok);
       +        t1 = cmd2(tok, &tok);
                while(tok == ANDAND || tok == OROR) {
                        op = tok;
       -                t2 = cmd3(dropnl(yylex()), &tok);
       +                t2 = cmd2(dropnl(yylex()), &tok);
                        t1 = tree2(op, t1, t2);
                }
                *ptok = tok;
       t@@ -225,15 +213,15 @@ cmd2(int tok, int *ptok)
        }
        
        static tree*
       -cmd3(int tok, int *ptok)
       +cmd2(int tok, int *ptok)
        {
                tree *t1, *t2, *t3;
        
                // |        cmd PIPE cmd                {$$=mung2($2, $1, $3);}
       -        t1 = cmd4(tok, &tok);
       +        t1 = cmd3(tok, &tok);
                while(tok == PIPE) {
                        t2 = yylval.tree;
       -                t3 = cmd4(dropnl(yylex()), &tok);
       +                t3 = cmd3(dropnl(yylex()), &tok);
                        t1 = mung2(t2, t1, t3);
                }
                *ptok = tok;
       t@@ -241,7 +229,7 @@ cmd3(int tok, int *ptok)
        }
        
        static tree*
       -cmd4(int tok, int *ptok)
       +cmd3(int tok, int *ptok)
        {
                tree *t1, *t2, *t3, *t4;
        
       t@@ -336,16 +324,16 @@ cmd4(int tok, int *ptok)
                case SUBSHELL:
                        // |        BANG cmd                {$$=mung1($1, $2);}
                        // |        SUBSHELL cmd                {$$=mung1($1, $2);}
       -                // Note: cmd3: ! x | y is !{x | y} not {!x} | y.
       +                // Note: cmd2: ! x | y is !{x | y} not {!x} | y.
                        t1 = yylval.tree;
       -                return mung1(t1, cmd3(yylex(), ptok));
       +                return mung1(t1, cmd2(yylex(), ptok));
        
                case REDIR:
                case DUP:
                        // |        redir cmd  %prec BANG        {$$=mung2($1, $1->child[0], $2);}
       -                // Note: cmd3: {>x echo a | tr a-z A-Z} writes A to x.
       +                // Note: cmd2: {>x echo a | tr a-z A-Z} writes A to x.
                        t1 = yyredir(tok, &tok);
       -                t2 = cmd3(tok, ptok);
       +                t2 = cmd2(tok, ptok);
                        return mung2(t1, t1->child[0], t2);
        
                case '{':
       t@@ -372,9 +360,9 @@ cmd4(int tok, int *ptok)
                t1 = yyword(tok, &tok, 0);
                if(tok == '=') {
                        // assignment
       -                // Note: cmd3: {x=1 true | echo $x} echoes 1.
       +                // Note: cmd2: {x=1 true | echo $x} echoes 1.
                        t1 = tree2('=', t1, yyword(yylex(), &tok, 1));
       -                t2 = cmd3(tok, ptok);
       +                t2 = cmd2(tok, ptok);
                        return mung3(t1, t1->child[0], t1->child[1], t2);
                }
        
       t@@ -440,6 +428,9 @@ yyword(int tok, int *ptok, int eqok)
                        goto out;
                for(;;) {
                        if(iswordtok(tok)) {
       +                        // No free carats around parens.
       +                        if(t->type == PAREN || tok == '(')
       +                                syntax(tok);
                                t = tree2('^', t, word1(tok, &tok));
                                continue;
                        }
 (DIR) diff --git a/src/cmd/rc/test.rc b/src/cmd/rc/test.rc
       t@@ -83,3 +83,11 @@ x = y
        # x y=z
        # x =y
        # x -flag=y
       +
       +>z x | y
       +
       +# rejected now, was like parens were spaces before.
       +# echo Formatting Venti arenas and indices (this takes a while).
       +
       +
       +# echo $STATLINE(1)^$STATLINE(3)'        '$STATLINE(2)'        '$STATLINE(4)'        '$LSLINE(6)