ref: af0488a8bcb5aeb7a1c263079cb13ec7419c19db
dir: /sys/src/games/linden.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <ctype.h> Biobuf *Bin; typedef struct Symbol Symbol; typedef struct SString SString; enum { TSTRING = -2 }; struct Symbol { Rune name; SString *rule; char *output; Symbol *next; }; struct SString { int n; Symbol **d; }; #pragma varargck type "σ" SString* Symbol *syms; SString *sstring; char strbuf[1024]; void * emalloc(ulong n) { void *v; v = malloc(n); if(v == nil) sysfatal("malloc: %r"); memset(v, 0, n); setmalloctag(v, getcallerpc(&n)); return v; } void sstringaddsym(SString *a, Symbol *b) { a->d = realloc(a->d, (a->n + 1) * sizeof(Symbol *)); a->d[a->n++] = b; } void sstringappend(SString *a, SString *b) { a->d = realloc(a->d, (a->n + b->n) * sizeof(Symbol *)); memcpy(a->d + a->n, b->d, b->n * sizeof(Symbol *)); a->n += b->n; } Symbol * getsym(Rune name) { Symbol **sp; for(sp = &syms; *sp != nil; sp = &(*sp)->next) if(name == (*sp)->name) return *sp; *sp = emalloc(sizeof(Symbol)); (*sp)->name = name; return *sp; } int peektok = -1; int lex(void) { int c; char *p; if(peektok >= 0){ c = peektok; peektok = -1; return c; } do c = Bgetrune(Bin); while(c >= 0 && c < 0x80 && isspace(c) && c != '\n'); if(c == '\''){ p = strbuf; for(;;){ c = Bgetc(Bin); if(c == '\'') break; if(p < strbuf + sizeof(strbuf) - 1) *p++ = c; } *p = 0; return TSTRING; } return c; } int peek(void) { if(peektok >= 0) return peektok; return peektok = lex(); } SString * symstring(void) { int c; SString *r; r = emalloc(sizeof(SString)); for(;;){ c = peek(); if(c == '\n' || c == ':') break; lex(); r->d = realloc(r->d, (r->n + 1) * sizeof(Symbol *)); r->d[r->n++] = getsym(c); } return r; } int fmtsstring(Fmt *f) { SString *s; int i; s = va_arg(f->args, SString *); for(i = 0; i < s->n; i++) fmtprint(f, "%C", s->d[i]->name); return 0; } void syntax(void) { sysfatal("syntax error"); } void parse(void) { Symbol *s; int c; sstring = symstring(); while(peek() > 0){ if(peek() == '\n') {lex(); continue;} if(peek() == ':') syntax(); s = getsym(lex()); c = lex(); if(c == ':') s->rule = symstring(); else if(c == '='){ if(lex() != TSTRING) syntax(); s->output = strdup(strbuf); }else syntax(); c = lex(); if(c != -1 && c != '\n') syntax(); } } SString * iterate(SString *in) { SString *r; int i; r = emalloc(sizeof(SString)); for(i = 0; i < in->n; i++) if(in->d[i]->rule == nil) sstringaddsym(r, in->d[i]); else sstringappend(r, in->d[i]->rule); return r; } void main() { int i, j; fmtinstall(L'σ', fmtsstring); Bin = Bfdopen(0, OREAD); if(Bin == nil) sysfatal("Bfdopen: %r"); parse(); for(j = 0; j < 9; j++){ for(i = 0; i < sstring->n; i++) if(sstring->d[i]->output != nil) print("%s\n", sstring->d[i]->output); print("end\n"); sstring = iterate(sstring); } }