summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Mikkelsen <peter@pmikkelsen.com>2021-06-30 20:51:02 +0000
committerPeter Mikkelsen <peter@pmikkelsen.com>2021-06-30 20:51:02 +0000
commitff418c798b580204f6fea5512adc36835f8b7efa (patch)
tree71c24b829c2a037653e302adb680f4237fc2a6bb
parenta8b1fadd149126e9c8d3081a56d206812211f1e6 (diff)
Add comparison predicates
-rw-r--r--builtins.c84
-rw-r--r--dat.h7
-rw-r--r--eval.c2
-rw-r--r--fns.h1
-rw-r--r--parser.c10
-rw-r--r--stdlib.pl24
6 files changed, 121 insertions, 7 deletions
diff --git a/builtins.c b/builtins.c
index f66cd5e..6cba6d8 100644
--- a/builtins.c
+++ b/builtins.c
@@ -19,6 +19,9 @@ BuiltinProto(builtincompound);
BuiltinProto(builtinnonvar);
BuiltinProto(builtinnumber);
BuiltinProto(builtinstring);
+BuiltinProto(builtincompare);
+
+int compareterms(Term *, Term *);
Builtin
findbuiltin(Term *goal)
@@ -64,6 +67,8 @@ findbuiltin(Term *goal)
return builtinnumber;
if(Match(L"string", 1))
return builtinstring;
+ if(Match(L"compare", 3))
+ return builtincompare;
return nil;
}
@@ -209,4 +214,83 @@ builtinstring(Term *database, Term *goal, Goal **goals, Choicepoint **choicestac
USED(bindings);
Term *arg = goal->children;
return (arg->tag == StringTerm);
+}
+
+#define Compare(A, B) ((A < B) ? -1 : ((A > B) ? 1 : 0))
+
+int
+compareterms(Term *t1, Term *t2)
+{
+ int result = 0;
+
+ if(t1->tag != t2->tag)
+ result = Compare(t1->tag, t2->tag);
+ else{
+ /* Same type term */
+ switch(t1->tag){
+ case VariableTerm:
+ if(t1->clausenr == t2->clausenr)
+ result = runestrcmp(t1->text, t2->text);
+ else
+ result = Compare(t1->clausenr, t2->clausenr);
+ break;
+ case NumberTerm:
+ if(t1->numbertype == t2->numbertype){
+ if(t1->numbertype == NumberInt)
+ result = Compare(t1->ival, t2->ival);
+ else
+ result = Compare(t1->dval, t2->dval);
+ }else
+ result = Compare(t1->numbertype, t2->numbertype);
+ break;
+ case StringTerm:
+ case AtomTerm:
+ result = runestrcmp(t1->text, t2->text);
+ break;
+ case CompoundTerm:
+ result = Compare(t1->arity, t2->arity);
+ if(result != 0)
+ break;
+
+ result = runestrcmp(t1->text, t2->text);
+ if(result != 0)
+ break;
+
+ t1 = t1->children;
+ t2 = t2->children;
+ while(t1 != nil && t2 != nil){
+ result = compareterms(t1, t2);
+ if(result != 0)
+ break;
+ else
+ t1 = t1->next;
+ t2 = t2->next;
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+int
+builtincompare(Term *database, Term *goal, Goal **goals, Choicepoint **choicestack, Binding **bindings)
+{
+ USED(database);
+ USED(goals);
+ USED(choicestack);
+ Term *order = goal->children;
+ Term *t1 = order->next;
+ Term *t2 = t1->next;
+
+ int result = compareterms(t1, t2);
+
+ Term *resultorder;
+ if(result == -1)
+ resultorder = mkatom(L"<");
+ else if(result == 0)
+ resultorder = mkatom(L"=");
+ else
+ resultorder = mkatom(L">");
+
+ return unify(order, resultorder, bindings);
} \ No newline at end of file
diff --git a/dat.h b/dat.h
index a090afb..2cf28b7 100644
--- a/dat.h
+++ b/dat.h
@@ -40,17 +40,18 @@ struct Choicepoint
Choicepoint *next;
};
+/* Sorted so that a lower value means it comes earlier in the standard ordering */
enum {
- CompoundTerm,
- AtomTerm,
VariableTerm,
NumberTerm,
StringTerm,
+ AtomTerm,
+ CompoundTerm,
};
enum {
- NumberInt,
NumberFloat,
+ NumberInt,
};
int debug;
diff --git a/eval.c b/eval.c
index 3a6ab38..3477141 100644
--- a/eval.c
+++ b/eval.c
@@ -6,7 +6,6 @@
Goal *addgoals(Goal *, Term *);
Term *findclause(Term *, Term *, Binding **);
-int unify(Term *, Term *, Binding **);
int equalterms(Term *, Term *);
void applybinding(Term *, Binding *);
Goal *copygoals(Goal *);
@@ -77,6 +76,7 @@ Retry:
Backtrack:
if(choicestack == nil)
return 0;
+ print("Backtracking..\n");
Choicepoint *cp = choicestack;
choicestack = cp->next;
/* freegoals(goals) */
diff --git a/fns.h b/fns.h
index 54db8dc..6d545e9 100644
--- a/fns.h
+++ b/fns.h
@@ -16,6 +16,7 @@ Term *mkstring(Rune *);
/* eval.c */
int evalquery(Term *, Term *, Binding **);
+int unify(Term *, Term *, Binding **);
/* repl.c */
void repl(Term *);
diff --git a/parser.c b/parser.c
index 577c338..d7f750a 100644
--- a/parser.c
+++ b/parser.c
@@ -264,7 +264,7 @@ parseoperators(Term *list)
for(i = 0, t = list; i < length; i++){
Operator *op = getoperator(t->text);
- if(op && t->tag == AtomTok){
+ if(op && t->tag == AtomTerm){
infos[i].type = op->type;
infos[i].level = op->level;
}else{
@@ -292,7 +292,10 @@ parseoperators(Term *list)
}
if(index == -1){
- print("Can't parse, list contains no operators");
+ print("Can't parse, list of length %d contains no operators: ", length);
+ for(i = 0; i < length; i++)
+ print("%S(%d) ", prettyprint(terms[i]), infos[i].level);
+ print("\n");
syntaxerror("parseoperators");
}
@@ -439,6 +442,7 @@ nexttoken(void)
replaypeek = -1;
}
+SkipWhite:
/* Skip whitespace */
while(isspacerune(peek))
peek = Bgetrune(parsein);
@@ -447,7 +451,7 @@ nexttoken(void)
if(peek == L'%'){
while(peek != L'\n')
peek = Bgetrune(parsein);
- peek = Bgetrune(parsein);
+ goto SkipWhite;
}
/* Variables */
diff --git a/stdlib.pl b/stdlib.pl
index c53cf78..b0f2160 100644
--- a/stdlib.pl
+++ b/stdlib.pl
@@ -28,3 +28,27 @@ A = A.
A \= B :-
\+ A = B.
+
+% Comparison of terms using the standard order
+
+A == B :-
+ compare(=, A, B).
+
+A \== B :-
+ \+ A == B.
+
+A @< B :-
+ compare(<, A, B).
+
+A @=< B :-
+ A == B.
+A @=< B :-
+ A @< B.
+
+A @> B :-
+ compare(>, A, B).
+
+A @>= B :-
+ A == B.
+A @>= B :-
+ A @> B.