aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-21 11:43:13 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-21 11:43:13 -0700
commitfaaf40e55e002212c0c28f7845dfa2322eb7ad05 (patch)
tree9c61e6125d054439019c3c037e46353597018870
parent5c20d687c495f2cb3f3a390d04854dcceb2ef74e (diff)
feat(rc): string concatenation works
-rw-r--r--sys/cmd/rc/code.c2
-rw-r--r--sys/cmd/rc/exec.c49
-rw-r--r--sys/cmd/rc/exec.h1
-rw-r--r--sys/cmd/rc/lex.c4
-rw-r--r--sys/cmd/rc/parse.c218
-rw-r--r--sys/cmd/rc/parse.h2
-rw-r--r--sys/cmd/rc/syntax.y1
7 files changed, 162 insertions, 115 deletions
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
index c5b1987..70fe818 100644
--- a/sys/cmd/rc/code.c
+++ b/sys/cmd/rc/code.c
@@ -77,7 +77,6 @@ walk(Tree *node)
walk(node->child[1]);
break;
-#if 0
case '^':
emitf(Xmark);
walk(node->child[1]);
@@ -85,7 +84,6 @@ walk(Tree *node)
walk(node->child[0]);
emitf(Xconcatenate);
break;
-#endif
case Targs:
walk(node->child[1]);
diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c
index 6d0c0a9..ac0dc08 100644
--- a/sys/cmd/rc/exec.c
+++ b/sys/cmd/rc/exec.c
@@ -578,6 +578,52 @@ Xword(void)
pushword(runner->code.exe[runner->code.i++].s);
}
+static
+Word*
+catlist(Word *l, Word *r, Word *tail)
+{
+ Word *w;
+ char *buf;
+
+ if(l->link || r->link)
+ tail = catlist( (!l->link)?l:l->link, (!r->link)?r:r->link, tail);
+
+ buf = emalloc(strlen(l->str)+strlen(r->str)+1);
+ strcpy(buf, l->str);
+ strcat(buf, r->str);
+
+ w = makeword(buf, tail);
+ efree(buf);
+
+ return w;
+}
+
+void
+Xconcatenate(void)
+{
+ int rn, ln;
+ Word *l = runner->args->word;
+ Word *r = runner->args->link->word;
+ Word *w = runner->args->link->link->word;
+
+ ln = count(l), rn = count(r);
+ if(ln != 0 || rn != 0) {
+ if(ln == 0 || rn == 0){
+ Xerror("null list in concatenation\n");
+ return;
+ }
+ if(ln != 1 && rn != 1 && ln != rn) {
+ Xerror("mismatched list lengths in concatenation\n");
+ return;
+ }
+ w = catlist(l, r, w);
+ }
+
+ poplist();
+ poplist();
+ runner->args->word = w;
+}
+
void
Xdollar(void)
{
@@ -638,7 +684,6 @@ Xassign(void)
poplist();
}
-
void
Xreadcmd(void)
{
@@ -982,8 +1027,6 @@ Xreturn(void)
exit(0);
}
-
-
void
Xexit(void)
{
diff --git a/sys/cmd/rc/exec.h b/sys/cmd/rc/exec.h
index f85c699..d018fed 100644
--- a/sys/cmd/rc/exec.h
+++ b/sys/cmd/rc/exec.h
@@ -20,6 +20,7 @@ void Xasync(void);
void Xbasic(void); // Xbasic(args) run command and wait for result
void Xsubshell(void);
void Xword(void);
+void Xconcatenate(void);
void Xcount(void);
void Xflat(void);
void Xpipe(void);
diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c
index 31c7cdc..8ddf270 100644
--- a/sys/cmd/rc/lex.c
+++ b/sys/cmd/rc/lex.c
@@ -33,6 +33,9 @@ yyerror(const char *msg)
print(shell.err, "%s\n", msg);
flush(shell.err);
+ lexer.hadword = 0;
+ lexer.haddollar = 0;
+
/* consume remaining tokens */
while(lexer.c[0] !='\n' && lexer.c[0] != EOF)
advance();
@@ -193,6 +196,7 @@ yylex(void)
/* inject tokens */
if(lexer.hadword){
+ lexer.hadword = 0;
if(d=='('){
advance();
strcpy(lexer.buf, "( [Tindex]");
diff --git a/sys/cmd/rc/parse.c b/sys/cmd/rc/parse.c
index edc1006..731c244 100644
--- a/sys/cmd/rc/parse.c
+++ b/sys/cmd/rc/parse.c
@@ -124,17 +124,17 @@ enum yysymbol_kind_t
YYSYMBOL_Tindex = 19, /* Tindex */
YYSYMBOL_Twhile = 20, /* Twhile */
YYSYMBOL_21_n_ = 21, /* '\n' */
- YYSYMBOL_22_ = 22, /* '$' */
- YYSYMBOL_Tcount = 23, /* Tcount */
- YYSYMBOL_Tflat = 24, /* Tflat */
- YYSYMBOL_25_ = 25, /* '(' */
- YYSYMBOL_26_ = 26, /* ')' */
- YYSYMBOL_27_ = 27, /* '{' */
- YYSYMBOL_28_ = 28, /* '}' */
- YYSYMBOL_29_ = 29, /* ';' */
- YYSYMBOL_30_ = 30, /* '&' */
- YYSYMBOL_31_ = 31, /* '=' */
- YYSYMBOL_32_ = 32, /* '^' */
+ YYSYMBOL_22_ = 22, /* '^' */
+ YYSYMBOL_23_ = 23, /* '$' */
+ YYSYMBOL_Tcount = 24, /* Tcount */
+ YYSYMBOL_Tflat = 25, /* Tflat */
+ YYSYMBOL_26_ = 26, /* '(' */
+ YYSYMBOL_27_ = 27, /* ')' */
+ YYSYMBOL_28_ = 28, /* '{' */
+ YYSYMBOL_29_ = 29, /* '}' */
+ YYSYMBOL_30_ = 30, /* ';' */
+ YYSYMBOL_31_ = 31, /* '&' */
+ YYSYMBOL_32_ = 32, /* '=' */
YYSYMBOL_YYACCEPT = 33, /* $accept */
YYSYMBOL_rc = 34, /* rc */
YYSYMBOL_line = 35, /* line */
@@ -483,7 +483,7 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 42
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 158
+#define YYLAST 155
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 33
@@ -512,16 +512,16 @@ static const yytype_int8 yytranslate[] =
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
21, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 22, 2, 30, 2,
- 25, 26, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 29,
- 2, 31, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 23, 2, 31, 2,
+ 26, 27, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 30,
+ 2, 32, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 32, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 22, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 27, 2, 28, 2, 2, 2, 2,
+ 2, 2, 2, 28, 2, 29, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -536,19 +536,19 @@ static const yytype_int8 yytranslate[] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 23, 24
+ 15, 16, 17, 18, 19, 20, 24, 25
};
#if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
-static const yytype_int8 yyrline[] =
+static const yytype_uint8 yyrline[] =
{
- 0, 37, 37, 38, 41, 42, 45, 46, 49, 52,
- 55, 56, 59, 60, 63, 64, 67, 70, 71, 74,
- 75, 78, 79, 80, 81, 82, 83, 84, 85, 86,
- 89, 90, 91, 94, 95, 98, 99, 102, 103, 106,
- 107, 108, 109, 110, 114, 114, 114, 114, 121, 122,
- 123, 125, 127
+ 0, 38, 38, 39, 42, 43, 46, 47, 50, 53,
+ 56, 57, 60, 61, 64, 65, 68, 71, 72, 75,
+ 76, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 90, 91, 92, 95, 96, 99, 100, 103, 104, 107,
+ 108, 109, 110, 111, 115, 115, 115, 115, 122, 123,
+ 124, 126, 128
};
#endif
@@ -567,8 +567,8 @@ static const char *const yytname[] =
"\"end of file\"", "error", "\"invalid token\"", "Tword", "Twords",
"Tif", "Telse", "Tbang", "Tsubshell", "Toror", "Tandand", "There",
"Tredir", "Tpipe", "Tdup", "Tbasic", "Tparen", "Tblock", "Targs",
- "Tindex", "Twhile", "'\\n'", "'$'", "Tcount", "Tflat", "'('", "')'",
- "'{'", "'}'", "';'", "'&'", "'='", "'^'", "$accept", "rc", "line",
+ "Tindex", "Twhile", "'\\n'", "'^'", "'$'", "Tcount", "Tflat", "'('",
+ "')'", "'{'", "'}'", "';'", "'&'", "'='", "$accept", "rc", "line",
"body", "paren", "block", "cmds", "cmdsln", "ifbody", "assign", "redir",
"epilog", "cmd", "basic", "atom", "word", "executable", "nonkeyword",
"keyword", "wordsnl", "nl", YY_NULLPTR
@@ -595,14 +595,14 @@ yysymbol_name (yysymbol_kind_t yysymbol)
STATE-NUM. */
static const yytype_int16 yypact[] =
{
- 22, -42, -23, 89, 89, 133, -42, 133, 133, 133,
- -42, 89, 18, 7, -5, 89, 89, 89, 24, 123,
- 20, -42, 89, -42, 25, 25, -42, -42, -42, -42,
- -42, 23, -42, -42, -42, -42, -42, 99, 15, -42,
- 89, 35, -42, -42, -5, -42, -42, 25, 25, -42,
- -42, -42, -42, 23, 133, 133, 36, 66, 133, -42,
- -42, 23, -42, -42, -42, -42, 66, 23, -42, -42,
- -42, 27, -42, 25, -42, -42, -42, 66, 25
+ 22, -42, -24, 75, 75, 129, -42, 129, 129, 129,
+ -42, 75, 26, -10, -5, 75, 75, 75, 8, 105,
+ 32, -42, 75, -42, 19, 19, -42, -42, -42, -42,
+ -42, 18, -42, -42, -42, -42, -42, 99, 4, -42,
+ 75, 31, -42, -42, -5, -42, -42, 19, 19, -42,
+ -42, -42, -42, 18, 129, 129, 24, 67, 129, -42,
+ -42, 18, -42, -42, -42, -42, 67, -42, 18, -42,
+ -42, 127, -42, 19, -42, -42, -42, 67, 19
};
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -616,15 +616,15 @@ static const yytype_int8 yydefact[] =
35, 18, 33, 34, 40, 42, 43, 0, 0, 12,
21, 6, 1, 3, 19, 23, 5, 26, 25, 51,
10, 11, 32, 31, 0, 0, 0, 21, 0, 49,
- 41, 50, 9, 7, 13, 20, 21, 16, 38, 8,
+ 41, 50, 9, 7, 13, 20, 21, 38, 16, 8,
52, 19, 27, 14, 36, 24, 51, 21, 15
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int8 yypgoto[] =
{
- -42, -42, 46, 10, -42, 19, 11, -42, -42, -42,
- -13, 28, 0, -42, 12, -14, -42, 5, -42, -42,
+ -42, -42, 34, 15, -42, -4, 28, -42, -42, -42,
+ -13, 12, 0, -42, 11, -14, -42, 5, -42, -42,
-41
};
@@ -642,54 +642,54 @@ static const yytype_int8 yydefgoto[] =
static const yytype_int8 yytable[] =
{
18, 44, 22, 24, 25, 53, 52, 5, 66, 6,
- 32, 15, 32, 32, 32, 18, 47, 48, 42, 34,
- 35, 36, -2, 61, 32, 1, 15, 2, 43, 3,
- 4, 44, 56, 76, 5, 77, 6, 49, 49, 5,
- 67, 6, 32, 62, 7, 8, 9, 10, 49, 11,
- 63, 54, 55, 50, 51, 58, 64, 73, 44, 32,
- 32, 46, 69, 32, 50, 51, 75, 68, 0, 1,
- 74, 2, 65, 3, 4, 0, 71, 78, 5, 0,
- 6, 0, 0, 0, 0, 0, 0, 70, 7, 8,
- 9, 10, 1, 11, 2, 0, 3, 4, 0, 0,
- 0, 5, 1, 6, 26, 27, 28, 29, 0, 0,
- 0, 7, 8, 9, 10, 0, 11, 0, 0, 0,
- 59, 7, 8, 9, 10, 60, 1, 0, 26, 27,
- 28, 29, 0, 0, 0, 5, 1, 6, 26, 27,
- 28, 29, 0, 0, 0, 7, 8, 9, 10, 0,
- 0, 0, 0, 0, 0, 7, 8, 9, 10
+ 32, 43, 32, 32, 32, 18, 47, 48, 34, 35,
+ 36, 49, -2, 61, 32, 1, 42, 2, 15, 3,
+ 4, 44, 49, 62, 5, 77, 6, 56, 50, 51,
+ 58, 68, 32, 15, 49, 7, 8, 9, 10, 46,
+ 11, 69, 64, 71, 54, 63, 65, 73, 44, 32,
+ 32, 50, 51, 32, 55, 67, 75, 0, 0, 74,
+ 1, 0, 2, 0, 3, 4, 0, 78, 1, 5,
+ 2, 6, 3, 4, 0, 0, 0, 5, 70, 6,
+ 7, 8, 9, 10, 0, 11, 0, 0, 7, 8,
+ 9, 10, 1, 11, 26, 27, 28, 29, 1, 0,
+ 26, 27, 28, 29, 0, 0, 0, 5, 0, 6,
+ 59, 0, 7, 8, 9, 10, 60, 0, 7, 8,
+ 9, 10, 1, 76, 26, 27, 28, 29, 0, 5,
+ 0, 6, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 7, 8, 9, 10
};
static const yytype_int8 yycheck[] =
{
- 0, 14, 25, 3, 4, 19, 19, 12, 49, 14,
- 5, 0, 7, 8, 9, 15, 16, 17, 0, 7,
- 8, 9, 0, 37, 19, 3, 15, 5, 21, 7,
- 8, 44, 22, 6, 12, 76, 14, 13, 13, 12,
- 54, 14, 37, 28, 22, 23, 24, 25, 13, 27,
- 40, 31, 32, 29, 30, 32, 21, 57, 71, 54,
- 55, 15, 26, 58, 29, 30, 66, 55, -1, 3,
- 58, 5, 44, 7, 8, -1, 57, 77, 12, -1,
- 14, -1, -1, -1, -1, -1, -1, 21, 22, 23,
- 24, 25, 3, 27, 5, -1, 7, 8, -1, -1,
- -1, 12, 3, 14, 5, 6, 7, 8, -1, -1,
- -1, 22, 23, 24, 25, -1, 27, -1, -1, -1,
- 21, 22, 23, 24, 25, 26, 3, -1, 5, 6,
- 7, 8, -1, -1, -1, 12, 3, 14, 5, 6,
- 7, 8, -1, -1, -1, 22, 23, 24, 25, -1,
- -1, -1, -1, -1, -1, 22, 23, 24, 25
+ 0, 14, 26, 3, 4, 19, 19, 12, 49, 14,
+ 5, 21, 7, 8, 9, 15, 16, 17, 7, 8,
+ 9, 13, 0, 37, 19, 3, 0, 5, 0, 7,
+ 8, 44, 13, 29, 12, 76, 14, 22, 30, 31,
+ 22, 55, 37, 15, 13, 23, 24, 25, 26, 15,
+ 28, 27, 21, 57, 22, 40, 44, 57, 71, 54,
+ 55, 30, 31, 58, 32, 54, 66, -1, -1, 58,
+ 3, -1, 5, -1, 7, 8, -1, 77, 3, 12,
+ 5, 14, 7, 8, -1, -1, -1, 12, 21, 14,
+ 23, 24, 25, 26, -1, 28, -1, -1, 23, 24,
+ 25, 26, 3, 28, 5, 6, 7, 8, 3, -1,
+ 5, 6, 7, 8, -1, -1, -1, 12, -1, 14,
+ 21, -1, 23, 24, 25, 26, 27, -1, 23, 24,
+ 25, 26, 3, 6, 5, 6, 7, 8, -1, 12,
+ -1, 14, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 23, 24, 25, 26
};
/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
state STATE-NUM. */
static const yytype_int8 yystos[] =
{
- 0, 3, 5, 7, 8, 12, 14, 22, 23, 24,
- 25, 27, 34, 35, 38, 39, 42, 43, 45, 46,
- 49, 50, 25, 37, 45, 45, 5, 6, 7, 8,
+ 0, 3, 5, 7, 8, 12, 14, 23, 24, 25,
+ 26, 28, 34, 35, 38, 39, 42, 43, 45, 46,
+ 49, 50, 26, 37, 45, 45, 5, 6, 7, 8,
47, 48, 50, 51, 47, 47, 47, 52, 36, 39,
40, 45, 0, 21, 43, 44, 35, 45, 45, 13,
- 29, 30, 43, 48, 31, 32, 36, 53, 32, 21,
- 26, 48, 28, 36, 21, 44, 53, 48, 47, 26,
+ 30, 31, 43, 48, 22, 32, 36, 53, 22, 21,
+ 27, 48, 29, 36, 21, 44, 53, 47, 48, 27,
21, 38, 41, 45, 47, 45, 6, 53, 45
};
@@ -1446,199 +1446,199 @@ yyreduce:
switch (yyn)
{
case 2: /* rc: %empty */
-#line 37 "sys/cmd/rc/syntax.y"
+#line 38 "sys/cmd/rc/syntax.y"
{ return 0; }
#line 1452 "sys/cmd/rc/parse.c"
break;
case 3: /* rc: line '\n' */
-#line 38 "sys/cmd/rc/syntax.y"
+#line 39 "sys/cmd/rc/syntax.y"
{ return compile((yyvsp[-1].tree)); }
#line 1458 "sys/cmd/rc/parse.c"
break;
case 5: /* line: cmds line */
-#line 42 "sys/cmd/rc/syntax.y"
+#line 43 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); }
#line 1464 "sys/cmd/rc/parse.c"
break;
case 7: /* body: cmdsln body */
-#line 46 "sys/cmd/rc/syntax.y"
+#line 47 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); }
#line 1470 "sys/cmd/rc/parse.c"
break;
case 8: /* paren: '(' body ')' */
-#line 49 "sys/cmd/rc/syntax.y"
+#line 50 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tparen, (yyvsp[-1].tree)); }
#line 1476 "sys/cmd/rc/parse.c"
break;
case 9: /* block: '{' body '}' */
-#line 52 "sys/cmd/rc/syntax.y"
+#line 53 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tblock, (yyvsp[-1].tree)); }
#line 1482 "sys/cmd/rc/parse.c"
break;
case 11: /* cmds: cmd '&' */
-#line 56 "sys/cmd/rc/syntax.y"
+#line 57 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1('&', (yyvsp[-1].tree)); }
#line 1488 "sys/cmd/rc/parse.c"
break;
case 14: /* ifbody: cmd */
-#line 63 "sys/cmd/rc/syntax.y"
+#line 64 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(Tif, nil, (yyvsp[0].tree)); }
#line 1494 "sys/cmd/rc/parse.c"
break;
case 15: /* ifbody: block Telse nl cmd */
-#line 64 "sys/cmd/rc/syntax.y"
+#line 65 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree3(Tif, nil, (yyvsp[-3].tree), (yyvsp[-2].tree)); }
#line 1500 "sys/cmd/rc/parse.c"
break;
case 16: /* assign: executable '=' word */
-#line 67 "sys/cmd/rc/syntax.y"
+#line 68 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2('=', (yyvsp[-2].tree), (yyvsp[0].tree)); }
#line 1506 "sys/cmd/rc/parse.c"
break;
case 18: /* redir: Tredir word */
-#line 71 "sys/cmd/rc/syntax.y"
+#line 72 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 0); }
#line 1512 "sys/cmd/rc/parse.c"
break;
case 19: /* epilog: %empty */
-#line 74 "sys/cmd/rc/syntax.y"
+#line 75 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = nil; }
#line 1518 "sys/cmd/rc/parse.c"
break;
case 20: /* epilog: redir epilog */
-#line 75 "sys/cmd/rc/syntax.y"
+#line 76 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 1); }
#line 1524 "sys/cmd/rc/parse.c"
break;
case 21: /* cmd: %empty */
-#line 78 "sys/cmd/rc/syntax.y"
+#line 79 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = nil; }
#line 1530 "sys/cmd/rc/parse.c"
break;
case 22: /* cmd: basic */
-#line 79 "sys/cmd/rc/syntax.y"
+#line 80 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tbasic, (yyvsp[0].tree)); }
#line 1536 "sys/cmd/rc/parse.c"
break;
case 23: /* cmd: block epilog */
-#line 80 "sys/cmd/rc/syntax.y"
+#line 81 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangepilog((yyvsp[-1].tree), (yyvsp[0].tree)); }
#line 1542 "sys/cmd/rc/parse.c"
break;
case 24: /* cmd: cmd Tpipe nl cmd */
-#line 81 "sys/cmd/rc/syntax.y"
+#line 82 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangchild2((yyvsp[-2].tree), (yyvsp[-3].tree), 0, (yyvsp[0].tree), 1); }
#line 1548 "sys/cmd/rc/parse.c"
break;
case 25: /* cmd: redir cmd */
-#line 82 "sys/cmd/rc/syntax.y"
+#line 83 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 1); }
#line 1554 "sys/cmd/rc/parse.c"
break;
case 26: /* cmd: assign cmd */
-#line 83 "sys/cmd/rc/syntax.y"
+#line 84 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 2); }
#line 1560 "sys/cmd/rc/parse.c"
break;
case 27: /* cmd: Tif paren nl ifbody */
-#line 84 "sys/cmd/rc/syntax.y"
+#line 85 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangchild1((yyvsp[-2].tree), (yyvsp[-3].tree), 0); }
#line 1566 "sys/cmd/rc/parse.c"
break;
case 28: /* cmd: Tbang cmd */
-#line 85 "sys/cmd/rc/syntax.y"
+#line 86 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tbang, (yyvsp[0].tree)); }
#line 1572 "sys/cmd/rc/parse.c"
break;
case 29: /* cmd: Tsubshell cmd */
-#line 86 "sys/cmd/rc/syntax.y"
+#line 87 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tsubshell, (yyvsp[0].tree)); }
#line 1578 "sys/cmd/rc/parse.c"
break;
case 31: /* basic: basic word */
-#line 90 "sys/cmd/rc/syntax.y"
+#line 91 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(Targs, (yyvsp[-1].tree), (yyvsp[0].tree)); }
#line 1584 "sys/cmd/rc/parse.c"
break;
case 32: /* basic: basic redir */
-#line 91 "sys/cmd/rc/syntax.y"
+#line 92 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(Targs, (yyvsp[-1].tree), (yyvsp[0].tree)); }
#line 1590 "sys/cmd/rc/parse.c"
break;
case 34: /* atom: keyword */
-#line 95 "sys/cmd/rc/syntax.y"
+#line 96 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tword, (yyvsp[0].tree)); }
#line 1596 "sys/cmd/rc/parse.c"
break;
case 36: /* word: word '^' atom */
-#line 99 "sys/cmd/rc/syntax.y"
+#line 100 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); }
#line 1602 "sys/cmd/rc/parse.c"
break;
case 38: /* executable: executable '^' atom */
-#line 103 "sys/cmd/rc/syntax.y"
+#line 104 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); }
#line 1608 "sys/cmd/rc/parse.c"
break;
case 40: /* nonkeyword: '$' atom */
-#line 107 "sys/cmd/rc/syntax.y"
+#line 108 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1('$', (yyvsp[0].tree)); }
#line 1614 "sys/cmd/rc/parse.c"
break;
case 41: /* nonkeyword: '(' wordsnl ')' */
-#line 108 "sys/cmd/rc/syntax.y"
+#line 109 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = (yyvsp[-1].tree); }
#line 1620 "sys/cmd/rc/parse.c"
break;
case 42: /* nonkeyword: Tcount atom */
-#line 109 "sys/cmd/rc/syntax.y"
+#line 110 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tcount, (yyvsp[0].tree)); }
#line 1626 "sys/cmd/rc/parse.c"
break;
case 43: /* nonkeyword: Tflat atom */
-#line 110 "sys/cmd/rc/syntax.y"
+#line 111 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tflat, (yyvsp[0].tree)); }
#line 1632 "sys/cmd/rc/parse.c"
break;
case 48: /* wordsnl: %empty */
-#line 121 "sys/cmd/rc/syntax.y"
+#line 122 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = nil; }
#line 1638 "sys/cmd/rc/parse.c"
break;
case 50: /* wordsnl: wordsnl word */
-#line 123 "sys/cmd/rc/syntax.y"
+#line 124 "sys/cmd/rc/syntax.y"
{(yyval.tree) = (!(yyvsp[-1].tree)) ? ((!(yyvsp[0].tree)) ? nil : (yyvsp[0].tree)) : ((!(yyvsp[0].tree)) ? (yyvsp[-1].tree) : maketree2(Twords, (yyvsp[-1].tree), (yyvsp[0].tree))); }
#line 1644 "sys/cmd/rc/parse.c"
break;
@@ -1868,5 +1868,5 @@ yyreturnlab:
return yyresult;
}
-#line 128 "sys/cmd/rc/syntax.y"
+#line 129 "sys/cmd/rc/syntax.y"
diff --git a/sys/cmd/rc/parse.h b/sys/cmd/rc/parse.h
index c30606d..ef389bc 100644
--- a/sys/cmd/rc/parse.h
+++ b/sys/cmd/rc/parse.h
@@ -107,7 +107,7 @@ extern int yydebug;
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
-#line 23 "sys/cmd/rc/syntax.y"
+#line 24 "sys/cmd/rc/syntax.y"
struct Tree *tree;
diff --git a/sys/cmd/rc/syntax.y b/sys/cmd/rc/syntax.y
index cb4a174..76bcd88 100644
--- a/sys/cmd/rc/syntax.y
+++ b/sys/cmd/rc/syntax.y
@@ -16,6 +16,7 @@
%left '\n'
%left Tbang Tsubshell
%left Tpipe;
+%left '^';
%right '$' Tcount Tflat
%left Tindex