diff --git a/metadata/checksums.csv b/metadata/checksums.csv index f9620cc..45b040e 100644 --- a/metadata/checksums.csv +++ b/metadata/checksums.csv @@ -1 +1,2 @@ path,size,sha256 +/home/runner/work/C-Prolog-Workbench/C-Prolog-Workbench/raw_materials/c-prolog-1.5/c-prolog.tar.gz,360515,6db9e4db921ba3758b4d7c0dbd40e5d5325fcb4b07e0f97265bd065bf534fdf5 diff --git a/metadata/journal.md b/metadata/journal.md index 7a00d2f..79bac11 100644 --- a/metadata/journal.md +++ b/metadata/journal.md @@ -1 +1,6 @@ # Curation journal + +## 2026-07-03 + +Recorded checksums for: +- /home/runner/work/C-Prolog-Workbench/C-Prolog-Workbench/raw_materials/c-prolog-1.5/c-prolog.tar.gz (360515 bytes) sha256=6db9e4db921ba3758b4d7c0dbd40e5d5325fcb4b07e0f97265bd065bf534fdf5 diff --git a/source_code/README.md b/source_code/README.md deleted file mode 100644 index 132b864..0000000 --- a/source_code/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This folder is for the curated revision of the source code, which should be organized putting in a separated folder each major version of the code, in view of the recontruction of the development history as a new git repository. - -Please refer to the [SWHAPPE](https://github.com/Unipisa/SWHAPPE) guidelines for greater details. diff --git a/source_code/c-prolog-1982/._copyrigh.t b/source_code/c-prolog-1982/._copyrigh.t new file mode 100755 index 0000000..4dd48d7 Binary files /dev/null and b/source_code/c-prolog-1982/._copyrigh.t differ diff --git a/source_code/c-prolog-1982/arith.c b/source_code/c-prolog-1982/arith.c new file mode 100755 index 0000000..6af6520 --- /dev/null +++ b/source_code/c-prolog-1982/arith.c @@ -0,0 +1,530 @@ +/********************************************************************** +* * +* C-Prolog: arith.c * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982, 1983, * +* Fernando Pereira, Luis Damas and Lawrence Byrd. * +* * +* Improvements by Richard O'Keefe and Fernando Pereira, 1983 * +* * +**********************************************************************/ +/* Evaluate arithmetic expressions */ + +#include "pl.h" +#include "arithop.h" +#include +#include + +#define NEVER 0 +#define SOMETIMES 1 +#define ALWAYS 2 + +double +ffail() +{ + ArithError("internal error - undefined operator"); +} + +extern double sin(), asin(), exp(), sqrt(); +extern double cos(), acos(), log(), floor(); +extern double tan(), atan(), log10(); + +extern int brklev; + +static double (*UFloat[])() = { + ffail, + ffail, + ffail, + ffail, + exp, + log, + log10, + sqrt, + sin, + cos, + tan, + asin, + acos, + atan, + floor, + ffail +}; + +static char floatable[] = { /* code arity function */ + NEVER, /* 0 - UNUSABLE */ + NEVER, /* 1 1 ID */ + SOMETIMES, /* 2 1 - */ + NEVER, /* 3 1 \ */ + ALWAYS, /* 4 1 exp */ + ALWAYS, /* 5 1 log */ + ALWAYS, /* 6 1 log10 */ + ALWAYS, /* 7 1 sqrt */ + ALWAYS, /* 8 1 sin */ + ALWAYS, /* 9 1 cos */ + ALWAYS, /* 10 1 tan */ + ALWAYS, /* 11 1 asin */ + ALWAYS, /* 12 1 acos */ + ALWAYS, /* 13 1 atan */ + SOMETIMES, /* 14 1 floor */ + SOMETIMES, /* 15 1 SPARE */ + ALWAYS, /* 16 - UNUSABLE */ + SOMETIMES, /* 1 2 + */ + SOMETIMES, /* 2 2 - */ + SOMETIMES, /* 3 2 * */ + ALWAYS, /* 4 2 / */ + NEVER, /* 5 2 mod */ + NEVER, /* 6 2 /\ */ + NEVER, /* 7 2 \/ */ + NEVER, /* 8 2 << */ + NEVER, /* 9 2 >> */ + NEVER, /* 10 2 // */ + ALWAYS, /* 11 2 ^ */ + NEVER, /* 12 2 SPARE */ + NEVER, /* 13 2 SPARE */ + NEVER, /* 14 2 SPARE */ + NEVER /* 15 2 SPARE */ +}; + + +typedef struct { + char Float; + union { + int asInt; + double asFloat; + } val; +} Value; + +#define AsInt val.asInt +#define AsFloat val.asFloat + +int AllFloat = TRUE; + +static Value unary(), binary(); + +static Value +eval(t,g) +PTR t, g; +/* traverses a term producing its val and type. + t is the term (derefed and unwrapped), + g is the associated global frame (if t is a skel) +*/ +{ + int b, n, i, typ, fl; PTR f1, f2, arg1, arg2; Value v1, v2; + FUNCTOR *fn; + + if (IsRef(t) && Undef(*t)) /* undefined cell */ + NotNumber(); + if (IsPrim(t)) { /* primitive type */ + if (IsInt(t)) { /* integer */ + v1.Float = FALSE; + v1.AsInt = XtrInt(t); + return v1; + } + if (IsFloat(t)) { /* float */ + v1.Float = TRUE; + v1.AsFloat = XtrFloat(t); + return v1; + } + NotNumber(); /* non-number */ + } + /* atom or skel */ + /* grab expression info field */ + fn = FunctorP(SkelP(t)->Fn); + b = (fn->flgsoffe)&0x1f; + if (!b) NotOp(fn); + if (IsAtomic(t)) { /* atom */ + switch (b) { + case TIME: + v1.Float = TRUE; + v1.AsFloat = CPUTime(); + return v1; + case HEAP: + v1.Float = FALSE; + v1.AsInt = HeapUsed(); + return v1; + case BREAKLEV: + v1.Float = FALSE; + v1.AsInt = brklev; + return v1; + default: + NotOp(fn); + } + } + /* skel (first check for [_]) */ + if (fn == FunctorP(listfunc)) { + if (argv(Addr(SkelP(t)->Arg2),g,&f1) != atomnil) + ArithError("not a string"); + arg1 = argv(Addr(SkelP(t)->Arg1),g,&f1); + return eval(arg1,f1); + } + /* skel (general case) */ + n = fn->arityoffe; /* grab arity */ + if (n > 2) NotOp(fn); + switch (n) { + case 1: /* unary */ + arg1 = argv(++t,g,&f1); + return unary(b,arg1,f1); + case 2: /* binary */ + arg1 = argv(++t,g,&f1); + arg2 = argv(++t,g,&f2); + return binary(b, arg1, arg2, f1, f2); + default: + ffail(); + } +} + +static Value +unary(op,arg,env) +int op; PTR arg, env; +{ + int fl = floatable[op], typ; + Value v; + + typ = fl-(1-AllFloat) > 0; + errno = 0; /* no errors */ + v = eval(arg,env); + if (fl == NEVER) { + if (!ForceInt(&v)) NotInt(); + } else + if (v.Float) + typ = TRUE; + else if (typ) { + v.AsFloat = (double)(v.AsInt); + v.Float = TRUE; + } + switch (op) { + case ID: + break; + case UMINUS: + if (typ) v.AsFloat = -v.AsFloat; + else v.AsInt = -v.AsInt; + break; + case NOT: + v.AsInt = ~v.AsInt; + break; + default: /* ALWAYS functions */ + v.AsFloat = (*UFloat[op])(v.AsFloat); + } + if (errno != 0) ArithError(SysError()); + return v; +} + +static Value +binary(op,arg1,arg2,env1, env2) +int op; PTR arg1, arg2, env1, env2; +{ + Value v1, v2; + int fl = floatable[op+16], typ; + + v1 = eval(arg1,env1); + v2 = eval(arg2,env2); + typ = fl-(1-AllFloat) > 0; + errno = 0; /* no errors */ + if (fl == NEVER) { + if (!ForceInt(&v1)) NotInt(); + if (!ForceInt(&v2)) NotInt(); + } else { + typ |= v1.Float | v2.Float; + if (typ) { /* coerce both args. to float */ + if (!v1.Float) v1.AsFloat = (double)(v1.AsInt); + if (!v2.Float) v2.AsFloat = (double)(v2.AsInt); + } + v2.Float = typ; + } + switch (op) { + case PLUS: + if (typ) + v2.AsFloat = v1.AsFloat+v2.AsFloat; + else + v2.AsInt = v1.AsInt+v2.AsInt; + break; + case MINUS: + if (typ) + v2.AsFloat = v1.AsFloat-v2.AsFloat; + else + v2.AsInt = v1.AsInt-v2.AsInt; + break; + case TIMES: + if (typ) + v2.AsFloat = v1.AsFloat*v2.AsFloat; + else + v2.AsInt = v1.AsInt*v2.AsInt; + break; + case DIVIDE: + if (typ) + v2.AsFloat = v1.AsFloat/v2.AsFloat; + else + v2.AsInt = v1.AsInt/v2.AsInt; + break; + case MOD: + v2.AsInt = v1.AsInt%v2.AsInt; + return v2; + case AND: + v2.AsInt = v1.AsInt&v2.AsInt; + return v2; + case OR: + v2.AsInt = v1.AsInt|v2.AsInt; + return v2; + case LSHIFT: + v2.AsInt = v1.AsInt<>v2.AsInt; + return v2; + case IDIV: + v2.AsInt = v1.AsInt/v2.AsInt; + return v2; + case POW: + v2.AsFloat = pow(v1.AsFloat,v2.AsFloat); + return v2; + default: + ffail(); + } + if (errno) ArithError(SysError()); + return v2; +} + +int +intval(p) +PTR p; +/* Evaluates an expression as an integer, causes an event if + the value is not an integer */ +{ + PTR f, v; Value r; + + v = vvalue(p,&f); + r = eval(v,f); + if (r.Float) { + r.Float = !Narrow(r.AsFloat, &(r.AsInt)); + if (r.Float) ArithError("Integer expected"); + } + return r.AsInt; +} + +PTR +numeval(p) +PTR p; +/* Evaluates expression p and returns a number representation */ +{ + PTR f, v; + Value r; + + v = vvalue(p,&f); + r = eval(v,f); + if (r.Float) + r.Float = !Narrow(r.AsFloat, &(r.AsInt)); + if (r.Float) + return ConsFloat(r.AsFloat); + else + return ConsInt(r.AsInt); +} + +PTR +Unary(op,v) +int op; PTR v; +/* Applies op to x and returns a number representation */ +{ + Value r; PTR f; + + v = vvalue(v,&f); + r = unary(op,v,f); + if (r.Float) + r.Float = !Narrow(r.AsFloat, &(r.AsInt)); + if (r.Float) + return ConsFloat(r.AsFloat); + else + return ConsInt(r.AsInt); +} + +PTR +Binary(op,v1,v2) +int op; PTR v1, v2; +/* Applies op to v1 and v2 and returns a number representation */ +{ + Value r; PTR f1, f2; + + v1 = vvalue(v1,&f1); + v2 = vvalue(v2,&f2); + r = binary(op,v1,v2,f1,f2); + if (r.Float) + r.Float = !Narrow(r.AsFloat, &(r.AsInt)); + if (r.Float) + return ConsFloat(r.AsFloat); + else + return ConsInt(r.AsInt); +} + +int +numcompare(op,t1,t2) +int op; +PTR t1, t2; +/* Applies comparison operation op to expressions t1 and t2 */ +{ + PTR f, t; + Value v1, v2; + + t = vvalue(t1,&f); + v1 = eval(t,f); + t = vvalue(t2,&f); + v2 = eval(t,f); + if (v1.Float || v2.Float) { + if (!v1.Float) v1.AsFloat = (double)(v1.AsInt); + if (!v2.Float) v2.AsFloat = (double)(v2.AsInt); + switch (op) { + case EQ: return v1.AsFloat == v2.AsFloat; + case NE: return v1.AsFloat != v2.AsFloat; + case LT: return v1.AsFloat < v2.AsFloat; + case GT: return v1.AsFloat > v2.AsFloat; + case LE: return v1.AsFloat <= v2.AsFloat; + case GE: return v1.AsFloat >= v2.AsFloat; + default: return NEVER; + } + } + switch (op) { + case EQ: return v1.AsInt == v2.AsInt; + case NE: return v1.AsInt != v2.AsInt; + case LT: return v1.AsInt < v2.AsInt; + case GT: return v1.AsInt > v2.AsInt; + case LE: return v1.AsInt <= v2.AsInt; + case GE: return v1.AsInt >= v2.AsInt; + default: return NEVER; + } +} + +int +intsign(n1,n2) +PTR n1, n2; +/* returns the sign of the difference between numbers t1 and t2 */ +{ + double v1, v2; + + v1 = IsInt(n1) ? (double)XtrInt(n1) : XtrFloat(n1); + v2 = IsInt(n2) ? (double)XtrInt(n2) : XtrFloat(n2); + return (v1 > v2) ? 1 : ((v1 < v2) ? -1 : 0); +} + +/* ====================================================================== + +These two functions are totally dependant on the float representation +of the machine. The type tag for a constructed float is binary 110 +in the most significant bits of a 32 bit word. To fit a machine +float into a constructed float, the 3 least significant bits of the +mantissa are dropped. In the VAX F_floating format, the lowest +significance bits are on the right in the second 16 bit word +of the value. + +The code given here for the Perq appears to work. + +In the IEEE single precision floating point, the lowest significant bits +are on the right. + +*/ + +typedef union { +#ifdef vax + struct { + short loword; + short hiword; + } aswords; +#endif +#ifdef IEEE + unsigned asunsigned; +#endif + float asfloat; + PTR asPTR; + } Mixed; + +PTR +ConsFloat(f) + float f; + { + Mixed m; + + m.asfloat = f; +#ifdef vax + m.aswords.hiword = ((m.aswords.hiword>>3)&0x1fff)|(FLOAT_TAG>>16); +#endif +#ifdef IEEE + m.asunsigned = (m.asunsigned>>3)|FLOAT_TAG; +#endif + return m.asPTR; + } + +float +XtrFloat(p) + PTR p; + { + Mixed m; + + m.asPTR = p; +#ifdef Perq + m.aslong <<= 3; +#endif +#ifdef vax + m.aswords.hiword <<= 3; +#endif +#ifdef IEEE + m.asunsigned <<= 3; +#endif + return m.asfloat; + } + +/* ====================================================================== */ + +int +Narrow(f,i) + double f; int *i; + { + register int k; + + if (f < MinInt || f > MaxInt) return FALSE; + if ((double)(k = (int)f) != f) return FALSE; + *i = k; + return TRUE; + } + +static int +ForceInt(v) + register Value *v; + { + if (v->Float) v->Float = !Narrow(v->AsFloat, &(v->AsInt)); + return !v->Float; + } + +ArithError(s) + char *s; + { + ErrorMess = s; + Event(ARITH_ERROR); + } + +NotNumber() + { + ArithError("not a number"); + } + +static +NotInt() + { + ArithError("arithmetic operation requires integers"); + } + +static +NotOp(fn) + FUNCTOR *fn; + { + sprintf(OutBuf, + fn->arityoffe + ? "%s is not an arithmetic operator" + : "%s is not a number", + AtomP(fn->atoffe)->stofae); + ArithError(OutBuf); + } + diff --git a/source_code/c-prolog-1982/arith.o b/source_code/c-prolog-1982/arith.o new file mode 100755 index 0000000..bdb56a9 Binary files /dev/null and b/source_code/c-prolog-1982/arith.o differ diff --git a/source_code/c-prolog-1982/arithop.h b/source_code/c-prolog-1982/arithop.h new file mode 100755 index 0000000..3b49d83 --- /dev/null +++ b/source_code/c-prolog-1982/arithop.h @@ -0,0 +1,60 @@ +/********************************************************************** +* * +* C Prolog arithop.h * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ +/* Internal codes for the arithmetic comparison operators */ + +#define EQ 0 /* =:= */ +#define NE 1 /* \= */ +#define LT 2 /* < */ +#define GT 3 /* > */ +#define LE 4 /* =< */ +#define GE 5 /* >= */ + +/* nullary */ + +#define TIME 1 +#define HEAP 2 +#define BREAKLEV 3 + +/* unary */ + +#define ID 1 +#define UMINUS 2 +#define NOT 3 +#define EXP 4 +#define LOG 5 +#define LOG10 6 +#define SQRT 7 +#define SIN 8 +#define COS 9 +#define TAN 10 +#define ASIN 11 +#define ACOS 12 +#define ATAN 13 +#define FLOOR 14 + +/* binary */ + +#define PLUS 1 +#define MINUS 2 +#define TIMES 3 +#define DIVIDE 4 +#define MOD 5 +#define AND 6 +#define OR 7 +#define LSHIFT 8 +#define RSHIFT 9 +#define IDIV 10 +#define POW 11 diff --git a/source_code/c-prolog-1982/auxfn.c b/source_code/c-prolog-1982/auxfn.c new file mode 100755 index 0000000..c1824e5 --- /dev/null +++ b/source_code/c-prolog-1982/auxfn.c @@ -0,0 +1,210 @@ +/********************************************************************** +* * +* C Prolog auxfn.c * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ + +#include "pl.h" + +PTR +fentry(atom,arity) +PTR atom; int arity; +{ + register PTR fe, ne, p; int i; + + for (fe = atom;; fe = FunctorP(fe)->nxtoffe) + if (FunctorP(fe)->arityoffe == arity) + return fe; + else if (Undef(FunctorP(fe)->nxtoffe)) + break; + ne = getsp(szoffe+arity); + Unsafe(); + FunctorP(ne)->atoffe = atom; FunctorP(ne)->infoffe = 0; + FunctorP(ne)->arityoffe = arity; + FunctorP(ne)->FClauses.First = FunctorP(ne)->FClauses.Last = NULL; + FunctorP(ne)->FRecords.First = FunctorP(ne)->FRecords.Last = NULL; + FunctorP(ne)->nxtoffe = NULL; + FunctorP(fe)->nxtoffe = ne; + p = Addr(FunctorP(ne)->gtoffe); + for (i = 0; i < arity; i++) + *++p = SkelGlobal(i); + FunctorP(ne)->gtoffe = ne; + Safe(); + return ne; +} + +PTR +apply(at,n,args) +PTR at; register PTR args; register int n; +{ + PTR sk, s; register PTR r; + sk = Addr(FunctorP(fentry(at,n))->gtoffe); + s = r = v1; GrowGlobal(n); + while (n-- > 0) + *r++ = *args++; + ConsMol(sk,s,r); + return r; +} + +PTR +makelist(n,elms) +int n; PTR elms; +{ + register PTR p; PTR f; register int i; register PTR r; + p = elms+n-1; + for (; n > 10; n -= 9) { + f = r = v1; GrowGlobal(10); + for (i = 0; i < 10; i++) + *r++ = *p--; + ConsMol(List10,f,*++p); + } + f = r = v1; GrowGlobal(n); + for (i = 0; i < n; i++) + *r++ = *p--; + ConsMol(List10+(10-n)*3,f,r); + return r; +} + +int +list_to_string(t,s,n) +PTR t; +char *s; +int n; +{ + int c; + PTR e, a; + + if (t == atomnil) { + *s = '\0'; + return TRUE; + } + if (IsInp(t) || Undef(*t)) return FALSE; + e = MolP(t)->Env; t = MolP(t)->Sk; + while (t != atomnil) { + if (IsAtomic(t) || IsVar(t) || SkelP(t)->Fn != listfunc) return FALSE; + if (n-- <= 0) return FALSE; + a = arg(Addr(SkelP(t)->Arg1),e); + t = argv(Addr(SkelP(t)->Arg2),e,&e); + if (!IsInt(a)) return FALSE; + c = XtrInt(a); + if (c < 0 || c > 255) return FALSE; + *s++ = c; + } + *s = 0; + return TRUE; +} + +/* Print execution statistics */ + +Statistics() +{ + int i; PTR p; + + + for (i = 0; i < NAreas; i++) + printf("%s: %dK (in use: %d, max. used: %d)\n", + AreaName[i], Size[i]/K, used(i), tide(i)); + printf("Runtime: %8.2f sec.\n", CPUTime()); +} + +static int +used(a) +int a; +{ + int u; + + switch (a) { + case AtomId: u = sizeof(PTR)*(atomfp-atom0); break; + case AuxId: u = sizeof(PTR)*(vrz-auxstk0); break; + case TrailId: u = sizeof(PTR)*(tr-trbase); break; + case HeapId: u = HeapUsed(); break; + case GlobalId: u = sizeof(PTR)*(v1-glb0); break; + case LocalId: u = sizeof(PTR)*(v-lcl0); break; + default: u = 0; + } + return u; +} + +static int +tide(a) +int a; +{ + int u; + + switch (a) { + case HeapId: u = HeapTide(); break; + case AtomId: u = sizeof(PTR)*(atomfp-atom0); break; + case AuxId: + case TrailId: + case GlobalId: + case LocalId: u = sizeof(PTR)*(Tide[a]-Origin[a]); break; + default: u = 0; + } + return u; +} + +/* Atom hash function */ + +static PTR +string_to_atom(name,app) +char *name; PTR **app; +{ + register unsigned int h; register ATOM **ap; register char *s = name; + + h = strlen(s); + while (*s) h += *s++; + for (ap = (ATOM **)(hasha+h%HASHSIZE); *ap; + ap = (ATOM **)Addr((*ap)->nxtofae)) + if (strcmp((*ap)->stofae,name) == 0) break; + *app = (PTR*)ap; + return *ap; +} + +/* Intern a string to get a prolog atom */ + +PTR +lookup(id) +char *id; +{ + PTR old, ptr, new; + + if (old = string_to_atom(id,&ptr)) return old; + new = atomfp; + GrowAtom(Words(szofae+strlen(id))); + Unsafe(); + *ptr = new; ptr = new; + AtomP(ptr)->atofae = ptr; + AtomP(ptr)->infofae = 0; + AtomP(ptr)->infxofae = + AtomP(ptr)->prfxofae = AtomP(ptr)->psfxofae = -1; + AtomP(ptr)->AClauses.First = AtomP(ptr)->AClauses.Last = NULL; + AtomP(ptr)->ARecords.First = AtomP(ptr)->ARecords.Last = NULL; + AtomP(ptr)->fcofae = NULL; + AtomP(ptr)->nxtofae = NULL; + strcpy(AtomP(ptr)->stofae,id); + Safe(); + return ptr; +} + +int +hide_atom(a) +ATOM *a; +{ + PTR *aa; PTR *lostatoms = CellP(hasha+HASHSIZE); + + if (!string_to_atom(a->stofae,&aa)) return FALSE; + *aa = a->nxtofae; + a->nxtofae = *lostatoms; + *lostatoms = (PTR)a; + return TRUE; +} diff --git a/source_code/c-prolog-1982/auxfn.o b/source_code/c-prolog-1982/auxfn.o new file mode 100755 index 0000000..54a103f Binary files /dev/null and b/source_code/c-prolog-1982/auxfn.o differ diff --git a/source_code/c-prolog-1982/bootcmd b/source_code/c-prolog-1982/bootcmd new file mode 100755 index 0000000..39431dd --- /dev/null +++ b/source_code/c-prolog-1982/bootcmd @@ -0,0 +1,2 @@ +['pl/all']. +:-save(startup). diff --git a/source_code/c-prolog-1982/compare.c b/source_code/c-prolog-1982/compare.c new file mode 100755 index 0000000..46d8565 --- /dev/null +++ b/source_code/c-prolog-1982/compare.c @@ -0,0 +1,68 @@ +/********************************************************************** +* * +* C Prolog compare.c * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ +#include "pl.h" + +/* Returns the compare code of t, where t is atomic, unasigned or + a skeleton. + The compare codes are: + + variable: -2, primitive: -1, atom: 0, skeleton: its arity +*/ +#define code(t) (IsRef(t) ? -2 : (IsPrim(t) ? -1 : SkelP(t)->Fn->arityoffe)) + +compare(T1,T2) +PTR T1, T2; +/* Returns the comparison value between T1 and T2 */ +{ + PTR E1, E2; + + E1 = E2 = NULL; + T1 = vvalue(T1,&E1); + T2 = vvalue(T2,&E2); + return comp(T1,E1,T2,E2); +} + +static comp(T1,E1,T2,E2) +PTR T1, E1, T2, E2; +{ + PTR t1, e1, t2, e2; int d1, d; + + if (T1 == T2 && E1 == E2) return 0; + d1 = code(T1); + d = d1 - code(T2); + if (d) return d; /* If codes different return difference */ + if (d1 < 0) { /* Both vars. or primitives */ + if (IsNumber(T1)) /* Both numbers */ + return intsign(T1,T2); + else + return T1-T2; /* Both variables or pointers */ + } + /* both atoms or molecules */ + if (SkelP(T1)->Fn == SkelP(T2)->Fn) { + /* same functors (can't be atoms) */ + while (d1-- > 0) { + t1 = argv(++T1,E1,&e1); + t2 = argv(++T2,E2,&e2); + if (d = comp(t1,e1,t2,e2)) + break; + } + return d; + } + /* compare names */ + return strcmp(SkelP(T1)->Fn->atoffe->stofae, + SkelP(T2)->Fn->atoffe->stofae); +} + diff --git a/source_code/c-prolog-1982/compare.o b/source_code/c-prolog-1982/compare.o new file mode 100755 index 0000000..17c765b Binary files /dev/null and b/source_code/c-prolog-1982/compare.o differ diff --git a/source_code/c-prolog-1982/copyrigh.t b/source_code/c-prolog-1982/copyrigh.t new file mode 100755 index 0000000..5f4dd41 --- /dev/null +++ b/source_code/c-prolog-1982/copyrigh.t @@ -0,0 +1,15 @@ +/********************************************************************** +* * +* C Prolog * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ diff --git a/source_code/c-prolog-1982/dbase.c b/source_code/c-prolog-1982/dbase.c new file mode 100755 index 0000000..42f621a --- /dev/null +++ b/source_code/c-prolog-1982/dbase.c @@ -0,0 +1,519 @@ +/********************************************************************** +* * +* C Prolog dbase.c * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ + +#include "pl.h" + +#define Twice 1 +#define OnHead 2 +#define OnBody 4 +#define Global 8 + +extern int InBoot; + +static PTR vid[MAX_VAR+2], vn[MAX_VAR+2]; +static int nvars, lev, nt, nl, ng, toomany, refsflg, onhead; +static PTR i, f, g, k, r, head, body, argx; + +static int +LookVar(vi) +PTR vi; +/* lookup a variable */ +{ + int i; + + for (i = 0; i < nvars; i++) + if (vid[i] == vi) return i; + if (nvars > MAX_VAR) { + toomany = TRUE; + return MAX_VAR; + } + vid[nvars] = vi; vn[nvars] = 0; + return nvars++; +} + +PTR +heapify(t,g) +PTR t, g; +{ + int n; PTR p1, p3, f; unsigned p2; + if (IsPrim(t) && IsDBRef(t)) /* if database reference */ + XtrDBRef(t)->refcofcl++; /* increment ref count of refed term */ + if (IsAtomic(t)) + return t; /* nothing to store for atomic terms */ + if (Undef(*t)) { /* if variable */ + n = LookVar(t); /* look it up in variable table */ + p2 = vn[n]; /* get variable properties */ + if (p2) /* if previously used */ + p2 |= Twice; /* mark as multiple occurrence */ + if (onhead) /* if processing clause head */ + p2 |= OnHead; /* mark as such */ + else + p2 |= OnBody; /* else mark as body variable */ + if (lev > 1) /* if not at outer level */ + p2 |= Global; /* mark as global */ + vn[n] = p2; /* store updated properties */ + p2 = SkelGlobal(n); /* make variable prototype (global n) */ + if ((!lev) && !onhead) { /* handle variable goal */ + p1 = getsp(SkelSz(1)); /* by converting into call(X) */ + SkelP(p1)->Fn = calltag; SkelP(p1)->Arg1 = p2; + return p1; + } + return p2; /* return variable prototype */ + } + if(IsRef(t)) /* compound term */ + g = MolP(t)->Env, t = MolP(t)->Sk; /* extract skel and env */ + n = FunctorP(*t)->arityoffe; /* arity of functor */ + p1 = getsp(SkelSz(n)); /* make term vector */ + SkelP(p1)->Fn = SkelP(t)->Fn; p3 = Addr(SkelP(p1)->Arg1); lev++; + for (; n>0; n--) /* do term arguments */ + argx = argv(++t,g,&f), *p3++ = heapify(argx,f); + lev--; + return p1; /* return heapified term */ +} + +PTR +heapifybody(t,g) +PTR t, g; +{ + PTR p1, f; + + if (IsAtomic(t) || Undef(*t)) + return heapify(t,g); + if (IsRef(t)) + g = MolP(t)->Env, t = MolP(t)->Sk; + if (SkelP(t)->Fn == commatag) { + p1 = getsp(SkelSz(2)); + SkelP(p1)->Fn = commatag; + argx = argv(Addr(SkelP(t)->Arg1),g,&f); + SkelP(p1)->Arg1 = heapify(argx,f); + argx = argv(Addr(SkelP(t)->Arg2),g,&f); + SkelP(p1)->Arg2 = heapifybody(argx,f); + return p1; + } + return heapify(t,g); +} + +static +scan(c) +PTR c; +{ + int n; + + if (IsVar(*c)) { + *c = *CellP(CharP(vn)+VarNo(*c)); + return; + } + if (IsAtomic(*c)) + return; + c = *c; n = FunctorP(SkelP(c)->Fn)->arityoffe; + for (; n > 0; n--) + scan(++c); +} +PTR +record(key, t, rk, aorz) +PTR t, rk; int key, aorz; +{ + int j; PTR proclist; + + nvars = 0; toomany = FALSE; refsflg = FALSE; + if(IsRef(t) && !Undef(*t)) + g = MolP(t)->Env, t = MolP(t)->Sk; + if (key == RECORD) + goto dbase; + /* asserting a clause */ + lev = 0; onhead = TRUE; + if (IsComp(t) && (SkelP(t)->Fn == arrowtag)) { + argx = argv(Addr(SkelP(t)->Arg1),g,&f), head = heapify(argx,f); + onhead = FALSE; + argx = argv(Addr(SkelP(t)->Arg2),g,&f), body = heapifybody(argx,f); + } else { + head = heapify(t,g); + body = NULL; + } + if (IsVar(head)) { + ErrorMess ="! Clause head is a variable (assert)"; + goto errorexit; + } + if (IsPrim(head)) { + ErrorMess = "! Clause head is an integer (assert)"; + goto errorexit; + } + if (IsPrim(body) && !InBoot) { + ErrorMess = "! Clause body is an integer (assert)"; + goto errorexit; + } + r = SkelP(head)->Fn; + if ((FunctorP(r)->flgsoffe)&RESERVED) { + ErrorMess = "! Attempt to redefine a system predicate"; + goto errorexit; + } + if (rk && (!toomany) && !refsflg) { + /* reconsulting */ + for (proclist = vra; proclist < vrz; proclist++) + if(*proclist == r) goto found; + abolish(r); + *vrz++ = r; + HighTide(vrz,Auxtide); + if (vrz > auxmax) NoSpace(AuxId); + } + found: rk = r; + + goto insert; + + dbase: /* inserting a item on the data base */ + if (IsRef(rk)) { + rk = *rk; + if(IsComp(rk)) + rk = SkelP(rk)->Fn; + } + if (IsntName(rk) || IsRef(rk)) { + ErrorMess = "! Illegal key (record)"; + return NULL; + } + head = rk; + lev = 2; + body = heapify(t,g); + + insert: + if (toomany) { + ErrorMess = "! Too many variables in term or clause being recorded"; + goto errorexit; + } + if (refsflg) { + ErrorMess = "! Term or clause being recorded contains references"; + goto errorexit; + } + r = getsp(szofcl); + Unsafe(); + ClauseP(r)->hdofcl = head; ClauseP(r)->bdyofcl = body; + ng = nl = nt = 0; + for (j = 0; j < nvars; j++) + if (Unsigned(vn[j])&Global) + vn[j] = SkelGlobal(ng++); + else if (OnBody&Unsigned(vn[j])) + vn[j] = SkelLocal(nl++); + else vn[j] = ((PTR)0)+nt++; + if (nt > 0) { + k = SkelLocal(nl); + for (j = 0; j < nvars; j++) + if (Unsigned(vn[j]) < 1024) + vn[j] = Unsigned(k)+Unsigned(vn[j]); + } + ClauseP(r)->altofcl = ClauseP(r)->prevofcl = NULL; + ClauseP(r)->infofcl = 0; + ClauseP(r)->ltofcl = nl+nt; + ClauseP(r)->lvofcl = nl; + ClauseP(r)->gvofcl = ng; + if (body) + scan(&body); + if (key == CLAUSE) + scan(&head); + rk = key == CLAUSE ? &(FunctorP(rk)->FClauses) + : &(FunctorP(rk)->FRecords); + + if (aorz) { /* store at the beginning */ + r->prevofcl = NULL; + r->altofcl = rk->First; + if (rk->First) + rk->First->prevofcl = r; + rk->First = r; + if (!(rk->Last)) + rk->Last = r; + } else { /* store at the end */ + r->prevofcl = rk->Last; + r->altofcl = NULL; + if (rk->Last) + rk->Last->altofcl = r; + rk->Last = r; + if (!(rk->First)) + rk->First = r; + } + Safe(); + return ConsDBRef(r,key); + errorexit: + Safe(); + freeterm(head); + freeterm(body); + return NULL; +} + +int +erased(r) +PTR r; +{ + PTR c; + + if (!IsDBRef(r)) { + ErrorMess = "! Erased argument is not a reference"; + return -1; + } + c = XtrDBRef(r); + return((ClauseP(c)->infofcl&ERASED) != 0); +} + +erase(r) +PTR r; +/* erase term pointed by reference r */ +{ + int key; PTR c, d; + + if (!IsDBRef(r)) { + ErrorMess = "! Erase argument is not a reference"; + return FALSE; + } + key = DBType(r); + c = XtrDBRef(r); +/* fprintf(stderr,"Erasing: %c %x\n",key ? 'R' : 'C',c); */ + if (ClauseP(c)->infofcl&ERASED) return TRUE; + d = ClauseP(c)->hdofcl; + if (key == CLAUSE) + d = SkelP(d)->Fn; + if ((FunctorP(d)->flgsoffe)&RESERVED) { + ErrorMess = "! Attempt to erase a system object"; + return FALSE; + } + ClauseP(c)->infofcl |= ERASED; + if (!InUse(c)) unchain(r); +/* At this point, if c is idle it will have been unchained, so there + will be no junk in the chain if we dispose of it */ + if (Idle(c)) { + dispose(c); +/* fprintf(stderr,"Gone\n"); */ + } + return TRUE; +} + +/* release space occupied by source term c */ + +freeterm(c) +PTR c; +{ + int n, k; PTR p; + +/* c may be 0, in which case it will be caught by IsAtomic below */ + + if (IsPrim(c) && IsDBRef(c)) { + p = XtrDBRef(c); + if (--RC(p) == 0 && Erased(p) && !InUse(p)) +/* If these conditions are true, p will no longer be in a chain, + because it will have been removed either by erase or by hide when + untrailing +*/ + dispose(p); + return; + } + if (IsAtomic(c) || IsVar(c) || IsAtomic(*c)) + return; + k = FunctorP(SkelP(c)->Fn)->arityoffe; + for (p = c, n = k; n>0; n--) + freeterm(*++p); + freeblock(c,k+1); +} + +/* unchain(p), where p is a database reference, removes the record + or clause referred to by p from its backtracking CHAIN. + Unchain is only called for things that are not in use + (either when they are erased or on backtracking by hide). +*/ +unchain(p) +PTR p; +{ + PTR c, r; + int key; + + c = XtrDBRef(p); + key = DBType(p); + r = ClauseP(c)->hdofcl; + if (key == CLAUSE) + r = SkelP(r)->Fn; + /* Choose chain header */ + r = key == CLAUSE ? Addr(FunctorP(r)->FClauses) + : Addr(FunctorP(r)->FRecords); + Unsafe(); + if (c->prevofcl) + c->prevofcl->altofcl = c->altofcl; + else /* first in chain */ + r->First = c->altofcl; + if (c->altofcl) /* not last in chain */ + c->altofcl->prevofcl = c->prevofcl; + else /* last in chain */ + r->Last = c->prevofcl; + Safe(); +} + +/* dispose(c), where c is the address of a clause (record) gets rid + of the space occupied by the clause; freeterm will recover the + space used by the terms, and update reference counts of clauses + (records) pointed to from those terms, possibly causing recursive + calls to dispose. +*/ +dispose(c) +PTR c; +{ + freeterm(ClauseP(c)->bdyofcl); + freeterm(ClauseP(c)->hdofcl); + freeblock(c,szofcl); +} + +/* hide(r), where r is a database reference, is called when an ERASED + object leaves the in-use state (on backtracking). + First, the IN_USE flag is reset. + At this point, we + know that the object's backtrack chain is not being used. + If the object is idle at this point, we can dispose of it. +*/ +hide(r) +PTR r; +{ + PTR c; + + c = XtrDBRef(r); +/* fprintf(stderr,"Hiding: %c %x\n", key ? 'R': 'C',c); */ + ClauseP(c)->infofcl &= ~IN_USE; + unchain(r); + if (RC(c)==0) dispose(c); +} + +abolish(r) +FUNCTOR *r; +{ + CLAUSEREC *oldcl, *nextold; + + if ((r->flgsoffe)&RESERVED) return FALSE; + for (oldcl = r->defsoffe; oldcl; oldcl = nextold) { + nextold = ClauseP(oldcl->altofcl); + oldcl->infofcl |= ERASED; + if (!InUse(oldcl)) unchain(ConsDBRef((PTR)oldcl,CLAUSE)); + if (Idle(oldcl)) dispose(oldcl); + } + return TRUE; +} + +PTR +recorded(key) +int key; +{ +/* key should be RECORD for the data base + or CLAUSE for clauses; + The local stack is expected to contain + ARG1 term to be matched + ARG2 var to be unified with reference into data base + ARG3 + ARG4 indirect pointer to next term to be tried for match +*/ + PTR p, sv1, v1f, t, h, b, sx, tr0; + int n; + + p = *(ARG4); + if (Signed(p) < 255) return FALSE; /* this is a $sysp */ + /* since args of $record(_,_,_) are classified as temp. */ + GrowLocal(4); + sv1 = v1f = v1; tr0 = tr; + for (; TRUE; p = ClauseP(p)->altofcl) { + if (Undef(p)) return NULL; + if (Erased(p)) continue; + sx = x; x = v-4; + if (key == RECORD) { + n = ClauseP(p)->gvofcl; + InitGlobal(n,t); + t = ClauseP(p)->bdyofcl; + n = unifyarg(Addr(FrameP(sx)->v1ofcf),t,v1f); + } else n = 1; + n &= unifyarg(Addr(FrameP(sx)->v2ofcf),ConsDBRef(p,key),v1f); + x = sx; + if (n) break; + v1 = sv1; + while (tr != tr0) **--tr = NULL; + } + ARG4 = Addr(ClauseP(p)->altofcl); + if (!InUse(p)) { + ClauseP(p)->infofcl |= IN_USE; + TrailPtr(ConsDBRef(p,key)); + } + + return ConsDBRef(p,key); +} + +static int rl; static PTR tf; + +static PTR +globalize(t,bodyflg) +PTR t; int bodyflg; +{ + PTR a, b, k; int n; + if (IsAtomic(t)) return t; + if (bodyflg && SkelP(t)->Fn == commatag) { + a = globalize(SkelP(t)->Arg1,FALSE); + b = globalize(SkelP(t)->Arg2,TRUE); + *v1 = a; *(v1+1) = b; t = v1+2; + MolP(t)->Sk = Addr(FunctorP(commatag)->gtoffe); + MolP(t)->Env = v1; + GrowGlobal(4); + return t; + } + n = FunctorP(*t)->arityoffe; + MolP(v1)->Sk = Addr(FunctorP(*t)->gtoffe); + MolP(v1)->Env = v1+2; + a = v1; b = v1+2; GrowGlobal(n+2); + while (n-- > 0) { + k = *++t; + if (IsComp(k)) { + if (IsInp(k)) { + ConsMol(k,tf,k); + } + else if (IsLocalVar(k)) + k = rl+FrameVar(tf,VarNo(k)); + else + k = FrameVar(tf,VarNo(k)); + } + *b++ = k; + } + return a; +} + +int +instance(r,argp) +PTR r, argp; +{ + PTR p, h, b; + int g, l; + + if (!IsDBRef(r)) return -1; + + p = XtrDBRef(r); + g = ClauseP(p)->gvofcl; l = ClauseP(p)->ltofcl; + InitGlobal(g+l,tf); + rl = g-szofcf; + if (DBType(r) == RECORD) h = p->bdyofcl; + else { + h = ClauseP(p)->hdofcl; b = ClauseP(p)->bdyofcl; + if (Undef(b)) b = atomtrue; + if (l>0 ) { + h = globalize(h,FALSE); + b = globalize(b,TRUE); + } else { + if (IsComp(h)) + ConsMol(h,tf,h); + if (IsComp(b)) + ConsMol(b,tf,b); + } + *v1 = h; *(v1+1) = b; + h = Addr(FunctorP(arrowtag)->gtoffe); tf = v1; + GrowGlobal(2); + } + return unifyarg(argp,h,tf); +} + diff --git a/source_code/c-prolog-1982/dbase.o b/source_code/c-prolog-1982/dbase.o new file mode 100755 index 0000000..9a62779 Binary files /dev/null and b/source_code/c-prolog-1982/dbase.o differ diff --git a/source_code/c-prolog-1982/evalp.h b/source_code/c-prolog-1982/evalp.h new file mode 100755 index 0000000..3a83375 --- /dev/null +++ b/source_code/c-prolog-1982/evalp.h @@ -0,0 +1,154 @@ +/********************************************************************** +* * +* C Prolog evalp.h * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ + +/* Internal codes for the evaluable predicates. + These connect the definitions in the bootstrap file(s) to the + big case statement following the label EvalPted: in main.c. + The definitions in the bootstrap file are clauses of the form + + p(A1,...,Ak) :- n. + + or calls of the form + + :- $sysp(p(A1,...,Ak),n). + + where p is the evaluable predicate being defined, and n + is its internal code (Prolog doesn't know about the + symbolic definitions below, the actual numbers must be used). + The difference between the first and second forms of definition + is that in the first a stack frame is build for a call to the + predicate, containing the arguments, which can be accessed + in the standard way via the 'x' pointer. In other words, + the C code for the evaluable predicate will execute as + if the definition clause was its parent. In contrast, + evaluable predicates defined in the second way have no + frame pushed for them, it is up to them to find their + arguments and xecution environment. +*/ + +#define _call 1 +#define _cut 2 +#define _repeat 3 +#define _abort 4 +#define _call1 5 +#define _and 6 +#define _see 10 +#define _seeing 11 +#define _seen 12 +#define _tell 13 +#define _telling 14 +#define _told 15 +#define _close 16 +#define _read 17 +#define _write 18 +#define _nl 19 +#define _get0 20 +#define _get 21 +#define _skip 22 +#define _put 23 +#define _tab 24 +#define _fileerrors 25 +#define _nofileerrors 26 +#define _rename 27 +#define _writeq 28 +#define _sh 29 +#define _system 30 +#define _prompt 31 +#define _exists 32 +#define _save 33 +#define _is 40 +#define _ncompare 41 +/* ncompare_+NE + +LT + +GT + +LE + +GE: RESERVED */ +#define _var 50 +#define _nonvar 51 +#define _integer 52 +#define _atomic 53 +#define _eq 54 +#define _ne 55 +#define _functor 56 +#define _arg 57 +#define _univ 58 +#define _atom 59 +#define _erase 60 +#define _asst1 61 +#define _assta1 62 +#define _asst2 63 +#define _assta2 64 +#define _clause 65 +/* clause_+1 : RESERVED */ +#define _rcrded 67 +/* _rcrd_+1 : RESERVED */ +#define _instance 69 +#define _NOLC 70 +#define _LC 71 +#define _trace 72 +#define _rcrda 73 +#define _rcrdz 74 +#define _name 75 +#define _op 76 +#define _leash 78 +#define _debug 79 +#define _catom 80 +/* catom_+1: RESERVED */ +#define _cfunctor 82 +/* cfunctor_+1: RESERVED */ +#define _flags 84 +#define _compare 85 +#define _alpLT 86 +#define _alpGT 87 +#define _alpLE 88 +#define _alpGE 89 +#define _all_float 90 +#define _number 91 +#define _erased 92 +#define _statistics 93 +#define _sysp 100 +#define _sysflgs 101 +#define _brk 102 +#define _exit_break 103 +#define _xprompt 104 +#define _user_exec 105 +#define _save_vars 106 +#define _reset_vars 107 +#define _repply 108 +#define _recons 109 +#define _brkstart 110 +#define _brkend 111 +#define _asstr 112 +#define _RIP 113 +#define _user_call 114 +#define _xrepeat 115 +#define _yes 116 +#define _no 117 +#define _primitive 118 +#define _db_reference 119 +#ifdef GRAPHICS +#define _graphics 120 +#endif +#define _hidden_call 121 +#define _unary 130 +/* 131-149: reserved for unary arithmetic operators */ +#define _binary 150 +/* 151-169: reserved for binary arithmetic operators */ +#define _carith 170 +#define _hideat 171 +#define _isop 172 +#define _abolish 173 +#define _append 174 diff --git a/source_code/c-prolog-1982/hw1 b/source_code/c-prolog-1982/hw1 new file mode 100755 index 0000000..4285a26 --- /dev/null +++ b/source_code/c-prolog-1982/hw1 @@ -0,0 +1,105 @@ +/* + +Name: HW1 +Author: Kenneth Ray Barnhouse +SSN: 245-29-5485 +Date: 5-Feb-1988 +Class: CSE 511 + +Purpose: This programming assignment is a basic introduction to + PROLOG. There are four parts to the homework assignments. + Each is commented below. + +*/ + +/* + +QUESTION 1. + +Define some facts and rules in PROLOG. + +*/ + +man(fred). +man(bill). +woman(jane). +woman(mary). +dog(fido). +dog(pluto). + +animal(X) :- dog(X). +animal(X) :- human(X). +human(X) :- man(X). +human(X) :- woman(X). + +/* + +QUESTION 2. + +Define a prolog procedure called listall/1 that will list all the members of a +class of objects. + +To solve this problem, I used the "fail" function to repeatly find fact +of the form, Class(X) and write them out on the screen in a nice format. + +*/ + +listall(Class) :- Goal =.. [Class,X], + call(Goal), + write(X),write(' is a '),write(Class),nl, + fail. + +listall(_). + +/* + +QUESTION 3: + +define a procedure listof/2 that binds a list of members of a class, +Class, to the variable, List. + +To solve this problem, I first needed to define a function, member, +which would test to see if an atom is contanted in a list. I next +defined listof/2 to call a work function, listof2/3. listof2/3 is a +recursive procedure made of up two clauses. This first clause will +attempt to bind to a variable X a member of the class, Class. Next, the +clause checks to see if this member is already on the list. If not, it +calls itself to find other member of the class, Class other than the +current value of X. When listof2 clause 1 exits, it will add X to the +final list, List. The second clause of the listof2 procedure is called +only if the first clause fails. this clause also defines the List to be +null if no members of Class are found. + +Note: The way I have implemented listof will only return the full list +of members of a certain class. If you remove the cut from the listof +clause, listof will return not only the full list, but on repeated calls +will return all sublist of the full list of members of the class. + +*/ + +member(X,[X|_]). +member(X,[_|T]) :- member(X,T). + +listof(Class,List) :- listof2(Class,[],List),!. + +listof2(Class,Found,[X|List]) :- Goal =.. [Class,X], + call(Goal), + \+ member(X,Found), + listof2(Class,[X|Found],List). +listof2(_,_,List) :- List = []. + +/* + +QUESTION 4: + +define a procedure count/1 that prints the number of members of a certain class. + +To solve this problems, I used the length built-in function and the +listof function defined in Question 3. + +*/ + +count(Class) :- listof(Class,List), + length(List,Size), + write('Number of '),write(Class),write(' = '),write(Size). + diff --git a/source_code/c-prolog-1982/hw4.pl b/source_code/c-prolog-1982/hw4.pl new file mode 100755 index 0000000..b567697 --- /dev/null +++ b/source_code/c-prolog-1982/hw4.pl @@ -0,0 +1,159 @@ +/* + +Name: HW4 +Author: Kenneth Ray Barnhouse +SSN: 245-29-5485 +Date: 15-Apr-1988 +Class: CSE 511 + +Purpose: + To build a simple forward chaining production system in PROLOG. + The language will have two kind of statements, facts and rules. + Facts look just like PROLOG facts. Rules are of the form: + + when condition(s) then action(s) + + where condition(s) are one or more facts connected with 'and'. + and action(s) are one and more actions connected with 'and'. + + Actions are basically any of six verbs: store, remove, output, + input, newline, halt. + + The Top level interpreter will accept two command: run and load. + The form of the load command is: + + load 'filename'. (the single quotes are NOT optional). + + and the run command is just + + run. + + The inner interpreter executes in a basic fetch/execute cycle from + top to bottom in the rule database. This cycle will continue until + a halt statements is executed. + +*/ + +/* + +define some operators to make PROLOG do the work for me. + +*/ + +?- op(300,xfx,then). +?- op(200,fy,when). +?- op(100,xfy,and). +?- op(50,fx,store). +?- op(50,fx,remove). +?- op(50,fx,output). +?- op(50,fx,input). +?- op(50,fx,load). + +/* + +This is the highest level interpreter in my little FCPS. I display a +prompt, read a command and execute it. I then call interpreter to +loop. There are really only two good command here, "load" and "run". + +*/ + +my_interpreter :- write(' My Simple FCPS V1.0 '),nl, + write(' by Ken Barnhouse '),nl, + write(' Valid Commands are '),nl, + write(' load ''filename'' and run '),nl, + unknown(_,fail), + interpreter. + +interpreter :- write('=> '), + read(Command), + call(Command), + interpreter. +/* + +Here I implement the load command. I can't just use consult because the +PROLOG interpreter will not allow me to "retract" any initial facts read in by +"consult". By asserting all the term myself, I can retract them at will. +A little more programming, but it was clean and easy. + +*/ + +load Program :- see(Program), + read_in_terms, + seen. + +read_in_terms :- read(Term), + assert_term(Term). +read_in_terms. + +assert_term(end_of_file). +assert_term(Term) :- assert(Term), + read_in_terms. + +/* + +Here is the inner rule interpreter for my FCPS. It basically implements a +fetch/execute cycle. The first line of the first rule gets a FCPS rule from +the PROLOG database, then the second try to execute it. I used fail to loop +through the database. Then second rule of run just does a recursive call to +run to loop to the top of the database. + +*/ + +run :- when Conditions then Actions, + execute(Conditions,Actions), + fail. +run :- run. + +/* + +the execute rule does the "if conditions met then fire" part of the rule +interpreter. It checks to see if the condition part of the rule is met. +if so, it fire the action part of the rule. If not, it returns true. + +*/ + +execute(Conditions,Actions) :- conditions_met(Conditions),!, + fire_actions(Actions). +execute(_,_). + +/* + +conditions_met/1 checks to see if the conditions are met. We have to do +this recursively if we have several 'and'ed conditions. + +*/ + +conditions_met(Firstcondition and Otherconditions) :- + Firstcondition, + conditions_met(Otherconditions),!. + +conditions_met(Singlecondition) :- Singlecondition. + +/* + +first_actions/1 is basically like condition_met/1 in form, since we must +recursely execute actions that we connected with and's. + +*/ + +fire_actions(Firstaction and Otheractions) :- + call(Firstaction), + fire_actions(Otheractions),!. + +fire_actions(Singleaction) :- call(Singleaction). + +/* + +Here I define the verbs in this language. + +*/ + +store Fact :- assert(Fact). + +remove Fact :- retract(Fact). + +output Term :- write(Term). + +input Term :- read(Term). + +newline :- nl. diff --git a/source_code/c-prolog-1982/main.c b/source_code/c-prolog-1982/main.c new file mode 100755 index 0000000..053ef35 --- /dev/null +++ b/source_code/c-prolog-1982/main.c @@ -0,0 +1,1788 @@ +/********************************************************************** +* * +* C Prolog main.c * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ + +#include "pl.h" +#include "evalp.h" +#include "arithop.h" +#include "trace.h" +#include +#include + +extern int sys_nerr; +extern char *sys_errlist[]; +extern PTR HeapTop(); + +#define TEST(c,s,f) {if (c) goto s; else goto f;} +#define TRY(c) TEST(c,continuation,efail) +#define FlOffset (Addr(ClauseP(0)->altofcl)-(PTR)0) + +/* initial atoms */ + +PTR BasicAtom[BATOMS]; + +/* initial functors */ + +PTR BasicFunctor[BFUNCS]; + +/* initial terms */ + +PTR BasicTerm[BTERMS]; + +/* Variables for comunication with read, write and symbol table */ + +PTR hasha, lsp, atomfp, varfp, atprompt; +int lc, quoteia, nvars, fileerrors, reading, InBoot; +VarP varchain; + +/* start-up flag */ + +int running = FALSE; + +/* variables for communication with dbase */ + +PTR vra, vrz; + +/* general error message passing string */ + +char *ErrorMess; + +/* emergency exit */ + +typedef struct { + jmp_buf buf; +} JumpBuf; + +extern JumpBuf ZeroState; + +/* Heap management block */ + +extern char Heap[]; +extern int HeapHeader; + +/* Names of work areas */ + +char *AreaName[] = { + "atom space", "aux. stack", "trail", "heap", + "global stack", "local stack" +}; + +/* Prolog machine registers */ + +PTR x, x1, v, v1, vv, vv1, v1f, tr, tr0; + +/* main loop variables */ + +static int info; +PTR pg, c, bg; +static PTR g, fl; + +#define FL ClauseP(fl) /* failure label */ + +/* miscellaneous */ + +int brklev; + +static int n; +static PTR f, d, b, k, k1, y, p, l, arg1; +static int i, j, i1, i2, bb, modeflag; +static char ch, ch2, *bn, *plparm; + +/* Input/output diversion */ + +#define IfInput(flag,code) { \ + int savedstream = Input; \ + JumpBuf catch; \ + catch = ZeroState; \ + if (!setjmp (ZeroState.buf)) { \ + if (flag) Input = STDIN; \ + code; \ + if (flag) Input = savedstream; \ + ZeroState = catch; \ + } else { \ + if (flag) Input = savedstream; \ + ZeroState = catch; \ + longjmp (ZeroState.buf, 1); \ + } \ +} + +#define IfOutput(flag,code) { \ + int savedstream = Output; \ + JumpBuf catch; \ + catch = ZeroState; \ + if (!setjmp (ZeroState.buf)) { \ + if (flag) \ + Output = STDOUT; \ + code; \ + if (flag) \ + Output = savedstream; \ + ZeroState = catch; \ + } else { \ + if (flag) \ + Output = savedstream; \ + ZeroState = catch; \ + longjmp (ZeroState.buf, 1); \ + } \ +} + +/* Variables for the basic debugging package */ + +int debug = FALSE, lev, sklev, spy, leash = 10 /* half */, + dotrace, breakret, invokno, execsys; + +static int recons, cmparith = 0, InStat, OutStat; +static VarP vchain; +static PTR pvrz, *savead; +PTR brkp; + +/* variables to be saved on a break */ + +static PTR * BreakVars[] = { + &breakret, &brkp, &vchain, &recons, &pvrz, + &vra, &vrz, + &x, &x1, &v, &v1, &vv, &vv1, &v1f, &tr, &tr0, + &debug, &execsys, &pg, &g, &info, &lev, &c, &invokno, &fl, + &lc, + &f, &d, &b, &k, &k1, &n, &y, &p, &l, &bb, + &spy, &sklev, &dotrace, + &Input, &Output, &InStat, &OutStat +}; + +/* There must be a one-to-one correspondence between elements of + BreakVars and VarType. The VarType of a BreakVars is REMAP if + the BreakVars is a PTR, otherwise it is FIX. FIXes are converted + to Prolog integers when they are saved, therefore they cannot be + more than 29 bits. + +*/ + +#define FIX 0 +#define REMAP 1 + +static char VarType[] = { + FIX, REMAP, REMAP, FIX, REMAP, + REMAP, REMAP, + REMAP, REMAP, REMAP, REMAP, REMAP, REMAP, REMAP, REMAP, REMAP, + FIX, REMAP, REMAP, REMAP, REMAP, FIX, REMAP, FIX, REMAP, + FIX, + REMAP, REMAP, REMAP, REMAP, REMAP, REMAP, REMAP, REMAP, REMAP, FIX, + FIX, FIX, FIX, + FIX, FIX, FIX, FIX +}; + +/* Number of locations in the Prolog environment */ + +#define BrkEnvSize (sizeof(BreakVars)/sizeof(PTR *)) + +static +savev (p, n) +PTR *p; int n; +/* saves n vars starting with p */ +{ + while (n-- > 0) + *savead++ = *p++; +} + +static +rstrv(p,n) +PTR *p; int n; +/* restores n vars starting with v */ +{ + while (n-- > 0) + *p++ = *savead++; +} + +static +savevars() +/* to enter a break */ +{ + PTR nbrkp, **p; char *tp; + + nbrkp = v+MAX_FRAME; + if (nbrkp > vmax) NoSpace(LocalId); + for (p = BreakVars, tp = VarType, savead = nbrkp; + p-BreakVars < BrkEnvSize; p++, tp++, savead++) + *savead = (*tp == FIX) ? ConsInt(Signed(**p)) : **p; + vra = vrz; v = savead; brkp = nbrkp; +} + +static +popbreak() +/* to continue from a break */ +{ + PTR **p; char *tp; + + for (p = BreakVars, tp = VarType, savead = brkp; + p-BreakVars < BrkEnvSize; p++, tp++, savead++) + **p = (*tp == FIX) ? (PTR)XtrInt(*savead) : *savead; +} + +#define latS LSave[AtomId] +#define lauxS LSave[AuxId] +#define ltrS LSave[TrailId] +#define lskelS LSave[HeapId] +#define lglbS LSave[GlobalId] +#define llclS LSave[LocalId] +#define savepS LSave[NAreas] + +static int +save() +/* save current prolog state */ +{ + int i; + unsigned LSave[NAreas+1]; + unsigned *pl; PTR ps; + FILE *fa; + int oldin, oldout; + + /* open file */ + if (!(fa = fopen(AtomToFile(ARG1),"w"))) return FALSE; + errno = 0; /* no errors right now */ + /* save state */ + oldin = Input; oldout = Output; + Input = STDIN; Output = STDOUT; + savevars(); /* create a break environ */ + savepS = savead-lcl0; + savev(BasicAtom,BATOMS); + savev(BasicFunctor,BFUNCS); + savev(BasicTerm,BTERMS); + savev(&atprompt,1); + savev(&brklev,1); + savev(&atomfp,1); + /* compute length of different stacks */ + latS = atomfp-atom0; + lauxS = vrz-auxstk0; + ltrS = tr-trbase; + lskelS = HeapTop()-skel0; + lglbS = v1-glb0; + llclS = savead-lcl0+2; + fwrite(SaveMagic,1,4,fa); /* mark with tag and version no. */ + fwrite(&saveversion,sizeof saveversion,1,fa); + fwrite(LSave,sizeof LSave,1,fa); + fwrite(Origin,sizeof(PTR),NAreas,fa); + fwrite(Limit,sizeof(PTR),NAreas,fa); + fwrite(Heap,HeapHeader,1,fa); + fwrite(&brkp,sizeof brkp,1,fa); + fwrite(&fileerrors,sizeof fileerrors,1,fa); + pl = LSave; ps = Origin; + for (i = 0; i< NAreas; i++) + fwrite(*ps++,sizeof(PTR),*pl++,fa); + fclose(fa); + popbreak(); + Input = oldin; Output = oldout; + if (errno) ErrorMess = SysError(); + return (errno == 0); /* TRUE if no errors, FALSE otherwise */ +} + +/*--------------------------------------------------------------- + + restore Prolog state + +---------------------------------------------------------------*/ + +static PTR PArea[2*NAreas]; +static int RArea[NAreas]; +static unsigned LArea[NAreas]; + +#define patom PArea[AtomId] +#define pauxstk PArea[AuxId] +#define ptr PArea[TrailId] +#define pskel PArea[HeapId] +#define pglb PArea[GlobalId] +#define plcl PArea[LocalId] + +#define ratom RArea[AtomId] +#define rauxstk RArea[AuxId] +#define rtr RArea[TrailId] +#define rskel RArea[HeapId] +#define rglb RArea[GlobalId] +#define rlcl RArea[LocalId] + +static +remap(tp) +PTR tp; +/* remap source term pointed to by tp */ +{ + PTR t; int n; + t = *tp; + if (IsVar(t)) return; + if (SC(t,<,patom)) return; + if (SC(t,<,pskel)) { + *tp = t+ratom; + return; + } + *tp = t+rskel; + tp = *tp; t = *tp+rskel; *tp = t; + n = FunctorP(t)->arityoffe; + while (n-- > 0) + remap(++tp); +} + +static int +restore(sfile) +char *sfile; +{ + FILE *fa; + int i, l; + unsigned savep; int *p; PTR *p1, *p2, s, t, r; + char magic[5]; + + /* open file */ + if (!(fa = fopen(sfile,"r"))) { + ErrorMess = SysError(); + return FALSE; + } + /* check it is a saved Prolog state */ + fread(magic,1,4,fa); magic[4] = 0; + if (strcmp(magic,SaveMagic)) { + sprintf(OutBuf,"! File %s is not a saved Prolog state",sfile); + ErrorMess = OutBuf; + return FALSE; + } + /* check version */ + fread(&i,sizeof(int),1,fa); + if (i != saveversion) { + sprintf(OutBuf, + "! File %s is not compatible with this version of Prolog", + sfile); + ErrorMess = OutBuf; + return FALSE; + } + fread(LArea,sizeof LArea,1,fa); + { + int newsize; + + for(i = 0; i < NAreas; i++) { + newsize = (1+(LArea[i]*sizeof(PTR))/K); + newsize = K*(int)(1.33*newsize); /* 33% margin */ + if (Size[i] < newsize) { + fprintf(stderr, + "[ Expanding %s from %dK to %dK ]\n", + AreaName[i], Size[i]/K, newsize/K); + Size[i] = newsize; + } + } + } + CreateStacks(); + fread(&savep,sizeof savep,1,fa); + fread(PArea,sizeof PArea,1,fa); + fread(Heap,HeapHeader,1,fa); + fread(&brkp,sizeof brkp,1,fa); + fread(&fileerrors,sizeof fileerrors,1,fa); + /* compute relocation constants */ + p1 = Origin; p2 = PArea; p = RArea; + for (i = 0; i < NAreas; i++) + *p++ = *p1++ - *p2++; + /* extract stacks from file */ + p = LArea; p2 = Origin; + for (i = 0; i < NAreas; i++, p++, p2++) { + l = *p; s = *p2; + fread(s,sizeof(PTR),l,fa); + if (i != AtomId && i != HeapId && i != AuxId) + /* relocate stack contents */ + while (l-- > 0) { + k = *s; + if (SC(k,<,ptr)) { + if (SC(k,>=,pauxstk)) k += rauxstk; + else if (SC(k,>=,patom)) k += ratom; + } else { + if (SC(k,>=,pglb)) + k += SC(k,>=,plcl) ? rlcl : rglb; + else + k += (SC(k,>=,pskel)) ? rskel : rtr; + } + *s++ = k; + } + } + savead = savep+lcl0; + rstrv(BasicAtom,BATOMS); + rstrv(BasicFunctor,BFUNCS); + rstrv(BasicTerm,BTERMS); + rstrv(&atprompt,1); + rstrv(&brklev,1); + rstrv(&atomfp,1); + brkp += rlcl; + popbreak(); + /* NB: the various registers in the Prolog machine (those + referred to in BreakVars) have already been remapped + because savevars() saves the environment in the local + stack, whose contents have been remapped above (tricky, + this one!) + */ + /* remap free space chains */ + RelocHeap(rskel); + + /* fix prompt (may have been remapped) */ + SetPlPrompt(AtomP(atprompt)->stofae); + + /* remap auxiliary stack */ + for (k = auxstk0; k < vrz;) { + /* the auxiliary stack can only contain variable records (from 'read') + or functor and atom pointers (from 'reconsult'). Variable records + are distinguished by having either NULL or an aux. stack pointer in + their first word (NextVar); they are variable length, + with the length in VarLen. */ + if (k->NextVar == NULL || + (SC(k->NextVar,>=,pauxstk) && SC(k->NextVar,<,ptr))) { + k->VarValue += rglb; + if (k->NextVar) k->NextVar += rauxstk; + k += k->VarLen; + } + else { + if (SC(*k,>=,pskel)) *k += rskel; + else *k += ratom; + k++; + } + } + /* Remap atom and heap areas */ + + /* Start from the hash table. The test in the loop is <= rather + than < because we want to remap hidden atoms as well, whose + chain is stored at hasha+HASHSIZE */ + + for (k = hasha = atom0; k <= hasha+HASHSIZE; k++) { + p = k; + /* remap hash chain */ + while (*p) { + /* remap arity chain */ + p1 = p; + while (*p1) { + t = *p1; + t += SC(t,<,pskel) ? ratom : rskel; + *p1 = t; /* remap pointer to entry */ + p1 = *p1; + FunctorP(p1)->atoffe += ratom; /* remap pointer to atom */ + if (FunctorP(p1)->FClauses.Last) + FunctorP(p1)->FClauses.Last += rskel; + if (FunctorP(p1)->FRecords.Last) + FunctorP(p1)->FRecords.Last += rskel; + /* remap chain of definitions */ + p2 = Addr(FunctorP(p1)->defsoffe); + while (SC(*p2,>=,pskel)) { + p2 = *p2 += rskel; + /* check for circularity */ + if (ClauseP(p2)->altofcl == p2) break; + remap(&(ClauseP(p2)->hdofcl)); + remap(&(ClauseP(p2)->bdyofcl)); + if (ClauseP(p2)->prevofcl) + ClauseP(p2)->prevofcl += rskel; + p2 = Addr(ClauseP(p2)->altofcl); + } + /* remap data base chain */ + p2 = Addr(FunctorP(p1)->dboffe); + while (SC(*p2,>=,pskel)) { + p2 = *p2 +=rskel; + t = ClauseP(p2)->hdofcl; /* remap key pointer */ + t += (SC(t,<,pskel)) ? ratom : rskel; + ClauseP(p2)->hdofcl = t; + remap(&(ClauseP(p2)->bdyofcl)); + if (ClauseP(p2)->prevofcl) + ClauseP(p2)->prevofcl += rskel; + p2 = Addr(ClauseP(p2)->altofcl); + } + if (SC(p1,>=,skel0)) { + t = Addr(FunctorP(p1-rskel)->gtoffe); + remap(&t); + } + p1 = Addr(FunctorP(p1)->nxtoffe); + } + p = Addr(AtomP(*p)->nxtofae); + } + } + fclose(fa); + return TRUE; +} + +static +ResetTrail(t) +register PTR t; +{ + register PTR k, xtr; register char *status; + + xtr = tr; + while (xtr-- != t) { + k = *xtr; + if (IsRef(k)) *k = NULL; + else { + status = &(ClauseP(XtrDBRef(k))->infofcl); + if (!((*status)&ERASED)) *status &= ~IN_USE; + else hide(k); + } + } + tr = xtr; +} + +static PTR +bread() +/* read initialization terms */ +{ + PTR r; + + do { + v = lcl0; v1 = glb0; + SetPlPrompt(" >> "); PromptIfUser("boot>> "); + varfp = vrz; lsp = v; + reading = FALSE; + } while (!(r = pread())); + return r; +} + +/*=============================================================== + + Prolog execution starts here + +===============================================================*/ + +int PrologEvent; + +main(ArgC,ArgV) +int ArgC; char *ArgV[]; +{ + /* our first Prolog event will be a cold start */ + Safe(); + PrologEvent = COLD_START; + /* Prolog events cause execution to resume fom here */ + setjmp(ZeroState.buf); + CatchSignals(); /* prepare to handle signals etc. */ + switch (PrologEvent) { + /* Prolog event handling + Unix signals are mapped to Prolog events, + Event(..) can also be used to force + a Prolog event to occur. */ + case ABORT: /* abort */ + aborting: + fprintf(stderr,"\n\n[ execution aborted ]\n\n"); + ResetTrail(trbase); CloseFiles(); InitIO(); + goto restart; + case IO_ERROR: /* files error */ + IoFailure: + if (fileerrors) goto efail; + debug = TRUE; + fprintf(stderr,"\n\n%s\n",ErrorMess); + goto aborting; + case END_OF_FILE: /* input ended */ + Seen(); + if (reading) { + reading = FALSE; + goto readend; + } + ErrorMess = "! Input ended"; + goto IoFailure; + case ARITH_ERROR: /* error in arithmetic expression */ + fprintf(stderr,"\n! Error in arithmetic expression: %s\n", + ErrorMess); + debug = TRUE; sklev = NEVER_SKIP; goto efail; + case GEN_ERROR: /* general error with message requiring abort */ + fprintf(stderr,"\n%s",ErrorMess); + goto aborting; + case COLD_START: /* cold start */ + break; + } + + printf("%s\n",version); + + /* process parameters */ + + for (i = 0; i < Switches; i++) + State[i] = FALSE; + plparm = NULL; + while (--ArgC > 0) + if (**++ArgV == '-') { + for (i = 0; i < NParms; i++) + if (Parameter[i] == (*ArgV)[1]) { + ArgV++; ArgC--; + if (*ArgV) Size[i] = atoi(*ArgV)*K; + } + for (i1 = 1; (*ArgV)[i1]; i1++) { + for (i = 0; i < Switches; i++) + if (Switch[i] == (*ArgV)[i1]) { + State[i] = TRUE; + break; + } + if (i > Switches) + fprintf(stderr, + "! Unknown switch: %c\n",(*ArgV)[i1]); + } + } else { + plparm = *ArgV; + break; + } + InBoot = FALSE; + if (!State[IN_BOOT]) { + if (!plparm) { + plparm = UserStartup(); + if (!Exists(plparm)) { + plparm = StandardStartup; + State[QUIET] = TRUE; + } + } + if (!Exists(plparm)) { + fprintf(stderr,"! File %s does not exist\n",plparm); + exit(BAD_EXIT); + } + if (!State[QUIET]) { + printf("[ Restoring file %s ]\n",plparm); + } + if (restore(plparm)) { + InitIO(); + Vtide = v; V1tide = v1; TRtide = tr; Auxtide = vrz; + running = TRUE; + /* the system is now up and running */ + if (brklev > 0) + printf("[ Restarting break (level %d) ]\n",brklev); + TRY(unifyarg(Addr(ARG2),ConsInt(1),0)); + } + fprintf(stderr,"%s\n",ErrorMess); + exit(BAD_EXIT); + } + + if ((!plparm) || (!Exists(plparm))) { + fprintf(stderr,"** File %s does not exist\n",plparm); + exit(BAD_EXIT); + } + printf("[ Bootstrapping session. Initializing from file %s ]\n", + plparm); + + /* create stacks */ + + CreateStacks(); + + /* initialize atom area */ + + hasha = atom0; atomfp = atom0; + for (i = 0; i <= HASHSIZE; i++) *atomfp++ = NULL; + /* hasha+HASHSIZE points to atoms that have been hidden by $hide_atom */ + + /* initialize read/print vars */ + + lc = TRUE; quoteia = FALSE; + + /* initialize heap */ + + InitHeap(); + + /* initialise i/o system */ + + InitIO(); + fileerrors = FALSE; + InBoot = TRUE; /* We are booting */ + + /* junk (otherwise unititialised) */ + + brkp = l = n = recons = spy = 0; + + /* now load bootstrap file information */ + + CSee(plparm); + + /* read required atoms */ + + for (i = 0; i < BATOMS; i++) + BasicAtom[i] = bread(); + + /* read required functors */ + + for (i = 0; i Sk)->Fn; + + /* read required terms */ + + pg = getsp(27); k = pg; + for (i = 9; i > 0; i--) { + SkelP(k)->Fn = listfunc; + SkelP(k)->Arg1 = SkelGlobal(i); + SkelP(k)->Arg2 = k+3; + k += 3; + } + *(pg+26) = SkelGlobal(i); + List10 = pg; + + for (i = 0; i < BTERMS; i++) { /* first term is the special List10 */ + if (i == 0) + pg = ConsInt(0); /* a dummy term */ + else + pg = bread(); /* read a term */ + x1 = v1; + *v1++ = pg; /* push it into global stack */ + ConsMol(Addr(FunctorP(PrivTerm)->gtoffe),x1,pg); /* encapsulate it */ + if (!(g = record(CLAUSE,pg,0,0))) { /* assert encapsulated term */ + fprintf(stderr,"Cannot create basic term: "); + Output = STDERR; + pwrite(pg,0,1200); + Put('\n'); + exit(BAD_EXIT); + } + if (i == 0) /* major hack for List10 */ + SkelP(ClauseP(XtrDBRef(g))->hdofcl)->Arg1 = List10; + else + BasicTerm[i] = SkelP(ClauseP(XtrDBRef(g))->hdofcl)->Arg1; + } + +/* Set top level termination */ + +/* On success */ + + FunctorP(Yes)->defsoffe = _yes; + +/* On failure - clause $no :- _no */ + + k = v1 = glb0; + *v1++ = No; + *v1++ = ConsInt(_no); + ConsMol(Addr(FunctorP(arrowtag)->gtoffe),k,pg); + if (!record(CLAUSE,pg,0,0)) { + fprintf(stderr,"\n! Fatal error in startup - consult guru\n"); + Stop(TRUE); + } + k = FunctorP(No)->defsoffe; /* Fail to itself */ + ClauseP(k)->altofcl = k; + + atprompt = atomnil; + running = TRUE; /* boot is now running */ + + /* restart here after an abort etc. */ + + restart: + vrz = auxstk0; + v = lcl0; + v1 = glb0; + tr = trbase; + FileAtom[STDIN] = FileAtom[STDOUT] = user; + ResetStreams(); + dotrace = FALSE; + execsys = PRIM_TAG|HIDDEN_FRAME; + brklev = 0; + if (!State[IN_BOOT]) { + pg = live; + goto go; + } + + /* main loop during bootstrap session */ + + mainloop: + pg = bread(); + if (IsRef(pg) && *pg) g = *pg; else g = pg; + if (g == EndOfFile) { + Seen(); + State[IN_BOOT] = FALSE; + goto restart; + } + + if (IsAtomic(g) || SkelP(g)->Fn != provefunc) { + if (!record(CLAUSE,pg,0,0)) { + int telling; + + fprintf(stderr,"%s\n",ErrorMess); + telling = Output; + Output = STDERR; + pwrite(pg,0,1200); + Put('\n'); + Output = telling; + } + goto mainloop; + } + + SetPlPrompt("| "); + pg = arg(Addr(SkelP(g)->Arg1),pg->Env); + + /* go - run the goal pg */ + + go: + brkp = 0; /* no break points so far */ + tr = trbase; vv = x = lcl0; vv1 = x1 = glb0; c = Yes; + VV->gofcf = No; + VV->altofcf = Addr(FunctorP(No)->defsoffe->altofcl); + VV->gfofcf = VV->lcpofcf = vv; + VV->gsofcf = vv1; + VV->trofcf = tr0 = tr; + VV->infofcf = PRIM_TAG|HIDDEN_FRAME; + VV->cofcf = c; + GrowLocal(szofcf); + dotrace = FALSE; + lev = 1; invokno = 0; execsys = HIDDEN_FRAME; + sklev = NEVER_SKIP; + +/******************************************************************** + + interpreter main loop + +********************************************************************/ + + icall: + if (IsInp(pg)) g = pg; + else { + x1 = MolP(pg)->Env; + g = MolP(pg)->Sk; + } + f = SkelP(g)->Fn; + d = FunctorP(f)->defsoffe; + if (execsys) + info = PRIM_TAG|HIDDEN_FRAME; + else { + bb = FunctorP(f)->flgsoffe; + if (!(bb&INVISIBLE)) invokno++; + info = FrameInfo(invokno,lev); + brokencall: + Trace((debug && !(bb&(INVISIBLE|UNTRACEABLE))), + v,pg,x,info,CALL_PORT); + } + if (Signed(d) > 0 && Signed(d) < 255) { + i = Signed(d); + goto EvalPred; + } + while (d && Erased(d)) d = ClauseP(d)->altofcl; + if (!d) goto efail; + + V->lcpofcf = vv; + V->gofcf = pg; + V->gfofcf = x; + V->gsofcf = v1; + V->trofcf = tr0 = tr; + V->infofcf = info; + V->cofcf = c; + vv = v; vv1 = v1; + + /* try one clause */ + alt: + n = SkelP(g)->Fn->arityoffe; + fl = Addr(ClauseP(d)->altofcl); + v1f=v1; + if ((!debug) && !*fl) { + vv = V->lcpofcf; + vv1 = VV->gsofcf; + } + InitGlobal(ClauseP(d)->gvofcl,k); + k = Addr(V->v1ofcf); + i = ClauseP(d)->ltofcl; + while (i-- > 0) *k++ = 0; + V->altofcf = fl; + if (IsComp(g)) { + register PTR ta, tb, a, b, pa, pb; int arity; + + /* in-line top level for unification */ + + ta = ClauseP(d)->hdofcl; + tb = g; + arity = SkelP(ta)->Fn->arityoffe; + + /* main loop */ + + while (arity-- > 0) { + a = *++ta; + if (IsVar (a)) { + pa = FrameVar (IsLocalVar (a) ? v : v1f, VarNo (a)); + a = *pa; + while (IsRef (a)) { + pa = a; + a = *a; + } + b = *++tb; + if (IsVar (b)) { + pb = FrameVar (IsLocalVar (b) ? x : x1, VarNo (b)); + b = *pb; + while (IsRef (b)) { + pb = b; + b = *b; + } + if (pa == pb) + continue; + if (Undef (b)) { + if (Undef (a)) { + if (pa > pb) { + *pa = pb; + TrailVar (pa); + continue; + } + *pb = pa; + TrailVar (pb); + continue; + } + if (IsComp (a)) + *pb = pa; + else + *pb = a; + TrailVar (pb); + continue; + } + + if (Undef (a)) { + if (IsComp (b)) + *pa = pb; + else + *pa = b; + TrailVar (pa); + continue; + } + + if (IsAtomic (a)) { + if (a == b) + continue; + else + goto fail; + } + if (IsAtomic (b) || + !gunify (a, MolP (pa) -> Env, b, MolP (pb) -> Env)) + goto fail; + continue; + } + if (IsAtomic (b)) { + if (Undef (a)) { + *pa = b; + TrailVar (pa); + continue; + } + if (a == b) + continue; + goto fail; + } + if (Undef (a)) { + ConsMol (b, x1, *pa); + TrailVar (pa); + continue; + } + if (IsAtomic (a) || + !gunify (a, MolP (pa) -> Env, b, x1)) + goto fail; + continue; + } + b = *++tb; + if (IsInp (b)) { + if (IsComp (a)) { + if (IsAtomic (b) || !gunify (a, v1f, b, x1)) + goto fail; + continue; + } + if (b != a) + goto fail; + continue; + } + pb = FrameVar (IsLocalVar (b) ? x : x1, VarNo (b)); + b = *pb; + while (IsRef (b)) { + pb = b; + b = *b; + } + if (Undef (b)) { + if (IsAtomic (a)) + *pb = a; + else + ConsMol (a, v1f, *pb); + TrailVar (pb); + continue; + } + if (IsComp (b)) { + if (IsAtomic (a) || + !gunify (a, v1f, b, MolP (pb) -> Env)) + goto fail; + continue; + } + if (b != a) + goto fail; + continue; + } + } + + if (v > vmax) NoSpace(LocalId); + if (v1 > v1max) NoSpace(GlobalId); + bn = &(ClauseP(d)->infofcl); + if (!((*bn)&IN_USE)) { + *bn |= IN_USE; + TrailPtr(ConsDBRef(d,CLAUSE)); + } + x = v; x1 = v1f; + GrowLocal(szofcf+ClauseP(d)->lvofcl); + if (c = ClauseP(d)->bdyofcl) { + if (!execsys && !(bb&INVISIBLE)) { + if (bb&PROTECTED) execsys = HIDDEN_FRAME; + else lev++; + } + if (IsInt(c)) { + i = XtrInt(c)&255; + modeflag = XtrInt(c)>>8; + c = NULL; + goto EvalPred; + } + } +continuation: + while (!c) { + HighTide(v,Vtide); + if (x > vv) v = x; + fromcut: + c = X->cofcf; + pg = X->gofcf; + info = X->infofcf; + execsys = SysFrame(info); + if (!execsys) lev = Level(info); + brokenexit: + Trace((debug && (!execsys)),x,pg,X->gfofcf,info,EXIT_PORT); + x = X->gfofcf; + x1 = X->gsofcf; + } + + /* nonempty continuation */ + + notfoot: + x1 = X->gsofcf; + if (IsPrim(c)) goto efail; + if (SkelP(c)->Fn != commatag) { + pg = c; c = NULL; + goto icall; + } + pg = SkelP(c)->Arg1; + c = SkelP(c)->Arg2; + if (IsPrim(pg)) goto efail; + goto icall; + + + /* shallow backtracking */ + + fail: + d = *fl; + while (tr != tr0) **--tr = NULL; + while (d && Erased(d)) d = ClauseP(d)->altofcl; + if (d) { + v1 = v1f; + goto alt; + } + vv = V->lcpofcf; + + /* deep backtracking */ + + efail: + HighTide(v,Vtide); + HighTide(v1,V1tide); + HighTide(tr,TRtide); + if (!debug) { + while(TRUE) { + for (d = *(VV->altofcf); d && Erased(d); d = ClauseP(d)->altofcl); + if (d) break; + vv = VV->lcpofcf; + } + } else { + brokenfail: + Trace((!execsys),v,pg,x,info,FAIL_PORT); + for (d = *(VV->altofcf); d && Erased(d); d = ClauseP(d)->altofcl); + } + { + int fail_parent = vv == x && !c; + + v = vv; vv1 = v1 = V->gsofcf; + x = V->gfofcf; + x1 = X->gsofcf; + pg = V->gofcf; + c = V->cofcf; + info = V->infofcf; + execsys = SysFrame(info); + tr0 = V->trofcf; + while (tr != tr0) { + k = *--tr; + if (IsRef(k)) *k = NULL; + else { + bn = &(ClauseP(XtrDBRef(k))->infofcl); + if (!((*bn)&ERASED)) *bn &= ~IN_USE; + else hide(k); + } + } + brokenback: + Trace((debug&&(!execsys)&&(!fail_parent)),v,pg,x,info,BACK_PORT); + } + if (!d) { + vv = VV->lcpofcf; + goto efail; + } else { + if (IsInp(pg)) + g = pg, x1 = X->gsofcf; + else + g = MolP(pg)->Sk, x1 = MolP(pg)->Env; + bb = FunctorP(SkelP(g)->Fn)->flgsoffe; + goto alt; + } + +/**************************************************************** +* * +* evaluable predicates * +* * +****************************************************************/ + + EvalPred: + switch (i) { + +/* control predicates */ + + case _and: /* conjunction a,b a6 */ + k = arg(Addr(SkelP(g)->Arg2),x1); + if (IsInp(k) && IsComp(k)) + ConsMol(k,x1,k); + *v1 = k; *(v1+1) = &(FunctorP(HiddenCall)->gtoffe); + *(v1+2) = v1; + k = v1+1; GrowGlobal(3); + if (!c) c = k; + else { + *v1 = commatag; *(v1+1) = k; *(v1+2) = c; + c = v1; GrowGlobal(3); + } + case _hidden_call: + pg = arg(Addr(SkelP(g)->Arg1),x1); + if (IsPrim(pg) || Undef(*pg)) goto efail; + if (IsInp(pg) && IsComp(pg)) + ConsMol(pg,x1,pg); + goto icall; + case _user_call: /* revive tracing (for setof, etc.) */ + lev++; + execsys = FALSE; + case _call: /* call(a) */ + pg = ARG1; + TEST(IsPrim(pg) || Undef(*pg),efail,icall); + case _cut: /* cut operator */ + cut: + if (x > vv) goto continuation; + HighTide(v,Vtide); + v = x+szofcf+((X->altofcf)-FlOffset)->ltofcl; + vv = X->lcpofcf; + vv1 = VV->gsofcf; + HighTide(tr,TRtide); + if (X->trofcf != tr) { + register PTR kept, old, entry ; PTR globound, locbound; + +/* If debugging, trail entries pointing to frames not being discarded + cannot be removed, otherwise the retry option would not work. + The variables globound and locbound contain the lowest discardable + entries for the global and local stack respectively */ + + if (debug) + globound = v1, locbound = v; + else + globound = vv1, locbound = vv; + kept = old = X->trofcf; + do { + entry = *old++; + if ((!IsRef(entry)) + || entry < globound + || (lcl0 <= entry && entry < locbound)) + *kept++ = entry; + } while (old != tr); + tr = kept; + } + TEST(c, notfoot, fromcut); + case _repeat: /* repeat b3 */ + repeat: + vv = x; + vv1 = x1; + *fl = d; + goto continuation; + case _abort: /* abort a4 */ + goto aborting; + case _call1: /* $call(x) */ + pg = arg(Addr(SkelP(g)->Arg1),x1); + c = X->cofcf; x = X->gfofcf; + if (IsPrim(pg) || Undef(*pg)) goto efail; + if (IsInp(pg) && IsComp(pg)) + ConsMol(pg,x1,pg); + goto icall; + +/*---------------------------------------------------------------- + + I/O predicates + +----------------------------------------------------------------*/ + case _see: /* see(f) */ + See(ARG1); + goto continuation; + case _seeing: /* seeing(x) */ + k = Seeing(); + goto unifyatom; + case _seen: /* seen */ + Seen(); + goto continuation; + case _tell: /* tell(f) */ + Tell(ARG1,"w"); + goto continuation; + case _append: /* append(f) */ + Tell(ARG1,"a"); + goto continuation; + case _telling: /* telling(x) */ + k = Telling(); + unifyatom: /* unify atom k with arg in v1ofcf */ + k1 = ARG1; + if (IsRef(k1) && Undef(*k1)) { + *k1 = k; + TrailVar(k1); + goto continuation; + } + TRY(k == k1); + case _told: /* told b15 */ + Told(); + goto continuation; + case _close: /* close(f) b16 */ + PClose(ARG1); + goto continuation; + case _read: /* read(x) */ + varfp = vrz; + lsp = v+3; + varchain = NULL; reading = TRUE; + IfInput(modeflag,k = pread()); + readunify: + reading = FALSE; + if (!k) goto efail; + TRY(unifyarg(Addr(ARG1),k,0)); + readend: /* input ended trapped while reading */ + k = EndOfFile; + goto readunify; + case _write: /* write(x) b18 */ + quoteia = FALSE; + IfOutput(modeflag,pwrite(ARG1,x1,1200)); + goto continuation; + case _writeq: /* writeq(x) b28 */ + quoteia = TRUE; + IfOutput(modeflag,pwrite(ARG1,x1,1200)); + goto continuation; + case _nl: /* nl b19 */ + IfOutput(modeflag,Put('\n')); + goto continuation; + case _get0: /* get0(n) b20 */ + IfInput(modeflag,k = ConsInt(Get())); + goto unifyatom; + case _get: /* get(n) b21 */ + IfInput(modeflag, + do ch = Get(); while (ch <= ' ' || ch >= 127); + ) + k = ConsInt(ch); + goto unifyatom; + case _skip: /* skip(n) b22 */ + ch2 = intval(&(ARG1)); + IfInput(modeflag, + do ch = Get(); while (ch != ch2); + ) + goto continuation; + case _put: /* put(n) b23 */ + IfOutput(modeflag,Put(intval(&(ARG1)))); + goto continuation; + case _tab: /* tab(n) b24 */ + i = intval(&(ARG1)); + IfOutput(modeflag,while (i-- > 0) Put(' ')); + goto continuation; + case _fileerrors: /* fileerrors b25 */ + fileerrors = FALSE; + goto continuation; + case _nofileerrors: /* nofileerrors b26 */ + fileerrors = TRUE; + goto continuation; + case _rename: /* rename(f,f1) b27 */ + if (ARG2 == atomnil) + Remove(AtomToFile(ARG1)); + else + Rename(AtomToFile(ARG1),AtomToFile(ARG2)); + goto continuation; + case _sh: /* sh b29 */ + TRY(Sh()); + case _system: /* system(_) b30 */ + TRY(CallSystem(ARG1)); + case _prompt: /* prompt(_,_) b31 */ + if (!unifyarg(Addr(ARG1),atprompt,0)) goto efail; + k = vvalue(Addr(ARG2),&l); + if (IsntName(k) || !IsAtomic(k)) goto efail; + atprompt = k; + SetPlPrompt(AtomP(atprompt)->stofae); + goto continuation; + case _carith: /* $carith(_,_) */ + if (!(unifyarg(Addr(ARG1),ConsInt(cmparith),0))) goto efail; + k = vvalue(Addr(ARG2),&l); + if (!IsInt(k)) goto efail; + cmparith = XtrInt(k); + goto continuation; + case _exists: /* exists(f) b32 */ + TRY(Exists(AtomToFile(ARG1))); + case _save: /* $save(f,i) a33 */ + if (save()) { + TRY(unifyarg(Addr(ARG2),ConsInt(0),0)); + } else goto IoFailure; + +/*--------------------------------------------------------------- + + arithmetic predicates + +---------------------------------------------------------------*/ + case _is: /* is b40 */ + k = numeval(&(ARG2)); + goto unifyatom; + case _ncompare+EQ: + case _ncompare+NE: + case _ncompare+LT: + case _ncompare+GT: + case _ncompare+LE: + case _ncompare+GE: + TRY(numcompare(i-_ncompare,&(ARG1),&(ARG2))); + + /* expanded arithmetic predicates */ + + /* unary */ + + case _unary+ID: + case _unary+UMINUS: + case _unary+NOT: + case _unary+EXP: + case _unary+LOG: + case _unary+LOG10: + case _unary+SQRT: + case _unary+SIN: + case _unary+COS: + case _unary+TAN: + case _unary+ASIN: + case _unary+ACOS: + case _unary+ATAN: + case _unary+FLOOR: + TRY(unifyarg(Addr(ARG2),Unary(i-_unary,Addr(ARG1)),0)); + + /* binary */ + + case _binary+PLUS: + case _binary+MINUS: + case _binary+TIMES: + case _binary+DIVIDE: + case _binary+MOD: + case _binary+AND: + case _binary+OR: + case _binary+LSHIFT: + case _binary+RSHIFT: + case _binary+IDIV: + case _binary+POW: + TRY(unifyarg(Addr(ARG3), + Binary(i-_binary,Addr(ARG1),Addr(ARG2)),0)); + +/*--------------------------------------------------------------*/ + + case _var: /* var(x) b50 */ + k = ARG1; + TRY(IsRef(k) && Undef(*k)); + case _nonvar:/* nonvar(x) b51 */ + k = ARG1; + TRY(!IsRef(k) || !Undef(*k)); + case _integer: /* integer(x) b52 */ + TRY(IsInt(ARG1)); + case _number: /* number(x) b91 */ + TRY(IsNumber(ARG1)); + case _primitive: /* primitive(x) */ + TRY(IsPrim(ARG1)); + case _db_reference: /* db_reference(x) */ + TRY(IsDBRef(ARG1)); + case _atomic: /* atomic(x) b53 */ + TRY(IsAtomic(ARG1)); + case _atom: /* atom(x) b59 */ + k = ARG1; + TRY(!IsPrim(k) && IsAtomic(k)); + case _eq: /* == b54 */ + TRY(!compare(&(ARG1),&(ARG2))); + case _ne: /* \== b55 */ + TRY(compare(&(ARG1),&(ARG2))); + case _functor: /* functor(t,f,n) b56 */ + k = ARG1; + if (IsAtomic(k)) { + k1 = ConsInt(0); + goto unifyfn; + } + if (IsRef(k) && !Undef(*k)) { + k = SkelP(MolP(k)->Sk)->Fn; + k1 = ConsInt(FunctorP(k)->arityoffe); + k = FunctorP(k)->atoffe; goto unifyfn; + } + i1 = intval(&(ARG3)); + if (i1 == 0) { + k = ARG2; + goto unifyt; + } + if (i1 < 0 || i1 > 100) goto efail; + InitGlobal(i1,k1); + k = ARG2; + if (IsPrim(k) || IsComp(k)) goto efail; + k = Addr(FunctorP(fentry(k,i1))->gtoffe); + unifyt: + TRY(unifyarg(Addr(ARG1),k,k1)); + unifyfn: + TRY(unifyarg(Addr(ARG2),k,0) && + unifyarg(Addr(ARG3),k1,0)); + case _arg: /* arg(n,t,a) b57 */ + i1 = intval(&(ARG1)); + k1 = ARG2; + if (IsInp(k1) || Undef(*k1)) goto efail; + y = MolP(k1)->Env; k1 = MolP(k1)->Fn; + if ( i1 <= 0 || + i1 > FunctorP(SkelP(k1)->Fn)->arityoffe) + goto efail; + k = argv(k1+i1,y,&y); + TRY(unifyarg(Addr(ARG3),k,y)); + case _univ: /* x=..l b58 */ + k = ARG1; + if (IsRef(k) && Undef(*k)) goto tcons; + k1 = v+2; + n = 2; + if (IsInp(k)) { + *k1 = k; + goto mklst; + } + y = MolP(k)->Env; k = MolP(k)->Sk; + *k1 = FunctorP(SkelP(k)->Fn)->atoffe; + i = FunctorP(SkelP(k)->Fn)->arityoffe; + n += i; + while (i-- > 0) { + b = arg(++k,y); + if (IsComp(b) && IsInp(b)) + ConsMol(b,y,b); + *++k1 = b; + } + mklst: *(k1+1) = atomnil; + k = makelist(n,v+2); v1 -= 2; + TRY(unifyarg(Addr(ARG2),MolP(k)->Sk,MolP(k)->Env)); + tcons: + k = ARG2; + if (IsInp(k) || Undef(*k)) goto efail; + y = MolP(k)->Env; k = MolP(k)->Sk; + l = v+2; n = 0; + while (k != atomnil) { + if (IsAtomic(k) || + IsVar(k) || SkelP(k)->Fn != listfunc) + goto efail; + if (n++ > 100) { + ErrorMess = "! Too many arguments in =.."; + goto aborting; + } + k1 = arg(Addr(SkelP(k)->Arg1),y); + if (IsComp(k1) && IsInp(k1)) + ConsMol(k1,y,k1); + *l++ = k1; + k = argv(Addr(SkelP(k)->Arg2),y,&y); + } + k = *(v+2); + if (IsComp(k)) goto efail; + if (n == 1) + TRY(unifyarg(Addr(ARG1),k,0)); + if (IsPrim(k)) goto efail; + k = apply(k,n-1,v+3); + v1 -= 2; + TRY(unifyarg(Addr(ARG1),MolP(k)->Sk,MolP(k)->Env)); + case _asst1: /* assert(c) */ + TEST(record(CLAUSE,ARG1,0,FALSE),continuation,dbfail); + case _assta1: /* asserta(c) */ + TEST(record(CLAUSE,ARG1,0,TRUE),continuation,dbfail); + case _asst2: /* assert(c,r) */ + i1 = FALSE; + assertr: + k = record(CLAUSE,ARG1,0,i1); + y = &(ARG2); + unfref: + if (!k) goto dbfail; + k1 = XtrDBRef(k); + ClauseP(k1)->infofcl |= IN_USE; + TrailPtr(k); + TRY(unifyarg(y,k,0)); + case _assta2: /* asserta(c,r) */ + i1 = TRUE; + goto assertr; + case _rcrda: /* recorda(k,t,r) */ + i1 = TRUE; goto recordr; + case _rcrdz: /* recordz(k,t,r) */ + i1 = FALSE; + recordr: + k = record(RECORD,ARG2,ARG1,i1); + y = &(ARG3); + goto unfref; + case _clause: /* $clause(p,r,_) */ + k = *fl; + fl = Addr(ClauseP(k)->altofcl); + *fl = k; + k = ARG3; + if (IsRef(k)) k = MolP(k)->Sk; + if ((FunctorP(SkelP(k)->Fn)->flgsoffe)&PROTECTED) goto cutfail; + ARG4 = Addr(FunctorP(SkelP(k)->Fn)->defsoffe); + case _clause+1: + k = recorded(CLAUSE); + if (!k) goto cutfail; + TRY(instance(k,Addr(ARG1))); + case _rcrded: /* $recorded(t,r,k) */ + k = *fl; + fl = Addr(ClauseP(k)->altofcl); + *fl = k; + k = ARG3; + if (IsRef(k)) k = MolP(k)->Sk; + ARG4 = Addr(FunctorP(SkelP(k)->Fn)->dboffe); + case _rcrded+1: + k = recorded(RECORD); + TEST(k,continuation,cutfail); + dbfail: + fprintf(stderr,"\n%s\n",ErrorMess); + debug = TRUE; sklev = NEVER_SKIP; + cutfail: + if (vv >= x) vv = X->lcpofcf; + goto efail; + case _instance: /* instance(r,t) */ + k = instance(ARG1,&(ARG2)); + if (!k) goto efail; + if (k == 1) goto continuation; + ErrorMess = + "! First argument of instance must be a reference"; + goto dbfail; + case _erase: /* erase(r) */ + TEST(erase(ARG1),continuation,dbfail); + case _abolish: /* abolish(a,n) */ + TRY(IsAtomic(ARG1) && (!IsPrim(ARG1)) && + IsInt(ARG2) && (i = XtrInt(ARG2)) >= 0 && + abolish(i == 0 ? ARG1 : fentry(ARG1,i))); + case _erased: /* erased(r) */ + if ((i1 = erased(ARG1)) < 0) goto dbfail; + TRY(i1); + case _NOLC: /* 'NOLC' */ + lc = FALSE; + goto continuation; + case _LC: /* 'LC' */ + lc = TRUE; + goto continuation; + case _trace: /* trace */ + debug = dotrace = TRUE; + goto continuation; + case _op: /* op(p,t,a) */ + TRY(op(ARG1,ARG2,Addr(ARG3))); + case _leash: /* $leash(x,n) */ + if (!unifyarg(Addr(ARG1),ConsInt(leash),0)) + goto efail; + leash = intval(Addr(ARG2)); + goto continuation; + case _debug: /* $debug(p,n) */ + if (!unifyarg(Addr(ARG1),ConsInt(debug),0)) + goto efail; + spy = debug = intval(&(ARG2)); + goto continuation; + case _name: /* name(x,l) */ + k = ARG1; + if (IsRef(k) && Undef(*k)) goto namecons; + if (IsComp(k)) goto nameerr; + if (IsName(k)) bn = AtomP(k)->stofae; + else { + if (!IsNumber(k)) goto nameerr; + if (IsInt(k)) + sprintf(OutBuf,"%d",XtrInt(k)); + else + sprintf(OutBuf,"%f",XtrFloat(k)); + bn = OutBuf; + } + i = strlen(bn); + if (i > 0) { + k1 = v+1; n = i+1; + while (i-- > 0) + *++k1 = ConsInt(*bn++); + goto mklst; + } else + TRY(unifyarg(Addr(ARG2),atomnil,0)); + + namecons: + if (!list_to_string(ARG2,OutBuf,255)) goto nameerr; + bn = OutBuf; + if (NumberString(&bn,&k,FALSE)) { + TRY(unifyarg(Addr(ARG1),k,0)); + } + mkname: + TRY(unifyarg(Addr(ARG1),lookup(OutBuf),0)); + nameerr: + ErrorMess = "! Illegal arguments name(atomic,list)"; + goto dbfail; + case _catom: /* current_atom(a) */ + k = ARG1; + if (IsAtomic(k) && !IsPrim(k)) goto cut; + if (IsInp(k) || !Undef(*k)) goto cutfail; + ARG2 = 0; ARG3 = NULL; + fl = *fl; FL->altofcl = fl; + case _catom+1: + GrowLocal(3); + i = ARG2; k1 = ARG3; + while (k1 == NULL) { + if (i >= HASHSIZE) goto cutfail; + k1 = *(hasha+i++); + } + ARG2 = i; ARG3 = AtomP(k1)->nxtofae; + unifyarg(Addr(ARG1),k1,0); + goto continuation; + case _cfunctor: /* $current_functor(a,n,key,mask) + mode_(+,?,+,+) */ + ARG5 = ARG1; + fl = *fl; FL->altofcl = fl; + case _cfunctor+1: + GrowLocal(5); + k1 = ARG5; + nextfunc: + if (!k1) goto cutfail; + k = k1; k1 = FunctorP(k)->nxtoffe; + i = XtrInt(ARG3)&255; + if ((XtrInt(ARG4)&(FunctorP(k)->flgsoffe)) != i) + goto nextfunc; + if ((XtrInt(ARG3)&256) && !FunctorP(k)->defsoffe) + goto nextfunc; + if (!unifyarg(Addr(ARG2), + ConsInt(FunctorP(k)->arityoffe),0)) + goto nextfunc; + ARG5 = k1; + goto continuation; + case _flags: /* $flags(p,old,new) */ + bn = &(SkelP(FunctorP(MolP(ARG1)->Sk)->Fn)->flgsoffe); + if (!unifyarg(Addr(ARG2),ConsInt(*bn),0)) goto efail; + *bn = (char)intval(&(ARG3)); + goto continuation; + + case _compare: /* compare(Op,T1,T2) */ + i = compare(&(ARG2),&(ARG3)); + k = (i < 0) ? LessThan : ((i > 0) ? GreaterThan : Equal); + goto unifyatom; + + case _alpLT: /* T1 @< T2 */ + TRY(compare(&(ARG1),&(ARG2)) < 0); + + case _alpGT: /* T1 @> T2 */ + TRY(compare(&(ARG1),&(ARG2)) > 0); + + case _alpLE: /* T1 @=< T2 */ + TRY(compare(&(ARG1),&(ARG2)) <= 0); + + case _alpGE: /* T1 @>= T2 */ + TRY(compare(&(ARG1),&(ARG2)) >= 0); + case _all_float: /* $all_float(x,y) */ + if (!unifyarg(Addr(ARG1),ConsInt(AllFloat),0)) goto efail; + k = vvalue(Addr(ARG2),&l); + if (!IsPrim(k) || !IsInt(k)) goto efail; + AllFloat = XtrInt(k); + goto continuation; + case _statistics: /* statistics. */ + Statistics(); + goto continuation; + +/*------------------------------------------------------------------ + + system private predicates + +------------------------------------------------------------------*/ + + case _sysp: /* $sysp(f,n) */ + FunctorP(SkelP(MolP(ARG1)->Sk)->Fn)->defsoffe = + XtrInt(ARG2)&255; + goto continuation; + case _sysflgs: /* $sysflgs(p,n) */ + FunctorP(SkelP(MolP(ARG1)->Sk)->Fn)->flgsoffe = + (char)XtrInt(ARG2); + goto continuation; + case _hideat: /* $hide_atom(a) */ + TRY((IsAtomic(ARG1) && (!IsPrim(ARG1)) && + hide_atom(ARG1))); + case _brk: /* $break(g) a102 */ + bg = arg(g+1,x1); + if (IsPrim(bg) || Undef(*bg)) goto efail; + if (IsComp(bg) && IsInp(bg)) ConsMol(bg,x1,bg); + breakret = CONT; + enterbreak: + InStat = SaveStream(Input); + OutStat = SaveStream(Output); + savevars(); + Output = STDOUT; + Input = STDIN; + pg = bg; + goto icall; + case _exit_break: /* $exit_break a103 */ + popbreak(); + RestStream(Input,InStat); + RestStream(Output,OutStat); + switch(breakret) { + case CALL_PORT: goto brokencall; + case EXIT_PORT: goto brokenexit; + case BACK_PORT: goto brokenback; + case FAIL_PORT: goto brokenfail; + default: goto continuation; + } + case _xprompt: /* $prompt(p) b104 */ + PromptIfUser(AtomP(ARG1)->stofae); + goto continuation; + case _user_exec: /* $user_exec(_) b105 */ + c = ARG1; + if (IsPrim(c) || Undef(*c)) goto efail; + GrowLocal(1); lev = 1; invokno = 0; + if (debug) { + spy = TRUE; + if (dotrace) { + sklev = NEVER_SKIP; + dotrace = FALSE; + } else sklev = 0; + } else sklev = 0; + execsys = FALSE; + goto continuation; + case _save_vars: /* $save_read_vars a106 */ + vchain = varchain; pvrz = vrz; vrz = varfp; + goto continuation; + case _reset_vars: /* $reset_read_vars a107 */ + vrz = pvrz; + goto continuation; + case _repply: /* $repply a108 */ + if (!vchain) goto continuation; + { + VarP var; int telling; + + telling = Output; + Output = STDOUT; + for (var = vchain; var; var = var->NextVar) { + Put('\n'); + PutString(var->VarName); PutString(" = "); + k = vvalue(var->VarValue,&k1); + pwrite(k,k1,1200); + } + PutString(" "); + Output = telling; + } + ch = ToEOL(0,0); + TRY(ch != ';' && ch != 'y' && ch != 'Y'); + case _recons: /* $recons(_) b109 */ + recons = XtrInt(ARG1); + goto continuation; + case _brkstart: /* $break_start a110 */ + printf("[ Break (level %d) ]\n",++brklev); + goto continuation; + case _brkend: /* $break_end a111 */ + printf("[ End break (level %d) ]\n",brklev--); + goto continuation; + case _asstr: /* $assertr(_) b112 */ + k = record(CLAUSE,ARG1,recons,FALSE); + if (k) goto continuation; + fprintf(stderr,"\n%s\n",ErrorMess); + goto efail; + case _isop: /* $isop(_,_,_,_,_) */ + TRY((IsAtomic(ARG1) && (!IsPrim(ARG1)) && + IsInt(ARG2) && + isop(ARG1,XtrInt(ARG2),&i,&i1,&i2) && + unifyarg(Addr(ARG3),ConsInt(i),NULL) && + unifyarg(Addr(ARG4),ConsInt(i1),NULL) && + unifyarg(Addr(ARG5),ConsInt(i2),NULL))); + case _RIP: /* $rest_in_peace a113 */ + CloseFiles(); + printf("\n[ Prolog execution halted ]\n"); + exit(GOOD_EXIT); + case _xrepeat: /* b115 $repeat */ + goto repeat; + case _yes: /* top level success in bootstrap */ + ResetTrail(trbase); + goto mainloop; + case _no: /* top level failure in bootstrap */ + PutString("no\n"); + goto mainloop; +#ifdef GRAPHICS: + case _graphics: + TRY(plgraphics()); +#endif + default: + fprintf(stderr,"\n! Undefined built-in predicate : %d\n",i); + goto efail; + } +} diff --git a/source_code/c-prolog-1982/main.o b/source_code/c-prolog-1982/main.o new file mode 100755 index 0000000..8153a1d Binary files /dev/null and b/source_code/c-prolog-1982/main.o differ diff --git a/source_code/c-prolog-1982/makefile b/source_code/c-prolog-1982/makefile new file mode 100755 index 0000000..453c99c --- /dev/null +++ b/source_code/c-prolog-1982/makefile @@ -0,0 +1,51 @@ +PLSTARTUP=/usr/local/lib/pstartup1.5 +GRIND=igrind + +# Replace VAX by IEEE for IEEE floating point machines (e.g. Sun) +FLOATING=IEEE + +# Replace the right-end side by the empty string to get +# -1 as end of file character + +EOF= + +CC=cc +CFLAGS=-w -g $(EOF) -D$(FLOATING) -DSTARTUPFILE=\"$(PLSTARTUP)\" +# change define in parms.c - no mistakes then! +BIN=/usr/local/bin/prolog +OBJECTS=main.o unify.o rewrite.o dbase.o sysbits.o space.o \ + parms.o arith.o compare.o auxfn.o trace.o + +prolog : $(OBJECTS) + $(CC) -o prolog $(OBJECTS) -lm + +main.o : arithop.h evalp.h trace.h + +$(OBJECTS) : pl.h +arith.o : arithop.h +trace.o : trace.h + +clean : /tmp + rm -f $(OBJECTS) prolog startup + +startup : prolog pl/init + ./prolog -b pl/init cprolog.doc + +cprolog.doc: app.me cprolog.me + tbl cprolog.me app.me | $(TROFF) -me $(DEST) + + diff --git a/source_code/c-prolog-1982/makefile.save b/source_code/c-prolog-1982/makefile.save new file mode 100755 index 0000000..4b34076 --- /dev/null +++ b/source_code/c-prolog-1982/makefile.save @@ -0,0 +1,50 @@ +PLSTARTUP=/usr/local/bin/pstartup1.5 +GRIND=igrind + +# Replace VAX by IEEE for IEEE floating point machines (e.g. Sun) +FLOATING=VAX + +# Replace the right-end side by the empty string to get +# -1 as end of file character + +EOF=-DAsDEC10 + +CFLAGS=-w -g $(EOF) -D$(FLOATING) -DSTARTUPFILE=\"$(PLSTARTUP)\" +# change define in parms.c - no mistakes then! +BIN=/usr/local/bin/prolog +OBJECTS=main.o unify.o rewrite.o dbase.o sysbits.o space.o \ + parms.o arith.o compare.o auxfn.o trace.o + +prolog : $(OBJECTS) + $(CC) -o prolog $(OBJECTS) -lm -lg + +main.o : arithop.h evalp.h trace.h + +$(OBJECTS) : pl.h +arith.o : arithop.h +trace.o : trace.h + +clean : /tmp + rm -f $(OBJECTS) prolog startup + +startup : prolog pl/init + ./prolog -b pl/init cprolog.doc + +cprolog.doc: app.me cprolog.me + tbl cprolog.me app.me | $(TROFF) -me $(DEST) + + diff --git a/source_code/c-prolog-1982/makesys.com b/source_code/c-prolog-1982/makesys.com new file mode 100755 index 0000000..373626b --- /dev/null +++ b/source_code/c-prolog-1982/makesys.com @@ -0,0 +1,23 @@ +$ cc arith +$ cc auxfn +$ cc compare +$ cc dbase +$ cc main +$ cc parms +$ cc rewrite +$ cc space +$ cc sysbits +$ cc trace +$ cc unify +$ link/executable:prolog arith,auxfn,compare,dbase,main,parms,rewrite,space,- +$ trace,sysbits,unify +! The line below should be changed to whatever is appropriate at +! your installation +$ prolog :== $usr$:prolog.exe +$ prolog -b [.pl]init +['[.pl]vmsall']. +:-save(startup). +end_of_file. +! The file 'startup' should be moved to its final place as defined in +! parms.c + diff --git a/source_code/c-prolog-1982/man/app.me b/source_code/c-prolog-1982/man/app.me new file mode 100755 index 0000000..fdcd104 --- /dev/null +++ b/source_code/c-prolog-1982/man/app.me @@ -0,0 +1,107 @@ +.bp +.uh "Appendix I \*- Summary of Evaluable Predicates" +.TS H +l l. +.TH +\fPabolish(\fIF\fP,\fIN\fP) Abolish the procedure named \fIF\fP arity \fIN\fP. +abort Abort execution of the current directive. +arg(\fIN\fP,\fIT\fP,\fIA\fP) The \fIN\fPth argument of term \fIT\fP is \fIA\fP. +assert(\fIC\fP) Assert clause \fIC\fP. +assert(\fIC\fP,\fIR\fP) Assert clause \fIC\fP, ref. \fIR\fP. +asserta(\fIC\fP) Assert \fIC\fP as first clause. +asserta(\fIC\fP,\fIR\fP) Assert \fIC\fP as first clause, ref. \fIR\fP. +assertz(\fIC\fP) Assert \fIC\fP as last clause. +assertz(\fIC\fP,\fIR\fP) Assert \fIC\fP as last clause, ref. \fIR\fP. +atom(\fIT\fP) Term \fIT\fP is an atom. +atomic(\fIT\fP) Term \fIT\fP is an atom or integer. +bagof(\fIX\fP,\fIP\fP,\fIB\fP) The bag of \fIX\fPs such that \fIP\fP is provable is \fIB\fP. +break Break at the next procedure call. +call(\fIP\fP) Execute the procedure call \fIP\fP. +clause(\fIP\fP,\fIQ\fP) There is a clause, head \fIP\fP, body \fIQ\fP. +clause(\fIP\fP,\fIQ\fP,\fIR\fP) There is an clause, head \fIP\fP, body \fIQ\fP, ref \fIR\fP. +close(\fIF\fP) Close file \fIF\fP. +compare(\fIC\fP,\fIX\fP,\fIY\fP) \fIC\fP is the result of comparing terms \fIX\fP and \fIY\fP. +consult(\fIF\fP) Extend the program with clauses from file \fIF\fP. +current_atom(\fIA\fP) One of the currently defined atoms is \fIA\fP. +current_functor(\fIA\fP,\fIT\fP) A current functor is named \fIA\fP, m.g. term \fIT\fP. +current_predicate(\fIA\fP,\fIP\fP) A current predicate is named \fIA\fP, m.g. goal \fIP\fP. +db_reference(\fIT\fP) \fIT\fP is a database reference. +debug Switch on debugging. +debugging Output debugging status information. +display(\fIT\fP) Display term \fIT\fP on the terminal. +erase(\fIR\fP) Erase the clause or record, ref. \fIR\fP. +erased(\fIR\fP) The object with ref. \fIR\fP has been erased. +expanded_exprs(\fIO\fP,\fIN\fP) Expression expansion if \fIN\fP=on. +expand_term(\fIT\fP,\fIX\fP) Term \fIT\fP is a shorthand which expands to term \fIX\fP. +exists(\fIF\fP) The file \fIF\fP exists. +fail Backtrack immediately. +fileerrors Enable reporting of file errors. +functor(\fIT\fP,\fIF\fP,\fIN\fP) The top functor of term \fIT\fP has name \fIF\fP, arity \fIN\fP. +get(\fIC\fP) The next non-blank character input is \fIC\fP. +get0(\fIC\fP) The next character input is \fIC\fP. +halt Halt Prolog, exit to the monitor. +instance(\fIR\fP,\fIT\fP) A m.g. instance of the record ref. \fIR\fP is \fIT\fP. +integer(\fIT\fP) Term \fIT\fP is an integer. +\fIY\fP is \fIX\fP \fIY\fP is the value of arithmetic expression \fIX\fP. +keysort(\fIL\fP,\fIS\fP) The list \fIL\fP sorted by key yields \fIS\fP. +leash(\fIM\fP) Set leashing mode to \fIM\fP. +listing List the current program. +listing(\fIP\fP) List the procedure(s) \fIP\fP. +name(\fIA\fP,\fIL\fP) The name of atom or number \fIA\fP is string \fIL\fP. +nl Output a new line. +nodebug Switch off debugging. +nofileerrors Disable reporting of file errors. +nonvar(\fIT\fP) Term \fIT\fP is a non-variable. +nospy \fIP\fP Remove spy-points from the procedure(s) \fIP\fP. +number(\fIT\fP) Term \fIT\fP is a number. +op(\fIP\fP,\fIT\fP,\fIA\fP) Make atom \fIA\fP an operator of type \fIT\fP precedence \fIP\fP. +primitive(\fIT\fP) \fIT\fP is a number or a database reference +print(\fIT\fP) Portray or else write the term \fIT\fP. +prompt(\fIA\fP,\fIB\fP) Change the prompt from \fIA\fP to \fIB\fP. +put(\fIC\fP) The next character output is \fIC\fP. +read(\fIT\fP) Read term \fIT\fP. +reconsult(\fIF\fP) Update the program with procedures from file \fIF\fP. +recorda(\fIK\fP,\fIT\fP,\fIR\fP) Make term \fIT\fP the first record under key \fIK\fP, ref. \fIR\fP. +recorded(\fIK\fP,\fIT\fP,\fIR\fP) Term \fIT\fP is recorded under key \fIK\fP, ref. \fIR\fP. +recordz(\fIK\fP,\fIT\fP,\fIR\fP) Make term \fIT\fP the last record under key \fIK\fP, ref. \fIR\fP. +rename(\fIF\fP,\fIG\fP) Rename file \fIF\fP to \fIG\fP. +repeat Succeed repeatedly. +retract(\fIC\fP) Erase the first clause of form \fIC\fP. +save(\fIF\fP) Save the current state of Prolog in file \fIF\fP. +see(\fIF\fP) Make file \fIF\fP the current input stream. +seeing(\fIF\fP) The current input stream is named \fIF\fP. +seen Close the current input stream. +setof(\fIX\fP,\fIP\fP,\fIB\fP) The set of \fIX\fPs such that \fIP\fP is provable is \fIB\fP. +sh Start a recursive shell +skip(\fIC\fP) Skip input characters until after character \fIC\fP. +sort(\fIL\fP,\fIS\fP) The list \fIL\fP sorted into order yields \fIS\fP. +spy \fIP\fP Set spy-points on the procedure(s) \fIP\fP. +statistics Display execution statistics. +system(\fIS\fP) Execute command \fIS\fP. +tab(\fIN\fP) Output \fIN\fP spaces. +tell(\fIF\fP) Make file \fIF\fP the current output stream. +telling(\fIF\fP) The current output stream is named \fIF\fP. +told Close the current output stream. +trace Switch on debugging and start tracing. +true Succeed. +var(\fIT\fP) Term \fIT\fP is a variable. +write(\fIT\fP) Write the term \fIT\fP. +writeq(\fIT\fP) Write the term \fIT\fP, quoting names if necessary. +\&'LC' The following Prolog text uses lower case. +\&'NOLC' The following Prolog text uses upper case only. +! Cut any choices taken in the current procedure. +\e+ \fIP\fP Goal \fIP\fP is not provable. +\fIX\fP<\fIY\fP As numbers, \fIX\fP is less than \fIY\fP. +\fIX\fP=<\fIY\fP As numbers, \fIX\fP is less than or equal to \fIY\fP. +\fIX\fP>\fIY\fP As numbers, \fIX\fP is greater than \fIY\fP. +\fIX\fP>=\fIY\fP As numbers, \fIX\fP is greater than or equal to \fIY\fP. +\fIX\fP=\fIY\fP Terms \fIX\fP and \fIY\fP are equal (i.e. unified). +\fIT\fP=..\fIL\fP The functor and args. of term \fIT\fP comprise the list \fIL\fP. +\fIX\fP==\fIY\fP Terms \fIX\fP and \fIY\fP are strictly identical. +\fIX\fP\e==\fIY\fP Terms \fIX\fP and \fIY\fP are not strictly identical. +\fIX\fP@<\fIY\fP Term \fIX\fP precedes term \fIY\fP. +\fIX\fP@=<\fIY\fP Term \fIX\fP precedes or is identical \fIY\fP. +\fIX\fP@>\fIY\fP Term \fIX\fP follows term \fIY\fP. +\fIX\fP@>=\fIY\fP Term \fIX\fP follows or is identical to term \fIY\fP. +[\fIF\fP|\fIR\fP] Perform the (re)consult(s) specified by [\fIF\fP|\fIR\fP]. +.TE diff --git a/source_code/c-prolog-1982/man/app.out b/source_code/c-prolog-1982/man/app.out new file mode 100755 index 0000000..c35555c --- /dev/null +++ b/source_code/c-prolog-1982/man/app.out @@ -0,0 +1,131 @@ + + + + + + + +_A_p_p_e_n_d_i_x _I -- _S_u_m_m_a_r_y _o_f _E_v_a_l_u_a_b_l_e _P_r_e_d_i_c_a_t_e_s + +l l. +abolish(_F,_N) Abolish the procedure named _F arity _N. +abort Abort execution of the current directive. +arg(_N,_T,_A) The _Nth argument of term _T is _A. +assert(_C) Assert clause _C. assert(_C,_R) Assert +clause _C, ref. _R. asserta(_C) Assert _C as first clause. +asserta(_C,_R) Assert _C as first clause, ref. _R. +assertz(_C) Assert _C as last clause. +assertz(_C,_R) Assert _C as last clause, ref. _R. +atom(_T) Term _T is an atom. atomic(_T) Term _T is an +atom or integer. bagof(_X,_P,_B) The bag of _Xs such that _P +is provable is _B. break Break at the next procedure call. +call(_P) Execute the procedure call _P. clause(_P,_Q) There +is a clause, head _P, body _Q. clause(_P,_Q,_R) There is an +clause, head _P, body _Q, ref _R. close(_F) Close file +_F. compare(_C,_X,_Y) _C is the result of comparing terms _X and +_Y. consult(_F) Extend the program with clauses from +file _F. current_atom(_A) One of the currently defined atoms +is _A. current_functor(_A,_T) A current functor is named _A, +m.g. term _T. current_predicate(_A,_P) A current predicate is +named _A, m.g. goal _P. db_reference(_T) _T is a database +reference. debug Switch on debugging. +debugging Output debugging status information. +display(_T) Display term _T on the terminal. +erase(_R) Erase the clause or record, ref. _R. +erased(_R) The object with ref. _R has been erased. +expanded_exprs(_O,_N) Expression expansion if _N=on. +expand_term(_T,_X) Term _T is a shorthand which expands +to term _X. exists(_F) The file _F exists. +fail Backtrack immediately. fileerrors Enable re- +porting of file errors. functor(_T,_F,_N) The top functor of +term _T has name _F, arity _N. get(_C) The next non-blank +character input is _C. get0(_C) The next character input is +_C. halt Halt Prolog, exit to the monitor. +instance(_R,_T) A m.g. instance of the record ref. _R is _T. +integer(_T) Term _T is an integer. _Y is _X _Y is the +value of arithmetic expression _X. keysort(_L,_S) The list +_L sorted by key yields _S. leash(_M) Set leashing mode +to _M. listing List the current program. +listing(_P) List the procedure(s) _P. +name(_A,_L) The name of atom or number _A is string _L. +nl Output a new line. nodebug Switch off debugging. +nofileerrors Disable reporting of file errors. +nonvar(_T) Term _T is a non-variable. nospy _P Remove +spy-points from the procedure(s) _P. number(_T) Term _T +is a number. op(_P,_T,_A) Make atom _A an operator of +type _T precedence _P. primitive(_T) _T is a number or a da- +tabase reference print(_T) Portray or else write the +term _T. prompt(_A,_B) Change the prompt from _A to _B. +put(_C) The next character output is _C. read(_T) Read term +_T. + + + + + + + + + + + + + +reconsult(_F) Update the program with procedures from file +_F. recorda(_K,_T,_R) Make term _T the first record under key +_K, ref. _R. recorded(_K,_T,_R) Term _T is recorded under key _K, +ref. _R. recordz(_K,_T,_R) Make term _T the last record under +key _K, ref. _R. rename(_F,_G) Rename file _F to _G. +repeat Succeed repeatedly. retract(_C) Erase the first +clause of form _C. save(_F) Save the current state of Prolog +in file _F. see(_F) Make file _F the current input stream. +seeing(_F) The current input stream is named _F. +seen Close the current input stream. setof(_X,_P,_B) The +set of _Xs such that _P is provable is _B. sh Start a re- +cursive shell skip(_C) Skip input characters until after +character _C. sort(_L,_S) The list _L sorted into order +yields _S. spy _P Set spy-points on the procedure(s) _P. +statistics Display execution statistics. +system(_S) Execute command _S. tab(_N) Output _N spaces. +tell(_F) Make file _F the current output stream. +telling(_F) The current output stream is named _F. +told Close the current output stream. trace Switch on +debugging and start tracing. true Succeed. var(_T) Term +_T is a variable. write(_T) Write the term _T. +writeq(_T) Write the term _T, quoting names if neces- +sary. 'LC' The following Prolog text uses lower case. +'NOLC' The following Prolog text uses upper case only. +! Cut any choices taken in the current procedure. \+ +_P Goal _P is not provable. _X<_Y As numbers, _X is less +than _Y. _X=<_Y As numbers, _X is less than or equal to _Y. +_X>_Y As numbers, _X is greater than _Y. _X>=_Y As +numbers, _X is greater than or equal to _Y. _X=_Y Terms _X +and _Y are equal (i.e. unified). _T=.._L The functor and +args. of term _T comprise the list _L. _X==_Y Terms _X and _Y +are strictly identical. _X\==_Y Terms _X and _Y are not +strictly identical. _X@<_Y Term _X precedes term _Y. +_X@=<_Y Term _X precedes or is identical _Y. _X@>_Y Term _X +follows term _Y. _X@>=_Y Term _X follows or is identical to +term _Y. [_F|_R] Perform the (re)consult(s) specified by + + + + + + + + + + + + + + + + +9 + +9 + + + diff --git a/source_code/c-prolog-1982/man/cprolog.me b/source_code/c-prolog-1982/man/cprolog.me new file mode 100755 index 0000000..4d09a41 --- /dev/null +++ b/source_code/c-prolog-1982/man/cprolog.me @@ -0,0 +1,2891 @@ +.po 1.1i +.he 'C-Prolog\ User\'s\ Manual''%' +.ds Vn 1.5 +.tp +.(l C +.sz +4 +C-Prolog User's Manual +.sz -4 +.sp +.sp +Version \*(Vn +\*(td +.sp +Edited by Fernando Pereira\** +.(f +\**Formerly at EdCAAD, Dept. of Architecture, University of Edinburgh +.)f +SRI International, Menlo Park, California +.sp +from material by +.sp +David Warren +SRI International, Menlo Park, California +.sp +David Bowen, Lawrence Byrd +Dept. of Artificial Intelligence, University of Edinburgh +.sp +Luis Pereira +Dept. de Informatica, Universidade Nova de Lisboa +.)l +.(l C +\fIAbstract\fP +.)l +.sp +.(l F +This is a revised edition of the user's manual for C-Prolog, +a Prolog interpreter written in C for 32 bit machines. +C-Prolog is based on an earlier Prolog interpreter written +in IMP for the EMAS operating system +by Luis Damas, who borrowed many +aspects of the design from the DECsystem-10/20 Prolog system +developed by David Warren, Fernando Pereira, Lawrence Byrd +and Luis Pereira. +This manual is based on the EMAS Prolog manual, which +in turn was based on the DECsystem-10/20 Prolog manual. +.)l +.bp +.sh 1 "Using C-Prolog" +.pp +.sh 2 "Preface" +.pp +This manual describes C-Prolog, a Prolog interpreter written in C. +C-Prolog was developed at EdCAAD, Dept. of Architecture, University +of Edinburgh, and +is based on a previous interpreter, written in IMP for +the EMAS operating system by +Luis Damas of the Dept. of +Computer Science, University of Edinburgh. +C-Prolog was designed for machines with a large, uniform, address space, +and assumes a pointer cell 32 bits wide. At the time of writing, +it has been tested on VAX\** +.(f +\**VAX, VMS, PDP and DECsystem-10 are trademarks of +Digital Equipment Corporation. +.)f +machines under the \s-2UNIX\s0\** +.(f +\**\s-2UNIX\s0 is a Trademark of Bell Laboratories. +.)f +and VAX/VMS operating systems, on the Sun workstation +under 4.1/2 \s-2UNIX\s0, +and has been ported with minor changes to +other MC68000-based workstations and to the Three Rivers PERQ. +.pp +Prolog is a simple but powerful programming language +originally developed at the University of Marseilles, as +a practical tool for programming in logic. +From a user's point of view the major attraction of the language +is ease of programming. +Clear, readable, concise programs can be written quickly with few errors. +Prolog is especially suitable for high-level symbolic programming tasks +and has been applied in many areas of Artificial Intelligence research. +.pp +The system consists of a Prolog interpreter and a wide range of +builtin (system defined) procedures. +Its design was based on the (Edinburgh) DECsystem-10 Prolog system and the system +is closely compatible with DECsystem-10 Prolog and thus is also +reasonably close to PDP-11 \s-2UNIX\s0 and RT-11 Prolog. +.pp +This manual is not intended as an introduction to +the Prolog language and how to use it. +For this purpose you should study: +.(l +\fIProgramming in Prolog\fP +W. Clocksin & C. Mellish +Springer Verlag 1981 +.)l +.pp +This manual assumes that you are familiar with the principles of the +Prolog language, its purpose being to explain how to use C-Prolog, +and to describe all the evaluable predicates provided by C-Prolog. +.sh 2 "Using C-Prolog \*- Overview" +.pp +C-Prolog offers the user +an interactive programming environment with +tools for incrementally building programs, debugging programs by following +their executions, and modifying parts of programs without having to +start again from scratch. +.pp +The text of a Prolog program is normally created in a +number of files +using a text editor. +C-Prolog can then be instructed to read-in programs +from these files; this is called \fIlconsulting\fP the file. +To change parts of a program being run, it is possible +to \fIreconsult\fP files containing the changed parts. +Reconsulting means that definitions for procedures in the file will +replace any old definitions for these procedures. +.pp +It is recommended that you make use of a number of different files +when writing programs. +Since you will be editing and consulting/reconsulting +individual files it is useful to use files to group together related +procedures; +keeping collections of procedures that do different things in different files. +Thus a Prolog program will consist of a number of files, +each file containing a number of related procedures. +.pp +When your programs start to grow to a fair size, it is also a good idea +to have one file which just contains commands to the interpreter +to consult all the other files which form a program. +You will then be able to consult your entire program by just consulting +this single file. +.sh 2 "Access to C-Prolog" +.pp +In this manual, +we assume that there is a command on your computer +.(l +prolog +.)l +that invokes C-Prolog. +.pp +We assume that there are three keys or key combinations that achieve +the effects of terminating an input line, marking end of input, +and interrupting execution of a program. Because these depend +on operating system and individual tastes, they are denoted in this manual +by \s-2END-OF-LINE\s0, \s-2END-OF-INPUT\s0 and \s-2INTERRUPT\s0 respectively +(they are carriage return, control-Z and control-C on the computer +this is being written on). +.pp +Since Prolog makes syntactic use of the difference between upper and +lower case it is important that you have your terminal set up +so that it accepts lower case in the normal way. +This means, for a start, that you must be using an upper and lower case +terminal - and not, for example, an upper case only teletype. +It is possible to use Prolog using upper case only +(see Section 2.4) +but it is unnecessarily painful. +We shall assume both upper and lower case throughout this manual. + +If you type the `prolog' command, +Prolog will output a banner and prompt you for directives as follows: +.(l +C-Prolog version \*(Vn +| ?- +.)l +There will be a pause between the first line and the prompt while the +system loads itself. It is possible to type ahead during this period if +you get impatient. +.pp +If you give an argument to the `prolog' command, +C-Prolog will interpret it as the name of a file containing +a saved state created earlier, and will restore that saved state. +Saved states will be explained fully later. +.(l +prolog prog (Restore \*(lqprog\*(rq) +.)l +.pp +C-Prolog uses six major internal data areas: the \fIheap\fP, +the \fIglobal stack\fP, the \fIlocal stack\fP, the \fItrail\fP, +the \fIatom area\fP and the \fIauxiliary stack\fP. Although +the system is initially configured with reasonable allocations +for each of those areas, a particular program might exceed +one of the allocations, causing an error message. Ideally, +the system should adjust the available storage among areas +automatically, but this facility is not implemented yet. +Instead, the user may specify when starting Prolog the allocations +(in K bytes) for some or all of the areas. This is done by giving +command line switches between the program name and the optional +file argument. For example, +.(l +prolog -h 1000 -g 1000 -l 500 bigprogram +.)l +specifies heap and global stack allocations of 1000 K and a local +stack allocation of 500 K. The full set of switches is: +.(l +.TS +l l. +-h \fIN\fP heap allocation is \fIN\fP K bytes +-g \fIN\fP global stack allocation is \fIN\fP K bytes +-l \fIN\fP local stack allocation is \fIN\fP K bytes +-t \fIN\fP trail allocation is \fIN\fP K bytes +-a \fIN\fP atom area allocation is \fIN\fP K bytes +-x \fIN\fP auxiliary stack allocation is \fIN\fP K bytes +.TE +.)l +.sh 2 "Reading-in Programs" +.pp +A program is made up of a sequence of clauses, possibly +interspersed with directives to the interpreter. The clauses of a +procedure do not have to be immediately consecutive, but remember that +their relative order may be important. +.pp +To input a program from a file \fIfile\fP, give the directive: +.(l +| ?- [\fIfile\fP]. +.)l +which will instruct the interpreter to consult the program. +The file specification \fIfile\fP must be a Prolog atom. +It may be any file name, note that if this file name contains +characters which are not normally allowed in an atom +then it is necessary to surround the whole file specification with +single quotes (since quoted atoms can include any character), for example +.(l +| ?- ['people/greeks']. +.)l +The specified file is then read in. +Clauses in the file are stored in the database ready to be +executed, while any directives +are obeyed as they are encountered. +When the end of the file is found, the +interpreter displays on the terminal the time spent in reading-in and +the number of bytes occupied by the program. +.pp +In general, this directive can be any list of filenames, such as: +.(l +| ?- [myprogram, extras, testbits]. +.)l +In this case all three files would be consulted. If a filename is preceded +by a minus sign, as in: +.(l +| ?- [-testbits, -moreideas]. +.)l +then that file is reconsulted. The difference between consulting and +reconsulting is important, and works as follows: +if a file is consulted then all the clauses in the file are simply added +to C-Prolog's database. If you consult the same file twice then you will +get two copies of all the clauses. +However, if a file is reconsulted then the clauses for all +the procedures in the file will replace any existing clauses for those +procedures, that is +any such previously existing clauses in the database get thrown away. +Reconsulting is useful for telling Prolog about corrections in your program. +.pp +Clauses may also be typed in directly at the terminal. +To enter clauses at the terminal, +you must give the directive: +.(l +| ?- [user]. +.)l +The interpreter is now in a state where it expects input of clauses or +directives. +To get back to the top level of the interpreter, type the \s-2END-OF-INPUT\s0 +character. +.pp +Typing clauses directly into C-Prolog +is only recommended if the clauses will not be needed +permanently, and are few in number. +For significant bits of program you should use an editor to produce +a file containing the text of the program. +.sh 2 "Directives: Questions and Commands" +.pp +When Prolog is at top level (signified by an initial prompt of \*(lq|\ ?-\ \*(rq, +with continuation lines prompted with \*(lq|\ \ \ \ \*(rq, that is indented out from +the left margin) it reads in terms and treats them as directives to +the interpreter to try and satisfy some goals. +These directives are called questions. +Remember that Prolog terms must terminate with a period (\*(lq.\*(rq), and +that therefore Prolog will not execute anything for you until you +have typed the period (and then \s-2END-OF-LINE\s0) at the end +of the directive. +.pp +Suppose list membership has been defined by: +.(l +member(X,[X|\(ul]). +member(X,[\(ul|L]) :- member(X,L). +.)l +(Note the use of anonymous variables written \*(lq\(ul\*(rq). +.pp +If the goal(s) specified in a question can be satisfied, and if there are +no variables as in this example: +.(l +| ?- member(b,[a,b,c]). +.)l +then the system answers +.(l +yes +.)l +and execution of the question terminates. +.pp +If variables are included in the question, then the final value of each +variable is displayed (except for anonymous variables). +Thus the question +.(l +| ?- member(X,[a,b,c]). +.)l +would be answered by +.(l +X = a +.)l +At this point the interpreter is waiting for you to indicate whether +that solution is sufficient, or whether you want it to backtrack to see +if there are any more solutions. +Simply typing \s-2END-OF-LINE\s0 terminates the question, while +typing \*(lq;\*(rq followed by \s-2END-OF-LINE\s0 causes the +system to backtrack looking for alternative solutions. +If no further solutions can be found it outputs +.(l +no +.)l +The outcome of some questions is shown below, where a number +preceded by \*(lq\(ul\*(rq is a system-generated name for a variable. +.(l +| ?- member(X,[tom,dick,harry]). +X = tom ; +X = dick ; +X = harry ; +no +| ?- member(X,[a,b,f(Y,c)]),member(X,[f(b,Z),d]). +Y = b, +X = f(b,c), +Z = c + % Just \s-2END-OF-LINE\s0 typed here +yes +| ?- member(X,[f(\(ul),g]). +X = f(\(ul1728) +yes +| ?- +.)l +When C-Prolog reads terms from a file (or from the terminal following a call to +[user]), it treats them all as program clauses. In order to get the +interpreter to execute directives from a file they must be preceded by +\&`?-', for questions, or `:-', for commands. +.pp +Commands are like questions except that they do not cause +answers to be printed out. +They always start with the symbol \*(lq:-\*(rq. At top level this is simply +written after the prompted \*(lq?-\*(rq which is then effectively overridden. +Any required output must be programmed explicitly; for example, the command +.(l +:- member(3,[1,2,3]), write(ok). +.)l +directs the system to check whether 3 belongs to the list [1,2,3], and +to output \*(lqok\*(rq if so. Execution of a command terminates when all the +goals in the command have been successfully executed. Other +alternative solutions are not sought (one may imagine an implicit +\*(lqcut\*(rq at the end of the command). If no solution can be found, the +system gives: +.(l +? +.)l +as a warning. +.pp +The main use for commands (as opposed to questions) is to allow +files to contain directives which call various procedures, but for which +you don't want to have the answers printed out. +In such cases you only want to call the procedures for effect. +A useful example would be the use of a +directive in a file which consults a whole +list of other files, such as\**: +.(f +\**The extra parentheses, with the `:-' immediately +next to them, are currently essential due to a problem with +prefix operators (like `:-') and lists. They are not +required for commands that do not contain lists. +This restriction will be eventually removed. +.)f +.(l +:-([ bits, bobs, mainpart, testcases, data, junk ]). +.)l +.pp +If this directive was contained in the file `program' then typing the +following at top level would be a quick way of loading your +entire program: +.(l +| ?- [program]. +.)l +.pp +When you are +simply interacting with the top level of the Prolog interpreter +the distinction between questions and commands is not very important. +At the top level you should normally only type questions. In a file, if you +wish to execute some goals then you should use a command. +That is, to execute a +directive in a file it must be preceded by \*(lq:-\*(rq, otherwise it will be +treated as a clause. +.sh 2 "Saving A Program" +.pp +Once a program has been read, the interpreter will have available +all the information necessary for its execution. This information is +called a program \fIstate\fP. +.pp +The state of a program may be saved on a file for future execution. +To save a program into a file \fIfile\fP, perform the command: +.(l +?- save(\fIfile\fP). +.)l +\fBSave\fP can be called at top level, from within a break level (q.v.), +or from anywhere within a program. +.sh 2 "Restoring A Saved Program" +.pp +Once a program has been saved into a file \fIfile\fP, C-Prolog +can be restored to this saved state by invoking it +as follows: +.(l +prolog \fIfile\fP +.)l +After execution of this command, the interpreter will be in \fIexactly\fP the +same state as existed immediately prior to the call to \fBsave\fP, +except for open files, which are automatically closed by \fBsave\fP. +That is to say execution will start at the goal immediately following the +call to \fBsave\fP, just as if \fBsave\fP had returned successfully. +If you saved the state at top level then you will be back at top level, +but if you explicitly called \fBsave\fP from within your program then the +execution of your program will continue. +.pp +Saved states can only be restored when C-Prolog is initially run from +command level. Version \*(Vn provides no way of restoring a saved state from +inside C-Prolog. +.pp +Note that when a new version of C-Prolog is installed, +saved states created with the old version may become unusable. +You are thus advised to rely on source files for your programs and +not on some gigantic saved state. +.sh 2 "Program Execution And Interruption" +.pp +Execution of a program is started by giving the interpreter a +directive which contains a call to one of the program's procedures. +.pp +Only when execution of one directive is complete does the +interpreter become ready for another directive. However, one may +interrupt the normal execution of a directive by hitting the \s-2INTERRUPT\s0 key +on your terminal. +In response to the prompt +.(l +Action (h for help): +.)l +you can type either \*(lqa\*(rq, \*(lqt\*(rq, \*(lqd\*(rq or \*(lqc\*(rq followed by \s-2END-OF-LINE\s0. +The \*(lqa\*(rq response will force Prolog to abort back to top level, +the \*(lqt\*(rq option will switch on tracing, +the +\*(lqd\*(rq response will switch on debugging and continue the execution, +and the \*(lqc\*(rq response will just continue the execution. +.sh 2 "Nested Executions \*- Break and Abort" +.pp +C-Prolog provides a way to suspend the execution of your program +and to enter a new incarnation of the top level where you can issue +directives to solve goals etc. +When the evaluable predicate \fBbreak\fP is called, +the message +.(l +[ Break (level 1) ] +.)l +will be displayed. This signals the start of a \fIbreak\fP +and except +for the effect of \fBabort\fPs (see below), it is as if the interpreter +was at top level. +If break is called within a break, then another recursive break is +started (and the message will say (level 2) etc). +Breaks can be arbitrarily nested. +.pp +Typing the \s-2END-OF-INPUT\s0 character +will close the break and resume the execution which +was suspended, starting at the procedure call where the suspension took +place. +.pp +To abort the current execution, forcing an immediate +failure of the directive being executed +and a return to the top level of the interpreter, +call the evaluable predicate \fBabort\fP, either from the program +or by executing the directive: +.(l +| ?- abort. +.)l +within a break. In this case no \s-2END-OF-INPUT\s0 character is needed to close the +break, because \fIall\fP break levels are discarded and the system returns right +back to top level. The \*(lqa\*(rq response to \s-2INTERRUPT\s0 (described above) can also +be used to force an abort. +.sh 2 "Exiting From The Interpreter" +.pp +To exit from C-Prolog interpreter +you should give the directive: +.(l +| ?- halt. +.)l +This can be issued either at top level, or within a break, +or indeed from within your program. +.pp +If your program is still executing then you should interrupt it and abort +to return to top level +so that you can call \fBhalt\fP. +.pp +Typing +the \s-2END-OF-INPUT\s0 charater at +top level also causes C-Prolog to terminate. +.sh 1 "Prolog Syntax" +.pp +.sh 2 "Terms" +.pp +The data objects of the language are called \fIterm\fPs. +A term is either a \fIconstant\fP, a \fIvariable\fP or a \fIcompound term\fP. +.pp +The constants include \fInumber\fPs such as +.(l +0 -999 -5.23 0.23E-5 +.)l +.pp +Constants also include \fIatom\fPs such as +.(l +a void = := 'Algol-68' [] +.)l +The symbol for an atom can be any sequence of characters, +written in single quotes if there is possibility of confusion with other +symbols (such as variables or numbers). As in other programming +languages, constants are definite elementary objects. +.pp +Variables are distinguished by an initial capital letter or by +the initial character \*(lq\(ul\*(rq, for example +.(l +X Value A A1 \(ul3 \(ulRESULT +.)l +If a variable is only referred to once, it does not need to be named +and may be written as an \fIanonymous\fP variable, indicated by the +underline character \*(lq\(ul\*(rq. +.pp +A variable should be thought of as standing for some definite but +unidentified object. +A variable is not simply a writeable +storage location as in most programming languages; rather it is a +local name for some data object, cf. the variable of pure LISP and +constant declarations in Pascal. +.pp +The structured data objects of the language are the compound terms. A +compound term comprises a \fIfunctor\fP (called the \fIprincipal\fP functor of +the term) and a sequence of one or more terms called \fIarguments\fP. +A functor is characterised by its \fIname\fP, which is an atom, and its +\fIarity\fP or number of arguments. +For example the compound term whose functor is +named `point' of arity 3, with arguments X, Y and Z, is written +.(l +point(X,Y,Z) +.)l +An atom is considered to be a functor of arity 0. +.pp +One may think of a functor as a record type and the +arguments of a compound term as the fields of a record. Compound +terms are usefully pictured as trees. For example, the term +.(l +s(np(john),vp(v(likes),np(mary))) +.)l +would be pictured as the structure +.(b + s + / \e + np vp + | / \e + john v np + | | + likes mary +.)b +.pp +Sometimes it is convenient to write certain functors as \fIoperators\fP +\*- 2-ary functors may be declared as \fIinfix\fP operators and 1-ary functors +as \fIprefix\fP or \fIpostfix\fP operators. +Thus it is possible to write +.(l +X+Y (P;Q) X ]). +:- op( 1200, fx, [ :-, ?- ]). +:- op( 1100, xfy, [ ; ]). +:- op( 1050, xfy, [ -> ]). +:- op( 1000, xfy, [ ',' ]). /* See note below */ +:- op( 900, fy, [ not, \e+, spy, nospy ]). +:- op( 700, xfx, [ =, is, =.., ==, \e==, @<, @>, @=<, @>=, +\& \& \& =:=, =\e=, <, >, =<, >= ]). +:- op( 500, yfx, [ +, -, /\e, \e/ ]). +:- op( 500, fx, [ +, - ]). +:- op( 400, yfx, [ *, /, //, <<, >> ]). +:- op( 300, xfx, [ mod ]). +:- op( 200, xfy, [ ^ ]). +.TE +.)l +.pp +Operator declarations are most usefuly placed in directives at the top +of your program files. In this case the directive should be a command as +shown above. Another common method of organisation is to have one file +just containing commands to declare all the necessary operators. This file +is then always consulted first. +.pp +Note that a comma written literally as a punctuation character +can be used as though it were an infix operator of precedence 1000 and +type `xfy': +.(l +X,Y ','(X,Y) +.)l +represent the same compound term. But note that a comma written as a +quoted atom is \fInot\fP a standard operator. +.pp +Note also that the arguments of a compound term written in +standard syntax must be expressions of precedence \fIbelow\fP 1000. Thus it +is necessary to bracket the expression \*(lqP:-Q\*(rq in +.(l +assert((P:-Q)) +.)l +The following syntax restrictions serve to +remove potential ambiguity associated with prefix operators. +.ip - +In a term written in standard syntax, the principal functor and +its following \*(lq(\*(rq must \fInot\fP be separated by any blankspace. Thus +.(l +point (X,Y,Z) +.)l +is invalid syntax. +.ip - +If the argument of a prefix operator starts with a \*(lq(\*(rq, this \*(lq(\*(rq +must be separated from the operator by at least one space or other +non-printable character. Thus +.(l +:-(p;q),r. +.)l +(where `:-' is the prefix operator) is invalid syntax, and must be written as +.(l +:- (p;q),r. +.)l +.ip - +If a prefix operator is written without an argument, as an +ordinary atom, the atom is treated as an expression of the same +precedence as the prefix operator, and must therefore be bracketed +where necessary. Thus the brackets are necessary in +.(l +X = (?-) +.)l +.sh 2 "Syntax Errors" +.pp +Syntax errors are detected when reading. Each clause, +directive or in general any term read-in by the evaluable predicate +\fBread\fP that fails to comply with syntax requirements is displayed on the +terminal as soon as it is read. A mark indicates the point in the +string of symbols where the parser has failed to continue its analysis. +For example, typing +.(l +member(X,X L). +.)l +gives: +.(l +***syntax error*** +member(X,X +***here*** + L). +.)l +.pp +Syntax errors do not disrupt the (re)consulting of a file in any way +except that the clause or command +with the syntax error will be ignored\** +.(f +\**After all, it could not +be read. +.)f +All the other clauses in the file will have been read-in +properly. +If the syntax error occurs at top level then you should just retype the +question. +Given that Prolog has a very simple syntax it is usually quite +straightforward +to see what the problems is (look for missing brackets in particular). +The book \fIProgramming in Prolog\fP gives +further examples. +.sh 2 "Using a Terminal without Lower-Case" +.pp +The syntax of Prolog assumes that a full ASCII character +set is available. With this \fIfull character set\fP or `LC' convention, +variables are (normally) distinguished by an initial capital letter, +while atoms and other functors must start with a lower-case letter +(unless enclosed in single quotes). +.pp +When lower-case is not available, the \fIno lower-case\fP or `NOLC' +convention has to be adopted. With this convention, variables must be +distinguished by an initial underline character \*(lq\(ul\*(rq, and the names of +atoms and other functors, which now have to be written in upper-case, +are implicitly translated into lower-case (unless enclosed in single +quotes). For example, +.(l +\(ulVALUE2 +.)l +is a variable, while +.(l +VALUE2 +.)l +is `NOLC' convention notation for the atom which is identical to: +.(l +value2 +.)l +written in the `LC' convention. +.pp +The default convention is `LC'. To switch to the no lower-case +convention, call the evaluable predicate `NOLC': +.(l +| ?- 'NOLC'. +.)l +To switch back to the full character set convention, call the +evaluable predicate `LC': +.(l +| ?- 'LC'. +.)l +.pp +Note that the names of these two procedures consist of upper-case +letters (so that they can be referred to on all devices), and +therefore the names must \fIalways\fP be enclosed in single quotes. +.pp +It is recommended that the `NOLC' convention only be used in emergencies, +since the standard syntax is far easier to use and +is also easier +for other people to read. +.sh 1 "The Meaning of Prolog Programs" +.sh 2 "Programs" +.pp +A fundamental unit of a logic program is the \fIliteral\fP, for instance +.(l +gives(tom,apple,teacher) reverse([1,2,3],L) X/ +is used, for example \fBconcatenate\fP/3. +.pp +Certain predicates are +predefined by procedures supplied by the Prolog system. Such predicates are +called \fIevaluable predicates\fP. +.pp +As we have seen, the goals in the body +of a clause are linked by the operator `,' which can be interpreted as +conjunction (\*(lqand\*(rq). It is sometimes convenient to use an additional +operator `;', standing for disjunction (\*(lqor\*(rq) (The precedence of `;' is such +that it dominates `,' but is dominated by `:-'.). An example is the clause. +.(l +grandfather(X,Z) :- (mother(X,Y); father(X,Y)), father(Y,Z). +.)l + which can be +read as +.(l +\*(lqFor any X, Y and Z, X has Z as a grandfather if either the mother +of X is Y or the father of X is Y, and the father of Y is Z.\*(rq +.)l +Such uses of disjunction can always be eliminated by defining an +extra predicate - for instance the previous example is equivalent to +.(l +grandfather(X,Z) :- parent(X,Y), father(Y,Z). +parent(X,Y) :- mother(X,Y). +parent(X,Y) :- father(X,Y). +.)l +and so disjunction will not be mentioned further in the following, more +formal, description of the semantics of clauses. +.sh 2 "Declarative and Procedural Semantics" +.pp +The semantics of definite clauses should be fairly clear from the informal +interpretations already given. However it is useful to have a precise +definition. The \fIdeclarativesemantics\fP of definite clauses tells us which goals +can be considered true according to a given program, and is defined recursively +as follows. +.(l F +A goal is \fItrue\fP if it is the head of some clause instance and each of +the goals (if any) in the body of that clause \fIinstance\fP is true, where +an instance of a clause (or term) is obtained by substituting, for each +of zero or more of its variables, a new term for all occurrences of the +variable. +.)l +For example, if a program contains the preceding procedure for +\fBconcatenate\fP, +then the declarative semantics tells us that +.(l +concatenate([a],[b],[a,b]) +.)l +is true, because this goal is the head of a certain instance of the first +clause for \fBconcatenate\fP, namely, +.(l +concatenate([a],[b],[a,b]) :- concatenate([],[b],[b]). +.)l +and we know that the only goal in the body of this clause instance is true, +since it is an instance of the unit clause which is the second clause for +\fBconcatenate\fP. +.pp +The declarative semantics makes no reference to the sequencing of +goals within the body of a clause, nor to the sequencing of clauses within a +program. This sequencing information is, however, very relevant for the +\fIprocedural semantics\fP which Prolog gives to definite clauses. The procedural +semantics defines exactly how the Prolog system will execute a goal, and the +sequencing information is the means by which the Prolog programmer directs the +system to execute his program in a sensible way. The effect of executing a +goal is to enumerate, one by one, its true instances. Here then is an informal +definition of the procedural semantics. +.(l F +To execute a goal, the system searches forwards from the beginning of +the program for the first clause whose head \fImatches\fP or \fIunifies\fP with the +goal. The unification process finds the most general +common instance of the two terms, which is unique if it exists. If a +match is found, the matching clause instance is then activated by +executing in turn, from left to right, each of the goals (if any) in +its body. If at any time the system fails to find a match for a goal, +it \fIbacktracks\fP, that is it rejects the most recently activated clause, +undoing any substitutions made by the match with the head of the +clause. Next it reconsiders the original goal which activated the +rejected clause, and tries to find a subsequent clause which also +matches the goal. +.)l +For example, if we execute the goal in the query +.(l +:- concatenate(X,Y,[a,b]). +.)l +we find that it matches the head of the first clause for \fBconcatenate\fP, with X +instantiated to [a|X1]. The new variable X1 is constrained by the new goal +produced, which is the recursive procedure call +.(l +concatenate(X1,Y,[b]) +.)l +Again this goal matches the first clause, instantiating X1 to [b|X2], and +yielding the new goal +.(l +concatenate(X2,Y,[]) +.)l +Now this goal will only match the second clause, instantiating both X2 and Y to +[]. Since there are no further goals to be executed, we have a solution +.(l +X = [a,b] +Y = [] +.)l +representing a true instance of the original goal +.(l +concatenate([a,b],[],[a,b]) +.)l +If this solution is rejected, backtracking will generate the further +solutions +.(l +X = [a] +Y = [b] + +X = [] +Y = [a,b] +.)l +in that order, by rematching, against the second clause for \fBconcatenate\fP, goals +already solved once using the first clause. +.sh 2 "Occurs Check" +.pp +Prolog's unification does not have an \fIoccurs check\fP, i.e. when unifying a +variable against a term the system does not check whether the variable occurs +in the term. When the variable occurs in the term, unification should fail, +but the absence of the check means that the unification succeeds, producing a +\fIcircular term\fP. Trying to print a circular term, or trying to unify two +circular terms, will cause an infinite loop and possibly make Prolog +run out of stack space. +.pp +The absence of the occur check is not a bug or design oversight, but a +conscious design decision. The reason for this decision is that unification +with the occur check is at best linear on the sum of the sizes of the terms +being unified, whereas unification without the occur check is linear on the +size of the smallest of the terms being unified. In any practical programming +language, basic operations are supposed to take constant time. +Unification against a variable should be thought of as the basic +operation of Prolog, but this can take constant time only if the occur check is +omitted. Thus the absence of a occur check is essential to make Prolog into a +practical programming language. The inconvenience caused by this restriction +seems in practice to be very slight. Usually, the restriction is only felt in +toy programs. +.sh 2 "The Cut Symbol" +.pp +Besides the sequencing of goals and clauses, Prolog provides one other very +important facility for specifying control information. This is the \fIcut\fP symbol, +written \*(lq!\*(rq. It is inserted in the program just like a goal, but is not to be +regarded as part of the logic of the program and should be ignored as far as +the declarative semantics is concerned. +.pp +The effect of the cut symbol is as follows. When first encountered as a goal, +cut succeeds immediately. If backtracking should later return to the cut, the +effect is to fail the \fIparent goal\fP, the goal which matched the head of +the clause containing the cut, and caused the clause to be activated. In other +words, the cut operation commits the system to all choices made since the +parent goal was invoked, and causes other alternatives to be discarded. The +goals thus rendered \fIdeterminate\fP are the parent goal itself, any goals +occurring before the cut in the clause containing the cut, and any subgoals +which were executed during the execution of those preceding goals. +.pp +For example, the procedure +.(l +member(X,[X|L]). +member(X,[Y|L]) :- member(X,L). +.)l +can be used to test whether a given term is in a list, and the goal +.(l +:- member(b,[a,b,c]). +.)l +will succeed. +The procedure can also be used to extract elements +from a list, as in +.(l +:- member(X,[d,e,f]). +.)l +With backtracking this will successively return each element of the list. Now +suppose that the first clause had been written instead: +.(l +member(X,[X|L]) :- !. +.)l +In this case, the above call would extract only the first element of the list +(`d'). On backtracking, the cut would immediately fail the whole procedure. +.pp +A procedure of the form +.(l +\fIx\fP :- \fIp\fP, !, \fIq\fP. +\fIx\fP :- \fIr\fP. +.)l +is similar to +.(l +\fIx\fP := if \fIp\fP then \fIq\fP else \fIr\fP; +.)l +in an Algol-like language. +.pp +A cut discards all the alternatives since the parent +goal, even when the cut appears within a disjunction. This means that the +normal method for eliminating a disjunction by defining an extra predicate +cannot be applied to a disjunction containing a cut. +.sh 1 "Debugging Facilities" +.pp +This section describes the debugging facilities that are available +in C-Prolog. The purpose of these facilities is to provide +information concerning the control flow of your program. The main +features of the debugging package are as follows: +.ip - +The \fIProcedure box\fP +model of Prolog execution which provides a simple way of visualising +control flow, especially during backtracking. Control flow is viewed at +the procedure level, rather than at the level of individual clauses. +.ip - +The ability to exhaustively trace your program or to selectively set +\fIspy points\fP. Spy points allow you to nominate interesting procedures at +which the program is to pause so that you can interact. +.ip - +The wide choice of control and information options available during +debugging. +.pp +Much of the information in this chapter is similar +but not identical to that of Chapter 8 of \fIProgramming in Prolog\fP. +.sh 2 "The Procedure Box Control Flow Model" +.pp +During debugging the interpreter prints out a sequence of goals in +various states of instantiation in order to show the state the program has +reached in its execution. However, in order to understand what is +occurring it is necessary to understand when and why the interpreter prints +out goals. As in other programming languages, key points of interest +are procedure entry and return, but in Prolog there is the additional +complexity of backtracking. One of the major confusions that novice +Prolog programmers have to face is the question of what actually happens when +a goal fails and the system suddenly starts backtracking. The Procedure +Box model of Prolog execution views program control flow in terms of +movement about the program text. This model provides a basis for the +debugging mechanism in the interpreter, and enables the user to view the +behaviour of his program in a consistent way. +.pp +Let us look at an example Prolog procedure: +.(b + *--------------------------------------* + Call | | Exit + ---------> + descendant(X,Y) :- of\&fspring(X,Y). + ---------> + | | + | descendant(X,Z) :- | + <--------- + of\&fspring(X,Y), descendant(Y,Z). + <--------- + Fail | | BackTo + *--------------------------------------* +.)b +The first clause states that Y is a descendant of X if Y is an offspring of +X, and the second clause states that Z is a descendant of X if Y is an +offspring of X and if Z is a descendant of Y. In the diagram a box has been +drawn around the whole procedure and labelled arrows indicate the control +flow in and out of this box. There are four such arrows which we shall look +at in turn. +.lp +Call +.ip +This arrow represents initial invocation of the procedure. When a +\fBdescendant\fP goal of the form \fBdescendant\fP(X,Y) is required to +be satisfied, control passes through the Call \fIport\fP of the +\fBdescendant\fP box with the intention of matching a component clause and +then satisfying any subgoals in the body of that clause. Notice +that this is independent of whether such a match is possible, that is first +the box is called, and then the attempt to match takes place. Textually we +can imagine moving to the code for \fBdescendant\fP when meeting a call to +\fBdescendant\fP in some other part of the code. +.lp +Exit +.ip +This arrow represents a successful return from the procedure. This +occurs when the initial goal has been unified with one of the component +clauses and any subgoals have been satisfied. Control now passes out of +the Exit port of the \fBdescendant\fP box. Textually we stop following the +code for \fBdescendant\fP and go back to the place we came from. +.lp +BackTo +.ip +This arrow indicates that a subsequent goal has failed and that the system +has come back to this goal in an attempt to match the goal against another +clause. Control passes through the BackTo port of the \fBdescendant\fP +box in an attempt to rematch the original goal with an alternative clause +and then try to satisfy any subgoals in the body of this new clause. +Textually we follow the code backwards up the way we came looking for +new ways of succeeding, possibly dropping down on to another clause +and following that if necessary. Note that this is somewhat less informative +than the Redo port described in \fIProgramming in Prolog\fP, because it does not +show the path in the program from a failed goal back to the first goal where +alternative clauses exist, but only this goal. +.lp +Fail +.ip +This arrow represents +a failure of the initial goal, which might occur if no clause is matched, +or if subgoals are never satisfied, or if any solution produced is always +rejected by later processing. Control now passes out of the Fail port of the +\fBdescendant\fP box and the system continues to backtrack. Textually we +move back to the code which called this procedure and keep moving backwards +up the code looking for choice points. +.pp +In terms of this model, the +information we get about the procedure box is only the control flow through +these four ports. This means that at this level we are not concerned +with which clause matches, and how any subgoals are satisfied, but +rather we only wish to know the initial goal and the final outcome. +However, it can be seen that whenever we are trying to satisfy subgoals, +what we are actually doing is passing through the ports of \fItheir\fP +respective boxes. If we were to follow this, then we would have +complete information about the control flow inside the procedure box. + +Note that the box we have drawn round the procedure should really be seen as +an \fIinvocation box\fP. That is, there will be a different box for each +different invocation of the procedure. Obviously, with something like +a recursive procedure, there will be many different Calls and Exits in the +control flow, but these will be for different invocations. Since this might +get confusing each invocation box is given a unique integer identifier. +.sh 2 "Basic Debugging Predicates" +.pp +The interpreter provides a range of evaluable predicates for control of +the debugging facilities. The most basic predicates are as follows: +.lp +\fBdebug\fP +.ip +Switches \fIdebug mode\fP on. (It is initially off.) In order for the +full range of control flow information to be available it is necessary +to have this on from the start. When it is off the system does not +remember invocations that are being executed. (This is because it is +expensive and not required for normal running of programs.) You can +switch debug mode on in the middle of execution, either from within your +program or after an interrupt (see \fBtrace\fP below), but information prior +to this will just be unavailable. +.lp +\fBnodebug\fP +.ip +switches debug mode off. If there are any spy points set then they +will be removed. +.lp +\fBdebugging\fP +.ip +prints onto the terminal information about the current debugging +state. It shows whether debug mode is on or off and gives various +other information to be described later. +.sh 2 "Tracing" +.pp +The following evaluable predicate may be used to commence an exhaustive +trace of a program. +.lp +\fBtrace\fP +.ip +Switches debug mode on, if it is not on already, and ensures that +the next time control enters a procedure box, a message will be +produced and you will be asked to interact. +.pp +When stopped at a goal being traced, +you have a number of options which will be detailed later. +In particular, you can just type \s-2END-OF-LINE\s0 (carriage-return) to creep (or +single-step) into your program. If you continue to creep through your +program you will see every entry and exit to/from every invocation box. +However, you will notice that you are only given the opportunity to +interact on Call and BackTo ports, i.e. a single creep decision may take you +through several Exit ports or several Fail ports. Normally this is +desirable, as it would be tedious to go through all those ports step by step. +However, if it is not what you want, the following evaluable predicate gives +full control over the ports at which you are prompted. +.lp +\fBleash\fP(\fIMode\fP) +.ip +Sets the \fIleashing mode\fP to \fIMode\fP, where +\fIMode\fP can be one of the following +.(l +.TS +l l. +full prompt on Call, Exit, BackTo and Fail +tight prompt on Call, BackTo and Fail +half prompt on Call and BackTo +loose prompt on Call +off never prompt +.TE +.)l +or any other combination of ports as described later. +The initial \fIleashing mode\fP is `half'. +.sh 2 "Spy Points" +.pp +For programs of any size, it is clearly impractical to creep through the +entire program. Spy points make it possible to stop the program whenever it +gets to a particular procedure which is of interest. Once there, one can +set further spy points in order to catch the control flow a bit further +on, or one can start creeping. +.pp +Setting a spy-point on a procedure indicates that you wish to see all +control flow through the various ports of its invocation boxes. When +control passes through any port of a procedure with a spy-point set on it, a +message is output and the user is asked to interact. Note that the current +mode of leashing does not affect spy points: user interaction is requested on +\fIevery\fP port. +.pp +Spy points are set and removed by the following evaluable predicates which +are also standard operators: +.lp +\fBspy\fP \fIX\fP +.ip +Sets spy points on all the procedures given by \fIX\fP. \fIX\fP is either a +single predicate specification, or a list of such specifications. +A predicate specification is either of the form /, +which means the procedure with the name and an arity of + (for example member/2, foo/0, hello/27), or it is of the form +, which means all the procedures with the name that +currently have clauses in the data-base (e.g. member, foo, hello). +This latter form may refer to multiple procedures which have the +same name but different arities. If you use the form but +there are no clauses for this predicate (of any arity) then nothing +will be done. If you really want to place a spy point on a +currently non-existent procedure, then you must use the full form +/; you will get a warning message in this case. If +you set some spy points when debug mode is off then it will be +automatically switched on. +.lp +\fBnospy\fP \fIX\fP +.ip +This reverses the effect of spy \fIX\fP: all the procedures given by \fIX\fP +will have previously set spy points removed from them. +.pp +The options available when you arrive at a spy-point are described below. +.sh 2 "Format of Debugging Messages" +.pp +We will now look at the exact format of the message output by the system at +a port. All trace messages are output to the terminal regardless of where +the current output is directed. (This allows you to trace programs while +they are performing file I/O.) The basic format is as follows: +.(l +** (23) 6 Call : foo(hello,there,\(ul123) ? +.)l +The \*(lq**\*(rq indicates that this is a spy-point. If this port is not for +a procedure with a spy-point set, then there will be two spaces there +instead. If this port is the requested return from a Skip then the +second character becomes \*(lq>\*(rq. This gives four possible combinations: +.(l +.TS +l lt. +\*(lq**\*(rq This is a spy-point. +\*(lq*>\*(rq T{ +This is a spy-point, and you also did a Skip last time you were in +this box. +T} +\*(lq >\*(rq T{ +This is not a spy-point, but you did a Skip last time you were in +this box. +T} +\*(lq \*(rq This is not a spy-point. +.TE +.)l +.lp +The number in parentheses is the unique invocation identifier. This +is continuously incrementing regardless of whether or not you are actually +seeing the invocations (provided that debug mode is on). This number can +be used to cross correlate the trace messages for the various ports, since +it is unique for every invocation. It will also give an indication +of the number of procedure calls made since the start of the execution. The +invocation counter starts again for every fresh execution of a command, and +it is also reset when retries (see later) are performed. +.pp +The number following this is the current depth, that is, the number of +direct ancestors this goal has. +.pp +The next word specifies the particular port (Call, Exit, BackTo or Fail). +.pp +The goal is then printed so that you can inspect its current +instantiation state. +.pp +The final \*(lq?\*(rq is the prompt indicating that you should type in one of +the option codes allowed (see next section). If this particular port is +unleashed then you will obviously not get this prompt since you have +specified that you do not wish to interact at this point. +.pp +Notice that not all procedure calls are traced; there are a few +basic procedures which have been made invisible since it is more convenient +not to see them. These include all primitive I/O evaluable predicates +(for example \fBget\fP, \fBput\fP, \fBread\fP, \fBwrite\fP), all basic control +structures (that is, `,', `;', `->') and all debugging control evaluable +predicates (for instance, \fBdebug\fP, \fBspy\fP, \fBleash\fP, \fBtrace\fP). +This means that you will never see messages concerning these predicates +during debugging. +.sh 2 "Options Available during Debugging" +.pp +This section describes the particular options that are available when +the system prompts you after printing out a debugging message. All the +options are one letter mnemonics. They are read from the terminal with +any blanks being completely ignored up to the next end of line. +The \fIcreep\fP option needs only the new line. + +The only option which you really have to remember is \*(lqh\*(rq. This provides +help in the form of the following list of available options: +.(l +.TS +l l l l. +\s-2END-OF-LINE\s0 creep a abort +c creep f fail +l leap b break +s skip h help +r retry r retry goal +q quasi-skip n nodebug +g goal stack [ read clauses from terminal +e exit Prolog +.TE +.)l +The first three options are the basic control decisions: +.lp +\fBc\fP, \s-2END-OF-LINE\s0: Creep +.ip +Causes the interpreter to single-step to the very next port and print a +message. Then if the port is leashed the user is +prompted for further interaction. Otherwise it continues creeping. If +leashing is off, creep is the same as leap (see below) except that a +complete trace is printed on the terminal. +.lp +\fBl\fP: Leap +.ip +causes the interpreter to resume running your program, only stopping +when a spy-point is reached (or when the program terminates). Leaping +can thus be used to follow the execution at a higher level than +exhaustive tracing. All you need to do is to set spy points on an +evenly spread set of pertinent procedures, and then follow the control +flow through these by leaping from one to the other. +.lp +\fBs\fP: Skip +.ip +Skip is only valid for Call and BackTo ports. It skips over the entire +execution of the procedure. That is, you will not see anything until +control comes back to this procedure (at either the Exit port or the +Fail port). Skip is particularly useful while creeping since it +guarantees that control will be returned after the (possibly complex) +execution within the box. If you skip then no message at all will +appear until control returns. This includes calls to procedures with +spy points set; they will be masked out during the skip. There are two +ways of overriding this : there is a Quasi-skip which does not ignore +spy points, and the \*(lqt\*(rq option after an interrupt will disable the +masking. Normally, however, this masking is just what is required! +.lp +\fBq\fP: Quasi-skip +.ip +Is like Skip except that it does not mask out spy points. If there is +a spy-point within the execution of the goal then control returns at +this point and any action can be performed there. The initial skip +still guarantees an eventual return of control, though, when the +internal execution is finished. +.lp +\fBf\fP: Fail +.ip +Transfers to the Fail port of +the current box. This puts your execution in a position +where it is about to backtrack out of the current +invocation, that is, you have manually failed the initial goal. +.lp +\fBr\fP: Retry +.ip +Transfers to the Call port of the current goal, or if given a numeric +argument \fIn\fP, to the Call port of the invocation numbered \fIn\fP. +IF the invocation being retried has been deleted by the cut control primitive, +the most recent active invocation before it will be retried. If \fIn\fP +is out of range, the current invocation is retried. +This option is extremely useful to go back to an earlier state of +computation if some point of interest was overshot in a debugging +session. Note however that side effects, such as database modification, +are not undone. +.lp +\fBg\fP: Goal Stack +.ip +Shows the goal that called the current one, and the one that called +it, and so on, that is, the \fBstack\fP of pending goals. Goals +are printed one per line, from the most recent to the least recent. +Each goal is labeled by its recursion level \fIl\fP, its invocation +number \fIi\fP and the ordinal position \fIp\fP of the clause currently +used to solve the goal. +.lp +\fBa\fP: Abort +.ip +Causes an abort of the current execution. All the execution states +built so far are destroyed and you are put right back at the top level +of the interpreter. (This is the same as the evaluable predicate +\fBabort\fP.) +.lp +\fB[\fP: Read clauses from terminal +.ip +starts reading clauses typed by the user as if doing a \fIconsult(user)\fP. +An \s-2END-OF-INPUT\s0 returns to the debugger. +.lp +\fBe\fP: Exit from Prolog +.ip +causes an irreversible exit from the Prolog system. +(This is the same as the evaluable predicate \fBhalt\fP.) +.lp +\fBh\fP: Help +.ip +Displays the table of options given above. +.lp +\fBb\fP: Break +.ip +Calls the evaluable predicate \fBbreak\fP, thus putting you at interpreter +top level with the execution so far sitting underneath you. When you +end the break with the \s-2END-OF-INPUT\s0 character, you will be reprompted at the port at which you +broke. The new execution is completely separate from the suspended +one; the invocation numbers will start again from 1 during the break. +Debug mode is not switched off as you call the break, but if you do +switch it off then it will be re-switched on when you finish the break +and go back to the old execution. However, any changes to the leashing +or to spy points will remain in effect. +.lp +\fBn\fP: Nodebug +.ip +Turns off debug mode. Notice that this is the correct way to switch +debugging off at a trace point. You cannot use the \*(lqb\*(rq option +because it always restores debug mode upon return. +.sh 2 "Reconsulting during Debugging" +.pp +It is possible, and sometimes useful, to reconsult a file whilst in the +middle of a program execution. However this can lead to unexpected +behaviour under the following circumstances: a procedure has been +successfully executed; it is subsequently re-defined by a reconsult, +and is later re-activated by backtracking. When the backtracking +occurs, all the new clauses for the procedure appear to the interpreter +to be potential alternative solutions, even though identical clauses may +already have been used. Thus large amounts of (unwanted) activity takes +place on backtracking. The problem does not arise if you do the reconsult +when you are at the Call port of the procedure to be re-defined. +.sh 1 "Evaluable Predicates" +.pp +This section describes all the evaluable predicates available in +C-Prolog. +These predicates are provided in advance by the system and they cannot +be redefined by the user. +Any attempt to add clauses or delete clauses to an evaluable predicate +fails with an error +message, and leaves the evaluable predicate unchanged. +The C-Prolog provides a fairly wide range of evaluable predicates +to perform the following tasks: +.(l +Input/Output + Reading-in programs + Opening and closing files + Reading and writing Prolog terms + Getting and putting characters +Arithmetic +Affecting the flow of the execution +Classifying and operating on Prolog terms (meta-logical facilities) +Sets +Term Comparison +Manipulating the Prolog program database +Manipulating the additional indexed database +Debugging facilities +Environmental facilities +.)l +The evaluable predicates will be described according to this +classification. Appendix I +contains +a complete list of the evaluable predicates. +.sh 2 "Input and Output" +.pp +A total of 15 I/O streams may be open at any one time for input and +output. This includes a stream that is always available +for input and output to the user's +terminal. A stream to a file \fIF\fP is opened for input by the first +\fBsee\fP(\fIF\fP) executed. \fIF\fP then becomes the current input stream. +Similarly, a stream to file \fIH\fP is opened for output by the first +\fBtell\fP(\fIH\fP) executed. \fIH\fP then becomes the current output stream. +Subsequent calls to \fBsee\fP(\fIF\fP) or to \fBtell\fP(\fIH\fP) make \fIF\fP or +\fIH\fP the current input or output stream, respectively. Any input or output +is always to the current stream. +.pp +When no input or output stream has been specified, the standard +ersatz file `user', denoting the user's terminal, is utilised for +both. +When the terminal is +waiting for input on a new line, a prompt will be displayed as follows: +.(l +.TS +l l. +\*(lq| ?- \*(rq interpreter waiting for command +\*(lq| \*(rq interpreter wating for command continuation line +\*(lq| \*(rq \fBconsult\fP(user) wating for continuation line +\*(lq|:\*(rq default for waiting for other user input +.TE +.)l +When the current input (or output) stream is closed, the user's +terminal becomes the current input (or output) stream. +.pp +The only file +that can be simultaneously open +for input and output is the ersatz file `user'. +.pp +A file is referred to by its name, \fIwritten as an atom\fP, e.g. +.(l +myfile +\&'F123' +data\(ullst +\&'tom/greeks' +.)l +.pp +All I/O errors normally cause an \fBabort\fP, except for the effect +of the evaluable predicate \fBnofileerrors\fP decribed below. +.pp +End of file is signalled on the user's terminal +by typing the \s-2END-OF-INPUT\s0 character. +Any more input requests for a file whose end has been reached causes +an error failure. +.sh 3 "Reading-in Programs" +.lp +\fBconsult\fP(\fIF\fP) +.ip +Instructs +the interpreter to read-in the program which is +in file \fIF\fP. When a directive is read it is immediately executed. When +a clause is read it is put after any clauses already read by the interpreter +for that procedure. +.lp +\fBreconsult\fP(\fIF\fP) +.ip +Like +\fBconsult\fP except that any procedure defined in the +reconsulted file erases any clauses for that procedure already +present in the interpreter. +\fBreconsult\fP makes it possible to amend a program +without having to restart from scratch and consult all the files which +make up the program. +.lp +\fB[\fP\fIFile\fP\fB|\fP\fIFiles\fP\fB]\fP +.ip +This +is a shorthand way of consulting or reconsulting a list of files. +A file name may optionally be preceded by the operator `-' to +indicate that the file should be reconsulted rather than +consulted. Thus +.(l +| ?- [file1,-file2,file3]. +.)l +is merely a shorthand for +.(l +| ?- consult(file1), reconsult(file2), consult(file3). +.)l +.sh 3 "File Handling" +.lp +\fBsee\fP(\fIF\fP) +.ip +File \fIF\fP becomes the current input stream. +.lp +\fBseeing\fP(\fIF\fP) +.ip +\fIF\fP +is unified with the name of the current input file. +.lp +\fBseen\fP +.ip +Closes +the current input stream. +.lp +\fBtell\fP(\fIF\fP) +.ip +File +\fIF\fP becomes the current output stream. +.lp +\fBtelling\fP(\fIF\fP) +.ip +\fIF\fP +is unified with the name of the current output file. +.lp +\fBtold\fP +.ip +Closes +the current output stream. +.lp +\fBclose\fP(\fIF\fP) +.ip +File +\fIF\fP, currently open for input or output, is closed. +.lp +\fBfileerrors\fP +.ip +Undoes +the effect of \fBnofileerrors\fP. +.lp +\fBnofileerrors\fP +.ip +After +a call to this predicate, the I/O error conditions +\*(lqincorrect file name ...\*(rq, \*(lqcan't see file ...\*(rq, \*(lqcan't tell file +\&...\*(rq and \*(lqend of file ...\*(rq cause a call to \fBfail\fP instead of the +default action, which is to type an error message and then call +\fBabort\fP. +.lp +\fBexists\fP(\fIF\fP) +.ip +Succeeds +if the file F exists. +.lp +\fBrename\fP(\fIF\fP,\fIN\fP) +.ip +If +File \fIF\fP is renamed to \fIN\fP. +If \fIN\fP is `[]', the file is deleted. +If \fIF\fP was a currently open stream, it is closed first. +.sh 3 "Input and Output of Terms" +.lp +\fBread\fP(\fIX\fP) +.ip +The +next term, delimited by a full stop (i.e. a \*(lq.\*(rq followed by a carriage-return +or a space), is read from the current input stream and +unified with \fIX\fP. The syntax of the term must accord with current +operator declarations. If a call \fBread\fP(\fIX\fP) causes the end of the +current input stream to be reached, \fIX\fP is unified with the atom +\&`end\(ulof\(ulfile'. Further calls to \fBread\fP for the same stream will then +cause an error failure. +.lp +\fBwrite\fP(\fIX\fP) +.ip +The +term \fIX\fP is written to the current output stream according to +operator declarations in force. +.lp +\fBdisplay\fP(\fIX\fP) +.ip +The +term \fIX\fP is displayed on the terminal in standard parenthesised +prefix notation. +.lp +\fBwriteq\fP(\fITerm\fP) +.ip +Similar +to \fBwrite\fP(\fITerm\fP), but the names of atoms and functors +are quoted where necessary to make the result acceptable as input to \fBread\fP. +.lp +\fBprint\fP(\fITerm\fP) +.ip +Print \fITerm\fP onto the current output. +This predicate provides a handle for user defined pretty printing. +If \fITerm\fP is a variable then it is written, +using \fBwrite\fP(\fITerm\fP). +If \fITerm\fP is non-variable then a call is made to +the user defined procedure \fBportray\fP(\fITerm\fP). +If this succeeds then it is assumed that \fITerm\fP has been output. +Otherwise \fBprint\fP is equivalent to \fBwrite\fP. +.sh 3 "Character Input/Output" +.lp +\fBnl\fP +.ip +A new line is started on the current output stream. +.lp +\fBget0\fP(\fIN\fP) +.ip +\fIN\fP +is the ASCII code of the next character from the current input +stream. If the current input stream reaches its end of file, +the ASCII character code for control-Z is returned and +the stream closed. +.lp +\fBget\fP(\fIN\fP) +.ip +\fIN\fP +is the ASCII code of the next non-blank printable character +from the current input stream. It has the same behaviour as \fBget0\fP +on end of file. +.lp +\fBskip\fP(\fIN\fP) +.ip +Skips +to just past the next ASCII character code \fIN\fP from the +current input stream. \fIN\fP may be an integer expression. +Skipping past the end of file causes an error. +.lp +\fBput\fP(\fIN\fP) +.ip +ASCII +character code \fIN\fP is output to the current output stream. +\fIN\fP may be an integer expression. +.lp +\fBtab\fP(\fIN\fP) +.ip +\fIN\fP +spaces are output to the current output stream. \fIN\fP +may be an integer expression. +.sh 2 "Arithmetic" +.pp +Arithmetic is performed by evaluable predicates which take as +arguments \fIarithmetic expressions\fP and \fIevaluate\fP them. +An arithmetic expression is a term built from \fIevaluable functors\fP, +numbers and variables. +At the time of evaluation, each variable in an arithmetic +expression must be bound to a number or +to an arithmetic expression. +The result of evaluation will always be converted back to an integer +if possible. +.pp +Each evaluable functor stands for an arithmetic operation. +The adjective \*(lqinteger\*(rq in the descriptions below means that +the operation only makes sense for integers, and will fail +for floating point numbers. +.pp +Because arithmetic expressions are compound terms, they use up storage +that is only recovered on backtracking. The evaluable predicate +\fBexpanded\(ulexprs\fP can be used to avoid this overhead +by preexpanding arithmetic +expressions into calls to arithmetic evaluation predicates. However, +this makes program read-in slower and clauses bigger. +.pp +In general, an arithmetic operation that combines integers and +floating point numbers will return a floating point number. +However, if the result is integral, it is converted back to +integer representation, and the same applies to numbers read in +by the reader. Thus, the goal +.(l +| ?- p(2.0). +.)l +will succeed with the clause +.(l +p(2). +.)l +and the result of the query +.(l +| ?- X is 2*1.5. +.)l +is +.(l +X = 5 +.)l +.pp +Numbers may be integers +.(l +-33 0 9999 +.)l +or floating point numbers +.(l +1.333 -2.6E+7 0.555E-2 +.)l +.pp +Note that the decimal \*(lq.\*(rq cannot be confused with the end of clause because +the latter must be followed by blank space (space, tab or \s-2END-OF-LINE\s0). +However, if an operator \*(lq.\*(rq is declared as infix, it will only be possible +to apply it to two numbers if they are separated by blank space from +the operator. +.pp +The +evaluable functors are as follows, where \fIX\fP and \fIY\fP are +arithmetic expressions. +.RS +.lp +\fIX\fP+\fIY\fP +.ip +addition +.lp +\fIX\fP-\fIY\fP +.ip +subtraction +.lp +\fIX\fP*\fIY\fP +.ip +multiplication +.lp +\fIX\fP/\fIY\fP +.ip +division +.lp +\fIX\fP//\fIY\fP +.ip +integer division +.lp +\fIX\fP mod \fIY\fP +.ip +\fIX\fP (integer) modulo \fIY\fP +.lp +-\fIX\fP +.ip +unary minus +.lp +\fBexp\fP(\fIX\fP) +.ip +exponential function +.lp +\fBlog\fP(\fIX\fP) +.ip +natural logarithm +.lp +\fBlog10\fP(\fIX\fP) +.ip +base 10 logarithm +.lp +\fBsqrt\fP(\fIX\fP) +.ip +square root +.lp +\fBsin\fP(\fIX\fP) +.ip +sine +.lp +\fBcos\fP(\fIX\fP) +.ip +cosine +.lp +\fBtan\fP(\fIX\fP) +.ip +tangent +.lp +\fBasin\fP(\fIX\fP) +.ip +arc sine +.lp +\fBacos\fP(\fIX\fP) +.ip +arc cosine +.lp +\fBatan\fP(\fIX\fP) +.ip +arc tangent +.lp +\fBfloor\fP(\fIX\fP) +.ip +the largest integer not greater than \fIX\fP +.lp +\fIX\fP^\fIY\fP +.ip +\fIX\fP to the power \fIY\fP +.lp +\fIX\fP/\e\fIY\fP +.ip +integer bitwise conjunction +.lp +\fIX\fP\/\fIY\fP +.ip +integer bitwise disjunction +.lp +\fIX\fP<<\fIY\fP +.ip +integer bitwise left shift of \fIX\fP by \fIY\fP places +.lp +\fIX\fP>>\fIY\fP +.ip +integer bitwise right shift of \fIX\fP by \fIY\fP places +.lp +\e\fIX\fP +.ip +integer bitwise negation +.lp +\fBcputime\fP +.ip +CPU time since C-Prolog was started, in seconds. +.lp +\fBheapused\fP +.ip +Heap space in use, in bytes. +.lp +[\fIX\fP] +.ip +(a list of just one element) +evaluates to \fIX\fP if \fIX\fP is an integer. +Since a quoted string is just a list of integers, this allows a quoted +character to be used in place of its ASCII code; e.g. \*(lqA\*(rq behaves within +arithmetic expressions as the integer 65. +.RE +.pp +The arithmetic evaluable predicates are as follows, where \fIX\fP and +\fIY\fP stand for arithmetic expressions, and \fIZ\fP for some term. +Note that this means that \fBis\fP only evaluates one of its arguments +as an arithmetic expression (the right-hand side one), +whereas all the comparison +predicates evaluate both their arguments. +.lp +\fIZ\fP \fBis\fP \fIX\fP +.ip +Arithmetic +expression \fIX\fP is evaluated and the result, +is unified with +\fIZ\fP. Fails if \fIX\fP is not an arithmetic expression. +.lp +\fIX\fP \fB=:=\fP \fIY\fP +.ip +The +values of \fIX\fP and \fIY\fP are equal. +.lp +\fIX\fP \fB=\=\fP \fIY\fP +.ip +The +values of \fIX\fP and \fIY\fP are not equal. +.lp +\fIX\fP\fB < \fP\fIY\fP +.ip +The +value of \fIX\fP is less than the value of \fIY\fP. +.lp +\fIX\fP\fB > \fP\fIY\fP +.ip +The +value of \fIX\fP is greater than the value of \fIY\fP. +.lp +\fIX\fP\fB =<\fP \fIY\fP +.ip +The +value of \fIX\fP is less than or equal to the value of \fIY\fP. +.lp +\fIX\fP\fB >=\fP \fIY\fP +.ip +The +value of \fIX\fP is greater than or equal to the value of \fIY\fP. +.lp +\fBexpanded\(ulexprs\fP(\fIOld\fP,\fINew\fP) +.ip +Unifies \fIOld\fP to the current value of the expression expansion flag, +and sets the value of the flag to \fINew\fP. The possible values of +the flag are `off' (the default) for not expanding arithmetic expressions +into procedure calls, and `on' to do the expansion. +.sh 2 "Convenience" +.lp +\fIP\fP \fB,\fP \fIQ\fP +.ip +\fIP\fP +and \fIQ\fP. +.lp +\fIP\fP \fB;\fP \fIQ\fP +.ip +\fIP\fP +or \fIQ\fP. +.lp +\fBtrue\fP +.ip +Always +succeeds. +.lp +\fIX\fP \fB=\fP \fIY\fP +.ip +Defined as if by the clause \*(lq Z=Z. \*(rq, +that is \fIX\fP and \fIY\fP are unified. +.sh 2 "Extra Control" +.lp +\fB!\fP +.ip +Cut (discard) all choice points made since +the parent goal started execution. +.lp +\fB\\+\fP \fIP\fP +.ip +If +the goal \fIP\fP has a solution, fail, otherwise succeed. It is +defined as if by +.(l +\e+(P) :- P, !, fail. +\e+(\(ul). +.)l +.lp +\fIP\fP \fB->\fP \fIQ\fP \fB;\fP \fIR\fP +.ip +Analogous to +.(l +\*(lqif \fIP\fP then \fIQ\fP else \fIR\fP\*(rq +.)l +i.e. defined as if by +.(l +P -> Q; R :- P, !, Q. +P-> Q; R :- R. +.)l +.lp +\fIP\fP \fB->\fP \fIQ\fP +.ip +When +occurring other than as one of the alternatives of a +disjunction, is equivalent to +.(l +\fIP\fP -> \fIQ\fP; fail. +.)l +.lp +\fBrepeat\fP +.ip +Generates +an infinite sequence of backtracking choices. It +behaves as if defined by the clauses: +.(l +repeat. +repeat :- repeat. +.)l +.lp +\fBfail\fP +.ip +Always fails. +.sh 2 "Meta-Logical" +.lp +\fBvar\fP(\fIX\fP) +.ip +Tests +whether \fIX\fP is currently instantiated to a variable. +.lp +\fBnonvar\fP(\fIX\fP) +.ip +Tests +whether \fIX\fP is currently instantiated to a non-variable term. +.lp +\fBatom\fP(\fIX\fP) +.ip +Checks +that \fIX\fP is currently instantiated to an atom (i.e. a +non-variable term of arity 0, other than a number or database reference). +.lp +\fBnumber\fP(\fIX\fP) +.ip +Checks +that \fIX\fP is currently instantiated to a number. +.lp +\fBinteger\fP(\fIX\fP) +.ip +Checks +that \fIX\fP is currently instantiated to an integer. +.lp +\fBatomic\fP(\fIX\fP) +.ip +Checks +that \fIX\fP is currently instantiated to an atom, number or database +reference. +.lp +\fBprimitive\fP(\fIX\fP) +.ip +Checks +that \fIX\fP is currently instantiated to a number or database +reference. +.lp +\fBdb\(ulreference\fP(\fIX\fP) +.ip +Checks +that \fIX\fP is currently instantiated to a database +reference. +.lp +\fBfunctor\fP(\fIT\fP,\fIF\fP,\fIN\fP) +.ip +The +principal functor of term \fIT\fP has name \fIF\fP and arity +\fIN\fP, where \fIF\fP +is either an atom or, provided \fIN\fP is 0, a number. +Initially, +either \fIT\fP must be instantiated to a non-variable, or \fIF\fP and +\fIN\fP must +be instantiated to, respectively, either an atom and a +non-negative integer or an integer and 0. If these conditions are +not satisfied, an error message is given. In the case where \fIT\fP is +initially instantiated to a variable, the result of the call is +to instantiate \fIT\fP to the most general term having the principal +functor indicated. +.lp +\fBarg\fP(\fII\fP,\fIT\fP,\fIX\fP) +.ip +Initially, +\fII\fP must be instantiated to a positive integer and +\fIT\fP to +a compound term. The result of the call is to unify \fIX\fP with the +\fII\fPth argument of term \fIT\fP. (The arguments are numbered +from 1 +upwards.) If the initial conditions are not satisfied or \fII\fP is out +of range, the call merely fails. +.lp +\fIX\fP \fB=..\fP \fIY\fP +.ip +\fIY\fP +is a list whose head is the atom corresponding to the principal +functor of \fIX\fP and whose tail is the argument list of that functor +in \fIX\fP. E.g. +.(l +product(0,N,N-1) =.. [product,0,N,N-1] + +N-1 =.. [-,N,1] + +product =.. [product] +.)l +If \fIX\fP is instantiated to a variable, then \fIY\fP must be instantiated +either to a list of determinate length whose head is an atom, or to a list of +length 1 whose head is a number. +.lp +\fBname\fP(\fIX\fP,\fIL\fP) +.ip +If +\fIX\fP is an atom or a number then \fIL\fP is a list of the +ASCII codes of the characters comprising the name of \fIX\fP. E.g. +.(l +name(product,[112,114,111,100,117,99,116]) +.)l +i.e. name(product,"product") +.(l +name(1976,[49,57,55,54]) + +name(hello,[104,101,108,108,111]) + +name([],"[]") +.)l +If \fIX\fP is instantiated to a variable, \fIL\fP must be instantiated +to a list of ASCII character codes. E.g. +.(l +| ?- name(X,[104,101,108,108,111])). + +X = hello + +| ?- name(X,"hello"). + +X = hello +.)l +.lp +\fBcall\fP(\fIX\fP) +.ip +If +\fIX\fP is instantiated to a term which would be acceptable as body +of a clause, the goal \fBcall\fP(\fIX\fP) is executed exactly as if that +term appeared textually in place of the \fBcall\fP(\fIX\fP), except that +any cut (\*(lq!\*(rq) occurring in \fIX\fP will remove only those choice points +in \fIX\fP. +If \fIX\fP is not instantiated as +described above, an error message is printed and \fBcall\fP fails. +.lp +\fIX\fP +.ip +(where +\fIX\fP is a variable) Exactly the same as \fBcall\fP(\fIX\fP). +.sh 2 "Sets" +.pp +When there are many solutions to a problem, and when all those solutions are +required to be collected together, this can be achieved by repeatedly +backtracking and gradually building up a list of the solutions. The following +evaluable predicates are provided to automate this process. +.lp +\fBsetof\fP(\fIX\fP,\fIP\fP,\fIS\fP) +.RS +.lp +Read this as \*(lq\fIS\fP is the set of all instances of \fIX\fP such that +\fIP\fP is +provable, where that set is non-empty\*(rq. The term \fIP\fP +specifies a +goal or goals as in \fBcall\fP(\fIP\fP). +\fIS\fP is a set of terms represented as a +list of those terms, without duplicates, in the standard order for +terms (see Section 5.3). If there are no instances of \fIX\fP such that +\fIP\fP is satisfied then the predicate fails. +.lp +The variables appearing in the term \fIX\fP should not appear anywhere +else in the clause except within the term \fIP\fP. Obviously, the set to +be enumerated should be finite, and should be enumerable by Prolog +in finite time. It is possible for the provable instances to +contain variables, but in this case the list \fIS\fP will only provide an +imperfect representation of what is in reality an infinite set. +.lp +If there are uninstantiated variables in \fIP\fP which do not also appear +in \fIX\fP, then a call to this evaluable predicate may backtrack, +generating alternative values for \fIS\fP corresponding to different +instantiations of the free variables of \fIP\fP. (It is to cater for +such usage that the set S is constrained to be non-empty.) For +example, the call: +.(l +| ?- setof(X, X likes Y, S). +.)l +might produce two alternative solutions via backtracking: +.(l +Y = beer, S = [dick, harry, tom] +Y = cider, S = [bill, jan, tom ] +.)l +The call: +.(l +| ?- setof((Y,S), setof(X, X likes Y, S), SS). +.)l +would then produce: +.(l +SS = [ (beer,[dick,harry,tom]), (cider,[bill,jan,tom]) ] +.)l +.lp +Variables occurring in \fIP\fP will not be treated as free if they are +explicitly bound within \fIP\fP by an existential quantifier. An +existential quantification is written: +.(l +\fIY\fP^\fIQ\fP +.)l +meaning \*(lqthere exists a \fIY\fP such that \fIQ\fP is true\*(rq, +where \fIY\fP is some Prolog variable. +For example: +.(l +| ?- setof(X, Y^(X likes Y), S). +.)l +would produce the single result: +.(l +X = [bill, dick, harry, jan, tom] +.)l +in contrast to the earlier example. +.RE +.lp +\fBbagof\fP(\fIX\fP,\fIP\fP,\fIBag\fP) +.ip +This is exactly the same as \fBsetof\fP except that the list (or +alternative lists) returned will not be ordered, and may contain +duplicates. The effect of this relaxation is to save considerable +time and space in execution. +.lp +\fIX\fP\fB^\fP\fIP\fP +.ip +The interpreter recognises this as meaning \*(lqthere exists an \fIX\fP such +that \fIP\fP is true\*(rq, and treats it as equivalent to \fBcall\fP(\fIP\fP). +The use of this explicit existential +quantifier outside the \fBsetof\fP and \fBbagof\fP +constructs is superfluous. +.sh 2 "Comparison of Terms" +.pp +These evaluable predicates are meta-logical. They treat uninstantiated +variables as objects with values which may be compared, and they never +instantiate those variables. They should \fInot\fP be used when what you really want +is arithmetic comparison (Section 5.2) or unification. +.pp +The predicates make reference to a standard total ordering of terms, which is +as follows: +.ip - +variables, in a standard order (roughly, oldest first - the order is +\fInot\fP related to the names of variables); +.ip - +Database references, roughly in order of age; +.ip - +numbers, from -\*(lqinfinity\*(rq to +\*(lqinfinity\*(rq; +.ip - +atoms, in alphabetical (i.e. ASCII) order; +.ip - +complex terms, ordered first by arity, then by the name of principal +functor, then by the arguments (in left-to-right order). +.pp +For example, here is a list of terms in the standard order: +.(l +[ X, -9, 1, fie, foe, fum, X = Y, fie(0,2), fie(1,1) ] +.)l +These are the basic predicates for comparison of arbitrary terms: +.lp +\fIX\fP \fB==\fP \fIY\fP +.ip +Tests if the terms currently instantiating \fIX\fP and \fIY\fP +are literally +identical (in particular, variables in equivalent positions in the +two terms must be identical). For example, the question +.(l +| ?- X == Y. +.)l +fails (answers \*(lqno\*(rq) because \fIX\fP and \fIY\fP +are distinct uninstantiated +variables. However, the question +.(l +| ?- X = Y, X == Y. +.)l +succeeds because the first goal unifies the two variables (see page 42). +.lp +\fIX\fP \fB\e==\fP \fIY\fP +.ip +Tests if the terms currently instantiating \fIX\fP and \fIY\fP are +not literally identical. +.lp +\fIT1\fP \fB@<\fP \fIT2\fP +.ip +Term \fIT1\fP is before term \fIT2\fP in the standard order. +.lp +\fIT1\fP \fB@>\fP \fIT2\fP +.ip +Term \fIT1\fP is after term \fIT2\fP in the standard order. +.lp +\fIT1\fP \fB@=<\fP \fIT2\fP +.ip +Term \fIT1\fP is not after term \fIT2\fP in the standard order. +.lp +\fIT1\fP \fB@>=\fP \fIT2\fP +.ip +Term \fIT1\fP is not before term \fIT2\fP in the standard order. +.pp +Some further predicates involving comparison of terms are: +.lp +\fBcompare\fP(\fIOp\fP,\fIT1\fP,\fIT2\fP) +.ip +The result of comparing terms \fIT1\fP and \fIT2\fP is \fIOp\fP, +where the possible +values for \fIOp\fP are: +.(l +\&`=' if \fIT1\fP is identical to \fIT2\fP, + +\&`<' if \fIT1\fP is before \fIT2\fP in the standard order, + +\&`>' if \fIT1\fP is after \fIT2\fP in the standard order. +.)l +Thus \fBcompare\fP(=,\fIT1\fP,\fIT2\fP) is equivalent to +\fIT1\fP \fB==\fP \fIT2\fP. +.lp +\fBsort\fP(\fIL1\fP,\fIL2\fP) +.ip +The elements of the list \fIL1\fP are sorted into the standard order, and +any identical (i.e. `==') elements are merged, yielding the list +\fIL2\fP. (The time taken to do this is at worst order (N log N) where N +is the length of \fIL1\fP.) +.lp +\fBkeysort\fP(\fIL1\fP,\fIL2\fP) +.ip +The list \fIL1\fP must +consist of items of the form \fIKey\fP-\fIValue\fP. These +items are sorted into order according to the value of \fIKey\fP, yielding +the list \fIL2\fP. No merging takes place. (The time taken to do this is +at worst order (N log N) where N is the length of L1.) +.sh 2 "Modification of the Program" +.pp +The predicates defined in this section allow modification of the program +as it is actually running. +Clauses can be added to the program (\fIasserted\fP) or removed from the program +(\fIretracted\fP). +Some of the predicates make use of an implementation-defined identifier +or \fIdatabase reference\fP +which uniquely identifies every clause in the interpreted program. +This identifier makes it possible to access clauses directly, instead of +requiring a search through the program every time. +However these facilities are intended for more complex use of the database and +are not required (and undoubtedly should be avoided) by novice users. +.lp +\fBassert\fP(\fIC\fP) +.ip +The +current instance of \fIC\fP is interpreted as a clause and is added +to the program (with new private variables +replacing any uninstantiated variables). The position of the new +clause within the procedure concerned is implementation-defined. +\fIC\fP must be instantiated to a non-variable. +.lp +\fBassert\fP(\fIClause\fP,\fIRef\fP) +.ip +Similar +to \fBassert\fP(\fIClause\fP), but also +unifies \fIRef\fP with the database reference +of the clause asserted. +.lp +\fBasserta\fP(\fIC\fP) +.ip +Like +\fBassert\fP(\fIC\fP), except that the new clause becomes the \fIfirst\fP +clause for the procedure concerned. +.lp +\fBasserta\fP(\fIClause\fP,\fIRef\fP) +.ip +Similar to +\fBasserta\fP(\fIClause\fP), but also unifies \fIRef\fP with the database reference +of the clause asserted. +.lp +\fBassertz\fP(\fIC\fP) +.ip +Like +\fBassert\fP(\fIC\fP), except that the new clause becomes the \fIlast\fP +clause for the procedure concerned. +.lp +\fBassertz\fP(\fIClause\fP,\fIRef\fP) +.ip +Similar to +\fBassertz\fP(\fIClause\fP), but also unifies \fIRef\fP with the database reference +of the clause asserted. +.lp +\fBclause\fP(\fIP\fP,\fIQ\fP) +.ip +\fIP\fP +must be bound to a non-variable term, and the +program is searched for a clause whose head matches \fIP\fP. +The head and body of those clauses are unified with \fIP\fP and \fIQ\fP +respectively. If one of the clauses is a unit clause, \fIQ\fP will be +unified with `true'. +.lp +\fBclause\fP(\fIHead\fP,\fIBody\fP,\fIRef\fP) +.ip +Similar +to \fBclause\fP(\fIHead\fP,\fIBody\fP) but also unifies \fIRef\fP with the +database reference of the clause +concerned. If \fIRef\fP is not given at the time of the call, +\fIHead\fP must be instantiated to a non-variable term. Thus this +predicate can have two different modes of use, depending on whether the +database reference of the clause is known or unknown. +.lp +\fBretract\fP(\fIC\fP) +.ip +The first clause in the +program that matches \fIC\fP is erased. +\fIC\fP must be initially instantiated to a non-variable. +The predicate may be used in a non-determinate fashion, +i.e. it will successively retract clauses matching the argument through +backtracking. +.lp +\fBabolish\fP(\fIN\fP,\fIA\fP) +.RS +Completely +remove all clauses for the procedure with name \fIN\fP (which should be +an atom), and arity \fIA\fP (which should be an integer). +.lp +The space +occupied by retracted or abolished clauses will be recovered when +instances of the clause are no longer in use. +.lp +See also \fBerase\fP (Section 5.10) which allows a clause to be +directly erased via its database reference\**. +.(f +\**This is a lower level facility, +required only for complicated database manipulations. +.)f +.RE +.sh 2 "Information about the State of the Program" +.lp +\fBlisting\fP +.ip +Lists +in the current output stream all the clauses in the +program. +.lp +\fBlisting\fP(\fIA\fP) +.ip +The argument \fIA\fP may be a predicate specification of +the form \fIName\fP/\fIArity\fP in which case only the clauses for the +specified predicate are listed. +If \fIA\fP is just an atom, then +the interpreted procedures for all predicates of that name are listed +as for \fBlisting\fP/0. +Finally, it is possible for \fIA\fP to be a list +of predicate specifications of either type, e.g. +.(l +| ?- listing([concatenate/3, reverse, go/0]). +.)l +.lp +\fBcurrent\(ulatom\fP(\fIAtom\fP) +.ip +Generates +(through backtracking) all currently known atoms, and +returns each one as \fIAtom\fP. +.lp +\fBcurrent\(ulfunctor\fP(\fIName\fP,\fIFunctor\fP) +.ip +Generates +(through backtracking) all currently known functors, +and for each one returns its name and most general term as \fIName\fP and +\fIFunctor\fP respectively. If \fIName\fP is given, only functors with +that name are generated. +.lp +\fBcurrent\(ulpredicate\fP(\fIName\fP,\fIFunctor\fP) +.ip +Similar +to \fBcurrent\(ulfunctor\fP, but it only generates functors +corresponding to predicates for which there exists +a procedure. +.sh 2 "Internal Database" +.pp +This section describes predicates for manipulating an internal indexed database +that is kept separate from the normal program database. +They are intended for more sophisticated database applications and +are not really necessary for novice users. +For normal tasks you should be able to program quite satisfactorily +just using \fBassert\fP and \fBretract\fP. +.lp +\fBrecorded\fP(\fIKey\fP,\fITerm\fP,\fIRef\fP) +.ip +The +internal database is searched for terms recorded under the key +\fIKey\fP. These terms are successively unified with \fITerm\fP in the order +they occur in the database. At the same time, \fIRef\fP is unified with +the database reference of the recorded item. +The key must be given, and may be an atom or complex term. +If it is a complex term, only the principal functor is significant. +.lp +\fBrecorda\fP(\fIKey\fP,\fITerm\fP,\fIRef\fP) +.ip +The +term \fITerm\fP is recorded in the internal database as the first +item for the key \fIKey\fP, where \fIRef\fP is its database reference. +The key must be given, and only its principal functor is +significant. +.lp +\fBrecordz\fP(\fIKey\fP,\fITerm\fP,\fIRef\fP) +.ip +The +term \fITerm\fP is recorded in the internal database as the last +item for the key \fIKey\fP, where \fIRef\fP is its database reference. +The key must be given, and only its principal functor is +significant. +.lp +\fBerase\fP(\fIRef\fP) +.ip +The +recorded item \fIor\fP clause whose database reference +is \fIRef\fP is effectively erased from the internal +database or program. +An erased item will no longer be accessible through the predicates +that search through the database, but will still be accessible +through its database reference, if this is available in +the execution state after the call to \fBerase\fP. Only when +all instances of the item's database reference have been forgotten +through database erasures and/or backtracking will the item +be actually removed from the database. +.lp +\fBerased\fP(\fI\R\fP) +.ip +Suceeds if \fIR\fP is a database reference to a database item +that has been \fBerase\fPd, otherwise fails. +.lp +\fBinstance\fP(\fIRef\fP,\fITerm\fP) +.ip +A +(most general) instance of the recorded term whose database reference +is \fIRef\fP is unified with \fITerm\fP. \fIRef\fP must be +instantiated to a database reference. Note that \fBinstance\fP +will even pick database items that have been \fBerase\fPd. +.lp +.sh 2 "Debugging" +.lp +\fBdebug\fP +.ip +Debug +mode is switched on. Information will now +be retained for debugging purposes and executions will +require more space. +.lp +\fBnodebug\fP +.ip +Debug +mode is switched off. Information is no longer retained +for debugging, and spy points are removed. +.lp +\fBtrace\fP +.ip +Debug +mode is switched on, and the interpreter starts tracing from +the next call to a user goal. +If \fBtrace\fP was given in a command on its +own, the goal(s) traced will be those of the next command. +Since this is a once-off decision, a call to trace is necessary whenever +tracing is required right from the start of an execution, otherwise +tracing will only happen at spy points. +.lp +\fBspy\fP \fISpec\fP +.ip +Spy points +will be placed on all the procedures given by \fISpec\fP. +All control flow through the ports of these procedures will henceforth +be traced. +If debug mode was previously off, then it will be switched on. +\fISpec\fP can either be a predicate specification of the form \fIName/Arity\fP +or \fIName\fP, or a list of such specifications. +When the \fIName\fP is given without the \fIArity\fP this refers to all +predicates of that name which currently have definitions. +If there are none, then nothing will be done. +Spy points can be placed on particular undefined procedures only +by using the full form, \fIName/Arity\fP. +.lp +\fBnospy\fP \fISpec\fP +.ip +Spy points +are removed from all the procedures given by \fISpec\fP +(as for \fBspy\fP). +.lp +\fBleash\fP(\fIMode\fP) +.ip +Sets the leashing mode to \fIMode\fP, where +\fIMode\fP can be one of the following +.(l +.TS +l l. +full prompt on Call, Exit, BackTo and Fail +tight prompt on Call, BackTo and Fail +half prompt on Call and BackTo +loose prompt on Call +off never prompt +\fIN\fP T{ +\fIN\fP is an integer. If the binary notation of +\fIN\fP is 2'\fIcebf\fP, the digits \fIc\fP, \fIe\fP, \fIb\fP +and \fIf\fP correspond to the Call, Exit BackTo and Fail respectively, +and are 1 (0) if the corresponding port is leashed (unleashed). +T} +.TE +.)l +The initial \fIleashing mode\fP is `half'. +.lp +\fBdebugging\fP +.ip +Outputs +information concerning the status of the debugging package. +This will show whether debug mode is on, and if it is +.(l +what spy points have been set + +what mode of leashing is in force. +.)l +.sh 2 "Environmental" +.pp +.lp +\&'\fBNOLC\fP' +.ip +Establishes +the no lower-case convention described in Section +2.4. +.lp +\&'\fBLC\fP' +.ip +Establishes +the full character set convention described in +Section 2.4. It is the default setting. +.lp +\fBop\fP(\fIpriority\fP,\fItype\fP,\fIname\fP) +.ip +Treat +name \fIname\fP as an operator of the stated \fItype\fP and +\fIpriority\fP +(refer to Section 2.2). +\fIname\fP may also be a list of names in which +case all are to be treated as operators of the stated \fItype\fP and +\fIpriority\fP. +.lp +\fBbreak\fP +.ip +Causes +the current execution to be suspended at the next +procedure call. Then the message \*(lq[ Break (level 1) ]\*(rq is +displayed. The interpreter is then ready to accept input as +though it was at top level. +If another call of \fBbreak\fP is encountered, it moves up to level 2, and +so on. +To close the break and resume the +execution which was suspended, type the \s-2END-OF-INPUT\s0 character. +Execution will be resumed at the procedure call where +it had been suspended. Alternatively, the suspended execution +can be aborted by calling the evaluable predicate \fBabort\fP. Refer +to Section 1.9. +.lp +\fBabort\fP +.ip +Aborts +the current execution taking you back to top level. +Refer to Section 1.9. +.lp +\fBsave\fP(\fIF\fP) +.ip +The +system saves the current state of the system into file \fIF\fP. +Refer to Section 1.6. +.lp +\fBsave\fP(\fIF\fP,\fIWhen\fP) +.ip +Saves the current state of the system into file \fIF\fP. +\fBWhen\fP is unified with 0 or 1 depending on whether the +system is returning from the \fBsave\fP goal in the original Prolog +session or after the saved state in \fIF\fP has been restored +by invoking Prlog with file \fIF\fP as argument. +.lp +\fBprompt\fP(\fIOld\fP,\fINew\fP) +.ip +The +sequence of characters (prompt) which indicates that the +system is waiting for user input is represented as an atom, and +matched to \fIOld\fP; the atom bound to \fINew\fP specifies the new +prompt. In particular, the goal +.(l +prompt(X,X) +.)l +matches the current prompt to X, without changing it. +Note that this only affects the prompt issued for reads in the user's +program; it will not change the propmts used by the system at top level +etc. +.lp +\fBsystem\fP(\fIString\fP) +.ip +Calls the operating system with string \fIString\fP as argument. For +example +.(l +system("ls") +.)l +will produce a directory listing on \s-2UNIX\s0. +.lp +\fBsh\fP +.ip +Suspends C-Prolog and enters a recursive command interpreter. +On \s-2UNIX\s0, the shell used will be that specified in the environment +variable SHELL. +.lp +\fBstatistics\fP +.ip +Shows the current allocations and amounts used for each of the +six working areas of C-Prolog, and also the runtime since C-Prolog +started. For example: +.(l +| ?- statistics. +atom space: 64K (15596 bytes used) +aux. stack: 8K (0 bytes used) +trail: 64K (48 bytes used) +heap: 256K (30664 bytes used) +global stack: 256K (0 bytes used) +local stack: 256K (300 bytes used) +Runtime: 1.42 sec. +| ?- +.)l +.sh 2 "Preprocessing" +.lp +\fBexpand\(ulterm\fP(\fIT1\fP,\fIT2\fP) +.ip +Each top level term \fIT1\fP read when consulting a file is rewritten +into \fIT2\fP before being asserted or executed. The default transformations +provided by this predicate are the ones for grammar rules and for inline +expansion of arithmetic expressions. +The user may define further transformations as clauses for the +predicate \fBterm\(ulexpansion\fP/2, which has similar arguments. +User defined transformations are applied \fIbefore\fP system-defined ones. diff --git a/source_code/c-prolog-1982/man/cprolog.out b/source_code/c-prolog-1982/man/cprolog.out new file mode 100755 index 0000000..68adabd --- /dev/null +++ b/source_code/c-prolog-1982/man/cprolog.out @@ -0,0 +1,3959 @@ + + + + +. + + + + + C-Prolog User's Manual + + + Version 1.5 + February 22, 1984 + + Edited by Fernando Pereira[1] + SRI International, Menlo Park, California + + from material by + + David Warren + SRI International, Menlo Park, California + + David Bowen, Lawrence Byrd + Dept. of Artificial Intelligence, University of Edinburgh + + Luis Pereira + Dept. de Informatica, Universidade Nova de Lisboa + + + _A_b_s_t_r_a_c_t + + + + This is a revised edition of the user's manual for + C-Prolog, a Prolog interpreter written in C for 32 + bit machines. C-Prolog is based on an earlier Pro- + log interpreter written in IMP for the EMAS operat- + ing system by Luis Damas, who borrowed many aspects + of the design from the DECsystem-10/20 Prolog system + developed by David Warren, Fernando Pereira, + Lawrence Byrd and Luis Pereira. This manual is + based on the EMAS Prolog manual, which in turn was + based on the DECsystem-10/20 Prolog manual. + + + + + + + + + + + + + ____________________ + [1]Formerly at EdCAAD, Dept. of Architecture, University + of Edinburgh + + + + + + + + + + + + +. + C-Prolog User's Manual 1 + + + _1. _U_s_i_n_g _C-_P_r_o_l_o_g + + _1._1. _P_r_e_f_a_c_e + + This manual describes C-Prolog, a Prolog interpreter + written in C. C-Prolog was developed at EdCAAD, Dept. of + Architecture, University of Edinburgh, and is based on a + previous interpreter, written in IMP for the EMAS operating + system by Luis Damas of the Dept. of Computer Science, + University of Edinburgh. C-Prolog was designed for machines + with a large, uniform, address space, and assumes a pointer + cell 32 bits wide. At the time of writing, it has been + tested on VAX[2] machines under the UNIX[3] and VAX/VMS + operating systems, on the Sun workstation under 4.1/2 UNIX, + and has been ported with minor changes to other MC68000- + based workstations and to the Three Rivers PERQ. + + Prolog is a simple but powerful programming language + originally developed at the University of Marseilles, as a + practical tool for programming in logic. From a user's + point of view the major attraction of the language is ease + of programming. Clear, readable, concise programs can be + written quickly with few errors. Prolog is especially suit- + able for high-level symbolic programming tasks and has been + applied in many areas of Artificial Intelligence research. + + The system consists of a Prolog interpreter and a wide + range of builtin (system defined) procedures. Its design + was based on the (Edinburgh) DECsystem-10 Prolog system and + the system is closely compatible with DECsystem-10 Prolog + and thus is also reasonably close to PDP-11 UNIX and RT-11 + Prolog. + + This manual is not intended as an introduction to the + Prolog language and how to use it. For this purpose you + should study: + + _P_r_o_g_r_a_m_m_i_n_g _i_n _P_r_o_l_o_g + W. Clocksin & C. Mellish + Springer Verlag 1981 + + + This manual assumes that you are familiar with the + principles of the Prolog language, its purpose being to + explain how to use C-Prolog, and to describe all the evalu- + able predicates provided by C-Prolog. + + ____________________ + [2]VAX, VMS, PDP and DECsystem-10 are trademarks of Digi- + tal Equipment Corporation. + [3]UNIX is a Trademark of Bell Laboratories. + + + + + + + + + + + + +. + C-Prolog User's Manual 2 + + + _1._2. _U_s_i_n_g _C-_P_r_o_l_o_g -- _O_v_e_r_v_i_e_w + + C-Prolog offers the user an interactive programming + environment with tools for incrementally building programs, + debugging programs by following their executions, and modi- + fying parts of programs without having to start again from + scratch. + + The text of a Prolog program is normally created in a + number of files using a text editor. C-Prolog can then be + instructed to read-in programs from these files; this is + called _l_c_o_n_s_u_l_t_i_n_g the file. To change parts of a program + being run, it is possible to _r_e_c_o_n_s_u_l_t files containing the + changed parts. Reconsulting means that definitions for pro- + cedures in the file will replace any old definitions for + these procedures. + + It is recommended that you make use of a number of dif- + ferent files when writing programs. Since you will be edit- + ing and consulting/reconsulting individual files it is use- + ful to use files to group together related procedures; keep- + ing collections of procedures that do different things in + different files. Thus a Prolog program will consist of a + number of files, each file containing a number of related + procedures. + + When your programs start to grow to a fair size, it is + also a good idea to have one file which just contains com- + mands to the interpreter to consult all the other files + which form a program. You will then be able to consult your + entire program by just consulting this single file. + + _1._3. _A_c_c_e_s_s _t_o _C-_P_r_o_l_o_g + + In this manual, we assume that there is a command on + your computer + + prolog + + that invokes C-Prolog. + + We assume that there are three keys or key combinations + that achieve the effects of terminating an input line, mark- + ing end of input, and interrupting execution of a program. + Because these depend on operating system and individual + tastes, they are denoted in this manual by END-OF-LINE, + END-OF-INPUT and INTERRUPT respectively (they are carriage + return, control-Z and control-C on the computer this is + being written on). + + Since Prolog makes syntactic use of the difference + between upper and lower case it is important that you have + your terminal set up so that it accepts lower case in the + + + + + + + + + + +. + C-Prolog User's Manual 3 + + + normal way. This means, for a start, that you must be using + an upper and lower case terminal - and not, for example, an + upper case only teletype. It is possible to use Prolog + using upper case only (see Section 2.4) but it is unneces- + sarily painful. We shall assume both upper and lower case + throughout this manual. + + If you type the `prolog' command, Prolog will output a + banner and prompt you for directives as follows: + + C-Prolog version 1.5 + | ?- + + There will be a pause between the first line and the prompt + while the system loads itself. It is possible to type ahead + during this period if you get impatient. + + If you give an argument to the `prolog' command, C- + Prolog will interpret it as the name of a file containing a + saved state created earlier, and will restore that saved + state. Saved states will be explained fully later. + + prolog prog (Restore "prog") + + + C-Prolog uses six major internal data areas: the _h_e_a_p, + the _g_l_o_b_a_l _s_t_a_c_k, the _l_o_c_a_l _s_t_a_c_k, the _t_r_a_i_l, the _a_t_o_m _a_r_e_a + and the _a_u_x_i_l_i_a_r_y _s_t_a_c_k. Although the system is initially + configured with reasonable allocations for each of those + areas, a particular program might exceed one of the alloca- + tions, causing an error message. Ideally, the system should + adjust the available storage among areas automatically, but + this facility is not implemented yet. Instead, the user may + specify when starting Prolog the allocations (in K bytes) + for some or all of the areas. This is done by giving command + line switches between the program name and the optional file + argument. For example, + + prolog -h 1000 -g 1000 -l 500 bigprogram + + specifies heap and global stack allocations of 1000 K and a + local stack allocation of 500 K. The full set of switches + is: + + + -h _N heap allocation is _N K bytes + -g _N global stack allocation is _N K bytes + -l _N local stack allocation is _N K bytes + -t _N trail allocation is _N K bytes + -a _N atom area allocation is _N K bytes + -x _N auxiliary stack allocation is _N K bytes + + + + + + + + + + + + +. + C-Prolog User's Manual 4 + + + _1._4. _R_e_a_d_i_n_g-_i_n _P_r_o_g_r_a_m_s + + A program is made up of a sequence of clauses, + possibly interspersed with directives to the inter- + preter. The clauses of a procedure do not have to be + immediately consecutive, but remember that their relative + order may be important. + + To input a program from a file _f_i_l_e, give the direc- + tive: + + | ?- [_f_i_l_e]. + + which will instruct the interpreter to consult the program. + The file specification _f_i_l_e must be a Prolog atom. It may + be any file name, note that if this file name contains char- + acters which are not normally allowed in an atom then it is + necessary to surround the whole file specification with sin- + gle quotes (since quoted atoms can include any character), + for example + + | ?- ['people/greeks']. + + The specified file is then read in. Clauses in the file are + stored in the database ready to be executed, while any + directives are obeyed as they are encountered. When the end + of the file is found, the interpreter displays on the ter- + minal the time spent in reading-in and the number of + bytes occupied by the program. + + In general, this directive can be any list of + filenames, such as: + + | ?- [myprogram, extras, testbits]. + + In this case all three files would be consulted. If a + filename is preceded by a minus sign, as in: + + | ?- [-testbits, -moreideas]. + + then that file is reconsulted. The difference between con- + sulting and reconsulting is important, and works as follows: + if a file is consulted then all the clauses in the file are + simply added to C-Prolog's database. If you consult the same + file twice then you will get two copies of all the clauses. + However, if a file is reconsulted then the clauses for all + the procedures in the file will replace any existing clauses + for those procedures, that is any such previously existing + clauses in the database get thrown away. Reconsulting is + useful for telling Prolog about corrections in your program. + + Clauses may also be typed in directly at the terminal. + To enter clauses at the terminal, you must give the + + + + + + + + + + +. + C-Prolog User's Manual 5 + + + directive: + + | ?- [user]. + + The interpreter is now in a state where it expects input of + clauses or directives. To get back to the top level of + the interpreter, type the END-OF-INPUT character. + + Typing clauses directly into C-Prolog is only recom- + mended if the clauses will not be needed permanently, + and are few in number. For significant bits of program you + should use an editor to produce a file containing the text + of the program. + + _1._5. _D_i_r_e_c_t_i_v_e_s: _Q_u_e_s_t_i_o_n_s _a_n_d _C_o_m_m_a_n_d_s + + When Prolog is at top level (signified by an initial + prompt of "| ?- ", with continuation lines prompted with + "| ", that is indented out from the left margin) it reads + in terms and treats them as directives to the interpreter to + try and satisfy some goals. These directives are called + questions. Remember that Prolog terms must terminate with a + period ("."), and that therefore Prolog will not execute + anything for you until you have typed the period (and then + END-OF-LINE) at the end of the directive. + + Suppose list membership has been defined by: + + member(X,[X|_]). + member(X,[_|L]) :- member(X,L). + + (Note the use of anonymous variables written "_"). + + If the goal(s) specified in a question can be satis- + fied, and if there are no variables as in this example: + + | ?- member(b,[a,b,c]). + + then the system answers + + yes + + and execution of the question terminates. + + If variables are included in the question, then the + final value of each variable is displayed (except for + anonymous variables). Thus the question + + | ?- member(X,[a,b,c]). + + would be answered by + + X = a + + + + + + + + + + +. + C-Prolog User's Manual 6 + + + At this point the interpreter is waiting for you to indicate + whether that solution is sufficient, or whether you want it + to backtrack to see if there are any more solutions. Simply + typing END-OF-LINE terminates the question, while typing ";" + followed by END-OF-LINE causes the system to backtrack look- + ing for alternative solutions. If no further solutions can + be found it outputs + + no + + The outcome of some questions is shown below, where a + number preceded by "_" is a system-generated name for a + variable. + + | ?- member(X,[tom,dick,harry]). + X = tom ; + X = dick ; + X = harry ; + no + | ?- member(X,[a,b,f(Y,c)]),member(X,[f(b,Z),d]). + Y = b, + X = f(b,c), + Z = c + % Just END-OF-LINE typed here + yes + | ?- member(X,[f(_),g]). + X = f(_1728) + yes + | ?- + + When C-Prolog reads terms from a file (or from the terminal + following a call to [user]), it treats them all as program + clauses. In order to get the interpreter to execute direc- + tives from a file they must be preceded by `?-', for ques- + tions, or `:-', for commands. + + Commands are like questions except that they do not + cause answers to be printed out. They always start with the + symbol ":-". At top level this is simply written after the + prompted "?-" which is then effectively overridden. Any + required output must be programmed explicitly; for example, + the command + + :- member(3,[1,2,3]), write(ok). + + directs the system to check whether 3 belongs to the list + [1,2,3], and to output "ok" if so. Execution of a command + terminates when all the goals in the command have been + successfully executed. Other alternative solutions + are not sought (one may imagine an implicit "cut" at the + end of the command). If no solution can be found, the + system gives: + + + + + + + + + + + +. + C-Prolog User's Manual 7 + + + ? + + as a warning. + + The main use for commands (as opposed to questions) is + to allow files to contain directives which call various pro- + cedures, but for which you don't want to have the answers + printed out. In such cases you only want to call the pro- + cedures for effect. A useful example would be the use of a + directive in a file which consults a whole list of other + files, such as[4]: + + :-([ bits, bobs, mainpart, testcases, data, junk ]). + + + If this directive was contained in the file `program' + then typing the following at top level would be a quick way + of loading your entire program: + + | ?- [program]. + + + When you are simply interacting with the top level of + the Prolog interpreter the distinction between questions and + commands is not very important. At the top level you should + normally only type questions. In a file, if you wish to exe- + cute some goals then you should use a command. That is, to + execute a directive in a file it must be preceded by ":-", + otherwise it will be treated as a clause. + + _1._6. _S_a_v_i_n_g _A _P_r_o_g_r_a_m + + Once a program has been read, the interpreter will have + available all the information necessary for its execution. + This information is called a program _s_t_a_t_e. + + The state of a program may be saved on a file for + future execution. To save a program into a file _f_i_l_e, per- + form the command: + + ?- save(_f_i_l_e). + + Save can be called at top level, from within a break level + (q.v.), or from anywhere within a program. + + ____________________ + [4]The extra parentheses, with the `:-' immediately next + to them, are currently essential due to a problem with pre- + fix operators (like `:-') and lists. They are not required + for commands that do not contain lists. This restriction + will be eventually removed. + + + + + + + + + + + + +. + C-Prolog User's Manual 8 + + + _1._7. _R_e_s_t_o_r_i_n_g _A _S_a_v_e_d _P_r_o_g_r_a_m + + Once a program has been saved into a file _f_i_l_e, C- + Prolog can be restored to this saved state by invoking it as + follows: + + prolog _f_i_l_e + + After execution of this command, the interpreter will be in + _e_x_a_c_t_l_y the same state as existed immediately prior to the + call to save, except for open files, which are automati- + cally closed by save. That is to say execution will start + at the goal immediately following the call to save, just as + if save had returned successfully. If you saved the state + at top level then you will be back at top level, but if you + explicitly called save from within your program then the + execution of your program will continue. + + Saved states can only be restored when C-Prolog is ini- + tially run from command level. Version 1.5 provides no way + of restoring a saved state from inside C-Prolog. + + Note that when a new version of C-Prolog is installed, + saved states created with the old version may become unus- + able. You are thus advised to rely on source files for your + programs and not on some gigantic saved state. + + _1._8. _P_r_o_g_r_a_m _E_x_e_c_u_t_i_o_n _A_n_d _I_n_t_e_r_r_u_p_t_i_o_n + + Execution of a program is started by giving the + interpreter a directive which contains a call to one of the + program's procedures. + + Only when execution of one directive is complete + does the interpreter become ready for another direc- + tive. However, one may interrupt the normal execution of a + directive by hitting the INTERRUPT key on your terminal. In + response to the prompt + + Action (h for help): + + you can type either "a", "t", "d" or "c" followed by END- + OF-LINE. The "a" response will force Prolog to abort back + to top level, the "t" option will switch on tracing, the "d" + response will switch on debugging and continue the execu- + tion, and the "c" response will just continue the execution. + + _1._9. _N_e_s_t_e_d _E_x_e_c_u_t_i_o_n_s -- _B_r_e_a_k _a_n_d _A_b_o_r_t + + C-Prolog provides a way to suspend the execution of + your program and to enter a new incarnation of the top level + where you can issue directives to solve goals etc. When the + evaluable predicate break is called, the message + + + + + + + + + + +. + C-Prolog User's Manual 9 + + + [ Break (level 1) ] + + will be displayed. This signals the start of a _b_r_e_a_k and + except for the effect of aborts (see below), it is as if + the interpreter was at top level. If break is called within + a break, then another recursive break is started (and the + message will say (level 2) etc). Breaks can be arbitrarily + nested. + + Typing the END-OF-INPUT character will close the + break and resume the execution which was suspended, + starting at the procedure call where the suspension took + place. + + To abort the current execution, forcing an immedi- + ate failure of the directive being executed and a return to + the top level of the interpreter, call the evaluable predi- + cate abort, either from the program or by executing the + directive: + + | ?- abort. + + within a break. In this case no END-OF-INPUT character is + needed to close the break, because _a_l_l break levels are dis- + carded and the system returns right back to top level. The + "a" response to INTERRUPT (described above) can also be used + to force an abort. + + _1._1_0. _E_x_i_t_i_n_g _F_r_o_m _T_h_e _I_n_t_e_r_p_r_e_t_e_r + + To exit from C-Prolog interpreter you should give the + directive: + + | ?- halt. + + This can be issued either at top level, or within a break, + or indeed from within your program. + + If your program is still executing then you should + interrupt it and abort to return to top level so that you + can call halt. + + Typing the END-OF-INPUT charater at top level also + causes C-Prolog to terminate. + + _2. _P_r_o_l_o_g _S_y_n_t_a_x + + _2._1. _T_e_r_m_s + + The data objects of the language are called _t_e_r_ms. A + term is either a _c_o_n_s_t_a_n_t, a _v_a_r_i_a_b_l_e or a _c_o_m_p_o_u_n_d _t_e_r_m. + + + + + + + + + + + + +. + C-Prolog User's Manual 10 + + + The constants include _n_u_m_b_e_rs such as + + 0 -999 -5.23 0.23E-5 + + + Constants also include _a_t_o_ms such as + + a void = := 'Algol-68' [] + + The symbol for an atom can be any sequence of characters, + written in single quotes if there is possibility of confu- + sion with other symbols (such as variables or numbers). As + in other programming languages, constants are definite + elementary objects. + + Variables are distinguished by an initial capital + letter or by the initial character "_", for example + + X Value A A1 _3 _RESULT + + If a variable is only referred to once, it does not need to + be named and may be written as an _a_n_o_n_y_m_o_u_s variable, + indicated by the underline character "_". + + A variable should be thought of as standing for some + definite but unidentified object. A variable is not + simply a writeable storage location as in most pro- + gramming languages; rather it is a local name for some data + object, cf. the variable of pure LISP and constant + declarations in Pascal. + + The structured data objects of the language are the + compound terms. A compound term comprises a _f_u_n_c_t_o_r (called + the _p_r_i_n_c_i_p_a_l functor of the term) and a sequence of one or + more terms called _a_r_g_u_m_e_n_t_s. A functor is characterised by + its _n_a_m_e, which is an atom, and its _a_r_i_t_y or number of argu- + ments. For example the compound term whose functor is named + `point' of arity 3, with arguments X, Y and Z, is written + + point(X,Y,Z) + + An atom is considered to be a functor of arity 0. + + One may think of a functor as a record type and + the arguments of a compound term as the fields of a + record. Compound terms are usefully pictured as trees. + For example, the term + + s(np(john),vp(v(likes),np(mary))) + + would be pictured as the structure + + + + + + + + + + + + +. + C-Prolog User's Manual 11 + + + s + / \ + np vp + | / \ + john v np + | | + likes mary + + + Sometimes it is convenient to write certain functors as + _o_p_e_r_a_t_o_r_s -- 2-ary functors may be declared as _i_n_f_i_x opera- + tors and 1-ary functors as _p_r_e_f_i_x or _p_o_s_t_f_i_x operators. + Thus it is possible to write + + X+Y (P;Q) X ]). + :- op( 1200, fx, [ :-, ?- ]). + :- op( 1100, xfy, [ ; ]). + :- op( 1050, xfy, [ -> ]). + :- op( 1000, xfy, [ ',' ]). /* See note below */ + :- op( 900, fy, [ not, \+, spy, nospy ]). + :- op( 700, xfx, [ =, is, =.., ==, \==, @<, @>, @=<, @>=, + =:=, =\=, <, >, =<, >= ]). + :- op( 500, yfx, [ +, -, /\, \/ ]). + :- op( 500, fx, [ +, - ]). + :- op( 400, yfx, [ *, /, //, <<, >> ]). + :- op( 300, xfx, [ mod ]). + :- op( 200, xfy, [ ^ ]). + + + + + + + + + + + +. + C-Prolog User's Manual 15 + + + Operator declarations are most usefuly placed in direc- + tives at the top of your program files. In this case the + directive should be a command as shown above. Another common + method of organisation is to have one file just containing + commands to declare all the necessary operators. This file + is then always consulted first. + + Note that a comma written literally as a punctuation + character can be used as though it were an infix operator of + precedence 1000 and type `xfy': + + X,Y ','(X,Y) + + represent the same compound term. But note that a comma + written as a quoted atom is _n_o_t a standard operator. + + Note also that the arguments of a compound term + written in standard syntax must be expressions of pre- + cedence _b_e_l_o_w 1000. Thus it is necessary to bracket the + expression "P:-Q" in + + assert((P:-Q)) + + The following syntax restrictions serve to remove potential + ambiguity associated with prefix operators. + + - In a term written in standard syntax, the principal + functor and its following "(" must _n_o_t be + separated by any blankspace. Thus + + point (X,Y,Z) + + is invalid syntax. + + - If the argument of a prefix operator starts with a "(", + this "(" must be separated from the operator by at + least one space or other non-printable character. Thus + + :-(p;q),r. + + (where `:-' is the prefix operator) is invalid syntax, + and must be written as + + :- (p;q),r. + + + - If a prefix operator is written without an argu- + ment, as an ordinary atom, the atom is treated + as an expression of the same precedence as the prefix + operator, and must therefore be bracketed where + necessary. Thus the brackets are necessary in + + X = (?-) + + + + + + + + + + +. + C-Prolog User's Manual 16 + + + _2._3. _S_y_n_t_a_x _E_r_r_o_r_s + + Syntax errors are detected when reading. Each + clause, directive or in general any term read-in by the + evaluable predicate read that fails to comply with syntax + requirements is displayed on the terminal as soon as it + is read. A mark indicates the point in the string of sym- + bols where the parser has failed to continue its analysis. + For example, typing + + member(X,X L). + + gives: + + ***syntax error*** + member(X,X + ***here*** + L). + + + Syntax errors do not disrupt the (re)consulting of a + file in any way except that the clause or command with the + syntax error will be ignored[5] All the other clauses in the + file will have been read-in properly. If the syntax error + occurs at top level then you should just retype the ques- + tion. Given that Prolog has a very simple syntax it is usu- + ally quite straightforward to see what the problems is (look + for missing brackets in particular). The book _P_r_o_g_r_a_m_m_i_n_g + _i_n _P_r_o_l_o_g gives further examples. + + _2._4. _U_s_i_n_g _a _T_e_r_m_i_n_a_l _w_i_t_h_o_u_t _L_o_w_e_r-_C_a_s_e + + The syntax of Prolog assumes that a full ASCII charac- + ter set is available. With this _f_u_l_l _c_h_a_r_a_c_t_e_r _s_e_t or `LC' + convention, variables are (normally) distinguished by an + initial capital letter, while atoms and other functors + must start with a lower-case letter (unless enclosed in sin- + gle quotes). + + When lower-case is not available, the _n_o _l_o_w_e_r-_c_a_s_e or + `NOLC' convention has to be adopted. With this convention, + variables must be distinguished by an initial underline + character "_", and the names of atoms and other functors, + which now have to be written in upper-case, are implicitly + translated into lower-case (unless enclosed in single + quotes). For example, + + _VALUE2 + + ____________________ + [5]After all, it could not be read. + + + + + + + + + + + + +. + C-Prolog User's Manual 17 + + + is a variable, while + + VALUE2 + + is `NOLC' convention notation for the atom which is identi- + cal to: + + value2 + + written in the `LC' convention. + + The default convention is `LC'. To switch to the no + lower-case convention, call the evaluable predicate `NOLC': + + | ?- 'NOLC'. + + To switch back to the full character set convention, + call the evaluable predicate `LC': + + | ?- 'LC'. + + + Note that the names of these two procedures consist of + upper-case letters (so that they can be referred to + on all devices), and therefore the names must _a_l_w_a_y_s be + enclosed in single quotes. + + It is recommended that the `NOLC' convention only be + used in emergencies, since the standard syntax is far easier + to use and is also easier for other people to read. + + _3. _T_h_e _M_e_a_n_i_n_g _o_f _P_r_o_l_o_g _P_r_o_g_r_a_m_s + + _3._1. _P_r_o_g_r_a_m_s + + A fundamental unit of a logic program is the _l_i_t_e_r_a_l, + for instance + + gives(tom,apple,teacher) reverse([1,2,3],L) X/ + is used, for example concatenate/3. + + Certain predicates are predefined by procedures sup- + plied by the Prolog system. Such predicates are called + _e_v_a_l_u_a_b_l_e _p_r_e_d_i_c_a_t_e_s. + + As we have seen, the goals in the body of a clause are + linked by the operator `,' which can be interpreted as + conjunction ("and"). It is sometimes convenient to use + an additional operator `;', standing for disjunction ("or") + (The precedence of `;' is such that it dominates `,' but is + dominated by `:-'.). An example is the clause. + + + + + + + + + + + +. + C-Prolog User's Manual 20 + + + grandfather(X,Z) :- (mother(X,Y); father(X,Y)), father(Y,Z). + + which can be read as + + "For any X, Y and Z, X has Z as a grandfather if either the mother + of X is Y or the father of X is Y, and the father of Y is Z." + + Such uses of disjunction can always be eliminated by + defining an extra predicate - for instance the previous + example is equivalent to + + grandfather(X,Z) :- parent(X,Y), father(Y,Z). + parent(X,Y) :- mother(X,Y). + parent(X,Y) :- father(X,Y). + + and so disjunction will not be mentioned further in the + following, more formal, description of the semantics of + clauses. + + _3._2. _D_e_c_l_a_r_a_t_i_v_e _a_n_d _P_r_o_c_e_d_u_r_a_l _S_e_m_a_n_t_i_c_s + + The semantics of definite clauses should be fairly + clear from the informal interpretations already given. + However it is useful to have a precise definition. + The _d_e_c_l_a_r_a_t_i_v_e_s_e_m_a_n_t_i_c_s of definite clauses tells us which + goals can be considered true according to a given program, + and is defined recursively as follows. + + A goal is _t_r_u_e if it is the head of some clause + instance and each of the goals (if any) in the body + of that clause _i_n_s_t_a_n_c_e is true, where an instance + of a clause (or term) is obtained by substituting, + for each of zero or more of its variables, a new + term for all occurrences of the variable. + + For example, if a program contains the preceding pro- + cedure for concatenate, then the declarative semantics tells + us that + + concatenate([a],[b],[a,b]) + + is true, because this goal is the head of a certain + instance of the first clause for concatenate, namely, + + concatenate([a],[b],[a,b]) :- concatenate([],[b],[b]). + + and we know that the only goal in the body of this + clause instance is true, since it is an instance of the unit + clause which is the second clause for concatenate. + + The declarative semantics makes no reference to the + sequencing of goals within the body of a clause, nor to the + sequencing of clauses within a program. This + + + + + + + + + + +. + C-Prolog User's Manual 21 + + + sequencing information is, however, very relevant for + the _p_r_o_c_e_d_u_r_a_l _s_e_m_a_n_t_i_c_s which Prolog gives to definite + clauses. The procedural semantics defines exactly how + the Prolog system will execute a goal, and the sequencing + information is the means by which the Prolog programmer + directs the system to execute his program in a sensible + way. The effect of executing a goal is to enumerate, one by + one, its true instances. Here then is an informal defini- + tion of the procedural semantics. + + To execute a goal, the system searches forwards from + the beginning of the program for the first clause + whose head _m_a_t_c_h_e_s or _u_n_i_f_i_e_s with the goal. The + unification process finds the most general common + instance of the two terms, which is unique if it ex- + ists. If a match is found, the matching + clause instance is then activated by executing in + turn, from left to right, each of the goals (if + any) in its body. If at any time the system fails + to find a match for a goal, it _b_a_c_k_t_r_a_c_k_s, that is + it rejects the most recently activated clause, + undoing any substitutions made by the match + with the head of the clause. Next it reconsiders + the original goal which activated the rejected + clause, and tries to find a subsequent clause + which also matches the goal. + + For example, if we execute the goal in the query + + :- concatenate(X,Y,[a,b]). + + we find that it matches the head of the first clause for + concatenate, with X instantiated to [a|X1]. The new variable + X1 is constrained by the new goal produced, which is + the recursive procedure call + + concatenate(X1,Y,[b]) + + Again this goal matches the first clause, instantiat- + ing X1 to [b|X2], and yielding the new goal + + concatenate(X2,Y,[]) + + Now this goal will only match the second clause, instantiat- + ing both X2 and Y to []. Since there are no further goals to + be executed, we have a solution + + X = [a,b] + Y = [] + + representing a true instance of the original goal + + concatenate([a,b],[],[a,b]) + + + + + + + + + + +. + C-Prolog User's Manual 22 + + + If this solution is rejected, backtracking will generate the + further solutions + + X = [a] + Y = [b] + + X = [] + Y = [a,b] + + in that order, by rematching, against the second clause for + concatenate, goals already solved once using the first + clause. + + _3._3. _O_c_c_u_r_s _C_h_e_c_k + + Prolog's unification does not have an _o_c_c_u_r_s _c_h_e_c_k, + i.e. when unifying a variable against a term the system + does not check whether the variable occurs in the term. + When the variable occurs in the term, unification should + fail, but the absence of the check means that the unifica- + tion succeeds, producing a _c_i_r_c_u_l_a_r _t_e_r_m. Trying to print a + circular term, or trying to unify two circular terms, + will cause an infinite loop and possibly make Prolog run out + of stack space. + + The absence of the occur check is not a bug or + design oversight, but a conscious design decision. + The reason for this decision is that unification with the + occur check is at best linear on the sum of the sizes of + the terms being unified, whereas unification without + the occur check is linear on the size of the smallest of the + terms being unified. In any practical programming + language, basic operations are supposed to take constant + time. Unification against a variable should be thought of + as the basic operation of Prolog, but this can take constant + time only if the occur check is omitted. Thus the absence + of a occur check is essential to make Prolog into a practi- + cal programming language. The inconvenience caused by this + restriction seems in practice to be very slight. Usually, + the restriction is only felt in toy programs. + + _3._4. _T_h_e _C_u_t _S_y_m_b_o_l + + Besides the sequencing of goals and clauses, Prolog + provides one other very important facility for specifying + control information. This is the _c_u_t symbol, written "!". + It is inserted in the program just like a goal, but is not + to be regarded as part of the logic of the program and + should be ignored as far as the declarative semantics is + concerned. + + The effect of the cut symbol is as follows. When + first encountered as a goal, cut succeeds immediately. If + + + + + + + + + + +. + C-Prolog User's Manual 23 + + + backtracking should later return to the cut, the effect is + to fail the _p_a_r_e_n_t _g_o_a_l, the goal which matched the head of + the clause containing the cut, and caused the clause to be + activated. In other words, the cut operation commits the + system to all choices made since the parent goal was + invoked, and causes other alternatives to be discarded. The + goals thus rendered _d_e_t_e_r_m_i_n_a_t_e are the parent goal + itself, any goals occurring before the cut in the + clause containing the cut, and any subgoals which were exe- + cuted during the execution of those preceding goals. + + For example, the procedure + + member(X,[X|L]). + member(X,[Y|L]) :- member(X,L). + + can be used to test whether a given term is in a list, and + the goal + + :- member(b,[a,b,c]). + + will succeed. The procedure can also be used to extract + elements from a list, as in + + :- member(X,[d,e,f]). + + With backtracking this will successively return each ele- + ment of the list. Now suppose that the first clause had + been written instead: + + member(X,[X|L]) :- !. + + In this case, the above call would extract only the first + element of the list (`d'). On backtracking, the cut would + immediately fail the whole procedure. + + A procedure of the form + + _x :- _p, !, _q. + _x :- _r. + + is similar to + + _x := if _p then _q else _r; + + in an Algol-like language. + + A cut discards all the alternatives since the parent + goal, even when the cut appears within a disjunction. + This means that the normal method for eliminating a + disjunction by defining an extra predicate cannot be applied + to a disjunction containing a cut. + + + + + + + + + + + +. + C-Prolog User's Manual 24 + + + _4. _D_e_b_u_g_g_i_n_g _F_a_c_i_l_i_t_i_e_s + + This section describes the debugging facilities + that are available in C-Prolog. The purpose of these facil- + ities is to provide information concerning the control + flow of your program. The main features of the debug- + ging package are as follows: + + - The _P_r_o_c_e_d_u_r_e _b_o_x model of Prolog execution which pro- + vides a simple way of visualising control flow, + especially during backtracking. Control flow is viewed + at the procedure level, rather than at the level of + individual clauses. + + - The ability to exhaustively trace your program or to + selectively set _s_p_y _p_o_i_n_t_s. Spy points allow you to + nominate interesting procedures at which the program + is to pause so that you can interact. + + - The wide choice of control and information options + available during debugging. + + Much of the information in this chapter is similar but + not identical to that of Chapter 8 of _P_r_o_g_r_a_m_m_i_n_g _i_n _P_r_o_l_o_g. + + _4._1. _T_h_e _P_r_o_c_e_d_u_r_e _B_o_x _C_o_n_t_r_o_l _F_l_o_w _M_o_d_e_l + + During debugging the interpreter prints out a + sequence of goals in various states of instantiation in + order to show the state the program has reached in its + execution. However, in order to understand what is + occurring it is necessary to understand when and why the + interpreter prints out goals. As in other programming + languages, key points of interest are procedure entry and + return, but in Prolog there is the additional complexity of + backtracking. One of the major confusions that novice + Prolog programmers have to face is the question of what + actually happens when a goal fails and the system sud- + denly starts backtracking. The Procedure Box model of Pro- + log execution views program control flow in terms of move- + ment about the program text. This model provides a basis + for the debugging mechanism in the interpreter, and enables + the user to view the behaviour of his program in a con- + sistent way. + + Let us look at an example Prolog procedure: + + + + + + + + + + + + + + + + + +. + C-Prolog User's Manual 25 + + + *--------------------------------------* + Call | | Exit + ---------> + descendant(X,Y) :- offspring(X,Y). + ---------> + | | + | descendant(X,Z) :- | + <--------- + offspring(X,Y), descendant(Y,Z). + <--------- + Fail | | BackTo + *--------------------------------------* + + The first clause states that Y is a descendant of X if Y is + an offspring of X, and the second clause states that Z is a + descendant of X if Y is an offspring of X and if Z is a + descendant of Y. In the diagram a box has been drawn around + the whole procedure and labelled arrows indicate the control + flow in and out of this box. There are four such arrows + which we shall look at in turn. + + Call + + This arrow represents initial invocation of the pro- + cedure. When a descendant goal of the form + descendant(X,Y) is required to be satisfied, control + passes through the Call _p_o_r_t of the descendant box with + the intention of matching a component clause and then + satisfying any subgoals in the body of that + clause. Notice that this is independent of whether + such a match is possible, that is first the box is + called, and then the attempt to match takes place. + Textually we can imagine moving to the code for descen- + dant when meeting a call to descendant in some other + part of the code. + + Exit + + This arrow represents a successful return from the pro- + cedure. This occurs when the initial goal has + been unified with one of the component clauses and any + subgoals have been satisfied. Control now passes + out of the Exit port of the descendant box. Textually + we stop following the code for descendant and go back + to the place we came from. + + BackTo + + This arrow indicates that a subsequent goal has failed + and that the system has come back to this goal in an + attempt to match the goal against another clause. + Control passes through the BackTo port of the des- + cendant box in an attempt to rematch the original goal + with an alternative clause and then try to satisfy + any subgoals in the body of this new clause. Textu- + ally we follow the code backwards up the way we + came looking for new ways of succeeding, possibly + + + + + + + + + + +. + C-Prolog User's Manual 26 + + + dropping down on to another clause and following + that if necessary. Note that this is somewhat less + informative than the Redo port described in _P_r_o_g_r_a_m_m_i_n_g + _i_n _P_r_o_l_o_g, because it does not show the path in the + program from a failed goal back to the first goal where + alternative clauses exist, but only this goal. + + Fail + + This arrow represents a failure of the initial goal, + which might occur if no clause is matched, or if + subgoals are never satisfied, or if any solution pro- + duced is always rejected by later processing. Control + now passes out of the Fail port of the descendant box + and the system continues to backtrack. Textually we + move back to the code which called this procedure and + keep moving backwards up the code looking for choice + points. + + In terms of this model, the information we get about + the procedure box is only the control flow through these + four ports. This means that at this level we are not + concerned with which clause matches, and how any + subgoals are satisfied, but rather we only wish to know the + initial goal and the final outcome. However, it can be + seen that whenever we are trying to satisfy subgoals, what + we are actually doing is passing through the ports of + _t_h_e_i_r respective boxes. If we were to follow this, + then we would have complete information about the control + flow inside the procedure box. + + Note that the box we have drawn round the procedure should + really be seen as an _i_n_v_o_c_a_t_i_o_n _b_o_x. That is, there will be + a different box for each different invocation of the + procedure. Obviously, with something like a recursive + procedure, there will be many different Calls and Exits + in the control flow, but these will be for different invoca- + tions. Since this might get confusing each invocation box + is given a unique integer identifier. + + _4._2. _B_a_s_i_c _D_e_b_u_g_g_i_n_g _P_r_e_d_i_c_a_t_e_s + + The interpreter provides a range of evaluable + predicates for control of the debugging facilities. The + most basic predicates are as follows: + + debug + + Switches _d_e_b_u_g _m_o_d_e on. (It is initially off.) In + order for the full range of control flow infor- + mation to be available it is necessary to have this + on from the start. When it is off the system + does not remember invocations that are being + + + + + + + + + + +. + C-Prolog User's Manual 27 + + + executed. (This is because it is expensive and not + required for normal running of programs.) You can + switch debug mode on in the middle of execution, either + from within your program or after an interrupt (see + trace below), but information prior to this will + just be unavailable. + + nodebug + + switches debug mode off. If there are any spy points + set then they will be removed. + + debugging + + prints onto the terminal information about the + current debugging state. It shows whether debug mode + is on or off and gives various other information to be + described later. + + _4._3. _T_r_a_c_i_n_g + + The following evaluable predicate may be used to com- + mence an exhaustive trace of a program. + + trace + + Switches debug mode on, if it is not on already, and + ensures that the next time control enters a procedure + box, a message will be produced and you will be + asked to interact. + + When stopped at a goal being traced, you have a number + of options which will be detailed later. In particular, you + can just type END-OF-LINE (carriage-return) to creep + (or single-step) into your program. If you continue to + creep through your program you will see every entry and exit + to/from every invocation box. However, you will notice + that you are only given the opportunity to interact on + Call and BackTo ports, i.e. a single creep decision may + take you through several Exit ports or several Fail + ports. Normally this is desirable, as it would be tedi- + ous to go through all those ports step by step. However, if + it is not what you want, the following evaluable predicate + gives full control over the ports at which you are + prompted. + + leash(_M_o_d_e) + + Sets the _l_e_a_s_h_i_n_g _m_o_d_e to _M_o_d_e, where _M_o_d_e can be one + of the following + + + full prompt on Call, Exit, BackTo and Fail + tight prompt on Call, BackTo and Fail + half prompt on Call and BackTo + loose prompt on Call + off never prompt + + + + + + +. + C-Prolog User's Manual 28 + + + or any other combination of ports as described later. + The initial _l_e_a_s_h_i_n_g _m_o_d_e is `half'. + + _4._4. _S_p_y _P_o_i_n_t_s + + For programs of any size, it is clearly impractical to + creep through the entire program. Spy points make it possi- + ble to stop the program whenever it gets to a particular + procedure which is of interest. Once there, one can set + further spy points in order to catch the control flow a + bit further on, or one can start creeping. + + Setting a spy-point on a procedure indicates that you + wish to see all control flow through the various ports + of its invocation boxes. When control passes through any + port of a procedure with a spy-point set on it, a message is + output and the user is asked to interact. Note that the + current mode of leashing does not affect spy points: user + interaction is requested on _e_v_e_r_y port. + + Spy points are set and removed by the following evalu- + able predicates which are also standard operators: + + spy _X + + Sets spy points on all the procedures given by _X. _X + is either a single predicate specification, or a list + of such specifications. A predicate specification + is either of the form /, which means the + procedure with the name and an arity of + (for example member/2, foo/0, hello/27), + or it is of the form , which means all the pro- + cedures with the name that currently have + clauses in the data-base (e.g. member, foo, hello). + This latter form may refer to multiple procedures + which have the same name but different arities. + If you use the form but there are no clauses for + this predicate (of any arity) then nothing will be + done. If you really want to place a spy point + on a currently non-existent procedure, then you must + use the full form /; you will get a warn- + ing message in this case. If you set some spy + points when debug mode is off then it will be + automatically switched on. + + nospy _X + + This reverses the effect of spy _X: all the procedures + given by _X will have previously set spy points removed + from them. + + The options available when you arrive at a spy-point + are described below. + + + + + + + + + + +. + C-Prolog User's Manual 29 + + + _4._5. _F_o_r_m_a_t _o_f _D_e_b_u_g_g_i_n_g _M_e_s_s_a_g_e_s + + We will now look at the exact format of the message + output by the system at a port. All trace messages are out- + put to the terminal regardless of where the current out- + put is directed. (This allows you to trace programs while + they are performing file I/O.) The basic format is as fol- + lows: + + ** (23) 6 Call : foo(hello,there,_123) ? + + The "**" indicates that this is a spy-point. If this + port is not for a procedure with a spy-point set, then + there will be two spaces there instead. If this port is the + requested return from a Skip then the second character + becomes ">". This gives four possible combinations: + + + "**" This is a spy-point. + "*>" + + This is a spy-point, and you also did a Skip last time you were in + this box. + " >" + + This is not a spy-point, but you did a Skip last time you were in + this box. + " " This is not a spy-point. + + + + The number in parentheses is the unique invocation + identifier. This is continuously incrementing regardless of + whether or not you are actually seeing the invocations + (provided that debug mode is on). This number can be used + to cross correlate the trace messages for the various ports, + since it is unique for every invocation. It will + also give an indication of the number of procedure calls + made since the start of the execution. The invocation + counter starts again for every fresh execution of a com- + mand, and it is also reset when retries (see later) are per- + formed. + + The number following this is the current depth, that + is, the number of direct ancestors this goal has. + + The next word specifies the particular port (Call, + Exit, BackTo or Fail). + + The goal is then printed so that you can inspect + its current instantiation state. + + The final "?" is the prompt indicating that you should + type in one of the option codes allowed (see next sec- + tion). If this particular port is unleashed then you will + obviously not get this prompt since you have specified that + you do not wish to interact at this point. + + + + + + + + + + +. + C-Prolog User's Manual 30 + + + Notice that not all procedure calls are traced; + there are a few basic procedures which have been made + invisible since it is more convenient not to see them. + These include all primitive I/O evaluable predicates (for + example get, put, read, write), all basic control structures + (that is, `,', `;', `->') and all debugging control + evaluable predicates (for instance, debug, spy, leash, + trace). This means that you will never see messages con- + cerning these predicates during debugging. + + _4._6. _O_p_t_i_o_n_s _A_v_a_i_l_a_b_l_e _d_u_r_i_n_g _D_e_b_u_g_g_i_n_g + + This section describes the particular options + that are available when the system prompts you after print- + ing out a debugging message. All the options are one letter + mnemonics. They are read from the terminal with any + blanks being completely ignored up to the next end of line. + The _c_r_e_e_p option needs only the new line. + + The only option which you really have to remember is "h". + This provides help in the form of the following list of + available options: + + + END-OF-LINE creep a abort + c creep f fail + l leap b break + s skip h help + r retry r retry goal + q quasi-skip n nodebug + g goal stack [ read clauses from terminal + e exit Prolog + + + The first three options are the basic control decisions: + + c, END-OF-LINE: Creep + + Causes the interpreter to single-step to the very next + port and print a message. Then if the port is + leashed the user is prompted for further interaction. + Otherwise it continues creeping. If leashing is off, + creep is the same as leap (see below) except that a + complete trace is printed on the terminal. + + l: Leap + + causes the interpreter to resume running your pro- + gram, only stopping when a spy-point is reached (or + when the program terminates). Leaping can thus be + used to follow the execution at a higher level + than exhaustive tracing. All you need to do is to + set spy points on an evenly spread set of pertinent + + + + + + + + + + +. + C-Prolog User's Manual 31 + + + procedures, and then follow the control flow through + these by leaping from one to the other. + + s: Skip + + Skip is only valid for Call and BackTo ports. It + skips over the entire execution of the procedure. + That is, you will not see anything until control comes + back to this procedure (at either the Exit port or + the Fail port). Skip is particularly useful + while creeping since it guarantees that control will be + returned after the (possibly complex) execution + within the box. If you skip then no message at all + will appear until control returns. This includes calls + to procedures with spy points set; they will be + masked out during the skip. There are two ways of + overriding this : there is a Quasi-skip which does not + ignore spy points, and the "t" option after an inter- + rupt will disable the masking. Normally, however, + this masking is just what is required! + + q: Quasi-skip + + Is like Skip except that it does not mask out spy + points. If there is a spy-point within the execution + of the goal then control returns at this point and + any action can be performed there. The initial skip + still guarantees an eventual return of control, + though, when the internal execution is finished. + + f: Fail + + Transfers to the Fail port of the current box. This + puts your execution in a position where it is about to + backtrack out of the current invocation, that is, + you have manually failed the initial goal. + + r: Retry + + Transfers to the Call port of the current goal, or if + given a numeric argument _n, to the Call port of the + invocation numbered _n. IF the invocation being retried + has been deleted by the cut control primitive, the most + recent active invocation before it will be retried. If + _n is out of range, the current invocation is retried. + This option is extremely useful to go back to an ear- + lier state of computation if some point of interest was + overshot in a debugging session. Note however that side + effects, such as database modification, are not undone. + + g: Goal Stack + + + + + + + + + + + + +. + C-Prolog User's Manual 32 + + + Shows the goal that called the current one, and the one + that called it, and so on, that is, the stack of pend- + ing goals. Goals are printed one per line, from the + most recent to the least recent. Each goal is labeled + by its recursion level _l, its invocation number _i and + the ordinal position _p of the clause currently used to + solve the goal. + + a: Abort + + Causes an abort of the current execution. All the + execution states built so far are destroyed and you are + put right back at the top level of the interpreter. + (This is the same as the evaluable predicate abort.) + + [: Read clauses from terminal + + starts reading clauses typed by the user as if doing a + _c_o_n_s_u_l_t(_u_s_e_r). An END-OF-INPUT returns to the + debugger. + + e: Exit from Prolog + + causes an irreversible exit from the Prolog system. + (This is the same as the evaluable predicate halt.) + + h: Help + + Displays the table of options given above. + + b: Break + + Calls the evaluable predicate break, thus putting + you at interpreter top level with the execution so far + sitting underneath you. When you end the break + with the END-OF-INPUT character, you will be + reprompted at the port at which you broke. The new + execution is completely separate from the suspended + one; the invocation numbers will start again from 1 + during the break. Debug mode is not switched off as + you call the break, but if you do switch it off + then it will be re-switched on when you finish the + break and go back to the old execution. However, any + changes to the leashing or to spy points will remain in + effect. + + n: Nodebug + + Turns off debug mode. Notice that this is the correct + way to switch debugging off at a trace point. You + cannot use the "b" option because it always restores + debug mode upon return. + + + + + + + + + + + +. + C-Prolog User's Manual 33 + + + _4._7. _R_e_c_o_n_s_u_l_t_i_n_g _d_u_r_i_n_g _D_e_b_u_g_g_i_n_g + + It is possible, and sometimes useful, to reconsult a + file whilst in the middle of a program execution. How- + ever this can lead to unexpected behaviour under the follow- + ing circumstances: a procedure has been successfully exe- + cuted; it is subsequently re-defined by a reconsult, + and is later re-activated by backtracking. When the + backtracking occurs, all the new clauses for the pro- + cedure appear to the interpreter to be potential alternative + solutions, even though identical clauses may already have + been used. Thus large amounts of (unwanted) activity takes + place on backtracking. The problem does not arise if you do + the reconsult when you are at the Call port of the pro- + cedure to be re-defined. + + _5. _E_v_a_l_u_a_b_l_e _P_r_e_d_i_c_a_t_e_s + + This section describes all the evaluable predicates + available in C-Prolog. These predicates are provided in + advance by the system and they cannot be redefined by the + user. Any attempt to add clauses or delete clauses to an + evaluable predicate fails with an error message, and leaves + the evaluable predicate unchanged. The C-Prolog provides a + fairly wide range of evaluable predicates to perform the + following tasks: + + Input/Output + Reading-in programs + Opening and closing files + Reading and writing Prolog terms + Getting and putting characters + Arithmetic + Affecting the flow of the execution + Classifying and operating on Prolog terms (meta-logical facilities) + Sets + Term Comparison + Manipulating the Prolog program database + Manipulating the additional indexed database + Debugging facilities + Environmental facilities + + The evaluable predicates will be described according to this + classification. Appendix I contains a complete list of the + evaluable predicates. + + _5._1. _I_n_p_u_t _a_n_d _O_u_t_p_u_t + + A total of 15 I/O streams may be open at any one time + for input and output. This includes a stream that is always + available for input and output to the user's terminal. A + stream to a file _F is opened for input by the first see(_F) + executed. _F then becomes the current input stream. + + + + + + + + + + +. + C-Prolog User's Manual 34 + + + Similarly, a stream to file _H is opened for output by the + first tell(_H) executed. _H then becomes the current output + stream. Subsequent calls to see(_F) or to tell(_H) make _F or + _H the current input or output stream, respectively. Any + input or output is always to the current stream. + + When no input or output stream has been specified, the + standard ersatz file `user', denoting the user's termi- + nal, is utilised for both. When the terminal is waiting for + input on a new line, a prompt will be displayed as follows: + + + "| ?- " interpreter waiting for command + "| " interpreter wating for command continuation line + "| " consult(user) wating for continuation line + "|:" default for waiting for other user input + + + When the current input (or output) stream is closed, the + user's terminal becomes the current input (or output) + stream. + + The only file that can be simultaneously open for + input and output is the ersatz file `user'. + + A file is referred to by its name, _w_r_i_t_t_e_n _a_s _a_n _a_t_o_m, + e.g. + + myfile + 'F123' + data_lst + 'tom/greeks' + + + All I/O errors normally cause an abort, except for the + effect of the evaluable predicate nofileerrors decribed + below. + + End of file is signalled on the user's terminal by typ- + ing the END-OF-INPUT character. Any more input requests + for a file whose end has been reached causes an error + failure. + + _5._1._1. _R_e_a_d_i_n_g-_i_n _P_r_o_g_r_a_m_s + + consult(_F) + + Instructs the interpreter to read-in the program which + is in file _F. When a directive is read it is immedi- + ately executed. When a clause is read it is put after + any clauses already read by the interpreter for that + procedure. + + + + + + + + + + + +. + C-Prolog User's Manual 35 + + + reconsult(_F) + + Like consult except that any procedure defined + in the reconsulted file erases any clauses for that + procedure already present in the interpreter. recon- + sult makes it possible to amend a program without hav- + ing to restart from scratch and consult all the files + which make up the program. + + [_F_i_l_e|_F_i_l_e_s] + + This is a shorthand way of consulting or reconsulting a + list of files. A file name may optionally be preceded + by the operator `-' to indicate that the file + should be reconsulted rather than consulted. + Thus + + | ?- [file1,-file2,file3]. + + is merely a shorthand for + + | ?- consult(file1), reconsult(file2), consult(file3). + + + _5._1._2. _F_i_l_e _H_a_n_d_l_i_n_g + + see(_F) + + File _F becomes the current input stream. + + seeing(_F) + + _F is unified with the name of the current input file. + + seen + + Closes the current input stream. + + tell(_F) + + File _F becomes the current output stream. + + telling(_F) + + _F is unified with the name of the current output file. + + told + + Closes the current output stream. + + close(_F) + + + + + + + + + + + + +. + C-Prolog User's Manual 36 + + + File _F, currently open for input or output, is closed. + + fileerrors + + Undoes the effect of nofileerrors. + + nofileerrors + + After a call to this predicate, the I/O error + conditions "incorrect file name ...", "can't see file + ...", "can't tell file ..." and "end of file ..." cause + a call to fail instead of the default action, which + is to type an error message and then call abort. + + exists(_F) + + Succeeds if the file F exists. + + rename(_F,_N) + + If File _F is renamed to _N. If _N is `[]', the file is + deleted. If _F was a currently open stream, it is + closed first. + + _5._1._3. _I_n_p_u_t _a_n_d _O_u_t_p_u_t _o_f _T_e_r_m_s + + read(_X) + + The next term, delimited by a full stop (i.e. a "." + followed by a carriage-return or a space), is read + from the current input stream and unified with _X. The + syntax of the term must accord with current operator + declarations. If a call read(_X) causes the end of the + current input stream to be reached, _X is unified with + the atom `end_of_file'. Further calls to read for + the same stream will then cause an error failure. + + write(_X) + + The term _X is written to the current output stream + according to operator declarations in force. + + display(_X) + + The term _X is displayed on the terminal in standard + parenthesised prefix notation. + + writeq(_T_e_r_m) + + Similar to write(_T_e_r_m), but the names of atoms and + functors are quoted where necessary to make the result + acceptable as input to read. + + + + + + + + + + + +. + C-Prolog User's Manual 37 + + + print(_T_e_r_m) + + Print _T_e_r_m onto the current output. This predicate + provides a handle for user defined pretty printing. If + _T_e_r_m is a variable then it is written, using + write(_T_e_r_m). If _T_e_r_m is non-variable then a call is + made to the user defined procedure portray(_T_e_r_m). If + this succeeds then it is assumed that _T_e_r_m has been + output. Otherwise print is equivalent to write. + + _5._1._4. _C_h_a_r_a_c_t_e_r _I_n_p_u_t/_O_u_t_p_u_t + + nl + + A new line is started on the current output stream. + + get0(_N) + + _N is the ASCII code of the next character from the + current input stream. If the current input stream + reaches its end of file, the ASCII character code for + control-Z is returned and the stream closed. + + get(_N) + + _N is the ASCII code of the next non-blank printable + character from the current input stream. It has the + same behaviour as get0 on end of file. + + skip(_N) + + Skips to just past the next ASCII character code _N + from the current input stream. _N may be an integer + expression. Skipping past the end of file causes an + error. + + put(_N) + + ASCII character code _N is output to the current output + stream. _N may be an integer expression. + + tab(_N) + + _N spaces are output to the current output stream. _N + may be an integer expression. + + _5._2. _A_r_i_t_h_m_e_t_i_c + + Arithmetic is performed by evaluable predicates which + take as arguments _a_r_i_t_h_m_e_t_i_c _e_x_p_r_e_s_s_i_o_n_s and _e_v_a_l_u_a_t_e + them. An arithmetic expression is a term built from + _e_v_a_l_u_a_b_l_e _f_u_n_c_t_o_r_s, numbers and variables. At the time + of evaluation, each variable in an arithmetic expression + + + + + + + + + + +. + C-Prolog User's Manual 38 + + + must be bound to a number or to an arithmetic expression. + The result of evaluation will always be converted back to an + integer if possible. + + Each evaluable functor stands for an arithmetic opera- + tion. The adjective "integer" in the descriptions below + means that the operation only makes sense for integers, and + will fail for floating point numbers. + + Because arithmetic expressions are compound terms, they + use up storage that is only recovered on backtracking. The + evaluable predicate expanded_exprs can be used to avoid this + overhead by preexpanding arithmetic expressions into calls + to arithmetic evaluation predicates. However, this makes + program read-in slower and clauses bigger. + + In general, an arithmetic operation that combines + integers and floating point numbers will return a floating + point number. However, if the result is integral, it is + converted back to integer representation, and the same + applies to numbers read in by the reader. Thus, the goal + + | ?- p(2.0). + + will succeed with the clause + + p(2). + + and the result of the query + + | ?- X is 2*1.5. + + is + + X = 5 + + + Numbers may be integers + + -33 0 9999 + + or floating point numbers + + 1.333 -2.6E+7 0.555E-2 + + + Note that the decimal "." cannot be confused with the + end of clause because the latter must be followed by blank + space (space, tab or END-OF-LINE). However, if an operator + "." is declared as infix, it will only be possible to apply + it to two numbers if they are separated by blank space from + the operator. + + + + + + + + + + + +. + C-Prolog User's Manual 39 + + + The evaluable functors are as follows, where _X + and _Y are arithmetic expressions. + + _X+_Y + + addition + + _X-_Y + + subtraction + + _X*_Y + + multiplication + + _X/_Y + + division + + _X//_Y + + integer division + + _X mod _Y + + _X (integer) modulo _Y + + -_X + + unary minus + + exp(_X) + + exponential function + + log(_X) + + natural logarithm + + log10(_X) + + base 10 logarithm + + sqrt(_X) + + square root + + sin(_X) + + sine + + cos(_X) + + + + + + + + + + + +. + C-Prolog User's Manual 40 + + + cosine + + tan(_X) + + tangent + + asin(_X) + + arc sine + + acos(_X) + + arc cosine + + atan(_X) + + arc tangent + + floor(_X) + + the largest integer not greater than _X + + _X^_Y + + _X to the power _Y + + _X/\_Y + + integer bitwise conjunction + + _X/_Y + + integer bitwise disjunction + + _X<<_Y + + integer bitwise left shift of _X by _Y places + + _X>>_Y + + integer bitwise right shift of _X by _Y places + + \_X + + integer bitwise negation + + cputime + + CPU time since C-Prolog was started, in seconds. + + heapused + + + + + + + + + + + + +. + C-Prolog User's Manual 41 + + + Heap space in use, in bytes. + + [_X] + + (a list of just one element) evaluates to _X if _X is an + integer. Since a quoted string is just a list of + integers, this allows a quoted character to be used in + place of its ASCII code; e.g. "A" behaves within arith- + metic expressions as the integer 65. + + The arithmetic evaluable predicates are as follows, + where _X and _Y stand for arithmetic expressions, and _Z for + some term. Note that this means that is only evaluates one + of its arguments as an arithmetic expression (the right-hand + side one), whereas all the comparison predicates evaluate + both their arguments. + + _Z is _X + + Arithmetic expression _X is evaluated and the result, is + unified with _Z. Fails if _X is not an arithmetic expres- + sion. + + _X =:= _Y + + The values of _X and _Y are equal. + + _X == _Y + + The values of _X and _Y are not equal. + + _X < _Y + + The value of _X is less than the value of _Y. + + _X > _Y + + The value of _X is greater than the value of _Y. + + _X =< _Y + + The value of _X is less than or equal to the value of _Y. + + _X >= _Y + + The value of _X is greater than or equal to the value of + _Y. + + expanded_exprs(_O_l_d,_N_e_w) + + Unifies _O_l_d to the current value of the expression + expansion flag, and sets the value of the flag to _N_e_w. + The possible values of the flag are `off' (the default) + + + + + + + + + + +. + C-Prolog User's Manual 42 + + + for not expanding arithmetic expressions into procedure + calls, and `on' to do the expansion. + + _5._3. _C_o_n_v_e_n_i_e_n_c_e + + _P , _Q + + _P and _Q. + + _P ; _Q + + _P or _Q. + + true + + Always succeeds. + + _X = _Y + + Defined as if by the clause " Z=Z. ", that is _X and _Y + are unified. + + _5._4. _E_x_t_r_a _C_o_n_t_r_o_l + + ! + + Cut (discard) all choice points made since the parent + goal started execution. + + \+ _P + + If the goal _P has a solution, fail, otherwise + succeed. It is defined as if by + + \+(P) :- P, !, fail. + \+(_). + + + _P -> _Q ; _R + + Analogous to + + "if _P then _Q else _R" + + i.e. defined as if by + + P -> Q; R :- P, !, Q. + P-> Q; R :- R. + + + _P -> _Q + + + + + + + + + + + + +_. + C-Prolog User's Manual 43 + + + When occurring other than as one of the alterna- + tives of a disjunction, is equivalent to + + _P -> _Q; fail. + + + repeat + + Generates an infinite sequence of backtracking + choices. It behaves as if defined by the clauses: + + repeat. + repeat :- repeat. + + + fail + + Always fails. + + _5._5. _M_e_t_a-_L_o_g_i_c_a_l + + var(_X) + + Tests whether _X is currently instantiated to a vari- + able. + + nonvar(_X) + + Tests whether _X is currently instantiated to a non- + variable term. + + atom(_X) + + Checks that _X is currently instantiated to an atom + (i.e. a non-variable term of arity 0, other than a + number or database reference). + + number(_X) + + Checks that _X is currently instantiated to a number. + + integer(_X) + + Checks that _X is currently instantiated to an integer. + + atomic(_X) + + Checks that _X is currently instantiated to an atom, + number or database reference. + + primitive(_X) + + + + + + + + + + + + +. + C-Prolog User's Manual 44 + + + Checks that _X is currently instantiated to a number or + database reference. + + db_reference(_X) + + Checks that _X is currently instantiated to a database + reference. + + functor(_T,_F,_N) + + The principal functor of term _T has name _F and arity _N, + where _F is either an atom or, provided _N is 0, a + number. Initially, either _T must be instantiated to a + non-variable, or _F and _N must be instantiated to, + respectively, either an atom and a non-negative + integer or an integer and 0. If these conditions are + not satisfied, an error message is given. In the case + where _T is initially instantiated to a variable, the + result of the call is to instantiate _T to the most + general term having the principal functor indicated. + + arg(_I,_T,_X) + + Initially, _I must be instantiated to a positive integer + and _T to a compound term. The result of the call is + to unify _X with the _Ith argument of term _T. (The + arguments are numbered from 1 upwards.) If the ini- + tial conditions are not satisfied or _I is out of range, + the call merely fails. + + _X =.. _Y + + _Y is a list whose head is the atom corresponding to the + principal functor of _X and whose tail is the argument + list of that functor in _X. E.g. + + product(0,N,N-1) =.. [product,0,N,N-1] + + N-1 =.. [-,N,1] + + product =.. [product] + + If _X is instantiated to a variable, then _Y must be + instantiated either to a list of determinate length + whose head is an atom, or to a list of length 1 whose + head is a number. + + name(_X,_L) + + If _X is an atom or a number then _L is a list of the + ASCII codes of the characters comprising the name of _X. + E.g. + + + + + + + + + + + +. + C-Prolog User's Manual 45 + + + name(product,[112,114,111,100,117,99,116]) + + i.e. name(product,"product") + + name(1976,[49,57,55,54]) + + name(hello,[104,101,108,108,111]) + + name([],"[]") + + If _X is instantiated to a variable, _L must be instan- + tiated to a list of ASCII character codes. E.g. + + | ?- name(X,[104,101,108,108,111])). + + X = hello + + | ?- name(X,"hello"). + + X = hello + + + call(_X) + + If _X is instantiated to a term which would be accept- + able as body of a clause, the goal call(_X) is exe- + cuted exactly as if that term appeared textually in + place of the call(_X), except that any cut ("!") occur- + ring in _X will remove only those choice points in _X. + If _X is not instantiated as described above, an error + message is printed and call fails. + + _X + + (where _X is a variable) Exactly the same as call(_X). + + _5._6. _S_e_t_s + + When there are many solutions to a problem, and when + all those solutions are required to be collected + together, this can be achieved by repeatedly back- + tracking and gradually building up a list of the solutions. + The following evaluable predicates are provided to automate + this process. + + setof(_X,_P,_S) + + Read this as "_S is the set of all instances of _X such that + _P is provable, where that set is non-empty". The term + _P specifies a goal or goals as in call(_P). _S is a set of + terms represented as a list of those terms, without dupli- + cates, in the standard order for terms (see Section 5.3). + If there are no instances of _X such that _P is satisfied + + + + + + + + + + +. + C-Prolog User's Manual 46 + + + then the predicate fails. + + The variables appearing in the term _X should not appear + anywhere else in the clause except within the term _P. Obvi- + ously, the set to be enumerated should be finite, and should + be enumerable by Prolog in finite time. It is possi- + ble for the provable instances to contain variables, but in + this case the list _S will only provide an imperfect + representation of what is in reality an infinite set. + + If there are uninstantiated variables in _P which do not also + appear in _X, then a call to this evaluable predicate + may backtrack, generating alternative values for _S + corresponding to different instantiations of the free vari- + ables of _P. (It is to cater for such usage that the + set S is constrained to be non-empty.) For example, the + call: + + | ?- setof(X, X likes Y, S). + + might produce two alternative solutions via backtracking: + + Y = beer, S = [dick, harry, tom] + Y = cider, S = [bill, jan, tom ] + + The call: + + | ?- setof((Y,S), setof(X, X likes Y, S), SS). + + would then produce: + + SS = [ (beer,[dick,harry,tom]), (cider,[bill,jan,tom]) ] + + + Variables occurring in _P will not be treated as free if + they are explicitly bound within _P by an existential + quantifier. An existential quantification is written: + + _Y^_Q + + meaning "there exists a _Y such that _Q is true", where _Y is + some Prolog variable. For example: + + | ?- setof(X, Y^(X likes Y), S). + + would produce the single result: + + X = [bill, dick, harry, jan, tom] + + in contrast to the earlier example. + + bagof(_X,_P,_B_a_g) + + + + + + + + + + + +. + C-Prolog User's Manual 47 + + + This is exactly the same as setof except that + the list (or alternative lists) returned will not be + ordered, and may contain duplicates. The effect of + this relaxation is to save considerable time and space + in execution. + + _X^_P + + The interpreter recognises this as meaning "there + exists an _X such that _P is true", and treats it as + equivalent to call(_P). The use of this explicit + existential quantifier outside the setof and bagof con- + structs is superfluous. + + _5._7. _C_o_m_p_a_r_i_s_o_n _o_f _T_e_r_m_s + + These evaluable predicates are meta-logical. + They treat uninstantiated variables as objects with + values which may be compared, and they never instan- + tiate those variables. They should _n_o_t be used when what + you really want is arithmetic comparison (Section 5.2) or + unification. + + The predicates make reference to a standard total + ordering of terms, which is as follows: + + - variables, in a standard order (roughly, oldest first - + the order is _n_o_t related to the names of variables); + + - Database references, roughly in order of age; + + - numbers, from -"infinity" to +"infinity"; + + - atoms, in alphabetical (i.e. ASCII) order; + + - complex terms, ordered first by arity, then by the + name of principal functor, then by the arguments (in + left-to-right order). + + For example, here is a list of terms in the standard + order: + + [ X, -9, 1, fie, foe, fum, X = Y, fie(0,2), fie(1,1) ] + + These are the basic predicates for comparison of arbitrary + terms: + + _X == _Y + + Tests if the terms currently instantiating _X and _Y are + literally identical (in particular, variables in + equivalent positions in the two terms must be identi- + cal). For example, the question + + + + + + + + + + +. + C-Prolog User's Manual 48 + + + | ?- X == Y. + + fails (answers "no") because _X and _Y are distinct + uninstantiated variables. However, the question + + | ?- X = Y, X == Y. + + succeeds because the first goal unifies the two vari- + ables (see page 42). + + _X \== _Y + + Tests if the terms currently instantiating _X and + _Y are not literally identical. + + _T_1 @< _T_2 + + Term _T_1 is before term _T_2 in the standard order. + + _T_1 @> _T_2 + + Term _T_1 is after term _T_2 in the standard order. + + _T_1 @=< _T_2 + + Term _T_1 is not after term _T_2 in the standard order. + + _T_1 @>= _T_2 + + Term _T_1 is not before term _T_2 in the standard order. + + Some further predicates involving comparison of terms + are: + + compare(_O_p,_T_1,_T_2) + + The result of comparing terms _T_1 and _T_2 is _O_p, where + the possible values for _O_p are: + + `=' if _T_1 is identical to _T_2, + + `<' if _T_1 is before _T_2 in the standard order, + + `>' if _T_1 is after _T_2 in the standard order. + + Thus compare(=,_T_1,_T_2) is equivalent to _T_1 == _T_2. + + sort(_L_1,_L_2) + + The elements of the list _L_1 are sorted into the stan- + dard order, and any identical (i.e. `==') elements are + merged, yielding the list _L_2. (The time taken to do + this is at worst order (N log N) where N is the length + + + + + + + + + + +. + C-Prolog User's Manual 49 + + + of _L_1.) + + keysort(_L_1,_L_2) + + The list _L_1 must consist of items of the form _K_e_y- + _V_a_l_u_e. These items are sorted into order according to + the value of _K_e_y, yielding the list _L_2. No merging + takes place. (The time taken to do this is at worst + order (N log N) where N is the length of L1.) + + _5._8. _M_o_d_i_f_i_c_a_t_i_o_n _o_f _t_h_e _P_r_o_g_r_a_m + + The predicates defined in this section allow modifica- + tion of the program as it is actually running. Clauses can + be added to the program (_a_s_s_e_r_t_e_d) or removed from the pro- + gram (_r_e_t_r_a_c_t_e_d). Some of the predicates make use of an + implementation-defined identifier or _d_a_t_a_b_a_s_e _r_e_f_e_r_e_n_c_e + which uniquely identifies every clause in the interpreted + program. This identifier makes it possible to access + clauses directly, instead of requiring a search through the + program every time. However these facilities are intended + for more complex use of the database and are not required + (and undoubtedly should be avoided) by novice users. + + assert(_C) + + The current instance of _C is interpreted as a clause + and is added to the program (with new private variables + replacing any uninstantiated variables). The position + of the new clause within the procedure concerned is + implementation-defined. _C must be instantiated to a + non-variable. + + assert(_C_l_a_u_s_e,_R_e_f) + + Similar to assert(_C_l_a_u_s_e), but also unifies _R_e_f with + the database reference of the clause asserted. + + asserta(_C) + + Like assert(_C), except that the new clause becomes + the _f_i_r_s_t clause for the procedure concerned. + + asserta(_C_l_a_u_s_e,_R_e_f) + + Similar to asserta(_C_l_a_u_s_e), but also unifies _R_e_f with + the database reference of the clause asserted. + + assertz(_C) + + Like assert(_C), except that the new clause becomes + the _l_a_s_t clause for the procedure concerned. + + + + + + + + + + + +. + C-Prolog User's Manual 50 + + + assertz(_C_l_a_u_s_e,_R_e_f) + + Similar to assertz(_C_l_a_u_s_e), but also unifies _R_e_f with + the database reference of the clause asserted. + + clause(_P,_Q) + + _P must be bound to a non-variable term, and the + program is searched for a clause whose head matches _P. + The head and body of those clauses are unified with _P + and _Q respectively. If one of the clauses is a unit + clause, _Q will be unified with `true'. + + clause(_H_e_a_d,_B_o_d_y,_R_e_f) + + Similar to clause(_H_e_a_d,_B_o_d_y) but also unifies _R_e_f with + the database reference of the clause concerned. If _R_e_f + is not given at the time of the call, _H_e_a_d must be + instantiated to a non-variable term. Thus this predi- + cate can have two different modes of use, depending on + whether the database reference of the clause is known + or unknown. + + retract(_C) + + The first clause in the program that matches _C is + erased. _C must be initially instantiated to a non- + variable. The predicate may be used in a non- + determinate fashion, i.e. it will successively retract + clauses matching the argument through backtracking. + + abolish(_N,_A) Completely remove all clauses for the procedure + with name _N (which should be an atom), and arity _A (which + should be an integer). + + The space occupied by retracted or abolished clauses will be + recovered when instances of the clause are no longer in use. + + See also erase (Section 5.10) which allows a clause to be + directly erased via its database reference[6]. + + _5._9. _I_n_f_o_r_m_a_t_i_o_n _a_b_o_u_t _t_h_e _S_t_a_t_e _o_f _t_h_e _P_r_o_g_r_a_m + + listing + + Lists in the current output stream all the clauses in + the program. + + ____________________ + [6]This is a lower level facility, required only for com- + plicated database manipulations. + + + + + + + + + + + + +. + C-Prolog User's Manual 51 + + + listing(_A) + + The argument _A may be a predicate specification of the + form _N_a_m_e/_A_r_i_t_y in which case only the clauses for the + specified predicate are listed. If _A is just an atom, + then the interpreted procedures for all predicates of + that name are listed as for listing/0. Finally, it is + possible for _A to be a list of predicate specifications + of either type, e.g. + + | ?- listing([concatenate/3, reverse, go/0]). + + + current_atom(_A_t_o_m) + + Generates (through backtracking) all currently known + atoms, and returns each one as _A_t_o_m. + + current_functor(_N_a_m_e,_F_u_n_c_t_o_r) + + Generates (through backtracking) all currently known + functors, and for each one returns its name and most + general term as _N_a_m_e and _F_u_n_c_t_o_r respectively. If _N_a_m_e + is given, only functors with that name are generated. + + current_predicate(_N_a_m_e,_F_u_n_c_t_o_r) + + Similar to current_functor, but it only generates func- + tors corresponding to predicates for which there exists + a procedure. + + _5._1_0. _I_n_t_e_r_n_a_l _D_a_t_a_b_a_s_e + + This section describes predicates for manipulating an + internal indexed database that is kept separate from the + normal program database. They are intended for more sophis- + ticated database applications and are not really necessary + for novice users. For normal tasks you should be able to + program quite satisfactorily just using assert and retract. + + recorded(_K_e_y,_T_e_r_m,_R_e_f) + + The internal database is searched for terms recorded + under the key _K_e_y. These terms are successively unified + with _T_e_r_m in the order they occur in the database. At + the same time, _R_e_f is unified with the database refer- + ence of the recorded item. The key must be given, and + may be an atom or complex term. If it is a complex + term, only the principal functor is significant. + + recorda(_K_e_y,_T_e_r_m,_R_e_f) + + + + + + + + + + + + +. + C-Prolog User's Manual 52 + + + The term _T_e_r_m is recorded in the internal database as + the first item for the key _K_e_y, where _R_e_f is its data- + base reference. The key must be given, and only its + principal functor is significant. + + recordz(_K_e_y,_T_e_r_m,_R_e_f) + + The term _T_e_r_m is recorded in the internal database as + the last item for the key _K_e_y, where _R_e_f is its data- + base reference. The key must be given, and only its + principal functor is significant. + + erase(_R_e_f) + + The recorded item _o_r clause whose database reference is + _R_e_f is effectively erased from the internal database or + program. An erased item will no longer be accessible + through the predicates that search through the data- + base, but will still be accessible through its database + reference, if this is available in the execution state + after the call to erase. Only when all instances of the + item's database reference have been forgotten through + database erasures and/or backtracking will the item be + actually removed from the database. + + erased(_R) + + Suceeds if _R is a database reference to a database item + that has been erased, otherwise fails. + + instance(_R_e_f,_T_e_r_m) + + A (most general) instance of the recorded term whose + database reference is _R_e_f is unified with _T_e_r_m. _R_e_f + must be instantiated to a database reference. Note that + instance will even pick database items that have been + erased. + + _5._1_1. _D_e_b_u_g_g_i_n_g + + debug + + Debug mode is switched on. Information will now be + retained for debugging purposes and executions will + require more space. + + nodebug + + Debug mode is switched off. Information is no longer + retained for debugging, and spy points are removed. + + trace + + + + + + + + + + + +. + C-Prolog User's Manual 53 + + + Debug mode is switched on, and the interpreter starts + tracing from the next call to a user goal. If trace + was given in a command on its own, the goal(s) traced + will be those of the next command. Since this is a + once-off decision, a call to trace is necessary when- + ever tracing is required right from the start of an + execution, otherwise tracing will only happen at spy + points. + + spy _S_p_e_c + + Spy points will be placed on all the procedures given + by _S_p_e_c. All control flow through the ports of these + procedures will henceforth be traced. If debug mode + was previously off, then it will be switched on. _S_p_e_c + can either be a predicate specification of the form + _N_a_m_e/_A_r_i_t_y or _N_a_m_e, or a list of such specifications. + When the _N_a_m_e is given without the _A_r_i_t_y this refers to + all predicates of that name which currently have defin- + itions. If there are none, then nothing will be done. + Spy points can be placed on particular undefined pro- + cedures only by using the full form, _N_a_m_e/_A_r_i_t_y. + + nospy _S_p_e_c + + Spy points are removed from all the procedures given by + _S_p_e_c (as for spy). + + leash(_M_o_d_e) + + Sets the leashing mode to _M_o_d_e, where _M_o_d_e can be one + of the following + + + full prompt on Call, Exit, BackTo and Fail + tight prompt on Call, BackTo and Fail + half prompt on Call and BackTo + loose prompt on Call + off never prompt + _N + + _N is an integer. If the binary notation of + _N is 2'_c_e_b_f, the digits _c, _e, _b + and _f correspond to the Call, Exit BackTo and Fail respectively, + and are 1 (0) if the corresponding port is leashed (unleashed). + + + The initial _l_e_a_s_h_i_n_g _m_o_d_e is `half'. + + debugging + + Outputs information concerning the status of the debug- + ging package. This will show whether debug mode is on, + and if it is + + + + + + + + + + + +. + C-Prolog User's Manual 54 + + + what spy points have been set + + what mode of leashing is in force. + + + _5._1_2. _E_n_v_i_r_o_n_m_e_n_t_a_l + + 'NOLC' + + Establishes the no lower-case convention described in + Section 2.4. + + 'LC' + + Establishes the full character set convention + described in Section 2.4. It is the default setting. + + op(_p_r_i_o_r_i_t_y,_t_y_p_e,_n_a_m_e) + + Treat name _n_a_m_e as an operator of the stated _t_y_p_e and + _p_r_i_o_r_i_t_y (refer to Section 2.2). _n_a_m_e may also be a + list of names in which case all are to be treated as + operators of the stated _t_y_p_e and _p_r_i_o_r_i_t_y. + + break + + Causes the current execution to be suspended at + the next procedure call. Then the message "[ Break + (level 1) ]" is displayed. The interpreter is then + ready to accept input as though it was at top + level. If another call of break is encountered, it + moves up to level 2, and so on. To close the break and + resume the execution which was suspended, type the + END-OF-INPUT character. Execution will be resumed at + the procedure call where it had been suspended. Alter- + natively, the suspended execution can be aborted by + calling the evaluable predicate abort. Refer to Section + 1.9. + + abort + + Aborts the current execution taking you back to top + level. Refer to Section 1.9. + + save(_F) + + The system saves the current state of the system into + file _F. Refer to Section 1.6. + + save(_F,_W_h_e_n) + + Saves the current state of the system into file _F. + When is unified with 0 or 1 depending on whether the + + + + + + + + + + +. + C-Prolog User's Manual 55 + + + system is returning from the save goal in the original + Prolog session or after the saved state in _F has been + restored by invoking Prlog with file _F as argument. + + prompt(_O_l_d,_N_e_w) + + The sequence of characters (prompt) which indicates + that the system is waiting for user input is + represented as an atom, and matched to _O_l_d; the atom + bound to _N_e_w specifies the new prompt. In particular, + the goal + + prompt(X,X) + + matches the current prompt to X, without changing it. + Note that this only affects the prompt issued for reads + in the user's program; it will not change the propmts + used by the system at top level etc. + + system(_S_t_r_i_n_g) + + Calls the operating system with string _S_t_r_i_n_g as argu- + ment. For example + + system("ls") + + will produce a directory listing on UNIX. + + sh + + Suspends C-Prolog and enters a recursive command inter- + preter. On UNIX, the shell used will be that specified + in the environment variable SHELL. + + statistics + + Shows the current allocations and amounts used for each + of the six working areas of C-Prolog, and also the run- + time since C-Prolog started. For example: + + | ?- statistics. + atom space: 64K (15596 bytes used) + aux. stack: 8K (0 bytes used) + trail: 64K (48 bytes used) + heap: 256K (30664 bytes used) + global stack: 256K (0 bytes used) + local stack: 256K (300 bytes used) + Runtime: 1.42 sec. + | ?- + + + + + + + + + + + + + + +. + C-Prolog User's Manual 56 + + + _5._1_3. _P_r_e_p_r_o_c_e_s_s_i_n_g + + expand_term(_T_1,_T_2) + + Each top level term _T_1 read when consulting a file is + rewritten into _T_2 before being asserted or executed. + The default transformations provided by this predicate + are the ones for grammar rules and for inline expansion + of arithmetic expressions. The user may define further + transformations as clauses for the predicate + term_expansion/2, which has similar arguments. User + defined transformations are applied _b_e_f_o_r_e system- + defined ones. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +. + C-Prolog User's Manual 57 + + + _A_p_p_e_n_d_i_x _I -- _S_u_m_m_a_r_y _o_f _E_v_a_l_u_a_b_l_e _P_r_e_d_i_c_a_t_e_s + + abolish(_F,_N) Abolish the procedure named _F arity _N. + abort Abort execution of the current directive. + arg(_N,_T,_A) The _Nth argument of term _T is _A. + assert(_C) Assert clause _C. + assert(_C,_R) Assert clause _C, ref. _R. + asserta(_C) Assert _C as first clause. + asserta(_C,_R) Assert _C as first clause, ref. _R. + assertz(_C) Assert _C as last clause. + assertz(_C,_R) Assert _C as last clause, ref. _R. + atom(_T) Term _T is an atom. + atomic(_T) Term _T is an atom or integer. + bagof(_X,_P,_B) The bag of _Xs such that _P is provable is _B. + break Break at the next procedure call. + call(_P) Execute the procedure call _P. + clause(_P,_Q) There is a clause, head _P, body _Q. + clause(_P,_Q,_R) There is an clause, head _P, body _Q, ref _R. + close(_F) Close file _F. + compare(_C,_X,_Y) _C is the result of comparing terms _X and _Y. + consult(_F) Extend the program with clauses from file _F. + current_atom(_A) One of the currently defined atoms is _A. + current_functor(_A,_T) A current functor is named _A, m.g. term _T. + current_predicate(_A,_P) A current predicate is named _A, m.g. goal _P. + db_reference(_T) _T is a database reference. + debug Switch on debugging. + debugging Output debugging status information. + display(_T) Display term _T on the terminal. + erase(_R) Erase the clause or record, ref. _R. + erased(_R) The object with ref. _R has been erased. + expanded_exprs(_O,_N) Expression expansion if _N=on. + expand_term(_T,_X) Term _T is a shorthand which expands to term _X. + exists(_F) The file _F exists. + fail Backtrack immediately. + fileerrors Enable reporting of file errors. + functor(_T,_F,_N) The top functor of term _T has name _F, arity _N. + get(_C) The next non-blank character input is _C. + get0(_C) The next character input is _C. + halt Halt Prolog, exit to the monitor. + instance(_R,_T) A m.g. instance of the record ref. _R is _T. + integer(_T) Term _T is an integer. + _Y is _X _Y is the value of arithmetic expression _X. + keysort(_L,_S) The list _L sorted by key yields _S. + leash(_M) Set leashing mode to _M. + listing List the current program. + listing(_P) List the procedure(s) _P. + name(_A,_L) The name of atom or number _A is string _L. + nl Output a new line. + nodebug Switch off debugging. + nofileerrors Disable reporting of file errors. + nonvar(_T) Term _T is a non-variable. + nospy _P Remove spy-points from the procedure(s) _P. + + + + + + + + + + + +. + C-Prolog User's Manual 58 + + + number(_T) Term _T is a number. + op(_P,_T,_A) Make atom _A an operator of type _T precedence _P. + primitive(_T) _T is a number or a database reference + print(_T) Portray or else write the term _T. + prompt(_A,_B) Change the prompt from _A to _B. + put(_C) The next character output is _C. + read(_T) Read term _T. + reconsult(_F) Update the program with procedures from file _F. + recorda(_K,_T,_R) Make term _T the first record under key _K, ref. _R. + recorded(_K,_T,_R) Term _T is recorded under key _K, ref. _R. + recordz(_K,_T,_R) Make term _T the last record under key _K, ref. _R. + rename(_F,_G) Rename file _F to _G. + repeat Succeed repeatedly. + retract(_C) Erase the first clause of form _C. + save(_F) Save the current state of Prolog in file _F. + see(_F) Make file _F the current input stream. + seeing(_F) The current input stream is named _F. + seen Close the current input stream. + setof(_X,_P,_B) The set of _Xs such that _P is provable is _B. + sh Start a recursive shell + skip(_C) Skip input characters until after character _C. + sort(_L,_S) The list _L sorted into order yields _S. + spy _P Set spy-points on the procedure(s) _P. + statistics Display execution statistics. + system(_S) Execute command _S. + tab(_N) Output _N spaces. + tell(_F) Make file _F the current output stream. + telling(_F) The current output stream is named _F. + told Close the current output stream. + trace Switch on debugging and start tracing. + true Succeed. + var(_T) Term _T is a variable. + write(_T) Write the term _T. + writeq(_T) Write the term _T, quoting names if necessary. + 'LC' The following Prolog text uses lower case. + 'NOLC' The following Prolog text uses upper case only. + ! Cut any choices taken in the current procedure. + \+ _P Goal _P is not provable. + _X<_Y As numbers, _X is less than _Y. + _X=<_Y As numbers, _X is less than or equal to _Y. + _X>_Y As numbers, _X is greater than _Y. + _X>=_Y As numbers, _X is greater than or equal to _Y. + _X=_Y Terms _X and _Y are equal (i.e. unified). + _T=.._L The functor and args. of term _T comprise the list _L. + _X==_Y Terms _X and _Y are strictly identical. + _X\==_Y Terms _X and _Y are not strictly identical. + _X@<_Y Term _X precedes term _Y. + _X@=<_Y Term _X precedes or is identical _Y. + _X@>_Y Term _X follows term _Y. + _X@>=_Y Term _X follows or is identical to term _Y. + [_F|_R] Perform the (re)consult(s) specified by [_F|_R]. + + + + + + + + diff --git a/source_code/c-prolog-1982/man/makefile b/source_code/c-prolog-1982/man/makefile new file mode 100755 index 0000000..1eb0e07 --- /dev/null +++ b/source_code/c-prolog-1982/man/makefile @@ -0,0 +1,5 @@ +TROFF=psroff -Tpsc +DEST=>cprolog.doc + +cprolog.doc: app.me cprolog.me + tbl cprolog.me app.me | $(TROFF) -me diff --git a/source_code/c-prolog-1982/man/makefile.save b/source_code/c-prolog-1982/man/makefile.save new file mode 100755 index 0000000..664cf63 --- /dev/null +++ b/source_code/c-prolog-1982/man/makefile.save @@ -0,0 +1,5 @@ +TROFF=ptroff -Tlp +DEST=>cprolog.doc + +cprolog.doc: app.me cprolog.me + tbl cprolog.me app.me | $(TROFF) -me diff --git a/source_code/c-prolog-1982/parms.c b/source_code/c-prolog-1982/parms.c new file mode 100755 index 0000000..e3a0974 --- /dev/null +++ b/source_code/c-prolog-1982/parms.c @@ -0,0 +1,84 @@ +/********************************************************************** +* * +* C Prolog parms.c * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ + +#include "pl.h" + +/* Declaration and properties of work areas */ + +#define AtomSize (128*K) +#define AuxSize (8*K) +#define TrailSize (64*K) +#define HeapSize (256*K) +#define GlobalSize (256*K) +#define LocalSize (128*K) + + +int Size[] = { AtomSize, AuxSize, TrailSize, + HeapSize, GlobalSize, LocalSize }; + +PTR Origin[7]; +PTR Limit[6]; +PTR Tide[6]; + +/* + Switches: b = boot, q = quiet start-up, d = dump on error, T = trace, + a = atom area size, + x = aux " " , + t = trail " " , + h = heap " " , + g = global " " , + l = local " " + +*/ + +char Parameter[] = { 'a', 'x', 't', 'h', 'g', 'l' }; +int NParms = 6; + +char Switch[] = { 0, 0, 'b', 'q', 'd', 'T' }; +int State[] = { 0, 0, 0, 0, 0, 0 }; + +int Switches = 6; + +#ifdef vms +#define STARTUPFILE "STARTUP" +#endif + +char StandardStartup[] = STARTUPFILE; + +char * +UserStartup() +{ + static char buf[256]; +#ifdef unix + static char format[] = "%s/prolog.bin"; + char *env = getenv("HOME"); +#else +#ifdef vms + static char format[] = "%sPROLOG.BIN"; + char *env = getenv("HOME"); +#else + static char format[] = "%sPROLOG.BIN"; + char *env = NULL; +#endif +#endif + sprintf(buf,format,env); + return buf; +} + +char version[] = "C-Prolog version 1.5"; +int saveversion = 26; + + diff --git a/source_code/c-prolog-1982/parms.o b/source_code/c-prolog-1982/parms.o new file mode 100755 index 0000000..f2906b1 Binary files /dev/null and b/source_code/c-prolog-1982/parms.o differ diff --git a/source_code/c-prolog-1982/pl.h b/source_code/c-prolog-1982/pl.h new file mode 100755 index 0000000..6ea3378 --- /dev/null +++ b/source_code/c-prolog-1982/pl.h @@ -0,0 +1,581 @@ +/********************************************************************** +* * +* C Prolog pl.h * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ + +#include + +#define TRUE 1 +#define FALSE 0 + +#define K 1024 + +/* the representable integers are in the interval [MinInt,MaxInt] */ + +#define MaxInt 268435455 /* largest integer = 2^28-1 */ +#define MinInt -268435456 /* smallest integer = -2^28 */ + + +/* SIGNED must be defined as the type of integers with the same width + as a pointer (int on a VAX). This type is used to interpret pointers + as signed numbers in comparisons related to the internal representation + of terms (see picture below). Despite attempts to parameterise as + much as possible, the sistem still depends on pointers being 32 bits + wide and numbers being held in two's-complement. +*/ + +typedef int SIGNED; + +/* The original EMAS Prolog in IMP relies too much on pointers being + just addresses, independently of the type pointed to, for me to be + able to do anything about it. To help satisfy the compiler's view + of typing, addresses are objects of type PTR, which are then cast + into the appopriate types. +*/ + +typedef unsigned **PTR; + +#define CellP(p) ((PTR*)(p)) +#define AtomP(p) ((ATOM*)(p)) +#define FunctorP(p) ((FUNCTOR*)(p)) +#define FrameP(p) ((FRAME*)(p)) +#define ClauseP(p) ((CLAUSEREC*)(p)) +#define MolP(p) ((MOL*)(p)) +#define SkelP(p) ((SKEL*)(p)) +#define Signed(p) ((SIGNED)(p)) +#define Unsigned(p) ((unsigned)(p)) +#define CharP(p) ((char*)(p)) + +#define Addr(p) ((PTR)&(p)) /* PTRise an address */ + +/* Prolog registers as cell pointers */ + +/* Words(number) converts a number of bytes to a number of PTRs */ + +#define Words(v) (((v)+sizeof(PTR))/sizeof(PTR)) + +#define SC(x,o,y) (Signed(x) o Signed(y)) /* signed pointer comparison */ + +/* Origin of input variables */ + +#define VAR0 0x40000000 /* all variables */ +#define LOCAL0 0x41000000 /* local variables */ +#define VMASK 0xf0000000 /* variable bit mask */ +#define LVMASK 0xff000000 /* local variable bit mask */ + +#ifdef COMMENT + + The definitions that follow depend crucially on the relative + positions of stacks and other work areas. Values of type PTR + whose most significant bit is 1 (negative as integers) are not + pointers but values of some primitive type (integers or + database pointers, floats sometime in the future). Positive + PTRs are pointers into the stacks/work areas. Therefore, the + top of the topmost area must be below address 2^30-1. If + Unix could cope with widely scattered segments (promised for + 4.2 BSD), I might be able to implement these things more + nicely in terms of tagged pointers. As it is, type checking + is done by signed comparisons, and the stacks/work areas + occupy a contiguous region in memory. This region is allocated + by CreateStacks() (sysbits.c), and area sizes are defined in + parms.c. + + The layout is as follows: + + atom0: *----------------------* + | Atoms | + auxstk0: *----------------------* + | Auxiliary stack | + trbase: *----------------------* + | Trail | + skel0: *----------------------* + | Heap (input terms) | + glb0: *----------------------* + | Global stack | + lcl0: *----------------------* + | Local stack | + *----------------------* + +#endif + +#define NAreas 6 /* number of work areas/stacks */ + +#define IsRef(c) SC(c,>=,glb0) /* reference */ +#define IsAtomic(c) SC(c,<,skel0) /* atomic term */ +#define IsInp(c) SC(c,<,glb0) /* input term */ +#define IsComp(c) SC(c,>=,skel0) /* compound or constructed term */ +#define IsLocal(c) SC(c,>=,lcl0) /* local address */ +#define IsPrim(c) SC(c,<,0) /* number or db reference */ +#define IsDBRef(c) ((Unsigned(c)&NUM0) == DB_REF0) /* db reference */ +#define IsNumber(c) ((Unsigned(c)&NUM0) == NUM0) /* number */ +#define IsInt(c) ((Unsigned(c)&INT0) == INT0) /* integer */ +#define IsFloat(c) ((Unsigned(c)&INT0) == FLOAT_TAG) /* float */ +#define Undef(c) (Unsigned(c) == 0) /* undefined cell */ +#define IsntName(c) SC(c,<,atom0) /* isn't atom or functor */ +#define IsName(c) SC(c,>=,atom0) /* not primitive */ +#define IsVar(c) ((Unsigned(c)&VMASK) == VAR0) /* input variable */ +#define IsLocalVar(c) ((Unsigned(c)&LVMASK) == LOCAL0)/* input local */ +#define VarNo(x) (Signed(x)&0xffff) /* var. offset */ + +#define FrameVar(v,n) ((PTR)(CharP(v)+(n))) /* var. cell address */ + +/* skeleton representation of the nth local variable */ + +#define SkelLocal(n) ((PTR)((Addr(FrameP(LOCAL0)->v1ofcf)+(n)))) + +/* ditto global variable */ + +#define SkelGlobal(n) (((PTR)VAR0)+n) + +/* extract and construct integer */ + +#define XtrInt(c) ((Signed(c)&SIGN) ? Signed(c) : Signed(c)&~INT0) +#define ConsInt(i) ((PTR)(INT0|(i))) + +/* extract and construct database pointer */ + +#define XtrDBRef(c) (skel0+(Unsigned(c)&~(NUM0|RECORD))) +#define DBType(c) (Unsigned(c)&RECORD) +#define ConsDBRef(p,k) ((PTR)(((p)-skel0)|DB_REF0|(k))) + +/* extract and construct float */ + +extern float XtrFloat(); +extern PTR ConsFloat(); + +/* Grow pointer p by n agains limit l on area i. */ + +#define Grow(p,l,n,i) {if ((p += (n)) > l) NoSpace(i); } + +/* Grow atom space */ + +#define GrowAtom(n) Grow(atomfp,atmax,n,AtomId) + +/* Grow stacks. */ + +#define GrowLocal(n) (v += (n)) + +#define GrowGlobal(n) (v1 += (n)) + +#define InitGlobal(n,k) { register PTR p; \ + p = v1+(n); \ + k = v1; \ + while (p > v1) *--p = NULL; \ + GrowGlobal(n); } + +/* construct molecule */ + +#define ConsMol(s,e,m) { MolP(v1)->Sk=(s); \ + MolP(v1)->Env=(e); \ + m = v1; \ + GrowGlobal(MolSz); } + +/* trail an assignment */ + +#define TrailPtr(t) {if (tr > trmax) NoSpace(TrailId); else *tr++ = (t);} + +#define TrailVar(t) { PTR tt; \ + tt = (t); \ + if (tt < vv1 || (lcl0 <= tt && tt < vv)) \ + TrailPtr(tt); \ + } + +/* Headers for doubly linked definition chains */ + +typedef struct { + PTR First; + PTR Last; +} Header; + +/* atom entry */ + +#define infofae AInfo.Infofae +#define arityofae AInfo.ABytes.Arityofae +#define flgsofae AInfo.Abytes.Flgsofae +#define infxofae AInfo.ABytes.InfixOfAE +#define defsofae AClauses.First +#define dbofae ARecords.First + +typedef struct ATOM { + PTR atofae; /* self pointer */ + union { + unsigned Infofae; /* information */ + struct { + char Arityofae; /* arity ( = 0 ) */ + char Flgsofae; /* flags field */ + short InfixOfAE; /* infix priority */ + } ABytes; + } AInfo; + Header AClauses; /* chain of definitions */ + Header ARecords; /* chain of records */ + PTR fcofae; /* functor chain */ + PTR nxtofae; /* hash chain */ + short prfxofae, psfxofae; /* prefix and postfix priorities */ + char stofae[1]; /* string for atom */ +} ATOM; + +/* size of atom entry (excluding string) */ + +#define szofae sizeof(ATOM) + +/* Size of hashtable */ + +#define HASHSIZE 269 /* a prime */ + +/* functor entry */ + +#define infoffe FInfo.Infoffe +#define arityoffe FInfo.FBytes.Arityoffe +#define flgsoffe FInfo.FBytes.Flgsoffe +#define defsoffe FClauses.First +#define dboffe FRecords.First + +typedef struct FUNCTOR { + PTR atoffe; /* atom for this functor */ + union { + unsigned Infoffe; /* general information field */ + struct { + char Arityoffe; /* arity */ + char Flgsoffe; /* flags field */ + } FBytes; + } FInfo; + Header FClauses; /* clauses for this functor */ + Header FRecords; /* data base entries under functor */ + PTR nxtoffe; /* chain of functors with same name */ + PTR gtoffe; /* start of general skeleton for this */ + /* term. points to this entry. */ +} FUNCTOR; + +/* size of functor entry (+ arity) in PTRs */ + +#define szoffe (sizeof(FUNCTOR)/sizeof(PTR)) + +/* clause */ + +#define MAX_VAR 255 /* highest variable number */ + +typedef struct CLAUSEREC { + unsigned char ltofcl; /* no. of local and temp. variables */ + unsigned char lvofcl; /* no. of local vars */ + unsigned char gvofcl; /* no. of global vars */ + char infofcl; /* general inf. */ + int refcofcl; /* reference count */ + PTR hdofcl; /* clause head */ + PTR bdyofcl; /* body of clause */ + PTR altofcl; /* alternatives */ + PTR prevofcl; /* previous clause */ +} CLAUSEREC; + +/* size of entry in PTRs */ + +#define szofcl (sizeof(CLAUSEREC)/sizeof(PTR)) + +/* local frame */ + +typedef struct { + PTR Lcpofcf; /* preyious choice point */ + PTR Gofcf; /* goal */ + PTR Gfofcf; /* goal's local frame */ + PTR Gsofcf; /* global frame associated with this frame */ + PTR Trofcf; /* tr at entry */ + unsigned Infofcf; /* general information */ + PTR Cofcf; /* continuation on entry */ + PTR Altofcf; /* alternatives */ +} FRAMECTL; + +/* size in cells */ + +#define szofcf sizeof(FRAMECTL)/sizeof(PTR) +#define MAX_FRAME szofcf+MAX_VAR+1 + +typedef struct FRAME { + FRAMECTL FCTL; + PTR v1ofcf; /* variables */ + PTR v2ofcf; + PTR v3ofcf; + PTR v4ofcf; + PTR v5ofcf; +} FRAME; + +/* Fields of the frame information word */ + +#define HIDDEN_FRAME NUM_TAG /* system frame, not traceable */ +#define LEVEL_WIDTH 12 /* width of the level field */ +#define CALL_NUMBER 0x3ffff /* invocation number mask */ +#define LEVEL 0xfff /* recursion level mask */ + +/* build the information for the current frame, faking a + primitive object */ + +#define FrameInfo(i,l) (((i&CALL_NUMBER)<>LEVEL_WIDTH)&CALL_NUMBER) +#define Level(info) ((info)&LEVEL) +#define SysFrame(info) ((info)&HIDDEN_FRAME) + +/* Evaluable predicate arguments */ + +#define ARG1 (X->v1ofcf) +#define ARG2 (X->v2ofcf) +#define ARG3 (X->v3ofcf) +#define ARG4 (X->v4ofcf) +#define ARG5 (X->v5ofcf) + +/* Frame locations */ + +#define lcpofcf FCTL.Lcpofcf +#define gofcf FCTL.Gofcf +#define gfofcf FCTL.Gfofcf +#define gsofcf FCTL.Gsofcf +#define trofcf FCTL.Trofcf +#define infofcf FCTL.Infofcf +#define cofcf FCTL.Cofcf +#define altofcf FCTL.Altofcf + +/* Prolog registers as frame pointers */ + +#define X FrameP(x) +#define V FrameP(v) +#define VV FrameP(vv) + +/* skeleton layout - add argument fields as required by code + (could define an arg. array instead, the generality is hardly worth + the bother) +*/ + +typedef struct SKEL { + PTR Fn; + PTR Arg1; + PTR Arg2; + } SKEL; + +#define SkelSz(n) ((n)+1) /* size of n arg. skeleton */ + + +/* molecule layout - the Sk field MUST be the first! */ + +typedef struct MOL { + PTR Sk; + PTR Env; + } MOL; + +#define MolSz 2 /* NB: size in PTRs, not in bytes */ + +/* entry is read's variable dictionary */ + +typedef struct VarEntry { + struct VarEntry *NextVar; /* must be the first */ + PTR VarValue; + int VarLen; + char VarName[1]; + } VarEntry; + +typedef VarEntry *VarP; + +/* Primitive objects (ints, floats and database pointers at present) + are distinguished by tag bits. Any primitive object will have + bit 31 (sign bit) set. The tags are as follows: + + tag bits + 31 30 29 + =============+==+==+== + int 1 1 1 + float 1 1 0 + ptr to clause 1 0 0 + ptr to record 1 0 1 + +*/ +#define PRIM_TAG 0x80000000 /* tag for primitive types */ +#define NUM_TAG 0x40000000 /* tag for numbers */ +#define NUM0 0xc0000000 /* origin of primitive types */ +#define INT0 0xe0000000 /* origin of integers */ +#define SIGN 0x10000000 /* sign bit on a constructed number */ +#define FLOAT_TAG NUM0 /* float tag bits */ +#define DB_REF0 0x80000000 /* origin of database references */ +#define RECORD 0x20000000 /* reference to a record */ +#define CLAUSE 0 /* reference to a clause (clear) */ + +/* clause/record flags */ + +#define ERASED 1 /* erased but not yet removed */ +#define IN_USE 2 /* in use in a proof, cannot be + deleted yet */ + +#define Erased(c) ((ClauseP(c)->infofcl)&ERASED) +#define InUse(c) ((ClauseP(c)->infofcl)&IN_USE) +#define RC(c) (ClauseP(c)->refcofcl) +#define Idle(c) (RC(c) == 0 && !InUse(c)) + +/* Flags in a functor entry - apply to the corresponding predicate */ + +#define RESERVED 0xe0 /* cannot be modified */ +#define HIDDEN 0xc0 /* Protected or invisible */ +#define PROTECTED 0x80 /* cannot be listed, traced, or modified */ +#define INVISIBLE 0x40 /* invisible to tracing and recursion level */ +#define UNTRACEABLE 0x20 /* cannot be traced */ +#define SPY_ME 0x10 /* is a spypoint */ + +/* NB. The low order 4 bits of the flags field in a functor or + atom entry, if non-zero, represent the internal code of that + functor or atom as an arithmetic operator. This means that + the maximum number of different arithmetic operators for each + arity is 15 (see arith.c). This could be changed by redefining + the layout of functor and atom entries, taking care with + the way unions are used in them (left-overs from the original + code in IMP). +*/ + +/* Internal event conditions */ + +#define COLD_START 0 /* first thing in the morning */ +#define ABORT 1 /* 'abort' evaluable predicate */ +#define IO_ERROR 2 /* every STDIO failure that is not */ +#define END_OF_FILE 3 /* end of file on input */ +#define ARITH_ERROR 4 /* incorrect args. to 'is", =:=, etc. */ +#define GEN_ERROR 5 /* all others report here */ + +/* Initial state flags (set by switches: see parms.c) */ + +#define IN_BOOT 2 +#define QUIET 3 +#define DEBUG 4 +#define TRACE 5 + +/* predefined I/O streams */ + +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +/* Work areas */ + +/* Indices of areas */ + +#define AtomId 0 +#define AuxId 1 +#define TrailId 2 +#define HeapId 3 +#define GlobalId 4 +#define LocalId 5 + +/* origins of work areas */ + +#define atom0 (Origin[AtomId]) +#define auxstk0 (Origin[AuxId]) +#define trbase (Origin[TrailId]) +#define skel0 (Origin[HeapId]) +#define glb0 (Origin[GlobalId]) +#define lcl0 (Origin[LocalId]) + +/* limits of work areas */ + +#define atmax Limit[AtomId] +#define auxmax Limit[AuxId] +#define trmax Limit[TrailId] +#define hpmax Limit[HeapId] +#define v1max Limit[GlobalId] +#define vmax Limit[LocalId] + +/* Tide marks */ + +#define HighTide(reg,mark) if (reg > mark) mark = reg + +#define Auxtide Tide[AuxId] +#define TRtide Tide[TrailId] +#define V1tide Tide[GlobalId] +#define Vtide Tide[LocalId] + +/* initial atoms */ + +#define BATOMS 15 + +#define atomnil BasicAtom[0] +#define commafunc BasicAtom[1] +#define assertatom BasicAtom[2] +#define EndOfFile BasicAtom[3] +#define atomtrue BasicAtom[4] +#define user BasicAtom[5] +#define live BasicAtom[6] +#define breakat BasicAtom[7] +#define LessThan BasicAtom[8] +#define Equal BasicAtom[9] +#define GreaterThan BasicAtom[10] +#define Yes BasicAtom[11] +#define No BasicAtom[12] +#define Minus BasicAtom[13] +#define semicatom BasicAtom[14] + +/* initial functors */ + +#define BFUNCS 8 + +#define calltag BasicFunctor[0] +#define commatag BasicFunctor[1] +#define assertfunc BasicFunctor[2] +#define listfunc BasicFunctor[3] +#define arrowtag BasicFunctor[4] +#define provefunc BasicFunctor[5] +#define HiddenCall BasicFunctor[6] +#define PrivTerm BasicFunctor[7] + +/* basic terms */ + +#define BTERMS 2 + +#define List10 BasicTerm[0] /* not read in from init file */ +#define CsltUser BasicTerm[1] + +/* Magic sequence that starts saved states */ + +#define SaveMagic "PLGS" + +/* Exit codes */ + +#ifdef unix +# define GOOD_EXIT 0 +# define BAD_EXIT 1 +#else +# define GOOD_EXIT 1 +# define BAD_EXIT 0 +#endif + +/* public data */ + +extern PTR v, x, vv, v1, vv1, x1, v1f, tr, tr0, + atomfp, hasha, vra, vrz, varfp, lsp, brkp, + Origin[], Limit[], Tide[], BasicFunctor[], BasicAtom[], + BasicTerm[], FileAtom[]; + +extern char Switch[], StandardStartup[], Parameter[], + *ErrorMess, OutBuf[], PlPrompt[], *AreaName[], version[]; + +extern VarP varchain; + +extern int crit, running, debug, sklev, quoteia, nvars, lc, errno, + saveversion, Switches, Size[], State[], NParms, + Input, Output, AllFloat; + +/* public functions */ + +extern int See(), Tell(), CSee(), CTell(), gunify(), instance(), + intval(), Statistics(), Safe(), Unsafe(); +extern PTR fentry(), apply(), makelist(), deref(), arg(), argv(), recorded(), + lookup(), lookupvar(), pread(), record(), getsp(), Telling(), + Seeing(), NoSpace(), Unary(), Binary(), scanstack(), findinv(); + +extern char Get(), ToEOL(), *SysError(), *AtomToFile(); + +extern float CPUTime(); diff --git a/source_code/c-prolog-1982/pl/all b/source_code/c-prolog-1982/pl/all new file mode 100755 index 0000000..31507af --- /dev/null +++ b/source_code/c-prolog-1982/pl/all @@ -0,0 +1,17 @@ +/* all: Load all the current bits of the standard Prolog system + + Fernando Pereira + Updated: 30 December 82 +*/ + +:-([ + 'pl/arith', % Arithmetic compilation + 'pl/grammar', % DCG grammar rule translation + 'pl/setof', % Setof and sorting + 'pl/tracing', % Debugging evaluable predicates + 'pl/listing' % Listing the database + ]). + + +:-([ 'pl/protect' ]). % Lock things up + diff --git a/source_code/c-prolog-1982/pl/arith b/source_code/c-prolog-1982/pl/arith new file mode 100755 index 0000000..2605ed2 --- /dev/null +++ b/source_code/c-prolog-1982/pl/arith @@ -0,0 +1,106 @@ +/* pl/arith: preprocess arithmetic expressions */ + +$compile_arith(P0,P) :- + $carith(1,1), !, + $expand_arith(P0,P). +$compile_arith(P,P). + +$expand_arith(P,P) :- var(P), !. +$expand_arith(P0,P) :- $expand_arith0(P0,P). + +$expand_arith0((P0,Q0),(P,Q)) :- !, + $expand_arith(P0,P), + $expand_arith(Q0,Q). +$expand_arith0((P0;Q0),(P;Q)) :- !, + $expand_arith(P0,P), + $expand_arith(Q0,Q). +$expand_arith0(X is Y, X is Y) :- var(Y), !. +$expand_arith0(X is Y, P) :- !, + $expand_expression(Y,P0,X0), + $drop_is(X0,X,P1), + $and(P0,P1,P). +$expand_arith0(Comp0,R) :- + functor(Comp0,Op,2), + $comp_op(Op), !, + arg(1,Comp0,E), + arg(2,Comp0,F), + functor(Comp,Op,2), + arg(1,Comp,U), + arg(2,Comp,V), + $expand_expression(E,P,U), + $expand_expression(F,Q,V), + $and(P,Q,R0), + $and(R0,Comp,R). +$expand_arith0(P,P). + +$expand_expression(V,true,V) :- var(V), !. +$expand_expression(A,true,A) :- atomic(A), !. +$expand_expression(T,P,V) :- + $op_to_pred(T,N,V,P0), + $expand_expression_args(N,T,P0,true,Q), + $and(Q,P0,P). + +$expand_expression_args(0,_,_,P,P) :- !. +$expand_expression_args(N,T,G,P0,P) :- + arg(N,T,E), + arg(N,G,V), + $expand_expression(E,Q,V), + M is N-1, + $and(P0,Q,P1), + $expand_expression_args(M,T,G,P1,P). + +$comp_op(<). +$comp_op(>). +$comp_op(=<). +$comp_op(>=). +$comp_op(=:=). +$comp_op(=\=). + +$and(true,P,P) :- !. +$and(P,true,P) :- !. +$and(P,Q,(P,Q)). + +$rename_op(Op0,N,Op) :- + $rename_op0(Op0,N,Op), !. +$rename_op(Op,_,Op). + +% Unary operations + +$rename_op0(+,1,'$+'). +$rename_op0(-,1,'$-'). +$rename_op0(\,1,'$\'). +$rename_op0(exp,1,$exp). +$rename_op0(log,1,$log). +$rename_op0(log10,1,$log10). +$rename_op0(sqrt,1,$sqrt). +$rename_op0(sin,1,$sin). +$rename_op0(cos,1,$cos). +$rename_op0(tan,1,$tan). +$rename_op0(asin,1,$asin). +$rename_op0(acos,1,$acos). +$rename_op0(atan,1,$atan). +$rename_op0(floor,1,$floor). + +% Binary operations + +$rename_op0(+,2,'$+'). +$rename_op0(-,2,'$-'). +$rename_op0(*,2,'$*'). +$rename_op0(/,2,'$/'). +$rename_op0(mod,2,$mod). +$rename_op0(/\,2,'$/\'). +$rename_op0(\/,2,'$\/'). +$rename_op0(<<,2,'$<<'). +$rename_op0(>>,2,'$>>'). +$rename_op0(//,2,'$//'). +$rename_op0(^,2,'$^'). + +$op_to_pred(T,N,V,P) :- + functor(T,Op0,N), + $rename_op(Op0,N,Op), + M is N+1, + functor(P,Op,M), + arg(M,P,V). + +$drop_is(V,V,true) :- var(V), !. +$drop_is(V,X,X is V). diff --git a/source_code/c-prolog-1982/pl/grammar b/source_code/c-prolog-1982/pl/grammar new file mode 100755 index 0000000..bb6d8df --- /dev/null +++ b/source_code/c-prolog-1982/pl/grammar @@ -0,0 +1,51 @@ +% grammar: translation of grammar rules - 30 December 82 + +$translate_rule((LP-->[]),H) :- !, $t_lp(LP,S,S,H). +$translate_rule((LP-->RP),(H:-B)):- + $t_lp(LP,S,SR,H), + $t_rp(RP,S,SR,B1), + $tidy(B1,B). + +$t_lp((LP,List),S,SR,H):- !, + $append(List,SR,List2), + $add_extra_args([S,List2],LP,H). + +$t_lp(LP,S,SR,H) :- $add_extra_args([S,SR],LP,H). + +$t_rp(!,S,S,!) :- !. +$t_rp([],S,S1,S=S1) :- !. +$t_rp([X],S,SR,c(S,X,SR)) :- !. +$t_rp([X|R],S,SR,(c(S,X,SR1),RB)) :- !, $t_rp(R,SR1,SR,RB). +$t_rp({T0},S,S,T) :- !, $compile_arith(T0,T). +$t_rp((T,R),S,SR,(Tt,Rt)) :- !, + $t_rp(T,S,SR1,Tt), + $t_rp(R,SR1,SR,Rt). +$t_rp((T;R),S,SR,(Tt;Rt)) :- !, + $t_or(T,S,SR,Tt), + $t_or(R,S,SR,Rt). +$t_rp(T,S,SR,Tt) :- $add_extra_args([S,SR],T,Tt). + +$t_or(X,S0,S,P) :- + $t_rp(X,S0a,S,Pa), + ( var(S0a), S0a \== S, !, S0=S0a, P=Pa; + P=(S0=S0a,Pa) ). + +$add_extra_args(L,T,T1) :- + T=..Tl, + $append(Tl,L,Tl1), + T1=..Tl1. + +$append([],L,L) :- !. +$append([X|R],L,[X|R1]) :- $append(R,L,R1). + +$tidy((P1;P2),(Q1;Q2)) :- !, + $tidy(P1,Q1), + $tidy(P2,Q2). +$tidy(((P1,P2),P3),Q) :- $tidy((P1,(P2,P3)),Q). +$tidy((P1,P2),(Q1,Q2)) :- !, + $tidy(P1,Q1), + $tidy(P2,Q2). +$tidy(A,A) :- !. + +c([X|S],X,S). + diff --git a/source_code/c-prolog-1982/pl/init b/source_code/c-prolog-1982/pl/init new file mode 100755 index 0000000..58dc209 --- /dev/null +++ b/source_code/c-prolog-1982/pl/init @@ -0,0 +1,541 @@ +/* init : Initial boot file for building the Prolog system + + Fernando Pereira + Updated: 27 July 83 +*/ + + % Atoms that the code requires +[]. +','. +'{}'. +end_of_file. +true. +user. +$live. +$break. +< . += . +> . +$yes. +$no. +- . +; . + + % Functors that the code requires +call(_). +','(_,_). +'{}'(_). +'.'(_,_). +':-'(_,_). +':-'(_). +$hidden_call(_). +$hidden_term(_). + + % Terms that the code requires + +% The first term is List10 which must be constructed specially */ + +$ttynl,$csult(0,user). + + % And now we start properly + + % Predicates are attached to evaluable predicates defined in the + % code by one of two methods: + % + % 1) pred(....) :- N. + % 2) :- $sysp(pred(....),N). + % + % where N is an integer specifying the evaluable + % predicate - N is the value of the switch label in "main.c". + % The difference between these is that with the first method a + % (local) frame will be built which will contain the arguments to the + % procedure; whereas in the second case no frame is built. + + % Set up the Operators + + :-(op(P,T,A),76). + + :-(op(1200,fx,[ :- , ?- ])). + :-op(1200,xfx,[ (:-) , --> ]). + :-op(1100,xfy,';'). + :-op(1050,xfy,'->'). + :-op(1000,xfy,','). + :-op(900,fy,[ \+ , not , spy , nospy ]). + :-op(700,xfx,[ =, is, =.. , ==, \==, @<, @>, @=<, @>=, =:=, =\=, <, > , =<, >= ]). + :-op(500,yfx,[+,-,/\,\/]). + :-op(500,fx,[(+),(-),\]). + :-op(400,yfx,[*,/,//,<<,>>]). + :-op(300,xfx,[mod]). + :-op(200,xfy,'^'). + + + % And now all the evaluable predicates + + $sysp(F,N) :- 100. + $sysflgs(F,N) :- 101. + $hide_atom(A) :- 171. + + :-$sysp((A,B),6). +call(P) :- 1. +:-$sysp($hidden_call(P),121). +:-$sysp(!,2). +true. + repeat :- 3. + :-$sysp(abort,4). + :-$sysp($call(_),5). + +$not(X) :- $user_call(X), !, fail. +$not(X). + +\+(X) :- $not(X). +not(X) :- $not(X). + +(A -> B ; C) :- !, $cond(A,B,C). + + $cond(A,B,C) :- $user_call(A), !, $user_call(B). + $cond(A,B,C) :- $user_call(C). + +(A;B) :- $call(A). +(A;B) :- $call(B). +(A -> B) :- $user_call(A), !, $user_call(B). + + see(F) :- 10. + seeing(F) :- 11. + seen :- 12. + tell(F) :- 13. + append(F) :- 174. + telling(F) :- 14. + told :- 15. + close(F) :- 16. + read(T) :- 17. + write(T) :- 18. display(T) :- 274. % + 256 + nl :- 19. ttynl :- 275. $ttynl :- 275. + get0(C) :- 20. ttyget0(C) :- 276. + get(C) :- 21. ttyget(C) :- 277. + skip(C) :- 22. ttyskip(C) :- 278. + put(C) :- 23. ttyput(C) :- 279. + tab(C) :- 24. ttytab(C) :- 280. + fileerrors :- 25. + nofileerrors :- 26. + rename(F,F1) :- 27. + writeq(T) :- 28. + sh :- 29. + system(S) :- 30. + +print(V) :- var(V), !, write(V). + +print(X) :- portray(X), !. + +print(X) :- write(X). + + % define arithmetic operators + + % nullary ops + + :-$sysflgs(cputime,1). + :-$sysflgs(heapused,2). + :-$sysflgs(breaklevel,3). + % unary operations + + :-$sysflgs([A|B],1). + :-$sysflgs(+(A),1). + :-$sysflgs(-(A),2). + :-$sysflgs(\(A),3). + :-$sysflgs(exp(A),4). + :-$sysflgs(log(A),5). + :-$sysflgs(log10(A),6). + :-$sysflgs(sqrt(A),7). + :-$sysflgs(sin(A),8). + :-$sysflgs(cos(A),9). + :-$sysflgs(tan(A),10). + :-$sysflgs(asin(A),11). + :-$sysflgs(acos(A),12). + :-$sysflgs(atan(A),13). + :-$sysflgs(floor(A),14). + + % binary operations + :-$sysflgs(A+B,1). + :-$sysflgs(A-B,2). + :-$sysflgs(A*B,3). + :-$sysflgs(A/B,4). + :-$sysflgs(A mod B,5). + :-$sysflgs(A /\ B,6). + :-$sysflgs(A\/B,7). + :-$sysflgs(A<>B,9). + :-$sysflgs(A//B,10). + :-$sysflgs(A^B,11). + +% Unary predicates + +'$+'(A,X) :- 131. +'$-'(A,X) :- 132. +'$\'(A,X) :- 133. +$exp(A,X) :- 134. +$log(A,X) :- 135. +$log10(A,X) :- 136. +$sqrt(A,X) :- 137. +$sin(A,X) :- 138. +$cos(A,X) :- 139. +tan(A,X) :- 140. +$asin(A,X) :- 141. +$acos(A,X) :- 142. +$atan(A,X) :- 143. +$floor(A,X) :- 144. + +% Binary operations + +'$+'(A,B,X) :- 151. +'$-'(A,B,X) :- 152. +'$*'(A,B,X) :- 153. +'$/'(A,B,X) :- 154. +$mod(A,B,X) :- 155. +'$/\'(A,B,X) :- 156. +'$\/'(A,B,X) :- 157. +'$<<'(A,B,X) :- 158. +'$>>'(A,B,X) :- 159. +'$//'(A,B,X) :- 160. +'$^'(A,B,X) :- 161. + +X is Y :- 40. +X =:= Y :- 41. +X =\= Y :- 42. +X < Y :- 43. +X > Y :- 44. +X =< Y :- 45. +X >= Y :- 46. + +var(X) :- 50. +nonvar(X) :- 51. +integer(X) :- 52. +number(X) :- 91. +atomic(X) :- 53. +atom(X) :- 59. +primitive(X) :- 118. +db_reference(X) :- 119. + +statistics :- 93. + +prompt(_,_) :- 31. +exists(user) :- !. +exists(_) :- 32. +$save(F,I) :- 33. + +save(F) :- $save(F,_). +save(F,I) :- $save(F,I). + +X=X. +functor(T,F,N) :- 56. +arg(N,T,A) :- 57. +X=..L :- 58. +name(X,L) :- 75. + +A == B :- 54. +A \== B :- 55. +A @< B :- 86. +A @> B :- 87. +A @=< B :- 88. +A @>= B :- 89. + +clause(P,Q) :- !, $checkkey(P), $clause((P:-Q),R,P). +clause(P,Q,R) :- var(R), !, $checkkey(P), $clause((P:-Q),R,P). +clause(P,Q,R) :- instance(R,(P:-Q)). +assert(C) :- 61. assertz(C) :- 61. +asserta(C) :- 62. +assert(C,R) :- 63. assertz(C,R) :- 63. +asserta(C,R) :- 64. +$clause(_,_,_) :- 65. $clause(_,_,_):-66. + +retract(C) :- $retract(C). + +$retract(V) :- var(V), !, fail. +$retract( (Head :- Body) ) :- + !, + clause(Head,Body,ID), + erase(ID). +$retract( UnitClause ) :- + clause(UnitClause,true,ID), + erase(ID). + +abolish(Pred,Arity) :- 173. + +$recorded(_,_,_) :- 67. $recorded(_,_,_):-68. +recorded(K,T,R) :- $checkkey(K), $recorded(T,R,K). +$checkkey(K) :- (var(K);primitive(K)),!, + ttynl,display('! invalid key to data base'),ttynl,trace,fail. +$checkkey(_). +recorda(K,T,R) :- $checkkey(K), $recorda(K,T,R). +recordz(K,T,R) :- $checkkey(K), $recordz(K,T,R). +$recorda(_,_,_) :- 73. +$recordz(_,_,_) :- 74. +instance(R,T) :- 69. +erase(R) :- 60. +erased(R) :- 92. + +$leash(P,N) :- 78. +$debug(P,N) :- 79. +current_atom(A) :- 80. +current_atom(A) :- 81. +$current_functor(A,N,K,M) :- 82. +$current_functor(A,N,K,M) :- 83. +current_functor(A,P) :- nonvar(P),!, functor(P,A,_). +current_functor(A,P) :- + current_atom(A), + $current_functor(A,N,0,0), + functor(P,A,N). +current_predicate(A,P) :- + current_atom(A), + $current_functor(A,N,256,2'11100000), + functor(P,A,N). + +$flags(F,P,N) :- 84. +compare(Op,T1,T2) :- 85. +trace :- 72. + +'NOLC' :- 70. +'LC' :- 71. + + % Various hacky system predicates + + :-$sysp($break(_),102). + :-$sysp($exit_break,103). + $prompt(_) :- 104. + $user_exec(_) :- 105. + :-$sysp($save_read_vars,106). + :-$sysp($reset_read_vars,107). + :-$sysp($repply,108). + $recons(_) :- 109. + :-$sysp($break_start,110). + :-$sysp($break_end,111). + $assertr(_) :- 112. + :-$sysp($rest_in_peace,113). + $user_call(_) :- 114. + $repeat :- 3. + $read(X) :- 17. + + % How to get out (various mnemonics) + + :- $sysp(halt,113). + +%----------------------------------------------------------------------- + +% Interpreter control + +$live:- $cycle(0), $rest_in_peace. % this is the Prolog session goal + +$cycle(0):- + prompt(Old,'| '), + $repeat, + $prompt('| ?- '), $read(C), + $interpret(C,0), + prompt(_,Old), + !. + +$cycle(Status):- + prompt(Old,'| '), + $repeat, + $read(C), + $interpret(C,Status), + prompt(_,Old), + !. + +$interpret(C,Status) :- + var(C), + !, + display('! Statement is a variable'), + ttynl, + fail. + +$interpret(end_of_file,_):-!. + +$interpret(C,Status):- + $directive(C,Status,D,T), + !, + prompt(Old,'|: '), + $dogoal(T,D), + prompt(_,Old), + fail. + +$interpret(C,Status):- + expand_term(C,C1), + $assert(C1), + !, + fail. + +$assert(C):-$assertr(C),!. +$assert(C):- + seeing(user), + !. +$assert(C):- + display('! clause: '), + display(C). + +$directive(:-(X),_,X,command) :- !. +$directive(?-(X),_,X,question) :- !. +$directive(X,0,X,question). + +$dogoal(command,C) :- + $user_exec(C), + !. + +$dogoal(command,_) :- + !, + ttynl, display('?'), + ttynl. + +$dogoal(question,Q) :- + $save_read_vars, + $user_exec(Q), + $repply, + ttynl, + $show_break_level, + display(yes), + $reset_read_vars, + ttynl, + !. + +$dogoal(question,_) :- + ttynl, + $show_break_level, + display(no), + $reset_read_vars, + ttynl, + !. + + +/* consult and reconsult */ + +consult(X):-!, $break($csult(0,X)). + +reconsult(X) :- $break($csult(1,X)). + +[X|Rest] :- $conlist([X|Rest]). + + $conlist([]) :- !. + $conlist([-X|Rest]) :- !, reconsult(X), $conlist(Rest). + $conlist([X|Rest]) :- !, consult(X), $conlist(Rest). + + +$csult(R,F) :- + S0 is heapused, + T0 is cputime, + $recons(R), + $checkfile(F), + $read_file(F,consult), + Tt is cputime-T0, + Ts is heapused-S0, + display(F), $dpr(R), display(Ts), display(' bytes '), + display(Tt), display(' sec.'), ttynl, + fail. +$csult(R,F) :- $exit_break. + +$dpr(0) :- !, display(' consulted '). +$dpr(1) :- display(' reconsulted '). + +$read_file(F,S) :- + seeing(I), + telling(O), + see(F), + $cycle(S), + close(F), + see(I), + tell(O), + fail. +$read_file(_,_). + +$checkfile(F) :- + (atom(F); + ttynl, display('! Invalid file name: '), + display(F), ttynl, fail + ), + !, + (exists(F); + ttynl, display('! The file '), display(F), + display(' does not exist.'), ttynl, fail + ), + !. + +/* break */ + +break :- $break($break). + +$break :- + $break_start, + $read_file(user,0), + $break_end, + $exit_break. +$break :- $exit_break. % just to make sure + +$show_break_level :- + B is breaklevel, + $shb(B). + +$shb(0) :- !. +$shb(N) :- ttyput("["), display(N), ttyput("]"), ttyput(" "). + +/* Arithmetic expansion */ + +expand_exprs(X,Y) :- + $carith(X0,X0), + $flag_code(X0,X), + nonvar(Y), + $flag_code(Y0,Y), + $carith(_,Y0). + +$carith(X,Y) :- 170. + +$isop(A,P,M,L,R) :- 172. + +current_op(Prio,Type,Atom) :- + $gen_atom(Atom), + $gen_pos(Type,Pos), + $isop(Atom,Pos,Prio,Left,Right), + $op_code(Type,Pos,Prio,Left,Right). + +$gen_atom(Atom) :- atom(Atom), !. +$gen_atom(Atom) :- var(Atom), !, current_atom(Atom). + +$gen_pos(Type,Pos) :- + atom(Type), !, + $type_to_pos(Type,Pos,_,_,_). +$gen_pos(_,Pos) :- + $op_pos(Pos). + +$op_code(Type,Pos,Prio,Left,Right) :- + $type_to_pos(Type,Pos,Prio,LeftExpr,RightExpr), + Left is LeftExpr, Right is RightExpr, !. + +$op_pos(0). % PREFIX (must be the same as in rewrite.c) +$op_pos(1). % INFIX +$op_pos(2). % POSTFIX + +$type_to_pos(fx,0,Prio,Prio,Prio-1). +$type_to_pos(fy,0,Prio,Prio,Prio). +$type_to_pos(xfx,1,Prio,Prio-1,Prio-1). +$type_to_pos(xfy,1,Prio,Prio-1,Prio). +$type_to_pos(yfx,1,Prio,Prio,Prio-1). +$type_to_pos(yf,2,Prio,Prio,Prio). +$type_to_pos(xf,2,Prio,Prio-1,Prio). + +all_float(X,Y) :- + $all_float(X0,X0), + $flag_code(X0,X), + nonvar(Y), + $flag_code(Y0,Y), + $all_float(_,Y0). + +$all_float(X,Y) :- 90. + +$flag_code(1,on). +$flag_code(0,off). + +expand_term(T0,T) :- + term_expansion(T0,T1), !, + $expand_term(T1,T). +expand_term(T0,T) :- $expand_term(T0,T). + +$expand_term(T0,T) :- $translate_rule(T0,T), !. +$expand_term((H:-B0),(H:-B)) :- $compile_arith(B0,B), !. +$expand_term(T,T). + +end_of_file. % needed here for a special reason... diff --git a/source_code/c-prolog-1982/pl/listing b/source_code/c-prolog-1982/pl/listing new file mode 100755 index 0000000..9b93479 --- /dev/null +++ b/source_code/c-prolog-1982/pl/listing @@ -0,0 +1,64 @@ +/* listing : Listing clauses in the database + + Lawrence + Updated: 6 October 81 +*/ + +listing :- + current_predicate(_,Pred), + $list_clauses(Pred). +listing. + + +listing(V) :- var(V), !. % ignore variables +listing([]) :- !. +listing([X|Rest]) :- + !, + listing(X), + listing(Rest). +listing(X) :- + $functorspec(X,Name,Arity), + current_predicate(Name,Pred), + functor(Pred,Name,Arity), + $list_clauses(Pred). +listing(_). + + +$list_clauses(Pred) :- + nl, + clause(Pred,Body), + $write_clause(Pred,Body), + fail. + +$write_clause(Head,Body) :- + writeq(Head), + ( Body = true ; + tab(1), write((:-)), + $write_body(Body,3,',') + ), + put("."), nl, + !. + +$write_body(X,I,T) :- var(X), !, $beforelit(T,I), writeq(X). +$write_body((P,Q), IO, T) :- + !, + $write_body(P,IO,T), + put(","), + $aftercomma(T,IO,I), + $write_body(Q,I,','). +$write_body((P;Q),I,T) :- + !, + nl, tab(I-2), put("("), + $write_body(P,I,'('), + put(";"), + $write_body(Q,I,';'), + tab(1), put(")"). +$write_body(X,I,T) :- + $beforelit(T,I), + writeq(X). + +$aftercomma(',',I,I) :- !. +$aftercomma(_,IO,I) :- I is IO + 3. + +$beforelit('(',_) :- !, tab(1). +$beforelit(_,I) :- nl, tab(I). diff --git a/source_code/c-prolog-1982/pl/protect b/source_code/c-prolog-1982/pl/protect new file mode 100755 index 0000000..20046a4 --- /dev/null +++ b/source_code/c-prolog-1982/pl/protect @@ -0,0 +1,64 @@ +/* protect : Setting the flags for the system predicates + + Fernando Pereira + Updated: 30 December 82 +*/ + + +$mem(X,[X|_]). +$mem(X,[_|Rest]) :- $mem(X,Rest). + +$protected(P,A) :- $unprotected(P,A), !, fail. +$protected(P,A). + +% Predicate flags used here: +% +% +% 128 (PROTECTED) +% 64 (INVISIBLE) +% 32 (UNTRACEABLE) + + +% Cut must be transparent due to the way it is currently +% implemented (this fixes bug that prevented tracing +% past cuts). +% Note that transparent also seem to imply untracable, +% which means you don't see cuts at all. + + :- $sysflgs(!,64). + + + % This list are all transparent and untracable. + + :-(( $mem(X,[ call(_),(A,B),(A;B),$call(_),$hidden_call(_),(A->B)]), + $sysflgs(X,96), fail ; true )). + + % The following predicates are better off invisible so + % they are made untracable as well. + + :-(( $mem(X,[ + write(_), writeq(_), nl, get0(_), get(_), skip(_), put(_), tab(_), + display(_), ttynl(_), ttytab(_), read(_), spy(_), nospy(_), + leash(_), trace, debug, nodebug, debugging + ]), + $sysflgs(X,32), fail ; true )). + + % ALL current predicates but those specified + % by $unprotected are turned into + % system predicates (which cannot be redefined, seen + % by listing etc). + + :-(( current_atom(A), $current_functor(A,Arity,256,0), $protected(A,Arity), + functor(Pred,A,Arity), $flags(Pred,Flags,Flags\/128), fail ; true )). + :- $flags(fail,Flags,Flags\/128). % Must be specially protected (no clauses) + + % Finally, ALL predicates whose names start with a + % dollar are made untraceable and their atoms hidden. + + :-(( current_atom(A), name(A,[36|_]), + $hide_atom(A), % THIS MUST BE IN THE LAST GOAL IN THE BOOT LOAD!! + $current_functor(A,Arity,256,0), + functor(Pred,A,Arity), + $flags(Pred,Flags,Flags\/32), fail ; true )). + + diff --git a/source_code/c-prolog-1982/pl/setof b/source_code/c-prolog-1982/pl/setof new file mode 100755 index 0000000..78caf89 --- /dev/null +++ b/source_code/c-prolog-1982/pl/setof @@ -0,0 +1,166 @@ +/* setof : 'setof', 'bagof' and sorting. */ + +:- op(200,xfy,^). + +setof(X,P,Set) :- + $setof(X,P,Set). + +$setof(X,P,Set) :- + $bagof(X,P,Bag), + sort(Bag,Set0), + Set=Set0. + +bagof(X,P,Bag) :- + $bagof(X,P,Bag). + +$bagof(X,P,Bag) :- + $excess_vars(P,X,[],L), $nonempty(L), !, + Key =.. [$|L], + $bagof(X,P,Key,Bag). +$bagof(X,P,Bag) :- + $tag('$bag','$bag'), + $user_call(P), + $tag('$bag',X), + fail. +$bagof(X,P,Bag) :- $reap([],Bag), $nonempty(Bag). + +$bagof(X,P,Key,Bag) :- + $tag('$bag','$bag'), + $user_call(P), + $tag('$bag',Key-X), + fail. +$bagof(X,P,Key,Bag) :- + $reap([],Bags0), + keysort(Bags0,Bags), + $pick(Bags,Key,Bag). + +$nonempty([_|_]). + +$reap(L0,L) :- + $untag('$bag',X), !, + $reap1(X,L0,L). + +$reap1(X,L0,L) :- X \== '$bag', !, $reap([X|L0],L). +$reap1(_,L,L). + +$pick(Bags,Key,Bag) :- + $nonempty(Bags), + $parade(Bags,Key1,Bag1,Bags1), + $decide(Key1,Bag1,Bags1,Key,Bag). + +$parade([Item|L1],K,[X|B],L) :- $item(Item,K,X), !, + $parade(L1,K,B,L). +$parade(L,K,[],L). + +$item(K-X,K,X). + +$decide(Key,Bag,Bags,Key,Bag) :- (Bags=[], ! ; true). +$decide(_,_,Bags,Key,Bag) :- $pick(Bags,Key,Bag). + +$excess_vars(T,X,L0,L) :- var(T), !, + ( $no_occurrence(T,X), !, $introduce(T,L0,L) + ; L = L0 ). +$excess_vars(X^P,Y,L0,L) :- !, $excess_vars(P,(X,Y),L0,L). +$excess_vars(setof(X,P,S),Y,L0,L) :- !, $excess_vars((P,S),(X,Y),L0,L). +$excess_vars(bagof(X,P,S),Y,L0,L) :- !, $excess_vars((P,S),(X,Y),L0,L). +$excess_vars(T,X,L0,L) :- functor(T,_,N), $rem_excess_vars(N,T,X,L0,L). + +$rem_excess_vars(0,_,_,L,L) :- !. +$rem_excess_vars(N,T,X,L0,L) :- + arg(N,T,T1), + $excess_vars(T1,X,L0,L1), + N1 is N-1, + $rem_excess_vars(N1,T,X,L1,L). + +$introduce(X,L,L) :- $included(X,L), !. +$introduce(X,L,[X|L]). + +$included(X,L) :- $doesnt_include(L,X), !, fail. +$included(X,L). + +$doesnt_include([],X). +$doesnt_include([Y|L],X) :- Y \== X, $doesnt_include(L,X). + +$no_occurrence(X,Term) :- $contains(Term,X), !, fail. +$no_occurrence(X,Term). + +$contains(T,X) :- var(T), !, T == X. +$contains(T,X) :- functor(T,_,N), $upto(N,I), arg(I,T,T1), $contains(T1,X). + +$upto(N,N) :- N > 0. +$upto(N,I) :- N > 0, N1 is N-1, $upto(N1,I). + +/*---------------------------------------------------------------------------- */ +/* Sorting by bisecting and merging. */ + +sort(L,R) :- length(L,N), $sort(N,L,_,R1), R=R1. + +$sort(2,[X1|L1],L,R) :- !, $comprises(L1,X2,L), + compare(Delta,X1,X2), + (Delta = (<) , !, R = [X1,X2] + ; Delta = (>) , !, R = [X2,X1] + ; R = [X2] + ). +$sort(1,[X|L],L,[X]) :- !. +$sort(0,L,L,[]) :- !. +$sort(N,L1,L3,R) :- + N1 is N//2, N2 is N-N1, + $sort(N1,L1,L2,R1), + $sort(N2,L2,L3,R2), + $merge(R1,R2,R). + +$merge([],R,R) :- !. +$merge(R,[],R) :- !. +$merge(R1,R2,[X|R]) :- + $comprises(R1,X1,R1a), $comprises(R2,X2,R2a), + compare(Delta,X1,X2), + (Delta = (<) , !, X = X1, $merge(R1a,R2,R) + ; Delta = (>) , !, X = X2, $merge(R1,R2a,R) + ; X = X1, $merge(R1a,R2a,R) + ). + +$comprises([X|L],X,L). + +/*------------------------------------------------------------------------ */ +/* Sorting on keys by bisecting and merging. */ + +keysort(L,R) :- length(L,N), $keysort(N,L,_,R1), R=R1. + +$keysort(2,[X1|L1],L,R) :- !, + $comprises(L1,X2,L), + $compare_keys(Delta,X1,X2), + (Delta = (>) , !, R = [X2,X1] ; R = [X1,X2] ). +$keysort(1,[X|L],L,[X]) :- !. +$keysort(0,L,L,[]) :- !. +$keysort(N,L1,L3,R) :- + N1 is N//2, N2 is N-N1, + $keysort(N1,L1,L2,R1), + $keysort(N2,L2,L3,R2), + $keymerge(R1,R2,R). + +$keymerge([],R,R) :- !. +$keymerge(R,[],R) :- !. +$keymerge(R1,R2,[X|R]) :- + $comprises(R1,X1,R1a), $comprises(R2,X2,R2a), + $compare_keys(Delta,X1,X2), + (Delta = (>) , !, X = X2, $keymerge(R1,R2a,R) + ; X = X1, $keymerge(R1a,R2,R) + ). + +$compare_keys(Delta,K1-X1,K2-X2) :- compare(Delta,K1,K2). + +/*======================================================================*/ + +X^P :- P. + +/*======================================================================*/ + +$tag(Key,Value) :- + recorda(Key,Value,_). + +$untag(Key,Value) :- + recorded(Key,Value,Ref), + erase(Ref). + +length([],0) :- !. +length([_|L],N) :- !, length(L,N0), N is N0+1. diff --git a/source_code/c-prolog-1982/pl/tracing b/source_code/c-prolog-1982/pl/tracing new file mode 100755 index 0000000..88f038d --- /dev/null +++ b/source_code/c-prolog-1982/pl/tracing @@ -0,0 +1,147 @@ +% tracing : trace control + +debug :- + $debug(P,1), + ( P=1 ; + display('Debug mode switched on.'), ttynl + ), !. + +nodebug :- + $debug(P,0), + ( P=0 ; + ( $someleft, $allspyremove, + display('All spy-points removed.'), ttynl ; + true + ), + display('Debug mode switched off.'), ttynl + ), !. + +spy(X) :- $spy(X,on), $someleft, debug, fail. +spy(_). + +nospy(X) :- $spy(X,off), fail. +nospy(_). + +leash(X) :- nonvar(X), + $leashcode(X,N), + $leash(P,N), + $prleash(N), !. +leash(X) :- + display('! Invalid leash specification : '), + display(X), ttynl, fail. + +$leashcode(full,2'1111) :- !. +$leashcode(on,2'1111):- !. +$leashcode(half,2'1010) :- !. +$leashcode(loose,2'1000) :- !. +$leashcode(off,2'0000) :- !. +$leashcode(N,N) :- integer(N), N>=0, N=<2'1111, !. + + +$prleash(0) :- !, display('No leashing.'), ttynl. +$prleash(N) :- + $leashcode(Code,N), + display('Leashing set to '), display(Code), + display(' ('),$pcl(Had,2'1000,N,call), + $pcl(Had,2'0100,N,exit), + $pcl(Had,2'0010,N,backto), + $pcl(Had,2'0001,N,fail), + display(').'),ttynl. + +$pcl(Had,M,N,W) :- N/\M =:= 0, !. +$pcl(Had,_,_,W) :- + ( var(Had),Had=yes ; + display(',') + ), + display(W), !. + +debugging :- $debug(D,D), + ( D=0, !, + display('Debug mode is switched off.'), + ttynl, ! ; + display('Debug mode is switched on.'), ttynl, + ( $someleft, !, + display('Spy-points set on : '),ttynl, + ( current_atom(Functor), + $current_functor(Functor,Arity,2'100010000,2'11110000), + ttytab(8), $prspy(Functor,Arity), ttynl, fail ; + true + ) ; + display('There are no spy-points set.'), ttynl + ), + $leash(L,L), $prleash(L) ), !. + +$spy(V,_) :- var(V), !, + display('! Invalid procedure specification : '), + display(V),ttynl. +$spy([],_) :- !. +$spy([HD|TL]):- !, + $spy(HD), + $spy(TL). +$spy(X,off) :- + $functorspec(X,Functor,Arity), + ( var(Arity) ; A=Arity ), + ( $current_functor(Functor,A,2'100010000,2'11110000), + !, + ( $current_functor(Functor,Arity,2'100010000,2'11110000), + functor(T,Functor,Arity), $flags(T,P,P/\2'11101111), + display('Spy-point on '), $prspy(Functor,Arity), + display(' removed.'), ttynl, fail + ; true + ) + ; display('There is no spy point on'), + display(X), display('.'), ttynl + ), !. + +$spy(X,on) :- + $functorspec(X,Functor,Arity), + ( atom(X), + ( $current_functor(Functor,Arity,2'100000000,2'11110000), + functor(Head,Functor,Arity), + $enter(Head,Functor,Arity), + fail + ; ( $current_functor(Functor,_,2'100000000,2'11100000) ; + display('You have no clauses for '), display(X), + display(' - nothing done.'), ttynl + ) ) + ; functor(Head,Functor,Arity), + ( $current_functor(Functor,Arity,256,2'111100000) + ; display('[ Warning: you have no clauses for '), + $prspy(Functor,Arity), display(' ]'), ttynl + ), + $enter(Head,Functor,Arity) + ), + !. + +$spy(_,_). + + +$enter(Head,Functor,Arity) :- + ( $current_functor(Functor,Arity,2'100010000,2'11110000), + display('There already is a spy-point on '); + $flags(Head,P,P), + ( P/\2'11100000 =:= 0, $flags(Head,P,P\/2'10000) ; true), + display('Spy-point placed on ') + ), + $prspy(Functor,Arity), + display('.'), ttynl, !. + +$prspy(Functor,Arity) :- + display(Functor), display(/), display(Arity). + +$someleft :- current_atom(A), $current_functor(A,_,2'10000,2'10000), !. + +$allspyremove :- + current_atom(F), + $current_functor(F,A,2'100010000,2'11110000), + functor(T,F,A), $flags(T,P,P/\2'11101111), fail. +$allspyremove. + +$functorspec(V,_,_) :- var(V),!, $badspec(V). +$functorspec(X,X,_) :- atom(X),!. +$functorspec(F/N,F,N) :- atom(F), integer(N), !. +$functorspec(X,_,_) :- $badspec(X). + +$badspec(X) :- display('! Invalid procedure specification : '), + display(X), ttynl, fail. + diff --git a/source_code/c-prolog-1982/pl/vmsall b/source_code/c-prolog-1982/pl/vmsall new file mode 100755 index 0000000..fd53a1a --- /dev/null +++ b/source_code/c-prolog-1982/pl/vmsall @@ -0,0 +1,17 @@ +/* PL_ALL : Load all the current bits of the standard Prolog system + + Fernando + Updated: 16 Nov 82 +*/ + +:-([ + '[.pl]arith', % arithmetic expansion + '[.pl]grammar', % DCG grammar rule translation + '[.pl]setof', % Setof and sorting + '[.pl]tracing', % Debugging evaluable predicates + '[.pl]listing' % Listing the database + ]). + + +:-([ '[.pl]protect' ]). % Lock things up + diff --git a/source_code/c-prolog-1982/prolog b/source_code/c-prolog-1982/prolog new file mode 100755 index 0000000..c690b53 Binary files /dev/null and b/source_code/c-prolog-1982/prolog differ diff --git a/source_code/c-prolog-1982/pstartup1.5 b/source_code/c-prolog-1982/pstartup1.5 new file mode 100755 index 0000000..5f7b541 Binary files /dev/null and b/source_code/c-prolog-1982/pstartup1.5 differ diff --git a/source_code/c-prolog-1982/read.me b/source_code/c-prolog-1982/read.me new file mode 100755 index 0000000..be3124a --- /dev/null +++ b/source_code/c-prolog-1982/read.me @@ -0,0 +1,258 @@ +*********************************************************************** +* * +* C Prolog * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +*********************************************************************** + + ********* WARNING ********* + +Both the location (defined in parms.c) and the contents of the startup save +state (startup) on this tape are unlikely to be correct for your +installation. Please follow the instructions below to adapt parms.c to your +installation and to build a new startup save state. + + -------------------------- +C-Prolog 1.5 20 Feb 84 + +Extended manual, many bug fixes and improvements. +In particular, the debugger has been almost entirely rewritten and +now has the `retry' command a la DEC-10 Prolog. This should make +debugging much smoother. The command line switches that specify +the sizes of working areas have been changed to be lower-case to +avoid a problem with the VMS C implementation. The system has +been checked under VMS, Eunice, and Berkeley Unix on VAXes and Suns. + +Identifiers have been changed to avoid name clashes in systems with +Version 7 or System III C compilers. The system has not been tested +on those systems, but it should now run in them with few modifications +if any. + +The printout of the 'g' debugger command has been changed. Goals +shown are preceded by + + l (i)->(c) + +where l is the recursion level, i the invocation number and c +the position of the clause being used within its procedure. + +C-Prolog 1.4 28 July 83 + + +Revised and expanded manual. + +The compilation switch IEEE (see makefile) allows compilation of +C-Prolog for implementations of 4.1/2 BSD Unix on machines with +IEEE floating point (such as the SUN workstation). + +There are command line switches to specify the sizes of the various +work areas of C-Prolog; adjustment between the sizes in a saved state +and a starting C-Prolog is automatic. +The switches are -H (heap), -G (global stack), -L (local stack), +-T (trail), -A (atom space) and -X (auxiliary stack). each such switch +should be followed by an integer argument that specifies the size in +K bytes (see new version of the manual). + +There is a 'statistics' evaluable predicate that prints out the +sizes and used amounts of the various work areas. + +The operation of expand_term has been cleaned up and as a result +a new name, term_expansion, has been given to the user defined +part of expand_term. + +Several bugs have been fixed. + +C-Prolog 1.3 24 June 83 + +The 'g' command to the debugger prints a stack backtrace in reverse +order, with goals labeled by the distance from the current goal and +by the position with its procedure of the clause being used to satisfy +the goal. + +The debugger now shows and stops at FAIL ports, like the one on DEC-10/20 +Prolog. + +Several bugs have been fixed. + +--------------------------------------------------------------------- + +CProlog 1.2b 9 May 83 + +To install CProlog: + +Decide on names and locations for the interpreter and its startup file. +Let's say you have decided on /usr/local/prolog for the interpreter +and /usr/local/prolog-startup for the startup file, and that you have +write access to the relevant directories, etc. Then you just need to +type the following command + + make install BIN=/usr/local/prolog PLSTARTUP=/usr/local/prolog-startup + +When this finishes, the system will be ready to use. +These instructions supersede the previous ones below. + +================================================================ + +Differences between CProlog 1.2a and 1.2 - 17 February 83 + +- A bug which reported a syntax error in \+ (p,q) has been fixed. + +- A bug which caused atoms containing % to be printed without quotes by +'writeq' has been fixed + +- A serious bug in the interaction between nested conjunctions and cut has +been cured. + +- Bugs that caused the system to crash when returning from some functions in +sysbits.c have been fixed. + +Outstanding problems: + +The types and casts in the sources of the system should be cleaned up to +comform to the requirements of C compilers that are more strict than the +Berkeley 4.1 compiler. + +News: + +The system has now been ported to the Apollo M68000-based workstation and to +the 3 Rivers PERQ. + +Differences between CProlog 1.2 and previous versions +Fernando Pereira, 6 Jan 83 + +New evaluable predicates: + +primitive(X) + + Tests whether X is a primitive object (number or database reference). + +db_reference(X) + + Tests whether X is a database reference. + +sh (UNIX only) + + Forks a sub-shell (the one specified in the environment variable + SHELL, or "/bin/sh" if that is undefined) + +system(S) (UNIX only) + + Similar to the 'system' function defined in Section 3 of the UNIX + manual. S should be a Prolog string, for example + + sh("ls") + + +Changed features + +The operation of the debugger has been somewhat improved: + + It is no longer necessary to call 'trace' to see spy points. + + 'trace' starts tracing from the next call to a user goal, even + if that user goal is called from the command immediately after the + command that invoked 'trace'. In previous versions, 'trace' had + to be called in the same command as the goal(s) to be traced. + +Cuts inside "metacalled" goals (goals called through the evaluable predicate +'call' or a variable goal) no longer behave as if they appeared on the +calling clause. That is, in previous versions, the program + + p(X) :- X = 1, P = !, call(P). + p(2). + +would have just one solution X = 1, and now has the two solutions X = 1 and X += 2. The reason for the referentially non-transparent behaviour of the +earlier versions was a bogus definition of the effect of 'call' in the +DEC-10/20 Prolog manual, on which CProlog is based. The DEC-10/20 system DOES +NOT behave as its manual states. CProlog version 1.2 and DEC-10/20 Prolog +(version 3 or above) are therefore compatible in this respect. + +Numbers preceded by '-', eg. + + -1.2 -1 + +are treated by the reader as negative numbers, instead of as the unary +operator '-' applied to a positive number. + +Bugs fixed + +Lots! I've not kept track... + +================================================================ + +Things to know about CProlog version 1.1: + +When it starts, CProlog reads in a saved state with essential initialisation +data. In the distributed version, this file should be placed in + + /usr/local/lib/prolog/.plstartup + +If you want to change this, edit parms.c and recompile the system. The +actual file is in this directory with name PLSTARTUP. + +The startup saved state can be reconstructed in the following way: + + cd into this directory + prolog -b pl/init + ['pl/all']. + :-save(startup). + halt. + +The startup file is now 'startup' in this directory, and you should move it +to its final place as described above. + +Various system parameters, such as the name of the startup file and the +sizes of work areas, are defined in the file parms.c. To change any of these +parameters, edit this file and recompile the system using 'make'. If you +change these parameters, old saved states should still work with the new +system. However, I suspect there may be bugs in this area. + + +Differences between this system and other similar Prolog systems (DEC-10/20 +Prolog, EMAS Prolog and PDP-11 Prolog): + +* Floating point! In particular, / is floating divide and // integer divide. +Beware of this if you are moving programs from other Prologs. Most of the +math functions in the C library are available as arithmetic operators, eg. +you may write a goal + + X is 3.5e2+sin(sqrt(Y)) + +* database references returned by recorda/z and friends can be used in +terms/clauses to be recorded/asserted; + +* prompting for alternatives at top level is like on DEC-10 Prolog, not like +on EMAS or PDP-11 Prolog. + +* setof, bagof, compare, sort, keysort, @<, @=<, @>, @>= are available, and +the same as in DEC-10 Prolog. Setof and bagof are very slow, though. + +A preliminary version of the user's manual for CProlog is in the directory +'man'. A printable version can be made with the makefile there. The manual +will print better if your output device can produce bold-face (we have a +local version of 'nroff' that produces "bold" on line-printers by +overstriking). + +Known Bugs +========== + +***** FIXED in 1.2 ***** +The system accepts without complaint clauses whose body is a single integer, +and then behaves strangely when such clauses are used. The cause of this is +the mechanism for linking from Prolog to C to implement the evaluable +predicates, which relies on clauses of that form. Some check should be made +to forbid such clauses except when bootstrapping the system. +********* + +Saved states should survive a change in the sizes of the work areas. They +seem to survive sometimes, but not always. No known cure at present. diff --git a/source_code/c-prolog-1982/rewrite.c b/source_code/c-prolog-1982/rewrite.c new file mode 100755 index 0000000..62dfe71 --- /dev/null +++ b/source_code/c-prolog-1982/rewrite.c @@ -0,0 +1,818 @@ +/********************************************************************** +* * +* C Prolog rewrite.c * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ + +#include "pl.h" + +#define Isatoz(a) ('a' <= (AtomP(a)->stofae)[1] && \ + (AtomP(a)->stofae)[1] <= 'z') + +#define PREFIX 0 +#define INFIX 1 +#define POSTFIX 2 + +/* decrease left priority flag */ + +#define dlprflg 0x2000 + +/* decrease rigth priority flag */ + +#define drprflg 0x1000 + +/* priority field */ + +#define mskprty 0x0fff + +/* Character types for tokeniser */ + +#define UC 1 /* Upper case alphabetic */ +#define UL 2 /* Underline */ +#define LC 3 /* Lower case alphabetic */ +#define N 4 /* Digit */ +#define QT 5 /* Single quote */ +#define DC 6 /* Double quote */ +#define SY 7 /* Symbol character */ +#define SL 8 /* Solo character */ +#define BK 9 /* Brackets & friends */ +#define BS 10 /* Blank space */ + +static char chtyp[] = { +/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ + BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, + +/* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ + BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, BS, + +/* sp ! " # $ % & ' ( ) * + , - . / */ + BS, SL, DC, SY, LC, SL, SY, QT, BK, BK, SY, SY, BK, SY, SY, SY, + +/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ + N, N, N, N, N, N, N, N, N, N, SY, SL, SY, SY, SY, SY, + +/* @ A B C D E F G H I J K L M N O */ + SY, UC, UC, UC, UC, UC, UC, UC, UC, UC, UC, UC, UC, UC, UC, UC, + +/* P Q R S T U V W X Y Z [ \ ] ^ _ */ + UC, UC, UC, UC, UC, UC, UC, UC, UC, UC, UC, BK, SY, BK, SY, UL, + +/* ` a b c d e f g h i j k l m n o */ + SY, LC, LC, LC, LC, LC, LC, LC, LC, LC, LC, LC, LC, LC, LC, LC, + +/* p q r s t u v w x y z { | } ~ del */ + LC, LC, LC, LC, LC, LC, LC, LC, LC, LC, LC, BK, BK, BK, SY, BS }; + +PTR term(); + + +int +isop(atom,optype,p,lp,rp) +PTR atom; int optype, *p, *lp, *rp; +{ + short oe; + + switch (optype) { + case PREFIX: + oe = AtomP(atom)->prfxofae; + break; + case INFIX: + oe = AtomP(atom)->infxofae; + break; + case POSTFIX: + oe = AtomP(atom)->psfxofae; + break; + default: + return FALSE; + } + if (oe < 0) return FALSE; + *p = oe&mskprty; + *lp = !(oe&dlprflg) ? *p : *p-1; + *rp = !(oe&drprflg) ? *p : *p-1; + return TRUE; +} + +op(prio,optype,spec) +PTR prio, optype, spec; +/* processes op declarations */ +{ + int c, i, pr, typ; PTR spf, at; + static char + *OpTypes[] = { "xfx", "xfy", "yfx", "xf", "yf", "fx", "fy" }; + static int + optyp[] = { INFIX, INFIX, INFIX, POSTFIX, POSTFIX, PREFIX, PREFIX }; + char *ops; + + if (!IsInt(prio)) return FALSE; + pr = XtrInt(prio); + if (pr > 1200 || pr <= 0) return FALSE; + if (!IsAtomic(optype) || IsPrim(optype)) return FALSE; + ops = AtomP(optype)->stofae; + c = -1; + for (i = 0;i < 7; i++) + if (!strcmp(ops,OpTypes[i])) { + c = i; + break; + } + if (c < 0) return FALSE; + typ = optyp[c]; + c = 1<<(c+1); + if (c&0x16) pr |= dlprflg; + if (c&0x4a) pr |= drprflg; + spec = vvalue(spec,&spf); + do { + if (IsntName(spec) || IsRef(spec)) return FALSE; + if (IsComp(spec)) { + if (SkelP(spec)->Fn != listfunc) return FALSE; + at = arg(Addr(SkelP(spec)->Arg1),spf); + if (IsntName(at) || IsRef(at)) return FALSE; + spec = argv(Addr(SkelP(spec)->Arg2),spf,&spf); + } else + at = spec, spec = atomnil; + switch (typ) { + case PREFIX: + AtomP(at)->prfxofae = pr; + break; + case INFIX: + AtomP(at)->infxofae = pr; + break; + case POSTFIX: + AtomP(at)->psfxofae = pr; + } + } while (spec != atomnil); + return TRUE; +} + +static +legalatom(s) +char *s; +{ + char c; + + c = chtyp[*s]; + if (c == LC) { + while (c = chtyp[*s], *s++) if (c > N) return FALSE; + return TRUE; + } + if (c == SL) return (s[0] != '%' && !s[1]); + if (c != SY) return FALSE; + if (!strcmp(s,"/*") || !strcmp(s,".")) return FALSE; + while (c = chtyp[*s], *s++) if (c != SY) return FALSE; + return TRUE; +} + +static +patom(at) +PTR at; +{ + char ch, *s; + s = AtomP(at)->stofae; + if (!quoteia || legalatom(s)) { + PutString(s); + return; + } + Put('\''); + while ((ch = *s++)) { + if (ch == '\'') Put(ch); + Put(ch); + } + Put('\''); +} + +/* pwrite - write a prolog term */ + +pwrite(t,g,p) +PTR t, g; int p; +/* write term t in context of priority p + with global frame g +*/ +{ + int i, m, mr, ml; PTR ax, f, a; + if (IsPrim(t)) { + if (IsInt(t)) { + sprintf(OutBuf,"%d",XtrInt(t)); PutString(OutBuf); + return; + } + if (IsFloat(t)) { + sprintf(OutBuf,"%g",XtrFloat(t)); PutString(OutBuf); + return; + } + sprintf(OutBuf,"%x",t); + PutString(OutBuf); + return; + } + if (IsAtomic(t)) { + patom(t); + return; + } + if (Undef(*t)) { + sprintf(OutBuf,"_%d",t-glb0); PutString(OutBuf); + return; + } + if (IsRef(t)) + g = MolP(t)->Env, t = MolP(t)->Sk; + if (SkelP(t)->Fn == listfunc) { + Put('['); + do { + ax = argv(Addr(SkelP(t)->Arg1),g,&a); + pwrite(ax,a,999); + t = argv(Addr(SkelP(t)->Arg2),g,&g); + } while (IsComp(t) && (MolP(t)->Sk == listfunc) && (Put(','),TRUE)); + if (t != atomnil) { + Put('|'); + pwrite(t,g,999); + } + Put(']'); + return; + } + if (MolP(t)->Sk == assertfunc) { + Put('{'); + ax = argv(Addr(SkelP(t)->Arg1),g,&g); pwrite(ax,g,1200); + Put('}'); + return; + } + f = SkelP(t)->Fn; + i = FunctorP(f)->arityoffe; + a = FunctorP(f)->atoffe; + if (i == 1) { + if (isop(a,PREFIX,&m,&ml,&mr)) { + if (m > p) Put('('); + patom(a); + if (Isatoz(a)) Put(' '); + ax = argv(Addr(SkelP(t)->Arg1),g,&f); + pwrite(ax,f,mr); + if (m > p) Put(')'); + return; + } + if (isop(a,POSTFIX,&m,&ml,&mr)) { + if (m > p) Put('('); + ax = argv(Addr(SkelP(t)->Arg1),g,&f); + pwrite(ax,f,ml); + if (Isatoz(a)) Put(' '); + patom(a); + if (m > p) Put(')'); + return; + } + } + if (i == 2 && isop(a,INFIX,&m,&ml,&mr)) { + if (m > p) Put('('); + ax = argv(Addr(SkelP(t)->Arg1),g,&f); + pwrite(ax,f,ml); + if (Isatoz(a)) Put(' '); + patom(a); + if (Isatoz(a)) Put(' '); + ax = argv(Addr(SkelP(t)->Arg2),g,&f); pwrite(ax,f,mr); + if (m > p) Put(')'); + return; + } + patom(a); + Put('('); + while (i-- > 0) { + ax = argv(++t,g,&f); pwrite(ax,f,999); + if (i > 0) Put(','); + } + Put(')'); + return; +} + + +/*------------------------------------------------------------------- + + pread - read a prolog term + (this function has lots of auxiliary functions, which are listed first) + +*/ + +static int e; + +/* Token types */ + +#define NAME 1 +#define PRIMITIVE 2 +#define VAR 3 +#define STRING 4 +#define PUNCTUATION 5 +#define FULLSTOP 6 + +static int retoken, tokentype, rechar, chtype, errflg; +static char *line, *lp, *lpmax, ch; +static char nam[255]; +static PTR slsp; + +union { + PTR AsPTR; + char AsChar; + char * AsString; +} tokeninfo; + +/* next character from input buffer (in read) +/* allows for single char lookahead */ + +static char +nextch() +{ + if (rechar) { + rechar = FALSE; + return chtype; + } + chtype = chtyp[ch = *++lp]; + if (lp >= lpmax) lp = lpmax-2; + return chtype; +} + + +/* look up variable name in variable table (in read) */ + +PTR +lookupvar(id) +char *id; +{ + PTR p; VarP r, q; int l; + + if (!strcmp(id,"_")) { + p = v1; *v1 = NULL; GrowGlobal(1); + return p; + } + for (q = varchain, r = NULL; q; r = q, q = q->NextVar) + if (!strcmp(q->VarName,id)) return q->VarValue; + l = Words(sizeof(VarEntry)+strlen(id))+1; + q = (VarP)varfp; + varfp += l; + HighTide(varfp,Auxtide); + if (varfp > auxmax) NoSpace(AuxId); + Unsafe(); + nvars++; + if (r) + r->NextVar = q; + else + varchain = q; + strcpy(q->VarName,id); + q->NextVar = NULL; + q->VarValue = p = v1; *v1 = NULL; + q->VarLen = l; + Safe(); + GrowGlobal(1); + return p; +} + + +/* report a syntax error and wind things up (in read) */ + +static +SyntaxError() +{ + char *i; + + rechar = FALSE; retoken = FALSE;; + if (errflg) { + lp = lpmax-2; + return; + } + fprintf(stderr,"\n***Syntax error***\n"); + for (i = line; i <= lpmax; i++) { + if (i == lp) + fprintf(stderr,"\n**here**\n"); + putc(*i,stderr); + } + lp = lpmax-2; errflg = TRUE; +} + + +/* token - tokeniser (in read) */ + +static int +token() +{ + int v, l; + + if (retoken) { + retoken = FALSE; + return tokentype; + } + start: + switch (nextch()) { + case BS: goto start; + + case UC: /* uppercase letter */ + v = lc; goto id; + + case UL: /* underline */ + v = 1; goto id; + case LC: /* lowercase letter */ + v = 0; + id: /* common to both variables and atoms */ + rechar = TRUE; l = 0; + while (nextch() <= N) { + if ((!lc) && (!v) && ch>='A' && ch<='Z') ch += 32; + nam[l++]=ch; + } + nam[l] = 0; + rechar = TRUE; + if (v) { + tokentype = VAR; + tokeninfo.AsPTR = lookupvar(nam); + return VAR; + } + tokentype = NAME; + tokeninfo.AsPTR = lookup(nam); + return NAME; + case N: /* digit */ + if (*(lp+1) == '\'') { + lp++; v = ch-'0'; l = 0; + while (nextch() == N) + l = l*v+ch-'0'; + tokeninfo.AsPTR = ConsInt(l); + rechar = TRUE; + return tokentype = PRIMITIVE; + } + if (!NumberString(&lp,&tokeninfo.AsPTR,TRUE)) + SyntaxError(); + return tokentype = PRIMITIVE; + case QT: /* single quote */ + v = QT; goto quoted; + + case DC: /* double quote */ + v = DC; + quoted: + l = 0; + while (nextch() != v || nextch() == v) { + nam[l++] = ch; + if (l >= 228) SyntaxError(); + } + nam[l] = 0; + rechar = TRUE; + if (v == QT) { + tokentype = NAME; tokeninfo.AsPTR = lookup(nam); + return NAME; + } + tokentype = STRING; tokeninfo.AsString = nam; + return STRING; + + case SY: /* symbol char */ + if (ch =='/' && *(lp+1) == '*') { + do + chtype = nextch(); + while (ch != '*' || *(lp+1) != '/'); + lp++; goto start; + } + l = 1; nam[0] = ch; + if (ch == '.') { /* full stop is a special case */ + if (nextch() == BS ) { + tokentype = FULLSTOP; lp--; + return FULLSTOP; + } + rechar = TRUE; + } + while (nextch() == SY) + nam[l++] = ch; + nam[l] = 0; + rechar = TRUE; + tokentype = NAME; tokeninfo.AsPTR = lookup(nam); + return NAME; + + case SL: /* solo char */ + nam[0] = ch; nam[1] = 0; + tokentype = NAME; tokeninfo.AsPTR = lookup(nam); + return NAME; + + case BK: /* ponctuation char */ + if (ch == '[' && *(lp+1) == ']') { + tokentype = NAME; strcpy(nam,"[]"); lp++; + if (atomnil) + tokeninfo.AsPTR = atomnil; + else tokeninfo.AsPTR = lookup(nam); + return NAME; + } + tokentype = PUNCTUATION; tokeninfo.AsChar = ch; + return PUNCTUATION; + } +} /* end of tokeniser */ + +/* readargs - parse arguments of a term (in read) */ + +static PTR +readargs(atom) +PTR atom; +{ + PTR savelsp, e; int a; + + savelsp = lsp; a = 0; + chtype = nextch(); /* pass over ( */ + do { + *lsp++ = term(999); a++; + } while (token() == PUNCTUATION && tokeninfo.AsChar == ','); + if (tokentype != PUNCTUATION || tokeninfo.AsChar != ')') + SyntaxError(); + e = apply(atom,a,savelsp); + lsp = savelsp; + return e; +} + + +/* stringtolist - string to list of chars (in read) */ + +static PTR +stringtolist() +{ + PTR savelsp; int n; register char c, *l; + + if (nam[0]==0) return atomnil; + savelsp = lsp; + for (l = nam; c = *l; l++) + *lsp++ = ConsInt(c); + n = l-nam; + *lsp = atomnil; lsp = savelsp; + return makelist(n+1,savelsp); +} + +/* readlist - parse a prolog list (in read) */ + +PTR +readlist() +{ + PTR savelsp, e; int n; + + savelsp = lsp; n = 1; + while (TRUE) { + *lsp++ = term(999); n++; + if (token() == PUNCTUATION && tokeninfo.AsChar == ',') { + if (token() == NAME && !strcmp(nam,"..")) { + e = term(999); + break; + } + else retoken = TRUE; + } + else { + if (tokentype == PUNCTUATION && tokeninfo.AsChar == '|') + e = term(999); + else { + e = atomnil; retoken = TRUE; + } + break; + } + } + *lsp = e; lsp = savelsp; + return makelist(n,savelsp); +} + + +/* term - parse token stream to get term (in read) */ + +static PTR +term(n) +int n; +{ + int m, m1, ml, mr; PTR e[2], s; + + if (errflg) return NULL; + m = 0; + switch (token()) { + case NAME: /* a name */ + if (*lp == '(') { + e[0] = readargs(tokeninfo.AsPTR); + break; + } + if (isop(tokeninfo.AsPTR,PREFIX,&m,&ml,&mr)) { + e[0] = s = tokeninfo.AsPTR; + if (token() == PUNCTUATION && + (tokeninfo.AsChar != '(' && + tokeninfo.AsChar != '{' && + tokeninfo.AsChar != '[') + || tokentype == FULLSTOP) { + if (m > n) SyntaxError(); + retoken = TRUE; + break; + } + retoken = TRUE; + e[0] = term(mr); + e[0] = (s == Minus && IsNumber(e[0])) ? + (IsFloat(e[0]) ? ConsFloat(-(XtrFloat(e[0]))) + : ConsInt(-(XtrInt(e[0])))) : + apply(s,1,e); + break; + } + e[0] = tokeninfo.AsPTR; + break; + + case PRIMITIVE: /* a primitive type (already encoded) */ + e[0] = tokeninfo.AsPTR; + break; + + case VAR: /* a variable */ + e[0] = tokeninfo.AsPTR; + break; + + case STRING: /* a string */ + e[0] = stringtolist(); + break; + + case PUNCTUATION: /* ponctuation char */ + if (tokeninfo.AsChar == '(') { + e[0] = term(1200); + if (token() != PUNCTUATION || tokeninfo.AsChar != ')') + SyntaxError(); + break; + } + if (tokeninfo.AsChar == '[') { + e[0] = readlist(); + if (token() != PUNCTUATION || + tokeninfo.AsChar != ']') SyntaxError(); + break; + } + if (tokeninfo.AsChar == '{') { + e[0] = term(1200); + if (token() != PUNCTUATION || tokeninfo.AsChar != '}') + SyntaxError(); + e[0] = apply(assertatom,1,e); + break; + } + + case FULLSTOP: /* other poctuation chars or fullstop */ + SyntaxError(); return NULL; + + } + on: + if (errflg) return NULL; + if (token() == NAME) { + if (isop(tokeninfo.AsPTR,INFIX,&m1,&ml,&mr)) { + if (m1 <= n && ml >= m) { + s = tokeninfo.AsPTR; + e[1] = term(mr); + e[0] = apply(s,2,e); + m = m1; + goto on; + } + } + if (isop(tokeninfo.AsPTR,POSTFIX,&m1,&ml,&mr)) { + if (m1 <= n && ml >= m) { + s = tokeninfo.AsPTR; + e[0] = apply(s,1,e); + m = m1; + goto on; + } + } + retoken = TRUE; + return e[0]; + } + + if (tokentype == FULLSTOP) { + retoken = TRUE; + return e[0]; + } + if (tokentype != PUNCTUATION || + tokeninfo.AsChar == '(' || tokeninfo.AsChar == '[') { + SyntaxError(); + return NULL; + } + if (tokeninfo.AsChar == ',' && n >= 1000 && m <= 999) { + e[1] = term(1000); + e[0] = apply(commafunc,2,e); + m = 1000; + if (m < n) goto on; + return e[0]; + } + retoken = TRUE; + return e[0]; + +} /* end of term */ + + +/* the read predicate */ + +PTR +pread() +{ + varchain = NULL; errflg = FALSE; nvars = 0; + lpmax = line = CharP(lsp); + slsp = lsp; + + loop: + ch = Get(); + l1: + chtype = chtyp[ch]; + if (chtype == BS) { + do ch = Get(); while(chtyp[ch] == BS); + *lpmax++ = ' '; + goto l1; + } + if (ch == '%') { + ch = Get(); + if (ch == '(') { + ch = '{'; goto l1; + } + if (ch == ')') { + ch = '}'; goto l1; + } + while (ch != '\n') ch = Get(); + goto loop; + } + *lpmax++ = ch; + if (chtype == QT && lpmax-line > 1 && chtyp[*(lpmax-2)] == N) + chtype = N; + if (ch == '*' && lpmax-line > 1 && *(lpmax-2) == '/') { + lpmax -= 2; + ch = Get(); + do { + while (ch != '*') ch = Get(); + ch = Get(); + while (ch == '*') ch = Get(); + } while (ch != '/'); + goto loop; + } + if ((CharP(vmax)) < lpmax) { + fprintf(stderr, + "! Term too long to read (%d characters)\n",lpmax-CharP(lsp)); + Event(ABORT); + } + if (chtype == QT || chtype == DC) { + do { + ch = Get(); *lpmax++ = ch; + } while(chtyp[ch] != chtype); + goto loop; + } + if (ch == '.' && lpmax-line >= 2 && chtyp[*(lpmax-2)] != SY) { + ch = Get(); + if (chtyp[ch] == BS) goto end; else goto l1; + } + goto loop; + + end: + *lpmax = '\n'; *(lpmax+1) = 0; + lp = line-1; + rechar = retoken = FALSE; + lsp += Words(lpmax-line+1); + e = term(1200); + if (token() != FULLSTOP) SyntaxError(); + if (errflg) e = NULL; +/* for (lp = line; lp <= lpmax; lp++) putchar(*lp); */ + lsp = slsp; + return e; +} + +int +NumberString(s,p,free) +/* Scans the string *s to see if it is a number. If yes, *p takes + the constructed number, and TRUE is returned, otherwise FALSE. + If free is FALSE, the number must reach the end of the string + to be accepted. In all cases, *s is updated to point to the + last character used for the number (oddity courtesy of nextch()) +*/ + +char **s; PTR *p; int free; +{ + double d; int i; char *t, *u, c; + + u = t = *s; + if (*t == '-' || *t == '+') t++; + if (!digits(&t)) goto no; + if (*t == '.') { + t++; + if (!digits(&t)) { + t--; + goto stop; + } + } + if (!*t) goto yes; + if (*t != 'e' && *t != 'E') goto stop; + if (*++t == '-' || *t == '+') t++; + if (!digits(&t)) goto no; + yes: + *s = t-1; + c = *t; + *t = ' '; + sscanf(u,"%F",&d); + *t = c; + if (Narrow(d,&i)) + *p = ConsInt(i); + else + *p = ConsFloat(d); + return TRUE; + stop: + if (free || !*t) goto yes; + no: + *s = t-1; + return FALSE; +} + +static +digits(s) +char **s; +{ + char *t; + + t = *s; + if (chtyp[*t] != N) return FALSE; + while (chtyp[*++t] == N); + *s = t; + return TRUE; +} diff --git a/source_code/c-prolog-1982/rewrite.o b/source_code/c-prolog-1982/rewrite.o new file mode 100755 index 0000000..cbb3098 Binary files /dev/null and b/source_code/c-prolog-1982/rewrite.o differ diff --git a/source_code/c-prolog-1982/space.c b/source_code/c-prolog-1982/space.c new file mode 100755 index 0000000..d616b88 --- /dev/null +++ b/source_code/c-prolog-1982/space.c @@ -0,0 +1,405 @@ +/* C Prolog space.c */ + +#include "pl.h" + +#ifdef ERRCHECK +int ReleaseCheck = TRUE; +#endif + +#define CHAINS 16 +#define BUCKET_SIZE 1024 + +typedef struct BLOCK +{ + struct BLOCK *NextBlock; + int BlockSize; +} Block, *BlockP; + +typedef struct +{ + BlockP FirstBlock, LastBlock; +} GCPair, *GCPairP; + +#define MIN_SIZE sizeof(Block)/sizeof(PTR) + +struct { + BlockP free[CHAINS+1]; + PTR top, bottom; + int used, maxused; +} Heap; + +int HeapHeader = sizeof(Heap); + +static int size; +static GCPairP Garbage; +static int Buckets; + +#define FreeChain Heap.free +#define Top Heap.top +#define Bottom Heap.bottom + +#define FreeMisc FreeChain[CHAINS] + +ClearMem(loc,num) +char *loc; +{ +#ifdef vax +#ifdef unix + asm(" movc5 $0,*4(ap),$0,8(ap),*4(ap) "); +#else + register char *l = loc; + register int n = num; + + while (n-- > 0) *l++ = NULL; +#endif +#else + register char *l = loc; + register int n = num; + + while (n-- > 0) *l++ = NULL; +#endif +} + +CopyMem(from,to,cc) +char *from, *to; +{ +#ifdef vax +#ifdef unix + asm(" movc3 12(ap),*4(ap),*8(ap) "); +#else + register char *f = from, *t = to; + register int n = cc; + + if (f < t) { + f += n; + t += n; + while (n-- > 0) *--t = *--f; + } + else while (n-- > 0) *t++ = *f++; +#endif +#else + register char *f = from, *t = to; + register int n = cc; + + if (f < t) { + f += n; + t += n; + while (n-- > 0) *--t = *--f; + } + else while (n-- > 0) *t++ = *f++; +#endif +} + +#define WDPtr(c) ((PTR)(c)) + +InitHeap() +/* Initialize space tables. Do it only once */ +{ + Top = Bottom = skel0; + ClearMem(FreeChain,(CHAINS+1)*sizeof(PTR)); + Heap.used = Heap.maxused = 0; +} + +#ifdef ERRCHECK + +#define NOOVERLAP 0 +#define SAME 1 +#define OVERLAP 2 + +static +overlap(a,b) +PTR a, b; +/* Check for overlap of space in error checking version */ +{ + register BlockP n; int i; + + for (i = CHAINS; i >= 0; i--) { + for (n = FreeChain[i]; n; n = n->NextBlock) { + if (b < (PTR)n) + continue; + if (a >= ((PTR)n)+n->BlockSize) + continue; + if (a == (PTR)n) + return SAME; + return OVERLAP; + } + } + return NOOVERLAP; +} + +check_free() +{ + int i; BlockP b, a; + for (i = 0; i <= CHAINS; i++) { + a = &FreeChain[i]; + for (b = a->NextBlock; b; a = b, b = a->NextBlock) + if (b < Bottom || b > Top) { + fprintf(stderr,"Invalid block %d: %x\n",i,a); + abort(); + } + } +} + +#endif + +PTR +freeblock(base,size) +BlockP base; int size; +{ + BlockP *list; +#ifdef ERRCHECK + if (ReleaseCheck) { + if (size < MIN_SIZE) { + fprintf(stderr,"%s\n","size < MIN_SIZE"); + abort(); + } + else if (base < Bottom || WDPtr(base)+size > Top) { + fprintf(stderr,"%s\n","out of bounds"); + abort(); + } + else + switch(overlap((PTR)base,((PTR)base)+size-1)) { + case NOOVERLAP: + break; + case SAME: + fprintf(stderr,"%s\n","space freed twice"); + abort(); + case OVERLAP: + fprintf(stderr,"%s\n","space overlap"); + abort(); + } + } +#endif + list = (size < CHAINS+MIN_SIZE) ? &FreeChain[size-MIN_SIZE] : &FreeMisc; + Unsafe(); + base->NextBlock = *list; + base->BlockSize = size; + *list = base; + Heap.used -= size; + Safe(); +#ifdef ERRCHECK + check_free(); +#endif +} + +static PTR +GetExact() +/* Get exact fit from specified list */ +{ + register BlockP b; + + if (!(b = FreeChain[size-MIN_SIZE])) + return NULL; + FreeChain[size-MIN_SIZE] = b->NextBlock; + Heap.used += size; + if (Heap.used > Heap.maxused) Heap.maxused = Heap.used; + return WDPtr(b); +} + +static PTR +GetMixed() +/* Get first fit from misc list */ +{ + register BlockP *l, n; + + l = &FreeMisc; + while (n = *l) { + if (n->BlockSize == size) { + *l = n->NextBlock; + Heap.used += size; + if (Heap.used > Heap.maxused) Heap.maxused = Heap.used; + return WDPtr(n); + } + else if (n->BlockSize >= size+MIN_SIZE) { + *l = n->NextBlock; + Heap.used += n->BlockSize; + freeblock(WDPtr(n)+size,n->BlockSize-size); + if (Heap.used > Heap.maxused) Heap.maxused = Heap.used; + return WDPtr(n); + } else { + l = &(n->NextBlock); + } + } + return NULL; +} + +static PTR +GetTop() +/* Get space from top of table */ +{ + PTR s; + + s = Top; + if (s+size > hpmax) + return NULL; + else { + Top += size; + Heap.used += size; + if (Heap.used > Heap.maxused) Heap.maxused = Heap.used; + return s; + } +} + +#define try(rtn) if (x = rtn()); + +PTR +getsp(sz) +/* allocate space of size sz */ +{ + PTR x; int gc = 0; + + if (sz < MIN_SIZE) { + fprintf(stderr,"! Internal error: heap request too small"); + Stop(TRUE); + } + Unsafe(); + while (gc < 2) { + size = sz; + if (size < CHAINS+MIN_SIZE) { + try(GetExact) else + try(GetTop) else + try(GetMixed); + } + else { + try(GetMixed) else + try(GetTop); + } + Safe(); + if (x) { + ClearMem(x,size*sizeof(PTR)); +#ifdef ERRCHECK + check_free(); +#endif + return x; + } else { + CollectGarbage(); + gc++; + } + } + Safe(); + NoSpace(HeapId); +} + +static +SortGarbage() +/* Sort all free lists onto Garbage by address */ +{ + register BlockP c, *p, q; register GCPairP s; int i; + + for (i = CHAINS; i >= 0; i--) + while (c = FreeChain[i]) { + FreeChain[i] = c->NextBlock; + s = &Garbage[(WDPtr(c)-Bottom)/BUCKET_SIZE]; + p = &(s->FirstBlock); + for (q = *p; q && q < c; q = *p) + p = &(q->NextBlock); + if (!q) s->LastBlock = c; + c->NextBlock = q; + *p = c; + Heap.used += c->BlockSize; + if (Heap.used > Heap.maxused) Heap.maxused = Heap.used; + } +} + +static +MergeGarbage() +/* Merge adjacent pieces of space on the sorted list Garbage */ +{ + register BlockP c, p; int i; + + for(i = Buckets-1; i >= 0; i--) + if (!(Garbage[i].FirstBlock)) { + Garbage[i] = Garbage[i+1]; + Garbage[i+1].FirstBlock = Garbage[i+1].LastBlock = NULL; + } + else if (Garbage[i+1].FirstBlock) { + Garbage[i].LastBlock->NextBlock = Garbage[i+1].FirstBlock; + Garbage[i+1].FirstBlock = Garbage[i+1].LastBlock = NULL; + } + p = Garbage[0].FirstBlock; + while (p) + if ((BlockP)(WDPtr(p)+(p->BlockSize)) != p->NextBlock) + p = p->NextBlock; + else { + c = p->NextBlock; + p->BlockSize += c->BlockSize; + p->NextBlock = c->NextBlock; + } +} + +static +RelGarbage() +/* Release all items on the merged, sorted list Garbage */ +{ + register BlockP c, p; +#ifdef ERRCHECK + int t = ReleaseCheck; + + ReleaseCheck = FALSE; +#endif + p = Garbage[0].FirstBlock; + while (p) { + c = p->NextBlock; + if (!c && WDPtr(p)+(p->BlockSize) == Top) { + Top = WDPtr(p); + Heap.used -= p->BlockSize; + } + freeblock(p,p->BlockSize); + p = c; + } +#ifdef ERRCHECK + ReleaseCheck = t; +#endif +} + +CollectGarbage() +/* The garbage collection driver */ +{ + int i; + + Buckets = (Top-Bottom)/BUCKET_SIZE; + if ((Top-Bottom)%BUCKET_SIZE) Buckets++; + Garbage = (GCPairP)(vrz ? vrz : auxstk0); + if (Garbage+Buckets+1 > auxmax) + return; + for (i = 0; i <= Buckets; i++) + Garbage[i].FirstBlock = Garbage[i].LastBlock = NULL; + SortGarbage(); + MergeGarbage(); + RelGarbage(); +} + +RelocHeap(delta) +int delta; +/* Relocates the free space chains, where the actual free space + has already been moved. +*/ +{ + int i; PTR p; + + for (i = 0; i <= CHAINS; i++) { + p = WDPtr(&FreeChain[i]); + while (*p) + p = WDPtr(&(((BlockP)(*p += delta))->NextBlock)); + } + Top += delta; + Bottom += delta; +} + +int +HeapUsed() +{ + return Heap.used*sizeof(PTR); +} + +int HeapTide() +{ + return Heap.maxused*sizeof(PTR); +} + +PTR +HeapTop() +{ + return Heap.top; +} + diff --git a/source_code/c-prolog-1982/space.o b/source_code/c-prolog-1982/space.o new file mode 100755 index 0000000..695138e Binary files /dev/null and b/source_code/c-prolog-1982/space.o differ diff --git a/source_code/c-prolog-1982/startup b/source_code/c-prolog-1982/startup new file mode 100755 index 0000000..5f7b541 Binary files /dev/null and b/source_code/c-prolog-1982/startup differ diff --git a/source_code/c-prolog-1982/sysbits.c b/source_code/c-prolog-1982/sysbits.c new file mode 100755 index 0000000..1fb1596 --- /dev/null +++ b/source_code/c-prolog-1982/sysbits.c @@ -0,0 +1,650 @@ +/********************************************************************** +* * +* C Prolog sysbits.c * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ + +/* + Interface with Unix -- apart from trivial STDIO calls, other + modules do not call Unix directly. +*/ + +#include "pl.h" +#include +#include +#include + +#ifdef vms +# include +# include "times.h" + +# define TIMESCALE (0.001) /* 10 msec. per times() unit in VMS */ + +#else +# include +# include +/* # include */ +# define HZ 60 + +# define TIMESCALE (1.0/HZ) /* times() units in 1/HZ sec. */ + +#endif + +#ifdef vms + +# include stdio +# include ssdef +# include descrip + +# define AsDEC10 + +#endif + +#define READ 1 +#define WRITE 2 +#define DIR 3 +#define PROT 4 +#define LOCK 8 +#define FREE 0 + +#define PromptSize 81 + +#define MaxFile 15 +#define NSigs 16 + +#define SAFE 0 +#define UNSAFE 1 +#define ABORTED 2 + +#ifdef AsDEC10 + +/* end of file character -- ^Z to simulate DEC-10 Prolog */ + +#define PlEOF '\032' + +#else + +/* -1 to be like STDIO */ + +#define PlEOF (-1) + +#endif + +char PlPrompt[PromptSize]; +static int NewLine, crit; +static int (*OldSignal[NSigs])(); + +typedef struct { jmp_buf buf; } JumpBuf; + +JumpBuf ZeroState; + +extern int sys_nerr, PrologEvent; +extern char *sys_errlist[]; + +/* stream information */ + +FILE *File[MaxFile]; +PTR FileAtom[MaxFile]; +int FileStatus[MaxFile]; + +int Input, Output; /* current I/O streams */ + +char OutBuf[256]; /* general purpose buffer */ + +InitIO() +{ + int i; + + for (i = 0; i < MaxFile; i++) { + File[i] = NULL; + FileAtom[i] = NULL; + FileStatus[i] = FREE; + } + File[STDIN] = stdin; + File[STDOUT] = stdout; + File[STDERR] = stderr; + FileStatus[STDIN] = READ|PROT; + FileStatus[STDOUT] = WRITE|PROT; + FileStatus[STDERR] = WRITE|PROT; + FileAtom[STDIN] = FileAtom[STDOUT] = user; + Input = STDIN; Output = STDOUT; + NewLine = FALSE; +} + +char * +AtomToFile(file) +PTR file; +{ + if (IsntName(file) || IsComp(file)) + IODie("Invalid file specification"); + return AtomP(file)->stofae; +} + +int +See(file) +PTR file; +{ + int i; + + if (file == user) + return Input = STDIN; + for (i = 0; i < MaxFile; i++) + if (FileAtom[i] == file) break; + if (i >= MaxFile) { /* not already open */ + i = CSee(AtomToFile(file)); + FileAtom[i] = file; + } + else if ((FileStatus[i]&DIR) != READ) {/* open but not right */ + if (i == Output) + Told(); + else + CClose(i); + i = CSee(AtomToFile(file)); + FileAtom[i] = file; + } else Input = i; + return i; +} + +int +Tell(file,mode) +PTR file; char *mode; +{ + int i; + + if (file == user) + return Output = STDOUT; + for (i = 0; i < MaxFile; i++) + if (FileAtom[i] == file) break; + if (i >= MaxFile) { /* not already open */ + i = CTell(AtomToFile(file),mode); + FileAtom[i] = file; + } + else if ((FileStatus[i]&DIR) != WRITE) { /* open but not right */ + if (i == Input) + Seen(); + else + CClose(i); + i = CTell(AtomToFile(file),mode); + FileAtom[i] = file; + } else Output = i; + return i; +} + +int +CSee(s) +char *s; +{ + return Input = COpen(s,"r",READ); +} + +int +CTell(s, mode) +char *s, *mode; +{ + return Output = COpen(s,mode,WRITE); +} + +static int +COpen(s,m,st) +char *s, *m; int st; +{ + int i; + + for (i = 0; i < MaxFile; i++) + if (FileStatus[i] == FREE) break; + if (i >= MaxFile) + IODie("Too many open files"); + if (!(File[i] = fopen(s,m))) + IOError(); + FileStatus[i] = st; + return i; +} + +Seen() +{ + int inp; + + CClose(Input); + Input = STDIN; +} + +Told() +{ + if (Output == STDOUT || Output == STDERR) return; + CClose(Output); + Output = STDOUT; +} + +PClose(file) +PTR file; +{ + int i; + + if (file == user) return; + for (i = 0; i < MaxFile; i++) + if (FileAtom[i] == file) { + CClose(i); + if (Input == i) + Input = STDIN; + else if (Output == i) + Output = STDOUT; + break; + } +} + +CloseFiles() +{ +int i; + + for (i = 0; i < MaxFile; i++) + if (!(FileStatus[i]&PROT) && (FileStatus[i]&DIR)) { + CClose(i); + if (Input == i) + Input = STDIN; + else if (Output == i) + Output = STDOUT; + } +} + +static +CClose(i) +int i; +{ + if (!(FileStatus[i]&PROT)) { + fclose(File[i]); + FileStatus[i] = FREE; + File[i] = NULL; + FileAtom[i] = NULL; + } else clearerr(File[i]); +} + +PTR +Seeing() +{ + return FileAtom[Input]; +} + +PTR +Telling() +{ + return FileAtom[Output]; +} + +SetPlPrompt(s) +char *s; +{ + if (s) strncpy(PlPrompt,s,PromptSize-1); + PlPrompt[PromptSize-1] = 0; +} + +Put(c) +char c; +{ + if (Output == STDOUT) NewLine = (c == '\n'); + putc(c,File[Output]); +} + +PutString(s) +char *s; +{ + register char c; + + while (c = *s++) Put(c); +} + +char +Get() +{ +int c; + + if (feof(File[Input])) { + Seen(); + Event(END_OF_FILE); +} + if (NewLine) + PromptIfUser(PlPrompt); + c = getc(File[Input]); + if (c == EOF) c = PlEOF; + else if (Input == STDIN) NewLine = (c == '\n'); + return c; +} + +Prompt(s) +char *s; +{ + fputs(s,stdout); + fflush(stdout); + NewLine = FALSE; +} + +PromptIfUser(s) +char *s; +{ + if (Input == STDIN) + Prompt(s); +} + +char +ToEOL(reply,count) +register char *reply; int count; +{ + char c0, c; + + while ((c0 = getchar()) <= ' ' && c0 != '\n'); + c = c0; + while (c0 != '\n') { + c0 = getchar(); + if (reply && --count>0) *reply++ = c0; + } + if (reply) *reply = '\0'; + if (c >= 'A' && c <= 'Z') c += 'a'-'A'; + return c; +} + +Exists(s) +char *s; +{ + return (access(s,0) == 0); +} + +Rename(f1,f2) +char *f1, *f2; +{ +int r; +#ifdef unix + if ((r = link(f1,f2)) == 0) { + if ((r = unlink(f1)) != 0) + unlink(f2); + } +#endif +#ifdef vms + fprintf(stderr,"! Rename not supported in this version of CProlog\n"); + r = -1; +#endif + if (r) IOError(); +} + +Remove(f) +char *f; +{ +#ifdef unix + if (unlink(f) != 0) + IOError(); +#endif +#ifdef vms + if (delete(f) !=0) + IOError(); +#endif +} + +/* create stacks */ + +CreateStacks() +{ + char *r; + int i, s = 0; + + for (i = 0; i < NAreas; i++) + s += Size[i]; + if ((r = malloc(s)) == NULL) { + perror("Prolog"); + exit(BAD_EXIT); + } + for (i = 0; i < NAreas; i++) { + Origin[i] = (PTR)r; + r += Size[i]; + } + Origin[NAreas] = r; + atmax = auxstk0-100; + auxmax = trbase-1; + trmax = skel0-1; + hpmax = glb0-100; + v1max = lcl0-500; + vmax = ((PTR)r)-500; +} + +/* Signals and events */ + +Event(n) +int n; +{ + if (State[TRACE]) + fprintf(stderr,"\n Prolog event %d\n",n); + if (!running) { + if (errno) + perror("Prolog"); + fputs("\nError while starting up Prolog -- cannot continue\n",stderr); + exit(BAD_EXIT); + } + if (crit != SAFE) { + fprintf(stderr,"%s\n",OutBuf); + fputs("\nCan't recover from this error - bye\n",stderr); + Stop(State[DEBUG]); + } + PrologEvent = n; + Unwind(); +} + +/* Signals */ + +TakeSignal(s) +int s; +{ + if (State[TRACE]) + fprintf(stderr,"\nSignal %d\n"); + switch (s) { + case SIGINT: + Interrupt(); + break; + case SIGQUIT: + Stop(FALSE); + case SIGFPE: + signal(SIGFPE,TakeSignal); + ArithError("Floating point exception"); + case SIGSEGV: + NoSpace(-1); + default: + fprintf(stderr,"\nUnexpected signal: %d\n",s); + Stop(TRUE); + } +} + +Stop(dump) +int dump; +{ + if (dump || State[DEBUG]) { + fputs("\nDisaster! Dumping core...\n",stderr); + abort(); + } + exit(GOOD_EXIT); +} + +Safe() +{ + if (crit == ABORTED) { + crit = SAFE; + Event(ABORT); + } + crit = SAFE; +} + + +Unsafe() +{ + crit = UNSAFE; +} + +Interrupt() +{ + while (TRUE) { + Prompt("Action (h for help): "); + switch(ToEOL(0,0)) { + case 'a': + if (crit == SAFE) + Event(ABORT); + crit = ABORTED; + goto cont; + case 't': + debug = TRUE; + sklev = 1000000; + goto cont; + case 'd': + debug = TRUE; + goto cont; + case 'h': + puts("a\tabort\nc\tcontinue\nd\tdebug\nt\ttrace\n"); + break; + case 'c': + goto cont; + default: + puts("Unknown option\n"); + } + } + cont: + signal(SIGINT,TakeSignal); +} + +PTR +NoSpace(s) +int s; +{ + char *n; + + n = (s >= 0 && s < NAreas) ? AreaName[s] : "?"; + sprintf(OutBuf,"\n! Out of %s during execution\n",AreaName[s]); + ErrorMess = OutBuf; + Event(GEN_ERROR); + return NULL; +} + + +CatchSignals() +{ + signal(SIGINT,TakeSignal); + signal(SIGFPE,TakeSignal); +/* signal(SIGSEGV,TakeSignal); + signal(SIGBUS,TakeSignal); */ +} + +/* Emergency exit */ + +Unwind() +{ + longjmp(ZeroState.buf,1); +} + +/* Errors */ + +static IOError() +{ + IODie(SysError()); +} + +static +IODie(s) +char *s; +{ + ErrorMess = s; + Event(IO_ERROR); +} + +char * +SysError() +{ + return errno < sys_nerr ? sys_errlist[errno] : "Unknown Unix error"; +} + +int +Sh() +{ +#ifndef vms + char *shell; int p; + if (!(shell=getenv("SHELL"))) + shell = "/bin/sh"; + if ((p=fork())==0) { + if (execl(shell,shell,0)<0) + return FALSE; + } else if (p<0) return FALSE; + wait(0); + return TRUE; +#else + return lib$spawn(); +#endif +} + +int +CallSystem(cmd) +PTR cmd; +{ + char command[256]; +#ifdef vms + struct dsc$descriptor_s s_d; +#endif + + if (!list_to_string(cmd,command,255)) + return FALSE; +#ifdef unix + return !system(command); +#else +#ifdef vms + s_d.dsc$w_length = strlen(command); + s_d.dsc$b_dtype = DSC$K_DTYPE_T; + s_d.dsc$b_class = DSC$K_CLASS_S; + s_d.dsc$a_pointer = command; + return lib$spawn(&s_d); +#endif +#endif +} + +suspend() +{ + signal(SIGINT,SIG_DFL); + kill(0,SIGINT); + signal(SIGINT,TakeSignal); +} + +float +CPUTime() +{ + struct tms Time; float t; + + times(&Time); + t = Time.tms_utime; + return t*TIMESCALE; +} + +int +SaveStream(stream) +int stream; +{ + int oldstate; + + if (!((oldstate = FileStatus[stream])&PROT)) + FileStatus[stream] |= PROT|LOCK; + return oldstate; +} + +RestStream(stream,oldstate) +int stream, oldstate; +{ + FileStatus[stream] = oldstate; +} + +ResetStreams() +{ + register int stream; + + for (stream = 0; stream < MaxFile; stream++) + if (FileStatus[stream]&LOCK) + FileStatus[stream] &= ~(LOCK|PROT); +} diff --git a/source_code/c-prolog-1982/sysbits.o b/source_code/c-prolog-1982/sysbits.o new file mode 100755 index 0000000..e45e9e2 Binary files /dev/null and b/source_code/c-prolog-1982/sysbits.o differ diff --git a/source_code/c-prolog-1982/trace.c b/source_code/c-prolog-1982/trace.c new file mode 100755 index 0000000..13bfefd --- /dev/null +++ b/source_code/c-prolog-1982/trace.c @@ -0,0 +1,275 @@ +#include "pl.h" +#include "trace.h" + +static char *portname[] = { + "Call: ", "Exit: ", "Back to: ", "Fail: " +}; + +int trace(frame,goal,goalenv,info,port) +PTR frame, goal, goalenv; unsigned info; int port; +{ + PTR realx = x, realx1 = x1, target; + char flags, arg[10]; + int level, telling, iarg; + + level = Level(info); + x = goalenv; + x1 = X->gsofcf; + if (IsRef(goal)) + x1 = MolP(goal)->Env, goal = MolP(goal)->Sk; + flags = FunctorP(SkelP(goal)->Fn)->flgsoffe; + if (port == CALL_PORT) { + if (dotrace) { + dotrace = FALSE; + sklev = NEVER_SKIP; + } + FrameP(frame)->infofcf = info; + } + if ((level > sklev-(port==BACK_PORT) && !(spy && (flags&SPY_ME))) || + (flags&(INVISIBLE|UNTRACEABLE))) { + x = realx; x1 = realx1; + return NORMAL; + } + message: + if (flags&SPY_ME) putchar('*'); else putchar(' '); + if (level == sklev) putchar('>'); else putchar(' '); + printf(" (%d) %d %s",InvNo(info),level,portname[port-1]); + telling = Output; + Output = STDOUT; + pwrite(goal,x1,999); + if (!(leash&(1<<(4-port)))) { + Put('\n'); + Output = telling; + x = realx; x1 = realx1; + return NORMAL; + } else PutString(" ? "); + Output = telling; + switch (ToEOL(arg,10)) { + case '\n': + case 'c': /* creep */ + sklev = NEVER_SKIP; spy = FALSE; + break; + case 'l': /* leap */ + sklev = 0; spy = TRUE; + break; + case 's': /* skip */ + if (port == EXIT_PORT || port == FAIL_PORT) goto notapp; + sklev = level; spy = FALSE; + break; + case 'q': /* quasi-skip */ + if (port == EXIT_PORT || port == FAIL_PORT) goto notapp; + sklev = level; spy = TRUE; + break; + case 'r': /* retry */ + spy = FALSE; sklev = NEVER_SKIP; + if (sscanf(arg,"%d",&iarg) == 1 + && iarg != InvNo(info) + && (target = findinv(iarg,frame,vv)) != frame) { + fprintf(stderr,"[** JUMP **]\n"); + failto(target); /* long retry */ + } else { + fprintf(stderr,"[ retry ]\n"); + if (port != EXIT_PORT) { + x = realx; + x1 = realx1; + lev = level; + invokno = InvNo(info); + if (port == BACK_PORT) + vv = VV->lcpofcf; /* this is essential !!! */ + } else failto(frame); /* fail to frame */ + } + invokno--; /* the Call port increments this again */ + return ICALL; + case 'f': /* fail */ + if (port == FAIL_PORT) goto notapp; + x = realx; + x1 = realx1; + lev = level; + invokno = InvNo(info); + if (port == EXIT_PORT) failto(frame); + else if (port == BACK_PORT) vv = VV->lcpofcf; /* essential */ + spy = FALSE; sklev = NEVER_SKIP; + return EFAIL; + case 'a': /* abort */ + return ABORTING; + case 'b': /* break */ + x = realx; + x1 = realx1; + breakret = port; bg = breakat; + return BREAK; + case '[': /* consult user */ + x = realx; + x1 = realx1; + breakret = port; ConsMol(CsltUser,x1,bg); + return BREAK; + case 'g': /* backtrace */ + backtrace(x); + goto message; + case 'e': + suspend(); + goto message; + default: + printf("Unknown option; these are the known ones: "); + case 'h': + puts("\ +\n creep a abort\ +\nc creep f fail\ +\nr retry r retry call \ +\nl leap b break\ +\ns skip h help\ +\nq quasi-skip n nodebug\ +\ng goal stack [ consult user\ +\ne exit Prolog\n"); + goto message; + case 'n': /* turn debug mode off */ + debug = FALSE; + break; + } + x1 = realx1; x = realx; + return NORMAL; + + notapp: + printf("Option not applicable at this port\n"); + goto message; +} + +int +clausenumber(fr) +PTR fr; +{ + PTR g, cp, np, onp, fp; int pos = 1; + + g = FrameP(fr)->gofcf; + if (!IsInp(g)) g = MolP(g)->Sk; + cp = FunctorP(SkelP(g)->Fn)->defsoffe; + fp = fr->altofcf; onp = NULL; + for (;(np = Addr(ClauseP(cp)->altofcl)) != fp; cp = *np) { + if (!*np) return 0; + if (onp == np) return 0; + onp = np; + if (!Erased(cp)) pos++; + } + return pos; +} + +backtrace(fr) +PTR fr; +{ PTR ofr, frg, fre, out, oldx; unsigned info; int clno; + + oldx = x; ofr = NULL; + out = Output; Output = STDOUT; + for (; fr != ofr; fr = x) { + ofr = fr; + x = fr->gfofcf; + info = fr->infofcf; + if (info== (PRIM_TAG|NUM_TAG)) continue; + frg = fr->gofcf; + if (IsInp(frg)) + fre = x->gsofcf; + else { + fre = MolP(frg)->Env; frg = MolP(frg)->Sk; + } + printf("%4d (%d)->",Level(info),InvNo(info)); + clno = clausenumber(fr); + if (clno) + printf("%d: ",clno); + else + printf("?: "); + pwrite(frg,fre,999); + printf("\n"); + } + x = oldx; + Output = out; +} + +/* scanstack(frame,choice,fun,all) scans stack frames backwards from frame + and last choice point choice calling fun with each as an argument until + fun returns TRUE or the stack for the current execution is exhausted. + If all is true, the entire stack is scanned; otherwise, only the stack + since the last breakpoint. + Return the last frame scanned or 0 if stack exhausted. +*/ + +PTR +scanstack(frame,choice,fun,all) +FRAME *frame, *choice; int (*fun)(); +{ + register FRAME *alt, *par; int result; + + par = frame; + alt = choice; + while ((alt != FrameP(alt->lcpofcf)) && + (all || (PTR)alt > brkp)) { + while (par > alt) { + if ((*fun)(par)) return (PTR)par; + par = FrameP(par->gfofcf); + } + if((*fun)(alt)) return (PTR)alt; + par = FrameP(alt->gfofcf); + alt = FrameP(alt->lcpofcf); + } + return (PTR)0; +} + +/* findinv(invno,frame,choice) finds the most recent user frame with + invocation number =< invno in the current execution (that is, it + does not search past break points). If no such frame is found, + findinv returns the oldest user frame in the execution. +*/ + +static PTR theframe; +static int target; + +static +invoked(frame) +FRAME *frame; +{ + unsigned int info = frame->infofcf; int frameno; + + if (SysFrame(info)) return FALSE; + theframe = frame; + frameno = InvNo(info); /* helps debugging */ + return frameno <= target; +} + +PTR +findinv(invno,frame,choice) +int invno; FRAME *frame, *choice; +{ + PTR found; + + target = invno; + theframe = frame; + found = scanstack(frame,choice,invoked,FALSE); + return (found ? found : theframe); +} + +/* failto(frame) simulates a failure back to frame. */ + +static failto(frame) +PTR frame; +{ register PTR p; register char *flagp; unsigned info; + + v = frame; + x = V->gfofcf; + v1 = V->gsofcf; + x1 = X->gsofcf; + vv = V->lcpofcf; + vv1 = VV->gsofcf; + pg = V->gofcf; + c = V->cofcf; + info = V->infofcf; + lev = Level(info); + invokno = InvNo(info); + execsys = SysFrame(info); + tr0 = V->trofcf; + while (tr != tr0) { + p = *--tr; + if (IsRef(p)) *p = NULL; + else { + flagp = &(ClauseP(XtrDBRef(p))->infofcl); + if (!((*flagp)&ERASED)) *flagp &= ~IN_USE; + else hide(p); + } + } +} diff --git a/source_code/c-prolog-1982/trace.h b/source_code/c-prolog-1982/trace.h new file mode 100755 index 0000000..0d33412 --- /dev/null +++ b/source_code/c-prolog-1982/trace.h @@ -0,0 +1,26 @@ +#define NEVER_SKIP 1000000 + +#define CONT 0 +#define CALL_PORT 1 +#define EXIT_PORT 2 +#define BACK_PORT 3 +#define FAIL_PORT 4 + +#define NORMAL 0 +#define EFAIL 1 +#define ICALL 2 +#define ABORTING 3 +#define BREAK 4 +#define Trace(when,frame,goal,goalenv,info,port) if (when) { \ + switch (trace(frame,goal,goalenv,info,port)) { \ + case EFAIL: goto efail; \ + case ICALL: goto icall; \ + case ABORTING: goto aborting; \ + case BREAK: goto enterbreak; \ + case NORMAL: break; \ + } \ + } + +extern int debug, lev, sklev, invokno, + spy, leash, dotrace, breakret, execsys; +extern PTR pg, bg, c; diff --git a/source_code/c-prolog-1982/trace.o b/source_code/c-prolog-1982/trace.o new file mode 100755 index 0000000..261ddc6 Binary files /dev/null and b/source_code/c-prolog-1982/trace.o differ diff --git a/source_code/c-prolog-1982/unify.c b/source_code/c-prolog-1982/unify.c new file mode 100755 index 0000000..028ffad --- /dev/null +++ b/source_code/c-prolog-1982/unify.c @@ -0,0 +1,341 @@ +/********************************************************************** +* * +* C Prolog unify.c * +* ======== * +* * +* By Fernando Pereira, July 1982. * +* EdCAAD, Dept. of Architecture, University of Edinburgh. * +* * +* Based on the Prolog system written in IMP by Luis Damas * +* for ICL 2900 computers, with some contributions by * +* Lawrence Byrd. * +* * +* Copyright (C) 1982 Fernando Pereira, Luis Damas and Lawrence Byrd * +* * +**********************************************************************/ + +#include "pl.h" + +int +gunify(ta, ga, tb, gb) + PTR ta, + ga, + tb, + gb; +{ +/* Unifies term t1 with global frame g1 and local frame v + with term t2 with global frame g2 and local frame x + result is TRUE if unification succeeds and FALSE otherwise. +*/ + + int arity; + PTR a, + b, + pa, + pb; + +/* check same functor */ +start: + if (*tb != (a = *ta)) + return FALSE; + + arity = FunctorP (a) -> arityoffe; + +/* main loop */ + + while (--arity > 0) { + a = *++ta; + if (IsVar (a)) { + pa = FrameVar (ga, VarNo (a)); + a = *pa; + while (IsRef (a)) { + pa = a; + a = *a; + } + b = *++tb; + if (IsVar (b)) { + pb = FrameVar ( gb, VarNo (b)); + b = *pb; + while (IsRef (b)) { + pb = b; + b = *b; + } + if (pa == pb) + continue; + if (Undef (b)) { + if (Undef (a)) { + if (pa > pb) { + *pa = pb; + TrailVar (pa); + continue; + } + *pb = pa; + TrailVar (pb); + continue; + } + if (IsComp (a)) + *pb = pa; + else + *pb = a; + TrailVar (pb); + continue; + } + + if (Undef (a)) { + if (IsComp (b)) + *pa = pb; + else + *pa = b; + TrailVar (pa); + continue; + } + + if (IsAtomic (a)) { + if (a == b) + continue; + else + return FALSE; + } + if (IsAtomic (b) || + !gunify (a, MolP (pa) -> Env, b, MolP (pb) -> Env)) + return FALSE; + continue; + } + if (IsAtomic (b)) { + if (Undef (a)) { + *pa = b; + TrailVar (pa); + continue; + } + if (a == b) + continue; + return FALSE; + } + if (Undef (a)) { + ConsMol (b, gb, *pa); + TrailVar (pa); + continue; + } + if (IsAtomic (a) || !gunify (a, MolP (pa) -> Env, b, gb)) + return FALSE; + continue; + } + b = *++tb; + if (IsInp (b)) { + if (IsComp (a)) { + if (IsAtomic (b) || !gunify (a, ga, b, gb)) + return FALSE; + continue; + } + if (b != a) + return FALSE; + continue; + } + pb = FrameVar ( gb, VarNo (b)); + b = *pb; + while (IsRef (b)) { + pb = b; + b = *b; + } + if (Undef (b)) { + if (IsAtomic (a)) + *pb = a; + else + ConsMol (a, ga, *pb); + TrailVar (pb); + continue; + } + if (IsComp (b)) { + if (IsAtomic (a) || !gunify (a, ga, b, MolP (pb) -> Env)) + return FALSE; + continue; + } + if (b != a) + return FALSE; + continue; + } + ta = *++ta; + if (IsVar (ta)) { + pa = FrameVar (ga, VarNo (ta)); + ta = *pa; + while (IsRef (ta)) { + pa = ta; + ta = *ta; + } + tb = *++tb; + if (IsVar (tb)) { + pb = FrameVar (gb, VarNo (tb)); + tb = *pb; + while (IsRef (tb)) { + pb = tb; + tb = *tb; + } + if (pa == pb) + return TRUE; + if (Undef (tb)) { + if (Undef (ta)) { + if (pa > pb) { + *pa = pb; + TrailVar (pa); + return TRUE; + } + *pb = pa; + TrailVar (pb); + return TRUE; + } + *pb = IsComp (ta) ? pa : ta; + TrailVar (pb); + return TRUE; + } + if (Undef (ta)) { + *pa = IsComp (tb) ? pb : tb; + TrailVar (pa); + return TRUE; + } + if (IsAtomic (ta)) + return (ta == tb); + if (IsAtomic (tb)) + return FALSE; + ga = MolP (pa) -> Env; + gb = MolP (pb) -> Env; + goto start; + } + if (IsAtomic (tb)) { + if (Undef (ta)) { + *pa = tb; + TrailVar (pa); + return TRUE; + } + return (ta == tb); + } + if (Undef (ta)) { + ConsMol (tb, gb, *pa); + TrailVar (pa); + return TRUE; + } + if (IsAtomic (ta)) + return FALSE; + ga = MolP (pa) -> Env; + goto start; + } + tb = *++tb; + if (IsInp (tb)) { + if (IsComp (ta)) { + if (IsAtomic (tb)) + return FALSE; + goto start; + } + return (tb == ta); + } + pb = FrameVar (gb, VarNo (tb)); + tb = *pb; + while (IsRef (tb)) { + pb = tb; + tb = *tb; + } + if (Undef (tb)) { + if (IsAtomic (ta)) + *pb = ta; + else + ConsMol (ta, ga, *pb); + TrailVar (pb); + return TRUE; + } + if (IsComp (tb)) { + if (IsAtomic (ta)) + return FALSE; + gb = MolP (pb) -> Env; + goto start; + } + return (tb == ta); +} + +int +unifyarg(a,t,tf) +PTR a, t; PTR tf; +{ + if(IsVar(t)) { + t=FrameVar(tf,VarNo(t)); + while(IsRef(*t)) t = *t; + } + while (IsRef(*a)) a = *a; + if (Undef(*a)) { + if (IsInp(t) && IsComp(t)) { + ConsMol(t,tf,*a); + TrailVar(a); + return TRUE; + } + if (IsRef(t) && Undef(*t) && t >= a) { + if (t == a) return TRUE; + *t = a; + TrailVar(t); + return TRUE; + } + *a = t; + TrailVar(a); + return TRUE; + } + if (IsRef(t) && Undef(*t)) { + *t = IsComp(*a) ? CellP(a) : CellP(*a); + TrailVar(t); + return TRUE; + } + if (t == *a && IsAtomic(t)) return TRUE; + if (IsAtomic(t) || IsAtomic(*a)) return FALSE; + if (!IsInp(t)) { + tf = MolP(t)->Env; + t = MolP(t)->Sk; + } + return gunify(MolP(a)->Sk,MolP(a)->Env,t,tf); +} + +PTR +deref(vp) +register PTR vp; +{ + while (IsRef(*vp)) vp = *vp; + return vp; +} + +PTR +vvalue(vp,tf) +register PTR vp; PTR *tf; +{ + vp = deref(vp); + if (Undef(*vp)) return vp; + if (IsComp(*vp)) *tf = MolP(vp)->Env; + return *vp; +} + +PTR +arg(argp,tf) +register PTR argp; PTR tf; +{ + register PTR a; + a = *argp; + if (IsVar(a)) { + if (IsLocalVar(a)) + argp = x; + else + argp = tf; + argp = deref(FrameVar(argp,VarNo(a))); + a = *argp; + if (Undef(a) || IsComp(a)) return argp; + } + return a; +} + +PTR +argv(argp,tf,af) +register PTR argp; PTR tf, *af; +{ + register PTR a; + a = arg(argp,tf); + if (IsRef(a)) { + if (Undef(*a)) return a; + *af = MolP(a)->Env; + return MolP(a)->Sk; + } + *af = tf; + return a; +} diff --git a/source_code/c-prolog-1982/unify.o b/source_code/c-prolog-1982/unify.o new file mode 100755 index 0000000..f11cd72 Binary files /dev/null and b/source_code/c-prolog-1982/unify.o differ