patmatch.lisp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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. (defun variable-p (x)
  9. "Is x a variable (a symbol beginning with `?')?"
  10. (and (symbolp x) (equal (elt (symbol-name x) 0) #\?)))
  11. (defun pat-match (pattern input &optional (bindings no-bindings))
  12. "Match pattern against input in the context of the bindings"
  13. (cond ((eq bindings fail) fail)
  14. ((variable-p pattern)
  15. (match-variable pattern input bindings))
  16. ((eql pattern input) bindings)
  17. ((segment-pattern-p pattern)
  18. (segment-matcher pattern input bindings))
  19. ((single-pattern-p pattern) ; ***
  20. (single-matcher pattern input bindings)) ; ***
  21. ((and (consp pattern) (consp input))
  22. (pat-match (rest pattern) (rest input)
  23. (pat-match (first pattern) (first input)
  24. bindings)))
  25. (t fail)))
  26. (setf (get '?is 'single-match) 'match-is)
  27. (setf (get '?or 'single-match) 'match-or)
  28. (setf (get '?and 'single-match) 'match-and)
  29. (setf (get '?not 'single-match) 'match-not)
  30. (setf (get '?* 'segment-match) 'segment-match)
  31. (setf (get '?+ 'segment-match) 'segment-match+)
  32. (setf (get '?? 'segment-match) 'segment-match?)
  33. (setf (get '?if 'segment-match) 'match-if)
  34. (defun segment-pattern-p (pattern)
  35. "Is this a segment-matching pattern like ((?* var) . pat)?"
  36. (and (consp pattern) (consp (first pattern))
  37. (symbolp (first (first pattern)))
  38. (segment-match-fn (first (first pattern)))))
  39. (defun single-pattern-p (pattern)
  40. "Is this a single-matching pattern?
  41. E.g. (?is x predicate) (?and . patterns) (?or . patterns)."
  42. (and (consp pattern)
  43. (single-match-fn (first pattern))))
  44. (defun segment-matcher (pattern input bindings)
  45. "Call the right function for this kind of segment pattern."
  46. (funcall (segment-match-fn (first (first pattern)))
  47. pattern input bindings))
  48. (defun single-matcher (pattern input bindings)
  49. "Call the right function for this kind of single pattern."
  50. (funcall (single-match-fn (first pattern))
  51. (rest pattern) input bindings))
  52. (defun segment-match-fn (x)
  53. "Get the segment-match function for x,
  54. if it is a symbol that has one."
  55. (when (symbolp x) (get x 'segment-match)))
  56. (defun single-match-fn (x)
  57. "Get the single-match function for x,
  58. if it is a symbol that has one."
  59. (when (symbolp x) (get x 'single-match)))
  60. (defun match-is (var-and-pred input bindings)
  61. "Succeed and bind var if the input satisfies pred,
  62. where var-and-pred is the list (var pred)."
  63. (let* ((var (first var-and-pred))
  64. (pred (second var-and-pred))
  65. (new-bindings (pat-match var input bindings)))
  66. (if (or (eq new-bindings fail)
  67. (not (funcall pred input)))
  68. fail
  69. new-bindings)))
  70. (defun match-and (patterns input bindings)
  71. "Succeed if all the patterns match the input."
  72. (cond ((eq bindings fail) fail)
  73. ((null patterns) bindings)
  74. (t (match-and (rest patterns) input
  75. (pat-match (first patterns) input
  76. bindings)))))
  77. (defun match-or (patterns input bindings)
  78. "Succeed if any one of the patterns match the input."
  79. (if (null patterns)
  80. fail
  81. (let ((new-bindings (pat-match (first patterns)
  82. input bindings)))
  83. (if (eq new-bindings fail)
  84. (match-or (rest patterns) input bindings)
  85. new-bindings))))
  86. (defun match-not (patterns input bindings)
  87. "Succeed if none of the patterns match the input.
  88. This will never bind any variables."
  89. (if (match-or patterns input bindings)
  90. fail
  91. bindings))
  92. (defun segment-match (pattern input bindings &optional (start 0))
  93. "Match the segment pattern ((?* var) . pat) against input."
  94. (let ((var (second (first pattern)))
  95. (pat (rest pattern)))
  96. (if (null pat)
  97. (match-variable var input bindings)
  98. (let ((pos (first-match-pos (first pat) input start)))
  99. (if (null pos)
  100. fail
  101. (let ((b2 (pat-match
  102. pat (subseq input pos)
  103. (match-variable var (subseq input 0 pos)
  104. bindings))))
  105. ;; If this match failed, try another longer one
  106. (if (eq b2 fail)
  107. (segment-match pattern input bindings (+ pos 1))
  108. b2)))))))
  109. (defun first-match-pos (pat1 input start)
  110. "Find the first position that pat1 could possibly match input,
  111. starting at position start. If pat1 is non-constant, then just
  112. return start."
  113. (cond ((and (atom pat1) (not (variable-p pat1)))
  114. (position pat1 input :start start :test #'equal))
  115. ((<= start (length input)) start) ;*** fix, rjf 10/1/92 (was <)
  116. (t nil)))
  117. (defun segment-match+ (pattern input bindings)
  118. "Match one or more elements of input."
  119. (segment-match pattern input bindings 1))
  120. (defun segment-match? (pattern input bindings)
  121. "Match zero or one element of input."
  122. (let ((var (second (first pattern)))
  123. (pat (rest pattern)))
  124. (or (pat-match (cons var pat) input bindings)
  125. (pat-match pat input bindings))))
  126. (defun match-if (pattern input bindings)
  127. "Test an arbitrary expression involving variables.
  128. The pattern looks like ((?if code) . rest)."
  129. ;; *** fix, rjf 10/1/92 (used to eval binding values)
  130. (and (progv (mapcar #'car bindings)
  131. (mapcar #'cdr bindings)
  132. (eval (second (first pattern))))
  133. (pat-match (rest pattern) input bindings)))
  134. (defun pat-match-abbrev (symbol expansion)
  135. "Define symbol as a macro standing for a pat-match pattern."
  136. (setf (get symbol 'expand-pat-match-abbrev)
  137. (expand-pat-match-abbrev expansion)))
  138. (defun expand-pat-match-abbrev (pat)
  139. "Expand out all pattern matching abbreviations in pat."
  140. (cond ((and (symbolp pat) (get pat 'expand-pat-match-abbrev)))
  141. ((atom pat) pat)
  142. (t (cons (expand-pat-match-abbrev (first pat))
  143. (expand-pat-match-abbrev (rest pat))))))
  144. (defun rule-based-translator
  145. (input rules &key (matcher 'pat-match)
  146. (rule-if #'first) (rule-then #'rest) (action #'sublis))
  147. "Find the first rule in rules that matches input,
  148. and apply the action to that rule."
  149. (some
  150. #'(lambda (rule)
  151. (let ((result (funcall matcher (funcall rule-if rule)
  152. input)))
  153. (if (not (eq result fail))
  154. (funcall action result (funcall rule-then rule)))))
  155. rules))