Last active
July 21, 2023 20:31
-
-
Save qxxt/816c2c7ed35959d2ac274588855c4b77 to your computer and use it in GitHub Desktop.
Simple arithmetic parser on Emacs Lisp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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