1
0

patmatch.lisp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. ;;;; -*- Mode: Lisp; Syntax: Common-Lisp -*-
  2. ;;;; Code from Paradigms of AI Programming
  3. ;;;; Copyright (c) 1991 Peter Norvig
  4. ;;;; File pat-match.lisp: Pattern matcher from section 6.2
  5. ;;; Two bug fixes By Richard Fateman, rjf@cs.berkeley.edu October 92.
  6. ;;; The basic are in auxfns.lisp; look for "PATTERN MATCHING FACILITY"
  7. (in-package #:chatikbot)
  8. (defconstant fail nil "Indicates pat-match failure")
  9. (defparameter no-bindings '((t . t))
  10. "Indicates pat-match success, with no variables.")
  11. (defun get-binding (var bindings)
  12. "Find a (variable . value) pair in a binding list."
  13. (assoc var bindings))
  14. (defun binding-val (binding)
  15. "Get the value part of a single binding."
  16. (cdr binding))
  17. (defun extend-bindings (var val bindings)
  18. "Add a (var . value) pair to a binding list."
  19. (cons (cons var val) bindings))
  20. (defun match-variable (var input bindings)
  21. "Does VAR match input? Uses (or updates) and returns bindings."
  22. (let ((binding (get-binding var bindings)))
  23. (cond ((not binding) (extend-bindings var input bindings))
  24. ((equal input (binding-val binding)) bindings)
  25. (t fail))))
  26. (defun variable-p (x)
  27. "Is x a variable (a symbol beginning with `?')?"
  28. (and (symbolp x) (equal (elt (symbol-name x) 0) #\?)))
  29. (defun pat-match (pattern input &optional (bindings no-bindings))
  30. "Match pattern against input in the context of the bindings"
  31. (cond ((eq bindings fail) fail)
  32. ((variable-p pattern)
  33. (match-variable pattern input bindings))
  34. ((eql pattern input) bindings)
  35. ((segment-pattern-p pattern)
  36. (segment-matcher pattern input bindings))
  37. ((single-pattern-p pattern) ; ***
  38. (single-matcher pattern input bindings)) ; ***
  39. ((and (consp pattern) (consp input))
  40. (pat-match (rest pattern) (rest input)
  41. (pat-match (first pattern) (first input)
  42. bindings)))
  43. (t fail)))
  44. (setf (get '?is 'single-match) 'match-is)
  45. (setf (get '?or 'single-match) 'match-or)
  46. (setf (get '?and 'single-match) 'match-and)
  47. (setf (get '?not 'single-match) 'match-not)
  48. (setf (get '?* 'segment-match) 'segment-match)
  49. (setf (get '?+ 'segment-match) 'segment-match+)
  50. (setf (get '?? 'segment-match) 'segment-match?)
  51. (setf (get '?if 'segment-match) 'match-if)
  52. (defun segment-pattern-p (pattern)
  53. "Is this a segment-matching pattern like ((?* var) . pat)?"
  54. (and (consp pattern) (consp (first pattern))
  55. (symbolp (first (first pattern)))
  56. (segment-match-fn (first (first pattern)))))
  57. (defun single-pattern-p (pattern)
  58. "Is this a single-matching pattern?
  59. E.g. (?is x predicate) (?and . patterns) (?or . patterns)."
  60. (and (consp pattern)
  61. (single-match-fn (first pattern))))
  62. (defun segment-matcher (pattern input bindings)
  63. "Call the right function for this kind of segment pattern."
  64. (funcall (segment-match-fn (first (first pattern)))
  65. pattern input bindings))
  66. (defun single-matcher (pattern input bindings)
  67. "Call the right function for this kind of single pattern."
  68. (funcall (single-match-fn (first pattern))
  69. (rest pattern) input bindings))
  70. (defun segment-match-fn (x)
  71. "Get the segment-match function for x,
  72. if it is a symbol that has one."
  73. (when (symbolp x) (get x 'segment-match)))
  74. (defun single-match-fn (x)
  75. "Get the single-match function for x,
  76. if it is a symbol that has one."
  77. (when (symbolp x) (get x 'single-match)))
  78. (defun match-is (var-and-pred input bindings)
  79. "Succeed and bind var if the input satisfies pred,
  80. where var-and-pred is the list (var pred)."
  81. (let* ((var (first var-and-pred))
  82. (pred (second var-and-pred))
  83. (new-bindings (pat-match var input bindings)))
  84. (if (or (eq new-bindings fail)
  85. (not (funcall pred input)))
  86. fail
  87. new-bindings)))
  88. (defun match-and (patterns input bindings)
  89. "Succeed if all the patterns match the input."
  90. (cond ((eq bindings fail) fail)
  91. ((null patterns) bindings)
  92. (t (match-and (rest patterns) input
  93. (pat-match (first patterns) input
  94. bindings)))))
  95. (defun match-or (patterns input bindings)
  96. "Succeed if any one of the patterns match the input."
  97. (if (null patterns)
  98. fail
  99. (let ((new-bindings (pat-match (first patterns)
  100. input bindings)))
  101. (if (eq new-bindings fail)
  102. (match-or (rest patterns) input bindings)
  103. new-bindings))))
  104. (defun match-not (patterns input bindings)
  105. "Succeed if none of the patterns match the input.
  106. This will never bind any variables."
  107. (if (match-or patterns input bindings)
  108. fail
  109. bindings))
  110. (defun segment-match (pattern input bindings &optional (start 0))
  111. "Match the segment pattern ((?* var) . pat) against input."
  112. (let ((var (second (first pattern)))
  113. (pat (rest pattern)))
  114. (if (null pat)
  115. (match-variable var input bindings)
  116. (let ((pos (first-match-pos (first pat) input start)))
  117. (if (null pos)
  118. fail
  119. (let ((b2 (pat-match
  120. pat (subseq input pos)
  121. (match-variable var (subseq input 0 pos)
  122. bindings))))
  123. ;; If this match failed, try another longer one
  124. (if (eq b2 fail)
  125. (segment-match pattern input bindings (+ pos 1))
  126. b2)))))))
  127. (defun first-match-pos (pat1 input start)
  128. "Find the first position that pat1 could possibly match input,
  129. starting at position start. If pat1 is non-constant, then just
  130. return start."
  131. (cond ((and (atom pat1) (not (variable-p pat1)))
  132. (position pat1 input :start start :test #'equal))
  133. ((<= start (length input)) start) ;*** fix, rjf 10/1/92 (was <)
  134. (t nil)))
  135. (defun segment-match+ (pattern input bindings)
  136. "Match one or more elements of input."
  137. (segment-match pattern input bindings 1))
  138. (defun segment-match? (pattern input bindings)
  139. "Match zero or one element of input."
  140. (let ((var (second (first pattern)))
  141. (pat (rest pattern)))
  142. (or (pat-match (cons var pat) input bindings)
  143. (pat-match pat input bindings))))
  144. (defun match-if (pattern input bindings)
  145. "Test an arbitrary expression involving variables.
  146. The pattern looks like ((?if code) . rest)."
  147. ;; *** fix, rjf 10/1/92 (used to eval binding values)
  148. (and (progv (mapcar #'car bindings)
  149. (mapcar #'cdr bindings)
  150. (eval (second (first pattern))))
  151. (pat-match (rest pattern) input bindings)))
  152. (defun pat-match-abbrev (symbol expansion)
  153. "Define symbol as a macro standing for a pat-match pattern."
  154. (setf (get symbol 'expand-pat-match-abbrev)
  155. (expand-pat-match-abbrev expansion)))
  156. (defun expand-pat-match-abbrev (pat)
  157. "Expand out all pattern matching abbreviations in pat."
  158. (cond ((and (symbolp pat) (get pat 'expand-pat-match-abbrev)))
  159. ((atom pat) pat)
  160. (t (cons (expand-pat-match-abbrev (first pat))
  161. (expand-pat-match-abbrev (rest pat))))))
  162. (defun rule-based-translator
  163. (input rules &key (matcher 'pat-match)
  164. (rule-if #'first) (rule-then #'rest) (action #'sublis))
  165. "Find the first rule in rules that matches input,
  166. and apply the action to that rule."
  167. (some
  168. #'(lambda (rule)
  169. (let ((result (funcall matcher (funcall rule-if rule)
  170. input)))
  171. (if (not (eq result fail))
  172. (funcall action result (funcall rule-then rule)))))
  173. rules))