diff options
author | aiju <devnull@localhost> | 2018-03-28 17:08:30 +0000 |
---|---|---|
committer | aiju <devnull@localhost> | 2018-03-28 17:08:30 +0000 |
commit | 382d37dbf0ee8bf5af9594e922db6094e30ace2a (patch) | |
tree | 26d20b8c336da4017376c931fc8f0e507f16c613 /sys/src/cmd/forp/parse.c | |
parent | 80474f7f59ee755cd1967c5703e3be724582f001 (diff) |
add forp
Diffstat (limited to 'sys/src/cmd/forp/parse.c')
-rw-r--r-- | sys/src/cmd/forp/parse.c | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/sys/src/cmd/forp/parse.c b/sys/src/cmd/forp/parse.c new file mode 100644 index 000000000..b813e696a --- /dev/null +++ b/sys/src/cmd/forp/parse.c @@ -0,0 +1,454 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mp.h> +#include "dat.h" +#include "fns.h" + +Biobuf *bin; +Line line; +char lexbuf[512]; +int peektok; + +enum { + TEOF = -1, + TSYM = -2, + TNUM = -3, + TBIT = -4, + TOBVIOUSLY = -5, + TEQ = -6, + TNEQ = -7, + TLSH = -8, + TRSH = -9, + TLE = -10, + TGE = -11, + TLAND = -12, + TLOR = -13, + TASSUME = -14, + TIMP = -15, + TEQV = -16, + TSIGNED = -17, +}; + +typedef struct Keyword Keyword; +typedef struct Oper Oper; +struct Keyword { + char *name; + int tok; +}; +/* both tables must be sorted */ +static Keyword kwtab[] = { + "assume", TASSUME, + "bit", TBIT, + "obviously", TOBVIOUSLY, + "signed", TSIGNED, +}; +/* <=> is implemented through a hack below */ +static Keyword koptab[] = { + "!=", TNEQ, + "&&", TLAND, + "<<", TLSH, + "<=", TLE, + "==", TEQ, + "=>", TIMP, + ">=", TGE, + ">>", TRSH, + "||", TLOR, +}; +static Keyword *kwjmp[128]; +static Keyword *kopjmp[128]; +struct Oper { + int tok; + int type; + int pred; + char *str; +}; +#define MAXPREC 15 +static Oper optab[] = { + '*', OPMUL, 14, "*", + '/', OPDIV, 14, "/", + '%', OPMOD, 14, "%", + '+', OPADD, 13, "+", + '-', OPSUB, 13, "-", + TLSH, OPLSH, 12, "<<", + TRSH, OPRSH, 12, ">>", + '<', OPLT, 11, "<", + TLE, OPLE, 11, "<=", + '>', OPGT, 11, ">", + TGE, OPGE, 11, ">=", + TEQ, OPEQ, 10, "==", + TNEQ, OPNEQ, 10, "!=", + '&', OPAND, 9, "&", + '^', OPXOR, 8, "^", + '|', OPOR, 7, "|", + TLAND, OPLAND, 6, "&&", + TLOR, OPLOR, 5, "||", + TEQV, OPEQV, 4, "<=>", + TIMP, OPIMP, 4, "=>", + /* ?: */ + '=', OPASS, 2, "=", + ',', OPCOMMA, 1, ",", + -1, OPNOT, MAXPREC, "!", + -1, OPCOM, MAXPREC, "~", + -1, OPNEG, MAXPREC, "-", +}; + +void +error(Line *l, char *msg, ...) +{ + char buf[256]; + Fmt f; + va_list va; + + if(l == nil) l = &line; + fmtfdinit(&f, 2, buf, sizeof(buf)); + fmtprint(&f, "%s:%d: ", l->filen, l->lineno); + va_start(va, msg); + fmtvprint(&f, msg, va); + va_end(va); + fmtrune(&f, '\n'); + fmtfdflush(&f); + exits("error"); +} + +static int +tokfmt(Fmt *f) +{ + int t; + Keyword *k; + + t = va_arg(f->args, int); + if(t >= ' ' && t < 0x7f) return fmtprint(f, "%c", t); + for(k = kwtab; k < kwtab + nelem(kwtab); k++) + if(k->tok == t) + return fmtprint(f, "%s", k->name); + for(k = koptab; k < koptab + nelem(koptab); k++) + if(k->tok == t) + return fmtprint(f, "%s", k->name); + switch(t){ + case TSYM: return fmtprint(f, "TSYM"); break; + case TNUM: return fmtprint(f, "TNUM"); break; + case TEOF: return fmtprint(f, "eof"); break; + default: return fmtprint(f, "%d", t); break; + } +} + +static int +exprfmt(Fmt *f) +{ + Node *n; + Oper *o; + int w; + + n = va_arg(f->args, Node *); + if(n == nil) return fmtprint(f, "nil"); + switch(n->type){ + case ASTSYM: return fmtprint(f, "%s", n->sym->name); + case ASTBIN: + for(o = optab; o < optab + nelem(optab); o++) + if(o->type == n->op) + break; + if(o == optab + nelem(optab)) return fmtprint(f, "[unknown operation %O]", n->op); + w = f->width; + if(w > o->pred) fmtrune(f, '('); + fmtprint(f, "%*ε %s %*ε", o->pred, n->n1, o->str, o->pred + 1, n->n2); + if(w > o->pred) fmtrune(f, ')'); + return 0; + case ASTNUM: return fmtprint(f, "0x%B", n->num); + default: return fmtprint(f, "???(%α)", n->type); + } +} + +static int +issymchar(int c) +{ + return c >= 0 && (isalnum(c) || c == '_' || c >= 0x80); +} + +static int +lex(void) +{ + int c, d; + char *p; + Keyword *kw; + + if(peektok != 0){ + c = peektok; + peektok = 0; + return c; + } +loop: + do{ + c = Bgetc(bin); + if(c == '\n') line.lineno++; + }while(c >= 0 && isspace(c)); + if(c < 0) return TEOF; + if(c == '/'){ + c = Bgetc(bin); + if(c == '/'){ + do + c = Bgetc(bin); + while(c >= 0 && c != '\n'); + if(c < 0) return TEOF; + line.lineno++; + goto loop; + }else if(c == '*'){ + s0: + c = Bgetc(bin); + if(c != '*') goto s0; + s1: + c = Bgetc(bin); + if(c == '*') goto s1; + if(c != '/') goto s0; + goto loop; + }else{ + Bungetc(bin); + return '/'; + } + } + if(isdigit(c)){ + p = lexbuf; + *p++ = c; + while(c = Bgetc(bin), issymchar(c)) + if(p < lexbuf + sizeof(lexbuf) - 1) + *p++ = c; + Bungetc(bin); + *p = 0; + strtol(lexbuf, &p, 0); + if(p == lexbuf || *p != 0) + error(nil, "invalid number %q", lexbuf); + return TNUM; + } + if(issymchar(c)){ + p = lexbuf; + *p++ = c; + while(c = Bgetc(bin), issymchar(c)) + if(p < lexbuf + sizeof(lexbuf) - 1) + *p++ = c; + Bungetc(bin); + *p = 0; + c = lexbuf[0]; + if((signed char)c>= 0 && (kw = kwjmp[c], kw != nil)) + for(; kw < kwtab + nelem(kwtab) && kw->name[0] == c; kw++) + if(strcmp(lexbuf, kw->name) == 0) + return kw->tok; + return TSYM; + } + if(kw = kopjmp[c], kw != nil){ + d = Bgetc(bin); + for(; kw < koptab + nelem(koptab) && kw->name[0] == c; kw++) + if(kw->name[1] == d){ + if(kw->tok == TLE){ + c = Bgetc(bin); + if(c == '>') + return TEQV; + Bungetc(bin); + } + return kw->tok; + } + Bungetc(bin); + } + return c; +} + +static void +superman(int t) +{ + assert(peektok == 0); + peektok = t; +} + +static int +peek(void) +{ + if(peektok != 0) return peektok; + return peektok = lex(); +} + +static void +expect(int t) +{ + int s; + + s = lex(); + if(t != s) + error(nil, "expected %t, got %t", t, s); +} + +static int +got(int t) +{ + return peek() == t && (lex(), 1); +} + +static Node * +expr(int level) +{ + Node *a, *b, *c; + Oper *op; + Symbol *s; + mpint *num; + int t; + + if(level == MAXPREC+1){ + switch(t = lex()){ + case '~': return node(ASTUN, OPCOM, expr(level)); + case '!': return node(ASTUN, OPNOT, expr(level)); + case '+': return expr(level); + case '-': return node(ASTUN, OPNEG, expr(level)); + case '(': + a = expr(0); + expect(')'); + return a; + case TSYM: + s = symget(lexbuf); + switch(s->type){ + case SYMNONE: + error(nil, "%#q undefined", s->name); + default: + error(nil, "%#q symbol type error", s->name); + case SYMBITS: + break; + } + return node(ASTSYM, s); + case TNUM: + num = strtomp(lexbuf, nil, 0, nil); + return node(ASTNUM, num); + default: + error(nil, "unexpected %t", t); + } + }else if(level == MAXPREC){ + a = expr(level + 1); + if(got('[')){ + b = expr(0); + if(got(':')) + c = expr(0); + else + c = nil; + expect(']'); + a = node(ASTIDX, a, b, c); + } + return a; + }else if(level == 3){ + a = expr(level + 1); + if(got('?')){ + b = expr(level); + expect(':'); + c = expr(level); + a = node(ASTTERN, a, b, c); + } + return a; + } + a = expr(level+1); + for(;;){ + t = peek(); + for(op = optab; op < optab + nelem(optab); op++) + if(op->tok == t && op->pred >= level) + break; + if(op == optab+nelem(optab)) return a; + lex(); + a = node(ASTBIN, op->type, a, expr(level+1)); + } +} + +static void +vardecl(void) +{ + Symbol *s; + int l, flags; + + flags = 0; + for(;;) + switch(l = lex()){ + case TBIT: if((flags & 1) != 0) goto err; flags |= 1; break; + case TSIGNED: if((flags & 2) != 0) goto err; flags |= 2; break; + default: superman(l); goto out; + } +out: + do{ + expect(TSYM); + s = symget(lexbuf); + if(s->type != SYMNONE) error(nil, "%#q redefined", s->name); + s->type = SYMBITS; + if((flags & 2) != 0) + s->flags |= SYMFSIGNED; + s->size = 1; + if(got('[')){ + expect(TNUM); + s->type = SYMBITS; + s->size = strtol(lexbuf, nil, 0); + expect(']'); + } + s->vars = emalloc(sizeof(int) * s->size); + }while(got(',')); + expect(';'); + return; +err: error(nil, "syntax error"); +} + +static int +statement(void) +{ + Node *n; + int t; + + switch(t=peek()){ + case TEOF: + return 0; + case TBIT: + case TSIGNED: + vardecl(); + break; + case TASSUME: + case TOBVIOUSLY: + lex(); + n = expr(0); + expect(';'); + convert(n, -1); + if(t == TASSUME) + assume(n); + else + obviously(n); + break; + case ';': + lex(); + break; + default: + n = expr(0); + convert(n, -1); + expect(';'); + } + return 1; +} + +void +parsinit(void) +{ + Keyword *k; + + fmtinstall('t', tokfmt); + fmtinstall(L'ε', exprfmt); + for(k = kwtab; k < kwtab + nelem(kwtab); k++) + if(kwjmp[k->name[0]] == nil) + kwjmp[k->name[0]] = k; + for(k = koptab; k < koptab + nelem(koptab); k++) + if(kopjmp[k->name[0]] == nil) + kopjmp[k->name[0]] = k; +} + +void +parse(char *fn) +{ + if(fn == nil){ + bin = Bfdopen(0, OREAD); + line.filen = "<stdin>"; + }else{ + bin = Bopen(fn, OREAD); + line.filen = strdup(fn); + } + if(bin == nil) sysfatal("open: %r"); + line.lineno = 1; + while(statement()) + ; +} |