plan9front/sys/src/games/linden.c

199 lines
2.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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);
}
}