shithub: pprolog

Download patch

ref: ff418c798b580204f6fea5512adc36835f8b7efa
parent: a8b1fadd149126e9c8d3081a56d206812211f1e6
author: Peter Mikkelsen <peter@pmikkelsen.com>
date: Wed Jun 30 16:51:02 EDT 2021

Add comparison predicates

--- a/builtins.c
+++ b/builtins.c
@@ -19,7 +19,10 @@
 BuiltinProto(builtinnonvar);
 BuiltinProto(builtinnumber);
 BuiltinProto(builtinstring);
+BuiltinProto(builtincompare);
 
+int compareterms(Term *, Term *);
+
 Builtin
 findbuiltin(Term *goal)
 {
@@ -64,6 +67,8 @@
 		return builtinnumber;
 	if(Match(L"string", 1))
 		return builtinstring;
+	if(Match(L"compare", 3))
+		return builtincompare;
 
 	return nil;
 }
@@ -209,4 +214,83 @@
 	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
--- a/dat.h
+++ b/dat.h
@@ -40,17 +40,18 @@
 	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;
--- 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 @@
 Backtrack:
 				if(choicestack == nil)
 					return 0;
+				print("Backtracking..\n");
 				Choicepoint *cp = choicestack;
 				choicestack = cp->next;
 				/* freegoals(goals) */
--- a/fns.h
+++ b/fns.h
@@ -16,6 +16,7 @@
 
 /* eval.c */
 int evalquery(Term *, Term *, Binding **);
+int unify(Term *, Term *, Binding **);
 
 /* repl.c */
 void repl(Term *);
--- a/parser.c
+++ b/parser.c
@@ -264,7 +264,7 @@
 
 	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 @@
 		}
 
 		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 @@
 		replaypeek = -1;
 	}
 
+SkipWhite:
 	/* Skip whitespace */
 	while(isspacerune(peek))
 		peek = Bgetrune(parsein);
@@ -447,7 +451,7 @@
 	if(peek == L'%'){
 		while(peek != L'\n')
 			peek = Bgetrune(parsein);
-		peek = Bgetrune(parsein);
+		goto SkipWhite;
 	}
 
 	/* Variables */
--- a/stdlib.pl
+++ b/stdlib.pl
@@ -28,3 +28,27 @@
 
 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.