-
Notifications
You must be signed in to change notification settings - Fork 8
/
3-lisp.cl
2075 lines (2051 loc) · 194 KB
/
3-lisp.cl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;; -*- common-lisp -*-
;; Load this with:
;; (load "3-lisp.cl" :external-format :utf-8) ; LispWorks
;; (load "3-lisp.cl" :external-format 'charset:utf-8) ; clisp
;; (load "3-lisp.cl") ; sbcl
;; so much for portability.
;; This is a port of 3-lisp.lisp from CADR-machine LISP (mostly Maclisp) to a
;; modern Common Lisp.
;; Porting notes.
;;
;; This 40-years old code required surprisingly few changes.
;;
;; Where a difference between Maclisp and Common Lisp is basically a rename,
;; this rename was done directly in the sources. Specifically:
;;
;; Maclisp/CADR Common Lisp
;;
;; CASEQ CASE
;; *CATCH CATCH
;; *THROW THROW
;; READCH READ-CHAR
;; / \ (as an escape)
;; DECLARE PROCLAIM (at the top level)
;; COMPILE :COMPILE-TOPLEVEL (EVAL-WHEN keywords, see http://clhs.lisp.se/Body/s_eval_w.htm
;; LOAD :LOAD-TOPLEVEL "The use of eval, compile, and load is deprecated.")
;; EVAL :EXECUTE
;; READTABLE *READTABLE*
;; LOGIN-SETQ SETQ (https://hanshuebner.github.io/lmman/fd-hac.xml)
;; IGNORE FOO (DECLARE (IGNORE FOO))
;;
;;
;; Some missing Maclisp functions were added: MEMQ, FIXP
;;
;; AND is a macro in Common Lisp and cannot be applied. (So much for orthogonality.) See AND*.
;;
;; Some functions changed signatures:
;;
;; TYPEP Takes 2 parameters and returns Boolean in Common Lisp
;; BREAK Takes some additional arguments in Maclisp-CADR
;; IF Like Elisp, Maclisp allows multiple forms in the ELSE part
;;
;; 3-NORMALISE* assumes that Common Lisp implementations are tail-recursive, compare 3-lisp.lisp.
;;
;; *LEXPR is not needed:
;;
;; *lexpr Special Form
;;
;; (*lexpr sym1 sym2 ... ) declares sym1, sym2, etc. to
;; be names of functions. In addition it prevents these functions from
;; appearing in the list of functions referenced but not defined printed at
;; the end of the compilation.
;;
;; http://www.bitsavers.org/pdf/mit/cadr/chinual_3rdEd_Mar81.pdf
;;
;; Old Lisps had no string type and used symbols for string manipulations. This
;; weirdly-looking code was preserved to honour human ingenuity, see IMPLODE and
;; EXPLODEC.
;;
;; (https://www.cs.cmu.edu/Groups/AI/html/faqs/lang/lisp/part2/faq-doc-3.html).
;;
;;
;; 3-lisp re-uses built-in lisp reader to parse 3-lisp input and 3-lisp code
;; that is part of the 3-lisp implementation. There were some (but again, less
;; than one would expect for such a sensitive part of the language) changes in
;; this area:
;;
;; READ-PRESERVING-WHITESPACE is used instead of READ in a few places to
;; avoid eating newlines, see READ*.
;;
;; SET-SYNTAX-MACRO-CHAR -> SET-MACRO-CHARACTER.
;;
;; "Reader macro function" (the second argument to SET-MACRO-CHARACTER)
;; takes stream and character.
;;
;; There is no SET-SYNTAX-FROM-DESCRIPTION in Common Lisp and there are no
;; "self-delimiting single-character" symbols (see
;; http://www.bitsavers.org/pdf/mit/cadr/chinual_5thEd_Jan83/chinualJan83_21_IOsystem.pdf,
;; p. 381, see CLTL 22.1.1, p. 554), SINGLE-MACRO-CHARACTER.
;;
;; Mysteriously, the parser table for this file (L=READTABLE) refers to the
;; functions defined later in the file (i.e., not yet parsed at the time
;; when the table is installed). This presumably implies some form of
;; multi-pass parsing that modern implementations lack and was fixed by
;; re-ordering the definitions.
;;
;; Maclisp maintains backquote context across recursive parser
;; invocations. For example in the expression (which happens within defun
;; 3-EXPAND-PAIR)
;;
;; `\(PCONS ~,a ~,d)
;;
;; the backquote is consumed by the top-level activation of READ. Backslash
;; forces the switch to 3-lisp readtable and call to 3-READ to handle the
;; rest of the expression. Within this 3-READ activation, the tilde forces
;; switch back to L=READTABLE and a call to READ to handle ",a". In Maclisp,
;; this second READ activation re-uses the backquote context established by
;; the top-level READ activation. Of all Common Lisp implementations that I
;; tried, only sbcl correctly handles this situation. Lisp Works and clisp
;; complain about "comma outside of backquote". In clisp,
;; clisp-2.49/src/io.d:read_top() explicitly binds BACKQUOTE-LEVEL to nil.
;;
;; In addition to UPWARDS ARROW "↑" and LEFTWARDS ARROW "←" used by 3-lisp.lisp,
;; this file uses DOWNWARDS ARROW "↓" instead of "!". Because progress.
;; 3-lisp implementation from Procedural Reflection in Programming Languages,
;; volume i., Brian Cantwell Smith, February 1982, Appendix, pp. 708--751.
;; http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-272.pdf
;;; -*- Mode:LISP; Package:User; Base: 10. -*- Page 1 001
;;; 002
;;; 3-LISP 003
;;; ====== 004
;;; 005
;;; A statically scoped, higher order, semantically rationalised, procedurally 006
;;; reflective dialect of LISP, supporting SIMPLE and REFLECTIVE procedures. 007
;;; 008
;;; This is a straightforward and EXTREMELY INEFFICIENT implementation; the 009
;;; intent is merely to manifest the basic 3-LISP functionality. A variety 010
;;; of techniques could increase the efficiency by several orders of magnitude 011
;;; (most obvious would be to avoid consing explicit continuation structures at 012
;;; each step of NORMALISE). With some ingenuity 3-LISP could be implemented 013
;;; as efficiently as any other dialect. 014
;;; 015
;;; 1. Structural Field: 016
;;; -------------------- 017
;;; 018
;;; Structure Type Designation Notation 019
;;; 020
;;; 1. Numerals -- Numbers -- sequence of digits 021
;;; 2. Booleans -- Truth values -- $T or $F 022
;;; 3. Pairs -- Functions (& appns) -- (<exp> . <exp>) 023
;;; 4. Rails -- Sequences -- [<exp> <exp> ... <exp>] 024
;;; 5. Handles -- S-expressions -- '<exp> 025
;;; 6. Atoms -- (whatever bound to) -- sequence of alphanumerics 026
;;; 027
;;; a. There is no derived notion of a LIST, and no atom NIL. 028
;;; b. Pairs and rails are pseudo-composite; the rest are atomic. 029
;;; c. Numerals, booleans, and handles are all normal-form and canonical. 030
;;; Some rails (those whose elements are normal form) and some pairs 031
;;; (the closures) are normal form, but neither type is canonical. 032
;;; No atoms are normal-form. 033
; 034
;;; 2. Semantics: The semantical domain is typed as follows: 035
;;; ------------- 036
;;; ___ numeral 037
;;; |___ boolean 038
;;; ____ s-expression ___|___ pair 039
;;; | |___ rail 040
;;; | |___ handle 041
;;; | |___ atom 042
;;; Object ___| 043
;;; | ___ number 044
;;; |____ abstraction ____|___ truth-value 045
;;; | |___ sequence 046
;;; | 047
;;; |_________________________ function 048
; 049
;;; 3. Notation 050
;;; ----------- 051
;;; 052
;;; Each structural field category is notated with a distinguishable notational 053
;;; category, recognisable in the first character, as follows (thus 3-LISP 054
;;; could be parsed by a grammar with a single-character look-ahead): 055
;;; 056
;;; 1. Digit --> Numeral 4. Left bracket --> Rail 057
;;; 2. Dollar sign --> Boolean 5. Singe quote --> Handle 058 [sic. leg. "Single"]
;;; 3. Left paren --> Pair 6. Non-digit --> Atom 059
;;; 060
;;; The only exceptions are that numerals can have a leading "+" or "-", and in 061
;;; this implementation an atom may begin with a numeral providing it contains 062
;;; at least one non-digit (since MACLISP supports that). 063
;;; Page 1:1 064
;;; BNF Grammar Double quotes surround object level constants, "←" indicates 065
;;; ----------- concatenation, brackets delineate groupings, "*" means 066
;;; zero-or-more repetition, and "|" separates alternatives: 067
;;; 068
;;; formula ::= [break←]* form [←break]* 069
;;; form ::= L-numeral | L-boolean | L-pair | L-rail | L-handle | L-atom 070
;;; 071
;;; L-numeral ::= ["+"← | "-"←]* digit [←digit]* 072
;;; L-boolean ::= "$T" | "$F" 073
;;; L-pair ::= "("← formula ←"."← formula ←")" 074
;;; L-rail ::= "["← [formula←]* "]" 075
;;; L-handle ::= "'"← formula 076
;;; L-atom ::= [character←]* non-digit [←character]* 077
;;; 078
;;; character ::= digit | non-digit 079
;;; non-digit ::= alphabetic | special 080
;;; 081
;;; digit ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0" 082
;;; alphabetic ::= "a" | "b" | "c" | ... | "A" | "B" | "C" | ... etc. 083
;;; special ::= "*" | "-" | "+" | "/" | "@" | "#" | "%" | "&" | "<" | ">" | 084
;;; "←" | "=" | "\" | "?" | ":" | "~" | "↓" 085
;;; reserved ::= "'" | ";" | "(" | ")" | "[" | "]" | "{" | "}" | "|" | """ | 086
;;; "," | "." | "↑" | "`" | "$" | <space> | <end-of-line> 087
;;; 088
;;; break ::= <space> | <end-of-line> | comment 089
;;; comment ::= ";" [←character | ←reserved | ←<space> ]* <end-of-line> 090
;;; 091
;;; The Lexical Notation Interpretation Function THETA (by category): 092
;;; ----------------------------------------------------------------- 093
;;; 094
;;; L-numeral -- Numerals in the standard fashion; 095
;;; L-boolean -- $T and $F to each of the two booleans; 096
;;; L-pair -- A new (otherwise inaccessible) pair whose CAR is THETA of 097
;;; the first formula and whose CDR is THETA of the second; 098
;;; L-rail -- A new (otherwise inaccessible) rail whose elements are THETA 099
;;; of each of the constituent formulae; 100
;;; L-handle -- The handle of THETA of the constituent formula. 101 [sic. "." vs. ";"]
;;; L-atom -- The corresponding atom. 102
;;; 103
;;; NOTES: 104
;;; 105
;;; 1. Case is ignored (converted to upper case on input) 106
;;; 2. Notational Sugar: 107
;;; 108
;;; "(<e1> <e2> ... <en>)" abbreviates "(<e1> . [<e2> ... <en>])" 109
;;; 110
;;; 3. We use exclamation point in place of down-arrow, since MACLISP does 111
;;; not support the latter character (it is not in ASCII, sadly). 112
;;; 4. A Summary of the use of reserved characters: 113
;;; 114
;;; a: ( -- starts pairs h: . -- in "[ ... ]" for JOIN 115
;;; b: ) -- ends pairs i: ↑ -- NAME 116
;;; c: . -- in "( ... )" for CDR j: ↓ -- REFERENT 117
;;; d: [ -- starts rails (k: : -- DYNAMIC) 118 [DYNAMIC is not present]
;;; e: ] -- ends rails l: ` -- Backquote a la MACLISP 119 [sic. capitalisation]
;;; f: ' -- starts handles m: , -- " " " " 120
;;; g: ; -- starts comments (to CRLF) n: ~ -- Switch to MACLISP 121
;;; 122
;;; A-g are primitive, h-m are sugar, and n is implementation-specific. In 123
;;; this implementation, since "↓" is used for REFERENT (it should be 124
;;; down-arrow), it is reserved rather than special. Similarly, "~" is 125
;;; reserved in this implementation for the MACLISP escape. Finally, the 126
;;; characters "{", "}", "|", and """ are reserved but not currently used 127
;;; (intended for sacks, arbitrary atom names (a la MACLISP) and strings). 128
;;; Page 1:2 129
;;; 4. Processor: 130
;;; ------------- 131
;;; 132
;;; The main driving loop of the processor is a READ-NORMALISE-PRINT loop 133
;;; (see item 6, below), taking expressions into normal-form co-designators. 134
;;; The normal form designators for each of the semantic types are: 135
;;; 136
;;; Semantic type Normal form designator (NFD) 137
;;; 138
;;; 1. Numbers Numerals 139
;;; 2. Truth-values Boolean constants 140
;;; 3. S-expressions Handles 141
;;; 4. Sequences Rails of NFD's of the elements 142
;;; 5. Functions Pairs: (<type> <env> <pattern> <body>) 143
;;; 6. Environments Rails: [['<a1> '<b1>] ['<a2> '<b2>] ... ] 144
;;; 145
;;; 1-3 are CANONICAL, 4-6 are not. Thus, A = B implies ↑A = ↑B only if A and 146
;;; B designate numbers, truth-values, or s-expressions. 147
; 148
;;; 5. Primitive procedures: 149
;;; ------------------------ 150
;;; 151
;;; Summary (fuller definitions are given below): 152
;;; 153
;;; Typing: TYPE -- defined over 10 types (4 syntactic) 154
;;; Identity: = -- defined over s-expressions, truth- 155
;;; values, sequences, and numbers 156
;;; Structural: PCONS, CAR, CDR -- to construct and examine pairs 157
;;; LENGTH, NTH, TAIL -- to examine rails and sequences 158
;;; RCONS, SCONS, PREP -- to construct " " " 159
;;; Modifiers: RPLACA, RPLACD -- to modify pairs 160
;;; RPLACN, RPLACT -- " " rails 161
;;; Functions: SIMPLE, REFLECT -- make procedures from expressions 162
;;; Control: EF -- an extensional if-then-else conditional 163
;;; Semantics: NAME, REFERENT -- to mediate between sign & signified 164
;;; Arithmetic: +, -, *, / -- as usual 165
;;; I/O: READ, PRINT, TERPRI -- as usual 166
;;; Reflection: LEVEL -- the current reflective level 167
;;; 168
;;; The following kernel functions need NOT be primitive; they are defined in 169
;;; the reflective model in terms of the above: 170
;;; 171
;;; DEFINE, LAMBDA, NORMALISE, REDUCE, SET, BINDING, MACRO 172
;;; 173
;;; Syntax and definitions: 174
;;; 175
;;; Form of use Designation (environment relative): 176
;;; 177
;;; (TYPE <exp>) -- The atom indicating the type of <exp> (one of 178
;;; the 10 on the fringe of the tree in #2, above) 179
;;; 180
;;; (= <a> <b>) -- Truth if <a> and <b> are the same, falsity 181
;;; otherwise, providing <a> and <b> are of the 182
;;; same type, and are s-expressions, truth-values, 183
;;; sequences, or numbers 184
;;; 185
;;; (PCONS <a> <b>) -- A (new) pair whose CAR is <a> and CDR is <b> 186
;;; (CAR <a>) -- The CAR of pair <a> 187
;;; (CDR <a>) -- The CDR of pair <a> 188
;;; (RPLACA <a> <b>) -- The new CAR <b> of modified pair <a> 189
;;; (RPLACD <a> <b>) -- The new CDR <b> of modified pair <a> 190
;;; 191
;;; (LENGTH <a>) -- The length of rail or sequence <a> 192
;;; (NTH <n> <a>) -- The <n>th element of rail or sequence <a> 193
;;; (TAIL <n> <a>) -- Tail of rail/seq <a> starting after <n>th elemnt 194 [sic. "elemnt"]
;;; (RCONS <a1> ... <ak>) -- A new rail whose elements are <a1>, ... , <ak> 195 [sic. comma spacing]
;;; (SCONS <a1> ... <ak>) -- The sequence whose elements are <a1>, ..., <ak> 196
;;; (PREP <a> <rs>) -- A new rail/seq whose 1st is <a>, 1st tail is <b> 197 [sic. <b>, leg. <rs>]
;;; (RPLACN <n> <a> <b>) -- The new <n>th element <b> of modified rail <a> 198
;;; (RPLACT <n> <a> <b>) -- The new <n>th tail <b> of modified rail <a> 199
;;; Page 1:3 200
;;; (SIMPLE <e> <p> <b>) -- NOT FOR CASUAL USE! (The function of given type 201
;;; (REFLECT <e> <p> <b>) designated by the lambda abstraction of pattern 202
;;; <p> over expression <b> in environment <e>) 203
;;; 204
;;; (EF <p> <a> <b>) -- <a>, if <p> designates truth; <b> if falsity. 205 [sic. full stop]
;;; 206
;;; (NAME <a>) -- The (or a) normal-form designator of <a> 207
;;; (REFERENT <a> <env>) -- The object designated by <a> in environment <env> 208
;;; 209
;;; (+ <a> <b>) -- The sum, difference, produce, and quotient of 210 [sic. "produce", leg. "product"]
;;; (- <a> <b>) <a> and <b>, respectively 211
;;; (* <a> <b>) 212
;;; (/ <a> <b>) 213
;;; 214
;;; (READ) -- The s-expression notated by the next formula in 215
;;; the input stream. 216 [sic. full stops]
;;; (PRINT <a>) -- <a>, which has just been printed. 217
;;; 218
;;; (LEVEL) -- The number of the current reflective level. 219
; 220
;;; 6. Processor Top Level: 221
;;; ----------------------- 222
;;; 223
;;; Each reflective level of the processor is assumed to start off 224
;;; running the following function: 225
;;; 226
;;; (define READ-NORMALISE-PRINT 227
;;; (lambda simple [env] 228
;;; (block (prompt (level)) 229
;;; (let [[normal-form (normalise (read) env id)]] 230
;;; (prompt (level)) 231
;;; (print normal-form) 232
;;; (read-normalise-print env))))) 233
;;; 234
;;; The way this is imagined to work is as follows: the very top processor 235
;;; level (infinitely high up) is invoked by someone (say, God, or some 236
;;; functional equivalent) normalising the expression (READ-NORMALISE-PRINT 237
;;; GLOBAL). When it reads an expression, it is given the input string 238
;;; "(READ-NORMALISE-PRINT GLOBAL)", which causes the level below it to read 239
;;; an expression, which is in turn given "(READ-NORMALISE-PRINT GLOBAL)", 240
;;; and so forth, until finally the second reflective level is given 241
;;; "(READ-NORMALISE-PRINT GLOBAL)". This types out "1>" on the console, 242
;;; and awaits YOUR input. 243
;;; 244
;;; 7. Environments: 245
;;; ---------------- 246
;;; 247
;;; Environments are sequences of two-element sequences, with each sub-sequence 248
;;; consisting of a variable and a binding (both of which are of course 249
;;; expressions). A normal-form environment designator, therefore, is a rail of 250
;;; rails, with each rail consisting of two handles. Variables are looked up 251
;;; starting at the front (i.e. the second element of the first subrail whose 252
;;; first element is the variable is the binding of that variable in that 253
;;; environment). Environments can also share tails: this is implemented by 254
;;; normal-form environment designators sharing tails (this is used heavily in 255
;;; the GLOBAL/ROOT/LOCAL protocols, and so forth). Effecting a side-effect on 256
;;; the standard normal-form environment designator CHANGES what the environment 257
;;; is, which is as it should be. Each level is initialised with the same global 258
;;; environment (the implementation does not support root environments -- see 259
;;; note 11). Page 1:4 260
;;; 261
;;; 8. Implementation: 262
;;; ------------------ 263
;;; 264
;;; 3-LISP Structural Type: MACLISP implementation: 265
;;; 266
;;; 1. Numerals -- Numerals 267
;;; 2. Booleans -- The atoms $T and $F 268
;;; 3. Pairs -- Pairs 269
;;; 4. Rails -- (~RAIL~ <e1> ... <en>) (but see note 9) 270
;;; 5. Handles -- (~QUOTE~ . <exp>) 271
;;; 6. Atoms -- atoms (except for $T, $F, ~RAIL~, ~QUOTE~, 272
;;; ~C0~, ~C1~, ~C2~, ~C3~, ~C4~, ~C5~, ~PRIM~, 273
;;; and NIL) 274
;;; 275
;;; The main processor functions constantly construct MACLISP representations 276
;;; of the 3-LISP normal-form designators of the continuations and environments 277
;;; that WOULD be being used if the processor were running reflectively. In 278
;;; this way functions that reflect can be given the right arguments without 279
;;; further ado. In assembling these continuations and environments (see 280
;;; 3-NORMALISE etc.), the code assumes that the incoming values are already in 281
;;; normal form. A more efficient but trickier strategy would be to put these 282
;;; objects together only if and when they were called for; I haven't attempted 283
;;; that here. This would all be made simpler if both environments and 284
;;; continuations were functions abstractly defined: no copying of structure 285
;;; would ever be needed, since the appropriate behaviour could be wrapped 286
;;; around the information in whatever form it was encoded in the primitive 287
;;; implementation. 288
;;; 289
;;; Two major recognition strategies are used for efficiency. Those instances 290
;;; of the four STANDARD continuation types that were generated by the MACLISP 291
;;; version of the processor are trapped and decoded primitively: if this were 292
;;; not done the processor would reflect at each step. Also, explicit calls to 293
;;; REDUCE and NORMALISE are trapped and run directly by the implementing 294
;;; processor: this is not strictly necessary, but unless it were done the 295
;;; processor might never come down again after reflecting up. 296
;;; 297
;;; The standard continuation types, called C0 - C3, are identified in the 298
;;; comments and in the definitions of NORMALISE and REDUCE (q.v.), and listed 299
;;; below. These types must be recognized by 3-APPLY and 3-REDUCE, so that the 300
;;; implementing processor can drop down whenever possible, whether or not the 301
;;; explicit interpretation of a (non-primitive) reflective function has 302
;;; intervened. The atoms ~C0~, ~C1~, ~C2~, and ~C3~ -- called the SIMPLE 303
;;; ALIASES -- are used instead of the primitive SIMPLE closure as the function 304
;;; type (i.e. as the CAR of the continuation closures). These atoms are also 305 [sic. triple space]
;;; MACLISP function names to effect the continuation). The implementation 306
;;; makes these atoms look = to the SIMPLE closure, so that the user cannot 307
;;; tell different atoms are being used, but so that the continuations can be 308
;;; trapped. 309
;;; 310
;;; Three other simple aliases are used (~C4~, ~C5~, and ~PRIM~). ~C4~ is used 311
;;; to identify the continuation used by READ-NORMALISE-PRINT, since the higher 312
;;; level READ-NORMALISE-PRINT continuation may not explicitly exist. ~C5~ is 313
;;; used by the IN-3-LISP macro to read in 3-LISP code embedded within MACLISP 314
;;; (it can therefore be used to read in 3-LISP code in files and so forth). 315
;;; ~PRIM~ is used in normal-form designators of primitive procedures. Thus, 316
;;; while PCONS in the initial global environment looks to a 3-LISP program to 317
;;; normalise to (<SIMPLE> '[ ... <global>] '[A B] '(PCONS A B)), in fact the 318
;;; CAR of that form is ~PRIM~, not <SIMPLE>. 319
;;; 320
;;; The four standard continuations: 321
;;; 322
;;; C0: Accept the normalised function designator in an application. 323
;;; C1: Accept the normalised arguments for a SIMPLE application. 324
;;; C2: Accept the normalised first element in a rail fragment. 325
;;; C3: Accept the normalised tail of a rail fragment. 326
;;; 327
;;; (C4: Identifies top level call of READ-NORMALISE-PRINT.) 328
;;; (C5: Used in order to read in 3-LISP structures by IN-3-LISP.) 329
;;; Programming conventions: Page 1:5 331 [sic. no 330]
;;; 332
;;; Special variables are prefixed with "3=". Procedures are prefixed with "3-". 333
;;; If they operate on MACLISP structures implementing 3-LISP structures, the 334
;;; procedure name is defined with respect to the operation viewed with respect 335
;;; to the 3-LISP structure. For example, 3-EQUAL returns T if the two arguments 336
;;; encode the same 3-LISP structure. 337
;;; 338
;;; NOTE: In fall 1981, the implementation was minimally changed to run on an MIT 339
;;; CADR machine, not in MACLISP. The only concessions to the new base were in 340
;;; the treatment of I/O and interrupts; no particular features of the CADR have 341
;;; been used. It should therefore require minimal work to retrofit it to a 342
;;; MACLISP base. 343
; 344
;;; 9. Rails: Implementation and Management: 345
;;; ---------------------------------------- 346
;;; 347
;;; The implementation of rails is tricky, because RPLACT modifications must be 348
;;; able to take effect on the 0'th tail, as well as subsequent ones, requiring 349
;;; either the use of full bi-directional linkages, or "invisible pointers" (a 350
;;; true LISP-machine implementation could perhaps use the underlying invisible 351
;;; pointer facility) and special circularity checking. We choose the latter 352
;;; option. The implementation (where "+" means one or more, "*" means zero or 353
;;; more) of a rail is: 354
;;; 355
;;; [a b ... z] ==> (<~RAIL~>+ a <~RAIL~>* b ... <~RAIL~>* z <~RAIL~>*) 356
;;; 357
;;; where the ~RAIL~ atoms are effectively invisible, but begin every rail that 358
;;; is given out to the outside world (and can thus be used to distinguish 359
;;; rails from 3-LISP cons pairs). Just reading in [A B ... Z] generates 360
;;; (~RAIL~ A B ... Z). 361
;;; 362
;;; Unless RPLACT's are done, the number of ~RAIL~ atoms cannot exceed the number 363
;;; of elements. With arbitrary RPLACT'ing, the efficiency can get arbitrarily 364
;;; bad (although it could be corrected back to a linear constant of 2 by a 365
;;; compacting garbage collector.) 366 [sic. stop placement]
;;; 367
;;; 10. User Interface: 368
;;; ------------------- 369
;;; 370
;;; To run 3-LISP, load the appropriate one of the following FASL files: 371
;;; 372
;;; ML: ML:BRIAN;3-LISP FASL 373 [illegible: colon or semicolon?]
;;; PARC: [Phylum]<BrianSmith>3-lisp>3-lisp.qfasl 374
;;; 375
;;; The processor can be started up by executing (3-LISP), and re-initialised 376
;;; completely at any point by executing (3-INIT) (both in MACLISP). The 377
;;; READ-NORMALISE-PRINT loop prints the current reflective level to the left 378
;;; of the prompt character. The following interrupt characters are defined: 379
;;; 380
;;; a. Control-E -- Toggles between MACLISP and 3-LISP. 381
;;; 382
;;; b. Control-G -- Quit to level 1 (regular quit in MACLISP) 383 [sic. full stop]
;;; c. Control-F -- Quit to current level (regular quit in MACLISP) 384
;;; 385
;;; To read in and manipulate files, surround an arbitrary number of 386
;;; expressions with the MACLISP wrapping macro IN-3-LISP, and precede each 387
;;; 3-LISP expression with a backslash, so that it will be read in by the 388
;;; 3-LISP reader. Then load the file as if it were a regular MACLISP file. 389
;;; For example: 390
;;; 391
;;; (in-3-lisp 392
;;; \(define increment (lambda simple [x] (+ x 1))) 393
;;; \(define quit (lambda reflect [] 'QUIT))) 394
;;; 395
;;; Equivalent, and with the advantage that TAGS and @ see the definitions, is: 396
;;; 397
;;; (in-3-lisp \[ 398
;;; 399
;;; (define increment (lambda simple [x] (+ x 1))) 400
;;; (define quit (lambda reflect ? 'QUIT)) ]) 401
;;; Page 1:6 404 [sic. no 402, 403]
;;; 11. Limitations of the Implementation: 405
;;; -------------------------------------- 406
;;; 407
;;; There are a variety of respects in which this implementation is incomplete 408
;;; or flawed: 409
;;; 410
;;; 1. Side effects to the reflective procedures will not be noticed -- in a 411
;;; serious implementation these procedures would want to be kept in a pure 412
;;; page so that side effects to them could be trapped, causing one level 413
;;; of reflective deferral. 414
;;; 415
;;; 2. Reflective deferral is not yet support at all. No problems are 416 [sic. leg. "supported"]
;;; expected; it merely needs attention. 417
;;; 418
;;; 3. In part because I think it may be a bad idea, this implementation does 419
;;; not support a root environment protocol. 420
;;; 421
;;; 12. Obvious Extensions: 422
;;; ----------------------- 423
;;; 424
;;; Obvious extensions to the implementation fall into two groups: those that 425
;;; would increase the efficiency of the implementation, but not change its 426
;;; basic functionality, and those that would extend that functionality. 427
;;; Regarding the first, the following are obvious candidates: 428
;;; 429
;;; 1. Get rid of the automatic consing of continuation and environment 430
;;; structures, as mentioned earlier. 431
;;; 432
;;; 2. Support various intensional procedures (LAMBDA, IF, COND, MACRO, SELECT, 433
;;; and so forth) as primitives. This would require the virtual provision 434
;;; of all of the continuation structure at the reflective level that would 435
;;; have been generated had the definitions used here been used explicitly: 436
;;; it wouldn't be trivial. Unless, of course, the language was redefined 437
;;; to include these as primitives (but the current proof of its finiteness 438
;;; depends on no reflective primitives, so this too would take some work). 439
;;; 440
;;; Functional extensions include: 441
;;; 442
;;; 1. Make the bodies of LAMDBA, LET, COND, etc. take multiple expressions 443 [sic. "LAMDBA"]
;;; (i.e. be virtual BLOCK bodies). 444
;;; 445
;;; 2. Strings (and normal-form string designators, perhaps called "STRINGERS") 446
;;; could be added. 447
; 448
#+sbcl (declaim (sb-ext:muffle-conditions style-warning))
;;; Page 2 001
;;; Declarations and Macros: 002
;;; ======================== 003
; 004
(proclaim ; 005
'(special ; 006
3=simple-aliases 3=global-environment 3=states 3=level 3=break-flag ; 007
3=in-use 3=readtable L=readtable S=readtable 3=a1 3=a2 3=a3 3=a4 ; 008
3=normalise-closure 3=reduce-closure 3=simple-closure 3=reflect-closure ; 009
3=id-closure 3=backquote-depth)) ; 010
;(proclaim '(ignore 3=process))
;;; (herald 3-LISP) 013
; 014
(eval-when (:load-toplevel :execute :compile-toplevel) ; 015
; 016
;; Common Lisp portability
(defun memq (x y) (member x y :test #'eq))
(defun explodec (object)
(loop for char across (prin1-to-string object)
collect (intern (string char))))
(defun implode (list)
(read-from-string (coerce (mapcar #'character list) 'string)))
(defun fixp (x) (integerp x))
(defun and* (&rest args)
(cond ((null args) t)
((car args) (apply #'and* (cdr args)))
(nil)))
(defmacro list? (x) `(typep ,x 'list)) ; 017
(defmacro 1st (l) `(car ,l)) ; 018
(defmacro 2nd (l) `(cadr ,l)) ; 019
(defmacro 3rd (l) `(caddr ,l)) ; 020
; 021
) ; 022
; 023
(defmacro 3-primitive-simple-id (proc) `(cadr (3r-3rd (cdr ,proc)))) ; 024
; 025
(defmacro 3-numeral (e) `(fixp ,e)) ; 026
(defmacro 3-boolean (e) `(member ,e '($T $F))) ; 027
; 028
(defmacro 3-bind (vars vals env) ; 029
`(cons '~RAIL~ (nconc (3-bind* ,vars ,vals) ,env))) ; 030
; 031
;;; Two macros having to do with input: 032
; 033
(defmacro in-3-lisp (&rest body) ; 034
`(progn (or (boundp '3=global-environment) (3-init)) ; 035
,@(do ((exprs body (cdr exprs)) ; 036
(forms nil (cons `(3-lispify ',(car exprs)) forms))) ; 037
((null exprs) (nreverse forms))))) ; 038
; 039
(defmacro ~3-BACKQUOTE (expr) (3-expand expr nil)) ; 040
; 041
;;; 3-NORMALISE* If MACLISP were tail-recursive, calls to this would 042
;;; ------------ simply call 3-NORMALISE. Sets up the loop variables 043
;;; and jumps to the top of the driving loop. 044
; 045
(defun 3-normalise* (exp env cont) ; 046
(3-normalise exp env cont))
; 049
;;; The rest of the macro definitions are RAIL specific: 050
; 051
(defmacro 3r-1st (exp) `(car (3-strip ,exp))) ; 052
(defmacro 3r-2nd (exp) `(car (3-strip (3-strip ,exp)))) ; 053
(defmacro 3r-3rd (exp) `(car (3-strip (3-strip (3-strip ,exp))))) ; 054
(defmacro 3r-4th (exp) `(car (3-strip (3-strip (3-strip (3-strip ,exp)))))) ; 055
; 056
;;; Macros for RAIL management: 057
; 058
;;; 3-STRIP -- Returns a rail with all ~RAIL~ headers removed. Have 059
;;; ------- have to step through as many headers as have built up. 060 [sic. "have"]
;;; 061
;;; 3-STRIP* -- Returns the last header of arg -- used for RPLACD, and 062
;;; -------- to establish rail identity. Steps down through headers. 063
; 064
(eval-when (:load-toplevel :execute :compile-toplevel) ; 065
; 066
(defmacro 3-strip (rail) ; 067
`(do ((rest (cdr ,rail) (cdr rest))) ; 068
((not (eq (car rest) '~RAIL~)) rest))) ; 069
; Page 2:1 070
(defmacro 3-strip* (rail) ; 071
`(do ((rest ,rail (cdr rest))) ; 072
((not (eq (cadr rest) '~RAIL~)) rest))) ; 073
; 074
) ; 075
; 076
;;; 3-LENGTH* -- Return the length of a 3-LISP rail. 077 [sic. "return" vs. "returns"]
; 078
(defmacro 3-length* (rail) ; 079
`(do ((n 0 (1+ n)) ; 080
(rail (3-strip ,rail) (3-strip rail))) ; 081
((null rail) n))) ; 082
; 083
; Page 3 001
;;; Input/Output: 002
;;; ============= 003
;;; 004
; 005
;;; A special readtable (3=READTABLE) is used to read in 3-LISP notation, since 006
;;; it must be parsed differently from MACLISP notation. The 3-LISP READ- 007
;;; NORMALISE-PRINT loop uses this; in addition, a single expression will be 008
;;; read in under the 3-LISP reader if preceded by backslash ("\") in the 009
;;; MACLISP reader. Similarly, a single expression will be read in by the 010
;;; MACLISP reader if preceded with a tilde ("~") in the 3-LISP reader. 011
;;; 012
;;; MACLISP and 3-LISP both support backquote. The readers and the backquotes 013
;;; can be mixed, but be cautious: the evaluated or normalised expression must 014
;;; be read in with the right reader. For example, a MACLISP backquoted 015
;;; expression can contain a 3-LISP fragment with a to-be-evaluated-by-MACLISP 016
;;; constituent, but a tilde is required before it, so that the MACLISP reader 017
;;; will see it. Example: "`\[value ~,(plus x y)]". ",@" and ",." are not 018
;;; supported by the 3-LISP backquote. 019
;;; 020
;;; Any 3-LISP backquoted expression will expand to a new-structure-creating 021
;;; expression at the level of the back-quote, down to and including any level 022 [sic. hyphenation]
;;; including a comma'ed expression. Thus `[] expands to (rcons), `[[a b c] [d 023
;;; ,e f]] expands to (rcons '[a b c] (rcons 'd e 'f)), and so forth. This is 024
;;; done so as to minimise the chance of unwanted shared tails, but to avoid 025
;;; unnecessary structure consing. We use `[] in place of (rcons) many times in 026
;;; the code. 027
;;; 028
;;; Expressions like "~~C0~" are necessary in order to get the aliases into 029
;;; 3-LISP, since the first tilde flips readers. Once 3-LISP has been 030
;;; initialised the aliases will be rejected: to reload a function containing an 031
;;; alias, temporarily bind 3=simple-aliases to NIL. 032
;;; 033
;;; There are two special read macro characters, for name and referent (MACLISP 034
;;; and 3-LISP versions). (Ideally these would be uparrow and downarrow, but 035
;;; down-arrow is unfortunately not an ASCII character): 036 [sic. hyphenation]
;;; 037
;;; Form MACLISP expansion 3-LISP expansion 038
;;; 039
;;; 1. ↑<exp> (3-NAME <exp>) (NAME <exp>) 040
;;; 2. ↓<exp> (3-REF <exp>) (REFERENT <exp> (current-env)) 041
; 042
(eval-when (:load-toplevel :execute :compile-toplevel) ; 043
; 044
;;; Five constants need to be defined for 3-LISP structures to be read in: 045
; 046
(setq S=readtable *readtable* ; Save the system readtable ; 047
L=readtable (copy-readtable) ; and name two special ones: ; 048
3=readtable (copy-readtable) ; one for LISP, one for 3-LISP. ; 049
3=simple-aliases nil ; Make these NIL so we can read ; 050
3=backquote-depth 0) ; in the aliases in this file! ; 051
; 052
;;; The following has been modified from the original MACLISP to enable it to 053
;;; operate under the I/O protocols of the MIT LISP machine: 054
; 055
(setq *readtable* L=readtable) ; Needed in order to read this file. ; 056
; 057
(defun single-macro-character (stream char)
(declare (ignore stream))
(intern (string char)))
(defun read* (s)
(read-preserving-whitespace s))
(let ((*readtable* L=readtable)) ; 058
(set-macro-character #\\ #'(lambda (s c) (3-read s))) ; 059
(set-macro-character #\↑ #'(lambda (s c) `(cons '~QUOTE~ ,(read* s)))) ; 060
(set-macro-character #\↓ #'(lambda (s c) `(3-ref ,(read* s)))) ; 061
(set-macro-character #\] #'single-macro-character)) ; So "~FOO]" will work. ; 062
; Page 3:1 ; [sic. no line number]
; 063
(let ((*readtable* 3=readtable)) ; 064
(set-macro-character #\~ #'(lambda (s c) (let ((*readtable* L=readtable)) (read* s)))) ; 065
(set-macro-character #\↓ #'(lambda (s c) `(referent ~RAIL~ ,(3-read* s) ; 066
(current-env ~RAIL~)))) ; 067
(set-macro-character #\↑ #'(lambda (s c) `(name ~RAIL~ ,(3-read* s)))) ; 068
(set-macro-character #\' #'(lambda (s c) `(~QUOTE~ . ,(3-read* s)))) ; 069
(set-macro-character #\( #'(lambda (s c) (3-read-pair s))) ; 070
(set-macro-character #\[ #'(lambda (s c) (3-read-rail s))) ; 071
(set-macro-character #\` #'(lambda (s c) (3-backq-macro s))) ; 072
(set-macro-character #\, #'(lambda (s c) (3-comma-macro s))) ; 073
(set-macro-character #\) #'single-macro-character) ; 074
(set-macro-character #\/ #'single-macro-character) ; 075
(set-macro-character #\$ #'single-macro-character) ; 076
(set-macro-character #\] #'single-macro-character) ; 077
(set-macro-character #\. #'single-macro-character)) ; 078
; 079
;;; 3-ERROR General error handler. MESSAGE is to be printed by MACLISP's 005
;;; ------- PRINC, whereas EXPR is printed by 3-PRINT. 006
; 007
(defun 3-error (message &optional expr (label '|ERROR: |)) ; 008
(terpri) ; 009
(princ label) ; 010
(if (atom message) ; 011
(princ message) ; 012
(mapc #'(lambda (el) (princ el) (princ '| |)) ; 013
message)) ; 014
(if expr (3-print expr)) ; 015
(break) ; 016
(if 3=in-use ; 017
(throw '3-level-loop nil) ; 018
(3-lisp))) ; 019
; 020
;;; 3-TYPE-ERROR 3-ILLEGAL-CHAR 021
;;; 3-INDEX-ERROR 3-ILLEGAL-ATOM 022
;;; 3-IMPLEMENTATION-ERROR 3-ILLEGAL-BOOLEAN 023
;;; ---------------------- ----------------- 024
; 025
(defun 3-type-error (exp type) ; 026
(3-error `(expected a ,(implode `(,@(explodec type) #\,)) ; 027
but found the ,(3-type exp)) ; 028
exp '|TYPE-ERROR: |)) ; 029
; 030
(defun 3-ref-type-error (exp type) ; 031
(3-error `(expected a ,(implode `(,@(explodec type) #\,)) ; 032
but found the ,(3-ref-type exp)) ; 033
exp '|TYPE-ERROR: |)) ; 034
; 035
(defun 3-index-error (n rail) ; 036
(3-error `(,n is out of range for) rail '|INDEX-ERROR: |)) ; 037
; 038
(defun 3-implementation-error () (3-error '|Illegal implementation state!|)) ; 039
; 040
(defun 3-illegal-char (char) ; 041
(3-error `(unexpected ,(implode `(|"| ,@(explodec char) |"|))) ; 042
nil '|NOTATION-ERROR: |)) ; 043
; 044
(defun 3-illegal-boolean (exp) ; 045
(3-error `(expected a boolean\, but found ,(implode `($ ,@(explodec exp)))) ; 046
nil '|NOTATION-ERROR: |)) ; 047
; 048
(defun 3-illegal-atom (atom) ; 049
(3-error `(The atom ,atom is reserved in this implementation) ; 050
nil '|STRUCTURE-ERROR: |)) ; 051
; 052
;;; 3-READ(*) Read in one 3-LISP s-expression (*-version assumes the 080
;;; --------- 3-LISP readtable is already in force, and accepts an 081
;;; optional list of otherwise illegal atoms to let through). 082
; 083
(defun 3-read (&optional stream) ; 084
(let ((*readtable* 3=readtable)) (3-read* stream))) ; 085
; 086
(defun 3-read* (stream &optional OK) ; 087
(let ((token (read* stream))) ; 088
(cond ((memq token OK) token) ; 089
((memq token '(|)| |.| |]|)) (3-illegal-char token)) ; 090
((or (memq token '(~RAIL~ ~QUOTE~ NIL)) ; 091
(memq token 3=simple-aliases)) (3-illegal-atom token)) ; 092
((eq token '\$) (3-read-boolean stream)) ; 093
(t token)))) ; 094
; 095
(defun 3-read-boolean (stream) ; 096
(let ((a (read-char stream))) ; 097
(cond ((memq a '(#\T #\t)) '$T) ; 098
((memq a '(#\F #\f)) '$F) ; 099
(t (3-illegal-boolean a))))) ; 100
; 101
(defun 3-read-pair (stream) ; 102
(let ((a (3-read* stream)) ; 103
(b (3-read* stream '(|.| |)|)))) ; 104
(if (eq b '|.|) ; 105
(prog1 (cons a (3-read* stream)) ; 106
(setq b (read* stream)) ; 107
(if (not (eq b '|)|)) (3-illegal-char b))) ; 108
(do ((b b (3-read* stream '(|)|))) ; 109
(c nil (cons b c))) ; 110
((eq b '|)|) (list* a '~RAIL~ (nreverse c))))))) ; 111
; 112
(defun 3-read-rail (stream) ; 113
(do ((a nil (cons b a)) ; 114
(b (3-read* stream '(|]|)) (3-read* stream '(|]|)))) ; 115
((eq b '|]|) (cons '~RAIL~ (nreverse a))))) ; 116
; 117
) ; End of eval-when ; 118
; Page 3:2 ; [sic. no line number]
(eval-when (:execute :load-toplevel :compile-toplevel)
; Start another eval-when, since the following ; 119
; needs to be read in using 3-READ ; 120
; 121
(defun 3-type (exp) ; 007
(cond ((fixp exp) 'numeral) ; 008
((memq exp '($T $F)) 'boolean) ; 009
((symbolp exp) 'atom) ; 010
((eq (car exp) '~RAIL~) 'rail) ; 011
((eq (car exp) '~QUOTE~) 'handle) ; 012
(t 'pair))) ; 013
;;; BACKQUOTE 3-BACKQ-MACRO and 3-COMMA-MACRO are run on reading: they 122
;;; --------- put calls to ~3-BACKQUOTE and ~3-COMMA into the structures 123
;;; they build, which are then run on exit. This allows the 124
;;; expansion to happen from the inside out. 125
; 126
(defun 3-backq-macro (stream) ; 127
(let ((3=backquote-depth (1+ 3=backquote-depth))) ; 128
(macroexpand (list '~3-BACKQUOTE (read* stream))))) ; 129
; 130
(defun 3-comma-macro (stream) ; 131
(if (< 3=backquote-depth 1) (3-error '|Unscoped comma|)) ; 132
(let ((3=backquote-depth (1- 3=backquote-depth))) ; 133
(cons '~3-COMMA (read* stream)))) ; 134
; 135
;;; The second argument to the next 3 procedures is a flag: NIL if the 136
;;; backquote was at this level; T if not (implying that coalescing can 137
;;; happen if possible). 138
; 139
(defun 3-expand (x f) ; 140
(case (3-type x) ; 141
(PAIR (3-expand-pair x f)) ; 142
(RAIL (3-expand-rail x f)) ; 143
(T ↑x))) ; 144
; 145
(defun 3-expand-pair (x f) ; 146
(cond ((eq (car x) '~3-COMMA) (cdr x)) ; Found a ",<expr>". ; 147
((eq (car x) '~3-BACKQUOTE) ; Recursive use of backq, so ; 148
(3-expand (macroexpand x) f)) ; expand the inner one and then ; 149
(t (let ((a (3-expand (car x) t)) ; this one. ; 150
(d (3-expand (cdr x) t))) ; 151
(if (and f (3-handle a) (3-handle d)) ; 152
↑(cons (cdr a) (cdr d)) ; Do the cons now if possible; ; 153
`\(PCONS ~,a ~,d)))))) ; else use MACLISP's backquote ; 154
; to form a call to PCONS. ; 155
; 156
(defun 3-expand-rail (rail f) ; 157
(do ((rail (3-strip rail) (3-strip rail)) ; 158
(elements nil (cons (3-expand (car rail) t) elements))) ; 159
((null rail) ; 160
(if (and f (apply 'and* (mapcar '3-handle elements))) ; 161
↑(cons '~RAIL~ (mapcar 'cdr (nreverse elements))) ; 162
`(RCONS ~RAIL~ ,@(nreverse elements)))))) ; 163
; 164
) ; end of eval-when ; 165
; Page 3:3 ; [sic. no line number]
; 166
;;; 3-PRINT Print out <exp> in 3-LISP notation using notational sugar if 167
;;; ------- possible. No preliminary CR is printed (use TERPRI). Some 168
;;; attempt is made to avoid printing known circular structures 169
;;; (like <SIMPLE> and <REFLECT> and obvious circular environments 170
;;; of a sort that would be generated by Z). 171
; 172
(defun 3-print (exp) ; 173
(case (3-type exp) ; 174
(numeral (princ exp)) ; 175
(boolean (princ exp)) ; 176
(atom (if (memq exp 3=simple-aliases) ; 177
(princ '<simple>) ; 178
(prin1 exp))) ; 179
(handle (princ '|'|) (3-print ↓exp)) ; 180
(pair (cond ((eq exp 3=simple-closure) (princ '<simple>)) ; 181
((eq exp 3=reflect-closure) (princ '<reflect>)) ; 182
(t (princ '|(|) ; 183
(3-print (car exp)) ; 184
(if (3-rail (cdr exp)) ; 185
(if (3-circular-closure-p exp) ; 186
(progn (princ '| <circular-env>|) ; 187
(3-print-elements (cddr exp) 't)) ; 188
(3-print-elements (cdr exp) 't)) ; 189
(progn (princ '| . |) (3-print (cdr exp)))) ; 190
(princ '|)|)))) ; 191
(rail (princ '|[|) ; 192
(3-print-elements exp 'nil) ; 193
(princ '|]|)))) ; 194
; 195
(defun 3-print-elements (list flag) ; 196
(let ((global (3-strip 3=global-environment))) ; 197
(do ((list (3-strip list) (3-strip list)) ; 198
(flag flag 't)) ; 199
((null list)) ; 200
(if (eq list global) ; 201
(return (princ '| ... <global>|))) ; 202
(if flag (princ '| |)) ; 203
(3-print (car list))))) ; 204
; 205
(defun 3-prompt (level &optional (char ">")) ; 206
(format t "~%~D~A " level char) ; 207
(finish-output))
; 210
(defun 3-circular-closure-p (exp) ; 211
(and (< 0 (3-length (cdr exp))) ; 212
(3-rail (3r-1st (cdr exp))) ; 213
(< 0 (3-length (3r-1st (cdr exp)))) ; 214
(let ((env? (3r-1st (3r-1st (cdr exp))))) ; 215
(and (3-rail env?) ; 216
(< 1 (3-length env?)) ; 217
(3-handle (3r-1st env?)) ; 218
(3-atom ↓(3r-1st env?)) ; 219
(3-handle (3r-2nd env?)) ; 220
(eq exp ↓(3r-2nd env?)))))) ; 221
; 222
; Page 4 ; [sic. no line number]
; 001
;;; Main Processor: 002
;;; =============== 003
;;; 004
;;; 005
;;; 3-NORMALISE and 3-REDUCE The second clause in the following takes care 006
;;; ------------------------ of numerals, booleans, handles, normal-form 007
;;; function designators (applications in terms of 008
;;; the functions SIMPLE, MACRO, and REFLECT whose args are in normal form), 009
;;; and normal-form sequence designators (rails whose elements are all in 010
;;; normal-form). Thus all normal-form expressions normalise to themselves, 011
;;; even those (like rails and function-designators) that are not canonical 012
;;; designators of their referents. 013
; 014
(defun 3-normalise (exp env cont) ; 015
(cond ((3-atom exp) (3-apply cont (3-binding exp env))) ; 016
((3-normal exp) (3-apply cont exp)) ; 017
((3-rail exp) (3-normalise-rail exp env cont)) ; 018
(t (3-reduce (car exp) (cdr exp) env cont)))) ; 019
; 020
(defun 3-reduce (proc args env cont) ; 021
(3-normalise* proc env ; 022
`\(~~C0~ [['proc ~,↑proc] ['args ~,↑args] ['env ~,↑env] ['cont ~,↑cont]] ; C0 ; 023
'[proc*] ; 024
'(selectq (procedure-type proc*) ; 025
[reflect ((simple . ↓(cdr proc*)) args env cont)] ; 026
[simple (normalise args env (make-c1 proc* cont))])))) ; 027
; 028
;;; 3-NORMALISE-RAIL Normalise (the first element of) a rail. 029
;;; ---------------- 030
; 031
(defun 3-normalise-rail (rail env cont) ; 032
(if (null (3-strip rail)) ; 033
(3-apply cont rail) ; 034
(3-normalise* (3r-1st rail) env ; 035
`\(~~C2~ [['rail ~,↑rail] ['env ~,↑env] ['cont ~,↑cont]] ; C2 ; 036
'[element*] ; 037
'(normalise-rail (rest rail) env ; 038
(lambda simple [rest*] ; 039
(cont (prep element* rest*)))))))) ; 040
; 041
;;; 3-PRIMITIVE-REDUCE-SIMPLE The way each primitive function is treated is 042
;;; ------------------------- highly dependent on the way that 3-LISP 043
;;; structures are encoded in MACLISP. 044
; 045
(defun 3-primitive-reduce-simple (proc args cont) ; 046