pmintrfc.red 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. module pmintrfc; % Interface for pattern matcher.
  2. % Author: Kevin McIsaac.
  3. % Changes by Rainer M. Schoepf 1991.
  4. % For some reason, this doesn't like being compiled as a module.
  5. % REDUCE syntax for pattern matching.
  6. %
  7. % ?a
  8. % This is an ordinary pattern matching variable. It can any value.
  9. %
  10. % ??a
  11. % This is a segment pattern variable. I can take any value as does ?a
  12. % or a set of values.
  13. %
  14. % ?a_=cond
  15. % ?a can only be matched is the condition does not evaluate to false
  16. %
  17. % exp1 -> exp2
  18. % exp1 is replaced by exp2
  19. %
  20. % exp1 --> exp2
  21. % exp1 is replaced by exp2, RHS is quoted. exp2 is simplified after
  22. % replacement
  23. %
  24. % M(exp,pat)
  25. % Returns a list of replacements for pm variables in pat such that pat
  26. % and exp are equal. Where defined the properties of symmetry, assoc-
  27. % iativity and the identity element are used to match the expressions.
  28. %
  29. % S(exp,rep,rpt:1,depth:Inf) or S(exp,{rep1,rep2,...},rpt:1,depth:Inf)
  30. % The lhs of rep is matched against exp and subexpressions of exp.
  31. % When a match is found the replacements for pm variables in rhs are
  32. % substituted into the lhs and the resultant expression is used as a
  33. % replacement. This is done to a maximum (tree) depth of dept, with a
  34. % maximum number of repeats rpt, to a (tree) depth of dept.
  35. % S(exp,rep,depth:Inf) or S(exp,{rep1,rep2,...},depth:Inf)
  36. % Shorthand notation for S with Inf number of rpt's
  37. %
  38. % exp1 :- exp2
  39. % exp1 is added to a global list of automatic replacements. Most
  40. % specific rules are ordered before less specific rules. If a rule
  41. % already exists the the rule is replaced unless exp2 is null in which
  42. % case the rule is deleted.
  43. %
  44. % exp1 ::- exp2
  45. % as above except the RHS is quoted.
  46. %
  47. fluid '(!*trpm rpt subfg!* substitution varstack!*);
  48. switch trpm;
  49. put('m,'psopfn,'mx);
  50. symbolic procedure mx u; m1(reval car u,reval cadr u);
  51. symbolic procedure m1(exp, temp);
  52. begin scalar substitution, mmatch, count, freevars;
  53. count := 0;
  54. freevars := idsort union(findnewvars temp,nil);
  55. substitution := if freevars then freevars else t;
  56. for each j in freevars do newenv j;
  57. mmatch := amatch(temp, exp, t, nil);
  58. for each j in freevars do restorenv j;
  59. if mmatch then return
  60. if freevars then 'list . for each j in pair(freevars, mmatch)
  61. collect list('rep, car j, cdr j)
  62. else t
  63. end;
  64. symbolic procedure fixreplist(repset);
  65. % Check that repset is properly formed and add multi-generic
  66. % variables to assoc functions.
  67. begin scalar replist;
  68. if car(repset) memq '(rep repd) then replist := list(repset)
  69. else replist := cdr repset;
  70. replist := for each rep in replist collect fixrep(rep);
  71. return replist
  72. end;
  73. Comment It is necessary to replace all free variables by unique ones
  74. in order to avoid confusion during the superset operation.
  75. To this end we generate replace them by special gensyms
  76. before putting them in the rules database. This is not
  77. visible to the user;
  78. fluid '(pm!:gensym!-count!*);
  79. symbolic (pm!:gensym!-count!* := 0);
  80. symbolic procedure pm!:gensym;
  81. compress ('!? . '!_ .
  82. explode (pm!:gensym!-count!* := pm!:gensym!-count!* + 1));
  83. fluid '(freevarlist!*);
  84. symbolic procedure make!-unique!-freevars form;
  85. if atom form then
  86. if get(form,'gen) then begin scalar x;
  87. x := atsoc (form, freevarlist!*);
  88. if null x then << x := (form . pm!:gensym());
  89. put (cdr x, 'gen, t);
  90. freevarlist!* := x . freevarlist!*>>;
  91. return cdr x
  92. end
  93. else form
  94. else for each x in form collect make!-unique!-freevars x;
  95. symbolic procedure fixrep(repl);
  96. << (repl := make!-unique!-freevars repl) where freevarlist!* := nil;
  97. % Should check if the extra multi-generic variables are required.
  98. if flagp(caadr repl,'assoc) then
  99. if flagp(caadr repl,'symmetric) then
  100. list(car repl,append(cadr repl,list('!?!?!;)),
  101. list(caadr repl,caddr repl,'!?!?!;))
  102. else
  103. list(car repl,caadr(repl) .
  104. ('!?!?!^ . append(cdadr repl,list('!?!?!;))),
  105. list(caadr repl,'!?!?!^,caddr repl,'!?!?!;))
  106. else repl >>;
  107. put('s,'psopfn,'sx);
  108. symbolic procedure sx arg;
  109. % Fill in args for s0. Default: repeat 1, depth Inf.
  110. reval
  111. s0(reval car arg, reval cadr arg,
  112. if cddr arg then reval caddr arg else 1,
  113. if cddr arg and cdddr arg then reval car cdddr arg
  114. else 'inf);
  115. put('si,'psopfn,'si!-x);
  116. symbolic procedure si!-x arg;
  117. % Fill in args for s0. Default: repeat Inf, depth Inf.
  118. reval
  119. s0(reval car arg,reval cadr arg, 'inf,
  120. if cddr arg then reval caddr arg else 'inf);
  121. symbolic procedure s0(exp, repset,rpt,depth);
  122. % Breadth first search. Rpt is passed as a fluid.
  123. if length repset <= 1 or not memq(car repset,'(rep repd list))
  124. then exp
  125. else if (depth neq 'inf and depth < 0)
  126. or (rpt neq 'inf and rpt <=0) or atom(exp) then exp
  127. else sbreadth(exp,fixreplist repset,depth) ;
  128. symbolic procedure sbreadth(exp,replist,depth);
  129. % Substitute a set of replacements into the root expression until
  130. % expression stops changing, then recurse on all the sub expressions.
  131. <<exp:= sroot(exp,replist);
  132. if (depth neq 'inf and depth <= 0)
  133. or (rpt neq 'inf and rpt <=0) or atom(exp) then exp
  134. else ssbreadth(exp,replist,
  135. if depth neq 'inf then depth-1 else depth)>>;
  136. symbolic procedure ssbreadth(exp,replist,depth);
  137. begin scalar newexp, new, reps;
  138. if (depth neq 'inf and depth < 0)
  139. or (rpt neq 'inf and rpt <= 0) or atom(exp) then return exp;
  140. repeat
  141. begin
  142. new := nil;
  143. reps := replist;
  144. a: exp := reval for each subexp in exp collect
  145. << newexp := sroot1(subexp,car reps) ;
  146. new := new or (subexp neq newexp);
  147. newexp
  148. >>;
  149. if not (new or null(reps := cdr reps)) then go to a;
  150. end
  151. until(atom exp or not new);
  152. return
  153. if (depth neq 'inf and depth <= 0)
  154. or (rpt neq 'inf and rpt <= 0) or atom(exp) then exp
  155. else for each subexp in exp collect
  156. ssbreadth(subexp,replist,
  157. if depth neq 'inf then depth-1 else depth)
  158. end;
  159. put('sd,'psopfn,'sdx);
  160. symbolic procedure sdx arg;
  161. % Fill in args for sd0. Default: repeat 1, depth inf.
  162. reval
  163. sd0(reval car arg,reval cadr arg,
  164. if cddr arg then reval caddr arg else 1,
  165. if cddr arg and cdddr arg then reval car cdddr arg
  166. else 'inf);
  167. put('sdi,'psopfn,'sdi);
  168. symbolic procedure sdi arg;
  169. % Fill in args for sd0. Default: repeat Inf, depth Inf.
  170. reval
  171. sd0(reval car arg,reval cadr arg, 'inf,
  172. if cddr arg then reval caddr arg else 'inf);
  173. symbolic procedure sd0(exp, repset,rpt,depth);
  174. % Depth first search.
  175. if length repset <= 1 or not memq(car repset,'(rep repd list))
  176. then exp
  177. else if (depth neq 'inf and depth < 0)
  178. or (rpt neq 'inf and rpt <= 0) or atom(exp) then exp
  179. else sdepth(exp,fixreplist repset,depth) ;
  180. symbolic procedure sdepth(exp,replist,depth);
  181. <<exp:= sroot(exp,replist);
  182. if (depth neq 'inf and depth <= 0)
  183. or (rpt neq 'inf and rpt <= 0) or atom(exp) then exp
  184. else car(exp) . for each subterm in cdr exp collect
  185. sdepth(subterm,replist,
  186. if depth neq 'inf then depth-1 else depth)>>;
  187. symbolic procedure sroot(exp,replist);
  188. % Substitute a set of replacements into a root expression until the
  189. % expression stops changing. When a replacement succeeds the
  190. % substitution process restarts on the new expression at the
  191. % beginning of the replacement list.
  192. begin scalar oldexp, reps;
  193. if (rpt neq 'inf and rpt <=0) or atom(exp) then return exp;
  194. repeat
  195. begin
  196. oldexp := exp;
  197. reps := replist;
  198. a: exp := sroot1(exp,car reps);
  199. if not(exp neq oldexp or null(reps := cdr reps)) then go to a;
  200. if exp neq oldexp then exp := reval exp
  201. end
  202. until(atom exp or exp eq oldexp);
  203. return exp;
  204. end;
  205. symbolic procedure sroot1(exp,rep);
  206. % Try to substitute a single replacement into a root expression once
  207. % only.
  208. begin scalar freevars,substitution,mmatch;
  209. if (rpt neq 'inf and rpt <=0) or
  210. atom(exp) or (car(exp) neq caadr(rep)) then return exp;
  211. freevars := union(findnewvars cadr rep,nil);
  212. substitution := caddr rep;
  213. for each j in freevars do newenv j;
  214. if !*trpm then <<write("Trying rule "); rprint(rep);
  215. write("against "); rprint(exp)>>;
  216. mmatch := amatch(cadr rep, exp, t,nil);
  217. if !*trpm
  218. then <<if mmatch then <<write("producing ");
  219. rprint(mmatch := embed!-null!-fn mmatch)>>
  220. else <<write("failed"); terpri()>>;
  221. terpri()>>;
  222. for each j in freevars do restorenv j;
  223. return if mmatch then
  224. << if (rpt neq 'inf) then rpt := rpt - 1;
  225. embed!-null!-fn mmatch>>
  226. else exp
  227. end;
  228. symbolic procedure embed!-null!-fn u;
  229. if atom u then u
  230. else for each j in u conc
  231. if atom j then list(j)
  232. else if car j eq 'null!-fn then embed!-null!-fn cdr j
  233. else list(embed!-null!-fn j);
  234. algebraic operator null!-fn;
  235. % Code for printing null-fn(a,b,...) as [a,b,...]. Modeled on LIST code.
  236. put('null!-fn,'prifn,'null!-fn!-pri);
  237. fluid '(orig!* posn!*);
  238. symbolic procedure null!-fn!-pri l;
  239. % This definition is basically that of INPRINT, except that it
  240. % decides when to split at the comma by looking at the size of
  241. % the argument.
  242. (begin scalar split,u;
  243. u := l;
  244. l := cdr l;
  245. prin2!* "[";
  246. orig!* := if posn!*<18 then posn!* else orig!*+3;
  247. if null l then go to b;
  248. split := treesizep(l,40); % 40 is arbitrary choice.
  249. a: maprint(negnumberchk car l,0);
  250. l := cdr l;
  251. if null l then go to b;
  252. oprin '!*comma!*;
  253. if split then terpri!* t;
  254. go to a;
  255. b: prin2!* "]";
  256. return u
  257. end)
  258. where orig!* := orig!*;
  259. % Assignments and automatic replacements.
  260. symbolic operator rset;
  261. symbolic procedure rset(temp,exp);
  262. % Add new rule to rule list. If RHS is null then delete rule.
  263. if atom temp then setk(temp,exp)
  264. else begin scalar oldsubfg!*,varstack!*;
  265. %rebind subfg. Don't do this do that(yuck..lisp..)
  266. % rebind varstack!* since the template is simplified again
  267. oldsubfg!* := subfg!*; subfg!* := nil;
  268. temp := reval temp;
  269. put(car temp,'opmtch,
  270. rinsert(fixrep('rset . list(temp,exp)),
  271. get(car temp,'opmtch)));
  272. subfg!* := oldsubfg!*;
  273. return exp
  274. end;
  275. symbolic operator rsetd;
  276. symbolic procedure rsetd(temp,exp);
  277. % Delayed version.
  278. if atom temp then 'hold . setk(temp,exp)
  279. else 'hold . list
  280. begin scalar oldsubfg!*,varstack!*;
  281. %rebind subfg. Don't do this do that(yuck..lisp..)
  282. oldsubfg!* := subfg!*; subfg!* := nil;
  283. temp := reval temp;
  284. put(car temp,'opmtch,
  285. rinsert(fixrep('rsetd . list(temp,exp)),
  286. get(car temp,'opmtch)));
  287. subfg!* := oldsubfg!*;
  288. return exp
  289. end;
  290. symbolic procedure rinsert(rule,rulelist);
  291. % Insert rule in rule list so that most specific rules are found first.
  292. % Use super-set idea, due to Grief. If an equivalent rule exits then
  293. % replace with new rule. A new rule will be placed as far down the rule
  294. % list as possible If the RHS of rule is nil then delete the rule.
  295. if null rulelist or not atom caar rulelist then rule . rulelist
  296. else
  297. (lambda ss;
  298. if ss eq 'equal then
  299. if cadr rule then rule . cdr(rulelist)
  300. else cdr(rulelist)
  301. else if ss eq 't then rule . rulelist
  302. else car(rulelist) . rinsert(rule,cdr rulelist))
  303. superset(cadar rulelist,cadr rule);
  304. symbolic procedure superset(temp1,temp2);
  305. begin scalar mmatch;
  306. mmatch := m1(temp2,temp1);
  307. return(
  308. if null mmatch then nil
  309. else if mmatch eq 't then 'equal
  310. else if not bound2gen(cdr mmatch) then t
  311. else if null (mmatch := m1(temp1,temp1)) then t
  312. else 'equal)
  313. end;
  314. symbolic procedure bound2gen(replist);
  315. % True if all Generic variables are bound to generic variables.
  316. null replist or (genp(caddar replist) and bound2gen(cdr replist));
  317. symbolic operator arep;
  318. symbolic procedure arep(replist);
  319. % Add the replacements in replist to the list of automatically
  320. % applied replacements.
  321. if atom replist then replist
  322. else if car replist eq 'rep
  323. then list('rset ,cadr replist,caddr replist)
  324. else if car replist eq 'repd
  325. then list('rsetd,cadr replist,caddr replist)
  326. else if car replist eq 'list then
  327. % '!*set!* . for each rep in cdr replist collect arep(rep)
  328. 'list . for each rep in cdr replist collect arep(rep)
  329. else nil;
  330. symbolic operator drep;
  331. symbolic procedure drep(replist);
  332. % Delete the replacements in replist from the list of automatically
  333. % applied replacements.
  334. if atom replist then replist
  335. else if car replist eq 'rep then list('rset ,cadr replist,nil)
  336. else if car replist eq 'repd then list('rsetd,cadr replist,nil)
  337. else if car replist eq 'list then
  338. % '!*set!*.for each rep in cdr replist collect Drep(rep)
  339. 'list . for each rep in cdr replist collect drep(rep)
  340. else nil;
  341. symbolic procedure opmtch(exp);
  342. begin scalar oldexp, replist, rpt;
  343. rpt := 'inf;
  344. replist := get(car exp, 'opmtch);
  345. if null(replist) or null subfg!* then return nil;
  346. oldexp := exp;
  347. repeat
  348. exp := if (atom caar replist) then sroot1(exp, car replist)
  349. else oldmtch(exp,car replist)
  350. until (exp neq oldexp or null(replist := cdr replist));
  351. return if exp eq oldexp then nil else exp
  352. end;
  353. symbolic procedure oldmtch(exp,rule);
  354. begin scalar x, y;
  355. y := mcharg(cdr exp, car rule,car exp);
  356. while (y and null x) do
  357. <<x := if eval subla(car y,cdadr rule)
  358. then subla(car y,caddr rule);
  359. y := cdr y>>;
  360. return if x then x else exp
  361. end;
  362. put('!?,'gen,t);
  363. put('!?!?!;,'mgen,t);
  364. put('!?!?!$,'mgen,t);
  365. put('!?!?!^,'mgen,t);
  366. symbolic operator prop!-alg;
  367. newtok '((!_) prop!-alg);
  368. symbolic procedure prop!-alg(f);
  369. begin scalar x;
  370. x := prop f;
  371. while x do <<prin2(car x); prin2(" "); print(cadr x); print(" ");
  372. x := cddr x>>
  373. end;
  374. symbolic operator preceq;
  375. symbolic procedure preceq(u,v);
  376. % Give u same precedence as v.
  377. <<put(u,'op,get(v,'op));
  378. put(u,'infix,get(v,'infix));>>;
  379. newtok '((!: !- ) rset);
  380. newtok '((!: !: !- ) rsetd);
  381. newtok '((!- !>) rep);
  382. newtok '((!- !- !>) repd);
  383. newtok '((!_ !=) such!-that);
  384. flag ('(such!-that), 'spaced); % _ adjacent to symbols causes problems.
  385. algebraic;
  386. infix :-;
  387. nosimp(:-,'(t nil));
  388. %precedence :-,:=; %can't do this
  389. infix ::-;
  390. nosimp(::-,'(t t));
  391. precedence rsetd,rset;
  392. infix ->;
  393. precedence ->,rsetd;
  394. infix -->;
  395. nosimp(-->,'(nil t));
  396. precedence -->,->;
  397. infix _=;
  398. nosimp(_=,'(nil t));
  399. precedence _=,-->;
  400. operator hold;
  401. nosimp(hold,t);
  402. flag('(rset rsetd rep repd such!-that), 'right);
  403. preceq(rsetd,rset);
  404. preceq(-->,->);
  405. flag('(plus times expt),'assoc);
  406. endmodule;
  407. end;