Guest User

Untitled

a guest
Dec 13th, 2024
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.69 KB | None | 0 0
  1. ;;;; shunting.lisp
  2.  
  3. (in-package #:shunting)
  4.  
  5. ;; wikipedia https://en.wikipedia.org/wiki/Shunting_yard_algorithm
  6.  
  7. ;; Used to keep attributes for an operator, higher rank = more immediacy
  8. ;; in application
  9.  
  10. (defclass op-details ()
  11. ((rank :initarg :rank :reader rank :initform 0)
  12. (fn :initarg :fn :reader fn)
  13. (left-assoc :initarg :left-assoc :reader left-assoc :initform t)
  14. (num-args :initarg :num-args :reader num-args :initform 2)))
  15.  
  16. ;; Function to skip the make-instance malarky
  17. (defun make-op-details (&rest inits &key &allow-other-keys)
  18. (apply #'make-instance 'op-details inits))
  19.  
  20. ;; Hash tables are cleaner with Alexandria but keeping it 0 dependency
  21. (defparameter *operators-LOL*
  22. (let ((temp (make-hash-table :test 'eq)))
  23. (loop :for (key value)
  24. :in `((- ,(make-op-details :rank 0 :fn #'-))
  25. (+ ,(make-op-details :rank 0 :fn #'+))
  26. (/ ,(make-op-details :rank 1 :fn #'/))
  27. (* ,(make-op-details :rank 1 :fn #'*))
  28. (^ ,(make-op-details :rank 2 :fn #'expt :left-assoc nil)))
  29. :do (setf (gethash key temp) value))
  30. temp))
  31.  
  32. (defun operatorp (symbol)
  33. "If symbol is a member of the *operators-LOL* table's keys return true."
  34. (or (gethash symbol *operators-LOL*)))
  35.  
  36. ;;; properties
  37.  
  38. (defun op-props (symbol)
  39. (assert (operatorp symbol))
  40. (gethash symbol *operators-LOL*))
  41.  
  42. (defun op-rank (symbol)
  43. (rank (op-props symbol)))
  44.  
  45. (defun op-fn(symbol)
  46. (fn (op-props symbol)))
  47.  
  48. (defun op-left-assoc (symbol)
  49. (left-assoc (op-props symbol)))
  50.  
  51. (defun op-num-args (symbol)
  52. (num-args (op-props symbol)))
  53.  
  54. ;;; These two paren modifiers are for order of ops, using parens causes a mess
  55. (defun left-paren-p (symbol)
  56. (eq symbol '[))
  57.  
  58. (defun right-paren-p (symbol)
  59. (eq symbol ']))
  60.  
  61. ;;; Custom queue via Paul Graham
  62. (defun make-queue () (cons nil nil))
  63.  
  64. (defun enqueue (obj q)
  65. (if (null (car q))
  66. (setf (cdr q) (setf (car q) (list obj)))
  67. (setf (cdr (cdr q)) (list obj)
  68. (cdr q) (cdr (cdr q))))
  69. (car q))
  70.  
  71. (defun dequeue (q)
  72. (pop (car q)))
  73.  
  74. (defun queue-to-list (q)
  75. (car q))
  76.  
  77. (defun RPN-eval (rpn-queue)
  78. (loop :with the-stack := nil
  79. :for token :in (queue-to-list rpn-queue)
  80. :for fn-args := nil
  81. :do (cond ((numberp token)
  82. (push token the-stack))
  83. ((operatorp token)
  84. (dotimes (_ (op-num-args token))
  85. (push (pop the-stack) fn-args))
  86. (push (apply (op-fn token) fn-args) the-stack)))
  87. :finally (return (car the-stack))))
  88.  
  89. ;; Direct translation from Wikipedia
  90. ;; It's uh ... stateful and whilish - hold my ALGOL
  91. ;; TODO break out logic for operatorp and right-paren-p
  92. (defun infix-to-RPN (input)
  93. (loop :with output-queue := (make-queue)
  94. :with operator-stack := nil
  95. :for token :in input
  96. :do (cond ((numberp token) ; Numbers go on output
  97. (enqueue token output-queue))
  98. ((functionp token) ; Functions go on operator stack
  99. (push token operator-stack))
  100. ((operatorp token) ; Drain all higher ops into output
  101. (loop :for op2 := (car operator-stack)
  102. :while op2
  103. :while (not (left-paren-p op2))
  104. :while (let* ((token-rank (op-rank token))
  105. (op2-rank (op-rank op2))
  106. (token-left (op-left-assoc token)))
  107. (or (> op2-rank token-rank)
  108. (and (= op2-rank token-rank) token-left)))
  109. :do (enqueue (pop operator-stack) output-queue))
  110. (push token operator-stack))
  111. ((left-paren-p token) ; Start grouping
  112. (push '[ operator-stack))
  113. ((right-paren-p token) ; Eval group backwards
  114. (loop :while operator-stack
  115. :for op2 := (car operator-stack)
  116. :while (not (left-paren-p op2))
  117. :do (assert (not (null operator-stack)))
  118. (enqueue (pop operator-stack) output-queue))
  119. (assert (left-paren-p (car operator-stack)))
  120. (pop operator-stack)
  121. (when (functionp (car operator-stack))
  122. (enqueue (pop operator-stack) output-queue))))
  123. :finally (loop :while operator-stack
  124. :do (enqueue (pop operator-stack) output-queue))
  125. (return output-queue)))
  126.  
Add Comment
Please, Sign In to add comment