Fixing parsing of numbers in mexpr mode.

This commit is contained in:
Simon Brooke 2023-03-29 08:50:34 +01:00
parent 6d887ff19b
commit 51a018b705
No known key found for this signature in database
GPG key ID: A7A4F18D1D4DF987
7 changed files with 47 additions and 13 deletions

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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)))))