URI: 
       trc: move newline handling into parser - 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 3caf5c238a886d06b438ec6d42f2609b8625463f
   DIR parent 47d4646eebac34c0b94951cfcf1b81ed2ca513e1
  HTML Author: Russ Cox <rsc@swtch.com>
       Date:   Mon,  4 May 2020 22:52:27 -0400
       
       rc: move newline handling into parser
       
       Diffstat:
         M src/cmd/rc/checkparse               |       6 ++++--
         M src/cmd/rc/lex.c                    |      24 ++++++++++++++++--------
         M src/cmd/rc/parse.c                  |      27 +++++++++++++++------------
         M src/cmd/rc/pcmd.c                   |       5 ++++-
         M src/cmd/rc/syn.y                    |       2 +-
         M src/cmd/rc/test.rc                  |      27 +++++++++++++++++++++++++++
       
       6 files changed, 67 insertions(+), 24 deletions(-)
       ---
   DIR diff --git a/src/cmd/rc/checkparse b/src/cmd/rc/checkparse
       t@@ -9,6 +9,8 @@ fi
        
        for i in $files
        do
       -        echo '#' $i
       -        diff <(./o.rc -DY $i 2>&1) <(./o.rc -D $i 2>&1)
       +        if ! diff <(./o.rc -DY $i 2>&1) <(./o.rc -D $i 2>&1); then
       +                echo '#' $i
       +                exit 1
       +        fi
        done
   DIR diff --git a/src/cmd/rc/lex.c b/src/cmd/rc/lex.c
       t@@ -102,15 +102,17 @@ pprompt(void)
                doprompt = 0;
        }
        
       -void
       +int
        skipwhite(void)
        {
       -        int c;
       +        int c, skipped;
       +        skipped = 0;
                for(;;){
                        c = nextc();
                        /* Why did this used to be  if(!inquote && c=='#') ?? */
                        if(c=='#'){
                                incomm = 1;
       +                        skipped = 1;
                                for(;;){
                                        c = nextc();
                                        if(c=='\n' || c==EOF) {
       t@@ -120,9 +122,12 @@ skipwhite(void)
                                        advance();
                                }
                        }
       -                if(c==' ' || c=='\t')
       +                if(c==' ' || c=='\t') {
       +                        skipped = 1;
                                advance();
       -                else return;
       +                }
       +                else
       +                        return skipped;
                }
        }
        
       t@@ -210,7 +215,8 @@ yylex(void)
                        }
                }
                inquote = 0;
       -        skipwhite();
       +        if(skipwhite() && flag['Z'])
       +                return SP;
                switch(c = advance()){
                case EOF:
                        lastdol = 0;
       t@@ -231,7 +237,8 @@ yylex(void)
                case '&':
                        lastdol = 0;
                        if(nextis('&')){
       -                        skipnl();
       +                        if(flag['Y'])
       +                                skipnl();
                                strcpy(tok, "&&");
                                return ANDAND;
                        }
       t@@ -240,7 +247,8 @@ yylex(void)
                case '|':
                        lastdol = 0;
                        if(nextis(c)){
       -                        skipnl();
       +                        if(flag['Y'])
       +                                skipnl();
                                strcpy(tok, "||");
                                return OROR;
                        }
       t@@ -329,7 +337,7 @@ yylex(void)
                        }
                        *w='\0';
                        yylval.tree = t;
       -                if(t->type==PIPE)
       +                if(t->type==PIPE && flag['Y'])
                                skipnl();
                        if(t->type==REDIR) {
                                skipwhite();
   DIR diff --git a/src/cmd/rc/parse.c b/src/cmd/rc/parse.c
       t@@ -20,6 +20,14 @@ static tree*        words(int tok, int *ptok);
        
        static jmp_buf yyjmp;
        
       +static int
       +dropnl(int tok)
       +{
       +        while(tok == '\n')
       +                tok = yylex();
       +        return tok;
       +}
       +
        static void
        syntax(int tok)
        {
       t@@ -191,13 +199,11 @@ cmd(int tok, int *ptok)
                        tok = yylex();
                        if(tok == NOT) {
                                t1 = yylval.tree;
       -                        skipnl();
       -                        t2 = cmd(yylex(), ptok);
       +                        t2 = cmd(dropnl(yylex()), ptok);
                                return mung1(t1, t2);
                        }
                        t2 = paren(tok);
       -                skipnl();
       -                t3 = cmd(yylex(), ptok);
       +                t3 = cmd(dropnl(yylex()), ptok);
                        return mung2(t1, t2, t3);
        
                case FOR:
       t@@ -224,8 +230,7 @@ cmd(int tok, int *ptok)
                                        syntax(tok);
                                break;
                        }
       -                skipnl();
       -                t4 = cmd(yylex(), ptok);
       +                t4 = cmd(dropnl(yylex()), ptok);
                        return mung3(t1, t2, t3, t4);
        
                case WHILE:
       t@@ -233,16 +238,14 @@ cmd(int tok, int *ptok)
                        //                {$$=mung2($1, $2, $4);}
                        t1 = yylval.tree;
                        t2 = paren(yylex());
       -                skipnl();
       -                t3 = cmd(yylex(), ptok);
       +                t3 = cmd(dropnl(yylex()), ptok);
                        return mung2(t1, t2, t3);
        
                case SWITCH:
                        // |        SWITCH word {skipnl();} brace
                        //                {$$=tree2(SWITCH, $2, $4);}
                        t1 = yyword(yylex(), &tok);
       -                while(tok == '\n')
       -                        tok = yylex();
       +                tok = dropnl(tok); // doesn't work in yacc grammar but works here!
                        t2 = brace(tok);
                        *ptok = yylex();
                        return tree2(SWITCH, t1, t2);
       t@@ -261,7 +264,7 @@ cmd2(int tok, int *ptok)
                t1 = cmd3(tok, &tok);
                while(tok == ANDAND || tok == OROR) {
                        op = tok;
       -                t2 = cmd3(yylex(), &tok);
       +                t2 = cmd3(dropnl(yylex()), &tok);
                        t1 = tree2(op, t1, t2);
                }
                *ptok = tok;
       t@@ -277,7 +280,7 @@ cmd3(int tok, int *ptok)
                t1 = cmd4(tok, &tok);
                while(tok == PIPE) {
                        t2 = yylval.tree;
       -                t3 = cmd4(yylex(), &tok);
       +                t3 = cmd4(dropnl(yylex()), &tok);
                        t1 = mung2(t2, t1, t3);
                }
                *ptok = tok;
   DIR diff --git a/src/cmd/rc/pcmd.c b/src/cmd/rc/pcmd.c
       t@@ -244,7 +244,10 @@ pcmdu(io *f, tree *t) /* unambiguous */
                                        pfmt(f, "[%d]", t->fd0);
                                break;
                        }
       -                pfmt(f, "%u %u)", c0, c1);
       +                if(t->rtype == HERE)
       +                        pfmt(f, "HERE %u)", c1);
       +                else
       +                        pfmt(f, "%u %u)", c0, c1);
                        break;
                case '=':
                        pfmt(f, "(%u=%u %u)", c0, c1, c2);
   DIR diff --git a/src/cmd/rc/syn.y b/src/cmd/rc/syn.y
       t@@ -1,4 +1,4 @@
       -%term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN
       +%term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN SP
        %term WORD REDIR REDIRW DUP PIPE SUB
        %term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */
        /* operator priorities -- lowest first */
   DIR diff --git a/src/cmd/rc/test.rc b/src/cmd/rc/test.rc
       t@@ -36,3 +36,30 @@ $#$x
        x for in while if not ~ ! @ switch fn
        x not$y
        a;b;c
       +if(x)
       +y
       +if(x)
       +{
       +y
       +}
       +if not
       +z
       +for(x)
       +y
       +for(x in y)
       +z
       +while(x)
       +y
       +# yacc doesn't accept a newline before the brace
       +# even though the rule is written as if it would
       +switch x {
       +}
       +switch (x) {
       +}
       +z
       +x &&
       +y
       +x ||
       +y
       +x |
       +y