aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nnoll523@gmail.com>2021-10-26 12:35:22 -0700
committerNicholas Noll <nnoll523@gmail.com>2021-10-26 12:35:22 -0700
commit2416a8654e3c1a4b74fcc0379dac5294670a1f46 (patch)
treeeb63703a92b035752674b9ab97a310fe58b2862a
parent47e1e78da8eba4d755179d61a16f2c7920d2da39 (diff)
feat(rc): keywords now recognized. for and while loop
Prototypes for loops sketched. This required recognizing keywords and returning from yylex. Debugging/testing will be required.
-rw-r--r--sys/cmd/rc/code.c37
-rw-r--r--sys/cmd/rc/exec.c25
-rw-r--r--sys/cmd/rc/exec.h8
-rw-r--r--sys/cmd/rc/lex.c5
-rw-r--r--sys/cmd/rc/main.c1
-rw-r--r--sys/cmd/rc/parse.c2
-rw-r--r--sys/cmd/rc/rc.h6
-rw-r--r--sys/cmd/rc/syntax.y2
-rw-r--r--sys/cmd/rc/var.c69
9 files changed, 146 insertions, 9 deletions
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
index 0723279..786f284 100644
--- a/sys/cmd/rc/code.c
+++ b/sys/cmd/rc/code.c
@@ -163,6 +163,43 @@ walk(Tree *node)
}
node = n;
break;
+ /* control structures */
+ case Twhile:
+ addr1 = interpreter.i; // head of loop
+ walk(node->child[0]);
+ if(addr1 == interpreter.i)
+ fatal("TODO");
+ emitf(Xtrue);
+ addr2 = emiti(0); // goto end of loop
+
+ walk(node->child[1]);
+ emitf(Xgoto);
+ emiti(addr1); // goto top of loop
+ storepc(addr2);
+ break;
+
+ case Tfor:
+ emitf(Xmark);
+ if(node->child[1]){ // for( x in X )
+ walk(node->child[1]);
+ // emitf(Xglob)
+ }else{ // for(X)
+ fatal("TODO");
+ }
+ emitf(Xmark); // null initial value for Xlocal
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xlocal);
+
+ addr1 = emitf(Xfor);
+ addr2 = emiti(0);
+
+ walk(node->child[2]);
+ emitf(Xgoto);
+ emiti(addr1);
+ storepc(addr2);
+ emitf(Xunlocal);
+ break;
/* forks */
case '&':
diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c
index fbcfb9b..5f3c6d6 100644
--- a/sys/cmd/rc/exec.c
+++ b/sys/cmd/rc/exec.c
@@ -656,6 +656,31 @@ Xfalse(void)
runner->code.i = runner->code.exe[runner->code.i].i;
}
+void
+Xgoto(void)
+{
+ runner->code.i = runner->code.exe[runner->code.i].i;
+}
+
+void
+Xfor(void)
+{
+ if(!runner->args->word){
+ poplist();
+ runner->code.i = runner->code.exe[runner->code.i].i;
+ }else{
+ freelist(runner->local->val);
+
+ runner->local->val = runner->args->word;
+ runner->local->new = 1;
+ runner->args->word = runner->args->word->link;
+
+ runner->local->val->link = nil;
+ runner->code.i++;
+ }
+
+}
+
static
Word*
catlist(Word *l, Word *r, Word *tail)
diff --git a/sys/cmd/rc/exec.h b/sys/cmd/rc/exec.h
index 635eb1d..a3a6ae9 100644
--- a/sys/cmd/rc/exec.h
+++ b/sys/cmd/rc/exec.h
@@ -8,12 +8,14 @@
*/
void Xmark(void); // Xmark marks stack location for word
-void Xtrue(void); // Xtrue{...} execute {} if true
-void Xfalse(void); // Xfalse{...} execute {} if false
-void Xdollar(void); // Xdollar(name) get value of name
void Xindex(void); // Xindex
void Xlocal(void); // Xlocal(name,val) create local variable, assign value
void Xunlocal(void); // Xunlocal delete local variable
+void Xdollar(void); // Xdollar(name) get value of name
+void Xtrue(void); // Xtrue{...} execute {} if true
+void Xfalse(void); // Xfalse{...} execute {} if false
+void Xgoto(void); // Xgoto[addr] goto address
+void Xfor(void); // Xfor(var, list){... Xreturn}
void Xreadcmd(void); //
void Xassign(void);
void Xbang(void);
diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c
index 6065981..596021b 100644
--- a/sys/cmd/rc/lex.c
+++ b/sys/cmd/rc/lex.c
@@ -386,7 +386,10 @@ yylex(void)
*w = 0;
node = token(Tword, lexer.buf);
- // TODO: keywords
+ if((c=iskeyword(lexer.buf))){
+ node->type = c;
+ lexer.hadword = 0;
+ }
node->quoted = 0;
diff --git a/sys/cmd/rc/main.c b/sys/cmd/rc/main.c
index 9e35a87..12f0859 100644
--- a/sys/cmd/rc/main.c
+++ b/sys/cmd/rc/main.c
@@ -56,6 +56,7 @@ main(int argc, char *argv[])
initenv();
initpath();
+ initkeywords();
initshell();
// enablevi();
diff --git a/sys/cmd/rc/parse.c b/sys/cmd/rc/parse.c
index fa3e165..1b29d41 100644
--- a/sys/cmd/rc/parse.c
+++ b/sys/cmd/rc/parse.c
@@ -632,7 +632,7 @@ static const yytype_int8 yydefact[] =
26, 0, 0, 0, 0, 26, 26, 0, 22, 50,
0, 0, 0, 69, 26, 0, 0, 0, 24, 26,
26, 26, 4, 27, 41, 48, 0, 26, 72, 72,
- 0, 34, 35, 58, 57, 59, 60, 61, 62, 63,
+ 0, 34, 35, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 46, 23, 44, 45, 51, 54, 55,
0, 0, 12, 26, 6, 56, 1, 3, 24, 28,
5, 33, 32, 72, 72, 72, 10, 11, 43, 42,
diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h
index 3090002..e35c3e4 100644
--- a/sys/cmd/rc/rc.h
+++ b/sys/cmd/rc/rc.h
@@ -239,7 +239,6 @@ void background(Thread *, int);
int count(Word *);
Word *makeword(char *str, Word *link);
void freeword(Word *w);
-void initpath(void);
/* var.c */
Var *var(char*);
@@ -247,6 +246,11 @@ Var *definevar(char*, Var *);
Var *globalvar(char*);
Var *makevar(char *name, Var *link);
void setvar(char *, Word *);
+int iskeyword(char *);
+
+void initpath(void);
+void initkeywords(void);
+
char **mkenv(void);
/* code.c */
diff --git a/sys/cmd/rc/syntax.y b/sys/cmd/rc/syntax.y
index 58bef16..0bdc776 100644
--- a/sys/cmd/rc/syntax.y
+++ b/sys/cmd/rc/syntax.y
@@ -129,7 +129,7 @@ nonkeyword:
//| Tredir block { $$ = hangchild1($1, $2, 0); $$->type = Tpipefd; }
keyword:
- Tin|Tfor|Twhile|Tif|Telse|Tswitch|Tcase|Tbang|Tsubshell|Tfunc
+ Tfor|Tin|Twhile|Tif|Telse|Tswitch|Tcase|Tbang|Tsubshell|Tfunc
words:
/* empty */ { $$ = nil; }
diff --git a/sys/cmd/rc/var.c b/sys/cmd/rc/var.c
index 5e1e90c..3e9635f 100644
--- a/sys/cmd/rc/var.c
+++ b/sys/cmd/rc/var.c
@@ -1,6 +1,19 @@
#include "rc.h"
+#include "parse.h"
+
+// TODO: string interning
+
+// -----------------------------------------------------------------------
+// globals
+
+struct Keyword
+{
+ char *name;
+ int type;
+};
static Var *globals[512];
+static struct Keyword keywords[100]; // sparse map means less hits
// -----------------------------------------------------------------------
// internals
@@ -111,8 +124,6 @@ bigpath(Var *v)
·setvar("path", w, 0);
}
-
-
// -----------------------------------------------------------------------
// exports
@@ -269,3 +280,57 @@ initpath(void)
bigpath(v);
}
+#define KEYWORDS \
+ KEYWORD("for", Tfor) \
+ KEYWORD("in", Tin) \
+ KEYWORD("while", Twhile) \
+ KEYWORD("if", Tif) \
+ KEYWORD("else", Telse) \
+ KEYWORD("switch", Tswitch) \
+ KEYWORD("case", Tcase) \
+ KEYWORD("!", Tbang) \
+ KEYWORD("@", Tsubshell) \
+ KEYWORD("func", Tfunc)
+
+void
+initkeywords(void)
+{
+ int i, s, j, h;
+#define KEYWORD(a, b) a,
+ static char *name[] = { KEYWORDS };
+#undef KEYWORD
+#define KEYWORD(a, b) b,
+ static int type[] = { KEYWORDS };
+#undef KEYWORD
+
+ for(i = 0; i < arrlen(type); i++){
+ h = hash(name[i], arrlen(keywords));
+ for(s=0; s < arrlen(keywords); s++){
+ j = (h + s) % arrlen(keywords);
+ if(!keywords[j].type || strcmp(keywords[j].name, name[i]) == 0){
+ keywords[j].name = name[i];
+ keywords[j].type = type[i];
+ goto nextkeyword;
+ }
+ }
+ nextkeyword:;
+ }
+}
+
+int
+iskeyword(char *word)
+{
+ int i, s, h;
+
+ h = hash(word, arrlen(keywords));
+ for(s = 0; s < arrlen(keywords); s++){
+ i = (h + s) % arrlen(keywords);
+ if(!keywords[i].type)
+ return 0;
+ if(strcmp(keywords[i].name, word) == 0)
+ return keywords[i].type;
+ }
+ return 0;
+}
+
+#undef KEYWORDS