(texdraft.github.io) Hello

ROAM_REFS: https://texdraft.github.io/

Lisp compiler source code Lisp compiler internals

(texdraft.github.io) LISP 1.5 Source

ROAM_REFS: https://texdraft.github.io/lisp-1.5/listing.html
  • LISP 1.5 System Listing

What is this?

This is a hyperlinked, marked-up version of the source code of the first Lisp implementation, LISP 1.5 for the IBM 704/709/7090/7094 computers. The code is ultimately derived from a 1961 listing of the system, whose text has been reconstructed by some intrepid retrocomputerists (Pascal Bourguignon, Rich Cornwell, and Bob Abeles).

The code is written in the syntax of a series of assemblers, beginning with SAP [Symbolic (later SHARE) Assembly Program] (manual), followed by FAP (FORTRAN Assembly Program) (several manuals), then MAP (Macro Assembly Program) (ditto). These languages are mostly compatible, later versions maintaining obsolete features of previous iterations. Luckily, the LISP 1.5 source tends to stick to a SAP subset, using only a handful of the more advanced capabilities of FAP and MAP.

As for the machines themselves, you can read the official documentation on Bitsavers (704, 709, 7090, 7094) or Jack Harper's website (presently offline, unfortunately). Wikipedia's article on the 704 summarizes some key details that will help understanding LISP 1.5. Briefly, this series of machines (all shared the same basic “architecture”) had thirty-six-bit words with a fifteen-bit address space (32768₁₀, or rather 10000₈—get used to octal). Negative integers were represented using sign–magnitude. To make self-modifying code easier, two address-sized subfields of words could conveniently be manipulated, because they were used for operands in common instructions. These fields, as you might know, were called the address and decrements, hence c/a/r and c/d/r, etc. The system had two general-purpose registers, conventionally called “AC” (for “Accumulator”) and “MQ” (for “Multiplier-Quotient”), and three (seven on the 7094) fifteen-bit index registers known as “IR1”, “IR2”, and “IR4” (the missing numbers filled in for the 7094). When an instruction had an index register specified, that index register's contents was subtracted from the instruction (not from the address accessed by the instruction!). By placing the two's complement of a number in an index register, the effect of adding that number may be obtained. There was nothing like a hardware stack.

There are two kinds of line in the listing below: comment lines (“remarks”) and code lines. Every line is numbered, and you can use that number to link to a particular line. (This is a deviation from the printed listing, which did not provide line numbers for assembler-generated lines and reset the number to 1 after a DECK pseudo-operation, in order to make it easy to identify lines uniquely.) Code lines have several fields, many of which may be blank:

Flags, containing single-character markers that indicate problems with the line.

You can hover over the flags to see what they signify. The only ones in this listing are for absent fields in an instruction.

Address, the location in memory.

Five octal digits, absent for pseudo-operations that did not result in any assembly.

Assembly, a representation of the machine word produced by the assembler.

One or more fields in several formats, related to the encoding of the instruction, absent for some pseudo-operations. The vast majority of instruction have a five-digit (octal) address part that you can look at to see the value of the expression in that field.

Line number, as explained above.

Location, usually containing a symbol to be defined as the address.

Today we would probably say “label”. The lone exception is with the HED psuedo-operation, which instead interpreted the first column as a character used to “head” symbols. Heading a symbol meant prefixing it with the head character and spaces to pad it to six characters (leaving it alone if it's already long enough). For example, if the head is “=L=”, then

LOAD
is headed to
L␣LOAD
, but
COMMON
is unaffected by a head. Programmers can opt out per symbol by writing
C=/=$=/=S
, where
C
is the desired head character (or empty to indicate no head) and
S
is the name before heading. For example,
C$MOV
becomes
C␣␣MOV
, and
$CPPI
will always be
␣␣CPPI
no matter what the head is. The point of this feature is to provide rudimentary namespace separation, so that symbols' “scope” could be limited to certain subprograms. Later assemblers supported multiple head simultaneously using the new HEAD pseudo-operation, which took an arbitrary number of heads in the variable field.

When you click on a symbol in the location field, you'll be taken to a cross-reference page for that symbol, showing its definition (the line you came from) and every line that contains the symbol in an expression.

Operation, containing the mnemonic for the operation.

Operations are either machine instructions (such as TRA or CLA or LDC, or commands for the assembler (such as BSS or TTL). When it's a machine instruction, * after the mnemonic indicates indirect addressing.

Variable field*/*remarks, containing operands and commentary.

This field usually consists of comma-separated expressions (the “variable field”) and then a comment after some whitespace. The variable field can sometimes contain spaces, when the operation is BCD or BCI or VFD.

When you click on a symbol in the variable field, you'll be taken to that symbol's point of definition. Hover over integers to see their magnitude in octal and decimal.

Good luck!

(texdraft.github.io) Lisp Compiler

ROAM_REFS: https://texdraft.github.io/lisp-compiler/internals.html
  • The First Lisp Compiler

** By Asher Olsen

** Introduction

This page examines the earliest surviving Lisp compiler, written by Timothy Hart and Michael Levin around 1961. To avoid repetition of phrases like “the compiler”, we will use the abbreviation “HLC” (for “Hart–Levin Compiler”) to refer to it. The HLC was introduced in M.I.T. AIM-039 and documented more fully in the LISP 1.5 Programmer's Manual by McCarthy et al.

For information about the timeline of Lisp compilers, I refer you to the ques­tion “What was the first Lisp compiler” on the Retrocomputing Stack­Exchange site; the answer there gives an excellent overview. We will be focusing on implementation details. It should be mentioned, however, that al­though the title of this page is “The First Lisp Compiler”, the HLC is really the second Lisp compiler. A more correct title would be “The First Good Lisp Com­piler” or “The First Lisp Compiler Whose Source Code is Available”.

In order to understand the HLC, a decent amount of prequisite knowledge is required, about the machine LISP 1.5 ran on and about LISP 1.5 itself. If you aren't already familiar, I recommend reading the LISP 1.5 Programmer's Manual linked above and checking out Jack Harper's site on the IBM 7090. You might also be interested in a GitHub issue I wrote a little while ago.

** The source

The source code of the HLC comes from an archive of CTSS source code, namely lines 278–592 of file ctss/lispset.job. Reading the code in its original form is quite difficult, since there is virtually no indentation or meaningful spacing. Occasionally atoms will start on one line/card and end on the next! And of course all-uppercase text is not known for being especially readable. Therefore I have prepared a formatted and cross-referenced version of the code for easy viewing.

Even though the code looks pretty, I still find it hard to follow. All destruc­turing is done with compositions of car and cdr. (I'm not criticizing the authors here, since it's not like LISP 1.5 gave them anything better to work with. But it feels like a step down when compared to Common Lisp, where we have fancy lambda lists and destructuring-bind.) An additional obscurity lies in the choices of function and variable names. For example, the name pi2 provides no clue as to its purpose (which is to construct a setq form). I think this is an assembly language convention.

To run the code, you could try simulating the LISP 1.5 system, or you can use my translation to Common Lisp. Note: This translation does the bare mini­mum to get it running. I make no attempt to use any high-level Common Lisp constructs; the aim was to leave the code as unchanged as possible except to add indentation. To compile the compiler, uncomment the lines at the bottom.

The source code of an earlier version of the HLC also exists, in a document titled “LISP LIBRARY NOVEMBER 1963”.

See Also

Local Graph

org-roam 3130a06b-6bc8-4cd2-9829-7550536c8f4d (texdraft.github.io) Hello //texdraft.github.io/lisp-compiler/listing.html https://texdraft.github.io/lisp-compiler/listing.html 3130a06b-6bc8-4cd2-9829-7550536c8f4d->//texdraft.github.io/lisp-compiler/listing.html //texdraft.github.io/lisp-compiler/internals.html https://texdraft.github.io/lisp-compiler/internals.html 3130a06b-6bc8-4cd2-9829-7550536c8f4d->//texdraft.github.io/lisp-compiler/internals.html ff9fbc90-85a8-4b34-a759-a9cc19b9ed15 (www.softwarepreservation.org) LISP 1... 3130a06b-6bc8-4cd2-9829-7550536c8f4d->ff9fbc90-85a8-4b34-a759-a9cc19b9ed15