From 2416a8654e3c1a4b74fcc0379dac5294670a1f46 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Tue, 26 Oct 2021 12:35:22 -0700 Subject: 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. --- sys/cmd/rc/code.c | 37 ++++++++++++++++++++++++++++ sys/cmd/rc/exec.c | 25 +++++++++++++++++++ sys/cmd/rc/exec.h | 8 ++++--- sys/cmd/rc/lex.c | 5 +++- sys/cmd/rc/main.c | 1 + sys/cmd/rc/parse.c | 2 +- sys/cmd/rc/rc.h | 6 ++++- sys/cmd/rc/syntax.y | 2 +- sys/cmd/rc/var.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 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 -- cgit v1.2.1