Skip to content

Instantly share code, notes, and snippets.

@qxxt
Last active July 21, 2023 20:31
Show Gist options
  • Save qxxt/816c2c7ed35959d2ac274588855c4b77 to your computer and use it in GitHub Desktop.
Save qxxt/816c2c7ed35959d2ac274588855c4b77 to your computer and use it in GitHub Desktop.
Simple arithmetic parser on Emacs Lisp
(require 'calc-misc)
(defun last-elem (list)
(car (last list)))
(defun pow (num pow)
(if (floatp pow)
(error "No float"))
(if (zerop pow)
1
(when (< num 0)
(setq pow (* pow -1)
num (/ 1 num)))
(let ((res num))
(while (and (not (equal pow 1))
(not (zerop res)))
(setq res (* res num))
(if (math-evenp pow)
(setq pow (/ pow 2)
num (* num num))
(setq pow (1- pow))))
res)))
(defun arithmetic-tokenizer ()
(goto-char (point-min))
(let (tokens)
(while (not (eobp))
(skip-chars-forward " \t")
(cond
((looking-at "[0-9]+")
(add-to-list 'tokens (list (string-to-number (match-string 0)) 'operand) t 'nil))
((looking-at "-\\|\\+")
(add-to-list 'tokens (list (intern (match-string 0)) 'operator1) t 'nil))
((looking-at "/\\|\\*")
(add-to-list 'tokens (list (intern (match-string 0)) 'operator2) t 'nil))
((looking-at "\\^")
(add-to-list 'tokens (list 'pow 'operator3) t 'nil))
(t
(error "Bad input")))
(goto-char (match-end 0)))
tokens))
(defun arithmetic-parse(input)
(with-temp-buffer
(if (not (string-match-p "^[-\\|\\+]" input))
(setq input (concat "+" input)))
(insert input)
(message "inpt: %s" input)
(message "true: %s" (calc-eval input))
(let* ((tokens (arithmetic-tokenizer))
(res (list (car (pop tokens)))))
(while tokens
(let ((token (pop tokens)))
(message "’%s’" res)
(cond
((equal (last-elem token) 'operand)
(setq res (append res (list (car token)))))
((equal (car res) (car token)))
((equal (last-elem token) 'operator2)
(setq res (append (butlast res)
(list (list (car token)
(last-elem res)
(car (pop tokens)))))))
(t
(setq res (list (car token) res))))))
(message "’%s’" res)
res)))
(let* ((input "3 + 5 + 2 - 2 * 2 + 2 * 20")
(res (arithmetic-parse input)))
(message "eval: %s" (eval res)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment