1 ;; -*- mode: emacs-lisp -*-
3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4 ;; This program is free software; you can redistribute it and/or ;;
5 ;; modify it under the terms of the GNU General Public License as ;;
6 ;; published by the Free Software Foundation; either version 3, or (at ;;
7 ;; your option) any later version. ;;
9 ;; This program is distributed in the hope that it will be useful, but ;;
10 ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;
11 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;
12 ;; General Public License for more details. ;;
14 ;; You should have received a copy of the GNU General Public License ;;
15 ;; along with this program. If not, see <http://www.gnu.org/licenses/>. ;;
17 ;; Written by and Copyright (C) Francois Fleuret ;;
18 ;; Contact <francois@fleuret.org> for comments & bug reports ;;
19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
21 ;; This short scripts performs arithmetic computations in a latex
22 ;; file. It collects variables defined by \fflet{VARNAME}{VALUE}
23 ;; expressions in the latex file, and updates the VALUE in the
24 ;; expressions of the form \ffeval{EXPRESSION}{VALUE}
26 ;; Note that you have to add
28 ;; \newcommand{\fflet}[2]{}
29 ;; \newcommand{\ffeval}[2]{#2}
31 ;; Somewhere in your latex file.
34 ;; \fflet{X}{12} \fflet{Y}{19 + X * (X + 3)} \ffeval{18 * Y}{}
37 (defun arithmlatex/eval (expression var-table)
39 (while (string-match "\\([A-Za-z][A-Za-z0-9_]*\\)" expression)
40 (setq nb-loops (1+ nb-loops)
43 (concat "(" (gethash (sxhash (match-string 1 expression)) var-table) ")")
45 (when (> nb-loops 100) (error "Too many evaluation levels"))
47 (calc-eval expression))
49 (defun arithmlatex (&optional universal) (interactive "P")
50 (let ((var-table (make-hash-table))
55 ;; First we collect the variable definitions
56 (goto-char (point-min))
57 (while (re-search-forward
58 "\\fflet{\\([^}]*\\)}{\\([^}]*\\)}"
60 (let ((a (match-string-no-properties 1))
61 (b (match-string-no-properties 2)))
62 (if (gethash (sxhash a) var-table)
63 (error "%s is multiply defined" a))
64 (puthash (sxhash a) b var-table)
67 ;; Then we evaluate the expressions
68 (goto-char (point-min))
69 (while (re-search-forward
70 "\\ffeval{\\([^}]*\\)}{\\([^}]*\\)}"
72 (let* ((a (match-string-no-properties 1))
73 (b (match-string-no-properties 2))
74 (start (match-beginning 2))
76 (v (condition-case nil (arithmlatex/eval a var-table) (error "???"))))
77 (if (not (stringp v)) (setq v "???"))
79 ;; Do the change only if necessary
81 (setq nb-changes (1+ nb-changes))
83 (kill-region start end)
90 (message "There would be %s substitutions" nb-changes)
91 (message "There have been %s substitutions" nb-changes))