199 lines
2.8 KiB
C
199 lines
2.8 KiB
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);
|
|||
|
}
|
|||
|
}
|