home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d524 / kamin.lha / Kamin / P-Distr.lzh / prolog.p < prev    next >
Text File  |  1989-07-16  |  29KB  |  1,030 lines

  1. (*****************************************************************
  2.  *                     DECLARATIONS                              *
  3.  *****************************************************************)
  4. program prolog (input, output);
  5.  
  6. label 99;
  7.  
  8. const
  9.    NAMELENG = 20;      (* Maximum length of a name *)
  10.    MAXNAMES = 300;     (* Maximum number of different names *)
  11.    MAXINPUT = 2000;    (* Maximum length of an input *)
  12.    PROMPT = '-> ';
  13.    PROMPT2 = '> ';
  14.    COMMENTCHAR = ';';
  15.    TABCODE = 9;        (* in ASCII *)
  16.  
  17. type
  18.    NAMESIZE = 0..NAMELENG;
  19.    NAMESTRING = packed array [1..NAMELENG] of char;
  20.  
  21.    NAME = 1 .. MAXNAMES; (* a NAME is an index in printNames *)
  22.  
  23.    CLAUSE = ^CLAUSEREC;
  24.    GOALLIST = ^GOALLISTREC;
  25.    GOAL = ^GOALREC;
  26.    EXP = ^EXPREC;
  27.    EXPLIST = ^EXPLISTREC;
  28.    VARIABLE = ^VARIABLEREC;
  29.    VARLIST = ^ VARLISTREC;
  30.    SUBST = ^SUBSTREC;
  31.       
  32.    GOALREC = record
  33.                pred: NAME;
  34.                args: EXPLIST
  35.             end;
  36.  
  37.    GOALLISTREC = record
  38.                head: GOAL;
  39.                tail: GOALLIST;
  40.             end;
  41.  
  42.    VARIABLEREC = record
  43.                varname: NAME;
  44.                varindex: integer
  45.             end;
  46.  
  47.    VARLISTREC = record
  48.                head: VARIABLE;
  49.                tail: VARLIST;
  50.             end;
  51.  
  52.    EXPTYPE = (VAREXP,INTEXP,APEXP);
  53.    EXPREC = record
  54.                case etype: EXPTYPE of
  55.                   VAREXP: (varble: VARIABLE);
  56.                   INTEXP: (intval: integer);
  57.                   APEXP: (optr: NAME; args: EXPLIST)
  58.             end;
  59.  
  60.    EXPLISTREC = record
  61.                head: EXP;
  62.                tail: EXPLIST;
  63.             end;
  64.  
  65.    CLAUSEREC = record
  66.                lhs: GOAL;
  67.                rhs: GOALLIST;
  68.                nextclause: CLAUSE
  69.             end;
  70.  
  71.    SUBSTREC = record
  72.                domain: VARLIST;
  73.                range: EXPLIST
  74.             end;
  75.  
  76. var
  77.    clauses, lastclause: CLAUSE;
  78.  
  79.    toplevelGoal: GOALLIST;
  80.  
  81.    userinput: array [1..MAXINPUT] of char;
  82.    inputleng, pos: 0..MAXINPUT;
  83.  
  84.    printNames: array [NAME] of NAMESTRING;
  85.    numNames, numBuiltins : NAME;
  86.  
  87.    quittingtime: Boolean;
  88.  
  89. (*****************************************************************
  90.  *                     DATA STRUCTURE OP'S                       *
  91.  *****************************************************************)
  92.  
  93. (* mkGoal - create a new GOAL with pred p and arguments a        *)
  94. function mkGoal (p: NAME; a: EXPLIST): GOAL;
  95. var newg: GOAL;
  96. begin
  97.    new(newg);
  98.    newg^.pred := p;
  99.    newg^.args := a;
  100.    mkGoal := newg
  101. end; (* mkGoal *)
  102.  
  103. (* mkVAREXP - create a new EXP of type VAREXP                    *)
  104. function mkVAREXP (v: VARIABLE): EXP;
  105. var newe: EXP;
  106. begin
  107.    new(newe);
  108.    newe^.etype := VAREXP;
  109.    newe^.varble := v;
  110.    mkVAREXP := newe
  111. end; (* mkVAREXP *)
  112.  
  113. (* mkINTEXP - create a new EXP of type INTEXP                    *)
  114. function mkINTEXP (n: integer): EXP;
  115. var newe: EXP;
  116. begin
  117.    new(newe);
  118.    newe^.etype := INTEXP;
  119.    newe^.intval := n;
  120.    mkINTEXP := newe
  121. end; (* mkINTEXP *)
  122.  
  123. (* mkAPEXP - create a new EXP of type APEXP                      *)
  124. function mkAPEXP (o: NAME; a: EXPLIST): EXP;
  125. var newe: EXP;
  126. begin
  127.    new(newe);
  128.    newe^.etype := APEXP;
  129.    newe^.optr := o;
  130.    newe^.args := a;
  131.    mkAPEXP := newe
  132. end; (* mkAPEXP *)
  133.  
  134. (* mkVariable - create a new VARIABLE with name n and index i    *)
  135. function mkVariable (n: NAME; i: integer): VARIABLE;
  136. var newv: VARIABLE;
  137. begin
  138.    new(newv);
  139.    newv^.varname := n;
  140.    newv^.varindex := i;
  141.    mkVariable := newv
  142. end; (* mkVariable *)
  143.  
  144. (* mkVarlist - create a new VARLIST with head v and tail vl      *)
  145. function mkVarlist (v: VARIABLE; vl: VARLIST): VARLIST;
  146. var newvl: VARLIST;
  147. begin
  148.    new(newvl);
  149.    newvl^.head := v;
  150.    newvl^.tail := vl;
  151.    mkVarlist := newvl
  152. end; (* mkVarlist *)
  153.  
  154. (* mkGoallist - return a GOALLIST with head g and tail gl        *)
  155. function mkGoallist (g: GOAL; gl: GOALLIST): GOALLIST;
  156. var newgl: GOALLIST;
  157. begin
  158.    new(newgl);
  159.    newgl^.head := g;
  160.    newgl^.tail := gl;
  161.    mkGoallist := newgl
  162. end; (* mkGoallist *)
  163.  
  164. (* mkExplist - return an EXPLIST with head e and tail el         *)
  165. function mkExplist (e: EXP; el: EXPLIST): EXPLIST;
  166. var newel: EXPLIST;
  167. begin
  168.    new(newel);
  169.    newel^.head := e;
  170.    newel^.tail := el;
  171.    mkExplist := newel
  172. end; (* mkExplist *)
  173.  
  174. (* mkClause - create a new GOAL with lhs l and rhs r             *)
  175. function mkClause (l: GOAL; r: GOALLIST): CLAUSE;
  176. var c: CLAUSE;
  177. begin
  178.    new(c);
  179.    c^.lhs := l;
  180.    c^.rhs := r;
  181.    c^.nextclause := nil;
  182.    mkClause := c
  183. end; (* mkClause *)
  184.  
  185. (* eqVar - compare two VARIABLE's for equality                   *)
  186. function eqVar (v1, v2: VARIABLE): Boolean;
  187. begin
  188.    eqVar := (v1^.varname = v2^.varname)
  189.            and (v1^.varindex = v2^.varindex)
  190. end; (* eqVar *)
  191.  
  192. (* lengthEL - return length of EXPLIST el                        *)
  193. function lengthEL (el: EXPLIST): integer;
  194. var i: integer;
  195. begin
  196.    i := 0;
  197.    while el <> nil do begin
  198.       i := i+1;
  199.       el := el^.tail
  200.       end;
  201.    lengthEL := i
  202. end; (* lengthEL *)
  203.  
  204. (*****************************************************************
  205.  *                     NAME MANAGEMENT                           *
  206.  *****************************************************************)
  207.  
  208. (* newClause - add new clause at end of clauses list             *)
  209. procedure newClause (l: GOAL; r: GOALLIST);
  210. begin
  211.     if lastclause = nil
  212.     then begin
  213.             clauses := mkClause(l, r);
  214.             lastclause := clauses
  215.          end
  216.     else begin
  217.             lastclause^.nextclause := mkClause(l, r);
  218.             lastclause := lastclause^.nextclause
  219.          end
  220. end; (* newClause *)
  221.  
  222. (* initNames - place all pre-defined names into printNames       *)
  223. procedure initNames;
  224. var i: integer;
  225. begin
  226.    clauses := nil;
  227.    lastclause := nil;
  228.    i := 1;
  229.    printNames[i]:='plus                '; i:=i+1;
  230.    printNames[i]:='minus               '; i:=i+1;
  231.    printNames[i]:='less                '; i:=i+1;
  232.    printNames[i]:='print               ';
  233.    numBuiltins := i;
  234.    numNames := i
  235. end; (* initNames *)
  236.  
  237. (* install - insert new name into printNames                     *)
  238. function install (nm: NAMESTRING): NAME;
  239. var
  240.    i: integer;
  241.    found: Boolean;
  242. begin
  243.    i := 1; found := false;
  244.    while (i <= numNames) and not found
  245.    do if nm = printNames[i]
  246.       then found := true
  247.       else i := i+1;
  248.    if not found
  249.    then begin
  250.            if i > MAXNAMES
  251.            then begin
  252.                    writeln('No more room for names');
  253.                    goto 99
  254.                 end;
  255.            numNames := i;
  256.            printNames[i] := nm
  257.         end;
  258.    install := i
  259. end; (* install *)
  260.  
  261. (* prName - print name nm                                        *)
  262. procedure prName (nm: NAME);
  263. var i: integer;
  264. begin
  265.    i := 1;
  266.    while i <= NAMELENG
  267.    do if printNames[nm][i] <> ' '
  268.       then begin
  269.               write(printNames[nm][i]);
  270.               i := i+1
  271.            end
  272.       else i := NAMELENG+1
  273. end; (* prName *)
  274.  
  275. (*****************************************************************
  276.  *                      INPUT                                    *
  277.  *****************************************************************)
  278.  
  279. (* isDelim - check if c is a delimiter                           *)
  280. function isDelim (c: char): Boolean;
  281. begin
  282.    isDelim := c in ['(', ')', ' ', COMMENTCHAR]
  283. end; (* isDelim *)
  284.  
  285. (* skipblanks - return next non-blank position in userinput      *)
  286. function skipblanks (p: integer): integer;
  287. begin
  288.    while userinput[p] = ' ' do p := p+1;
  289.    skipblanks := p
  290. end; (* skipblanks *)
  291.  
  292. (* matches - check if string nm matches userinput[s .. s+ln]     *)
  293. function matches (s: integer; ln: NAMESIZE;
  294.                    nm: NAMESTRING): Boolean;
  295. var
  296.    match: Boolean;
  297.    i: integer;
  298. begin
  299.    match := true; i := 1;
  300.    while match and (i <= ln) do begin
  301.       if userinput[s] <> nm[i] then match := false;
  302.       i := i+1;
  303.       s := s+1
  304.       end;
  305.    if not isDelim(userinput[s]) then match := false;
  306.    matches := match
  307. end; (* matches *)
  308.  
  309. (* reader - read char's into userinput; be sure input not blank  *)
  310. procedure reader;
  311.  
  312. (* readInput - read char's into userinput                        *)
  313.    procedure readInput;
  314.  
  315.    var c: char;
  316.  
  317. (* nextchar - read next char - filter tabs and comments          *)
  318.       procedure nextchar (var c: char);
  319.       begin
  320.          read(c);
  321.          if c = chr(TABCODE)
  322.          then c := ' '
  323.          else if c = COMMENTCHAR
  324.               then begin while not eoln do read(c); c := ' ' end
  325.       end; (* nextchar *)
  326.  
  327. (* readParens - read char's, ignoring newlines, to matching ')'  *)
  328.       procedure readParens;
  329.       var
  330.          parencnt: integer;
  331.          c: char;
  332.       begin
  333.          parencnt := 1;
  334.          repeat
  335.             if eoln then write(PROMPT2);
  336.             nextchar(c);
  337.             pos := pos+1;
  338.             if pos = MAXINPUT
  339.             then begin
  340.                     writeln('User input too long');
  341.                     goto 99
  342.                  end;
  343.             userinput[pos] := c;
  344.             if c = '(' then parencnt := parencnt+1;
  345.             if c = ')' then parencnt := parencnt-1
  346.          until parencnt = 0
  347.       end; (* readParens *)
  348.  
  349.    begin (* readInput *)
  350.       write(PROMPT);
  351.       pos := 0;
  352.       repeat
  353.          pos := pos+1;
  354.          if pos = MAXINPUT
  355.          then begin
  356.                  writeln('User input too long');
  357.                  goto 99
  358.               end;
  359.          nextchar(c);
  360.          userinput[pos] := c;
  361.          if userinput[pos] = '(' then readParens
  362.       until eoln;
  363.       inputleng := pos;
  364.       userinput[pos+1] := COMMENTCHAR (* sentinel *)
  365.    end; (* readInput *)
  366.  
  367. begin (* reader *)
  368.     repeat
  369.        readInput;
  370.        pos := skipblanks(1);
  371.     until pos <= inputleng (* ignore blank lines *)
  372. end; (* reader *)
  373.  
  374. (* parseName - return (installed) NAME starting at userinput[pos]*)
  375. function parseName: NAME;
  376. var
  377.    nm: NAMESTRING; (* array to accumulate characters *)
  378.    leng: NAMESIZE; (* length of name *)
  379. begin
  380.    leng := 0;
  381.    while (pos <= inputleng) and not isDelim(userinput[pos])
  382.    do begin
  383.          if leng = NAMELENG
  384.          then begin
  385.                  writeln('Name too long, begins: ', nm);
  386.                  goto 99
  387.               end;
  388.          leng := leng+1;
  389.          nm[leng] := userinput[pos];
  390.          pos := pos+1
  391.       end;
  392.    if leng = 0
  393.    then begin
  394.            writeln('Error: expected name, instead read: ',
  395.                    userinput[pos]);
  396.            goto 99
  397.         end;
  398.    for leng := leng+1 to NAMELENG do nm[leng] := ' ';
  399.    pos := skipblanks(pos); (* skip blanks after name *)
  400.    parseName := install(nm)
  401. end; (* parseName *)
  402.  
  403. (* isVar - check if first character of name n is upper-case      *)
  404. function isVar (n: NAME): Boolean;
  405. begin
  406.    isVar := (printNames[n][1] >= 'A')
  407.            and (printNames[n][1] <= 'Z')
  408. end; (* isVar *)
  409.  
  410. (* isNumber - check if a number begins at pos                    *)
  411. function isNumber (pos: integer): Boolean;
  412.  
  413. (* isDigits - check if sequence of digits begins at pos          *)
  414.    function isDigits (pos: integer): Boolean;
  415.    begin
  416.       if not (userinput[pos] in ['0'..'9'])
  417.       then isDigits := false
  418.       else begin
  419.               isDigits := true;
  420.               while userinput[pos] in ['0'..'9'] do pos := pos+1;
  421.               if not isDelim(userinput[pos])
  422.               then isDigits := false
  423.            end
  424.    end; (* isDigits *)
  425.  
  426. begin (* isNumber *)
  427.    isNumber := isDigits(pos) or
  428.               ((userinput[pos] = '-') and isDigits(pos+1))
  429. end; (* isNumber *)
  430.  
  431. (* parseInt - return number starting at userinput[pos]           *)
  432. function parseInt: integer;
  433. var n, sign: integer;
  434. begin
  435.    n := 0; sign := 1;
  436.    if userinput[pos] = '-'
  437.    then begin
  438.            sign := -1;
  439.            pos := pos+1
  440.         end;
  441.    while userinput[pos] in ['0'..'9'] do
  442.       begin
  443.          n := 10*n + (ord(userinput[pos]) - ord('0'));
  444.          pos := pos+1
  445.       end;
  446.    pos := skipblanks(pos); (* skip blanks after number *)
  447.    parseInt := n*sign
  448. end; (* parseInt *)
  449.  
  450. function parseEL: EXPLIST; forward;
  451.  
  452. (* parseExp - return EXP starting at userinput[pos]              *)
  453. function parseExp: EXP;
  454. var
  455.    n: NAME;
  456.    el: EXPLIST;
  457. begin
  458.    if userinput[pos] = '('
  459.    then begin
  460.            pos := skipblanks(pos+1); (* skip '( ..' *)
  461.            n := parseName;
  462.            el := parseEL;
  463.            parseExp := mkAPEXP(n, el)
  464.         end
  465.    else if isNumber(pos)
  466.         then parseExp := mkINTEXP(parseInt)
  467.         else begin
  468.                 n := parseName;
  469.                 if isVar(n)
  470.                 then parseExp := mkVAREXP(mkVariable(n, 0))
  471.                 else parseExp := mkAPEXP(n, nil)
  472.              end
  473. end; (* parseExp *)
  474.  
  475. (* parseEL - return EXPLIST starting at userinput[pos]           *)
  476. function parseEL;
  477. var
  478.    e: EXP;
  479.    el: EXPLIST;
  480. begin
  481.    if userinput[pos] = ')'
  482.    then begin
  483.            pos := skipblanks(pos+1); (* skip ') ..' *)
  484.            parseEL := nil
  485.         end
  486.    else begin
  487.            e := parseExp;
  488.            el := parseEL;
  489.            parseEL := mkExplist(e, el)
  490.         end
  491. end; (* parseEL *)
  492.  
  493. (* parseGoal - return GOAL starting at userinput[pos]            *)
  494. function parseGoal: GOAL;
  495. var
  496.    pred: NAME;
  497.    il: EXPLIST;
  498. begin
  499.    if userinput[pos] = '('
  500.    then begin
  501.            pos := skipblanks(pos+1); (* skip '( ...' *)
  502.            pred := parseName;
  503.            il := parseEL
  504.         end
  505.    else begin
  506.            pred := parseName;
  507.            il := nil
  508.         end;
  509.    parseGoal := mkGoal(pred, il)
  510. end; (* parseGoal *)
  511.  
  512. (* parseGL - return GOALLIST starting at userinput[pos]          *)
  513. function parseGL: GOALLIST;
  514. var
  515.    g: GOAL;
  516.    gl: GOALLIST;
  517. begin
  518.    if userinput[pos] = ')'
  519.    then begin
  520.            pos := skipblanks(pos+1); (* skip ') ..' *)
  521.            parseGL := nil
  522.         end
  523.    else begin
  524.            g := parseGoal;
  525.            gl := parseGL;
  526.            parseGL := mkGoallist(g, gl)
  527.         end
  528. end; (* parseGL *)
  529.  
  530. (* parseClause - return CLAUSE at userinput[pos]                 *)
  531. procedure parseClause;
  532. var
  533.    h: GOAL;
  534.    g: GOALLIST;
  535. begin
  536.    pos := skipblanks(pos+1); (* skip '( ..' *)
  537.    pos := skipblanks(pos+5); (* skip 'infer ..' *)
  538.    h := parseGoal;
  539.    if userinput[pos] = ')'
  540.    then g := nil
  541.    else begin
  542.            pos := skipblanks(pos+4); (* skip 'from ..' *)
  543.            g := parseGL
  544.         end;
  545.    pos := skipblanks(pos+1); (* skip ') ..' *)
  546.    newClause(h, g)
  547. end; (* parseClause *)
  548.  
  549. (* parseQuery - return GOALLIST starting at userinput[pos]       *)
  550. function parseQuery: GOALLIST;
  551. begin
  552.    pos := skipblanks(pos+1); (* skip '( ..' *)
  553.    pos := skipblanks(pos+6); (* skip 'infer? ..' *)
  554.    parseQuery := parseGL;
  555.    pos := skipblanks(pos+1) (* skip ') ..' *)
  556. end; (* parseQuery *)
  557.  
  558. (*****************************************************************
  559.  *                     OUTPUT                                    *
  560.  *****************************************************************)
  561.  
  562. (* prExplist - print an EXPLIST                                  *)
  563. procedure prExplist (el: EXPLIST);
  564.  
  565. (* prExp - print an EXP                                          *)
  566.    procedure prExp (e: EXP);
  567.   
  568. (* prVariable - print variable, including index                  *)
  569.       procedure prVariable (v: VARIABLE);
  570.       begin
  571.          prName(v^.varname);
  572.          if v^.varindex > 0
  573.          then write(v^.varindex:1)
  574.       end; (* prVariable *)
  575.   
  576.    begin (* prExp *)
  577.       case e^.etype of
  578.          INTEXP: write(e^.intval:1);
  579.          VAREXP: prVariable(e^.varble);
  580.          APEXP:
  581.             if e^.args=nil
  582.             then prName(e^.optr)
  583.             else begin
  584.                     write('(');
  585.                     prName(e^.optr);
  586.                     if e^.args <> nil
  587.                     then begin
  588.                             write(' ');
  589.                             prExplist(e^.args)
  590.                          end;
  591.                     write(')')
  592.                  end
  593.       end (* case *)
  594.    end; (* prExp *)
  595.  
  596. begin (* prExplist *)
  597.    if el <> nil
  598.    then begin
  599.            prExp(el^.head);
  600.            if el^.tail <> nil
  601.            then begin
  602.                    write(' ');
  603.                    prExplist(el^.tail)
  604.                 end
  605.         end
  606. end; (* prExplist *)
  607.  
  608. (*****************************************************************
  609.  *                     SUBSTITUTIONS                             *
  610.  *****************************************************************)
  611.  
  612. (* emptySubst - create a substitution with no bindings           *)
  613. function emptySubst: SUBST;
  614. var s: SUBST;
  615. begin
  616.    new(s);
  617.    s^.domain := nil;
  618.    s^.range := nil;
  619.    emptySubst := s
  620. end; (* emptySubst *)
  621.  
  622. (* bindVar - bind variable v to expression e in sigma            *)
  623. procedure bindVar (v: VARIABLE; e: EXP; sigma: SUBST);
  624. begin
  625.    sigma^.domain := mkVarlist(v, sigma^.domain);
  626.    sigma^.range := mkExplist(e, sigma^.range)
  627. end; (* bindVar *)
  628.  
  629. (* findVar - look up variable v in sigma                         *)
  630. function findVar (v: VARIABLE; sigma: SUBST): EXPLIST;
  631. var
  632.    dl: VARLIST;
  633.    rl: EXPLIST;
  634.    found: Boolean;
  635. begin
  636.    found := false;
  637.    dl := sigma^.domain;
  638.    rl := sigma^.range;
  639.    while (dl <> nil) and not found do
  640.       if eqVar(dl^.head, v)
  641.       then found := true
  642.       else begin
  643.               dl := dl^.tail;
  644.               rl := rl^.tail
  645.            end;
  646.    findVar := rl
  647. end; (* findVar *)
  648.  
  649. (* fetch - fetch binding of variable v in sigma                  *)
  650. function fetch (v: VARIABLE; sigma: SUBST): EXP;
  651. var el: EXPLIST;
  652. begin
  653.    el := findVar(v, sigma);
  654.    fetch := el^.head
  655. end; (* fetch *)
  656.  
  657. (* isBound - check if variable v is bound in sigma               *)
  658. function isBound (v: VARIABLE; sigma: SUBST): Boolean;
  659. begin
  660.    isBound := findVar(v, sigma) <> nil
  661. end; (* isBound *)
  662.  
  663. procedure applyToExplist (s: SUBST; el: EXPLIST); forward;
  664.  
  665. (* applyToExp - apply substitution s to e, modifying e           *)
  666. procedure applyToExp (s: SUBST; var e: EXP);
  667. begin
  668.    case e^.etype of
  669.       INTEXP: ;
  670.       VAREXP:
  671.          if isBound(e^.varble, s)
  672.          then e := fetch(e^.varble, s);
  673.       APEXP: applyToExplist(s, e^.args)
  674.    end
  675. end; (* applyToExp *)
  676.  
  677. (* applyToExplist - apply substitution s to el, modifying el     *)
  678. procedure applyToExplist;
  679. begin
  680.    while el <> nil do begin
  681.       applyToExp(s, el^.head);
  682.       el := el^.tail
  683.       end
  684. end; (* applyToExplist *)
  685.  
  686. (* applyToGoal - apply substitution s to g, modifying g          *)
  687. procedure applyToGoal (s: SUBST; g: GOAL);
  688. begin
  689.    applyToExplist(s, g^.args)
  690. end; (* applyToGoal *)
  691.  
  692. (* applyToGoallist - apply substitution s to gl, modifying gl    *)
  693. procedure applyToGoallist (s: SUBST; gl: GOALLIST);
  694. begin
  695.    while gl <> nil do begin
  696.       applyToGoal(s, gl^.head);
  697.       gl := gl^.tail
  698.       end
  699. end; (* applyToGoallist *)
  700.  
  701. (* compose - change substitution s1 to composition of s1 and s2  *)
  702. procedure compose (s1, s2: SUBST);
  703. var
  704.    dom: VARLIST;
  705.    rng: EXPLIST;
  706. begin
  707.    applyToExplist(s2, s1^.range);
  708.    if s1^.domain = nil
  709.    then begin
  710.            s1^.domain := s2^.domain;
  711.            s1^.range := s2^.range
  712.         end
  713.    else begin
  714.            dom := s1^.domain;
  715.            rng := s1^.range;
  716.            while dom^.tail <> nil do begin
  717.               dom := dom^.tail;
  718.               rng := rng^.tail
  719.               end;
  720.            dom^.tail := s2^.domain;
  721.            rng^.tail := s2^.range
  722.         end
  723. end; (* compose *)
  724.  
  725. (*****************************************************************
  726.  *                     UNIFICATION                               *
  727.  *****************************************************************)
  728.  
  729. (* unify - unify g1 and g2; return unifying subst. (or nil)      *)
  730. function unify (g1, g2: GOAL): SUBST;
  731. var
  732.    sigma, varsubst: SUBST;
  733.    foundDiff: Boolean;
  734.    diff1, diff2: EXP;
  735.  
  736.    function findExpDiff (e1, e2: EXP): Boolean;
  737.       forward;
  738.  
  739. (* findELDiff - set diff1, diff2 to EXP's where el1, el2 differ  *)
  740.    function findELDiff (el1, el2: EXPLIST): Boolean;
  741.    var foundDiff: Boolean;
  742.    begin
  743.       foundDiff := false;
  744.       while (el1 <> nil) and not foundDiff do begin
  745.          foundDiff := findExpDiff(el1^.head, el2^.head);
  746.          el1 := el1^.tail;
  747.          el2 := el2^.tail
  748.          end;
  749.       findELDiff := foundDiff
  750.    end; (* findELDiff *)
  751.  
  752. (* findExpDiff - set diff1, diff2 to EXP's where e1, e2 differ   *)
  753.    function findExpDiff;
  754.    begin
  755.       findExpDiff := true;
  756.       diff1 := e1;
  757.       diff2 := e2;
  758.       if e1^.etype = e2^.etype
  759.       then case e1^.etype of
  760.               VAREXP:
  761.                  if eqVar(e1^.varble, e2^.varble)
  762.                  then findExpDiff := false;
  763.               INTEXP:
  764.                  if e1^.intval = e2^.intval
  765.                  then findExpDiff := false;
  766.               APEXP:
  767.                  if e1^.optr = e2^.optr
  768.                  then findExpDiff :=
  769.                         findELDiff(e1^.args, e2^.args)
  770.            end (* case *)
  771.    end; (* findExpDiff *)
  772.  
  773. (* occursInExp - check whether variable v occurs in exp e        *)
  774.    function occursInExp (v: VARIABLE; e: EXP): Boolean;
  775.    var
  776.       occurs: Boolean;
  777.       el: EXPLIST;
  778.    begin
  779.       with e^ do
  780.          case etype of
  781.             INTEXP: occursInExp := false;
  782.             VAREXP: occursInExp := eqVar(v, varble);
  783.             APEXP:
  784.                begin
  785.                   occurs := false;
  786.                   el := args;
  787.                   while (el <> nil) and not occurs do
  788.                      begin
  789.                         occurs := occursInExp(v, el^.head);
  790.                         el := el^.tail
  791.                      end;
  792.                   occursInExp := occurs
  793.                end
  794.          end (* case and with *)
  795.    end; (* occursInExp *)
  796.  
  797. (* makeSubst - bind d1 to d2 in s, first checking if possible    *)
  798.    procedure makeSubst (d1, d2: EXP; var s: SUBST);
  799.    begin
  800.       if d1^.etype <> VAREXP
  801.       then s := nil
  802.       else if occursInExp(d1^.varble, d2)
  803.            then s := nil
  804.            else bindVar(d1^.varble, d2, s)
  805.    end; (* makeSubst *)
  806.  
  807. begin (* unify *)
  808.    sigma := emptySubst;
  809.    repeat
  810.       foundDiff := findELDiff(g1^.args, g2^.args);
  811.       varsubst := emptySubst;
  812.       if foundDiff
  813.       then if diff1^.etype = VAREXP
  814.            then makeSubst(diff1, diff2, varsubst)
  815.            else makeSubst(diff2, diff1, varsubst);
  816.       if foundDiff and (varsubst <> nil)
  817.       then begin
  818.               applyToGoal(varsubst, g1);
  819.               applyToGoal(varsubst, g2);
  820.               compose(sigma, varsubst)
  821.            end
  822.    until (not foundDiff) (* done *)
  823.         or (varsubst=nil); (* not unifiable *)
  824.    if varsubst = nil
  825.    then  unify := nil
  826.    else unify := sigma
  827. end; (* unify *)
  828.  
  829. (*****************************************************************
  830.  *                     EVALUATION                                *
  831.  *****************************************************************)
  832.  
  833. (* applyPrim - apply primitive predicate, modifying sigma        *)
  834. function applyPrim (g: GOAL; var sigma: SUBST): Boolean;
  835.  
  836. var
  837.    arglist: EXPLIST;
  838.    arg1, arg2, arg3: EXP;
  839.  
  840.    procedure applyArith (op: integer);
  841.    var i: integer;
  842.    begin
  843.       arg3 := arglist^.tail^.tail^.head;
  844.       if arg3^.etype = APEXP
  845.       then applyPrim := false
  846.       else begin
  847.               case op of
  848.                  1: i := arg1^.intval + arg2^.intval;
  849.                  2: i := arg1^.intval - arg2^.intval
  850.               end;
  851.               if arg3^.etype = INTEXP
  852.               then if arg3^.intval <> i
  853.                    then applyPrim := false
  854.                    else (* applyPrim already true *)
  855.               else bindVar(arg3^.varble, mkINTEXP(i), sigma)
  856.            end
  857.    end; (* applyArith *)
  858.  
  859. begin
  860.    sigma := emptySubst;
  861.    applyPrim := true;
  862.    arglist := g^.args;
  863.    if g^.pred = 4 (* print *)
  864.    then begin
  865.            prExplist(arglist);
  866.            writeln
  867.         end
  868.    else begin
  869.            arg1 := arglist^.head;
  870.            arg2 := arglist^.tail^.head;
  871.            if (arg1^.etype <> INTEXP) or (arg2^.etype <> INTEXP)
  872.            then applyPrim := false
  873.            else case g^.pred of
  874.                    1, 2: (* plus, minus *)
  875.                       applyArith(g^.pred);
  876.                    3: (* less *)
  877.                       if arg1^.intval >= arg2^.intval
  878.                       then applyPrim := false
  879.                 end (* case *)
  880.         end
  881. end; (* applyPrim *)
  882.  
  883. function copyGoal (g: GOAL; id: integer): GOAL; forward;
  884.  
  885. (* copyGoallist - copy gl; rename variables if id<>0             *)
  886. function copyGoallist (gl: GOALLIST; id: integer): GOALLIST;
  887. begin
  888.    if gl = nil
  889.    then copyGoallist := nil
  890.    else copyGoallist := mkGoallist(copyGoal(gl^.head, id),
  891.                                    copyGoallist(gl^.tail, id))
  892. end; (* copyGoallist *)
  893.  
  894. (* copyGoal - copy g; rename variables if id<>0                  *)
  895. function copyGoal;
  896.  
  897. (* copyExplist - copy el; rename variables if id<>0              *)
  898.    function copyExplist (el: EXPLIST): EXPLIST;
  899.  
  900. (* copyExp - copy e; rename variables if id<>0                   *)
  901.       function copyExp (e: EXP): EXP;
  902.       begin
  903.          case e^.etype of
  904.             INTEXP: copyExp := e;
  905.             VAREXP:
  906.                if id = 0
  907.                then copyExp :=
  908.                        mkVAREXP(mkVariable(e^.varble^.varname,
  909.                                              e^.varble^.varindex))
  910.                else copyExp :=
  911.                        mkVAREXP(mkVariable(e^.varble^.varname,
  912.                                              id));
  913.             APEXP: copyExp :=
  914.                        mkAPEXP(e^.optr, copyExplist(e^.args))
  915.          end (* case *)
  916.       end; (* copyExp *)
  917.  
  918.    begin (* copyExplist *)
  919.       if el = nil
  920.       then copyExplist := nil
  921.       else copyExplist :=
  922.                 mkExplist(copyExp(el^.head),
  923.                             copyExplist(el^.tail))
  924.    end; (* copyExplist *)
  925.  
  926. begin (* copyGoal *)
  927.    copyGoal := mkGoal(g^.pred, copyExplist(g^.args))
  928. end; (* copyGoal *)
  929.  
  930. (* append - append second to end of first, modifying first       *)
  931. function append (first, second: GOALLIST): GOALLIST;
  932. begin
  933.    if first = nil
  934.    then append := second
  935.    else begin
  936.            append := first;
  937.            while first^.tail <> nil do first := first^.tail;
  938.            first^.tail := second
  939.         end
  940. end; (* append *)
  941.  
  942. (* prove - prove goals gl; return subst; id used to rename var's *)
  943. function prove (gl: GOALLIST; id: integer): SUBST;
  944.  
  945. var
  946.    cl: CLAUSE;
  947.    sigma0, sigma1: SUBST;
  948.  
  949. (* tryClause - try to match goal g and clause head of c          *)
  950.    function tryClause (clgoal, g: GOAL): SUBST;
  951.    begin
  952.       tryClause := nil;
  953.       if (clgoal^.pred = g^.pred)
  954.         and (lengthEL(clgoal^.args) = lengthEL(g^.args))
  955.       then begin
  956.               clgoal := copyGoal(clgoal, id);
  957.               g := copyGoal(g, 0);
  958.               tryClause := unify(clgoal, g)
  959.            end
  960.    end; (* tryClause *)
  961.  
  962. (* proveRest - add subgoals to restofgoals and prove             *)
  963.    function proveRest (subgoals, restofgoals: GOALLIST): SUBST;
  964.    begin
  965.       subgoals := copyGoallist(subgoals, id);
  966.       applyToGoallist(sigma0, subgoals);
  967.       restofgoals := copyGoallist(restofgoals, 0);
  968.       applyToGoallist(sigma0, restofgoals);
  969.       proveRest := prove(append(subgoals, restofgoals), id+1)
  970.    end; (* proveRest *)
  971.  
  972. begin (* prove *)
  973.    if gl = nil
  974.    then prove := emptySubst
  975.    else begin
  976.            if gl^.head^.pred <= numBuiltins
  977.            then if applyPrim(gl^.head, sigma0)
  978.                 then begin
  979.                         applyToGoallist(sigma0, gl^.tail);
  980.                         sigma1 := prove(gl^.tail, id+1)
  981.                      end
  982.                 else sigma1 := nil
  983.            else begin
  984.                    sigma1 := nil;
  985.                    cl := clauses;
  986.                    while (cl <> nil) and (sigma1 = nil) do begin
  987.                       sigma0 := tryClause(cl^.lhs, gl^.head);
  988.                       if sigma0 <> nil
  989.                       then sigma1 := proveRest(cl^.rhs, gl^.tail);
  990.                       cl := cl^.nextclause
  991.                       end (* while *)
  992.                 end;
  993.            if sigma1 = nil
  994.            then prove := nil
  995.            else begin
  996.                    compose(sigma0, sigma1);
  997.                    prove := sigma0
  998.                 end
  999.         end
  1000. end; (* prove *)
  1001.          
  1002. (*****************************************************************
  1003.  *                     READ-EVAL-PRINT LOOP                      *
  1004.  *****************************************************************)
  1005.  
  1006. begin (* prolog main *)
  1007.    initNames;
  1008.  
  1009.    quittingtime := false;
  1010. 99:
  1011.    while not quittingtime do begin
  1012.       reader;
  1013.       if matches(pos, 4, 'quit                ')
  1014.       then quittingtime := true
  1015.       else if matches(skipblanks(pos+1), 5, 'infer               ')
  1016.            then begin
  1017.                    parseClause;
  1018.                    writeln
  1019.                 end
  1020.            else begin
  1021.                    toplevelGoal := parseQuery;
  1022.                    writeln;
  1023.                    if prove(toplevelGoal, 1) = nil
  1024.                    then writeln('Not satisfied')
  1025.                    else writeln('Satisfied');
  1026.                    writeln
  1027.                 end
  1028.       end
  1029. end. (* prolog *)
  1030.