summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Mikkelsen <peter@pmikkelsen.com>2021-06-30 23:30:13 +0000
committerPeter Mikkelsen <peter@pmikkelsen.com>2021-06-30 23:30:13 +0000
commit85adea62d7e8eee9d0e3525d572325db4e58d21a (patch)
treee976789abf464f9868f9a12778285329db785d7a
parentfa83d3f1aba932e99833244ebb38b7415b142bd7 (diff)
Allow the repl to backtrack to give alternative results
-rw-r--r--TODO1
-rw-r--r--eval.c34
-rw-r--r--fns.h2
-rw-r--r--main.c3
-rw-r--r--parser.c2
-rw-r--r--repl.c46
-rw-r--r--stdlib.pl3
7 files changed, 72 insertions, 19 deletions
diff --git a/TODO b/TODO
index 5bb5070..a2783a8 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,3 @@
-* Add a repl
* Stop comparing strings all the time
* Stop copying the entire goal stack into every choicepoint
* Stop creating choicepoints when it is not needed
diff --git a/eval.c b/eval.c
index a3b1e87..e28e5e6 100644
--- a/eval.c
+++ b/eval.c
@@ -14,30 +14,33 @@ Builtin findbuiltin(Term *);
static uvlong clausenr;
int
-evalquery(Term *database, Term *query, Binding **resultbindings)
+evalquery(Term *database, Term *query, Binding **resultbindings, Choicepoint **resultchoicestack)
{
Goal *goals;
- Choicepoint *choicestack = nil;
-
- clausenr = 2; /* Start at two since 0 is for the facts in the database, and 1 is for queries */
+ Choicepoint *choicestack = *resultchoicestack;
+ if(choicestack == 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;
- 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);
- /* Now add the actual goals */
- goals = addgoals(goals, query);
+ clausenr = 2; /* Start at two since 0 is for the facts in the database, and 1 is for queries */
+ }else{
+ goto Backtrack;
+ }
while(goals->goal != nil){
Term *dbstart;
@@ -76,7 +79,9 @@ Retry:
Backtrack:
if(choicestack == nil)
return 0;
- print("Backtracking..\n");
+ if(debug)
+ print("Backtracking..\n");
+
Choicepoint *cp = choicestack;
choicestack = cp->next;
/* freegoals(goals) */
@@ -104,6 +109,7 @@ Backtrack:
}
goals = goals->next;
unify(query, goals->goal, resultbindings);
+ *resultchoicestack = choicestack;
return 1;
}
diff --git a/fns.h b/fns.h
index 6d545e9..aea1ba8 100644
--- a/fns.h
+++ b/fns.h
@@ -15,7 +15,7 @@ Term *mknumber(int, vlong, double);
Term *mkstring(Rune *);
/* eval.c */
-int evalquery(Term *, Term *, Binding **);
+int evalquery(Term *, Term *, Binding **, Choicepoint **);
int unify(Term *, Term *, Binding **);
/* repl.c */
diff --git a/main.c b/main.c
index c30e5f7..cd1485c 100644
--- a/main.c
+++ b/main.c
@@ -43,7 +43,8 @@ main(int argc, char *argv[])
Term *goal;
for(goal = initgoals; goal != nil; goal = goal->next){
Binding *bindings = nil;
- evalquery(database, goal, &bindings);
+ Choicepoint *choicestack = nil;
+ evalquery(database, goal, &bindings, &choicestack);
}
}
diff --git a/parser.c b/parser.c
index d7f750a..5480696 100644
--- a/parser.c
+++ b/parser.c
@@ -81,6 +81,7 @@ Term *prologtext(int);
Term *
parse(int fd, int querymode)
{
+ fd = dup(fd, -1);
parsein = Bfdopen(fd, OREAD);
if(parsein == nil){
print("Could not open file\n");
@@ -95,6 +96,7 @@ parse(int fd, int querymode)
uvlong id = 1;
result = copyterm(result, &id);
}
+ Bterm(parsein);
return result;
}
diff --git a/repl.c b/repl.c
index e81c2f2..2b09596 100644
--- a/repl.c
+++ b/repl.c
@@ -1,9 +1,12 @@
#include <u.h>
#include <libc.h>
+#include <bio.h>
#include "dat.h"
#include "fns.h"
+Rune parsefindmore(int);
+
void
repl(Term *database)
{
@@ -12,7 +15,10 @@ repl(Term *database)
print("?- ");
Term *query = parse(fd, 1);
Binding *bindings = nil;
- int success = evalquery(database, query, &bindings);
+ Choicepoint *choicestack = nil;
+ int success;
+FindMore:
+ success = evalquery(database, query, &bindings, &choicestack);
if(success == 0)
print("false.\n");
else{
@@ -20,10 +26,46 @@ repl(Term *database)
print("true.\n");
else{
while(bindings){
- print("%S = %S\n", bindings->name, prettyprint(bindings->value));
+ print(" %S = %S%s",
+ bindings->name,
+ prettyprint(bindings->value),
+ bindings->next ? " ,\n" : "");
bindings = bindings->next;
}
}
+ if(choicestack != nil){
+ print(" ");
+ if(parsefindmore(fd) == L';'){
+ print(";\n");
+ goto FindMore;
+ }else
+ print(".\n");
+ }else{
+ print(".\n");
+ }
}
}
+}
+
+Rune
+parsefindmore(int fd)
+{
+ int consctl = open("/dev/consctl", OWRITE);
+ if(consctl > 0)
+ write(consctl, "rawon", 5);
+ else{
+ print("Could not open /dev/consctl\n");
+ exits("open");
+ }
+
+ fd = dup(fd, -1);
+ Biobuf *input = Bfdopen(fd, OREAD);
+ Rune peek = Bgetrune(input);
+ Bterm(input);
+
+ if(consctl > 0){
+ write(consctl, "rawoff", 6);
+ close(consctl);
+ }
+ return peek;
} \ No newline at end of file
diff --git a/stdlib.pl b/stdlib.pl
index b0f2160..ecf7417 100644
--- a/stdlib.pl
+++ b/stdlib.pl
@@ -16,10 +16,13 @@ If -> Then :-
If -> Then ; _ :-
If, !, Then.
+
_ -> _ ; Else :-
!, Else.
+
If ; _ :-
If.
+
_ ; Else :-
Else.