Initial commit.
authorFrancois Fleuret <francois@fleuret.org>
Sat, 15 Aug 2015 07:25:18 +0000 (00:25 -0700)
committerFrancois Fleuret <francois@fleuret.org>
Sat, 15 Aug 2015 07:25:18 +0000 (00:25 -0700)
arithmlatex.el [new file with mode: 0644]

diff --git a/arithmlatex.el b/arithmlatex.el
new file mode 100644 (file)
index 0000000..7503e0e
--- /dev/null
@@ -0,0 +1,93 @@
+;; -*- mode: emacs-lisp -*-
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; This program is free software; you can redistribute it and/or         ;;
+;; modify it under the terms of the GNU General Public License as        ;;
+;; published by the Free Software Foundation; either version 3, or (at   ;;
+;; your option) any later version.                                       ;;
+;;                                                                       ;;
+;; This program is distributed in the hope that it will be useful, but   ;;
+;; WITHOUT ANY WARRANTY; without even the implied warranty of            ;;
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      ;;
+;; General Public License for more details.                              ;;
+;;                                                                       ;;
+;; You should have received a copy of the GNU General Public License     ;;
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.  ;;
+;;                                                                       ;;
+;; Written by and Copyright (C) Francois Fleuret                         ;;
+;; Contact <francois@fleuret.org> for comments & bug reports             ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; This short scripts performs arithmetic computations in a latex
+;; file. It collects variables defined by \fflet{VARNAME}{VALUE}
+;; expressions in the latex file, and updates the VALUE in the
+;; expressions of the form \ffeval{EXPRESSION}{VALUE}
+
+;; Note that you have to add
+;;
+;; \newcommand{\fflet}[2]{}
+;; \newcommand{\ffeval}[2]{#2}
+;;
+;; Somewhere in your latex file.
+;;
+;; EXAMPLE
+;; \fflet{X}{12} \fflet{Y}{19 + X * (X + 3)} \ffeval{18 * Y}{}
+
+
+(defun arithmlatex/eval (expression var-table)
+  (let ((nb-loops 0))
+    (while (string-match "\\([A-Za-z][A-Za-z0-9_]*\\)" expression)
+      (setq nb-loops (1+ nb-loops)
+            expression
+            (replace-match
+             (concat "(" (gethash (sxhash (match-string 1 expression)) var-table) ")")
+             t t expression))
+      (when (> nb-loops 100) (error "Too many evaluation levels"))
+      ))
+    (calc-eval expression))
+
+(defun arithmlatex (&optional universal) (interactive "P")
+  (let ((var-table (make-hash-table))
+        (nb-changes 0))
+
+    (save-excursion
+
+      ;; First we collect the variable definitions
+      (goto-char (point-min))
+      (while (re-search-forward
+              "\\fflet{\\([^}]*\\)}{\\([^}]*\\)}"
+              nil t)
+        (let ((a (match-string-no-properties 1))
+              (b (match-string-no-properties 2)))
+          (if (gethash (sxhash a) var-table)
+              (error "%s is multiply defined" a))
+          (puthash (sxhash a) b var-table)
+          ))
+
+      ;; Then we evaluate the expressions
+      (goto-char (point-min))
+      (while (re-search-forward
+              "\\ffeval{\\([^}]*\\)}{\\([^}]*\\)}"
+              nil t)
+        (let* ((a (match-string-no-properties 1))
+               (b (match-string-no-properties 2))
+               (start (match-beginning 2))
+               (end (match-end 2))
+               (v (condition-case nil (arithmlatex/eval a var-table) (error "???"))))
+          (if (not (stringp v)) (setq v "???"))
+
+          ;; Do the change only if necessary
+          (unless (string= v b)
+            (setq nb-changes (1+ nb-changes))
+            (unless universal
+              (kill-region start end)
+              (backward-char)
+              (insert v)))
+          ))
+      )
+
+    (if universal
+        (message "There would be %s substitutions" nb-changes)
+      (message "There have been %s substitutions" nb-changes))
+    )
+  )