Fixing parsing of numbers in mexpr mode.
This commit is contained in:
parent
6d887ff19b
commit
51a018b705
29
README.md
29
README.md
|
@ -130,7 +130,34 @@ You will require to have [Leiningen](https://leiningen.org/) installed.
|
|||
|
||||
This will start a Lisp 1.5 read/eval/print loop (REPL).
|
||||
|
||||
To end a session, type `quit` at the command prompt.
|
||||
Command line arguments are as follows:
|
||||
|
||||
```
|
||||
-f FILEPATH, --file-path FILEPATH Set the path to the directory for reading and writing Lisp files.
|
||||
-h, --help
|
||||
-p PROMPT, --prompt PROMPT Sprecan:: Set the REPL prompt to PROMPT
|
||||
-r INITFILE, --read INITFILE resources/lisp1.5.lsp Read Lisp system from file INITFILE
|
||||
-s, --strict Strictly interpret the Lisp 1.5 language, without extensions.
|
||||
-t, --trace Trace Lisp evaluation.
|
||||
```
|
||||
|
||||
To end a session, type `STOP` at the command prompt.
|
||||
|
||||
### Input/output
|
||||
|
||||
Lisp 1.5 greatly predates modern computers. It had a facility to print to a line printer, or to punch cards on a punch-card machine, and it had a facility to read system images in from tape; but there's no file I/O as we would currently understand it, and, because there are no character strings and the valid characters within an atom are limited, it isn't easy to compose a sensible filename.
|
||||
|
||||
I've provided two functions to work around this problem.
|
||||
|
||||
#### SYSOUT
|
||||
|
||||
`SYSOUT` dumps the global object list to disk as a single S Expression (specifically: an association list). This allows you to persist your session, with all your current work, to disk. The function takes one argument, expected to be a symbol, and, if that argument is provided, writes a file whose name is that symbol with `.lsp` appended. If no argument is provided, it will construct a filename comprising the token `Sysout`, followed by the current date, followed by `.lsp`. In either case the file will be written to the directory given in the FILEPATH argument at startup time, or by default the current directory.
|
||||
|
||||
Obviously, `SYSOUT` may be called interactively (and this is the expected practice).
|
||||
|
||||
#### SYSIN
|
||||
|
||||
`SYSIN` reads a file from disk and overwrites the global object list with its contents. The expected practice is that this will be a file created by `SYSOUT`. A command line flag `--read` is provided so that you can specify
|
||||
|
||||
## Learning Lisp 1.5
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
;; it to NIL
|
||||
(F . NIL)
|
||||
;; Binding all system functions to NIL so that you can see on the OBLIST that
|
||||
;; they exist
|
||||
;; they exist.
|
||||
(ADD1 . NIL)
|
||||
(APPEND . NIL)
|
||||
(APPLY . NIL)
|
||||
|
@ -25,6 +25,7 @@
|
|||
(PLUS . NIL)
|
||||
(PRETTY . NIL)
|
||||
(QUOTIENT . NIL)
|
||||
(READ . NIL)
|
||||
(REMAINDER)
|
||||
(RPLACA . NIL)
|
||||
(RPLACD . NIL)
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
[beowulf.host :refer [ADD1 DIFFERENCE FIXP NUMBERP PLUS QUOTIENT
|
||||
REMAINDER RPLACA RPLACD SUB1 TIMES]]
|
||||
[beowulf.io :refer [SYSIN SYSOUT]]
|
||||
[beowulf.oblist :refer [*options* oblist NIL]])
|
||||
[beowulf.oblist :refer [*options* oblist NIL]]
|
||||
[beowulf.read :refer [READ]])
|
||||
(:import [beowulf.cons_cell ConsCell]
|
||||
[clojure.lang Symbol]))
|
||||
|
||||
|
@ -411,6 +412,7 @@
|
|||
PLUS (apply PLUS args)
|
||||
PRETTY (apply pretty-print args)
|
||||
QUOTIENT (apply QUOTIENT args)
|
||||
READ (READ)
|
||||
REMAINDER (apply REMAINDER args)
|
||||
RPLACA (apply RPLACA args)
|
||||
RPLACD (apply RPLACD args)
|
||||
|
|
|
@ -174,7 +174,6 @@
|
|||
(if
|
||||
(coll? p)
|
||||
(case (first p)
|
||||
">" 'GREATERP
|
||||
:λ "LAMBDA"
|
||||
:λexpr (make-cons-cell
|
||||
(generate (nth p 1))
|
||||
|
@ -184,6 +183,7 @@
|
|||
:atom (symbol (second p))
|
||||
:bindings (generate (second p))
|
||||
:body (make-beowulf-list (map generate (rest p)))
|
||||
(:coefficient :exponent) (generate (second p))
|
||||
:cond (gen-cond p)
|
||||
:cond-clause (gen-cond-clause p)
|
||||
(:decimal :integer) (read-string (strip-leading-zeros (second p)))
|
||||
|
@ -191,7 +191,6 @@
|
|||
:dotted-pair (make-cons-cell
|
||||
(generate (nth p 1))
|
||||
(generate (nth p 2)))
|
||||
:exponent (generate (second p))
|
||||
:fncall (gen-fn-call p)
|
||||
:iexpr (gen-iexpr p)
|
||||
:iop (case (second p)
|
||||
|
@ -212,7 +211,7 @@
|
|||
(list 'QUOTE (symbol (upper-case (second p)))))
|
||||
:mvar (symbol (upper-case (second p)))
|
||||
:octal (let [n (read-string (strip-leading-zeros (second p) "0"))
|
||||
scale (generate (nth p 2))]
|
||||
scale (generate (nth p 3))]
|
||||
(* n (expt 8 scale)))
|
||||
|
||||
;; the quote read macro (which probably didn't exist in Lisp 1.5, but...)
|
||||
|
@ -221,7 +220,7 @@
|
|||
(empty? (second p)) 0
|
||||
(read-string (strip-leading-zeros (second p))))
|
||||
:scientific (let [n (generate (second p))
|
||||
exponent (generate (nth p 2))]
|
||||
exponent (generate (nth p 3))]
|
||||
(* n (expt 10 exponent)))
|
||||
|
||||
;; default
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
integer := #'-?[1-9][0-9]*';
|
||||
decimal := #'-?[1-9][0-9]*\\.?[0-9]*' | #'0.[0-9]*';
|
||||
scientific := coefficient e exponent;
|
||||
coefficient := decimal;
|
||||
coefficient := integer | decimal;
|
||||
exponent := integer;
|
||||
e := 'E';
|
||||
octal := #'[+-]?[0-7]+{1,12}' q scale-factor;
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
#(when (coll? %) (empty? %))
|
||||
(case (first p)
|
||||
(:λexpr
|
||||
:args :bindings :body :cond :cond-clause :defn :dot-terminal
|
||||
:args :bindings :body :cond :cond-clause :defn :dot-terminal
|
||||
:fncall :lhs :quoted-expr :rhs ) (map #(simplify % context) p)
|
||||
(:arg :expr :coefficient :fn-name :number) (simplify (second p) context)
|
||||
(:arrow :dot :e :lpar :lsqb :opt-comment :opt-space :q :quote :rpar :rsqb
|
||||
|
|
|
@ -42,11 +42,16 @@
|
|||
;; Wrapping in a function call puts us into mexpr contest;
|
||||
;; "T" would be interpreted as a sexpr, which would not be
|
||||
;; quoted.
|
||||
(let [expected "(ATOM A)"
|
||||
(let [expected "(ATOM (QUOTE A))"
|
||||
actual (print-str (gsp "atom[A]"))]
|
||||
(is (= actual expected)))
|
||||
(let [expected "(ATOM A)"
|
||||
actual (print-str (gsp "atom[a]"))]
|
||||
(is (= actual expected)))
|
||||
|
||||
;; I'm not clear how `car[(A B C)]` should be translated, but
|
||||
;; I suspect as (CAR (LIST A B C)).
|
||||
|
||||
(let [expected "(CAR (LIST A B C))"
|
||||
actual (print-str (gsp "car[(A B C)]"))]
|
||||
(is (= actual expected)))
|
||||
|
@ -63,10 +68,10 @@
|
|||
|
||||
(deftest conditional-tests
|
||||
(testing "Conditional expressions"
|
||||
(let [expected "(COND ((ATOM X) X) (T (FF (CAR X))))"
|
||||
(let [expected "(COND ((ATOM X) X) ((QUOTE T) (FF (CAR X))))"
|
||||
actual (print-str (gsp "[atom[x]->x; T->ff[car[x]]]"))]
|
||||
(is (= actual expected)))
|
||||
(let [expected "(LABEL FF (LAMBDA (X) (COND ((ATOM X) X) (T (FF (CAR X))))))"
|
||||
(let [expected "(LABEL FF (LAMBDA (X) (COND ((ATOM X) X) ((QUOTE T) (FF (CAR X))))))"
|
||||
actual (print-str
|
||||
(generate
|
||||
(simplify
|
||||
|
@ -83,6 +88,6 @@
|
|||
|
||||
(deftest assignment-tests
|
||||
(testing "Function assignment"
|
||||
(let [expected "(SET (QUOTE FF) (QUOTE (LAMBDA (X) (COND ((ATOM X) X) (T (FF (CAR X)))))))"
|
||||
(let [expected "(SET (QUOTE FF) (QUOTE (LAMBDA (X) (COND ((ATOM X) X) ((QUOTE T) (FF (CAR X)))))))"
|
||||
actual (print-str (gsp "ff[x]=[atom[x] -> x; T -> ff[car[x]]]"))]
|
||||
(is (= actual expected)))))
|
||||
|
|
Loading…
Reference in a new issue