;; Calculator for GNU Emacs, part I [calc-aent.el] ;; Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. ;; Written by Dave Gillespie, daveg@synaptics.com. ;; This file is part of GNU Emacs. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY. No author or distributor ;; accepts responsibility to anyone for the consequences of using it ;; or for whether it serves any particular purpose or works at all, ;; unless he says so in writing. Refer to the GNU Emacs General Public ;; License for full details. ;; Everyone is granted permission to copy, modify and redistribute ;; GNU Emacs, but only under the conditions described in the ;; GNU Emacs General Public License. A copy of this license is ;; supposed to have been given to you along with GNU Emacs so you ;; can know your rights and responsibilities. It should be in a ;; file named COPYING. Among other things, the copyright notice ;; and this notice must be preserved on all copies. ;; This file is autoloaded from calc.el. (require 'calc) (require 'calc-macs) (defun calc-Need-calc-aent () nil) (defun calc-do-quick-calc () (calc-check-defines) (if (eq major-mode 'calc-mode) (calc-algebraic-entry t) (let (buf shortbuf) (save-excursion (calc-create-buffer) (let* ((calc-command-flags nil) (calc-dollar-values calc-quick-prev-results) (calc-dollar-used 0) (enable-recursive-minibuffers t) (calc-language (if (memq calc-language '(nil big)) 'flat calc-language)) (entry (calc-do-alg-entry "" "Quick calc: " t)) (alg-exp (mapcar (function (lambda (x) (if (and (not calc-extensions-loaded) calc-previous-alg-entry (string-match "\\`[-0-9._+*/^() ]+\\'" calc-previous-alg-entry)) (calc-normalize x) (calc-extensions) (math-evaluate-expr x)))) entry))) (if (and (= (length alg-exp) 1) (eq (car-safe (car alg-exp)) 'calcFunc-assign) (= (length (car alg-exp)) 3) (eq (car-safe (nth 1 (car alg-exp))) 'var)) (progn (calc-extensions) (set (nth 2 (nth 1 (car alg-exp))) (nth 2 (car alg-exp))) (calc-refresh-evaltos (nth 2 (nth 1 (car alg-exp)))) (setq alg-exp (list (nth 2 (car alg-exp)))))) (setq calc-quick-prev-results alg-exp buf (mapconcat (function (lambda (x) (math-format-value x 1000))) alg-exp " ") shortbuf buf) (if (and (= (length alg-exp) 1) (memq (car-safe (car alg-exp)) '(nil bigpos bigneg)) (< (length buf) 20) (= calc-number-radix 10)) (setq buf (concat buf " (" (let ((calc-number-radix 16)) (math-format-value (car alg-exp) 1000)) ", " (let ((calc-number-radix 8)) (math-format-value (car alg-exp) 1000)) (if (and (integerp (car alg-exp)) (> (car alg-exp) 0) (< (car alg-exp) 127)) (format ", \"%c\"" (car alg-exp)) "") ")"))) (if (and (< (length buf) (frame-width)) (= (length entry) 1) calc-extensions-loaded) (let ((long (concat (math-format-value (car entry) 1000) " => " buf))) (if (<= (length long) (- (frame-width) 8)) (setq buf long)))) (calc-handle-whys) (message "Result: %s" buf))) (if (eq last-command-char ?\n) (insert shortbuf) (setq kill-ring (cons shortbuf kill-ring)) (if (> (length kill-ring) kill-ring-max) (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)) (setq kill-ring-yank-pointer kill-ring)))) ) (defun calc-do-calc-eval (str separator args) (calc-check-defines) (catch 'calc-error (save-excursion (calc-create-buffer) (cond ((and (consp str) (not (symbolp (car str)))) (let ((calc-language nil) (math-expr-opers math-standard-opers) (calc-internal-prec 12) (calc-word-size 32) (calc-symbolic-mode nil) (calc-matrix-mode nil) (calc-angle-mode 'deg) (calc-number-radix 10) (calc-leading-zeros nil) (calc-group-digits nil) (calc-point-char ".") (calc-frac-format '(":" nil)) (calc-prefer-frac nil) (calc-hms-format "%s@ %s' %s\"") (calc-date-format '((H ":" mm C SS pp " ") Www " " Mmm " " D ", " YYYY)) (calc-float-format '(float 0)) (calc-full-float-format '(float 0)) (calc-complex-format nil) (calc-matrix-just nil) (calc-full-vectors t) (calc-break-vectors nil) (calc-vector-commas ",") (calc-vector-brackets "[]") (calc-matrix-brackets '(R O)) (calc-complex-mode 'cplx) (calc-infinite-mode nil) (calc-display-strings nil) (calc-simplify-mode nil) (calc-display-working-message 'lots) (strp (cdr str))) (while strp (set (car strp) (nth 1 strp)) (setq strp (cdr (cdr strp)))) (calc-do-calc-eval (car str) separator args))) ((eq separator 'eval) (eval str)) ((eq separator 'macro) (calc-extensions) (let* ((calc-buffer (current-buffer)) (calc-window (get-buffer-window calc-buffer)) (save-window (selected-window))) (if calc-window (unwind-protect (progn (select-window calc-window) (calc-execute-kbd-macro str nil (car args))) (and (window-point save-window) (select-window save-window))) (save-window-excursion (select-window (get-largest-window)) (switch-to-buffer calc-buffer) (calc-execute-kbd-macro str nil (car args))))) nil) ((eq separator 'pop) (or (not (integerp str)) (= str 0) (calc-pop (min str (calc-stack-size)))) (calc-stack-size)) ((eq separator 'top) (and (integerp str) (> str 0) (<= str (calc-stack-size)) (math-format-value (calc-top-n str (car args)) 1000))) ((eq separator 'rawtop) (and (integerp str) (> str 0) (<= str (calc-stack-size)) (calc-top-n str (car args)))) (t (let* ((calc-command-flags nil) (calc-next-why nil) (calc-language (if (memq calc-language '(nil big)) 'flat calc-language)) (calc-dollar-values (mapcar (function (lambda (x) (if (stringp x) (progn (setq x (math-read-exprs x)) (if (eq (car-safe x) 'error) (throw 'calc-error (calc-eval-error (cdr x))) (car x))) x))) args)) (calc-dollar-used 0) (res (if (stringp str) (math-read-exprs str) (list str))) buf) (if (eq (car res) 'error) (calc-eval-error (cdr res)) (setq res (mapcar 'calc-normalize res)) (and (memq 'clear-message calc-command-flags) (message "")) (cond ((eq separator 'pred) (calc-extensions) (if (= (length res) 1) (math-is-true (car res)) (calc-eval-error '(0 "Single value expected")))) ((eq separator 'raw) (if (= (length res) 1) (car res) (calc-eval-error '(0 "Single value expected")))) ((eq separator 'list) res) ((memq separator '(num rawnum)) (if (= (length res) 1) (if (math-constp (car res)) (if (eq separator 'num) (math-format-value (car res) 1000) (car res)) (calc-eval-error (list 0 (if calc-next-why (calc-explain-why (car calc-next-why)) "Number expected")))) (calc-eval-error '(0 "Single value expected")))) ((eq separator 'push) (calc-push-list res) nil) (t (while res (setq buf (concat buf (and buf (or separator ", ")) (math-format-value (car res) 1000)) res (cdr res))) buf)))))))) ) (defun calc-eval-error (msg) (if (and (boundp 'calc-eval-error) calc-eval-error) (if (eq calc-eval-error 'string) (nth 1 msg) (error "%s" (nth 1 msg))) msg) ) ;;;; Reading an expression in algebraic form. (defun calc-auto-algebraic-entry (&optional prefix) (interactive "P") (calc-algebraic-entry prefix t) ) (defun calc-algebraic-entry (&optional prefix auto) (interactive "P") (calc-wrapper (let ((calc-language (if prefix nil calc-language)) (math-expr-opers (if prefix math-standard-opers math-expr-opers))) (calc-alg-entry (and auto (char-to-string last-command-char))))) ) (defun calc-alg-entry (&optional initial prompt) (let* ((sel-mode nil) (calc-dollar-values (mapcar 'calc-get-stack-element (nthcdr calc-stack-top calc-stack))) (calc-dollar-used 0) (calc-plain-entry t) (alg-exp (calc-do-alg-entry initial prompt t))) (if (stringp alg-exp) (progn (calc-extensions) (calc-alg-edit alg-exp)) (let* ((calc-simplify-mode (if (eq last-command-char ?\C-j) 'none calc-simplify-mode)) (nvals (mapcar 'calc-normalize alg-exp))) (while alg-exp (calc-record (if calc-extensions-loaded (car alg-exp) (car nvals)) "alg'") (calc-pop-push-record-list calc-dollar-used (and (not (equal (car alg-exp) (car nvals))) calc-extensions-loaded "") (list (car nvals))) (setq alg-exp (cdr alg-exp) nvals (cdr nvals) calc-dollar-used 0))) (calc-handle-whys))) ) (defun calc-do-alg-entry (&optional initial prompt no-normalize) (let* ((calc-buffer (current-buffer)) (blink-paren-function 'calcAlg-blink-matching-open) (alg-exp 'error)) (if (boundp 'calc-alg-ent-map) () (setq calc-alg-ent-map (copy-keymap minibuffer-local-map)) (define-key calc-alg-ent-map "'" 'calcAlg-previous) (define-key calc-alg-ent-map "`" 'calcAlg-edit) (define-key calc-alg-ent-map "\C-m" 'calcAlg-enter) (define-key calc-alg-ent-map "\C-j" 'calcAlg-enter) (or calc-emacs-type-19 (let ((i 33)) (setq calc-alg-ent-esc-map (copy-sequence esc-map)) (while (< i 127) (aset calc-alg-ent-esc-map i 'calcAlg-escape) (setq i (1+ i)))))) (or calc-emacs-type-19 (define-key calc-alg-ent-map "\e" nil)) (if (eq calc-algebraic-mode 'total) (define-key calc-alg-ent-map "\e" calc-alg-ent-esc-map) (define-key calc-alg-ent-map "\ep" 'calcAlg-plus-minus) (define-key calc-alg-ent-map "\em" 'calcAlg-mod) (define-key calc-alg-ent-map "\e=" 'calcAlg-equals) (define-key calc-alg-ent-map "\e\r" 'calcAlg-equals) (define-key calc-alg-ent-map "\e%" 'self-insert-command)) (setq calc-aborted-prefix nil) (let ((buf (read-from-minibuffer (or prompt "Algebraic: ") (or initial "") calc-alg-ent-map nil))) (if (eq alg-exp 'error) (if (eq (car-safe (setq alg-exp (math-read-exprs buf))) 'error) (setq alg-exp nil))) (setq calc-aborted-prefix "alg'") (or no-normalize (and alg-exp (setq alg-exp (mapcar 'calc-normalize alg-exp)))) alg-exp)) ) (defun calcAlg-plus-minus () (interactive) (if (calc-minibuffer-contains ".* \\'") (insert "+/- ") (insert " +/- ")) ) (defun calcAlg-mod () (interactive) (if (not (calc-minibuffer-contains ".* \\'")) (insert " ")) (if (calc-minibuffer-contains ".* mod +\\'") (if calc-previous-modulo (insert (math-format-flat-expr calc-previous-modulo 0)) (beep)) (insert "mod ")) ) (defun calcAlg-previous () (interactive) (if (calc-minibuffer-contains "\\`\\'") (if calc-previous-alg-entry (insert calc-previous-alg-entry) (beep)) (insert "'")) ) (defun calcAlg-equals () (interactive) (unwind-protect (calcAlg-enter) (if (consp alg-exp) (progn (setq prefix-arg (length alg-exp)) (calc-unread-command ?=)))) ) (defun calcAlg-escape () (interactive) (calc-unread-command) (save-excursion (calc-select-buffer) (use-local-map calc-mode-map)) (calcAlg-enter) ) (defun calcAlg-edit () (interactive) (if (or (not calc-plain-entry) (calc-minibuffer-contains "\\`\\([^\"]*\"[^\"]*\"\\)*[^\"]*\"[^\"]*\\'")) (insert "`") (setq alg-exp (buffer-string)) (and (> (length alg-exp) 0) (setq calc-previous-alg-entry alg-exp)) (exit-minibuffer)) ) (setq calc-plain-entry nil) (defun calcAlg-enter () (interactive) (let* ((str (buffer-string)) (exp (and (> (length str) 0) (save-excursion (set-buffer calc-buffer) (math-read-exprs str))))) (if (eq (car-safe exp) 'error) (progn (goto-char (point-min)) (forward-char (nth 1 exp)) (beep) (calc-temp-minibuffer-message (concat " [" (or (nth 2 exp) "Error") "]")) (calc-clear-unread-commands)) (setq alg-exp (if (calc-minibuffer-contains "\\` *\\[ *\\'") '((incomplete vec)) exp)) (and (> (length str) 0) (setq calc-previous-alg-entry str)) (exit-minibuffer))) ) (defun calcAlg-blink-matching-open () (let ((oldpos (point)) (blinkpos nil)) (save-excursion (condition-case () (setq blinkpos (scan-sexps oldpos -1)) (error nil))) (if (and blinkpos (> oldpos (1+ (point-min))) (or (and (= (char-after (1- oldpos)) ?\)) (= (char-after blinkpos) ?\[)) (and (= (char-after (1- oldpos)) ?\]) (= (char-after blinkpos) ?\())) (save-excursion (goto-char blinkpos) (looking-at ".+\\(\\.\\.\\|\\\\dots\\|\\\\ldots\\)"))) (let* ((char-num (char-int (char-after blinkpos))) (saved (aref (syntax-table) char-num))) (unwind-protect (progn (aset (syntax-table) char-num (+ (logand saved 255) (lsh (char-int (char-after (1- oldpos))) 8))) (blink-matching-open)) (aset (syntax-table) char-num saved))) (blink-matching-open)))) (defun calc-alg-digit-entry () (calc-alg-entry (cond ((eq last-command-char ?e) (if (> calc-number-radix 14) (format "%d.^" calc-number-radix) "1e")) ((eq last-command-char ?#) (format "%d#" calc-number-radix)) ((eq last-command-char ?_) "-") ((eq last-command-char ?@) "0@ ") (t (char-to-string last-command-char)))) ) (defun calcDigit-algebraic () (interactive) (if (calc-minibuffer-contains ".*[@oh] *[^'m ]+[^'m]*\\'") (calcDigit-key) (setq calc-digit-value (buffer-string)) (exit-minibuffer)) ) (defun calcDigit-edit () (interactive) (calc-unread-command) (setq calc-digit-value (buffer-string)) (exit-minibuffer) ) ;;; Algebraic expression parsing. [Public] (defun math-read-exprs (exp-str) (let ((exp-pos 0) (exp-old-pos 0) (exp-keep-spaces nil) exp-token exp-data) (if calc-language-input-filter (setq exp-str (funcall calc-language-input-filter exp-str))) (while (setq exp-token (string-match "\\.\\.\\([^.]\\|.[^.]\\)" exp-str)) (setq exp-str (concat (substring exp-str 0 exp-token) "\\dots" (substring exp-str (+ exp-token 2))))) (math-build-parse-table) (math-read-token) (let ((val (catch 'syntax (math-read-expr-list)))) (if (stringp val) (list 'error exp-old-pos val) (if (equal exp-token 'end) val (list 'error exp-old-pos "Syntax error"))))) ) (defun math-read-expr-list () (let* ((exp-keep-spaces nil) (val (list (math-read-expr-level 0))) (last val)) (while (equal exp-data ",") (math-read-token) (let ((rest (list (math-read-expr-level 0)))) (setcdr last rest) (setq last rest))) val) ) (setq calc-user-parse-table nil) (setq calc-last-main-parse-table nil) (setq calc-last-lang-parse-table nil) (setq calc-user-tokens nil) (setq calc-user-token-chars nil) (defun math-build-parse-table () (let ((mtab (cdr (assq nil calc-user-parse-tables))) (ltab (cdr (assq calc-language calc-user-parse-tables)))) (or (and (eq mtab calc-last-main-parse-table) (eq ltab calc-last-lang-parse-table)) (let ((p (append mtab ltab)) (toks nil)) (setq calc-user-parse-table p) (setq calc-user-token-chars nil) (while p (math-find-user-tokens (car (car p))) (setq p (cdr p))) (setq calc-user-tokens (mapconcat 'identity (sort (mapcar 'car toks) (function (lambda (x y) (> (length x) (length y))))) "\\|") calc-last-main-parse-table mtab calc-last-lang-parse-table ltab)))) ) (defun math-find-user-tokens (p) ; uses "toks" (while p (cond ((and (stringp (car p)) (or (> (length (car p)) 1) (equal (car p) "$") (equal (car p) "\"")) (string-match "[^a-zA-Z0-9]" (car p))) (let ((s (regexp-quote (car p)))) (if (string-match "\\`[a-zA-Z0-9]" s) (setq s (concat "\\<" s))) (if (string-match "[a-zA-Z0-9]\\'" s) (setq s (concat s "\\>"))) (or (assoc s toks) (progn (setq toks (cons (list s) toks)) (or (memq (aref (car p) 0) calc-user-token-chars) (setq calc-user-token-chars (cons (aref (car p) 0) calc-user-token-chars))))))) ((consp (car p)) (math-find-user-tokens (nth 1 (car p))) (or (eq (car (car p)) '\?) (math-find-user-tokens (nth 2 (car p)))))) (setq p (cdr p))) ) (defun math-read-token () (if (>= exp-pos (length exp-str)) (setq exp-old-pos exp-pos exp-token 'end exp-data "\000") (let ((ch (aref exp-str exp-pos))) (setq exp-old-pos exp-pos) (cond ((memq ch '(? ?\n ?\t)) (setq exp-pos (1+ exp-pos)) (if exp-keep-spaces (setq exp-token 'space exp-data " ") (math-read-token))) ((and (memq ch calc-user-token-chars) (let ((case-fold-search nil)) (eq (string-match calc-user-tokens exp-str exp-pos) exp-pos))) (setq exp-token 'punc exp-data (math-match-substring exp-str 0) exp-pos (match-end 0))) ((or (and (>= ch ?a) (<= ch ?z)) (and (>= ch ?A) (<= ch ?Z))) (string-match (if (memq calc-language '(c fortran pascal maple)) "[a-zA-Z0-9_#]*" "[a-zA-Z0-9'#]*") exp-str exp-pos) (setq exp-token 'symbol exp-pos (match-end 0) exp-data (math-restore-dashes (math-match-substring exp-str 0))) (if (eq calc-language 'eqn) (let ((code (assoc exp-data math-eqn-ignore-words))) (cond ((null code)) ((null (cdr code)) (math-read-token)) ((consp (nth 1 code)) (math-read-token) (if (assoc exp-data (cdr code)) (setq exp-data (format "%s %s" (car code) exp-data)))) ((eq (nth 1 code) 'punc) (setq exp-token 'punc exp-data (nth 2 code))) (t (math-read-token) (math-read-token)))))) ((or (and (>= ch ?0) (<= ch ?9)) (and (eq ch '?\.) (eq (string-match "\\.[0-9]" exp-str exp-pos) exp-pos)) (and (eq ch '?_) (eq (string-match "_\\.?[0-9]" exp-str exp-pos) exp-pos) (or (eq exp-pos 0) (and (memq calc-language '(nil flat big unform tex eqn)) (eq (string-match "[^])}\"a-zA-Z0-9'$]_" exp-str (1- exp-pos)) (1- exp-pos)))))) (or (and (eq calc-language 'c) (string-match "0[xX][0-9a-fA-F]+" exp-str exp-pos)) (string-match "_?\\([0-9]+.?0*@ *\\)?\\([0-9]+.?0*' *\\)?\\(0*\\([2-9]\\|1[0-4]\\)\\(#\\|\\^\\^\\)[0-9a-dA-D.]+[eE][-+_]?[0-9]+\\|0*\\([2-9]\\|[0-2][0-9]\\|3[0-6]\\)\\(#\\|\\^\\^\\)[0-9a-zA-Z:.]+\\|[0-9]+:[0-9:]+\\|[0-9.]+\\([eE][-+_]?[0-9]+\\)?\"?\\)?" exp-str exp-pos)) (setq exp-token 'number exp-data (math-match-substring exp-str 0) exp-pos (match-end 0))) ((eq ch ?\$) (if (and (eq calc-language 'pascal) (eq (string-match "\\(\\$[0-9a-fA-F]+\\)\\($\\|[^0-9a-zA-Z]\\)" exp-str exp-pos) exp-pos)) (setq exp-token 'number exp-data (math-match-substring exp-str 1) exp-pos (match-end 1)) (if (eq (string-match "\\$\\([1-9][0-9]*\\)" exp-str exp-pos) exp-pos) (setq exp-data (- (string-to-int (math-match-substring exp-str 1)))) (string-match "\\$+" exp-str exp-pos) (setq exp-data (- (match-end 0) (match-beginning 0)))) (setq exp-token 'dollar exp-pos (match-end 0)))) ((eq ch ?\#) (if (eq (string-match "#\\([1-9][0-9]*\\)" exp-str exp-pos) exp-pos) (setq exp-data (string-to-int (math-match-substring exp-str 1)) exp-pos (match-end 0)) (setq exp-data 1 exp-pos (1+ exp-pos))) (setq exp-token 'hash)) ((eq (string-match "~=\\|<=\\|>=\\|<>\\|/=\\|\\+/-\\|\\\\dots\\|\\\\ldots\\|\\*\\*\\|<<\\|>>\\|==\\|!=\\|&&&\\||||\\|!!!\\|&&\\|||\\|!!\\|:=\\|::\\|=>" exp-str exp-pos) exp-pos) (setq exp-token 'punc exp-data (math-match-substring exp-str 0) exp-pos (match-end 0))) ((and (eq ch ?\") (string-match "\\(\"\\([^\"\\]\\|\\\\.\\)*\\)\\(\"\\|\\'\\)" exp-str exp-pos)) (if (eq calc-language 'eqn) (progn (setq exp-str (copy-sequence exp-str)) (aset exp-str (match-beginning 1) ?\{) (if (< (match-end 1) (length exp-str)) (aset exp-str (match-end 1) ?\})) (math-read-token)) (setq exp-token 'string exp-data (math-match-substring exp-str 1) exp-pos (match-end 0)))) ((and (= ch ?\\) (eq calc-language 'tex) (< exp-pos (1- (length exp-str)))) (or (string-match "\\\\hbox *{\\([a-zA-Z0-9]+\\)}" exp-str exp-pos) (string-match "\\(\\\\\\([a-zA-Z]+\\|[^a-zA-Z]\\)\\)" exp-str exp-pos)) (setq exp-token 'symbol exp-pos (match-end 0) exp-data (math-restore-dashes (math-match-substring exp-str 1))) (let ((code (assoc exp-data math-tex-ignore-words))) (cond ((null code)) ((null (cdr code)) (math-read-token)) ((eq (nth 1 code) 'punc) (setq exp-token 'punc exp-data (nth 2 code))) ((and (eq (nth 1 code) 'mat) (string-match " *{" exp-str exp-pos)) (setq exp-pos (match-end 0) exp-token 'punc exp-data "[") (let ((right (string-match "}" exp-str exp-pos))) (and right (setq exp-str (copy-sequence exp-str)) (aset exp-str right ?\]))))))) ((and (= ch ?\.) (eq calc-language 'fortran) (eq (string-match "\\.[a-zA-Z][a-zA-Z][a-zA-Z]?\\." exp-str exp-pos) exp-pos)) (setq exp-token 'punc exp-data (upcase (math-match-substring exp-str 0)) exp-pos (match-end 0))) ((and (eq calc-language 'math) (eq (string-match "\\[\\[\\|->\\|:>" exp-str exp-pos) exp-pos)) (setq exp-token 'punc exp-data (math-match-substring exp-str 0) exp-pos (match-end 0))) ((and (eq calc-language 'eqn) (eq (string-match "->\\|<-\\|+-\\|\\\\dots\\|~\\|\\^" exp-str exp-pos) exp-pos)) (setq exp-token 'punc exp-data (math-match-substring exp-str 0) exp-pos (match-end 0)) (and (eq (string-match "\\\\dots\\." exp-str exp-pos) exp-pos) (setq exp-pos (match-end 0))) (if (memq (aref exp-data 0) '(?~ ?^)) (math-read-token))) ((eq (string-match "%%.*$" exp-str exp-pos) exp-pos) (setq exp-pos (match-end 0)) (math-read-token)) (t (if (and (eq ch ?\{) (memq calc-language '(tex eqn))) (setq ch ?\()) (if (and (eq ch ?\}) (memq calc-language '(tex eqn))) (setq ch ?\))) (if (and (eq ch ?\&) (eq calc-language 'tex)) (setq ch ?\,)) (setq exp-token 'punc exp-data (char-to-string ch) exp-pos (1+ exp-pos)))))) ) (defun math-read-expr-level (exp-prec &optional exp-term) (let* ((x (math-read-factor)) (first t) op op2) (while (and (or (and calc-user-parse-table (setq op (calc-check-user-syntax x exp-prec)) (setq x op op '("2x" ident 999999 -1))) (and (setq op (assoc exp-data math-expr-opers)) (/= (nth 2 op) -1) (or (and (setq op2 (assoc exp-data (cdr (memq op math-expr-opers)))) (eq (= (nth 3 op) -1) (/= (nth 3 op2) -1)) (eq (= (nth 3 op2) -1) (not (math-factor-after))) (setq op op2)) t)) (and (or (eq (nth 2 op) -1) (memq exp-token '(symbol number dollar hash)) (equal exp-data "(") (and (equal exp-data "[") (not (eq calc-language 'math)) (not (and exp-keep-spaces (eq (car-safe x) 'vec))))) (or (not (setq op (assoc exp-data math-expr-opers))) (/= (nth 2 op) -1)) (or (not calc-user-parse-table) (not (eq exp-token 'symbol)) (let ((p calc-user-parse-table)) (while (and p (or (not (integerp (car (car (car p))))) (not (equal (nth 1 (car (car p))) exp-data)))) (setq p (cdr p))) (not p))) (setq op (assoc "2x" math-expr-opers)))) (not (and exp-term (equal exp-data exp-term))) (>= (nth 2 op) exp-prec)) (if (not (equal (car op) "2x")) (math-read-token)) (and (memq (nth 1 op) '(sdev mod)) (calc-extensions)) (setq x (cond ((consp (nth 1 op)) (funcall (car (nth 1 op)) x op)) ((eq (nth 3 op) -1) (if (eq (nth 1 op) 'ident) x (if (eq (nth 1 op) 'closing) (if (eq (nth 2 op) exp-prec) (progn (setq exp-prec 1000) x) (throw 'syntax "Mismatched delimiters")) (list (nth 1 op) x)))) ((and (not first) (memq (nth 1 op) math-alg-inequalities) (memq (car-safe x) math-alg-inequalities)) (calc-extensions) (math-composite-inequalities x op)) (t (list (nth 1 op) x (math-read-expr-level (nth 3 op) exp-term)))) first nil)) x) ) (defun calc-check-user-syntax (&optional x prec) (let ((p calc-user-parse-table) (matches nil) match rule) (while (and p (or (not (progn (setq rule (car (car p))) (if x (and (integerp (car rule)) (>= (car rule) prec) (equal exp-data (car (setq rule (cdr rule))))) (equal exp-data (car rule))))) (let ((save-exp-pos exp-pos) (save-exp-old-pos exp-old-pos) (save-exp-token exp-token) (save-exp-data exp-data)) (or (not (listp (setq matches (calc-match-user-syntax rule)))) (let ((args (progn (calc-extensions) calc-arg-values)) (conds nil) temp) (if x (setq matches (cons x matches))) (setq match (cdr (car p))) (while (and (eq (car-safe match) 'calcFunc-condition) (= (length match) 3)) (setq conds (append (math-flatten-lands (nth 2 match)) conds) match (nth 1 match))) (while (and conds match) (calc-extensions) (cond ((eq (car-safe (car conds)) 'calcFunc-let) (setq temp (car conds)) (or (= (length temp) 3) (and (= (length temp) 2) (eq (car-safe (nth 1 temp)) 'calcFunc-assign) (= (length (nth 1 temp)) 3) (setq temp (nth 1 temp))) (setq match nil)) (setq matches (cons (math-normalize (math-multi-subst (nth 2 temp) args matches)) matches) args (cons (nth 1 temp) args))) ((and (eq (car-safe (car conds)) 'calcFunc-matches) (= (length (car conds)) 3)) (setq temp (calcFunc-vmatches (math-multi-subst (nth 1 (car conds)) args matches) (nth 2 (car conds)))) (if (eq temp 0) (setq match nil) (while (setq temp (cdr temp)) (setq matches (cons (nth 2 (car temp)) matches) args (cons (nth 1 (car temp)) args))))) (t (or (math-is-true (math-simplify (math-multi-subst (car conds) args matches))) (setq match nil)))) (setq conds (cdr conds))) (if match (not (setq match (math-multi-subst match args matches))) (setq exp-old-pos save-exp-old-pos exp-token save-exp-token exp-data save-exp-data exp-pos save-exp-pos))))))) (setq p (cdr p))) (and p match)) ) (defun calc-match-user-syntax (p &optional term) (let ((matches nil) (save-exp-pos exp-pos) (save-exp-old-pos exp-old-pos) (save-exp-token exp-token) (save-exp-data exp-data)) (while (and p (cond ((stringp (car p)) (and (equal exp-data (car p)) (progn (math-read-token) t))) ((integerp (car p)) (and (setq m (catch 'syntax (math-read-expr-level (car p) (if (cdr p) (if (consp (nth 1 p)) (car (nth 1 (nth 1 p))) (nth 1 p)) term)))) (not (stringp m)) (setq matches (nconc matches (list m))))) ((eq (car (car p)) '\?) (setq m (calc-match-user-syntax (nth 1 (car p)))) (or (nth 2 (car p)) (setq matches (nconc matches (list (cons 'vec (and (listp m) m)))))) (or (listp m) (not (nth 2 (car p))) (not (eq (aref (car (nth 2 (car p))) 0) ?\$)) (eq exp-token 'end))) (t (setq m (calc-match-user-syntax (nth 1 (car p)) (car (nth 2 (car p))))) (if (listp m) (let ((vec (cons 'vec m)) opos mm) (while (and (listp (setq opos exp-pos mm (calc-match-user-syntax (or (nth 2 (car p)) (nth 1 (car p))) (car (nth 2 (car p)))))) (> exp-pos opos)) (setq vec (nconc vec mm))) (setq matches (nconc matches (list vec)))) (and (eq (car (car p)) '*) (setq matches (nconc matches (list '(vec))))))))) (setq p (cdr p))) (if p (setq exp-pos save-exp-pos exp-old-pos save-exp-old-pos exp-token save-exp-token exp-data save-exp-data matches "Failed")) matches) ) (defconst math-alg-inequalities '(calcFunc-lt calcFunc-gt calcFunc-leq calcFunc-geq calcFunc-eq calcFunc-neq)) (defun math-remove-dashes (x) (if (string-match "\\`\\(.*\\)-\\(.*\\)\\'" x) (math-remove-dashes (concat (math-match-substring x 1) "#" (math-match-substring x 2))) x) ) (defun math-restore-dashes (x) (if (string-match "\\`\\(.*\\)[#_]\\(.*\\)\\'" x) (math-restore-dashes (concat (math-match-substring x 1) "-" (math-match-substring x 2))) x) ) (defun math-read-if (cond op) (let ((then (math-read-expr-level 0))) (or (equal exp-data ":") (throw 'syntax "Expected ':'")) (math-read-token) (list 'calcFunc-if cond then (math-read-expr-level (nth 3 op)))) ) (defun math-factor-after () (let ((exp-pos exp-pos) exp-old-pos exp-token exp-data) (math-read-token) (or (memq exp-token '(number symbol dollar hash string)) (and (assoc exp-data '(("-") ("+") ("!") ("|") ("/"))) (assoc (concat "u" exp-data) math-expr-opers)) (eq (nth 2 (assoc exp-data math-expr-opers)) -1) (assoc exp-data '(("(") ("[") ("{"))))) ) (defun math-read-factor () (let (op) (cond ((eq exp-token 'number) (let ((num (math-read-number exp-data))) (if (not num) (progn (setq exp-old-pos exp-pos) (throw 'syntax "Bad format"))) (math-read-token) (if (and math-read-expr-quotes (consp num)) (list 'quote num) num))) ((and calc-user-parse-table (setq op (calc-check-user-syntax))) op) ((or (equal exp-data "-") (equal exp-data "+") (equal exp-data "!") (equal exp-data "|") (equal exp-data "/")) (setq exp-data (concat "u" exp-data)) (math-read-factor)) ((and (setq op (assoc exp-data math-expr-opers)) (eq (nth 2 op) -1)) (if (consp (nth 1 op)) (funcall (car (nth 1 op)) op) (math-read-token) (let ((val (math-read-expr-level (nth 3 op)))) (cond ((eq (nth 1 op) 'ident) val) ((and (Math-numberp val) (equal (car op) "u-")) (math-neg val)) (t (list (nth 1 op) val)))))) ((eq exp-token 'symbol) (let ((sym (intern exp-data))) (math-read-token) (if (equal exp-data calc-function-open) (let ((f (assq sym math-expr-function-mapping))) (math-read-token) (if (consp (cdr f)) (funcall (car (cdr f)) f sym) (let ((args (if (or (equal exp-data calc-function-close) (eq exp-token 'end)) nil (math-read-expr-list)))) (if (not (or (equal exp-data calc-function-close) (eq exp-token 'end))) (throw 'syntax "Expected `)'")) (math-read-token) (if (and (eq calc-language 'fortran) args (calc-extensions) (let ((calc-matrix-mode 'scalar)) (math-known-matrixp (list 'var sym (intern (concat "var-" (symbol-name sym))))))) (math-parse-fortran-subscr sym args) (if f (setq sym (cdr f)) (and (= (aref (symbol-name sym) 0) ?\\) (< (prefix-numeric-value calc-language-option) 0) (setq sym (intern (substring (symbol-name sym) 1)))) (or (string-match "-" (symbol-name sym)) (setq sym (intern (concat "calcFunc-" (symbol-name sym)))))) (cons sym args))))) (if math-read-expr-quotes sym (let ((val (list 'var (intern (math-remove-dashes (symbol-name sym))) (if (string-match "-" (symbol-name sym)) sym (intern (concat "var-" (symbol-name sym))))))) (let ((v (assq (nth 1 val) math-expr-variable-mapping))) (and v (setq val (if (consp (cdr v)) (funcall (car (cdr v)) v val) (list 'var (intern (substring (symbol-name (cdr v)) 4)) (cdr v)))))) (while (and (memq calc-language '(c pascal maple)) (equal exp-data "[")) (math-read-token) (setq val (append (list 'calcFunc-subscr val) (math-read-expr-list))) (if (equal exp-data "]") (math-read-token) (throw 'syntax "Expected ']'"))) val))))) ((eq exp-token 'dollar) (let ((abs (if (> exp-data 0) exp-data (- exp-data)))) (if (>= (length calc-dollar-values) abs) (let ((num exp-data)) (math-read-token) (setq calc-dollar-used (max calc-dollar-used num)) (math-check-complete (nth (1- abs) calc-dollar-values))) (throw 'syntax (if calc-dollar-values "Too many $'s" "$'s not allowed in this context"))))) ((eq exp-token 'hash) (or calc-hashes-used (throw 'syntax "#'s not allowed in this context")) (calc-extensions) (if (<= exp-data (length calc-arg-values)) (let ((num exp-data)) (math-read-token) (setq calc-hashes-used (max calc-hashes-used num)) (nth (1- num) calc-arg-values)) (throw 'syntax "Too many # arguments"))) ((equal exp-data "(") (let* ((exp (let ((exp-keep-spaces nil)) (math-read-token) (if (or (equal exp-data "\\dots") (equal exp-data "\\ldots")) '(neg (var inf var-inf)) (math-read-expr-level 0))))) (let ((exp-keep-spaces nil)) (cond ((equal exp-data ",") (progn (math-read-token) (let ((exp2 (math-read-expr-level 0))) (setq exp (if (and exp2 (Math-realp exp) (Math-realp exp2)) (math-normalize (list 'cplx exp exp2)) (list '+ exp (list '* exp2 '(var i var-i)))))))) ((equal exp-data ";") (progn (math-read-token) (let ((exp2 (math-read-expr-level 0))) (setq exp (if (and exp2 (Math-realp exp) (Math-anglep exp2)) (math-normalize (list 'polar exp exp2)) (calc-extensions) (list '* exp (list 'calcFunc-exp (list '* (math-to-radians-2 exp2) '(var i var-i))))))))) ((or (equal exp-data "\\dots") (equal exp-data "\\ldots")) (progn (math-read-token) (let ((exp2 (if (or (equal exp-data ")") (equal exp-data "]") (eq exp-token 'end)) '(var inf var-inf) (math-read-expr-level 0)))) (setq exp (list 'intv (if (equal exp-data ")") 0 1) exp exp2))))))) (if (not (or (equal exp-data ")") (and (equal exp-data "]") (eq (car-safe exp) 'intv)) (eq exp-token 'end))) (throw 'syntax "Expected `)'")) (math-read-token) exp)) ((eq exp-token 'string) (calc-extensions) (math-read-string)) ((equal exp-data "[") (calc-extensions) (math-read-brackets t "]")) ((equal exp-data "{") (calc-extensions) (math-read-brackets nil "}")) ((equal exp-data "<") (calc-extensions) (math-read-angle-brackets)) (t (throw 'syntax "Expected a number")))) )