aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-19 10:53:45 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-19 10:53:45 -0700
commitaf3fa90e8bb41c306c5fe2d2cf105db6bbabd1d9 (patch)
tree807c8b5a18a1ff663808b5c369bf1262fdf03021
parent47e3d475df6244a48b73421cd4210b64c392df8d (diff)
Feat: word operators and more robust crashing
Added the length and concatenate operators. Slightly improved the robustness on syntax errors.
-rw-r--r--sys/cmd/rc/code.c20
-rw-r--r--sys/cmd/rc/exec.c65
-rw-r--r--sys/cmd/rc/exec.h5
-rw-r--r--sys/cmd/rc/input.c1
-rw-r--r--sys/cmd/rc/lex.c25
-rw-r--r--sys/cmd/rc/parse.c296
-rw-r--r--sys/cmd/rc/parse.h42
-rw-r--r--sys/cmd/rc/prompt.c2
-rw-r--r--sys/cmd/rc/syntax.y35
9 files changed, 331 insertions, 160 deletions
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
index d4dd6e1..c98cde2 100644
--- a/sys/cmd/rc/code.c
+++ b/sys/cmd/rc/code.c
@@ -51,6 +51,7 @@ walk(Tree *node)
switch(node->type){
default:
print(shell.err, "bad type %d in interpreter walk\n", node->type);
+ fatal("crashing\n");
break;
case '$':
@@ -59,6 +60,20 @@ walk(Tree *node)
emitf(Xdollar);
break;
+ case Tcount:
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xcount);
+ break;
+
+ case Tflat:
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xflat);
+ break;
+
+ case Tindex:
+
#if 0
case '&':
emitf(Xasync);
@@ -103,6 +118,11 @@ walk(Tree *node)
emits(strdup(node->str));
break;
+ case Twords:
+ walk(node->child[1]);
+ walk(node->child[0]);
+ break;
+
case '=':
for(n=node; node && node->type == '='; node = node->child[2])
;
diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c
index d78cb5d..87b6bb7 100644
--- a/sys/cmd/rc/exec.c
+++ b/sys/cmd/rc/exec.c
@@ -582,7 +582,11 @@ Xreadcmd(void)
root = runner;
if(yyparse()){
- exit(1);
+ // resource cleanup?
+ if(runner->flag.eof)
+ Xreturn();
+ else
+ --root->code.i;
}else{
--root->code.i; /* re-execute Xreadcmd after codebuf runs */
run(compiled, 1, root->local);
@@ -671,8 +675,65 @@ Xbasic(void)
}
void
+Xcount(void)
+{
+ Word *arg;
+ char *str, num[12];
+
+ if(count(runner->args->word) != 1){
+ Xerror("variable name not a singleton\n");
+ return;
+ }
+
+ str = runner->args->word->str;
+ arg = var(str)->val;
+ poplist();
+
+ itoa(num, count(arg));
+ pushword(num);
+}
+
+void
+Xflat(void)
+{
+ int len;
+ char *str;
+ Word *arg, *a;
+
+ if(count(runner->args->word)!=1){
+ Xerror("variable name is not a singleton\n");
+ return;
+ }
+
+ str = runner->args->word->str;
+ arg = var(str)->val;
+ poplist();
+
+ len = count(arg);
+ if(!len){
+ pushword("");
+ return;
+ }
+
+ for(a=arg; a; a=a->link)
+ len += strlen(a->str);
+
+ str = emalloc(len);
+ if(arg){
+ strcpy(str, arg->str);
+ for(a = arg->link; a; a = a->link){
+ strcat(str," ");
+ strcat(str,a->str);
+ }
+ }else
+ str[0] = 0;
+
+ pushword(str);
+ efree(str);
+}
+
+void
Xexit(void)
{
exit(shell.status);
}
-
diff --git a/sys/cmd/rc/exec.h b/sys/cmd/rc/exec.h
index ad53365..566c4a3 100644
--- a/sys/cmd/rc/exec.h
+++ b/sys/cmd/rc/exec.h
@@ -16,8 +16,11 @@ void Xreadcmd(void);
void Xunlocal(void);
void Xassign(void);
void Xbasic(void); // Xbasic(args) run command and wait for result
-void Xerror(char*);
void Xword(void);
+void Xcount(void);
+void Xflat(void);
+
+void Xerror(char*);
/* builtin commands */
void xfg(void);
diff --git a/sys/cmd/rc/input.c b/sys/cmd/rc/input.c
index 228b2d8..5e5fc78 100644
--- a/sys/cmd/rc/input.c
+++ b/sys/cmd/rc/input.c
@@ -1030,7 +1030,6 @@ readline(char *prompt)
/* insert a newline character at the end */
put(&runner->cmd.io, '\n');
- printf("\n");
return 1;
}
diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c
index b4a2e8c..06737ba 100644
--- a/sys/cmd/rc/lex.c
+++ b/sys/cmd/rc/lex.c
@@ -2,6 +2,7 @@
#include "parse.h"
static int advance(void);
+
// -----------------------------------------------------------------------
// lexer
@@ -14,10 +15,14 @@ struct Lexer
static struct Lexer lexer = { .c={0, EOF}, .doprompt=1 };
+#define put1(b) lexer.buf[0] = (b), lexer.buf[1] = 0;
+#define put2(b0,b1) lexer.buf[0] = (b0), lexer.buf[1] = (b1), lexer.buf[2] = 0;
+#define put3(b0,b1,b2) lexer.buf[0] = (b0), lexer.buf[1] = (b1), lexer.buf[2] = b2, lexer.buf[3] = 0;
+
void
yyerror(const char *msg)
{
- print(shell.err, "\nrc:%d: ", runner->line);
+ print(shell.err, "rc:%d: ", runner->line);
if(lexer.buf[0] && lexer.buf[0]!='\n')
print(shell.err, "%q: ", lexer.buf);
@@ -48,7 +53,6 @@ readc(void)
exit(1); // XXX: hack for signal handling right now...
c = get(runner->cmd.io);
-
lexer.doprompt = lexer.doprompt || c=='\n' || c==EOF;
if(c==EOF)
@@ -180,12 +184,25 @@ yylex(void)
skipws();
switch(c=advance()){
case EOF:
+ put3('E','O','F');
return EOF;
+
case '&':
- lexer.buf[0] = '&';
- lexer.buf[1] = 0;
+ put1('&');
return '&';
+ case '$':
+ if(nextis('#')){
+ put2('$','#');
+ return Tcount;
+ }
+ if(nextis('^')){
+ put2('$','^');
+ return Tflat;
+ }
+ put1('$');
+ return '$';
+
default:
;
}
diff --git a/sys/cmd/rc/parse.c b/sys/cmd/rc/parse.c
index 42834ed..b88e8ab 100644
--- a/sys/cmd/rc/parse.c
+++ b/sys/cmd/rc/parse.c
@@ -106,42 +106,47 @@ enum yysymbol_kind_t
YYSYMBOL_YYerror = 1, /* error */
YYSYMBOL_YYUNDEF = 2, /* "invalid token" */
YYSYMBOL_Tword = 3, /* Tword */
- YYSYMBOL_Tif = 4, /* Tif */
- YYSYMBOL_Telse = 5, /* Telse */
- YYSYMBOL_Tbang = 6, /* Tbang */
- YYSYMBOL_Targs = 7, /* Targs */
- YYSYMBOL_Tbasic = 8, /* Tbasic */
- YYSYMBOL_Tparen = 9, /* Tparen */
- YYSYMBOL_Tblock = 10, /* Tblock */
- YYSYMBOL_Twhile = 11, /* Twhile */
- YYSYMBOL_12_n_ = 12, /* '\n' */
- YYSYMBOL_13_ = 13, /* '$' */
- YYSYMBOL_14_ = 14, /* '(' */
- YYSYMBOL_15_ = 15, /* ')' */
- YYSYMBOL_16_ = 16, /* '{' */
- YYSYMBOL_17_ = 17, /* '}' */
- YYSYMBOL_18_ = 18, /* ';' */
- YYSYMBOL_19_ = 19, /* '&' */
- YYSYMBOL_20_ = 20, /* '=' */
- YYSYMBOL_21_ = 21, /* '^' */
- YYSYMBOL_YYACCEPT = 22, /* $accept */
- YYSYMBOL_rc = 23, /* rc */
- YYSYMBOL_line = 24, /* line */
- YYSYMBOL_body = 25, /* body */
- YYSYMBOL_paren = 26, /* paren */
- YYSYMBOL_block = 27, /* block */
- YYSYMBOL_cmds = 28, /* cmds */
- YYSYMBOL_cmdsln = 29, /* cmdsln */
- YYSYMBOL_ifbody = 30, /* ifbody */
- YYSYMBOL_assign = 31, /* assign */
- YYSYMBOL_cmd = 32, /* cmd */
- YYSYMBOL_basic = 33, /* basic */
- YYSYMBOL_atom = 34, /* atom */
- YYSYMBOL_word = 35, /* word */
- YYSYMBOL_executable = 36, /* executable */
- YYSYMBOL_nonkeyword = 37, /* nonkeyword */
- YYSYMBOL_keyword = 38, /* keyword */
- YYSYMBOL_nl = 39 /* nl */
+ YYSYMBOL_Twords = 4, /* Twords */
+ YYSYMBOL_Tif = 5, /* Tif */
+ YYSYMBOL_Telse = 6, /* Telse */
+ YYSYMBOL_Tbang = 7, /* Tbang */
+ YYSYMBOL_Targs = 8, /* Targs */
+ YYSYMBOL_Tindex = 9, /* Tindex */
+ YYSYMBOL_Tbasic = 10, /* Tbasic */
+ YYSYMBOL_Tparen = 11, /* Tparen */
+ YYSYMBOL_Tblock = 12, /* Tblock */
+ YYSYMBOL_Twhile = 13, /* Twhile */
+ YYSYMBOL_14_n_ = 14, /* '\n' */
+ YYSYMBOL_15_ = 15, /* '$' */
+ YYSYMBOL_Tcount = 16, /* Tcount */
+ YYSYMBOL_Tflat = 17, /* Tflat */
+ YYSYMBOL_18_ = 18, /* '(' */
+ YYSYMBOL_19_ = 19, /* ')' */
+ YYSYMBOL_20_ = 20, /* '{' */
+ YYSYMBOL_21_ = 21, /* '}' */
+ YYSYMBOL_22_ = 22, /* ';' */
+ YYSYMBOL_23_ = 23, /* '&' */
+ YYSYMBOL_24_ = 24, /* '=' */
+ YYSYMBOL_25_ = 25, /* '^' */
+ YYSYMBOL_YYACCEPT = 26, /* $accept */
+ YYSYMBOL_rc = 27, /* rc */
+ YYSYMBOL_line = 28, /* line */
+ YYSYMBOL_body = 29, /* body */
+ YYSYMBOL_paren = 30, /* paren */
+ YYSYMBOL_block = 31, /* block */
+ YYSYMBOL_cmds = 32, /* cmds */
+ YYSYMBOL_cmdsln = 33, /* cmdsln */
+ YYSYMBOL_ifbody = 34, /* ifbody */
+ YYSYMBOL_assign = 35, /* assign */
+ YYSYMBOL_cmd = 36, /* cmd */
+ YYSYMBOL_basic = 37, /* basic */
+ YYSYMBOL_atom = 38, /* atom */
+ YYSYMBOL_word = 39, /* word */
+ YYSYMBOL_executable = 40, /* executable */
+ YYSYMBOL_nonkeyword = 41, /* nonkeyword */
+ YYSYMBOL_keyword = 42, /* keyword */
+ YYSYMBOL_wordsnl = 43, /* wordsnl */
+ YYSYMBOL_nl = 44 /* nl */
};
typedef enum yysymbol_kind_t yysymbol_kind_t;
@@ -467,21 +472,21 @@ union yyalloc
#endif /* !YYCOPY_NEEDED */
/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 25
+#define YYFINAL 31
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 53
+#define YYLAST 91
/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 22
+#define YYNTOKENS 26
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 18
+#define YYNNTS 19
/* YYNRULES -- Number of rules. */
-#define YYNRULES 35
+#define YYNRULES 41
/* YYNSTATES -- Number of states. */
-#define YYNSTATES 52
+#define YYNSTATES 61
/* YYMAXUTOK -- Last valid token kind. */
-#define YYMAXUTOK 266
+#define YYMAXUTOK 270
/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
@@ -496,18 +501,18 @@ union yyalloc
static const yytype_int8 yytranslate[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 14, 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, 13, 2, 19, 2,
- 14, 15, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 18,
- 2, 20, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 15, 2, 23, 2,
+ 18, 19, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 22,
+ 2, 24, 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, 21, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 25, 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, 16, 2, 17, 2, 2, 2, 2,
+ 2, 2, 2, 20, 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, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -521,7 +526,8 @@ static const yytype_int8 yytranslate[] =
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, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
+ 17
};
#if YYDEBUG
@@ -531,7 +537,8 @@ static const yytype_int8 yyrline[] =
0, 36, 36, 37, 40, 41, 44, 45, 48, 51,
54, 55, 58, 59, 62, 63, 66, 69, 70, 71,
72, 73, 76, 77, 86, 87, 90, 91, 94, 95,
- 98, 99, 102, 102, 104, 106
+ 98, 99, 100, 101, 102, 106, 106, 113, 114, 115,
+ 117, 119
};
#endif
@@ -547,12 +554,12 @@ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
{
- "\"end of file\"", "error", "\"invalid token\"", "Tword", "Tif",
- "Telse", "Tbang", "Targs", "Tbasic", "Tparen", "Tblock", "Twhile",
- "'\\n'", "'$'", "'('", "')'", "'{'", "'}'", "';'", "'&'", "'='", "'^'",
- "$accept", "rc", "line", "body", "paren", "block", "cmds", "cmdsln",
- "ifbody", "assign", "cmd", "basic", "atom", "word", "executable",
- "nonkeyword", "keyword", "nl", YY_NULLPTR
+ "\"end of file\"", "error", "\"invalid token\"", "Tword", "Twords",
+ "Tif", "Telse", "Tbang", "Targs", "Tindex", "Tbasic", "Tparen", "Tblock",
+ "Twhile", "'\\n'", "'$'", "Tcount", "Tflat", "'('", "')'", "'{'", "'}'",
+ "';'", "'&'", "'='", "'^'", "$accept", "rc", "line", "body", "paren",
+ "block", "cmds", "cmdsln", "ifbody", "assign", "cmd", "basic", "atom",
+ "word", "executable", "nonkeyword", "keyword", "wordsnl", "nl", YY_NULLPTR
};
static const char *
@@ -562,7 +569,7 @@ yysymbol_name (yysymbol_kind_t yysymbol)
}
#endif
-#define YYPACT_NINF (-14)
+#define YYPACT_NINF (-22)
#define yypact_value_is_default(Yyn) \
((Yyn) == YYPACT_NINF)
@@ -576,12 +583,13 @@ yysymbol_name (yysymbol_kind_t yysymbol)
STATE-NUM. */
static const yytype_int8 yypact[] =
{
- 3, -14, -13, 24, 10, 5, 19, -14, 10, 10,
- 28, 24, -3, -14, 10, -14, -14, -14, -14, -14,
- -14, -2, -14, 10, 26, -14, -14, -14, -14, -14,
- -14, -14, 21, 24, 24, 25, 8, -14, -14, -14,
- 24, 21, -14, -14, -14, 38, -14, -14, -14, -14,
- 8, -14
+ 14, -22, -17, 73, 73, 73, -22, 52, 10, 2,
+ -22, 52, 52, 1, 73, 16, -22, 52, -22, -22,
+ -22, -22, -22, -22, -22, -22, 68, 7, -22, 52,
+ 13, -22, -22, -22, -22, -22, -22, -22, -5, 73,
+ 73, 18, 46, -22, -22, -5, -22, -22, -22, 73,
+ -5, -22, -22, -22, 27, -22, -22, -22, -22, 46,
+ -22
};
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -589,26 +597,27 @@ static const yytype_int8 yypact[] =
means the default is an error. */
static const yytype_int8 yydefact[] =
{
- 17, 30, 0, 0, 17, 0, 0, 19, 17, 17,
- 4, 18, 22, 28, 17, 34, 32, 33, 31, 24,
- 25, 0, 12, 17, 6, 1, 3, 5, 20, 10,
- 11, 26, 23, 0, 0, 0, 17, 9, 7, 13,
- 0, 16, 29, 8, 35, 19, 21, 14, 27, 34,
- 17, 15
+ 17, 30, 0, 0, 0, 0, 37, 17, 0, 0,
+ 19, 17, 17, 4, 18, 22, 28, 17, 40, 35,
+ 36, 31, 24, 25, 33, 34, 0, 0, 12, 17,
+ 6, 1, 3, 5, 20, 10, 11, 26, 23, 0,
+ 0, 0, 17, 38, 32, 39, 9, 7, 13, 0,
+ 16, 29, 8, 41, 19, 21, 14, 27, 40, 17,
+ 15
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int8 yypgoto[] =
{
- -14, -14, 40, 11, -14, 13, 22, -14, -14, -14,
- 0, -14, 1, 18, -14, -1, -14, 4
+ -22, -22, 11, -8, -22, 4, 15, -22, -22, -22,
+ 0, -22, 3, -21, -22, -1, -22, -22, -14
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int8 yydefgoto[] =
{
- 0, 5, 6, 21, 15, 7, 22, 23, 46, 9,
- 24, 11, 31, 32, 12, 13, 20, 36
+ 0, 8, 9, 27, 18, 10, 28, 29, 55, 12,
+ 30, 14, 37, 38, 15, 16, 23, 26, 42
};
/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
@@ -616,43 +625,53 @@ static const yytype_int8 yydefgoto[] =
number is the opposite. If YYTABLE_NINF, syntax error. */
static const yytype_int8 yytable[] =
{
- 10, 14, 19, -2, 18, 25, 1, 2, 10, 28,
- 19, 1, 2, 1, 2, 37, 3, 33, 34, 4,
- 44, 3, 8, 3, 4, 35, 4, 1, 16, 17,
- 8, 26, 19, 19, 38, 42, 47, 3, 39, 19,
- 43, 48, 40, 49, 29, 30, 29, 30, 27, 45,
- 51, 41, 0, 50
+ 13, 17, 22, 22, 22, 45, 21, 24, 25, 41,
+ 31, 13, 34, 22, -2, 11, 32, 1, 50, 2,
+ 49, 47, 33, 35, 36, 22, 11, 48, 46, 3,
+ 4, 5, 6, 58, 7, 35, 36, 52, 22, 22,
+ 39, 40, 56, 51, 59, 0, 54, 0, 22, 1,
+ 0, 2, 57, 0, 0, 1, 0, 2, 0, 60,
+ 53, 3, 4, 5, 6, 0, 7, 3, 4, 5,
+ 6, 1, 7, 19, 20, 0, 1, 0, 19, 20,
+ 0, 0, 43, 3, 4, 5, 6, 44, 3, 4,
+ 5, 6
};
static const yytype_int8 yycheck[] =
{
- 0, 14, 3, 0, 3, 0, 3, 4, 8, 9,
- 11, 3, 4, 3, 4, 17, 13, 20, 21, 16,
- 12, 13, 0, 13, 16, 14, 16, 3, 4, 5,
- 8, 12, 33, 34, 23, 34, 36, 13, 12, 40,
- 15, 40, 21, 5, 18, 19, 18, 19, 8, 36,
- 50, 33, -1, 49
+ 0, 18, 3, 4, 5, 26, 3, 4, 5, 17,
+ 0, 11, 12, 14, 0, 0, 14, 3, 39, 5,
+ 25, 29, 11, 22, 23, 26, 11, 14, 21, 15,
+ 16, 17, 18, 6, 20, 22, 23, 19, 39, 40,
+ 24, 25, 42, 40, 58, -1, 42, -1, 49, 3,
+ -1, 5, 49, -1, -1, 3, -1, 5, -1, 59,
+ 14, 15, 16, 17, 18, -1, 20, 15, 16, 17,
+ 18, 3, 20, 5, 6, -1, 3, -1, 5, 6,
+ -1, -1, 14, 15, 16, 17, 18, 19, 15, 16,
+ 17, 18
};
/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
state STATE-NUM. */
static const yytype_int8 yystos[] =
{
- 0, 3, 4, 13, 16, 23, 24, 27, 28, 31,
- 32, 33, 36, 37, 14, 26, 4, 5, 34, 37,
- 38, 25, 28, 29, 32, 0, 12, 24, 32, 18,
- 19, 34, 35, 20, 21, 25, 39, 17, 25, 12,
- 21, 35, 34, 15, 12, 27, 30, 32, 34, 5,
- 39, 32
+ 0, 3, 5, 15, 16, 17, 18, 20, 27, 28,
+ 31, 32, 35, 36, 37, 40, 41, 18, 30, 5,
+ 6, 38, 41, 42, 38, 38, 43, 29, 32, 33,
+ 36, 0, 14, 28, 36, 22, 23, 38, 39, 24,
+ 25, 29, 44, 14, 19, 39, 21, 29, 14, 25,
+ 39, 38, 19, 14, 31, 34, 36, 38, 6, 44,
+ 36
};
/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */
static const yytype_int8 yyr1[] =
{
- 0, 22, 23, 23, 24, 24, 25, 25, 26, 27,
- 28, 28, 29, 29, 30, 30, 31, 32, 32, 32,
- 32, 32, 33, 33, 34, 34, 35, 35, 36, 36,
- 37, 37, 38, 38, 39, 39
+ 0, 26, 27, 27, 28, 28, 29, 29, 30, 31,
+ 32, 32, 33, 33, 34, 34, 35, 36, 36, 36,
+ 36, 36, 37, 37, 38, 38, 39, 39, 40, 40,
+ 41, 41, 41, 41, 41, 42, 42, 43, 43, 43,
+ 44, 44
};
/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */
@@ -661,7 +680,8 @@ static const yytype_int8 yyr2[] =
0, 2, 0, 2, 1, 2, 1, 2, 3, 3,
2, 2, 1, 2, 1, 4, 3, 0, 1, 1,
2, 4, 1, 2, 1, 1, 1, 3, 1, 3,
- 1, 2, 1, 1, 0, 2
+ 1, 2, 3, 2, 2, 1, 1, 0, 2, 2,
+ 0, 2
};
@@ -1397,119 +1417,149 @@ yyreduce:
case 2: /* rc: %empty */
#line 36 "sys/cmd/rc/syntax.y"
{ return 0; }
-#line 1401 "sys/cmd/rc/parse.c"
+#line 1421 "sys/cmd/rc/parse.c"
break;
case 3: /* rc: line '\n' */
#line 37 "sys/cmd/rc/syntax.y"
{ return compile((yyvsp[-1].tree)); }
-#line 1407 "sys/cmd/rc/parse.c"
+#line 1427 "sys/cmd/rc/parse.c"
break;
case 5: /* line: cmds line */
#line 41 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); }
-#line 1413 "sys/cmd/rc/parse.c"
+#line 1433 "sys/cmd/rc/parse.c"
break;
case 7: /* body: cmdsln body */
#line 45 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); }
-#line 1419 "sys/cmd/rc/parse.c"
+#line 1439 "sys/cmd/rc/parse.c"
break;
case 8: /* paren: '(' body ')' */
#line 48 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tparen, (yyvsp[-1].tree)); }
-#line 1425 "sys/cmd/rc/parse.c"
+#line 1445 "sys/cmd/rc/parse.c"
break;
case 9: /* block: '{' body '}' */
#line 51 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tblock, (yyvsp[-1].tree)); }
-#line 1431 "sys/cmd/rc/parse.c"
+#line 1451 "sys/cmd/rc/parse.c"
break;
case 11: /* cmds: cmd '&' */
#line 55 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1('&', (yyvsp[-1].tree)); }
-#line 1437 "sys/cmd/rc/parse.c"
+#line 1457 "sys/cmd/rc/parse.c"
break;
case 14: /* ifbody: cmd */
#line 62 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(Tif, nil, (yyvsp[0].tree)); }
-#line 1443 "sys/cmd/rc/parse.c"
+#line 1463 "sys/cmd/rc/parse.c"
break;
case 15: /* ifbody: block Telse nl cmd */
#line 63 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree3(Tif, nil, (yyvsp[-3].tree), (yyvsp[-2].tree)); }
-#line 1449 "sys/cmd/rc/parse.c"
+#line 1469 "sys/cmd/rc/parse.c"
break;
case 16: /* assign: executable '=' word */
#line 66 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2('=', (yyvsp[-2].tree), (yyvsp[0].tree)); }
-#line 1455 "sys/cmd/rc/parse.c"
+#line 1475 "sys/cmd/rc/parse.c"
break;
case 17: /* cmd: %empty */
#line 69 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = nil; }
-#line 1461 "sys/cmd/rc/parse.c"
+#line 1481 "sys/cmd/rc/parse.c"
break;
case 18: /* cmd: basic */
#line 70 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tbasic, (yyvsp[0].tree)); }
-#line 1467 "sys/cmd/rc/parse.c"
+#line 1487 "sys/cmd/rc/parse.c"
break;
case 20: /* cmd: assign cmd */
#line 72 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 2); }
-#line 1473 "sys/cmd/rc/parse.c"
+#line 1493 "sys/cmd/rc/parse.c"
break;
case 21: /* cmd: Tif paren nl ifbody */
#line 73 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangchild1((yyvsp[-2].tree), (yyvsp[-3].tree), 0); }
-#line 1479 "sys/cmd/rc/parse.c"
+#line 1499 "sys/cmd/rc/parse.c"
break;
case 23: /* basic: basic word */
#line 77 "sys/cmd/rc/syntax.y"
- { (yyval.tree) = maketree2(Targs, (yyvsp[-1].tree), (yyvsp[0].tree)); }
-#line 1485 "sys/cmd/rc/parse.c"
+ { (yyval.tree) = maketree2(Targs, (yyvsp[-1].tree), (yyvsp[0].tree)); }
+#line 1505 "sys/cmd/rc/parse.c"
break;
case 25: /* atom: keyword */
#line 87 "sys/cmd/rc/syntax.y"
- { (yyval.tree) = maketree1(Tword, (yyvsp[0].tree)); }
-#line 1491 "sys/cmd/rc/parse.c"
+ { (yyval.tree) = maketree1(Tword, (yyvsp[0].tree)); }
+#line 1511 "sys/cmd/rc/parse.c"
break;
case 27: /* word: word '^' atom */
#line 91 "sys/cmd/rc/syntax.y"
- { (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); }
-#line 1497 "sys/cmd/rc/parse.c"
+ { (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); }
+#line 1517 "sys/cmd/rc/parse.c"
break;
case 29: /* executable: executable '^' atom */
#line 95 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); }
-#line 1503 "sys/cmd/rc/parse.c"
+#line 1523 "sys/cmd/rc/parse.c"
break;
case 31: /* nonkeyword: '$' atom */
#line 99 "sys/cmd/rc/syntax.y"
- { (yyval.tree) = maketree1('$', (yyvsp[0].tree)); }
-#line 1509 "sys/cmd/rc/parse.c"
+ { (yyval.tree) = maketree1('$', (yyvsp[0].tree)); }
+#line 1529 "sys/cmd/rc/parse.c"
+ break;
+
+ case 32: /* nonkeyword: '(' wordsnl ')' */
+#line 100 "sys/cmd/rc/syntax.y"
+ { (yyval.tree) = (yyvsp[-1].tree); }
+#line 1535 "sys/cmd/rc/parse.c"
+ break;
+
+ case 33: /* nonkeyword: Tcount atom */
+#line 101 "sys/cmd/rc/syntax.y"
+ { (yyval.tree) = maketree1(Tcount, (yyvsp[0].tree)); }
+#line 1541 "sys/cmd/rc/parse.c"
+ break;
+
+ case 34: /* nonkeyword: Tflat atom */
+#line 102 "sys/cmd/rc/syntax.y"
+ { (yyval.tree) = maketree1(Tflat, (yyvsp[0].tree)); }
+#line 1547 "sys/cmd/rc/parse.c"
+ break;
+
+ case 37: /* wordsnl: %empty */
+#line 113 "sys/cmd/rc/syntax.y"
+ { (yyval.tree) = nil; }
+#line 1553 "sys/cmd/rc/parse.c"
+ break;
+
+ case 39: /* wordsnl: wordsnl word */
+#line 115 "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 1559 "sys/cmd/rc/parse.c"
break;
-#line 1513 "sys/cmd/rc/parse.c"
+#line 1563 "sys/cmd/rc/parse.c"
default: break;
}
@@ -1733,5 +1783,5 @@ yyreturnlab:
return yyresult;
}
-#line 107 "sys/cmd/rc/syntax.y"
+#line 120 "sys/cmd/rc/syntax.y"
diff --git a/sys/cmd/rc/parse.h b/sys/cmd/rc/parse.h
index 8fc661f..85be043 100644
--- a/sys/cmd/rc/parse.h
+++ b/sys/cmd/rc/parse.h
@@ -55,14 +55,18 @@ extern int yydebug;
YYerror = 256, /* error */
YYUNDEF = 257, /* "invalid token" */
Tword = 258, /* Tword */
- Tif = 259, /* Tif */
- Telse = 260, /* Telse */
- Tbang = 261, /* Tbang */
- Targs = 262, /* Targs */
- Tbasic = 263, /* Tbasic */
- Tparen = 264, /* Tparen */
- Tblock = 265, /* Tblock */
- Twhile = 266 /* Twhile */
+ Twords = 259, /* Twords */
+ Tif = 260, /* Tif */
+ Telse = 261, /* Telse */
+ Tbang = 262, /* Tbang */
+ Targs = 263, /* Targs */
+ Tindex = 264, /* Tindex */
+ Tbasic = 265, /* Tbasic */
+ Tparen = 266, /* Tparen */
+ Tblock = 267, /* Tblock */
+ Twhile = 268, /* Twhile */
+ Tcount = 269, /* Tcount */
+ Tflat = 270 /* Tflat */
};
typedef enum yytokentype yytoken_kind_t;
#endif
@@ -72,14 +76,18 @@ extern int yydebug;
#define YYerror 256
#define YYUNDEF 257
#define Tword 258
-#define Tif 259
-#define Telse 260
-#define Tbang 261
-#define Targs 262
-#define Tbasic 263
-#define Tparen 264
-#define Tblock 265
-#define Twhile 266
+#define Twords 259
+#define Tif 260
+#define Telse 261
+#define Tbang 262
+#define Targs 263
+#define Tindex 264
+#define Tbasic 265
+#define Tparen 266
+#define Tblock 267
+#define Twhile 268
+#define Tcount 269
+#define Tflat 270
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@@ -89,7 +97,7 @@ union YYSTYPE
struct Tree *tree;
-#line 93 "sys/cmd/rc/parse.h"
+#line 101 "sys/cmd/rc/parse.h"
};
typedef union YYSTYPE YYSTYPE;
diff --git a/sys/cmd/rc/prompt.c b/sys/cmd/rc/prompt.c
index 94022ca..3d05e41 100644
--- a/sys/cmd/rc/prompt.c
+++ b/sys/cmd/rc/prompt.c
@@ -9,7 +9,7 @@ prompt(ushort *flag)
runner->flag.eof = 1;
return 0;
}
-
+ printf("\n");
runner->line++;
*flag = 0;
}
diff --git a/sys/cmd/rc/syntax.y b/sys/cmd/rc/syntax.y
index a580cb0..469260f 100644
--- a/sys/cmd/rc/syntax.y
+++ b/sys/cmd/rc/syntax.y
@@ -1,5 +1,5 @@
-%token Tword Tif Telse Tbang
-%token Targs
+%token Tword Twords Tif Telse Tbang
+%token Targs Tindex
%token Tbasic Tparen Tblock
%define parse.error verbose
@@ -12,18 +12,18 @@
%}
/* operator precendence: lowest first */
-%right Telse
-%left Twhile
+%left Twhile Telse
%left '\n'
%left Tbang
-%right '$'
+%right '$' Tcount Tflat
+%right Tindex
/* semantic types */
%union{
struct Tree *tree;
}
%type<tree> line cmds cmdsln body paren block ifbody assign;
-%type<tree> cmd basic executable nonkeyword keyword word atom arg args;
+%type<tree> cmd basic executable nonkeyword keyword word words wordsnl atom arg args;
%type<tree> Tbang;
%type<tree> Tword Tif Telse;
@@ -74,21 +74,21 @@ cmd:
basic:
executable
-| basic word { $$ = maketree2(Targs, $1, $2); }
+| basic word { $$ = maketree2(Targs, $1, $2); }
arg: word
args:
arg
-| args arg { $$ = maketree2(Targs, $1, $2); }
+| args arg { $$ = maketree2(Targs, $1, $2); }
atom:
nonkeyword
-| keyword { $$ = maketree1(Tword, $1); }
+| keyword { $$ = maketree1(Tword, $1); }
word:
atom
-| word '^' atom { $$ = maketree2('^', $1, $3); }
+| word '^' atom { $$ = maketree2('^', $1, $3); }
executable:
nonkeyword
@@ -96,11 +96,24 @@ executable:
nonkeyword:
Tword
-| '$' atom { $$ = maketree1('$', $2); }
+| '$' atom { $$ = maketree1('$', $2); }
+| '(' wordsnl ')' { $$ = $2; }
+| Tcount atom { $$ = maketree1(Tcount, $2); }
+| Tflat atom { $$ = maketree1(Tflat, $2); }
+//| '`' block { $$ = maketree1('`', $2); }
keyword:
Tif|Telse
+words:
+/* empty */ { $$ = nil; }
+| words word { $$ = maketree2(Twords, $1, $2); }
+
+wordsnl:
+/* empty */ { $$ = nil; }
+| wordsnl '\n' /* empty */
+| wordsnl word {$$ = (!$1) ? ((!$2) ? nil : $2) : ((!$2) ? $1 : maketree2(Twords, $1, $2)); }
+
nl:
/*empty*/
| nl '\n'