(defun infix->prefix-single (infix-expression)
(list (second infix-expression)
(first infix-expression)
(third infix-expression)))
(defun infix->prefix-single (infix-expression)
(mapcar (lambda (f) (funcall f infix-expression))
'(second first third)))
(defun apl-infix->prefix (expression)
(infix->prefix-single
(list (car expression)
(cadr expression)
(cddr expression))))
(defun apl-infix->prefix (expression)
(cond ((null (cdr expression)) expression)
(t (infix->prefix-single
(list (car expression)
(cadr expression)
(apl-infix->prefix (cddr expression)))))))
(defparameter *operators* '(+ - * /))
(defun find-lowest-precedence-operator (expression)
(or (position (first *operators*) expression)
(position (second *operators*) expression)
(position (third *operators*) expression)
(position (fourth *operators*) expression)))
(defun find-lowest-precedence-operator (expression)
(dolist (operator *operators*)
(let ((index (position operator expression)))
(when index (return-from find-lowest-precedence-operator index)))))
(defun find-lowest-precedence-operator (expression)
(some #'identity
(list (position (first *operators*) expression)
(position (second *operators*) expression)
(position (third *operators*) expression)
(position (fourth *operators*) expression))))
(defun find-lowest-precedence-operator (expression)
(some #'identity
(mapcar (lambda (operator)
(position operator expression))
*operators*)))
(defun split (list index)
(assert (<= 0 index (1- (length list)))
() "Cannot split before or after the bounds of the list")
(values (subseq list 0 index)
(elt list index)
(subseq list (1+ index))))
(defun infix->prefix (expression)
(let ((split-index (find-lowest-precedence-operator expression)))
(cond (split-index (multiple-value-bind (before operator after) (split expression split-index)
(list operator
(infix->prefix before)
(infix->prefix after))))
(t (car expression)))))
(defun pattern-variable-p (exp)
(and (consp exp)
(eq '? (car exp))
(cadr exp)))
(defun assoc-conflict (variable-value alist)
(let ((value (assoc (car variable-value) alist)))
(if value (not (equal (cdr variable-value) (cdr value))))))
(defun match (pattern expression &optional bindings)
(cond ((pattern-variable-p pattern) (when (not (null expression))
(let ((new-binding (cons (pattern-variable-p pattern) expression)))
(unless (assoc-conflict new-binding bindings)
(values t (cons new-binding bindings))))))
((atom pattern) (when (equal pattern expression)
(values t bindings)))
(t (unless (atom expression)
(if (pattern-variable-p (car pattern))
(loop for sublist-length from 0 to (length expression)
do (let ((before (subseq expression 0 sublist-length))
(after (subseq expression sublist-length)))
(multiple-value-bind (success bindings) (match (car pattern) before bindings)
(when success
(multiple-value-bind (success bindings) (match (cdr pattern) after bindings)
(when success (return-from match (values success bindings))))))))
(multiple-value-bind (success bindings) (match (car pattern) (car expression) bindings)
(when success
(multiple-value-bind (success bindings) (match (cdr pattern) (cdr expression) bindings)
(when success
(return-from match (values success bindings)))))))))))
|#
;; This way it should handle operator precedence as well
;; In order to write it ill consider what it might expand to
#|
(pattern-cond <exp>
(<pattern-1> <consequence-1>)
...)
(let* (bindings)
(cond ((multiple-value-bind (matched values) (match <pattern-1> <exp>)
(setq bindings values)
matched)
(progv (mapcar #'car bindings) (mapcar #'cdr bindings)
<consequence-1>))
...))
|#
(defmacro pattern-cond (expression &rest clauses)
(let ((bindings (gensym "bindings")))
(labels ((make-cond-clauses (clauses)
(when clauses
(if (eq 'else (caar clauses))
`((t ,@(cdar clauses)))
(cons `((multiple-value-bind (matched values)
(match ',(caar clauses) ,expression)
(setq ,bindings values)
matched)
(progv (mapcar #'car ,bindings) (mapcar #'cdr ,bindings)
,@(cdar clauses)))
(make-cond-clauses (cdr clauses)))))))
`(let* (,bindings)
(cond ,@(make-cond-clauses clauses))))))
(defun infix->prefix-convert (expression)
(pattern-cond expression
(((? x) + (? y)) `(+ ,(infix->prefix x) ,(infix->prefix y)))
(((? x) - (? y)) `(- ,(infix->prefix x) ,(infix->prefix y)))
(((? x) * (? y)) `(* ,(infix->prefix x) ,(infix->prefix y)))
(((? x) / (? y)) `(/ ,(infix->prefix x) ,(infix->prefix y)))
(else (if (null (cdr expression))
(car expression)
expression))))
;CL-USER> (infix->prefix-convert '(1 * 3 + 4))
;(+ (* 1 3) 4)
;CL-USER> (infix->prefix-convert '(1 * (3 + 4)))
;(* 1 (+ 3 4))
;CL-USER> (infix->prefix-convert '(1 / (3 * 4 * 5)))
(defun infix->prefix-optimize (expression)
(infix->prefix-optimize
(pattern-cond expression
((+ (+ (? x) (? y)) (? z)) `(+ ,x ,y ,z))
((+ (? x) (+ (? y) (? z))) `(+ ,x ,y ,z))
((* (* (? x) (? y)) (? z)) `(* ,x ,y ,z))
((* (? x) (* (? y) (? z))) `(* ,x ,y ,z))
((- (+ (? x) (? y)) (? z)) `(- ,x ,y ,z))
((- (? x) (+ (? y) (? z))) `(- ,x ,y ,z))
((/ (* (? x) (? y)) (? z)) `(/ ,x ,y ,z))
((/ (? x) (* (? y) (? z))) `(/ ,x ,y ,z))
(else (return-from infix->prefix-optimize expression)))))
(defun pattern-variable-p (exp)
(and (consp exp)
(or (eq '? (car exp)) (eq '?^ (car exp)))
(cadr exp)))
(defun match (pattern expression &optional bindings)
(cond ((pattern-variable-p pattern)
(when (or (not (null expression))
(eq '?^ (car pattern)))
(let ((new-binding (cons (pattern-variable-p pattern) expression)))
(unless (assoc-conflict new-binding bindings)
(values t (cons new-binding bindings))))))
((atom pattern) (when (equal pattern expression)
(values t bindings)))
(t (unless (and (atom expression) (not (null expression)))
(if (pattern-variable-p (car pattern))
(loop for sublist-length from 0 to (length expression)
do (let ((before (subseq expression 0 sublist-length))
(after (subseq expression sublist-length)))
(multiple-value-bind (success bindings) (match (car pattern) before bindings)
(when success
(multiple-value-bind (success bindings) (match (cdr pattern) after bindings)
(when success (return-from match (values success bindings)))))))))
(multiple-value-bind (success bindings) (match (car pattern) (car expression) bindings)
(when success
(multiple-value-bind (success bindings) (match (cdr pattern) (cdr expression) bindings)
(when success
(return-from match (values success bindings))))))))))
(defun infix->prefix-optimize (expression)
(infix->prefix-optimize
(pattern-cond expression
((+ (?^ x) (+ (?^ y)) (?^ z)) `(+ ,@x ,@y ,@z))
((* (?^ x) (* (?^ y)) (?^ z)) `(+ ,@x ,@y ,@z))
((- (?^ x) (+ (?^ y)) (?^ z)) `(- ,@x ,@y ,@z))
((/ (?^ x) (* (?^ y)) (?^ z)) `(/ ,@x ,@y ,@z))
(else (return-from infix->prefix-optimize expression)))))
(defun infix->prefix (expression)
(labels ((convert (expression)
(pattern-cond expression
(((? x) + (? y)) `(+ ,(infix->prefix x) ,(infix->prefix y)))
(((? x) - (? y)) `(- ,(infix->prefix x) ,(infix->prefix y)))
(((? x) * (? y)) `(* ,(infix->prefix x) ,(infix->prefix y)))
(((? x) / (? y)) `(/ ,(infix->prefix x) ,(infix->prefix y)))
(else (if (null (cdr expression))
(car expression)
expression))))
(optimize (expression)
(optimize
(pattern-cond expression
((+ (?^ x) (+ (?^ y)) (?^ z)) `(+ ,@x ,@y ,@z))
((* (?^ x) (* (?^ y)) (?^ z)) `(* ,@x ,@y ,@z))
((- (?^ x) (+ (?^ y)) (?^ z)) `(- ,@x ,@y ,@z))
((/ (?^ x) (* (?^ y)) (?^ z)) `(/ ,@x ,@y ,@z))
(else (return-from optimize expression))))))
(optimize (convert expression))))