diff options
author | Peter Mikkelsen <peter@pmikkelsen.com> | 2021-06-30 14:04:15 +0000 |
---|---|---|
committer | Peter Mikkelsen <peter@pmikkelsen.com> | 2021-06-30 14:04:15 +0000 |
commit | ee4298a2cfbbd9e015cfc775d9d714a9f5035846 (patch) | |
tree | 8d6f4b139abf1a645e9e4fe0fba811f64b03839f | |
parent | 79d1fe1cf2eb6748e2c12ffe9c36a678655302b1 (diff) |
Add a basic repl
-rw-r--r-- | dat.h | 10 | ||||
-rw-r--r-- | eval.c | 67 | ||||
-rw-r--r-- | example.pl | 8 | ||||
-rw-r--r-- | fns.h | 7 | ||||
-rw-r--r-- | main.c | 10 | ||||
-rw-r--r-- | mkfile | 2 | ||||
-rw-r--r-- | parser.c | 24 |
7 files changed, 70 insertions, 58 deletions
@@ -1,4 +1,6 @@ typedef struct Term Term; +typedef struct Binding Binding; + struct Term { int tag; @@ -13,6 +15,14 @@ struct Term uvlong clausenr; }; +struct Binding +{ + Rune *name; + uvlong nr; /* Unique number for each clause. Every time a clause is used, it gets a new number. */ + Term *value; + Binding *next; +}; + enum { CompoundTerm, AtomTerm, @@ -4,18 +4,9 @@ #include "dat.h" #include "fns.h" -typedef struct Binding Binding; typedef struct Goal Goal; typedef struct Choicepoint Choicepoint; -struct Binding -{ - Rune *name; - uvlong nr; /* Unique number for each clause. Every time a clause is used, it gets a new number. */ - Term *value; - Binding *next; -}; - struct Goal { Term *goal; @@ -38,15 +29,33 @@ Goal *copygoals(Goal *); static uvlong clausenr; -void -evalquery(Term *database, Term *query) +int +evalquery(Term *database, Term *query, Binding **resultbindings) { - Goal *goals = addgoals(nil, query); + Goal *goals; Choicepoint *choicestack = nil; clausenr = 0; - while(goals != nil){ + /* + The goal stack has the original query at the very bottom, protected by a goal there the ->goal field is nil. + This makes it so that we can continue until we hit the protective goal, at which point we have solved everything + and to get the result we can unify the original query with the one at the bottom of the stack, to get the bindings + applied. + */ + + goals = malloc(sizeof(Goal)); + goals->goal = copyterm(query, nil); + goals->next = nil; + Goal *protector = malloc(sizeof(Goal)); + protector->goal = nil; + protector->next = goals; + goals = protector; + + /* Now add the actual goals */ + goals = addgoals(goals, query); + + while(goals->goal != nil){ Term *dbstart; Term *goal; @@ -54,13 +63,6 @@ evalquery(Term *database, Term *query) Retry: goal = goals->goal; - if(goal == nil){ - goals = goals->next; - continue; - } - - print("Solving goal %S\n", prettyprint(goal)); - /* Find a clause where the head unifies with the goal */ Binding *bindings = nil; Term *clause = findclause(dbstart, goal, &bindings); @@ -74,28 +76,23 @@ Retry: choicestack = cp; } goals = goals->next; - /* Apply bindings to all goals on the top of the stack, down to the "bodystart" goal */ + + /* Apply bindings to all goals on the stack. */ Goal *g; - for(g = goals; g != nil && g->goal != nil; g = g->next) - applybinding(g->goal, bindings); + for(g = goals; g != nil; g = g->next){ + if(g->goal != nil) + applybinding(g->goal, bindings); + } /* Add clause body as goals, with bindings applied */ if(clause->tag == CompoundTerm && clause->arity == 2 && runestrcmp(clause->text, L":-") == 0){ - Goal *bodystart = malloc(sizeof(Goal)); - bodystart->goal = nil; - bodystart->next = goals; - goals = bodystart; - Term *subgoal = copyterm(clause->children->next, nil); applybinding(subgoal, bindings); goals = addgoals(goals, subgoal); } }else{ - if(choicestack == nil){ - print("Fail\n"); - return; - } - print("Backtracking...\n"); + if(choicestack == nil) + return 0; Choicepoint *cp = choicestack; choicestack = cp->next; /* freegoals(goals) */ @@ -105,7 +102,9 @@ Retry: goto Retry; } } - print("Success.\n"); + goals = goals->next; + unify(query, goals->goal, resultbindings); + return 1; } Goal * @@ -1,5 +1,3 @@ -:- dynamic(math/4). - math(A,B,C,D) :- D is A + B + C * A. parentest :- @@ -28,9 +26,3 @@ curly(A) :- A = {one,two,three}. length([], zero). length([Head|Tail], suc(Length)) :- length(Tail, Length). - -:- initialization(could_be_friends(bob, sam)). - -:- initialization(length([a,b,c,d], Len)). - -:- initialization(length(_,_)).
\ No newline at end of file @@ -1,5 +1,5 @@ /* parser.c */ -Term *parse(int); +Term *parse(int, int); /* prettyprint.c */ Rune *prettyprint(Term *); @@ -14,4 +14,7 @@ Term *mkcompound(Rune *, int, Term *); Term *mknumber(int, vlong, double); /* eval.c */ -void evalquery(Term *, Term *);
\ No newline at end of file +int evalquery(Term *, Term *, Binding **); + +/* repl.c */ +void repl(Term *);
\ No newline at end of file @@ -29,11 +29,15 @@ main(int argc, char *argv[]) int fd = open(parsetestfile, OREAD); if(fd < 0) exits("open"); - Term *prog = parse(fd); + Term *database = parse(fd, 0); Term *goal; - for(goal = initgoals; goal != nil; goal = goal->next) - evalquery(prog, goal); + for(goal = initgoals; goal != nil; goal = goal->next){ + Binding *bindings = nil; + evalquery(database, goal, &bindings); + } + + repl(database); } exits(nil); @@ -2,7 +2,7 @@ TARG=pprolog -OFILES=main.$O parser.$O eval.$O prettyprint.$O misc.$O +OFILES=main.$O parser.$O eval.$O prettyprint.$O misc.$O repl.$O HFILES=dat.h fns.h @@ -76,10 +76,10 @@ Term *compound(void); Term *parseoperators(Term *); void match(int); void syntaxerror(char *); -Term *prologtext(void); +Term *prologtext(int); Term * -parse(int fd) +parse(int fd, int querymode) { parsein = Bfdopen(fd, OREAD); if(parsein == nil){ @@ -90,21 +90,25 @@ parse(int fd) initoperators(); nexttoken(); - return prologtext(); + return prologtext(querymode); } Term * -prologtext(void) +prologtext(int querymode) { if(lookahead.tag == EofTok) return nil; Term *t = fullterm(AtomTok, L".", nil); - if(lookahead.tag == AtomTok && runestrcmp(lookahead.text, L".") == 0) - match(AtomTok); - else + if(lookahead.tag == AtomTok && runestrcmp(lookahead.text, L".") == 0){ + if(!querymode) + match(AtomTok); + }else syntaxerror("prologtext"); + if(querymode) + return t; + if(t->tag == CompoundTerm && runestrcmp(t->text, L":-") == 0 && t->arity == 1){ Term *body = t->children; print("Got directive: %S\n", prettyprint(body)); @@ -113,11 +117,11 @@ prologtext(void) initgoals = body->children; initgoals->next = tmp; } - t = prologtext(); + t = prologtext(querymode); }else if(t->tag == CompoundTerm && runestrcmp(t->text, L":-") == 0 && t->arity == 2){ - t->next = prologtext(); + t->next = prologtext(querymode); }else if(t->tag == AtomTerm || t->tag == CompoundTerm){ - t->next = prologtext(); + t->next = prologtext(querymode); }else{ print("Expected directive or clause as toplevel\n"); syntaxerror("prologtext"); |