polisher
2021-12-30
Infix notation to S-expression translator
Polisher
Infix notation to S-expression (Polish notation) translator for Common Lisp
Overview
Formulae inside the reader macro #i{ ... } are interpreted as infix notation.
If you don't want to use it, the macro polish is available instead.
(polisher:activate-infix-syntax) ; Activate #i{ ... } reader macro #i{1+2*3} ;=> 7 (polisher:polish "1+2*3") ; Exactly the same as the above one ;=> 7 #i{1 + 2*3} ; Spaces can be inserted anywhere ;=> 7 #i{2*3/4} ;=> 3/2 #i{2**2**3} ; Identical to 2**(2**3), not (2**2)**3 ;=> 256 #i{atan(1.0d0, 1.0d0)} ;=> 0.7853981633974483d0 (flet ((add1 (x) (+ x 1))) #i{add1(2)+3}) ;=> 6 (defparameter *some-global-value* 1.5) ; The symbol containg operator charcters #i{1 + 2 * "*some-global-value*"} ; must be double-quoted ;=> 4.0 #i{2*#c(1 2)+3} ;=> #C(5 4) #i{#b101 +3} ; Some spaces are needed after #b101 ;=> 8
Installation
Quicklisp
If you already have Quicklisp client, just run the following:
(ql:quickload :polisher)
It will resolve dependencies automatically.
Github and Quicklisp
- Clone or download the latest version from GitHub.
- In the cloned directory, run
(ql:register-local-projects). - Now you can use
(ql:quickload :polisher)anywhere.
ASDF
- Clone or download the latest version from GitHub.
- Place the directory where your ASDF system can find.
- Run
(asdf:load-system :polisher).
Requirements
Default operators
Following operators are defined by default:
| symbol | function | priority | left associative |
|---|---|---|---|
| + | + | 1 | t |
| - | - | 1 | t |
| * | * | 2 | t |
| / | / | 2 | t |
| ** | expt | 3 | nil |
Add your own operator
(polisher:add-operator (make-instance 'polisher:operator :symbol '^ :function 'expt :priority 3 :left-associative nil)) #i{2^2^3} ;=> 256
Note that if there are left-associative operators and right-associative operators
both having the same priority, formulae can't be evaluated correctly.
For example, when op1 is left-associative and op2 is right-associative,
x op1 y op2 z can be interpreted as either (x op1 y) op2 z and
x op1 (y op2 z).
When you add your own operator, be careful of which package its symbol is interned in.
Restrictions
Symbols start with numbers
Symbols which start with numbers must be double-quoted. The following example shows the reason:
(let ((1e 2)) #i{1e+1+1}) ;=> 11.0 (let ((1e 2)) #i{"1e"+1+1}) ;=> 4
No one defines such an odd symbol? Remember the standard functions 1+ and 1-!
Symbols with vertical bars
Symbols whose symbol-name sandwiched in vertical bars (e.g. |ab de|) can't be used.
This is because someone may want to use a vertical bar as the logical OR operator.
Double-quoting is necessary?
The infix formula 1+*global-symbol* can be uniquely interpreted as (+ 1 *global-symbol*),
so double-quoting may be unnecessary.
However in my opinion, the formula seems very weird when it appears in ALGOL-like languages;
so I think double-quoting should be used.
In addition, many text editors highlight double-quoted things, helping us to distinguish
symbol-names from operators.