calculator.el 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827
  1. ;;; calculator.el --- a [not so] simple calculator for Emacs
  2. ;; Copyright (C) 1998, 2000-2012 Free Software Foundation, Inc.
  3. ;; Author: Eli Barzilay <eli@barzilay.org>
  4. ;; Keywords: tools, convenience
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;;=====================================================================
  17. ;;; Commentary:
  18. ;;
  19. ;; A calculator for Emacs.
  20. ;; Why should you reach for your mouse to get xcalc (calc.exe, gcalc or
  21. ;; whatever), when you have Emacs running already?
  22. ;;
  23. ;; If this is not part of your Emacs distribution, then simply bind
  24. ;; `calculator' to a key and make it an autoloaded function, e.g.:
  25. ;; (autoload 'calculator "calculator"
  26. ;; "Run the Emacs calculator." t)
  27. ;; (global-set-key [(control return)] 'calculator)
  28. ;;
  29. ;; Written by Eli Barzilay: Maze is Life! eli@barzilay.org
  30. ;; http://www.barzilay.org/
  31. ;;
  32. ;; For latest version, check
  33. ;; http://www.barzilay.org/misc/calculator.el
  34. ;;
  35. ;;; History:
  36. ;; I hate history.
  37. (eval-when-compile (require 'cl))
  38. ;;;=====================================================================
  39. ;;; Customization:
  40. (defgroup calculator nil
  41. "Simple Emacs calculator."
  42. :prefix "calculator"
  43. :version "21.1"
  44. :group 'tools
  45. :group 'applications)
  46. (defcustom calculator-electric-mode nil
  47. "Run `calculator' electrically, in the echo area.
  48. Electric mode saves some place but changes the way you interact with the
  49. calculator."
  50. :type 'boolean
  51. :group 'calculator)
  52. (defcustom calculator-use-menu t
  53. "Make `calculator' create a menu.
  54. Note that this requires easymenu. Must be set before loading."
  55. :type 'boolean
  56. :group 'calculator)
  57. (defcustom calculator-bind-escape nil
  58. "If non-nil, set escape to exit the calculator."
  59. :type 'boolean
  60. :group 'calculator)
  61. (defcustom calculator-unary-style 'postfix
  62. "Value is either 'prefix or 'postfix.
  63. This determines the default behavior of unary operators."
  64. :type '(choice (const prefix) (const postfix))
  65. :group 'calculator)
  66. (defcustom calculator-prompt "Calc=%s> "
  67. "The prompt used by the Emacs calculator.
  68. It should contain a \"%s\" somewhere that will indicate the i/o radices;
  69. this will be a two-character string as described in the documentation
  70. for `calculator-mode'."
  71. :type 'string
  72. :group 'calculator)
  73. (defcustom calculator-number-digits 3
  74. "The calculator's number of digits used for standard display.
  75. Used by the `calculator-standard-display' function - it will use the
  76. format string \"%.NC\" where this number is N and C is a character given
  77. at runtime."
  78. :type 'integer
  79. :group 'calculator)
  80. (defcustom calculator-radix-grouping-mode t
  81. "Use digit grouping in radix output mode.
  82. If this is set, chunks of `calculator-radix-grouping-digits' characters
  83. will be separated by `calculator-radix-grouping-separator' when in radix
  84. output mode is active (determined by `calculator-output-radix')."
  85. :type 'boolean
  86. :group 'calculator)
  87. (defcustom calculator-radix-grouping-digits 4
  88. "The number of digits used for grouping display in radix modes.
  89. See `calculator-radix-grouping-mode'."
  90. :type 'integer
  91. :group 'calculator)
  92. (defcustom calculator-radix-grouping-separator "'"
  93. "The separator used in radix grouping display.
  94. See `calculator-radix-grouping-mode'."
  95. :type 'string
  96. :group 'calculator)
  97. (defcustom calculator-remove-zeros t
  98. "Non-nil value means delete all redundant zero decimal digits.
  99. If this value is not t, and not nil, redundant zeros are removed except
  100. for one and if it is nil, nothing is removed.
  101. Used by the `calculator-remove-zeros' function."
  102. :type '(choice (const t) (const leave-decimal) (const nil))
  103. :group 'calculator)
  104. (defcustom calculator-displayer '(std ?n)
  105. "A displayer specification for numerical values.
  106. This is the displayer used to show all numbers in an expression. Result
  107. values will be displayed according to the first element of
  108. `calculator-displayers'.
  109. The displayer is a symbol, a string or an expression. A symbol should
  110. be the name of a one-argument function, a string is used with a single
  111. argument and an expression will be evaluated with the variable `num'
  112. bound to whatever should be displayed. If it is a function symbol, it
  113. should be able to handle special symbol arguments, currently 'left and
  114. 'right which will be sent by special keys to modify display parameters
  115. associated with the displayer function (for example to change the number
  116. of digits displayed).
  117. An exception to the above is the case of the list (std C) where C is a
  118. character, in this case the `calculator-standard-displayer' function
  119. will be used with this character for a format string."
  120. :group 'calculator)
  121. (defcustom calculator-displayers
  122. '(((std ?n) "Standard display, decimal point or scientific")
  123. (calculator-eng-display "Eng display")
  124. ((std ?f) "Standard display, decimal point")
  125. ((std ?e) "Standard display, scientific")
  126. ("%S" "Emacs printer"))
  127. "A list of displayers.
  128. Each element is a list of a displayer and a description string. The
  129. first element is the one which is currently used, this is for the display
  130. of result values not values in expressions. A displayer specification
  131. is the same as the values that can be stored in `calculator-displayer'.
  132. `calculator-rotate-displayer' rotates this list."
  133. :type 'sexp
  134. :group 'calculator)
  135. (defcustom calculator-paste-decimals t
  136. "If non-nil, convert pasted integers so they have a decimal point.
  137. This makes it possible to paste big integers since they will be read as
  138. floats, otherwise the Emacs reader will fail on them."
  139. :type 'boolean
  140. :group 'calculator)
  141. (defcustom calculator-copy-displayer nil
  142. "If non-nil, this is any value that can be used for
  143. `calculator-displayer', to format a string before copying it with
  144. `calculator-copy'. If nil, then `calculator-displayer's normal value is
  145. used."
  146. :type 'boolean
  147. :group 'calculator)
  148. (defcustom calculator-2s-complement nil
  149. "If non-nil, show negative numbers in 2s complement in radix modes.
  150. Otherwise show as a negative number."
  151. :type 'boolean
  152. :group 'calculator)
  153. (defcustom calculator-mode-hook nil
  154. "List of hook functions for `calculator-mode' to run.
  155. Note: if `calculator-electric-mode' is on, then this hook will get
  156. activated in the minibuffer - in that case it should not do much more
  157. than local key settings and other effects that will change things
  158. outside the scope of calculator related code."
  159. :type 'hook
  160. :group 'calculator)
  161. (defcustom calculator-user-registers nil
  162. "An association list of user-defined register bindings.
  163. Each element in this list is a list of a character and a number that
  164. will be stored in that character's register.
  165. For example, use this to define the golden ratio number:
  166. (setq calculator-user-registers '((?g . 1.61803398875)))
  167. before you load calculator."
  168. :type '(repeat (cons character number))
  169. :set (lambda (_ val)
  170. (and (boundp 'calculator-registers)
  171. (setq calculator-registers
  172. (append val calculator-registers)))
  173. (setq calculator-user-registers val))
  174. :group 'calculator)
  175. (defcustom calculator-user-operators nil
  176. "A list of additional operators.
  177. This is a list in the same format as specified in the documentation for
  178. `calculator-operators', that you can use to bind additional calculator
  179. operators. It is probably not a good idea to modify this value with
  180. `customize' since it is too complex...
  181. Examples:
  182. * A very simple one, adding a postfix \"x-to-y\" conversion keys, using
  183. t as a prefix key:
  184. (setq calculator-user-operators
  185. '((\"tf\" cl-to-fr (+ 32 (/ (* X 9) 5)) 1)
  186. (\"tc\" fr-to-cl (/ (* (- X 32) 5) 9) 1)
  187. (\"tp\" kg-to-lb (/ X 0.453592) 1)
  188. (\"tk\" lb-to-kg (* X 0.453592) 1)
  189. (\"tF\" mt-to-ft (/ X 0.3048) 1)
  190. (\"tM\" ft-to-mt (* X 0.3048) 1)))
  191. * Using a function-like form is very simple, X for an argument (Y the
  192. second in case of a binary operator), TX is a truncated version of X
  193. and F does a recursive call, Here is a [very inefficient] Fibonacci
  194. number calculation:
  195. (add-to-list 'calculator-user-operators
  196. '(\"F\" fib (if (<= TX 1)
  197. 1
  198. (+ (F (- TX 1)) (F (- TX 2)))) 0))
  199. Note that this will be either postfix or prefix, according to
  200. `calculator-unary-style'."
  201. :type '(repeat (list string symbol sexp integer integer))
  202. :group 'calculator)
  203. ;;;=====================================================================
  204. ;;; Code:
  205. ;;;---------------------------------------------------------------------
  206. ;;; Variables
  207. (defvar calculator-initial-operators
  208. '(;; "+"/"-" have keybindings of themselves, not calculator-ops
  209. ("=" = identity 1 -1)
  210. (nobind "+" + + 2 4)
  211. (nobind "-" - - 2 4)
  212. (nobind "+" + + -1 9)
  213. (nobind "-" - - -1 9)
  214. ("(" \( identity -1 -1)
  215. (")" \) identity +1 10)
  216. ;; normal keys
  217. ("|" or (logior TX TY) 2 2)
  218. ("#" xor (logxor TX TY) 2 2)
  219. ("&" and (logand TX TY) 2 3)
  220. ("*" * * 2 5)
  221. ("/" / / 2 5)
  222. ("\\" div (/ TX TY) 2 5)
  223. ("%" rem (% TX TY) 2 5)
  224. ("L" log log 2 6)
  225. ("S" sin (sin DX) x 6)
  226. ("C" cos (cos DX) x 6)
  227. ("T" tan (tan DX) x 6)
  228. ("IS" asin (D (asin X)) x 6)
  229. ("IC" acos (D (acos X)) x 6)
  230. ("IT" atan (D (atan X)) x 6)
  231. ("Q" sqrt sqrt x 7)
  232. ("^" ^ calculator-expt 2 7)
  233. ("!" ! calculator-fact x 7)
  234. (";" 1/ (/ 1 X) 1 7)
  235. ("_" - - 1 8)
  236. ("~" ~ (lognot TX) x 8)
  237. (">" repR calculator-repR 1 8)
  238. ("<" repL calculator-repL 1 8)
  239. ("v" avg (/ (apply '+ L) (length L)) 0 8)
  240. ("l" tot (apply '+ L) 0 8)
  241. )
  242. "A list of initial operators.
  243. This is a list in the same format as `calculator-operators'. Whenever
  244. `calculator' starts, it looks at the value of this variable, and if it
  245. is not empty, its contents is prepended to `calculator-operators' and
  246. the appropriate key bindings are made.
  247. This variable is then reset to nil. Don't use this if you want to add
  248. user-defined operators, use `calculator-user-operators' instead.")
  249. (defvar calculator-operators nil
  250. "The calculator operators, each a list with:
  251. 1. The key that is bound to for this operation (usually a string);
  252. 2. The displayed symbol for this function;
  253. 3. The function symbol, or a form that uses the variables `X' and `Y',
  254. (if it is a binary operator), `TX' and `TY' (truncated integer
  255. versions), `DX' (converted to radians if degrees mode is on), `D'
  256. (function for converting radians to degrees if deg mode is on), `L'
  257. (list of saved values), `F' (function for recursive iteration calls)
  258. and evaluates to the function value - these variables are capital;
  259. 4. The function's arity, optional, one of: 2 => binary, -1 => prefix
  260. unary, +1 => postfix unary, 0 => a 0-arg operator func, non-number =>
  261. postfix/prefix as determined by `calculator-unary-style' (the
  262. default);
  263. 5. The function's precedence - should be in the range of 1 (lowest) to
  264. 9 (highest) (optional, defaults to 1);
  265. It it possible have a unary prefix version of a binary operator if it
  266. comes later in this list. If the list begins with the symbol 'nobind,
  267. then no key binding will take place - this is only useful for predefined
  268. keys.
  269. Use `calculator-user-operators' to add operators to this list, see its
  270. documentation for an example.")
  271. (defvar calculator-stack nil
  272. "Stack contents - operations and operands.")
  273. (defvar calculator-curnum nil
  274. "Current number being entered (as a string).")
  275. (defvar calculator-stack-display nil
  276. "Cons of the stack and its string representation.")
  277. (defvar calculator-char-radix
  278. '((?D . nil) (?B . bin) (?O . oct) (?H . hex) (?X . hex))
  279. "A table to convert input characters to corresponding radix symbols.")
  280. (defvar calculator-output-radix nil
  281. "The mode for display, one of: nil (decimal), 'bin, 'oct or 'hex.")
  282. (defvar calculator-input-radix nil
  283. "The mode for input, one of: nil (decimal), 'bin, 'oct or 'hex.")
  284. (defvar calculator-deg nil
  285. "Non-nil if trig functions operate on degrees instead of radians.")
  286. (defvar calculator-saved-list nil
  287. "A list of saved values collected.")
  288. (defvar calculator-saved-ptr 0
  289. "The pointer to the current saved number.")
  290. (defvar calculator-add-saved nil
  291. "Bound to t when a value should be added to the saved-list.")
  292. (defvar calculator-display-fragile nil
  293. "When non-nil, we see something that the next digit should replace.")
  294. (defvar calculator-buffer nil
  295. "The current calculator buffer.")
  296. (defvar calculator-eng-extra nil
  297. "Internal value used by `calculator-eng-display'.")
  298. (defvar calculator-eng-tmp-show nil
  299. "Internal value used by `calculator-eng-display'.")
  300. (defvar calculator-last-opXY nil
  301. "The last binary operation and its arguments.
  302. Used for repeating operations in calculator-repR/L.")
  303. (defvar calculator-registers ; use user-bindings first
  304. (append calculator-user-registers
  305. (list (cons ?e float-e) (cons ?p float-pi)))
  306. "The association list of calculator register values.")
  307. (defvar calculator-saved-global-map nil
  308. "Saved global key map.")
  309. (defvar calculator-restart-other-mode nil
  310. "Used to hack restarting with the electric mode changed.")
  311. ;;;---------------------------------------------------------------------
  312. ;;; Key bindings
  313. (defvar calculator-mode-map
  314. (let ((map (make-sparse-keymap)))
  315. (suppress-keymap map t)
  316. (define-key map "i" nil)
  317. (define-key map "o" nil)
  318. (let ((p
  319. '((calculator-open-paren "[")
  320. (calculator-close-paren "]")
  321. (calculator-op-or-exp "+" "-" [kp-add] [kp-subtract])
  322. (calculator-digit "0" "1" "2" "3" "4" "5" "6" "7" "8"
  323. "9" "a" "b" "c" "d" "f"
  324. [kp-0] [kp-1] [kp-2] [kp-3] [kp-4]
  325. [kp-5] [kp-6] [kp-7] [kp-8] [kp-9])
  326. (calculator-op [kp-divide] [kp-multiply])
  327. (calculator-decimal "." [kp-decimal])
  328. (calculator-exp "e")
  329. (calculator-dec/deg-mode "D")
  330. (calculator-set-register "s")
  331. (calculator-get-register "g")
  332. (calculator-radix-mode "H" "X" "O" "B")
  333. (calculator-radix-input-mode "id" "ih" "ix" "io" "ib"
  334. "iD" "iH" "iX" "iO" "iB")
  335. (calculator-radix-output-mode "od" "oh" "ox" "oo" "ob"
  336. "oD" "oH" "oX" "oO" "oB")
  337. (calculator-rotate-displayer "'")
  338. (calculator-rotate-displayer-back "\"")
  339. (calculator-displayer-prev "{")
  340. (calculator-displayer-next "}")
  341. (calculator-saved-up [up] [?\C-p])
  342. (calculator-saved-down [down] [?\C-n])
  343. (calculator-quit "q" [?\C-g])
  344. (calculator-enter [enter] [linefeed] [kp-enter]
  345. [return] [?\r] [?\n])
  346. (calculator-save-on-list " " [space])
  347. (calculator-clear-saved [?\C-c] [(control delete)])
  348. (calculator-save-and-quit [(control return)]
  349. [(control kp-enter)])
  350. (calculator-paste [insert] [(shift insert)]
  351. [paste] [mouse-2] [?\C-y])
  352. (calculator-clear [delete] [?\C-?] [?\C-d])
  353. (calculator-help [?h] [??] [f1] [help])
  354. (calculator-copy [(control insert)] [copy])
  355. (calculator-backspace [backspace])
  356. )))
  357. (while p
  358. ;; reverse the keys so first defs come last - makes the more
  359. ;; sensible bindings visible in the menu
  360. (let ((func (car (car p))) (keys (reverse (cdr (car p)))))
  361. (while keys
  362. (define-key map (car keys) func)
  363. (setq keys (cdr keys))))
  364. (setq p (cdr p))))
  365. (if calculator-bind-escape
  366. (progn (define-key map [?\e] 'calculator-quit)
  367. (define-key map [escape] 'calculator-quit))
  368. (define-key map [?\e ?\e ?\e] 'calculator-quit))
  369. ;; make C-h work in text-mode
  370. (or window-system (define-key map [?\C-h] 'calculator-backspace))
  371. ;; set up a menu
  372. (if (and calculator-use-menu (not (boundp 'calculator-menu)))
  373. (let ((radix-selectors
  374. (mapcar (lambda (x)
  375. `([,(nth 0 x)
  376. (calculator-radix-mode ,(nth 2 x))
  377. :style radio
  378. :keys ,(nth 2 x)
  379. :selected
  380. (and
  381. (eq calculator-input-radix ',(nth 1 x))
  382. (eq calculator-output-radix ',(nth 1 x)))]
  383. [,(concat (nth 0 x) " Input")
  384. (calculator-radix-input-mode ,(nth 2 x))
  385. :keys ,(concat "i" (downcase (nth 2 x)))
  386. :style radio
  387. :selected
  388. (eq calculator-input-radix ',(nth 1 x))]
  389. [,(concat (nth 0 x) " Output")
  390. (calculator-radix-output-mode ,(nth 2 x))
  391. :keys ,(concat "o" (downcase (nth 2 x)))
  392. :style radio
  393. :selected
  394. (eq calculator-output-radix ',(nth 1 x))]))
  395. '(("Decimal" nil "D")
  396. ("Binary" bin "B")
  397. ("Octal" oct "O")
  398. ("Hexadecimal" hex "H"))))
  399. (op (lambda (name key)
  400. `[,name (calculator-op ,key) :keys ,key])))
  401. (easy-menu-define
  402. calculator-menu map "Calculator menu."
  403. `("Calculator"
  404. ["Help"
  405. (let ((last-command 'calculator-help)) (calculator-help))
  406. :keys "?"]
  407. "---"
  408. ["Copy" calculator-copy]
  409. ["Paste" calculator-paste]
  410. "---"
  411. ["Electric mode"
  412. (progn (calculator-quit)
  413. (setq calculator-restart-other-mode t)
  414. (run-with-timer 0.1 nil (lambda () (message nil)))
  415. ;; the message from the menu will be visible,
  416. ;; couldn't make it go away...
  417. (calculator))
  418. :active (not calculator-electric-mode)]
  419. ["Normal mode"
  420. (progn (setq calculator-restart-other-mode t)
  421. (calculator-quit))
  422. :active calculator-electric-mode]
  423. "---"
  424. ("Functions"
  425. ,(funcall op "Repeat-right" ">")
  426. ,(funcall op "Repeat-left" "<")
  427. "------General------"
  428. ,(funcall op "Reciprocal" ";")
  429. ,(funcall op "Log" "L")
  430. ,(funcall op "Square-root" "Q")
  431. ,(funcall op "Factorial" "!")
  432. "------Trigonometric------"
  433. ,(funcall op "Sinus" "S")
  434. ,(funcall op "Cosine" "C")
  435. ,(funcall op "Tangent" "T")
  436. ,(funcall op "Inv-Sinus" "IS")
  437. ,(funcall op "Inv-Cosine" "IC")
  438. ,(funcall op "Inv-Tangent" "IT")
  439. "------Bitwise------"
  440. ,(funcall op "Or" "|")
  441. ,(funcall op "Xor" "#")
  442. ,(funcall op "And" "&")
  443. ,(funcall op "Not" "~"))
  444. ("Saved List"
  445. ["Eval+Save" calculator-save-on-list]
  446. ["Prev number" calculator-saved-up]
  447. ["Next number" calculator-saved-down]
  448. ["Delete current" calculator-clear
  449. :active (and calculator-display-fragile
  450. calculator-saved-list
  451. (= (car calculator-stack)
  452. (nth calculator-saved-ptr
  453. calculator-saved-list)))]
  454. ["Delete all" calculator-clear-saved]
  455. "---"
  456. ,(funcall op "List-total" "l")
  457. ,(funcall op "List-average" "v"))
  458. ("Registers"
  459. ["Get register" calculator-get-register]
  460. ["Set register" calculator-set-register])
  461. ("Modes"
  462. ["Radians"
  463. (progn
  464. (and (or calculator-input-radix calculator-output-radix)
  465. (calculator-radix-mode "D"))
  466. (and calculator-deg (calculator-dec/deg-mode)))
  467. :keys "D"
  468. :style radio
  469. :selected (not (or calculator-input-radix
  470. calculator-output-radix
  471. calculator-deg))]
  472. ["Degrees"
  473. (progn
  474. (and (or calculator-input-radix calculator-output-radix)
  475. (calculator-radix-mode "D"))
  476. (or calculator-deg (calculator-dec/deg-mode)))
  477. :keys "D"
  478. :style radio
  479. :selected (and calculator-deg
  480. (not (or calculator-input-radix
  481. calculator-output-radix)))]
  482. "---"
  483. ,@(mapcar 'car radix-selectors)
  484. ("Separate I/O"
  485. ,@(mapcar (lambda (x) (nth 1 x)) radix-selectors)
  486. "---"
  487. ,@(mapcar (lambda (x) (nth 2 x)) radix-selectors)))
  488. ("Decimal Display"
  489. ,@(mapcar (lambda (d)
  490. (vector (cadr d)
  491. ;; Note: inserts actual object here
  492. `(calculator-rotate-displayer ',d)))
  493. calculator-displayers)
  494. "---"
  495. ["Change Prev Display" calculator-displayer-prev]
  496. ["Change Next Display" calculator-displayer-next])
  497. "---"
  498. ["Copy+Quit" calculator-save-and-quit]
  499. ["Quit" calculator-quit]))))
  500. map)
  501. "The calculator key map.")
  502. ;;;---------------------------------------------------------------------
  503. ;;; Startup and mode stuff
  504. (define-derived-mode calculator-mode fundamental-mode "Calculator"
  505. ;; this help is also used as the major help screen
  506. "A [not so] simple calculator for Emacs.
  507. This calculator is used in the same way as other popular calculators
  508. like xcalc or calc.exe - but using an Emacs interface.
  509. Expressions are entered using normal infix notation, parens are used as
  510. normal. Unary functions are usually postfix, but some depends on the
  511. value of `calculator-unary-style' (if the style for an operator below is
  512. specified, then it is fixed, otherwise it depends on this variable).
  513. `+' and `-' can be used as either binary operators or prefix unary
  514. operators. Numbers can be entered with exponential notation using `e',
  515. except when using a non-decimal radix mode for input (in this case `e'
  516. will be the hexadecimal digit). If the result of a calculation is too
  517. large (out of range for Emacs), the value of \"inf\" is returned.
  518. Here are the editing keys:
  519. * `RET' `=' evaluate the current expression
  520. * `C-insert' copy the whole current expression to the `kill-ring'
  521. * `C-return' evaluate, save result the `kill-ring' and exit
  522. * `insert' paste a number if the one was copied (normally)
  523. * `delete' `C-d' clear last argument or whole expression (hit twice)
  524. * `backspace' delete a digit or a previous expression element
  525. * `h' `?' pop-up a quick reference help
  526. * `ESC' `q' exit (`ESC' can be used if `calculator-bind-escape' is
  527. non-nil, otherwise use three consecutive `ESC's)
  528. These operators are pre-defined:
  529. * `+' `-' `*' `/' the common binary operators
  530. * `\\' `%' integer division and reminder
  531. * `_' `;' postfix unary negation and reciprocal
  532. * `^' `L' binary operators for x^y and log(x) in base y
  533. * `Q' `!' unary square root and factorial
  534. * `S' `C' `T' unary trigonometric operators - sin, cos and tan
  535. * `|' `#' `&' `~' bitwise operators - or, xor, and, not
  536. The trigonometric functions can be inverted if prefixed with an `I', see
  537. below for the way to use degrees instead of the default radians.
  538. Two special postfix unary operators are `>' and `<': whenever a binary
  539. operator is performed, it is remembered along with its arguments; then
  540. `>' (`<') will apply the same operator with the same right (left)
  541. argument.
  542. hex/oct/bin modes can be set for input and for display separately.
  543. Another toggle-able mode is for using degrees instead of radians for
  544. trigonometric functions.
  545. The keys to switch modes are (`X' is shortcut for `H'):
  546. * `D' switch to all-decimal mode, or toggle degrees/radians
  547. * `B' `O' `H' `X' binary/octal/hexadecimal modes for input & display
  548. * `i' `o' followed by one of `D' `B' `O' `H' `X' (case
  549. insensitive) sets only the input or display radix mode
  550. The prompt indicates the current modes:
  551. * \"D=\": degrees mode;
  552. * \"?=\": (? is B/O/H) this is the radix for both input and output;
  553. * \"=?\": (? is B/O/H) the display radix (when input is decimal);
  554. * \"??\": (? is D/B/O/H) 1st char for input radix, 2nd for display.
  555. Also, the quote key can be used to switch display modes for decimal
  556. numbers (double-quote rotates back), and the two brace characters
  557. \(\"{\" and \"}\" change display parameters that these displayers use (if
  558. they handle such). If output is using any radix mode, then these keys
  559. toggle digit grouping mode and the chunk size.
  560. Values can be saved for future reference in either a list of saved
  561. values, or in registers.
  562. The list of saved values is useful for statistics operations on some
  563. collected data. It is possible to navigate in this list, and if the
  564. value shown is the current one on the list, an indication is displayed
  565. as \"[N]\" if this is the last number and there are N numbers, or
  566. \"[M/N]\" if the M-th value is shown.
  567. * `SPC' evaluate the current value as usual, but also adds
  568. the result to the list of saved values
  569. * `l' `v' computes total / average of saved values
  570. * `up' `C-p' browse to the previous value in the list
  571. * `down' `C-n' browse to the next value in the list
  572. * `delete' `C-d' remove current value from the list (if it is on it)
  573. * `C-delete' `C-c' delete the whole list
  574. Registers are variable-like place-holders for values:
  575. * `s' followed by a character attach the current value to that character
  576. * `g' followed by a character fetches the attached value
  577. There are many variables that can be used to customize the calculator.
  578. Some interesting customization variables are:
  579. * `calculator-electric-mode' use only the echo-area electrically.
  580. * `calculator-unary-style' set most unary ops to pre/postfix style.
  581. * `calculator-user-registers' to define user-preset registers.
  582. * `calculator-user-operators' to add user-defined operators.
  583. See the documentation for these variables, and \"calculator.el\" for
  584. more information.
  585. \\{calculator-mode-map}")
  586. (eval-when-compile (require 'electric) (require 'ehelp))
  587. ;;;###autoload
  588. (defun calculator ()
  589. "Run the Emacs calculator.
  590. See the documentation for `calculator-mode' for more information."
  591. (interactive)
  592. (if calculator-restart-other-mode
  593. (setq calculator-electric-mode (not calculator-electric-mode)))
  594. (if calculator-initial-operators
  595. (progn (calculator-add-operators calculator-initial-operators)
  596. (setq calculator-initial-operators nil)
  597. ;; don't change this since it is a customization variable,
  598. ;; its set function will add any new operators
  599. (calculator-add-operators calculator-user-operators)))
  600. (setq calculator-buffer (get-buffer-create "*calculator*"))
  601. (if calculator-electric-mode
  602. (save-window-excursion
  603. (progn (require 'electric) (message nil)) ; hide load message
  604. (let (old-g-map old-l-map (echo-keystrokes 0)
  605. (garbage-collection-messages nil)) ; no gc msg when electric
  606. (set-window-buffer (minibuffer-window) calculator-buffer)
  607. (select-window (minibuffer-window))
  608. (calculator-reset)
  609. (calculator-update-display)
  610. (setq old-l-map (current-local-map))
  611. (setq old-g-map (current-global-map))
  612. (setq calculator-saved-global-map (current-global-map))
  613. (use-local-map nil)
  614. (use-global-map calculator-mode-map)
  615. (run-hooks 'calculator-mode-hook)
  616. (unwind-protect
  617. (catch 'calculator-done
  618. (Electric-command-loop
  619. 'calculator-done
  620. ;; can't use 'noprompt, bug in electric.el
  621. (lambda () 'noprompt)
  622. nil
  623. (lambda (x y) (calculator-update-display))))
  624. (and calculator-buffer
  625. (catch 'calculator-done (calculator-quit)))
  626. (use-local-map old-l-map)
  627. (use-global-map old-g-map))))
  628. (progn
  629. (cond
  630. ((not (get-buffer-window calculator-buffer))
  631. (let ((window-min-height 2))
  632. ;; maybe leave two lines for our window because of the normal
  633. ;; `raised' modeline in Emacs 21
  634. (select-window
  635. (split-window-below
  636. ;; If the modeline might interfere with the calculator buffer,
  637. ;; use 3 lines instead.
  638. (if (and (fboundp 'face-attr-construct)
  639. (let* ((dh (plist-get (face-attr-construct 'default) :height))
  640. (mf (face-attr-construct 'modeline))
  641. (mh (plist-get mf :height)))
  642. ;; If the modeline is shorter than the default,
  643. ;; stick with 2 lines. (It may be necessary to
  644. ;; check how much shorter.)
  645. (and
  646. (not
  647. (or (and (integerp dh)
  648. (integerp mh)
  649. (< mh dh))
  650. (and (numberp mh)
  651. (not (integerp mh))
  652. (< mh 1))))
  653. (or
  654. ;; If the modeline is taller than the default,
  655. ;; use 3 lines.
  656. (and (integerp dh)
  657. (integerp mh)
  658. (> mh dh))
  659. (and (numberp mh)
  660. (not (integerp mh))
  661. (> mh 1))
  662. ;; If the modeline has a box with non-negative line-width,
  663. ;; use 3 lines.
  664. (let* ((bx (plist-get mf :box))
  665. (lh (plist-get bx :line-width)))
  666. (and bx
  667. (or
  668. (not lh)
  669. (> lh 0))))
  670. ;; If the modeline has an overline, use 3 lines.
  671. (plist-get (face-attr-construct 'modeline) :overline)))))
  672. -3 -2)))
  673. (switch-to-buffer calculator-buffer)))
  674. ((not (eq (current-buffer) calculator-buffer))
  675. (select-window (get-buffer-window calculator-buffer))))
  676. (calculator-mode)
  677. (setq buffer-read-only t)
  678. (calculator-reset)
  679. (message "Hit `?' For a quick help screen.")))
  680. (if (and calculator-restart-other-mode calculator-electric-mode)
  681. (calculator)))
  682. (defun calculator-message (string &rest arguments)
  683. "Same as `message', but special handle of electric mode."
  684. (apply 'message string arguments)
  685. (if calculator-electric-mode
  686. (progn (sit-for 1) (message nil))))
  687. ;;;---------------------------------------------------------------------
  688. ;;; Operators
  689. (defun calculator-op-arity (op)
  690. "Return OP's arity, 2, +1 or -1."
  691. (let ((arity (or (nth 3 op) 'x)))
  692. (if (numberp arity)
  693. arity
  694. (if (eq calculator-unary-style 'postfix) +1 -1))))
  695. (defun calculator-op-prec (op)
  696. "Return OP's precedence for reducing when inserting into the stack.
  697. Defaults to 1."
  698. (or (nth 4 op) 1))
  699. (defun calculator-add-operators (more-ops)
  700. "This function handles operator addition.
  701. Adds MORE-OPS to `calculator-operator', called initially to handle
  702. `calculator-initial-operators' and `calculator-user-operators'."
  703. (let ((added-ops nil))
  704. (while more-ops
  705. (or (eq (car (car more-ops)) 'nobind)
  706. (let ((i -1) (key (car (car more-ops))))
  707. ;; make sure the key is undefined, so it's easy to define
  708. ;; prefix keys
  709. (while (< (setq i (1+ i)) (length key))
  710. (or (keymapp
  711. (lookup-key calculator-mode-map
  712. (substring key 0 (1+ i))))
  713. (progn
  714. (define-key
  715. calculator-mode-map (substring key 0 (1+ i)) nil)
  716. (setq i (length key)))))
  717. (define-key calculator-mode-map key 'calculator-op)))
  718. (setq added-ops (cons (if (eq (car (car more-ops)) 'nobind)
  719. (cdr (car more-ops))
  720. (car more-ops))
  721. added-ops))
  722. (setq more-ops (cdr more-ops)))
  723. ;; added-ops come first, but in correct order
  724. (setq calculator-operators
  725. (append (nreverse added-ops) calculator-operators))))
  726. ;;;---------------------------------------------------------------------
  727. ;;; Display stuff
  728. (defun calculator-reset ()
  729. "Reset calculator variables."
  730. (or calculator-restart-other-mode
  731. (setq calculator-stack nil
  732. calculator-curnum nil
  733. calculator-stack-display nil
  734. calculator-display-fragile nil))
  735. (setq calculator-restart-other-mode nil)
  736. (calculator-update-display))
  737. (defun calculator-get-prompt ()
  738. "Return a string to display.
  739. The string is set not to exceed the screen width."
  740. (let* ((calculator-prompt
  741. (format calculator-prompt
  742. (cond
  743. ((or calculator-output-radix calculator-input-radix)
  744. (if (eq calculator-output-radix
  745. calculator-input-radix)
  746. (concat
  747. (char-to-string
  748. (car (rassq calculator-output-radix
  749. calculator-char-radix)))
  750. "=")
  751. (concat
  752. (if calculator-input-radix
  753. (char-to-string
  754. (car (rassq calculator-input-radix
  755. calculator-char-radix)))
  756. "=")
  757. (char-to-string
  758. (car (rassq calculator-output-radix
  759. calculator-char-radix))))))
  760. (calculator-deg "D=")
  761. (t "=="))))
  762. (prompt
  763. (concat calculator-prompt
  764. (cdr calculator-stack-display)
  765. (cond (calculator-curnum
  766. ;; number being typed
  767. (concat calculator-curnum "_"))
  768. ((and (= 1 (length calculator-stack))
  769. calculator-display-fragile)
  770. ;; only the result is shown, next number will
  771. ;; restart
  772. nil)
  773. (t
  774. ;; waiting for a number or an operator
  775. "?"))))
  776. (trim (- (length prompt) (1- (window-width)))))
  777. (if (<= trim 0)
  778. prompt
  779. (concat calculator-prompt
  780. (substring prompt (+ trim (length calculator-prompt)))))))
  781. (defun calculator-string-to-number (str)
  782. "Convert the given STR to a number, according to the value of
  783. `calculator-input-radix'."
  784. (if calculator-input-radix
  785. (let ((radix
  786. (cdr (assq calculator-input-radix
  787. '((bin . 2) (oct . 8) (hex . 16)))))
  788. (i -1) (value 0) (new-value 0))
  789. ;; assume mostly valid input (e.g., characters in range)
  790. (while (< (setq i (1+ i)) (length str))
  791. (setq new-value
  792. (let* ((ch (upcase (aref str i)))
  793. (n (cond ((< ch ?0) nil)
  794. ((<= ch ?9) (- ch ?0))
  795. ((< ch ?A) nil)
  796. ((<= ch ?Z) (- ch (- ?A 10)))
  797. (t nil))))
  798. (if (and n (<= 0 n) (< n radix))
  799. (+ n (* radix value))
  800. (progn
  801. (calculator-message
  802. "Warning: Ignoring bad input character `%c'." ch)
  803. (sit-for 1)
  804. value))))
  805. (if (if (< new-value 0) (> value 0) (< value 0))
  806. (calculator-message "Warning: Overflow in input."))
  807. (setq value new-value))
  808. value)
  809. (car (read-from-string
  810. (cond ((equal "." str) "0.0")
  811. ((string-match "[eE][+-]?$" str) (concat str "0"))
  812. ((string-match "\\.[0-9]\\|[eE]" str) str)
  813. ((string-match "\\." str)
  814. ;; do this because Emacs reads "23." as an integer
  815. (concat str "0"))
  816. ((stringp str) (concat str ".0"))
  817. (t "0.0"))))))
  818. (defun calculator-curnum-value ()
  819. "Get the numeric value of the displayed number string as a float."
  820. (calculator-string-to-number calculator-curnum))
  821. (defun calculator-rotate-displayer (&optional new-disp)
  822. "Switch to the next displayer on the `calculator-displayers' list.
  823. Can be called with an optional argument NEW-DISP to force rotation to
  824. that argument.
  825. If radix output mode is active, toggle digit grouping."
  826. (interactive)
  827. (cond
  828. (calculator-output-radix
  829. (setq calculator-radix-grouping-mode
  830. (not calculator-radix-grouping-mode))
  831. (calculator-message
  832. "Digit grouping mode %s."
  833. (if calculator-radix-grouping-mode "ON" "OFF")))
  834. (t
  835. (setq calculator-displayers
  836. (if (and new-disp (memq new-disp calculator-displayers))
  837. (let ((tmp nil))
  838. (while (not (eq (car calculator-displayers) new-disp))
  839. (setq tmp (cons (car calculator-displayers) tmp))
  840. (setq calculator-displayers
  841. (cdr calculator-displayers)))
  842. (setq calculator-displayers
  843. (nconc calculator-displayers (nreverse tmp))))
  844. (nconc (cdr calculator-displayers)
  845. (list (car calculator-displayers)))))
  846. (calculator-message
  847. "Using %s." (cadr (car calculator-displayers)))))
  848. (calculator-enter))
  849. (defun calculator-rotate-displayer-back ()
  850. "Like `calculator-rotate-displayer', but rotates modes back.
  851. If radix output mode is active, toggle digit grouping."
  852. (interactive)
  853. (calculator-rotate-displayer (car (last calculator-displayers))))
  854. (defun calculator-displayer-prev ()
  855. "Send the current displayer function a 'left argument.
  856. This is used to modify display arguments (if the current displayer
  857. function supports this).
  858. If radix output mode is active, increase the grouping size."
  859. (interactive)
  860. (if calculator-output-radix
  861. (progn (setq calculator-radix-grouping-digits
  862. (1+ calculator-radix-grouping-digits))
  863. (calculator-enter))
  864. (and (car calculator-displayers)
  865. (let ((disp (caar calculator-displayers)))
  866. (cond
  867. ((symbolp disp) (funcall disp 'left))
  868. ((and (consp disp) (eq 'std (car disp)))
  869. (calculator-standard-displayer 'left (cadr disp))))))))
  870. (defun calculator-displayer-next ()
  871. "Send the current displayer function a 'right argument.
  872. This is used to modify display arguments (if the current displayer
  873. function supports this).
  874. If radix output mode is active, decrease the grouping size."
  875. (interactive)
  876. (if calculator-output-radix
  877. (progn (setq calculator-radix-grouping-digits
  878. (max 2 (1- calculator-radix-grouping-digits)))
  879. (calculator-enter))
  880. (and (car calculator-displayers)
  881. (let ((disp (caar calculator-displayers)))
  882. (cond
  883. ((symbolp disp) (funcall disp 'right))
  884. ((and (consp disp) (eq 'std (car disp)))
  885. (calculator-standard-displayer 'right (cadr disp))))))))
  886. (defun calculator-remove-zeros (numstr)
  887. "Get a number string NUMSTR and remove unnecessary zeros.
  888. The behavior of this function is controlled by
  889. `calculator-remove-zeros'."
  890. (cond ((and (eq calculator-remove-zeros t)
  891. (string-match "\\.0+\\([eE][+-]?[0-9]*\\)?$" numstr))
  892. ;; remove all redundant zeros leaving an integer
  893. (if (match-beginning 1)
  894. (concat (substring numstr 0 (match-beginning 0))
  895. (match-string 1 numstr))
  896. (substring numstr 0 (match-beginning 0))))
  897. ((and calculator-remove-zeros
  898. (string-match
  899. "\\..\\([0-9]*[1-9]\\)?\\(0+\\)\\([eE][+-]?[0-9]*\\)?$"
  900. numstr))
  901. ;; remove zeros, except for first after the "."
  902. (if (match-beginning 3)
  903. (concat (substring numstr 0 (match-beginning 2))
  904. (match-string 3 numstr))
  905. (substring numstr 0 (match-beginning 2))))
  906. (t numstr)))
  907. (defun calculator-standard-displayer (num char)
  908. "Standard display function, used to display NUM.
  909. Its behavior is determined by `calculator-number-digits' and the given
  910. CHAR argument (both will be used to compose a format string). If the
  911. char is \"n\" then this function will choose one between %f or %e, this
  912. is a work around %g jumping to exponential notation too fast.
  913. The special 'left and 'right symbols will make it change the current
  914. number of digits displayed (`calculator-number-digits').
  915. It will also remove redundant zeros from the result."
  916. (if (symbolp num)
  917. (cond ((eq num 'left)
  918. (and (> calculator-number-digits 0)
  919. (setq calculator-number-digits
  920. (1- calculator-number-digits))
  921. (calculator-enter)))
  922. ((eq num 'right)
  923. (setq calculator-number-digits
  924. (1+ calculator-number-digits))
  925. (calculator-enter)))
  926. (let ((str (if (zerop num)
  927. "0"
  928. (format
  929. (concat "%."
  930. (number-to-string calculator-number-digits)
  931. (if (eq char ?n)
  932. (let ((n (abs num)))
  933. (if (or (< n 0.001) (> n 1e8)) "e" "f"))
  934. (string char)))
  935. num))))
  936. (calculator-remove-zeros str))))
  937. (defun calculator-eng-display (num)
  938. "Display NUM in engineering notation.
  939. The number of decimal digits used is controlled by
  940. `calculator-number-digits', so to change it at runtime you have to use
  941. the 'left or 'right when one of the standard modes is used."
  942. (if (symbolp num)
  943. (cond ((eq num 'left)
  944. (setq calculator-eng-extra
  945. (if calculator-eng-extra
  946. (1+ calculator-eng-extra)
  947. 1))
  948. (let ((calculator-eng-tmp-show t)) (calculator-enter)))
  949. ((eq num 'right)
  950. (setq calculator-eng-extra
  951. (if calculator-eng-extra
  952. (1- calculator-eng-extra)
  953. -1))
  954. (let ((calculator-eng-tmp-show t)) (calculator-enter))))
  955. (let ((exp 0))
  956. (and (not (= 0 num))
  957. (progn
  958. (while (< (abs num) 1.0)
  959. (setq num (* num 1000.0)) (setq exp (- exp 3)))
  960. (while (> (abs num) 999.0)
  961. (setq num (/ num 1000.0)) (setq exp (+ exp 3)))
  962. (and calculator-eng-tmp-show
  963. (not (= 0 calculator-eng-extra))
  964. (let ((i calculator-eng-extra))
  965. (while (> i 0)
  966. (setq num (* num 1000.0)) (setq exp (- exp 3))
  967. (setq i (1- i)))
  968. (while (< i 0)
  969. (setq num (/ num 1000.0)) (setq exp (+ exp 3))
  970. (setq i (1+ i)))))))
  971. (or calculator-eng-tmp-show (setq calculator-eng-extra nil))
  972. (let ((str (format (concat "%." (number-to-string
  973. calculator-number-digits)
  974. "f")
  975. num)))
  976. (concat (let ((calculator-remove-zeros
  977. ;; make sure we don't leave integers
  978. (and calculator-remove-zeros 'x)))
  979. (calculator-remove-zeros str))
  980. "e" (number-to-string exp))))))
  981. (defun calculator-number-to-string (num)
  982. "Convert NUM to a displayable string."
  983. (cond
  984. ((and (numberp num) calculator-output-radix)
  985. ;; print with radix - for binary I convert the octal number
  986. (let ((str (format (if (eq calculator-output-radix 'hex) "%x" "%o")
  987. (calculator-truncate
  988. (if calculator-2s-complement num (abs num))))))
  989. (if (eq calculator-output-radix 'bin)
  990. (let ((i -1) (s ""))
  991. (while (< (setq i (1+ i)) (length str))
  992. (setq s
  993. (concat s
  994. (cdr (assq (aref str i)
  995. '((?0 . "000") (?1 . "001")
  996. (?2 . "010") (?3 . "011")
  997. (?4 . "100") (?5 . "101")
  998. (?6 . "110") (?7 . "111")))))))
  999. (string-match "^0*\\(.+\\)" s)
  1000. (setq str (match-string 1 s))))
  1001. (if calculator-radix-grouping-mode
  1002. (let ((d (/ (length str) calculator-radix-grouping-digits))
  1003. (r (% (length str) calculator-radix-grouping-digits)))
  1004. (while (>= (setq d (1- d)) (if (zerop r) 1 0))
  1005. (let ((i (+ r (* d calculator-radix-grouping-digits))))
  1006. (setq str (concat (substring str 0 i)
  1007. calculator-radix-grouping-separator
  1008. (substring str i)))))))
  1009. (upcase
  1010. (if (and (not calculator-2s-complement) (< num 0))
  1011. (concat "-" str)
  1012. str))))
  1013. ((and (numberp num) calculator-displayer)
  1014. (cond
  1015. ((stringp calculator-displayer)
  1016. (format calculator-displayer num))
  1017. ((symbolp calculator-displayer)
  1018. (funcall calculator-displayer num))
  1019. ((and (consp calculator-displayer)
  1020. (eq 'std (car calculator-displayer)))
  1021. (calculator-standard-displayer num (cadr calculator-displayer)))
  1022. ((listp calculator-displayer)
  1023. (eval calculator-displayer))
  1024. (t (prin1-to-string num t))))
  1025. ;; operators are printed here
  1026. (t (prin1-to-string (nth 1 num) t))))
  1027. (defun calculator-update-display (&optional force)
  1028. "Update the display.
  1029. If optional argument FORCE is non-nil, don't use the cached string."
  1030. (set-buffer calculator-buffer)
  1031. ;; update calculator-stack-display
  1032. (if (or force
  1033. (not (eq (car calculator-stack-display) calculator-stack)))
  1034. (setq calculator-stack-display
  1035. (cons calculator-stack
  1036. (if calculator-stack
  1037. (concat
  1038. (let ((calculator-displayer
  1039. (if (and calculator-displayers
  1040. (= 1 (length calculator-stack)))
  1041. ;; customizable display for a single value
  1042. (caar calculator-displayers)
  1043. calculator-displayer)))
  1044. (mapconcat 'calculator-number-to-string
  1045. (reverse calculator-stack)
  1046. " "))
  1047. " "
  1048. (and calculator-display-fragile
  1049. calculator-saved-list
  1050. (= (car calculator-stack)
  1051. (nth calculator-saved-ptr
  1052. calculator-saved-list))
  1053. (if (= 0 calculator-saved-ptr)
  1054. (format "[%s]" (length calculator-saved-list))
  1055. (format "[%s/%s]"
  1056. (- (length calculator-saved-list)
  1057. calculator-saved-ptr)
  1058. (length calculator-saved-list)))))
  1059. ""))))
  1060. (let ((inhibit-read-only t))
  1061. (erase-buffer)
  1062. (insert (calculator-get-prompt)))
  1063. (set-buffer-modified-p nil)
  1064. (if calculator-display-fragile
  1065. (goto-char (1+ (length calculator-prompt)))
  1066. (goto-char (1- (point)))))
  1067. ;;;---------------------------------------------------------------------
  1068. ;;; Stack computations
  1069. (defun calculator-reduce-stack (prec)
  1070. "Reduce the stack using top operator.
  1071. PREC is a precedence - reduce everything with higher precedence."
  1072. (while
  1073. (cond
  1074. ((and (cdr (cdr calculator-stack)) ; have three values
  1075. (consp (nth 0 calculator-stack)) ; two operators & num
  1076. (numberp (nth 1 calculator-stack))
  1077. (consp (nth 2 calculator-stack))
  1078. (eq '\) (nth 1 (nth 0 calculator-stack)))
  1079. (eq '\( (nth 1 (nth 2 calculator-stack))))
  1080. ;; reduce "... ( x )" --> "... x"
  1081. (setq calculator-stack
  1082. (cons (nth 1 calculator-stack)
  1083. (nthcdr 3 calculator-stack)))
  1084. ;; another iteration
  1085. t)
  1086. ((and (cdr (cdr calculator-stack)) ; have three values
  1087. (numberp (nth 0 calculator-stack)) ; two nums & operator
  1088. (consp (nth 1 calculator-stack))
  1089. (numberp (nth 2 calculator-stack))
  1090. (= 2 (calculator-op-arity ; binary operator
  1091. (nth 1 calculator-stack)))
  1092. (<= prec ; with higher prec.
  1093. (calculator-op-prec (nth 1 calculator-stack))))
  1094. ;; reduce "... x op y" --> "... r", r is the result
  1095. (setq calculator-stack
  1096. (cons (calculator-funcall
  1097. (nth 2 (nth 1 calculator-stack))
  1098. (nth 2 calculator-stack)
  1099. (nth 0 calculator-stack))
  1100. (nthcdr 3 calculator-stack)))
  1101. ;; another iteration
  1102. t)
  1103. ((and (>= (length calculator-stack) 2) ; have two values
  1104. (numberp (nth 0 calculator-stack)) ; number & operator
  1105. (consp (nth 1 calculator-stack))
  1106. (= -1 (calculator-op-arity ; prefix-unary op
  1107. (nth 1 calculator-stack)))
  1108. (<= prec ; with higher prec.
  1109. (calculator-op-prec (nth 1 calculator-stack))))
  1110. ;; reduce "... op x" --> "... r" for prefix op
  1111. (setq calculator-stack
  1112. (cons (calculator-funcall
  1113. (nth 2 (nth 1 calculator-stack))
  1114. (nth 0 calculator-stack))
  1115. (nthcdr 2 calculator-stack)))
  1116. ;; another iteration
  1117. t)
  1118. ((and (cdr calculator-stack) ; have two values
  1119. (consp (nth 0 calculator-stack)) ; operator & number
  1120. (numberp (nth 1 calculator-stack))
  1121. (= +1 (calculator-op-arity ; postfix-unary op
  1122. (nth 0 calculator-stack)))
  1123. (<= prec ; with higher prec.
  1124. (calculator-op-prec (nth 0 calculator-stack))))
  1125. ;; reduce "... x op" --> "... r" for postfix op
  1126. (setq calculator-stack
  1127. (cons (calculator-funcall
  1128. (nth 2 (nth 0 calculator-stack))
  1129. (nth 1 calculator-stack))
  1130. (nthcdr 2 calculator-stack)))
  1131. ;; another iteration
  1132. t)
  1133. ((and calculator-stack ; have one value
  1134. (consp (nth 0 calculator-stack)) ; an operator
  1135. (= 0 (calculator-op-arity ; 0-ary op
  1136. (nth 0 calculator-stack))))
  1137. ;; reduce "... op" --> "... r" for 0-ary op
  1138. (setq calculator-stack
  1139. (cons (calculator-funcall
  1140. (nth 2 (nth 0 calculator-stack)))
  1141. (nthcdr 1 calculator-stack)))
  1142. ;; another iteration
  1143. t)
  1144. ((and (cdr calculator-stack) ; have two values
  1145. (numberp (nth 0 calculator-stack)) ; both numbers
  1146. (numberp (nth 1 calculator-stack)))
  1147. ;; get rid of redundant numbers:
  1148. ;; reduce "... y x" --> "... x"
  1149. ;; needed for 0-ary ops that puts more values
  1150. (setcdr calculator-stack (cdr (cdr calculator-stack))))
  1151. (t ;; no more iterations
  1152. nil))))
  1153. (defun calculator-funcall (f &optional X Y)
  1154. "If F is a symbol, evaluate (F X Y).
  1155. Otherwise, it should be a list, evaluate it with X, Y bound to the
  1156. arguments."
  1157. ;; remember binary ops for calculator-repR/L
  1158. (if Y (setq calculator-last-opXY (list f X Y)))
  1159. (condition-case nil
  1160. ;; there used to be code here that returns 0 if the result was
  1161. ;; smaller than calculator-epsilon (1e-15). I don't think this is
  1162. ;; necessary now.
  1163. (if (symbolp f)
  1164. (cond ((and X Y) (funcall f X Y))
  1165. (X (funcall f X))
  1166. (t (funcall f)))
  1167. ;; f is an expression
  1168. (let* ((__f__ f) ; so we can get this value below...
  1169. (TX (calculator-truncate X))
  1170. (TY (and Y (calculator-truncate Y)))
  1171. (DX (if calculator-deg (/ (* X pi) 180) X))
  1172. (L calculator-saved-list)
  1173. (Fbound (fboundp 'F))
  1174. (Fsave (and Fbound (symbol-function 'F)))
  1175. (Dbound (fboundp 'D))
  1176. (Dsave (and Dbound (symbol-function 'D))))
  1177. ;; a shortened version of flet
  1178. (fset 'F (function
  1179. (lambda (&optional x y)
  1180. (calculator-funcall __f__ x y))))
  1181. (fset 'D (function
  1182. (lambda (x)
  1183. (if calculator-deg (/ (* x 180) float-pi) x))))
  1184. (unwind-protect (eval f)
  1185. (if Fbound (fset 'F Fsave) (fmakunbound 'F))
  1186. (if Dbound (fset 'D Dsave) (fmakunbound 'D)))))
  1187. (error 0)))
  1188. ;;;---------------------------------------------------------------------
  1189. ;;; Input interaction
  1190. (defun calculator-last-input (&optional keys)
  1191. "Last char (or event or event sequence) that was read.
  1192. Optional string argument KEYS will force using it as the keys entered."
  1193. (let ((inp (or keys (this-command-keys))))
  1194. (if (or (stringp inp) (not (arrayp inp)))
  1195. inp
  1196. ;; this translates kp-x to x and [tries to] create a string to
  1197. ;; lookup operators
  1198. (let* ((i -1) (converted-str (make-string (length inp) ? )) k)
  1199. ;; converts an array to a string the ops lookup with keypad
  1200. ;; input
  1201. (while (< (setq i (1+ i)) (length inp))
  1202. (setq k (aref inp i))
  1203. ;; if Emacs will someday have a event-key, then this would
  1204. ;; probably be modified anyway
  1205. (and (if (fboundp 'key-press-event-p) (key-press-event-p k))
  1206. (if (fboundp 'event-key)
  1207. (and (event-key k) (setq k (event-key k)))))
  1208. ;; assume all symbols are translatable with an ascii-character
  1209. (and (symbolp k)
  1210. (setq k (or (get k 'ascii-character) ? )))
  1211. (aset converted-str i k))
  1212. converted-str))))
  1213. (defun calculator-clear-fragile (&optional op)
  1214. "Clear the fragile flag if it was set, then maybe reset all.
  1215. OP is the operator (if any) that caused this call."
  1216. (if (and calculator-display-fragile
  1217. (or (not op)
  1218. (= -1 (calculator-op-arity op))
  1219. (= 0 (calculator-op-arity op))))
  1220. ;; reset if last calc finished, and now get a num or prefix or 0-ary
  1221. ;; op
  1222. (calculator-reset))
  1223. (setq calculator-display-fragile nil))
  1224. (defun calculator-digit ()
  1225. "Enter a single digit."
  1226. (interactive)
  1227. (let ((inp (aref (calculator-last-input) 0)))
  1228. (if (and (or calculator-display-fragile
  1229. (not (numberp (car calculator-stack))))
  1230. (cond
  1231. ((not calculator-input-radix) (<= inp ?9))
  1232. ((eq calculator-input-radix 'bin) (<= inp ?1))
  1233. ((eq calculator-input-radix 'oct) (<= inp ?7))
  1234. (t t)))
  1235. ;; enter digit if starting a new computation or have an op on the
  1236. ;; stack
  1237. (progn
  1238. (calculator-clear-fragile)
  1239. (let ((digit (upcase (char-to-string inp))))
  1240. (if (equal calculator-curnum "0")
  1241. (setq calculator-curnum nil))
  1242. (setq calculator-curnum
  1243. (concat (or calculator-curnum "") digit)))
  1244. (calculator-update-display)))))
  1245. (defun calculator-decimal ()
  1246. "Enter a decimal period."
  1247. (interactive)
  1248. (if (and (not calculator-input-radix)
  1249. (or calculator-display-fragile
  1250. (not (numberp (car calculator-stack))))
  1251. (not (and calculator-curnum
  1252. (string-match "[.eE]" calculator-curnum))))
  1253. ;; enter the period on the same condition as a digit, only if no
  1254. ;; period or exponent entered yet
  1255. (progn
  1256. (calculator-clear-fragile)
  1257. (setq calculator-curnum (concat (or calculator-curnum "0") "."))
  1258. (calculator-update-display))))
  1259. (defun calculator-exp ()
  1260. "Enter an `E' exponent character, or a digit in hex input mode."
  1261. (interactive)
  1262. (if calculator-input-radix
  1263. (calculator-digit)
  1264. (if (and (or calculator-display-fragile
  1265. (not (numberp (car calculator-stack))))
  1266. (not (and calculator-curnum
  1267. (string-match "[eE]" calculator-curnum))))
  1268. ;; same condition as above, also no E so far
  1269. (progn
  1270. (calculator-clear-fragile)
  1271. (setq calculator-curnum (concat (or calculator-curnum "1") "e"))
  1272. (calculator-update-display)))))
  1273. (defun calculator-op (&optional keys)
  1274. "Enter an operator on the stack, doing all necessary reductions.
  1275. Optional string argument KEYS will force using it as the keys entered."
  1276. (interactive)
  1277. (catch 'op-error
  1278. (let* ((last-inp (calculator-last-input keys))
  1279. (op (assoc last-inp calculator-operators)))
  1280. (calculator-clear-fragile op)
  1281. (if (and calculator-curnum (/= (calculator-op-arity op) 0))
  1282. (setq calculator-stack
  1283. (cons (calculator-curnum-value) calculator-stack)))
  1284. (setq calculator-curnum nil)
  1285. (if (and (= 2 (calculator-op-arity op))
  1286. (not (and calculator-stack
  1287. (numberp (nth 0 calculator-stack)))))
  1288. ;; we have a binary operator but no number - search for a prefix
  1289. ;; version
  1290. (let ((rest-ops calculator-operators))
  1291. (while (not (equal last-inp (car (car rest-ops))))
  1292. (setq rest-ops (cdr rest-ops)))
  1293. (setq op (assoc last-inp (cdr rest-ops)))
  1294. (if (not (and op (= -1 (calculator-op-arity op))))
  1295. ;;(error "Binary operator without a first operand")
  1296. (progn
  1297. (calculator-message
  1298. "Binary operator without a first operand")
  1299. (throw 'op-error nil)))))
  1300. (calculator-reduce-stack
  1301. (cond ((eq (nth 1 op) '\() 10)
  1302. ((eq (nth 1 op) '\)) 0)
  1303. (t (calculator-op-prec op))))
  1304. (if (or (and (= -1 (calculator-op-arity op))
  1305. (numberp (car calculator-stack)))
  1306. (and (/= (calculator-op-arity op) -1)
  1307. (/= (calculator-op-arity op) 0)
  1308. (not (numberp (car calculator-stack)))))
  1309. ;;(error "Unterminated expression")
  1310. (progn
  1311. (calculator-message "Unterminated expression")
  1312. (throw 'op-error nil)))
  1313. (setq calculator-stack (cons op calculator-stack))
  1314. (calculator-reduce-stack (calculator-op-prec op))
  1315. (and (= (length calculator-stack) 1)
  1316. (numberp (nth 0 calculator-stack))
  1317. ;; the display is fragile if it contains only one number
  1318. (setq calculator-display-fragile t)
  1319. ;; add number to the saved-list
  1320. calculator-add-saved
  1321. (if (= 0 calculator-saved-ptr)
  1322. (setq calculator-saved-list
  1323. (cons (car calculator-stack) calculator-saved-list))
  1324. (let ((p (nthcdr (1- calculator-saved-ptr)
  1325. calculator-saved-list)))
  1326. (setcdr p (cons (car calculator-stack) (cdr p))))))
  1327. (calculator-update-display))))
  1328. (defun calculator-op-or-exp ()
  1329. "Either enter an operator or a digit.
  1330. Used with +/- for entering them as digits in numbers like 1e-3 (there is
  1331. no need for negative numbers since these are handled by unary operators)."
  1332. (interactive)
  1333. (if (and (not calculator-display-fragile)
  1334. calculator-curnum
  1335. (string-match "[eE]$" calculator-curnum))
  1336. (calculator-digit)
  1337. (calculator-op)))
  1338. ;;;---------------------------------------------------------------------
  1339. ;;; Input/output modes (not display)
  1340. (defun calculator-dec/deg-mode ()
  1341. "Set decimal mode for display & input, if decimal, toggle deg mode."
  1342. (interactive)
  1343. (if calculator-curnum
  1344. (setq calculator-stack
  1345. (cons (calculator-curnum-value) calculator-stack)))
  1346. (setq calculator-curnum nil)
  1347. (if (or calculator-input-radix calculator-output-radix)
  1348. (progn (setq calculator-input-radix nil)
  1349. (setq calculator-output-radix nil))
  1350. ;; already decimal - toggle degrees mode
  1351. (setq calculator-deg (not calculator-deg)))
  1352. (calculator-update-display t))
  1353. (defun calculator-radix-mode (&optional keys)
  1354. "Set input and display radix modes.
  1355. Optional string argument KEYS will force using it as the keys entered."
  1356. (interactive)
  1357. (calculator-radix-input-mode keys)
  1358. (calculator-radix-output-mode keys))
  1359. (defun calculator-radix-input-mode (&optional keys)
  1360. "Set input radix modes.
  1361. Optional string argument KEYS will force using it as the keys entered."
  1362. (interactive)
  1363. (if calculator-curnum
  1364. (setq calculator-stack
  1365. (cons (calculator-curnum-value) calculator-stack)))
  1366. (setq calculator-curnum nil)
  1367. (setq calculator-input-radix
  1368. (let ((inp (calculator-last-input keys)))
  1369. (cdr (assq (upcase (aref inp (1- (length inp))))
  1370. calculator-char-radix))))
  1371. (calculator-update-display))
  1372. (defun calculator-radix-output-mode (&optional keys)
  1373. "Set display radix modes.
  1374. Optional string argument KEYS will force using it as the keys entered."
  1375. (interactive)
  1376. (if calculator-curnum
  1377. (setq calculator-stack
  1378. (cons (calculator-curnum-value) calculator-stack)))
  1379. (setq calculator-curnum nil)
  1380. (setq calculator-output-radix
  1381. (let ((inp (calculator-last-input keys)))
  1382. (cdr (assq (upcase (aref inp (1- (length inp))))
  1383. calculator-char-radix))))
  1384. (calculator-update-display t))
  1385. ;;;---------------------------------------------------------------------
  1386. ;;; Saved values list
  1387. (defun calculator-save-on-list ()
  1388. "Evaluate current expression, put result on the saved values list."
  1389. (interactive)
  1390. (let ((calculator-add-saved t)) ; marks the result to be added
  1391. (calculator-enter)))
  1392. (defun calculator-clear-saved ()
  1393. "Clear the list of saved values in `calculator-saved-list'."
  1394. (interactive)
  1395. (setq calculator-saved-list nil)
  1396. (setq calculator-saved-ptr 0)
  1397. (calculator-update-display t))
  1398. (defun calculator-saved-move (n)
  1399. "Go N elements up the list of saved values."
  1400. (interactive)
  1401. (and calculator-saved-list
  1402. (or (null calculator-stack) calculator-display-fragile)
  1403. (progn
  1404. (setq calculator-saved-ptr
  1405. (max (min (+ n calculator-saved-ptr)
  1406. (length calculator-saved-list))
  1407. 0))
  1408. (if (nth calculator-saved-ptr calculator-saved-list)
  1409. (setq calculator-stack
  1410. (list (nth calculator-saved-ptr calculator-saved-list))
  1411. calculator-display-fragile t)
  1412. (calculator-reset))
  1413. (calculator-update-display))))
  1414. (defun calculator-saved-up ()
  1415. "Go up the list of saved values."
  1416. (interactive)
  1417. (calculator-saved-move +1))
  1418. (defun calculator-saved-down ()
  1419. "Go down the list of saved values."
  1420. (interactive)
  1421. (calculator-saved-move -1))
  1422. ;;;---------------------------------------------------------------------
  1423. ;;; Misc functions
  1424. (defun calculator-open-paren ()
  1425. "Equivalents of `(' use this."
  1426. (interactive)
  1427. (calculator-op "("))
  1428. (defun calculator-close-paren ()
  1429. "Equivalents of `)' use this."
  1430. (interactive)
  1431. (calculator-op ")"))
  1432. (defun calculator-enter ()
  1433. "Evaluate current expression."
  1434. (interactive)
  1435. (calculator-op "="))
  1436. (defun calculator-backspace ()
  1437. "Backward delete a single digit or a stack element."
  1438. (interactive)
  1439. (if calculator-curnum
  1440. (setq calculator-curnum
  1441. (if (> (length calculator-curnum) 1)
  1442. (substring calculator-curnum
  1443. 0 (1- (length calculator-curnum)))
  1444. nil))
  1445. (setq calculator-stack (cdr calculator-stack)))
  1446. (calculator-update-display))
  1447. (defun calculator-clear ()
  1448. "Clear current number."
  1449. (interactive)
  1450. (setq calculator-curnum nil)
  1451. (cond
  1452. ;; if the current number is from the saved-list - remove it
  1453. ((and calculator-display-fragile
  1454. calculator-saved-list
  1455. (= (car calculator-stack)
  1456. (nth calculator-saved-ptr calculator-saved-list)))
  1457. (if (= 0 calculator-saved-ptr)
  1458. (setq calculator-saved-list (cdr calculator-saved-list))
  1459. (let ((p (nthcdr (1- calculator-saved-ptr)
  1460. calculator-saved-list)))
  1461. (setcdr p (cdr (cdr p)))
  1462. (setq calculator-saved-ptr (1- calculator-saved-ptr))))
  1463. (if calculator-saved-list
  1464. (setq calculator-stack
  1465. (list (nth calculator-saved-ptr calculator-saved-list)))
  1466. (calculator-reset)))
  1467. ;; reset if fragile or double clear
  1468. ((or calculator-display-fragile (eq last-command this-command))
  1469. (calculator-reset)))
  1470. (calculator-update-display))
  1471. (defun calculator-copy ()
  1472. "Copy current number to the `kill-ring'."
  1473. (interactive)
  1474. (let ((calculator-displayer
  1475. (or calculator-copy-displayer calculator-displayer))
  1476. (calculator-displayers
  1477. (if calculator-copy-displayer nil calculator-displayers)))
  1478. (calculator-enter)
  1479. ;; remove trailing spaces and an index
  1480. (let ((s (cdr calculator-stack-display)))
  1481. (and s
  1482. (if (string-match "^\\([^ ]+\\) *\\(\\[[0-9/]+\\]\\)? *$" s)
  1483. (setq s (match-string 1 s)))
  1484. (kill-new s)))))
  1485. (defun calculator-set-register (reg)
  1486. "Set a register value for REG."
  1487. (interactive "cRegister to store into: ")
  1488. (let* ((as (assq reg calculator-registers))
  1489. (val (progn (calculator-enter) (car calculator-stack))))
  1490. (if as
  1491. (setcdr as val)
  1492. (setq calculator-registers
  1493. (cons (cons reg val) calculator-registers)))
  1494. (calculator-message "[%c] := %S" reg val)))
  1495. (defun calculator-put-value (val)
  1496. "Paste VAL as if entered.
  1497. Used by `calculator-paste' and `get-register'."
  1498. (if (and (numberp val)
  1499. ;; (not calculator-curnum)
  1500. (or calculator-display-fragile
  1501. (not (numberp (car calculator-stack)))))
  1502. (progn
  1503. (calculator-clear-fragile)
  1504. (setq calculator-curnum (let ((calculator-displayer "%S"))
  1505. (calculator-number-to-string val)))
  1506. (calculator-update-display))))
  1507. (defun calculator-paste ()
  1508. "Paste a value from the `kill-ring'."
  1509. (interactive)
  1510. (calculator-put-value
  1511. (let ((str (replace-regexp-in-string
  1512. "^ *\\(.+[^ ]\\) *$" "\\1" (current-kill 0))))
  1513. (and (not calculator-input-radix)
  1514. calculator-paste-decimals
  1515. (string-match "\\([0-9]+\\)\\(\\.[0-9]+\\)?\\(e[0-9]+\\)?"
  1516. str)
  1517. (or (match-string 1 str)
  1518. (match-string 2 str)
  1519. (match-string 3 str))
  1520. (setq str (concat (or (match-string 1 str) "0")
  1521. (or (match-string 2 str) ".0")
  1522. (or (match-string 3 str) ""))))
  1523. (condition-case nil (calculator-string-to-number str)
  1524. (error nil)))))
  1525. (defun calculator-get-register (reg)
  1526. "Get a value from a register REG."
  1527. (interactive "cRegister to get value from: ")
  1528. (calculator-put-value (cdr (assq reg calculator-registers))))
  1529. (defun calculator-help ()
  1530. ;; this is used as the quick reference screen you get with `h'
  1531. "Quick reference:
  1532. * numbers/operators/parens/./e - enter expressions
  1533. + - * / \\(div) %(rem) _(-X,postfix) ;(1/X,postfix) ^(exp) L(og)
  1534. Q(sqrt) !(fact) S(in) C(os) T(an) |(or) #(xor) &(and) ~(not)
  1535. * >/< repeats last binary operation with its 2nd (1st) arg as postfix op
  1536. * I inverses next trig function * '/\"/{} - display/display args
  1537. * D - switch to all-decimal, or toggle deg/rad mode
  1538. * B/O/H/X - binary/octal/hex mode for i/o (X is a shortcut for H)
  1539. * i/o - prefix for d/b/o/x - set only input/output modes
  1540. * enter/= - evaluate current expr. * s/g - set/get a register
  1541. * space - evaluate & save on list * l/v - list total/average
  1542. * up/down/C-p/C-n - browse saved * C-delete - clear all saved
  1543. * C-insert - copy whole expr. * C-return - evaluate, copy, exit
  1544. * insert - paste a number * backspace- delete backwards
  1545. * delete - clear argument or list value or whole expression (twice)
  1546. * escape/q - exit."
  1547. (interactive)
  1548. (if (eq last-command 'calculator-help)
  1549. (let ((mode-name "Calculator")
  1550. (major-mode 'calculator-mode)
  1551. (g-map (current-global-map))
  1552. (win (selected-window)))
  1553. (require 'ehelp)
  1554. (if calculator-electric-mode
  1555. (use-global-map calculator-saved-global-map))
  1556. (if (or (not calculator-electric-mode)
  1557. ;; XEmacs has a problem with electric-describe-mode
  1558. (featurep 'xemacs))
  1559. (describe-mode)
  1560. (electric-describe-mode))
  1561. (if calculator-electric-mode
  1562. (use-global-map g-map))
  1563. (select-window win) ; these are for XEmacs (also below)
  1564. (message nil))
  1565. (let ((one (one-window-p t))
  1566. (win (selected-window))
  1567. (help-buf (get-buffer-create "*Help*")))
  1568. (save-window-excursion
  1569. (with-output-to-temp-buffer "*Help*"
  1570. (princ (documentation 'calculator-help)))
  1571. (if one
  1572. (shrink-window-if-larger-than-buffer
  1573. (get-buffer-window help-buf)))
  1574. (message
  1575. "`%s' again for more help, any other key continues normally."
  1576. (calculator-last-input))
  1577. (select-window win)
  1578. (sit-for 360))
  1579. (select-window win))))
  1580. (defun calculator-quit ()
  1581. "Quit calculator."
  1582. (interactive)
  1583. (set-buffer calculator-buffer)
  1584. (let ((inhibit-read-only t)) (erase-buffer))
  1585. (if (not calculator-electric-mode)
  1586. (progn
  1587. (condition-case nil
  1588. (while (get-buffer-window calculator-buffer)
  1589. (delete-window (get-buffer-window calculator-buffer)))
  1590. (error nil))
  1591. (kill-buffer calculator-buffer)))
  1592. (setq calculator-buffer nil)
  1593. (message "Calculator done.")
  1594. (if calculator-electric-mode (throw 'calculator-done nil)))
  1595. (defun calculator-save-and-quit ()
  1596. "Quit the calculator, saving the result on the `kill-ring'."
  1597. (interactive)
  1598. (calculator-enter)
  1599. (calculator-copy)
  1600. (calculator-quit))
  1601. (defun calculator-repR (x)
  1602. "Repeat the last binary operation with its second argument and X.
  1603. To use this, apply a binary operator (evaluate it), then call this."
  1604. (if calculator-last-opXY
  1605. ;; avoid rebinding calculator-last-opXY
  1606. (let ((calculator-last-opXY calculator-last-opXY))
  1607. (calculator-funcall
  1608. (car calculator-last-opXY) x (nth 2 calculator-last-opXY)))
  1609. x))
  1610. (defun calculator-repL (x)
  1611. "Repeat the last binary operation with its first argument and X.
  1612. To use this, apply a binary operator (evaluate it), then call this."
  1613. (if calculator-last-opXY
  1614. ;; avoid rebinding calculator-last-opXY
  1615. (let ((calculator-last-opXY calculator-last-opXY))
  1616. (calculator-funcall
  1617. (car calculator-last-opXY) (nth 1 calculator-last-opXY) x))
  1618. x))
  1619. (defun calculator-integer-p (x)
  1620. "Non-nil if X is equal to an integer."
  1621. (condition-case nil
  1622. (= x (ftruncate x))
  1623. (error nil)))
  1624. (defun calculator-expt (x y)
  1625. "Compute X^Y, dealing with errors appropriately."
  1626. (condition-case
  1627. nil
  1628. (expt x y)
  1629. (domain-error 0.0e+NaN)
  1630. (range-error
  1631. (cond
  1632. ((and (< x 1.0) (> x -1.0))
  1633. ;; For small x, the range error comes from large y.
  1634. 0.0)
  1635. ((and (> x 0.0) (< y 0.0))
  1636. ;; For large positive x and negative y, the range error
  1637. ;; comes from large negative y.
  1638. 0.0)
  1639. ((and (> x 0.0) (> y 0.0))
  1640. ;; For large positive x and positive y, the range error
  1641. ;; comes from large y.
  1642. 1.0e+INF)
  1643. ;; For the rest, x must be large and negative.
  1644. ;; The range errors come from large integer y.
  1645. ((< y 0.0)
  1646. 0.0)
  1647. ((eq (logand (truncate y) 1) 1) ; expansion of cl `oddp'
  1648. ;; If y is odd
  1649. -1.0e+INF)
  1650. (t
  1651. ;;
  1652. 1.0e+INF)))
  1653. (error 0.0e+NaN)))
  1654. (defun calculator-fact (x)
  1655. "Simple factorial of X."
  1656. (if (and (>= x 0)
  1657. (calculator-integer-p x))
  1658. (if (= (calculator-expt (/ x 3.0) x) 1.0e+INF)
  1659. 1.0e+INF
  1660. (let ((r (if (<= x 10) 1 1.0)))
  1661. (while (> x 0)
  1662. (setq r (* r (truncate x)))
  1663. (setq x (1- x)))
  1664. (+ 0.0 r)))
  1665. (if (= x 1.0e+INF)
  1666. x
  1667. 0.0e+NaN)))
  1668. (defun calculator-truncate (n)
  1669. "Truncate N, return 0 in case of overflow."
  1670. (condition-case nil (truncate n) (error 0)))
  1671. (provide 'calculator)
  1672. ;;; calculator.el ends here