Compiler Common Lisp vers GNU Emacs Calc



Tags : #calc #commonlisp #emacs

Créé le 26 avril 2026.

GNU Emacs Calc est la calculatrice fournie avec Emacs, fonctionnant à l’aide d’une pile (stack). Arithmétique en précision arbitraire, modèle de programmation similaire à celui des calculatrices RPN des années 80, et la possibilité d’être pilotée par macros clavier — des suites d’instructions opérant sur une pile, rejouées via X. La notation y est concise, voire obscure.

Avec 123456789 et 3 déjà sur la pile, retourner les trois premiers chiffres de 123456789 demande :

TAB RET H L F 1 + C-u 3 C-M-i - n f S F

D’autres exemples dans le projet GitHub calc-problem-solving qui résoud plusieurs problème du Projet Euler.

cl-lisp2calc propose une autre voie : écrire l’algorithme en Common Lisp, et le compiler vers les instructions Calc correspondantes.

Un exemple simple :

(lisp2calc:convert '(+ 3 4))
;; output = 3 SPC 4 +

Un cas un peu moins simple — Project Euler 1, la somme des multiples de 3 ou 5 strictement inférieurs à 1000 :

(lisp2calc:convert
 '(let* ((n 1000)
         (sum 0))
   (dotimes (i n)
     (when (or (= 0 (mod i 3)) (= 0 (mod i 5)))
       (incf sum i)))
   sum))

Le compilateur produit :

1000 SPC 0 SPC 0 Z{ RET C-u 4 C-j 1 - a> Z/ 0 C-j 3 % a= Z[ 1 Z: 0 C-j 5 % a= Z] Z[ C-j C-j + C-u 3 M-DEL TAB Z: Z] RET 1 + M-DEL Z} DEL RET M-DEL M-DEL

Pour l’exécuter dans Emacs : sélectionnez la macro, M-x read-kbd-macro, basculez sur Calc, appuyez sur X. La bonne réponse s’affiche.

Le sous-ensemble de Common Lisp pris en charge est volontairement réduit — arithmétique, comparaisons, let/let*, setq/setf, incf/decf, if/when, dotimes, loop repeat, et quelques opérateurs internes à lisp2calc (while, prime-factorization, next-prime, last-element). De quoi exprimer les dix premiers problèmes du Project Euler, tous fournis comme exemples résolus dans le README.

Les tests unitaires vérifient que convert produit les instructions attendues pour des entrées connues — mais une chaîne d’instructions correctes et un calcul correct ne sont pas tout à fait la même chose. Une couche d’intégration optionnelle lance donc emacs --batch, transmet la macro générée à read-kbd-macro, l’exécute dans une véritable session Calc, et relit la pile résultante, pour véifier qu’on aboutit réellement au résultat attendu.

Testé avec SBCL sous Windows.