;; cli.lisp -- Command line interface entry point and option parsing ;; Copyright (C) 2024 Alexander Rosenberg ;; ;; 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 of the License, 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 . (defpackage #:truth-table/cli (:use #:common-lisp #:truth-table/base #:truth-table/args) (:export #:toplevel #:main)) (in-package :truth-table/cli) (defun eval-and-typeset-propositions (prop-strs &key (format "unicode") (implicit-and t) multi-char-names include-intermediate (include-vars t) pretty-print latin-truths) "Evaluate and then typeset PROP-STRS as a table, which is a list of proposition strings. For a description of the key parameters, see each of the functions involved in evaluating and typesetting." (loop with vars = '() for prop-str in prop-strs for (parsed-exp parsed-vars) = (multiple-value-list (parse-proposition-string prop-str :implicit-and implicit-and :multi-char-names multi-char-names)) collect parsed-exp into exps do (dolist (var parsed-vars) (unless (member var vars :test 'equal) (setq vars (nconc vars (list var))))) finally (let ((table (create-combined-truth-table exps vars :include-intermediate include-intermediate :include-vars include-vars))) (return (typeset-table-to-format table format :pretty-print pretty-print :latin-truths latin-truths))))) (defparameter *command-line-spec* '((#\h "help" help nil "print this message, then exit") (#\f "format" format t "specify the output format (*unicode*, ascii, latex, or html)") (#\s "subexps" subexps nil "include sub-expressions in the output table") (#\n "no-vars" no-vars nil "do not include variables in the output table") (#\m "multi-char" multi-char nil "allow multi-character variable names") (#\i "no-implicit" no-implicit nil "do not use implicit 'and' operations") (#\p "pretty" pretty nil "pretty print latex, html, etc. output") (#\l "latin" latin nil "use the Latin T and F characters for truth values")) "Specification for `parse-command-line'. This is of the format: (short long symbol has-arg-p desc).") (defun main (argv) "The main entry point to the program. ARGV is the list of command line arguments." (let ((cmdline-error nil)) (handler-bind (((or proposition-parse-error proposition-eval-error table-format-error) (lambda (c) (format *error-output* "error: ~a~%" c) (uiop:quit 1))) (command-line-error (lambda (c) ;; finish parsing command line before exiting (format *error-output* "error: ~a~%" c) (setq cmdline-error t) (continue)))) (destructuring-bind ((&rest prop-strs) &rest opts) (parse-command-line *command-line-spec* argv) (cond ((option-value 'help opts) (print-usage t *command-line-spec* "truth-table" :general-args "") (uiop:quit (if cmdline-error 1 0))) ((null prop-strs) (cerror *cli-parse-continue-string* 'no-input-error)) (cmdline-error (format *error-output* "Try -h or --help for more information.~%") (uiop:quit 1)) (t (let ((format (option-value 'format opts))) (when (or (not format) (zerop (length format))) (setq format "unicode")) (princ (eval-and-typeset-propositions prop-strs :format format :implicit-and (not (option-value 'no-implicit opts)) :multi-char-names (option-value 'multi-char opts) :include-vars (not (option-value 'no-vars opts)) :include-intermediate (option-value 'subexps opts) :pretty-print (option-value 'pretty opts) :latin-truths (option-value 'latin opts))) (terpri)))))))) (defun toplevel () "Top-level function to be passed to `save-lisp-and-die'." (handler-case (with-user-abort:with-user-abort (main (uiop:command-line-arguments))) (with-user-abort:user-abort () (format *error-output* "Keyboard interrupt~%") (uiop:quit 1))))