#include <u.h>
#include <libc.h>
#include <thread.h>
#include <bio.h>
#include "debug.h"
#include "lex.h"
#include "sky.h"
#include "dat.h"
#include "fns.h"
Lexer l;
struct Cmdnode *mkcmdnode(void);
Tok cmdeval(Cmdreg* reg, int depth);
int eqsig(Cmd *c1, Cmd *c2);
Tok (*(getfun)(struct Cmdnode*, Cmd*))(Tok*, int);
Cmdreg*
mkcmdreg(int fd)
{
Cmdreg *reg;
if((reg=malloc(sizeof(Cmdreg)))==nil)
return nil;
linit(®->l, fd, lexstart());
if((reg->head=mkcmdnode())==nil){
free(reg);
return nil;
}
return reg;
}
int
cmdregister(Cmdreg *reg, Cmd *c)
{
struct Cmdnode *head;
head = reg->head;
/* the tail node is always pre-allocated but unset */
while(head->next){
if(eqsig(c, head->c)){
head->c->fun = c->fun;
return 0;
}
head=head->next;
}
if((head->next=mkcmdnode())==nil)
return Ememory;
*(head->c) = *c;
return 0;
}
void
cmdterm(Cmdreg *reg)
{
struct Cmdnode *head, *nxt;
head = reg->head;
while(head){
nxt = head->next;
free(head->c);
free(head);
head = nxt;
}
lterm(®->l);
free(reg);
}
Tok
cmdeval(Cmdreg* reg, int depth)
{
struct Cmdnode *head;
Tok t, argv[Cmaxargs];
Cmd c;
Tok (*efun)(Tok*, int);
char *err;
head = reg->head;
memset(&c, 0, sizeof(Cmd));
while(t = lnexttok(®->l), t.typ != Teof){
eval: DBPRINT(20, "cmd.c:cmdeval tok: %d(%S)\n", t.typ, t.str);
switch(t.typ){
case Terror:
err = "parse error";
error: fprint(2, "%s in cmd %S L\"%S\"\n", err, *c.str ? c.str : L"nil", t.str);
return t;
case Tcmd:
runestrncpy(c.str, t.str, Ltoksize+1);
break;
case Tpclose:
if(depth <= 0){
err = "unmatched pclose";
goto error;
}
if((efun = getfun(head, &c)) == nil){
err = "unrecognised function signature";
goto error;
}
if((t = (*efun)(argv, c.argc)), t.typ == Terror){
err = "invalid data";
goto error;
}
DBIF(20) {
fprint(2, "cmd %S with %d arg(s) in reverse:", c.str, c.argc);
while(c.argc--) fprint(2, " %d(%S)", argv[c.argc].typ, argv[c.argc].str);
fprint(2, ": success\n");
}
return t;
case Tpopen:
t = cmdeval(reg, depth+1);
goto eval;
case Tidentifier:
case Tdecimal:
case Tstr:
c.argtyp[c.argc] = t.typ;
argv[c.argc++] = t;
break;
}
}
return t;
}
void
cmdproc(void *reg)
{
Tok t;
while(t = cmdeval(reg, 0), t.typ != Teof){
DBPRINT(20, "cmd.c:cmdproc eval: %d(%S)\n", t.typ, t.str);
}
}
struct Cmdnode*
mkcmdnode(void)
{
struct Cmdnode *h;
if((h=malloc(sizeof(struct Cmdnode)))==nil)
return nil;
memset(h, 0, sizeof(struct Cmdnode));
if((h->c=malloc(sizeof(Cmd)))==nil){
free(h);
return nil;
}
memset(h->c, 0, sizeof(Cmd));
return h;
}
int
eqsig(Cmd *c1, Cmd *c2)
{
int i, *a1, *a2;
if(!c1 || !c2) return 0;
/* negative argc matches any number */
if(runestrncmp(c1->str, c2->str, Ltoksize+1) || c1->argc != c2->argc) return 0;
for(i=0, a1=c1->argtyp, a2=c2->argtyp; i<c1->argc; i++)
if(*a1++ != *a2++) return 0;
return 1;
}
Tok (*(getfun)(struct Cmdnode *h, Cmd *c))(Tok*, int)
{
/* last node is always unset */
while(h->next){
if(eqsig(c, h->c)) return h->c->fun;
h = h->next;
}
return nil;
}
|