trc: move newline handling into parser - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
commit 3caf5c238a886d06b438ec6d42f2609b8625463f
parent 47d4646eebac34c0b94951cfcf1b81ed2ca513e1
Author: Russ Cox 
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(-)
---
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
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();
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;
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);
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 */
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