diff --git a/ulib/linklist.h b/ulib/linklist.h new file mode 100644 index 0000000..56b07f5 --- /dev/null +++ b/ulib/linklist.h @@ -0,0 +1,45 @@ +#ifndef ULIB_LINKLIST_H_ +#define ULIB_LINKLIST_H_ + +#define LL_APPEND(head, new) \ + do { \ + if ((head) != NULL) { \ + typeof((head)) __tmp; \ + (new)->next = NULL; \ + __tmp = (head); \ + while (__tmp->next != NULL) { \ + __tmp = __tmp->next; \ + } \ + __tmp->next = (new); \ + } else { \ + (new)->next = NULL; \ + (head) = (new); \ + } \ + } while(0) + +#define LL_REMOVE(head, ele) \ + do { \ + typeof((head)) __cur = (head); \ + typeof((head)) __prev = NULL; \ + while (__cur != (ele)) { \ + __prev = __cur; \ + __cur = __cur->next; \ + } \ + if (__prev != NULL) { \ + __prev->next = __cur->next; \ + } \ + } while(0) + +#define LL_FINDPROP(head, out, propname, propvalue) \ + do { \ + typeof((head)) __tmp = (head); \ + while (__tmp) { \ + if (__tmp->propname == (propvalue)) { \ + (out) = __tmp; \ + break; \ + } \ + __tmp = __tmp->next; \ + } \ + } while(0) + +#endif // ULIB_LINKLIST_H_ diff --git a/user/tb/interp.c b/user/tb/interp.c new file mode 100644 index 0000000..87cfc0a --- /dev/null +++ b/user/tb/interp.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "interp.h" +#include "runtime.h" + +static InterpResult RES; + +void tz_init(Tokenizer *tz, const char *str, size_t len) { + tz->str = str; + tz->len = len; + tz->pos = 0; +} + +void tz_free(Tokenizer *tz) { + Token *tk = tz->tokens; + while (tk) { + Token *tmp = tk; + tk = tk->next; + dlfree(tmp); + } +} + +int tz_next(Tokenizer *tz, Token *out) { + while (tz->pos < tz->len && string_chr_isspace(tz->str[tz->pos])) { + tz->pos++; + } + + if (tz->pos >= tz->len) { + return 0; + } + + size_t start = tz->pos; + if (tz->str[start] == '"') { + start++; + do { + tz->pos++; + } while (tz->pos < tz->len && tz->str[tz->pos] != '"'); + tz->pos++; + + out->ptr = tz->str + start; + out->len = tz->pos - start - 1; + + } else { + while (tz->pos < tz->len && !string_chr_isspace(tz->str[tz->pos])) { + tz->pos++; + } + out->ptr = tz->str + start; + out->len = tz->pos - start; + } + + return 1; +} + +void tz_classify(Tokenizer *tz) { + Token *tk = tz->tokens; + while (tk) { + if (tk->ptr[0] == '"' && tk->ptr[tk->len - 1] == '"') { + tk->type = TOK_STRING; + } else { + RtCmd *cmd = RTCMDS; + while (cmd) { + char tmpbuf[0xff] = {0}; + usnprintf(tmpbuf, sizeof(tmpbuf), "%.*s", (int)tk->len, tk->ptr); + if (string_strcmp(tmpbuf, cmd->cmdname) == 0) { + tk->type = TOK_CMD; + tk->cmd = cmd; + break; + } + cmd = cmd->next; + } + } + tk = tk->next; + } +} + +bool interp_readline(char *data, const char **bgptr, const char **endptr) { + static char *nextstart; + if (data) { + nextstart = data; + return true; + } + + if (*nextstart == '\0') { + return false; + } + *bgptr = nextstart; + const char *scn = nextstart; + + for (;;) { + while (*scn != '\0' && *scn != '\n') { + scn++; + } + if (*scn == '\n') { + if (scn > *bgptr && *(scn - 1) == '\\') { + scn--; + nextstart = scn; + *nextstart = ' '; + scn++; + if (*scn == '\n') { + scn++; + } + nextstart = scn; + continue; + } + } + break; + } + + *endptr = scn - 1; + + while (string_chr_isspace(**bgptr) && *bgptr < *endptr) { + (*bgptr)++; + } + + while (string_chr_isspace(**endptr) && *endptr >= *bgptr) { + (*endptr)--; + } + + (*endptr)++; + + if (*scn == '\n') { + scn++; + } + nextstart = scn; + + return true; +} + +bool interp_runstring(const char *string, size_t len, InterpResult **res) { + *res = &RES; + + rt_init(); + bool ok = true; + + const char *bg, *end; + interp_readline((char *)string, NULL, NULL); + while (interp_readline(NULL, &bg, &end)) { + size_t linelen = end - bg; + Tokenizer tz = ZERO(&tz); + tz_init(&tz, bg, linelen); + + Token toktmp = ZERO(&toktmp); + while (tz_next(&tz, &toktmp)) { + Token *tok = dlmalloc(sizeof(*tok)); + tok->ptr = toktmp.ptr; + tok->len = toktmp.len; + LL_APPEND(tz.tokens, tok); + } + + tz_classify(&tz); + + Token *cmdtk = tz.tokens; + if (cmdtk->type != TOK_CMD) { + ok = false; + usprintf(RES.errmsg, "Expected cmd name, but got %.*s", (int)cmdtk->len, cmdtk->ptr); + tz_free(&tz); + goto done; + } + + ok = cmdtk->cmd->fn(cmdtk->next); + if (!ok) { + ok = false; + usprintf(RES.errmsg, "cmd %.*s failed", (int)cmdtk->len, cmdtk->ptr); + tz_free(&tz); + goto done; + } + + tz_free(&tz); + } + +done: + return ok; +} diff --git a/user/tb/interp.h b/user/tb/interp.h new file mode 100644 index 0000000..28cb826 --- /dev/null +++ b/user/tb/interp.h @@ -0,0 +1,37 @@ +#ifndef TB_INTERP_H_ +#define TB_INTERP_H_ + +#include +#include +#include "runtime.h" + +#define INTERP_ERRMSG_BUF_MAX (2048) + +typedef struct { + char errmsg[INTERP_ERRMSG_BUF_MAX]; +} InterpResult; + +typedef struct Token { + struct Token *next; + const char *ptr; + size_t len; + + enum { + TOK_STRING, + TOK_CMD, + } type; + + struct RtCmd *cmd; +} Token; + +typedef struct { + const char *str; + size_t len; + size_t pos; + + Token *tokens; +} Tokenizer; + +bool interp_runstring(const char *string, size_t len, InterpResult **res); + +#endif // TB_INTERP_H_ diff --git a/user/tb/main.c b/user/tb/main.c index b23bf01..eb76bc4 100644 --- a/user/tb/main.c +++ b/user/tb/main.c @@ -13,6 +13,7 @@ #include #include #include +#include "interp.h" struct { char *modestr; @@ -74,6 +75,14 @@ void do_file(char *filepath) { goto done; } + InterpResult *res; + bool ok = interp_runstring((const char *)buf, statbuf.size, &res); + if (!ok) { + uprintf("Interpreter error:\n"); + uprintf("%s\n", res->errmsg); + goto done; + } + done: dlfree(buf); ioctl(ioh, IOCTL_CLOSEF, 0, 0, 0); diff --git a/user/tb/runtime.c b/user/tb/runtime.c new file mode 100644 index 0000000..4957b71 --- /dev/null +++ b/user/tb/runtime.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include "runtime.h" +#include "interp.h" + +RtCmd *RTCMDS = NULL; + +#define RTCMD(name) \ + do { \ + RtCmd *_cmd = dlmalloc(sizeof(*_cmd)); \ + _cmd->cmdname = #name; \ + _cmd->fn = rt_##name; \ + LL_APPEND(RTCMDS, _cmd); \ + } while(0) + +bool rt_print(Token *tks) { + Token *tk = tks; + while (tk) { + uprintf("%.*s", (int)tk->len, tk->ptr); + if (tk->next != NULL) { + uprintf(" "); + } + tk = tk->next; + } + + return true; +} + +void rt_init(void) { + RTCMD(print); +} diff --git a/user/tb/runtime.h b/user/tb/runtime.h new file mode 100644 index 0000000..33fbecd --- /dev/null +++ b/user/tb/runtime.h @@ -0,0 +1,18 @@ +#ifndef TB_RUNTIME_H_ +#define TB_RUNTIME_H_ + +#include + +struct Token; + +typedef struct RtCmd { + struct RtCmd *next; + char *cmdname; + bool (*fn)(struct Token *tks); +} RtCmd; + +void rt_init(void); + +extern RtCmd *RTCMDS; + +#endif // TB_RUNTIME_H_