Prolog Semantics Expressed in Algol-68
See L. Allison, A Practical Introduction to Denotational Semantics, CUP, Cambridge Computer Science Texts V23, 1986.
( print((newline," progch9.a68:Prolog Semantics 9/5/85 L.A.", newline)); #-----------------------------------------------------------------------------# #lexical domains# MODE ALFA = [1:10]CHAR; INT ident = 1, numeral = 2, varsy = 3, #e.g. fred, 99, X # ifsy = 4, qmark = 5, # :- ? # open = 6, close = 7, comma = 8,stopsy = 9; #-----------------------------------------------------------------------------# #syntactic domains# MODE PROG = STRUCT(CLIST c, QUERY q); MODE CLIST = REF CLISTNODE, RULE = STRUCT(PRED head, PLIST rhs); MODE CLISTNODE = STRUCT(CLAUSE h, CLIST t); MODE CLAUSE = UNION(PRED # a fact #, RULE); MODE APPLIC = STRUCT(ALFA id, ALIST args); # f(x,g(4,y)) # MODE PLIST = REF PLISTNODE; MODE PLISTNODE = STRUCT(PRED h, PLIST t); MODE PRED = UNION(APPLIC, ALFA); # odd(7). OR p. # MODE QUERY = PLIST; MODE ALIST = REF ALISTNODE; MODE ALISTNODE = STRUCT(ATOM h, ALIST t); MODE NAME = STRUCT(INT tag, ALFA id); # < ident,fred > OR < varsy,FRED > # MODE ATOM = UNION(INT, NAME, APPLIC, # numeral | ident | IDENT | f(args) # LOCN #NB. LOCN for VALUE not ATOM#); #-------------------------------------------------------------------------# # I/O # LOC INT line no := 1; LOC BOOL end of input := FALSE; print((newline, line no, "->")); OP = =(ALFA a, b)BOOL: (LOC BOOL eq:=TRUE; FOR i TO UPB a WHILE eq DO eq:=a[i]=b[i] OD; eq ); PROC getch = CHAR: (LOC CHAR ch; LOC FILE si:=stand in; PROC gc = CHAR: (LOC FILE si2 := si; PROC eof = (REF FILE f)BOOL: (print(("< EOF>", newline)); ch:="."; end of input := TRUE; GOTO eoflab ); on logical file end(si2, eof); get(si2, ch); print(ch); eoflab: ch ); PROC eol = (REF FILE f)BOOL: (ch:=" "; newline(f); line no +:=1; print((newline, line no, "->")); GOTO eolnlab ); on line end(si, eol); ch:=gc; eolnlab: ch ) # getch #; #-----------------------------------------------------------------------------# #lexical# LOC CHAR ch:=getch; #current character# LOC INT sy; # current symbol code # LOC ALFA word; # holds characters of a var or ident # LOC INT n; # value if sy=numeral # PROC error = (STRING m)VOID: (print((newline, " error:", m, " lineno=", whole(line no,0), " ch=", ch, " sy=", sy, " n=", n)); IF end of input THEN print(" end of input file") FI; GOTO stop ); PROC check = (INT sym, STRING message)VOID: IF sy=sym THEN insymbol ELSE error(message) FI; PROC insymbol = VOID: (PROC letter = (CHAR ch)BOOL: (ch >= "a" AND ch <= "z") OR (ch >= "A" AND ch <= "Z"); PROC capital = (CHAR ch)BOOL: ch >= "A" AND ch <= "Z"; PROC digit = (CHAR ch)BOOL: ch >= "0" AND ch <= "9"; LOC BOOL looked ahead := FALSE; WHILE ch=" " DO ch:=getch OD; # ch~=" " # FOR i FROM LWB word TO UPB word DO word[i]:=" " OD; IF letter(ch) THEN looked ahead := TRUE; word[1]:=ch; ch:=getch; LOC INT l:=1; WHILE letter(ch) OR digit(ch) DO l+:=1; IF l <= UPB word THEN word[l]:=ch FI; ch:=getch OD; IF capital(word[1]) THEN sy:=varsy ELSE sy:= ident FI ELIF digit(ch) THEN looked ahead := TRUE; n:=0; WHILE digit(ch) DO n:=n*10+ ABS ch - ABS "0"; ch:=getch OD; sy:=numeral ELIF ch="(" THEN sy:=open ELIF ch=")" THEN sy:=close ELIF ch="?" THEN sy:=qmark ELIF ch="," THEN sy:=comma ELIF ch="." THEN sy:=stopsy ELIF ch=":" THEN ch:=getch; IF ch="-" THEN sy:=ifsy ELSE error(" no - after : ") FI ELSE error(" in insymbol ") FI; IF NOT looked ahead THEN ch:=getch FI ) # insymbol #; #-----------------------------------------------------------------------------# #syntax# PROC parser = PROG: ( PROC p clist = CLIST: # list of >=0 clauses # IF sy = qmark THEN NIL ELSE CLAUSE h = p clause; HEAP CLISTNODE := (h, p clist) FI; PROC p clause = CLAUSE: ( PRED head = p pred; IF sy = stopsy THEN insymbol; head ELIF sy = ifsy THEN insymbol; PLIST rhs = p plist; check(stopsy, " no . after rule "); RULE (head, rhs) ELSE error(" . or :- expected in p clause"); SKIP FI ); PROC p plist = PLIST: # list of >=0 predicates # IF sy = stopsy THEN NIL ELSE PRED h = p pred; HEAP PLISTNODE:=(h,IF sy = comma THEN insymbol; p plist ELSE NIL FI ) FI; PROC p pred = PRED: IF sy = ident THEN ALFA id = word; insymbol; IF sy = open THEN insymbol; ALIST args = p alist; check(close, " ) expected "); APPLIC (id, args) ELSE id FI ELSE error(" identifier expected"); SKIP FI; PROC p alist = ALIST: # list of >=1 atoms # ( ATOM h = p atom; IF sy = comma THEN insymbol; HEAP ALISTNODE := (h, p alist) ELSE HEAP ALISTNODE := (h, NIL) FI ); PROC p atom = ATOM: IF sy = numeral THEN INT v = n; insymbol; n ELIF sy = varsy THEN ALFA id = word; insymbol; NAME (varsy, id) ELIF sy = ident THEN ALFA id = word; insymbol; IF sy = open THEN insymbol; ALIST args = p alist; check(close, " ) expected"); APPLIC (id, args) ELSE NAME (ident, id) FI ELSE error(" p atom: numeral, var or ident expected"); SKIP FI; PROC p query = QUERY: ( check(qmark, " ? expected"); PLIST q = p plist; check(stopsy, " . expected after query"); q ); insymbol; CLIST facts = p clist; (facts, p query) )#parser#; #-----------------------------------------------------------------------------# #semantics domains# MODE VALUE = ATOM, VLIST = ALIST; MODE ANS = REF ANSCELL; MODE ANSCELL = STRUCT(VALUE h, ANS t); MODE LOCN = STRUCT(INT l, dontcare); MODE ENV = PROC(ALFA)LOCN, STORE = PROC(LOCN)VALUE; MODE DATABASE = PROC(PRED, DATABASE, QCONT, INT, STORE)ANS; MODE QCONT = PROC(INT,STORE)ANS; MODE CLCONT = PROC(DATABASE)ANS; OP = = (LOCN a,b)BOOL: l OF a = l OF b; PROC show = (ANS a)VOID: ( PROC show2 = (ANS a,BOOL top level)VOID: ( PROC s = (VALUE a)VOID: CASE a IN (INT n): print(whole(n,0)), (NAME n):FOR i TO UPB id OF n WHILE (id OF n)[i] ~= " " DO print((id OF n)[i]) OD, (APPLIC f):(FOR i TO UPB id OF f WHILE (id OF f)[i] ~= " " DO print((id OF f)[i]) OD; print("("); show2(args OF f, FALSE); print(")") ), (LOCN ln): print(("L-", whole(l OF ln, 0) )) ESAC; IF a ISNT NIL THEN s(h OF a); IF t OF a ISNT NIL THEN print(","); IF top level THEN print(newline) FI; show2(t OF a, top level) FI FI ) #show2#; show2(a, TRUE) ) #show#; PROC append = (ANS a,b) ANS: IF a IS NIL THEN b ELIF b IS NIL THEN a ELSE HEAP ANSCELL := (h OF a, append(t OF a, b)) FI; MODE ALFAS = REF STRUCT(ALFA id, ALFAS t); PROC length = (ALFAS l)INT: IF l IS NIL THEN 0 ELSE 1+length(t OF l) FI; PROC index = (ALFA key, ALFAS l)INT: IF l IS NIL THEN -max int ELIF key = id OF l THEN 1 ELSE 1+index(key, t OF l) FI; PROC vars in pred = (PRED p)ALFAS: CASE p IN (APPLIC a): vars in alist(args OF a), (ALFA a):NIL ESAC; PROC vars in clause = (CLAUSE c)ALFAS: CASE c IN (PRED p): vars in pred(p), (RULE r): merge(vars in pred(head OF r), vars in plist(rhs OF r) ) ESAC; PROC vars in plist = (PLIST l)ALFAS: IF l IS NIL THEN NIL ELSE merge(vars in pred(h OF l), vars in plist(t OF l)) FI; PROC vars in alist = (ALIST l)ALFAS: IF l IS NIL THEN NIL ELSE merge(vars in atom(h OF l), vars in alist(t OF l)) FI; PROC vars in atom = (ATOM a)ALFAS: CASE a IN (NAME n): IF tag OF n = varsy THEN HEAP STRUCT(ALFA id,ALFAS t):=(id OF n, NIL) ELSE NIL FI, (APPLIC f): vars in alist(args OF f) OUT NIL ESAC; PROC merge = (ALFAS a,b)ALFAS: IF a IS NIL THEN b ELIF b IS NIL THEN a ELIF index(id OF a, b)>0 THEN merge(t OF a, b) ELSE HEAP STRUCT(ALFA id,ALFAS t):=(id OF a, merge(t OF a, b)) FI; PROC map e val = (ENV e, VALUE v)VALUE: CASE v IN (NAME n):IF tag OF n=ident THEN v ELSE e(id OF n) FI, (APPLIC f):APPLIC(id OF f, map e vlist(e, args OF f)) OUT v ESAC; PROC map e vlist = (ENV e, VLIST l)VLIST: IF l IS NIL THEN NIL ELSE HEAP ALISTNODE := (map e val(e, h OF l), map e vlist(e, t OF l)) FI; PROC map e pred = (ENV e, PRED p)PRED: CASE p IN (APPLIC f):APPLIC(id OF f, map e vlist(e, args OF f)), (ALFA a):p ESAC; PROC map e plist = (ENV e, PLIST l)PLIST: IF l IS NIL THEN NIL ELSE HEAP PLISTNODE := (map e pred(e, h OF l), map e plist(e, t OF l)) FI; #-----------------------------------------------------------------------------# #semantic functions# QCONT yes = (INT l, STORE s)ANS: HEAP ANSCELL := (NAME(ident,ALFA("y","e","s","*","*","*","*","*","*","*")), NIL); ALFA unset id = ("*","u","n","s","e","t","*","*","*","*"); VALUE unset = NAME(ident, unset id); PROC not set = (VALUE v)BOOL: CASE v IN (NAME n): (tag OF n = ident) AND (id OF n = unset id) OUT FALSE ESAC; DATABASE start d = (PRED p, DATABASE d, QCONT c, INT l, STORE s)ANS: ( PROC map s val = (VALUE v)VALUE: CASE v IN (LOCN l): IF not set(s(l)) THEN v ELSE map s val(s(l)) FI, (APPLIC f): APPLIC(id OF f, map s list(args OF f)) OUT v ESAC; PROC map s list = (VLIST l)VLIST: IF l IS NIL THEN NIL ELSE HEAP ALISTNODE := (map s val(h OF l), map s list(t OF l)) FI; CASE p IN (ALFA x): ( #debug# print("?");FOR i TO UPB x DO print(x[i]) OD; NIL), (APPLIC f):IF id OF f = ALFA("w","r","i","t","e"," "," "," "," "," ") THEN HEAP ANSCELL := (map s val(h OF args OF f), c(l,s)) ELSE #debug# print("?"); #debug# FOR i TO UPB id OF f DO print((id OF f)[i]) OD; #debug# print("(...)"); NIL FI ESAC ); STORE start s = (LOCN ln)VALUE: unset; PROC ppp = (PROG p)ANS: ( CLCONT ask = (DATABASE d)ANS: ( ALFAS vars = vars in plist(q OF p); INT n vars = length(vars); ENV e = (ALFA a)LOCN: (index(a,vars), 0); qqq(map e plist(e,q OF p), d, yes, n vars, start s) ); #debug#print(" P["); ddd(c OF p, start d, ask) ); PROC qqq = (QUERY q, DATABASE d, QCONT c, INT l, STORE s)ANS: IF q IS NIL THEN c(l, s) ELSE QCONT ask tail = (INT l, STORE s)ANS: qqq(t OF q, d, c, l, s); #debug# print(" Q["); d(h OF q, d, ask tail, l, s) FI; PROC ddd = (UNION(CLIST,CLAUSE) f, DATABASE d, CLCONT k)ANS: CASE f IN (CLIST f):IF f IS NIL THEN k(d) ELSE CLCONT do tail = (DATABASE d)ANS: ddd(t OF f, d, k); ddd(h OF f, d, do tail) FI, (CLAUSE f): CASE f IN (PRED p): ddd( RULE(p,NIL), d, k), (RULE r): ( # head:-rhs. e.g. p:-q,r. # DATABASE new d = (PRED p, DATABASE final d, QCONT c, INT l, STORE s)ANS: ( ALFAS vars = vars in clause(f); INT n vars = length(vars); INT l2 = l+n vars; STORE s2 = (LOCN ln)VALUE: IF l OF ln > l THEN unset ELSE s(ln) FI; ENV e = (ALFA a)LOCN: (index(a,vars)+l,0); QCONT ask body = (INT l, STORE s)ANS: qqq(map e plist(e,rhs OF r), final d, c, l, s); append( d(p, final d, c, l, s), uuu pred(map e pred(e,head OF r), p, ask body, l2, s2)) )#new d#; #debug#print(":-"); k(new d) ) ESAC ESAC; PROC uuu pred = (PRED a,b, QCONT c, INT l, STORE s)ANS: CASE a IN (ALFA pa): CASE b IN (ALFA pb): IF pa=pb THEN c(l,s) ELSE NIL FI OUT NIL ESAC, (APPLIC fa):CASE b IN (APPLIC fb): IF id OF fa = id OF fb THEN uuu list(args OF fa, args OF fb, c, l, s) ELSE NIL FI OUT NIL ESAC ESAC; PROC uuu list = (VLIST a,q, QCONT c, INT l, STORE s)ANS: IF (a IS NIL) OR (q IS NIL) THEN IF a IS q THEN c(l,s) ELSE NIL FI ELSE QCONT do tail = (INT l, STORE s)ANS: uuu list(t OF a, t OF q, c, l, s); uuu(h OF a, h OF q, do tail, l, s) FI; PROC uuu = (VALUE a, q, QCONT c, INT l, STORE s)ANS: ( PROC update = (LOCN x, VALUE v)ANS: IF not set(s(x)) THEN PROC new s = (LOCN x2)VALUE: IF x=x2 THEN v ELSE s(x2) FI; c(l, new s) ELSE uuu(s(x), v, c, l, s) FI; CASE q IN (NAME nq):# must be an ident # CASE a IN (LOCN la):update(la, q), (NAME na):IF id OF nq = id OF na THEN c(l,s) ELSE NIL FI OUT NIL ESAC, (LOCN lq):update(lq, a), (INT nq):CASE a IN (LOCN la):update(la,q), (INT na): IF nq=na THEN c(l,s) ELSE NIL FI OUT NIL ESAC, (APPLIC fq):CASE a IN (LOCN la):update(la, q), (APPLIC fa): IF id OF fq = id OF fa THEN uuu list(args OF fq,args OF fa,c,l,s) ELSE NIL FI OUT NIL ESAC ESAC ) # uuu#; show( ppp(parser) ) )