Search code examples
common-lispevalinfix-notation

Common lisp and infix package


There is the infix package for common lisp (see http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/syntax/infix/infix.cl), which transforms infix form to prefix.

For example:

(string->prefix "1+2") ;; => (+ 1 2)

It also provides the reader macro #I, which can evaluate an infix form, e.g.,

#I(1+2) ;; => 3

But I don't want to use this reader macro.

I have written a simple function, which uses cl-ppcre, to substitute a string with a number, i.e.,

(prepare-form "1+x*x" "x" 3) ;; => "1+3*3"

Finally, I have a function which evaluates the infix form

(defun eval-infix (form &rest args)
  (eval (string->prefix (apply #'prepare-form form args))))

Can the function eval-infix be implemented without using the eval function? My final goal is to call eval-infix like this:

(eval-infix "1+x*x" "x" (+ 1 2))

Solution

  • Well I think what you want to use is string->prefix. This will intern symbols so to avoid polluting your own package lets define one. Finally you can avoid the security problems of eval by defining your own eval. There is still a problem where symbols from other packages can be written and this makes me sad. There is also the problem that the infix reader can escape to the Lisp reader which can do arbitrary evaluation. Here is a sketch of the parts of the solution. I’ve probably got the arguments for some functions in the wrong order.

    (defpackage infix-vars)
    (defun read-infix-string (s) (let ((*package* (find-package "INFIX-VARS"))) (string->prefix s)))
    (defun substitute-var (expr v val)
       (let ((v (etypecase v (symbol v) (string (intern v (find-package "INFIX-VARS"))))))
        (subst expr v val)))
    (defun eval-expr (e)
      (etypecase e
        (number e)
        (list
          (ecase (car e)
            (+ (apply #'+ (mapcar #'eval-expr (cdr e))))))))