瀏覽代碼

Initial revision

sater 40 年之前
父節點
當前提交
3efa053ae7
共有 11 個文件被更改,包括 7326 次插入0 次删除
  1. 39 0
      doc/Makefile
  2. 419 0
      doc/ack.doc
  3. 1832 0
      doc/cg.doc
  4. 317 0
      doc/cref.doc
  5. 622 0
      doc/install.doc
  6. 1511 0
      doc/pcref.doc
  7. 505 0
      doc/peep.doc
  8. 131 0
      doc/regadd.doc
  9. 896 0
      doc/toolkit.doc
  10. 302 0
      doc/v7bugs.doc
  11. 752 0
      doc/val.doc

+ 39 - 0
doc/Makefile

@@ -0,0 +1,39 @@
+SUF=pr
+PRINT=cat
+RESFILES=cref.$(SUF) pcref.$(SUF) val.$(SUF) v7bugs.$(SUF) install.$(SUF)\
+ack.$(SUF) cg.$(SUF) regadd.$(SUF) peep.$(SUF) toolkit.$(SUF)
+NROFF=nroff
+
+cref.$(SUF):        cref.doc
+		tbl $? | $(NROFF) >$@
+v7bugs.$(SUF):      v7bugs.doc
+		$(NROFF) -ms $? >$@
+ack.$(SUF):         ack.doc
+		$(NROFF) -ms $? >$@
+cg.$(SUF):		cg.doc
+		$(NROFF) -ms $? >$@
+regadd.$(SUF):		regadd.doc
+		$(NROFF) -ms $? >$@
+install.$(SUF):     install.doc
+		$(NROFF) -ms $? >$@
+pcref.$(SUF):       pcref.doc
+		$(NROFF) $? >$@
+peep.$(SUF):	peep.doc
+		$(NROFF) -ms $? >$@
+val.$(SUF):         val.doc
+		$(NROFF) $? >$@
+toolkit.$(SUF):	toolkit.doc
+		$(NROFF) -ms $? >$@
+
+install cmp:
+
+pr:
+		@make "SUF="$SUF "NROFF="$NROFF "PRINT="$PRINT $(RESFILES) \
+			>make.pr.out 2>&1
+		@$(PRINT) $(RESFILES)
+
+opr:
+		make pr | opr
+
+clean:
+		-rm -f *.old $(RESFILES) *.t

+ 419 - 0
doc/ack.doc

@@ -0,0 +1,419 @@
+.nr LL 7.5i
+.tr ~
+.nr PD 1v
+.TL
+Ack Description File
+.br
+Reference Manual
+.AU
+Ed Keizer
+.AI
+Wiskundig Seminarium
+Vrije Universiteit
+Amsterdam
+.NH
+Introduction
+.PP
+The program \fIack\fP(I) internally maintains a table of
+possible transformations and a table of string variables.
+The transformation table contains one entry for each possible
+transformation of a file.
+Which transformations are used depends on the suffix of the
+source file.
+Each transformation table entry tells which input suffixes are
+allowed and what suffix/name the output file has.
+When the output file does not already satisfy the request of the
+user, with the flag \fB-c.suffix\fP, the table is scanned
+starting with the next transformation in the table for another
+transformation that has as input suffix the output suffix of
+the previous transformation.
+A few special transformations are recognized, among them is the
+combiner.
+A program combining several files into one.
+When no stop suffix was specified (flag \fB-c.suffix\fP) \fIack\fP
+stops after executing the combiner with as arguments the -
+possibly transformed - input files and libraries.
+\fIAck\fP will only perform the transformations in the order in
+which they are presented in the table.
+.LP
+The string variables are used while creating the argument list
+and program call name for
+a particular transformation.
+.NH
+Which descriptions are used
+.PP
+\fIAck\fP always uses two description files: one to define the
+front-end transformations and one for the machine dependent
+back-end transformations.
+Each description has a name.
+First the way of determining
+the name of the descriptions needed is described.
+.PP
+When the shell environment variable ACKFE is set \fIack\fP uses
+that to determine the front-end table name, otherwise it uses
+\fBfe\fP.
+.PP
+The way the backend table name is determined is more
+convoluted.
+.br
+First, when the last filename in the program call name is not
+one of \fIack\fP, \fIcc\fP, \fIacc\fP, \fIpc\fP or \fIapc\fP,
+this filename is used as the backend description name.
+Second, when the \fB-m\fP is present the \fB-m\fP is chopped of this
+flag and the rest is used as the backend description name.
+Third, when both failed the shell environment variable ACKM is
+used.
+Last, when also ACKM was not present the default backend is
+used, determined by the definition of ACKM in h/local.h.
+The presence and value of the definition of ACKM is
+determined at compile time of \fIack\fP.
+.PP
+Now, we have the names, but that is only the first step.
+\fIAck\fP stores a few descriptions at compile time.
+This descriptions are simply files read in at compile time.
+At the moment of writing this document, the descriptions
+included are: pdp, fe, i86, m68k2, vax2 and int.
+The name of a description is first searched for internally,
+then in the directory lib/ack and finally in the current
+directory of the user.
+.NH
+Using the description file
+.PP
+Before starting on a narrative of the description file,
+the introduction of a few terms is necessary.
+All these terms are used to describe the scanning of zero
+terminated strings, thereby producing another string or
+sequence of strings.
+.IP Backslashing 5
+.br
+All characters preceded by \e are modified to prevent
+recognition at further scanning.
+This modification is undone before a string is passed to the
+outside world as argument or message.
+When reading the description files the
+sequences \e\e, \e# and \e<newline> have a special meaning.
+\e\e translates to a single \e, \e# translates to a single #
+that is not
+recognized as the start of comment, but can be used in
+recognition and finally, \e<newline> translates to nothing at
+all, thereby allowing continuation lines.
+.nr PD 0
+.IP "Variable replacement"
+.br
+The scan recognizes the sequences {{, {NAME} and {NAME?text}
+Where NAME can be any combination if characters excluding ? and
+} and text may be anything excluding }.
+(~\e} is allowed of course~)
+The first sequence produces an unescaped single {.
+The second produces the contents of the NAME, definitions are
+done by \fIack\fP and in description files.
+When the NAME is not defined an error message is produced on
+the diagnostic output.
+The last sequence produces the contents of NAME if it is
+defined and text otherwise.
+.PP
+.IP "Expression replacement"
+.br
+Syntax:  (\fIsuffix sequence\fP:\fIsuffix sequence\fP=\fItext\fP)
+.br
+Example: (.c.p.e:.e=tail_em)
+.br
+If the two suffix sequences have a common member -~\&.e in this
+case~- the text is produced.
+When no common member is present the empty string is produced.
+Thus the example given is a constant expression.
+Normally, one of the suffix sequences is produced by variable
+replacement.
+\fIAck\fP sets three variables while performing the diverse
+transformations: HEAD, TAIL and RTS.
+All three variables depend on the properties \fIrts\fP and
+\fIneed\fP from the transformations used.
+Whenever a transformation is used for the first time,
+the text following the \fIneed\fP is appended to both the HEAD and
+TAIL variable.
+The value of the variable RTS is determined by the first
+transformation used with a \fIrts\fP property.
+.LP
+Two runtime flags have effect on the value of one or more of
+these variables.
+The flag \fB-.suffix\fP has the same effect on these three variables
+as if a file with that \fBsuffix\fP was included in the argument list
+and had to be translated.
+The flag \fB-r.suffix\fP only has that effect on the TAIL
+variable.
+The program call names \fIacc\fP and \fIcc\fP have the effect
+of an automatic \fB-.c\fB flag.
+\fIApc\fP and \fIpc\fP have the effect of an automatic \fB-.p\fP flag.
+.IP "Line splitting"
+.br
+The string is transformed into a sequence of strings by replacing
+the blank space by string separators (nulls).
+.IP "IO replacement"
+.br
+The > in the string is replaced by the output file name.
+The < in the string is replaced by the input file name.
+When multiple input files are present the string is duplicated
+for each input file name.
+.nr PD 1v
+.LP
+Each description is a sequence of variable definitions followed
+by a sequence of transformation definitions.
+Variable definitions use a line each, transformations
+definitions consist of a sequence of lines.
+Empty lines are discarded, as are lines with nothing but
+comment.
+Comment is started by a # character, and continues to the end
+of the line.
+Three special two-characters sequences exist: \e#, \e\e and
+\e<newline>.
+Their effect is described under 'backslashing' above.
+Each - nonempty - line starts with a keyword, possibly
+preceded by blank space.
+The keyword can be followed by a further specification.
+The two are separated by blank space.
+.PP
+Variable definitions use the keyword \fIvar\fP and look like this:
+.DS X
+   var NAME=text
+.DE
+The name can be any identifier, the text may contain any
+character.
+Blank space before the equal sign is not part of the NAME.
+Blank space after the equal is considered as part of the text.
+The text is scanned for variable replacement before it is
+associated with the variable name.
+.br
+.sp 2
+The start of a transformation definition is indicated by the
+keyword \fIname\fP.
+The last line of such a definition contains the keyword
+\fIend\fP.
+The lines in between associate properties to a transformation
+and may be presented in any order.
+The identifier after the \fIname\fP keyword determines the name
+of the transformation.
+This name is used for debugging and by the \fB-R\fP flag.
+The keywords are used to specify which input suffices are
+recognized by that transformation,
+the program to run, the arguments to be handed to that program
+and the name or suffix of the resulting output file.
+Two keywords are used to indicate which run-time startoffs and
+libraries are needed.
+The possible keywords are:
+.IP \fIfrom\fP
+.br
+followed by a sequence of suffices.
+Each file with one of these suffices is allowed as input file.
+Preprocessor transformations, those with the \fBP\fP property
+after the \fIprop\fP keyword, do not need the \fIfrom\fP
+keyword. All other transformations do.
+.nr PD 0
+.IP \fIto\fP
+.br
+followed by the suffix of the output file name or in the case of a
+linker -~indicated by C option after the \fIprop\fP keyword~-
+the output file name.
+.IP \fIprogram\fP
+.br
+followed by name of the load file of the program, a pathname most likely
+starts with either a / or {EM}.
+This keyword must be
+present, the remainder of the line
+is subject to backslashing and variable replacement.
+.IP \fImapflag\fP
+.br
+The mapflags are used to grab flags given to \fIack\fP and
+pass them on to a specific transformation.
+This feature uses a few simple pattern matching and replacement
+facilities.
+Multiple occurences of this keyword are allowed.
+This text following the keyword is
+subjected to backslashing.
+The keyword is followed by a match expression and a variable
+assignment separated by blank space.
+As soon as both description files are read, \fIack\fP looks
+at all transformations in these files to find a match for the
+flags given to \fIack\fP.
+The flags \fB-m\fP, \fB-o\fP,
+\fI-O\fP, \fB-r\fP, \fB-v\fP, \fB-g\fP, -\fB-c\fP, \fB-t\fP,
+\fB-k\fP, \fB-R\fP and -\f-.\fP are specific to \fIack\fP and
+not handed down to any transformation.
+The matching is performed in the order in which the entries
+appear in the definition.
+The scanning stops after first match is found.
+When a match is found, the variable assignment is executed.
+A * in the match expression matches any sequence of characters,
+a * in the right hand part of the assignment is
+replaced by the characters matched by
+the * in the expression.
+The right hand part is also subject to variable replacement.
+The variable will probably be used in the program arguments.
+The \fB-l\fP flags are special,
+the order in which they are presented to \fIack\fP must be
+preserved.
+The identifier LNAME is used in conjunction with the scanning of
+\fB-l\fP flags.
+The value assigned to LNAME is used to replace the flag.
+The example further on shows the use all this.
+.IP \fIargs\fP
+.br
+The keyword is followed by the program call arguments.
+It is subject to backslashing, variable replacement, expression
+replacement, line splitting and IO replacement.
+The variables assigned to by \fImapflags\P will probably be
+used here.
+The flags not recognized by \fIack\fP or any of the transformations
+are passed to the linker and inserted before all other arguments.
+.IP \fIprop\fB
+.br
+This -~optional~- keyword is followed by a sequence of options,
+each option is indicated by one character
+signifying a special property of the transformation.
+The possible options are:
+.DS X
+   <            the input file will be read from standard input
+   >            the output file will be written on standard output
+   p            the input files must be preprocessed
+   m            the input files must be preprocessed when starting with #
+   O            this transformation is an optimizer and may be skipped
+   P            this transformation is the preprocessor
+   C            this transformation is the linker
+.DE
+.IP \fIrts\fP
+.br
+This -~optional~- keyword indicates that the rest of the line must be
+used to set the variable RTS, if it was not already set.
+Thus the variable RTS is set by the first transformation
+executed which such a property or as a result from \fIack\fP's program
+call name (acc, cc, apc or pc) or by the \fB-.suffix\fP flag.
+.IP \fIneed\fP
+.br
+This -~optional~- keyword indicates that the rest of the line must be
+concatenated to the NEEDS variable.
+This is done once for every transformation used or indicated
+by one of the program call names mentioned above or indicated
+by the \fB-.suffix\fP flag.
+.br
+.nr PD 1v
+.NH
+Conventions used in description files
+.PP
+\fIAck\fP reads two description files.
+A few of the variables defined in the machine specific file
+are used by the descriptions of the front-ends.
+Other variables, set by \fack\fB, are of use to all
+transformations.
+.PP
+\fIAck\fP sets the variable EM to the home directory of the
+Amsterdam Compiler Kit.
+The variable SOURCE is set to the name of the argument that is currently
+being massaged, this is usefull for debugging.
+.br
+The variable M indicates the
+directory in mach/{M}/lib/tail_..... and NAME is the string to
+be defined by the preprocessor with -D{NAME}.
+The definitions of {w}, {s}, {l}, {d}, {f} and {p} indicate
+EM_WSIZE, EM_SSIZE, EM_LSIZE, EM_DSIZE, EM_FSIZE and EM_PSIZE
+respectively.
+.br
+The variable INCLUDES is used as the last argument to \fIcpp\fP,
+it is currently used to add the directory {EM}/include to
+the list of directories containing #include files.
+{EM}/include contains a few files used by the library routines
+for part III from the
+.UX
+manual.
+These routines are included in the kit.
+.PP
+The variables HEAD, TAIL and RTS are set by \fIack\fP and used
+to compose the arguments for the linker.
+.NH
+Example
+.sp 1
+description for front-end
+.DS X
+name cpp                        # the C-preprocessor
+        # no from, it's governed by the P property
+        to .i                   # result files have suffix i
+        program {EM}/lib/cpp    # pathname of loadfile
+        mapflag -I* CPP_F={CPP_F?} -I*          # grab -I.. -U.. and
+        mapflag -U* CPP_F={CPP_F?} -U*          # -D.. to use as arguments
+        mapflag -D* CPP_F={CPP_F?} -D*          # in the variable CPP_F
+        args {CPP_F?} {INCLUDES?} -D{NAME} -DEM_WSIZE={w} -DEM_PSIZE={p} \
+-DEM_SSIZE={s} -DEM_LSIZE={l} -DEM_FSIZE={f} -DEM_DSIZE={d} <
+                                # The arguments are: first the -[IUD]...
+                                #  then the include dir's for this machine
+                                #  then the NAME and size valeus finally
+                                #  followed by the input file name
+        prop >P                 # Output on stdout, is preprocessor
+end
+name cem                        # the C-compiler proper
+        from .c                 # used for files with suffix .c
+        to .k                   # produces compact code files
+        program {EM}/lib/em_cem # pathname of loadfile
+        mapflag -p CEM_F={CEM_F?} -Xp   # pass -p as -Xp to cem
+        mapflag -L CEM_F={CEM_F?} -l    # pass -L as -l to cem
+        args -Vw{w}i{w}p{p}f{f}s{s}l{l}d{d} {CEM_F?}
+                                # the arguments are the object sizes in
+                                # the -V... flag and possibly -l and -Xp
+        prop <>p                # input on stdin, output on stdout, use cpp
+        rts .c                  # use the C run-time system
+        need .c                 # use the C libraries
+end
+name decode                     # make human readable files from compact code
+        from .k.m               # accept files with suffix .k or .m
+        to .e                   # produce .e files
+        program {EM}/lib/em_decode      # pathname of loadfile
+        args <                  # the input file name is the only argument
+        prop >                  # the output comes on stdout
+end
+.DE
+
+.DS X
+Example of a backend, in this case the EM assembler/loader.
+
+var w=2                         # wordsize 2
+var p=2                         # pointersize 2
+var s=2                         # short size 2
+var l=4                         # long size 4
+var f=4                         # float size 4
+var d=8                         # double size 8
+var M=int                       # Unused in this example
+var NAME=int22                  # for cpp (NAME=int results in #define int 1)
+var LIB=mach/int/lib/tail_      # part of file name for libraries
+var RT=mach/int/lib/head_       # part of file name for run-time startoff
+var SIZE_FLAG=-sm               # default internal table size flag
+var INCLUDES=-I{EM}/include     # use {EM}/include for #include files
+name asld                       # Assembler/loader
+        from .k.m.a             # accepts compact code and archives
+        to e.out                # output file name
+        program {EM}/lib/em_ass         # load file pathname
+        mapflag -l* LNAME={EM}/{LIB}*   # e.g. -ly becomes
+                                        #   {EM}/mach/int/lib/tail_y
+        mapflag -+* ASS_F={ASS_F?} -+*  # recognize -+ and --
+        mapflag --* ASS_F={ASS_F?} --*
+        mapflag -s* SIZE_FLAG=-s*       # overwrite old value of SIZE_FLAG
+        args {SIZE_FLAG} \
+                ({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+                (.p:{TAIL}={EM}/{LIB}pc) \
+                (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+                (.c.p:{TAIL}={EM}/{LIB}mon)
+                # -s[sml] must be first argument
+                # the next line contains the choice for head_cc or head_pc
+                # and the specification of in- and output.
+                # the last three args lines choose libraries
+        prop C  # This is the final stage
+end
+.DE
+
+The command "ack -mint -v -v -I../h -L -ly prog.c"
+ would result in the following
+calls (with exec(II)):
+.DS X
+1)  /lib/cpp -I../h -I/usr/em/include -Dint22 -DEM_WSIZE=2 -DEM_PSIZE=2
+      -DEM_SSIZE=2 -DEM_LSIZE=4 -DEM_FSIZE=4 -DEM_DSIZE=8 prog.c
+2)  /usr/em/lib/em_cem -Vw2i2p2f4s2l4d8 -l
+3)  /usr/em/lib/em_ass -sm /usr/em/mach/int/lib/head_cc -o e.out prog.k
+      /usr/em/mach/int/lib/tail_y /usr/em/mach/int/lib/tail_cc.1s
+      /usr/em/mach/int/lib/tail_cc.2g /usr/em/mach/int/lib/tail_mon
+.DE

+ 1832 - 0
doc/cg.doc

@@ -0,0 +1,1832 @@
+.RP
+.TL
+The table driven code generator from 
+.br
+the Amsterdam Compiler Kit
+.AU
+Hans van Staveren
+.AI
+Dept. of Mathematics and Computer Science
+Vrije Universiteit
+Amsterdam, The Netherlands
+.AB
+It is possible to automate the process of compiler building
+to a great extent using collections of tools.
+The Amsterdam Compiler Kit is such a collection of tools.
+This document provides a description of the internal workings
+of the table driven code generator in the Amsterdam Compiler Kit,
+and a description of syntax and semantics of the driving table.
+.AE
+.NH 1
+Introduction
+.PP
+Part of the Amsterdam Compiler Kit is a code generator system consisting
+of a code generator generator (\fIcgg\fP for short) and some machine
+independent C code.
+.I Cgg
+reads a machine description table and creates two files,
+tables.h and tables.c.
+These are then used together with other C code to produce
+a code generator for the machine at hand.
+.PP
+This in turn reads compact EM code and produces
+assembly code.
+The remainder of this document will first broadly describe
+the working of the code generator,
+then a description of the machine table follows after which
+the internal workings of the code generator will be explained.
+.PP
+The reader is assumed to have at least a vague notion about the
+semantics of the intermediary EM code.
+Someone wishing to write a table for a new machine
+should be thoroughly acquainted with EM code
+and the assembly code of the machine at hand.
+.NH 1
+Global overview of the workings of the code generator.
+.PP
+The code generator or
+.I cg
+tries to generate good code by simulating the runtime stack
+of the program compiled and delaying emission of code as long
+as possible.
+It also keeps track of register contents, which enables it to
+eliminate redundant moves, and tries to eliminate redundant tests
+by keeping information about condition code status,
+if applicable for the machine.
+.PP
+.I Cg
+maintains a `fakestack' containing `tokens' that are built
+by executing the pseudo code contained in the code rules given
+by the table writer.
+One can think of the fakestack as a logical extension of the real
+stack the program compiled will have when run.
+During code generation tokens will be kept on the fakestack as long
+as possible but when they are moved to the real stack,
+by generating code for the push,
+all tokens above\u*\d
+.FS
+* in the rest of this document the stack is assumed to grow downwards,
+although the top of the stack will mean the first element that will
+be popped.
+.FE
+the tokens pushed will be pushed also,
+so that the fakestack will not contain holes.
+.PP
+The main loop of
+.I cg
+is this:
+.IP 1)
+find a pattern of EM instructions starting at the current one to
+generate code for.
+This pattern will usually be of length one but longer patterns can be used.
+.IP 2)
+Select one of the possibly many stack patterns that go with this
+EM pattern on the basis of heuristics and/or lookahead.
+.IP 3)
+Force the current fakestack contents to match the pattern.
+This may involve
+copying tokens to registers, making dummy transformations, e.g. to
+transform a "local" into an "register offsetted" or might even
+cause to have the complete fakestack contents put to the real stack
+and then back into registers if no suitable transformations
+were provided by the table writer.
+.IP 4)
+Execute the pseudocode associated with the code rule just selected,
+this may cause registers to be allocated,
+code to be emitted etc..
+.IP 5)
+Put tokens onto the fakestack to reflect the result of the operation.
+.IP 6)
+Insert some EM instructions into the stream,
+this is possible but not common.
+.IP 7)
+Account for the cost.
+The cost is kept in a (space, time) vector and lookahead decisions
+are based on a linear combination of these.
+.PP
+The table that drives
+.I cg
+is not read in every time,
+but instead is used at compiletime
+of
+.I cg
+to set parameters and to load pseudocode tables.
+A program called
+.I cgg
+reads the table and produces large lists of numbers that are
+compiled together with machine independent code to produce
+a code generator for the machine at hand.
+.NH 1
+Description of the machine table
+.PP
+The machine description table consists of the following sections:
+.IP 1)
+Constant definitions
+.IP 2)
+Register definitions
+.IP 3)
+Token definitions
+.IP 4)
+Token expression definitions
+.IP 5)
+Code rules
+.IP 6)
+Move definitions
+.IP 7)
+Test definitions
+.IP 8)
+Stacking definitions
+.PP
+Input is in free format, white space and newlines may be used
+at will to improve legibility.
+Identifiers used in the table have the same syntax as C identifiers,
+upper and lower case considered different, all characters significant.
+There is however one exception:
+identifiers must be more than one character long for parsing reasons.
+C style comments are accepted
+.DS
+	/* this is a comment */
+.DE
+and #define macros may be used if the need arises.
+.NH 2
+Some constants
+.PP
+Before anything else three constants must be defined,
+all with the syntax NAME=value, value being an integer.
+These constants are:
+.IP EM_WSIZE 10
+Number of bytes in a machine word.
+This is the number of bytes
+a simple \fBloc\fP instruction will put on the stack.
+.IP EM_PSIZE
+Number of bytes in a pointer.
+This is the number of bytes
+a \fBlal\fP instruction will put on the stack.
+.IP EM_BSIZE
+Number of bytes in the hole between AB and LB.
+If the calling sequence just saves PC and LB this
+size will be twice the pointersize.
+.PP
+EM_WSIZE and EM_PSIZE are checked when a program is compiled
+with the resulting code generator.
+EM_BSIZE is used by
+.I cg
+to add to the offset of instructions dealing with locals
+having positive offsets,
+i.e. parameters.
+.PP
+Optionally one can give here the factors with which the size and time
+parts of the cost function have to be multiplied to ensure they have the
+same order of magnitude.
+This can be done as
+.DS
+TIMEFACTOR = C\d1\u/C\d2\u
+SIZEFACTOR = C\d3\u/C\d4\u
+.DE
+Above numbers must be read as rational numbers.
+Defaults are 1/1 for both of them.
+These constants set the default size/time tradeoff in the code generator,
+so if TIMEFACTOR and SIZEFACTOR are both 1 the code generator will choose
+at random between two codesequences where one has
+cost (10,4) and the other has cost (8,6).
+See also the description of the cost field below.
+.PP
+Also optional is the definition of a printformat for integers in the codefile.
+This is given as
+.DS
+FORMAT = string
+.DE
+The default for string is "%d" or "%ld" depending on the wordsize of 
+the machine. For example on the PDP 11 one can use
+.DS
+FORMAT= "0%o"
+.DE
+to satisfy the old UNIX assembler that reads octal unless followed by
+a period, and the ACK assembler that follows C conventions.
+.NH 2
+Register definition
+.PP
+The next part of the tables describes the various registers of the
+machine and defines identifiers
+to be used in later parts of the tables.
+Example for the PDP-11:
+.DS L
+REGISTERS:
+R0 = ( "r0",2), REG.
+R1 = ( "r1",2), REG, ODDREG.
+R2 = ( "r2",2), REG.
+R3 = ( "r3",2), REG, ODDREG.
+R4 = ( "r4",2), REG.
+LB = ( "r5",2), LOCALBASE.
+R01= ( "r0",4,R0,R1), REGPAIR.
+R23= ( "r2",4,R2,R3), REGPAIR.
+FR0= ( "r0",4), FREG.
+FR1= ( "r1",4), FREG.
+FR2= ( "r2",4), FREG.
+FR3= ( "r3",4), FREG.
+DR0= ( "r0",8,FR0), DREG.
+DR1= ( "r1",8,FR1), DREG.
+DR2= ( "r2",8,FR2), DREG.
+DR3= ( "r3",8,FR3), DREG.
+.DE
+.PP
+The identifier before the '=' sign is the name of the register
+as used further on in the table.
+The string is the name of the register as far as the assembler is concerned.
+The number is the size of the register in bytes.
+Identifiers following the number but within the parentheses are previously
+defined registernames that are contained in the register being defined.
+The identifiers following the closing parenthesis are properties
+of the register.
+So for example R23 is a register with assembler name r2, 4 bytes long,
+contains the registers R2 and R3 and has the property REGPAIR.
+.PP
+It might seem wise to list each and every property of a register,
+so one might give R0 the extra property MFPTREG named after the not
+too well known MFPT instruction on newer PDP-11 types,
+but this is not a good idea.
+Every extra property means the registerset is more unorthogonal
+and 
+.I cg
+execution time is influenced by that,
+because it has to take into account a larger set of registers
+that are not equivalent.
+.PP
+There is a predefined property SCRATCH that is dynamic,
+i.e. a register can have the property SCRATCH one time,
+and loose it the next.
+A register has the property SCRATCH when it has a reference count of one.
+One needs to be able to discriminate between SCRATCH registers
+and others,
+because it is only allowed to do arithmetic on
+SCRATCH registers.
+.NH 2
+Stack token definition
+.PP
+The next part describes all possible tokens that can reside on
+the fakestack during code generation.
+Attributes of a token are described in the form of a C struct declaration,
+this is followed by the size in bytes of the token,
+optionally followed by the cost of the token when used as an addressing mode
+and the format
+to be used on output.
+.PP
+Tokens should usually be declared for every addressing mode
+of the machine at hand and for every size directly usable in
+a machine instruction.
+Example for the PDP-11 (incomplete):
+.DS L
+TOKENS:
+IREG2 =		{ REGISTER reg; } 2 "*%[reg]" /* indirect register */
+REGCONST =	{ REGISTER reg; STRING off; } 2 /* not really addressable */
+REGOFF2 =	{ REGISTER reg; STRING off; } 2 "%[off](%[reg])"
+IREGOFF2 =	{ REGISTER reg; STRING off; } 2 "*%[off](%[reg])"
+CONST =		{ INT off; } 2 cost=(2,850) "$%[off]."
+EXTERN2 =	{ STRING off; } 2 "%[off]"
+IEXTERN2 =	{ STRING off; } 2 "*%[off]"
+PAIRSIGNED =	{ REGISTER regeven,regodd; } 2 "%[regeven]"
+.DE
+.PP
+Types allowed in the struct are REGISTER, INT and STRING.
+Tokens without a printformat should never be output.
+.PP
+Notice that tokens need not correspond to addressing modes,
+the REGCONST token listed above,
+meaning the sum of the contents of the register and the constant,
+has no corresponding addressing mode on the PDP-11,
+but is included so that a sequence of add constant, load indirect,
+can be handled efficiently.
+This REGCONST token is needed as part of the path
+.DS
+REGISTER -> REGCONST -> REGOFF
+.DE
+of which the first and the last "exist" and the middle is needed
+only as an intermediate step.
+.NH 2
+Token expressions
+.PP
+Usually machines have certain collections of addressing modes that
+can be used with certain instructions.
+The stack patterns in the table are lists of these collections
+and since it is cumbersome to write out these long lists
+every time, there is a section here to give names to these
+collections.
+Please note that it is not forbidden to write out a token expression
+in the remainder of the table,
+but for clarity it is usually better not to.
+Example for the PDP-11 (incomplete):
+.DS L
+TOKENEXPRESSIONS:
+SOURCE2 = REG + IREG2 + REGOFF2 + IREGOFF2 + CONST + EXTERN2 +
+	  IEXTERN2
+SREG    = REG * SCRATCH
+.DE
+Permissible in the expressions are all PASCAL set operators, i.e.
+.IP +
+set union
+.IP -
+set difference
+.IP *
+set intersection
+.PP
+Every tokenidentifier is also a token expression identifier
+denoting the singleton collection of tokens containing
+just itself.
+Every register property as defined above is also a token expression
+matching all registers with that property when on the fakestack.
+The standard token expression identifier ALL denotes the collection of 
+all tokens.
+.NH 2
+Expressions
+.PP
+Throughout the rest of the table expressions can be used in some
+places.
+This section will give the syntax and semantics of expressions.
+There are four types of expressions: integer, string, register and undefined.
+Type checking is performed by
+.I cgg .
+An operator with at least one undefined operand returns undefined except
+for the defined() function mentioned below.
+An undefined expression is interpreted as FALSE when it is needed
+as a truth value.
+Basic terms in an expression are
+.IP number 16
+A number is a constant of type integer.
+.IP "string"
+A string within double quotes is a constant of type string.
+All the normal C style escapes may be used within the string.
+.IP REGIDENT
+The name of a register is a constant of type register.
+.IP $\fIi\fP
+A dollarsign followed by a number is the representation of the argument
+of EM instruction \fI\fP.
+The type of the operand is dependent on the instruction,
+sometimes it is integer,
+sometimes it is string.
+It is undefined when the instruction has no operand.
+.br
+Although an exhaustive list could be given describing all the types
+the following rule of thumb will suffice.
+If you cannot imagine the operand of the instruction ever to be
+something different from a plain integer, the type is integer,
+otherwise it is string.
+.br
+.I Cg
+makes all necessary conversions for you,
+like adding EM_BSIZE to positive arguments of instructions
+dealing with locals,
+prepending underlines to global names,
+converting codelabels into a unique representation etc.
+Details about this can be found in the section about
+machine dependent C code.
+.IP %[1]
+This in general means the token mentioned first in the
+stack pattern.
+When used inside an expression the token must be a simple register.
+Type of this is register.
+.IP %[1.off]
+This means field "off" of the first stack pattern token.
+Type is the same as that of field "off".
+To use this expression implies a check that all tokens
+in the token expression used have the same attributes.
+.IP %[1.1]
+This is the first subregister of the first token.
+Previous comments apply.
+.IP %[b]
+The second allocated register.
+.IP %[a.2]
+The second subregister of the first allocated register.
+.PP
+All normal C operators apply to integers,
+the + operator serves for string concatenation
+and register expressions can only be compared to each other.
+Furthermore there are some special "functions":
+.IP tostring(e) 16
+Converts an integer expression e to a string.
+.IP defined(e)
+Returns 1 if expression e is defined, 0 otherwise.
+.IP samesign(e1,e2)
+Returns 1 if integer expression e1 and e2 have the same sign.
+.IP sfit(e1,e2)
+Returns 1 if integer expression e1 fits as a signed integer
+into a field of e2 bits, 0 otherwise.
+.IP ufit(e1,e2)
+Same as above but now for unsigned e1.
+.IP rom(a,n)
+Integer expression giving the n'th argument from the \fBrom\fP descriptor
+pointed at by the a'th EM instruction.
+Undefined if that descriptor does not exist.
+.IP loww(a)
+Returns the lower half of the argument of the a'th EM instruction.
+This is used to split the arguments of a \fBldc\fP instruction.
+.IP highw(a)
+Same for upper half.
+.NH 2
+Code rules
+.PP
+The largest section of the tables consists of the code generation rules.
+They specify EM patterns, stack patterns, code to be generated etc.
+Syntax is
+.DS L
+code rule : EM pattern '|' stack pattern '|' code '|' 
+	   stack replacement '|' EM replacement '|' cost ;
+.DE
+All parts are optional, however there must be at least one pattern present.
+If the empattern is missing the rule becomes a rewriting rule or
+.I coercion
+to be used when code generation cannot continue 
+because of an invalid stack pattern.
+The code rules are preceded by the word
+.DS
+CODE:
+.DE
+The next paragraphs describe the various parts in detail.
+.NH 3
+The EM pattern
+.PP
+The EM pattern consists of a list of EM mnemonics followed
+by a boolean expression.
+Examples:
+.DS
+\fBloe\fP
+.DE
+will match a single \fBloe\fP instruction,
+.DS
+\fBloc\fP \fBloc\fP \fBcif\fP $1==2 && $2==8
+.DE
+is a pattern that will match
+.DS
+\fBloc\fP 2
+\fBloc\fP 8
+\fBcif\fP
+.DE
+and
+.DS
+\fBlol\fP \fBinc\fP \fBstl\fP $1==$3
+.DE
+will match for example
+.DS
+\fBlol\fP 6
+\fBinc\fP
+\fBstl\fP 6
+.DE
+A missing boolean expression evaluates to TRUE.
+.PP
+When the EM pattern is the same as in the previous code rule the pattern
+should be given as `...'.
+The code generator will match the longest EM pattern on every occasion,
+if two patterns of the same length match the first in the table will be chosen,
+while all patterns of length greater than or equal to three are considered
+to be of the same length.
+.NH 3
+The stack pattern
+.PP
+The stack pattern is a list of token expressions,
+usually token expression identifiers for clarity.
+No boolean expression is allowed here.
+The first expression is the one that matches the top of the stack.
+.PP
+The pattern can be followed by the word STACK
+in which case the pattern only matches if there is nothing
+else on the fakestack.
+The code generator will stack everything not matched at the start
+of the rule.
+.PP
+The pattern can be preceded with the word
+.DS
+nocoercions:
+.DE
+which tells the code generator not to try to coerce to the pattern
+but only to use it when it is already there.
+There are two reasons for this construction,
+correctness and speed.
+It is needed for correctness when the pattern contains a register
+that is not transparent when data is moved through it.
+.PP
+Example: on the PDP-11 the shortest code for
+.DS
+\fBlae\fP a
+\fBloi\fP 8
+\fBlae\fP b
+\fBsti\fP 8
+.DE
+is
+.DS
+movf _a,fr0
+movf fr0,_b
+.DE
+assuming that the floating point processor is in double
+precision mode and fr0 is free.
+Unfortunately this is not correct since a trap can occur on certain
+kinds of data.
+This could happen if there was a pattern for \fBsti\fP\ 8 that allowed
+one to move a floating point register not preceded by nocoercions: .
+The code generator would then find that moving the 8-byte global _a
+to a floating point register and then storing it to _b was the cheapest,
+assuming that the space/time knob was turned far enough to space.
+It is unfortunate that the type information is no longer present,
+since if _a really is a floating point number the move could be
+made without error.
+.PP
+The second reason for the nocoercions: construct is speed.
+When the code generator has a long list of possible stack patterns
+for one EM pattern it can waste a lot of time trying to find coercions
+to all of them, while the mere presence of such a long list
+indicates that the table writer has given a lot of special cases.
+In this case prepending all the special cases by nocoercions:
+will stop the code generator from trying to find things there aren't.
+.NH 3
+The code part
+.PP
+The code part consists of three parts, stack cleanup, register allocation
+and code to generate.
+All of these may be omitted.
+.NH 4
+Stack cleanup
+.PP
+The stack cleanup part describes certain stacktokens that should neither remain on
+the fakestack, nor remembered as contents of registers.
+This is usually only required with store operations.
+The entire fakestack, except for the part matched in the stack pattern,
+is searched for tokens matching the expression and they are copied
+to the real stack.
+Every register that contains the stacktoken is marked as empty.
+.PP
+Syntax is
+.DS
+remove(token expression) \fIor\fP
+remove(token expression, boolean expression)
+.DE
+Example:
+.DS
+remove(REGOFF2,%[reg] != LB || %[off] == $1)
+.DE
+is part of a remove() call for use in the \fBstl\fP code rule.
+It removes all register offsetted tokens where the register is not the
+localbase plus the local wherein the store is done.
+The necessity for this can be seen from the following example:
+.DS
+\fBlol\fP 4
+\fBinl\fP 4
+\fBstl\fP 6
+.DE
+Without a proper remove() call in the rule for \fBinl\fP code would
+be generated as here
+.DS
+inc 4(r5)
+mov 4(r5),6(r5)
+.DE
+so local 6 would be given the new value of local 4 instead of the old
+as the EM code prescribed.
+.PP
+When generating something like a branch instruction it 
+might be needed to empty the fakestack completely.
+This can of course be done with
+.DS
+remove(ALL)
+.DE
+.NH 4
+Register allocation
+.PP
+The register allocation part describes the kind of registers needed.
+Syntax for allocate() is
+.DS
+allocate(itemlist)
+.DE
+where itemlist is a list of three kinds of things:
+.IP 1)
+a tokendescription, for example %[1].
+.br
+This will instruct the code generator to temporarily decrement the reference count 
+of all registers contained in the token,
+so that they are available for allocation in this allocate() call
+if they were only used in that token.
+See example below.
+.IP 2)
+a register property.
+.br
+This will allocate a register with that property.
+The register will be marked as empty at this point.
+Lookahead will be performed if necessary.
+.IP 3)
+a register property with initialization.
+.br
+This will allocate the register as in 2) but will also
+initialize it.
+This eases the task of the code generator because it can
+find a register already filled with the right value
+if it exists.
+.PP
+Examples:
+.DS
+allocate(OREG)
+.DE
+will allocate an odd register, while 
+.DS
+allocate(REG={REGOFF2,LB,$1})
+.DE
+will allocate a register while simultaneously filling it with
+the asked value.
+.br
+Inside the coercion from SOURCE2 to REGISTER in the PDP-11 table
+the following allocate() can be found.
+.DS
+allocate(%[1],REG=%[1])
+.DE
+This tells the code generator that registers contained in %[1] can be used
+again and asks to fill the register allocated with %[1].
+So if %[1]={REGOFF2,R3,"4"} and R3 has a reference count of 1
+the following code might be generated.
+.DS
+mov 4(r3),r3
+.DE
+In the rest of the line the registers allocated can be named by
+%[a] and %[b.1],%[b.2], i.e. with lower case letters
+in order of allocation.
+.PP
+Warning: 
+.DS
+allocate(R3)
+.DE
+is \fRnot\fP the way to allocate R3.
+R3 is not a register property, so it will be seen as a token description
+and the effect is that R3 will have its reference count decremented.
+.NH 4
+Code
+.PP
+Code to be generated is specified as a list of items of the following kind:
+.IP 1)
+a string in double quotes ("This is a string").
+.br
+This is copied to the codefile and a newline ( \en ) is appended.
+Inside the string all normal C string conventions are allowed,
+and substitutions can be made of the following sorts.
+.RS
+.IP a)
+$1, $2 etc.
+These are the operands of the corresponding EM instructions
+and are printed according to their type.
+To put a real '$' inside the string it must be doubled ('$$').
+.IP b)
+%[1], %[2.reg], %[b.1] etc.
+These have their obvious meaning.
+If they describe a complete token ( %[1] )
+the printformat for the token is used.
+If they stand for a basic term in an expression
+they will be printed according to their type.
+To put a real '%' inside the string it must be doubled ('%%').
+.IP c)
+%( arbitrary expression %).
+This allows inclusion of arbitrary expressions inside strings.
+Usually not needed very often,
+so that the awkward notation is not too bad.
+Note that %(%[1]%) is equivalent to %[1].
+.RE
+.IP 2)
+a move() call.
+This has the following syntax:
+.DS
+move(token description, token description)
+.DE
+Moves are handled specially since that enables the code generator
+to keep track of register contents.
+Example:
+.DS
+move(R3,{REGOFF2,LB,$1})
+.DE
+will generate code to move R3 to $1(r5) except when
+R3 already was a copy of $1(r5).
+Then the code will be omitted.
+The rules describing how to move things to each other
+can be found in the MOVES section described below.
+.IP 3)
+an erase() call.
+This has the following syntax:
+.DS
+erase(register expression)
+.DE
+This tells the code generator that the register mentioned no longer has any
+useful value.
+This is 
+.I necessary
+after code in the table has changed the contents of registers.
+For example, after an add to a register the register must be erased,
+because the contents do no longer match any token.
+.IP 4)
+For machines that have condition codes,
+alas most of them do,
+there are provisions to remember condition code setting
+and prevent needless testing.
+To set the condition code to a token put in the code the following call:
+.DS
+test(token)
+.DE
+where token can be all of the standard forms that can also be used in move().
+This will generate a test if the condition codes 
+were not already set to that token.
+It is also possible to tell 
+.I cg
+that a certain operation, like a preceding add
+has set the condition codes to some token with the call
+.DS
+setcc(token)
+.DE
+So a sequence of a setcc and a test on the same token will generate
+no code. 
+Another allowed call within the code is
+.DS
+samecc
+.DE
+which tells the code generator that condition codes were unaffected
+in this rule.
+If no setcc or samecc has been given the default is
+.DS
+nocc
+.DE
+when a piece of code contained strings,
+which tells the code generator that the condition codes
+have no useful value any more.
+.NH 3
+Stack replacement
+.PP
+The stack replacement is a possibly empty list of items to be pushed onto
+the fakestack. Three kinds of items are possible:
+.IP 1)
+An item of the form %[1]. This will push the stacktoken mentioned back
+onto the stack unchanged.
+.IP 2)
+A register expression. This will push the register mentioned
+onto the fakestack.
+.IP 3)
+An item of the form { REGOFF2,%[1.reg],$1 }.
+This generates a token with tokenidentifier REGOFF2 and attributes 
+in order of declaration.
+.PP
+All tokens matched by the stack pattern at the beginning of the code rule
+are first removed and their registers deallocated.
+Items are pushed in the order of appearance.
+This means that the last item will be on the top of the
+stack after the push.
+So if the stack pattern contained two token expressions
+and you want to push them back unchanged,
+you have to specify as stack replacement
+.DS
+%[2] %[1]
+.DE
+and not the other way around.
+.NH 3
+EM replacement
+.PP
+In exceptional cases it might be useful to leave part of an empattern
+undone.
+For example, a \fBsdl\fP instruction might be split into two \fBstl\fP instructions
+when there is no 4-byte quantity on the stack. The emreplacement part allows
+one to express this.
+Example:
+.DS
+\fBstl\fP $1 \fBstl\fP $1+2
+.DE
+The instructions are inserted in the stream so that they can match
+the first part of a pattern in the next step.
+Note that since the code generator traverses the EM instructions in a strict
+linear fashion,
+it is impossible to let the EM replacement match later parts of a pattern.
+So if there is a pattern
+.DS
+\fBloc\fP \fBstl\fP $1==0
+.DE
+and the input is
+.DS
+\fBloc\fP 0 \fBsdl\fP 4
+.DE
+the \fBloc\fP\ 0 will be processed first,
+then the \fBsdl\fP might be split into two \fBstl\fP's but the pattern
+cannot match now.
+.NH 3
+Cost
+.PP
+The cost field can be specified when there is more than one
+code rule with the same empattern.
+If the code generator has a choice between two possibilities
+to generate code it will choose the cheapest according to
+the cost field.
+The cost for a code generation is the sum of the costs
+of all the coercions needed, plus the cost for freeing
+registers plus the cost of the code rule itself.
+.PP
+The format of the costfield is
+.DS
+( nbytes, time )		or
+( nbytes, time ) + %[\fIi\fP]
+.DE
+with time in the metric desired, like nanoseconds or states.
+See constants section above.
+The %[\fIi\fP] in the second example is used for adding the cost of a certain
+address mode used in the code generated.
+This can of course be repeated if desired.
+The cost of the address mode must then be specified in the token definition
+section.
+.NH 3
+Examples
+.PP
+A list of examples for the PDP-11 is given here.
+Far from being complete it gives examples of most kinds
+of instructions.
+.DS L
+\fBadi\fP $1==2 | SREG,SOURCE2 |
+	"add %[2],%[1]" erase(%[1]) setcc(%[1])
+	  | %[1] | | (2,450) + %[2]
+\&...       | SOURCE2,SREG |
+	"add %[1],%[2]" erase(%[2]) setcc(%[2])
+	  | %[2] | | (2,450) + %[1]
+.DE
+is an example of the use of the `...' construct
+and shows how to place erase() and setcc() calls.
+.DS L
+
+\fBdvi\fP $1==2 | SOURCE2,SPAIRSIGNED |
+	"div %[1],%[2]" erase(%[2])
+	  | %[2.regeven] | |
+
+\fBcmi\fP \fBtgt\fP $1==2 | SOURCE2,SOURCE2 | allocate(REG={CONST,0})
+	"cmp %[2],%[1];ble 1f;inc %[a];1:" erase(%[a])
+	  | %[a] | |
+
+\fBcal\fP | STACK |
+	"jsr pc,$1" 
+	  | | |
+
+\fBlol\fP | | | { REGOFF2, LB, $1 } | |
+
+\fBstl\fP | SOURCE2 |
+	remove(REGOFF2,%[off]==$1)
+	move(%[1],{REGOFF2,LB,$1})
+	  | | |
+
+| SOURCE2 |
+	allocate(%[1],REGPAIR)
+	move(%[1],%[a.2])
+	test(%[a.2])
+	"sxt %[a.even]" | { PAIRSIGNED, %[a.1], %[a.2] }| | 
+.DE
+This coercion shows how to use the move and test calls.
+At first you might think that the testcall is unnecessary,
+since the move will have set the condition codes,
+but the move may never have been executed
+if the register already contained the value,
+in which case it is necessary to do the test.
+If the move was executed the test will be omitted.
+.DS L
+| SOURCE2 | allocate(%[1],REG=%[1]) | %[a] | |
+
+\fBsdl\fP | SOURCE2 | | %[1] | \fBstl\fP $1 \fBstl\fP $1+2 |
+
+\fBexg\fP $1==2 | SOURCE2 SOURCE2 | | %[1] %[2] | |
+.DE
+This last example again shows the difference in the order
+of the stack pattern and the stack replacement.
+.NH 2
+Move code rules
+.PP
+When issuing a move() call as described above or a register allocation
+with initialization, the code generator has to know which
+instruction to use for the move.
+The code will of course only be generated if it cannot be omitted.
+This is listed in the move section of the tables by giving a list
+of tuples:
+.DS
+( source, destination, codepart [ , costfield ] )
+.DE
+where the square brackets mean the costfield is optional.
+Example for the PDP-11
+.DS
+MOVES:
+( CONST %[off]==0 , SOURCE2, "clr %[2]" )
+( SOURCE2, SOURCE2, "mov %[1],%[2]" )
+.DE
+The moves are scanned from top to bottom,
+so the first one that matches will be chosen.
+.NH 2
+Test code rules
+.PP
+When issuing a test() call as described above,
+the code generator has to know which instruction
+to use for the test.
+The code will only be generated if the condition codes
+were not already set to the token.
+This is listed in the test section of the tables by giving
+a list of tuples:
+.DS
+( source, codepart [ , costfield ] )
+.DE
+Example for the PDP-11
+.DS
+TESTS:
+( SOURCE2, "tst %[1]")
+( DREG, "tstf %[1]\encfcc")
+.DE
+The tests are scanned from top to bottom,
+so the first one that matches will be chosen.
+.NH 2
+Stacking code rules.
+.PP
+When the code generator has to stack a token it must know
+which code to use.
+Since it must at all times be possible to empty the fakestack
+even when no registers are free,
+it is mandatory that all
+tokens used must have a rule attached for stacking them
+without using a scratch register.
+Since however this might be clumsy and 
+a register might in practice be available
+it is also possible to give rules
+which use a register.
+On the Intel 8086 for example,
+there is no instruction to push a constant without using a register,
+and the code needed to do it without, must use global data
+and as such is very complicated and wasteful of memory and time.
+It can therefore be left to be used in extreme cases,
+while in general the constant is pushed through a register.
+The stacking rules are listed in the stack section of the table as a list
+of tuples:
+.DS
+(source, [ register property ] , codepart [ , costfield ] )
+.DE
+Example for the Intel 8086:
+.DS
+STACKS:
+(CONST, REG, move(%[1],%[a]) "push %[a]")
+(REG ,, "push %[1]")
+.DE
+.NH 1
+The files mach.h and mach.c
+.PP
+The table writer must also supply two files containing
+machine dependent declarations and C code.
+These files are mach.h and mach.c.
+.NH 2
+Types in the code generator
+.PP
+Three different types of integer coexist in the code generator
+and their range depends on the machine at hand.
+The type 'int' is used for things like labelcounters that won't require
+more than 16 bits precision.
+The type 'word' is used among others to assemble datawords and
+is of type 'long' if EM_WSIZE>2.
+The type 'full' is used for addresses and is of type 'long' if
+EM_WSIZE>2 or EM_PSIZE>2.
+.PP
+In macro and function definitions in later paragraphs implicit typing
+will be used for parameters, that is parameters starting with an 's'
+will be of type string, and the letters 'i','w','f' will stand for
+int, word and full respectively.
+.NH 2
+Global variables to work with
+.PP
+Some global variables are present in the code generator
+that can be manipulated by the routines in mach.h and mach.c.
+.LP
+The declarations are:
+.DS L
+.ta 20
+FILE *codefile;	/* code is emitted on this stream */
+word part_word;	/* words to be output are put together here */
+int part_size;	/* number of bytes already put in part_word */
+char str[];	/* Last string read in */
+long argval;	/* Last int read and kept */
+.DE
+.NH 2
+Macros in mach.h
+.PP
+In the file mach.h a collection of macros is defined that have
+to do with formatting of assembly code for the machine at hand.
+Some of these macros can of course be left undefined in which case the
+macro calls are left in the source and will be treated as 
+function calls.
+These functions can then be defined in \fImach.c\fR.
+.PP
+The macros to be defined are:
+.IP ex_ap(s) 16
+Must print the magic incantations that will mark the symbol \fI\fR
+to be exported to other modules.
+This is the translation of the EM \fBexa\fP and \fBexp\fP instructions.
+.IP in_ap(s)
+Same to import the symbol.
+Translation of \fBina\fP and \fBinp\fP.
+.IP newilb(s)
+Must print the definition of instruction label \fIs\fR.
+.IP newdlb(s)
+Must print the definition of data label \fIs\fR.
+.IP dlbdlb(s1,s2)
+Must define data label
+.I s1
+to be equal to
+.I s2 .
+.IP newlbss(s,f)
+Must declare a piece of memory initialized to BSS_INIT(see below)
+of length 
+.I f
+and with label
+.I s .
+.IP cst_fmt
+Format to be used when converting constant arguments of
+EM instructions to string.
+Argument to be formatted will be 'full'.
+.IP off_fmt
+Format to be used for integer part of label+constant,
+argument will be 'full'.
+.IP ilb_fmt
+Format to be used for creation of unique instruction labels.
+Arguments will be a unique procedure number (int) and the label
+number (int).
+.IP dlb_fmt
+Format to be used for printing numeric data labels.
+Argument will be 'int'.
+.IP hol_fmt
+Format to be used for generation of labels for
+space generated by a
+.B hol
+pseudo.
+Argument will be 'int'.
+.IP hol_off
+Format to be used for printing of the address of an element in
+.B hol
+space.
+Arguments will be the offset in the
+.B hol
+block (word) and the number of the
+.B hol
+(int).
+.IP con_cst(w)
+Must generate output that will assemble into one machineword.
+.IP con_ilb(s)
+Must generate output that will put the address of the instruction label
+into the datastream.
+.IP con_dlb(s)
+Must generate output that will put the address of the data label
+into the datastream.
+.IP id_first
+Must be a character.
+This is prepended to all nonnumeric global labels if their length
+is shorter than the maximum allowed(currently 8) or if they already
+start with that character.
+This is to avoid conflicts of user labels with system labels.
+.IP BSS_INIT
+Must be a constant.
+This is the value filled in all the words not initialized explicitly.
+This is loader and system dependent.
+If omitted no initialization is assumed.
+.NH 3
+Example mach.h for the PDP-11
+.DS L
+.ta 8 16 24 32 40 48 56
+#define ex_ap(y)	fprintf(codefile,"\et.globl %s\en",y)
+#define in_ap(y)	/* nothing */
+
+#define newilb(x)	fprintf(codefile,"%s:\en",x)
+#define newdlb(x)	fprintf(codefile,"%s:\en",x)
+#define	dlbdlb(x,y)	fprintf(codefile,"%s=%s\en",x,y)
+#define newlbss(l,x)	fprintf(codefile,"%s:.=.+%d.\en",l,x);
+
+#define cst_fmt		"$%d."
+#define off_fmt		"%d."
+#define ilb_fmt		"I%02x%x"
+#define dlb_fmt		"_%d"
+#define	hol_fmt		"hol%d"
+
+#define hol_off		"%d.+hol%d"
+
+#define con_cst(x)	fprintf(codefile,"%d.\en",x)
+#define con_ilb(x)	fprintf(codefile,"%s\en",x)
+#define con_dlb(x)	fprintf(codefile,"%s\en",x)
+
+#define id_first	'_'
+#define BSS_INIT	0
+.DE
+.NH 2
+Functions in mach.c
+.PP
+In mach.c some functions must be supplied,
+mostly manipulating data resulting from pseudoinstructions.
+The specifications are given here,
+implicit typing of parameters as above.
+.IP con_part(isz,word) 20
+This function must manipulate the globals 
+part_word and part_size to append the isz bytes
+contained in word to the output stream.
+If part_word is full, i.e. part_size==EM_WSIZE
+the function part_flush() may be called to empty the buffer.
+This is the function that must go through the trouble of
+doing byte order in words correct.
+.IP con_mult(w_size)
+This function must take the string str[] and create an integer
+from the string of size w_size and generate code to assemble global
+data for that integer.
+Only the sizes for which arithmetic is implemented need be
+handled,
+so if you didn't implement 200-byte integer division
+you don't have to implement 200-byte integer global data.
+Here one must take care of word order in long integers.
+.IP con_float()
+This function must generate code to assemble a floating
+point number of which the size is contained in argval
+and the ASCII representation in str[].
+.IP prolog(f_nlocals)
+This function is called at the start of every procedure.
+Function prolog code must be generated,
+and room made for local variables for a total of f_nlocals bytes.
+.IP mes(w_mesno)
+This function is called when a
+.B mes
+pseudo is seen that is not handled by the machine independent part.
+Example below shows all you probably have to know about that.
+.IP segname[]
+This is not a function,
+but an array of four strings.
+These strings are put out whenever the code generator
+switches segments.
+Segments are SEGTXT, SEGCON, SEGROM and SEGBSS in that order.
+.NH 3
+Example mach.c for the PDP-11
+.PP
+As an example of the sort of code expected,
+the mach.c for the PDP-11 is presented here.
+.DS L
+.ta 8 16 24 32 40 48 56 64
+/*
+ * machine dependent back end routines for the PDP-11
+ */
+
+con_part(sz,w) register sz; word w; {
+
+	while (part_size % sz)
+		part_size++;
+	if (part_size == EM_WSIZE)
+		part_flush();
+	if (sz == 1) {
+		w &= 0xFF;
+		if (part_size)
+			w <<= 8;
+		part_word |= w;
+	} else {
+		assert(sz == 2);
+		part_word = w;
+	}
+	part_size += sz;
+}
+
+con_mult(sz) word sz; {
+	long l;
+
+	if (sz != 4)
+		fatal("bad icon/ucon size");
+	l = atol(str);
+	fprintf(codefile,"\et%o;%o\en",(int)(l>>16),(int)l);
+}
+
+con_float() {
+	double f;
+	register short *p,i;
+
+	/*
+	 * This code is correct only when the code generator is
+	 * run on a PDP-11 or VAX-11 since it assumes native
+	 * floating point format is PDP-11 format.
+	 */
+
+	if (argval != 4 && argval != 8)
+		fatal("bad fcon size");
+	f = atof(str);
+	p = (short *) &f;
+	i = *p++;
+	if (argval == 8) {
+		fprintf(codefile,"\et%o;%o;",i,*p++);
+		i = *p++;
+	}
+	fprintf(codefile,"\et%o;%o\en",i,*p++);
+}
+
+prolog(nlocals) full nlocals; {
+
+	fprintf(codefile,"mov r5,-(sp)\enmov sp,r5\en");
+	if (nlocals == 0)
+		return;
+	if (nlocals == 2)
+		fprintf(codefile,"tst -(sp)\en");
+	else
+		fprintf(codefile,"sub $%d.,sp\en",nlocals);
+}
+
+mes(type) word type; {
+	int argt ;
+
+	switch ( (int)type ) {
+	case ms_ext :
+		for (;;) {
+			switch ( argt=getarg(
+			    ptyp(sp_cend)|ptyp(sp_pnam)|sym_ptyp) ) {
+			case sp_cend :
+				return ;
+			default:
+				strarg(argt) ;
+				fprintf(codefile,".globl %s\en",argstr) ;
+				break ;
+			}
+		}
+	default :
+		while ( getarg(any_ptyp) != sp_cend ) ;
+		break ;
+	}
+}
+
+char    *segname[] = {
+	".text",        /* SEGTXT */
+	".data",        /* SEGCON */
+	".data",        /* SEGROM */
+	".bss"          /* SEGBSS */
+};
+.DE
+.NH 1
+Coercions
+.PP
+A central part in code generation is taken by the
+.I coercions .
+It is the responsibility of the table writer to provide
+all necessary coercions so that code generation can continue.
+The very minimal set of coercions are
+the coercions to unstack every token expression,
+in combination with the rules to stack every token.
+.PP
+If these are present the code generator can always make the necessary
+transformations by stacking and unstacking.
+Of course for codequality it is usually best to provide extra coercions
+to prevent this stacking to take place.
+.I Cg
+discriminates three types of coercions:
+.IP 1)
+Unstacking coercions.
+This category can use the allocate() call in its code.
+.IP 2)
+Splitting coercions, these are the coercions that split
+larger tokens into smaller ones.
+.IP 3)
+Transforming coercions, these are the coercions that transform
+a token into another one of the same size.
+This category can use the allocate() call in its code.
+.PP
+When a stack configuration does not match the stack pattern
+.I coercions
+are searched for in the following order:
+.IP 1)
+First tokens are split if necessary to get their sizes right.
+.IP 2)
+Then transforming coercions are found that will make the pattern match.
+.IP 3)
+Finally if the stack pattern is longer than the fakestack contents
+unstacking coercions will be used to fill up the pattern.
+.PP
+At any point, when coercions are missing so code generation could not
+continue, the offending tokens are stacked.
+.NH 1
+Internal workings of the code generator.
+.NH 2
+Description of tables.c and tables.h contents
+.PP
+In this section the intermediate files will be described 
+that are produced by
+.I cgg
+and compiled with machine independent code to produce a code generator.
+.NH 3
+Tables.c
+.PP
+Tables.c contains a large number of initialized array's of all sorts.
+Description of each follows:
+.br
+.in 1i
+.ti -0.5i
+byte code rules[]
+.br
+Pseudo code interpreted by the code generator.
+Always starts with some opcode followed by operands depending
+on the opcode.
+Integers in this table are between 0 and 32767 and have a one byte
+encoding if between 0 and 127.
+.ti -0.5i
+char stregclass[]
+.br
+Number of computed static register class per register.
+Two registers are in the same class if they have the same properties
+and don't share a common subregister.
+.ti -0.5i
+struct reginfo machregs[]
+.br
+Info per register.
+Initialized with representation string, size,
+members of the register and set of registers affected when this
+one is changed.
+Also contains room for runtime information,
+like contents and reference count.
+.ti -0.5i
+tkdef_t tokens[]
+.br
+Information per tokentype.
+Initialized with size, cost, type of operands and formatstring.
+.ti -0.5i
+node_t enodes[]
+.br
+List of triples representing expressions for the code generator.
+.ti -0.5i
+string code strings[]
+.br
+List of strings.
+All strings are put in a list and checked for duplication,
+so only one copy per string will reside here.
+.ti -0.5i
+set_t machsets[]
+.br
+List of token expression sets.
+Bit 0 of the set is used for the SCRATCH property of registers,
+bit 1 upto NREG are for the corresponding registers
+and bit NREG+1 upto the end are for corresponding tokens.
+.ti -0.5i
+inst_t tokeninstances[]
+.br
+List of descriptions for building tokens.
+Contains type of rule for building one,
+plus operands depending on the type.
+.ti -0.5i
+move_t moves[]
+.br
+List of move rules.
+Contains token expressions for source and destination
+plus cost and index for code rule.
+.ti -0.5i
+byte pattern[]
+.br
+EM patterns.
+This is structured internally as chains of patterns,
+each chain pointed at by pathash[].
+After each pattern the list of possible code rules is given.
+.ti -0.5i
+int pathash[256]
+.br
+Indices into pattern[] for all patterns with a certain low order
+byte of the hashing function.
+.ti -0.5i
+c1_t c1coercs[]
+.br
+List of rules to stack tokens.
+Contains token expressions,
+register needed,
+cost
+and code rule.
+.ti -0.5i
+c2_t c2coercs[]
+.br
+List of splitting coercions.
+Token expressions,
+split factor,
+replacements
+and code rule.
+.ti -0.5i
+c3_t c3coercs[]
+.br
+List of one to one coercions.
+Token expressions,
+register needed,
+replacement
+and code rule.
+.ti -0.5i
+struct reginfo **reglist[]
+.br
+List of lists of pointers to register information.
+For every property the list is here
+to find the registers corresponding to it.
+.in 0
+.NH 3
+tables.h
+.PP
+In tables.h various derived constants for the tables are
+given.
+They are then used to determine array sizes in the actual code generator,
+plus loop termination in some cases.
+.NH 2
+Other important data structures
+.PP
+During code generation some other data structures are used
+and here is a short description of some of the important ones.
+.PP
+Tokens are kept in the code generator as a struct consisting of
+one integer
+.I t_token
+which is -1 if the token is a register,
+and the number of the token otherwise,
+plus an array of
+.I TOKENSIZE
+unions
+.I t_att
+of which the first is the register number in case of a register.
+.PP
+The fakestack is an array of these tokens,
+there is a global variable
+.I stackheight .
+.PP
+The results of expressions are kept in a struct
+.I result
+with elements
+.I e_typ ,
+giving the type of the expression:
+.I EV_INT ,
+.I EV_REG
+or
+.I EV_STR ,
+and a union
+.I e_v
+which contains the real result.
+.NH 2
+A tour through the sources
+.NH 3
+codegen.c
+.PP
+The file codegen.c contains one large function consisting
+of one giant switch statement.
+It is the interpreter for the code generator pseudo code
+as contained in code rules[].
+This function can call itself recursively when doing lookahead.
+Arguments are:
+.IP codep 10
+Pointer into code rules, pseudo program counter.
+.IP ply
+Number of EM pattern lookahead allowed.
+.IP toplevel
+Boolean telling whether this is the toplevel codegen() or
+a deeper incarnation.
+.IP costlimit
+A cutoff value to limit searches.
+If the cost crosses costlimit the incarnation can terminate.
+.IP forced
+A register number if nonzero.
+This is used inside coercions to force the allocate() call to allocate
+a register determined by earlier lookahead.
+.PP
+The instructions inplemented in the switch:
+.NH 4
+DO_NEXTEM
+.PP
+Matches the next EM pattern and does lookahead if necessary to find the best
+code rule associated with this pattern.
+Heuristics are used to determine best code rule when possible.
+This is done by calling the distance() function.
+.NH 4
+DO_COERC
+.PP
+This sets the code generator in the state to do a from stack coercion.
+.NH 4
+DO_XMATCH
+.PP
+This is done when a match no longer has to be checked.
+Used when the nocoercions: trick is used in the table.
+.NH 4
+DO_MATCH
+.PP
+This is the big one inside this function.
+It has the task to transform the contents of the current
+fakestack to match the pattern given after it.
+.PP
+Since the code generator does not know combining coercions,
+i.e. there is no way to make a big token out of two smaller ones,
+the first thing done is to stack every token that is too small.
+After that all tokens too big are split if possible to the right size.
+.PP
+Next the coercions are sought that would transform tokens in place to
+the right one, plus the coercions that would pop tokens of the stack.
+Each of those might need a register, so a list of registers is generated
+and at the end of looking for coercions the function 
+.I tuples()
+is called to generate the list of all possible \fIn\fP-tuples,
+where 
+.I n
+equals the number of registers needed.
+.PP
+Lookahead is now performed if the number of tuples is greater than one.
+If no possibility is found within the costlimit,
+the fakestack is made smaller by pushing the bottom token,
+and this process is repeated until either a way is found or
+the fakestack is completely empty and there is still no way
+to make the match.
+.PP
+If there is a way the corresponding coercions are executed
+and the code is finished.
+.NH 4
+DO_REMOVE
+.PP
+Here the remove() call is executed, all tokens matched by the 
+token expression plus boolean expression are pushed.
+In the current implementation there is no attempt to move those
+tokens to registers, but that is a possible future extension.
+.NH 4
+DO_DEALLOCATE
+.PP
+This one temporarily decrements by one the reference count of all registers
+contained in the token given as argument.
+.NH 4
+DO_REALLOCATE
+.PP
+Here all temporary deallocates are made undone.
+.NH 4
+DO_ALLOCATE
+.PP
+This is the part that allocates a register and decides which one to use.
+If the
+.I forced
+argument was given its task is simple,
+otherwise some work must be done.
+First the list of possible registers is scanned,
+all free registers noted and it is noted whether any of those
+registers is already
+containing the initialization.
+If no registers are available some fakestack token is stacked and the
+process is repeated.
+.PP
+After that if an exact match was found, 
+the list of registers is reduced to one register matching exactly
+out of every register class.
+Now lookahead is performed if necessary and the register chosen.
+If an initialization was given the corresponding move is performed,
+otherwise the register is marked empty.
+.NH 4
+DO_LOUTPUT
+.PP
+This prints a string and an expression.
+Only done on toplevel.
+.NH 4
+DO_ROUTPUT
+.PP
+Prints a string and a new line.
+Only on toplevel.
+.NH 4
+DO_MOVE
+.PP
+Calls the move() function in the code generator to implement the move()
+function in the table.
+.NH 4
+DO_ERASE
+.PP
+Marks the register that is its argument as empty.
+.NH 4
+DO_TOKREPLACE
+.PP
+This is the token replacement part.
+It is also called if there is no token replacement because it has
+some other functions as well.
+.PP
+First the tokens that will be pushed on the fakestack are computed
+and stored in a temporary array.
+Then the tokens that were matched in this rule are popped
+and their embedded registers have their reference count
+decremented.
+After that the replacement tokens are pushed.
+.PP
+Finally all registers allocated in this rule have their reference count
+decremented.
+If they were not pushed on the fakestack they will be available again
+in the next code rule.
+.NH 4
+DO_EMREPLACE
+.PP
+Places replacement EM instructions back into the instruction stream.
+.NH 4
+DO_COST
+.PP
+Accounts for cost as given in the code rule.
+.NH 4
+DO_RETURN
+.PP
+Returns from this level of codegen().
+Is used at the end of coercions,
+move rules etc..
+.NH 3
+compute.c
+.PP
+This module computes the various expressions as given
+in the enodes[] array.
+Nothing very special happens here,
+it is just a recursive function computing leaves
+of expressions and applying the operator.
+.NH 3
+equiv.c
+.PP
+In this module the tuples() function is implemented.
+It is given the number of registers needed and
+a list of register lists and it constructs a list of tuples
+where the \fIn\fP'th register comes from the \fIn\fP'th list.
+Before the list is constructed however 
+the dynamic register classes are computed.
+Two registers are in the same dynamic class if they are in the
+same static class and their contents is the same.
+.PP
+After that the permute() recursive function is called to
+generate the list of tuples.
+After construction a generated tuple is added to the list
+if it is not already pairwise in the same class
+or if the register relations are not the same,
+i.e. if the first and second register share a common
+subregister in one tuple and not in the other they are considered different.
+.NH 3
+fillem.c
+.PP
+This is the routine that does the reading of EM instructions
+and the handling of pseudos.
+The mach.c module provided by the table writer is included
+at the end of this module.
+The routine fillemlines() is called by nextem() at toplevel
+to make sure there are enough instruction to match.
+It fills the EM instruction buffer up to 5 places from the end to
+keep room for EM replacement instructions,
+or up to a pseudo.
+.PP
+The dopseudo() function performs the function of the pseudo last
+encountered.
+If the pseudo is a 
+.B rom
+the corresponding label is saved with the contents of the
+.B rom
+to be available to the code generator later.
+The rest of the routines are small service routines for either
+input or data output.
+.NH 3
+gencode.c
+.PP
+This module contains routines called by codegen() to generate the real
+code to the codefile.
+The function gencode() gets a string as argument and copies it to codefile
+while processing certain embedded control characters implementing
+the $2 and [1.reg] escapes.
+The function genexpr() prints the expression given as argument.
+It is used to implement the %(\ expr\ %) escape.
+The prtoken() function interprets the tokenformat as given in
+the tokens[] array.
+.NH 3
+glosym.c
+.PP
+This module maintains a list of global symbols that have a 
+.B rom
+pseudo associated.
+There are functions to enter a symbol and to find a symbol.
+.NH 3
+main.c
+.PP
+Main routine of the code generator.
+Processes arguments and flags.
+Flags available are:
+.IP -d
+Sets debug mode if the code generator was not compiled with
+the NDEBUG macro defined.
+Debug mode gives very long output on stderr indicating
+all steps of the code generation process including nesting
+of the codegen() function.
+.IP -p\fIn\fP
+Sets the lookahead depth to
+.I n ,
+the
+.I p
+stands for ply,
+a well known word in chess playing programs.
+.IP -w\fIn\fP
+Sets the weight percentage for size in the cost function to
+.I n
+percent.
+Uses Euclides algorithm to simplify rationals.
+.NH 3
+move.c
+.PP
+Function to implement the move() pseudo function in the tables,
+register initialization and the setcc and test pseudo functions.
+First tests are made to try to prevent the move from really happening.
+The condition code register is treated special here.
+After that, if there is an after that,
+the move rule is found and the code executed.
+.NH 3
+nextem.c
+.PP
+The entry point of this module is nextem().
+It hashes the next three EM instructions,
+and uses the low order byte of the hash
+as an index into the array pathash[],
+to find a chain of patterns in the array
+pattern[],
+that are all tried for a match.
+.PP
+The function trypat() does most of the work
+checking patterns.
+When a pattern is found to match all instructions
+the operands of the instruction are placed into the dollar[] array.
+Then the boolean expression is tried.
+If it matches the function can return,
+leaving the operands still in the dollar[] array,
+so later in the code rule they can still be used.
+.NH 3
+reg.c
+.PP
+Collection of routines to handle registers.
+Reference count routines are here,
+chrefcount() and getrefcount(),
+plus routines to erase a single register or all of them,
+erasereg() and cleanregs().
+.PP
+If NDEBUG hasn't been defined, here is also the routine that checks
+if the reference count kept with the register information is in
+agreement with the number of times it occurs on the fakestack.
+.NH 3
+salloc.c
+.PP
+Module for string allocation and garbage collection.
+Contains entry points myalloc(),
+a routine calling malloc() and checking whether room is left,
+myfree(), just free(),
+popstr() a function called from state.c to free all strings
+made since the last saved status.
+Furthermore there is salloc() which has the size of the string as parameter
+and returns a pointer to the allocated space,
+while keeping a copy of the pointer for garbage allocation purposes.
+.PP
+The function garbage_collect is called from codegen() at toplevel
+every now and then,
+and checks all places where strings may reside to mark strings
+as being in use.
+Strings not in use are returned to the pool of free space.
+.NH 3
+state.c
+.PP
+Set of routines called to save current status,
+restore a previous saved state and to free the room
+occupied by a saved state.
+A list of structs is kept here to save the state.
+If this is not done,
+small allocates will take space
+from the holes big enough for state saves,
+and as a result every new state save will need a new struct.
+The code generator runs out of room very rapidly under these conditions.
+.NH 3
+subr.c
+.PP
+Random set of leftover routines.
+.NH 4
+match
+.PP
+Computes whether a certain token matches a certain token expression.
+Just computes a bitnumber according to the algorithm explained with
+machsets[],
+and tests the bit and the boolean expression if it is there.
+.NH 4
+instance,cinstance
+.PP
+These two functions compute a token from a description.
+They differ very slight, cinstance() is used to compute
+the result of a coercion in a certain context
+and therefore has more arguments, which it uses instead of
+the global information instance() works on.
+.NH 4
+eqtoken
+.PP
+eqtoken computes whether two tokens can be considered identical.
+Used to check register contents during moves mainly.
+.NH 4
+distance
+.PP
+This is the heuristic function that computes a distance from
+the current fakestack contents to the token pattern in the table.
+It likes exact matches most, then matches where at least the sizes are correct
+and if the sizes are not correct it likes too large sizes more than too
+small, since splitting a token is easier than combining one.
+.NH 4
+split
+.PP
+This function tries to find a splitting coercion
+and executes it immediately when found.
+The fakestack is shuffled thoroughly when this happens,
+so pieces below the token that must be split are saved first.
+.NH 4
+docoerc
+.PP
+This function executes a coercion that was found.
+The same shuffling is done, so the top of the stack is again saved.
+.NH 4
+stackupto
+.PP
+This function gets a pointer into the fakestack and must stack
+every token including the one pointed at up to the bottom of the fakestack.
+The first stacking rule possible is used,
+so rules using registers must come first.
+.NH 4
+findcoerc
+.PP
+Looks for a one to one coercion, if found it returns a pointer
+to it and leaves a list of possible registers to use in the global
+variable curreglist.
+This is used by codegen().
+.NH 3
+var.c
+.PP
+Global variables used by more than one module.
+External definitions are in extern.h.

+ 317 - 0
doc/cref.doc

@@ -0,0 +1,317 @@
+.ll 72
+.nr ID 4
+.de hd
+'sp 2
+'tl ''-%-''
+'sp 3
+..
+.de fo
+'bp
+..
+.tr ~
+.               TITLE
+.de TL
+.sp 15
+.ce
+\\fB\\$1\\fR
+..
+.               AUTHOR
+.de AU
+.sp 15
+.ce
+by
+.sp 2
+.ce
+\\$1
+..
+.               DATE
+.de DA
+.sp 3
+.ce
+( Dated \\$1 )
+..
+.               INSTITUTE
+.de VU
+.sp 3
+.ce 4
+Wiskundig Seminarium
+Vrije Universteit
+De Boelelaan 1081
+Amsterdam
+..
+.               PARAGRAPH
+.de PP
+.sp
+.ti +\n(ID
+..
+.nr CH 0 1
+.               CHAPTER
+.de CH
+.nr SH 0 1
+.bp
+.in 0
+\\fB\\n+(CH.~\\$1\\fR
+.PP
+..
+.               SUBCHAPTER
+.de SH
+.sp 3
+.in 0
+\\fB\\n(CH.\\n+(SH.~\\$1\\fR
+.PP
+..
+.               INDENT START
+.de IS
+.sp
+.in +\n(ID
+..
+.               INDENT END
+.de IE
+.in -\n(ID
+.sp
+..
+.de PT
+.ti -\n(ID
+.ta \n(ID
+.fc " @
+"\\$1@"\c
+.fc
+..
+.               DOUBLE INDENT START
+.de DS
+.sp
+.in +\n(ID
+.ll -\n(ID
+..
+.               DOUBLE INDENT END
+.de DE
+.ll +\n(ID
+.in -\n(ID
+.sp
+..
+.               EQUATION START
+.de EQ
+.sp
+.nf
+..
+.               EQUATION END
+.de EN
+.fi
+.sp
+..
+.               ITEM
+.de IT
+.sp
+.in 0
+\\fB~\\$1\\fR
+.ti +5
+..
+.de CS
+.br
+~-~\\
+..
+.br
+.fi
+.TL "Ack-C reference manual"
+.AU "Ed Keizer"
+.DA "September 12, 1983"
+.VU
+.wh 0 hd
+.wh 60 fo
+.CH "Introduction"
+The C frontend included in the Amsterdam Compiler Kit
+translates UNIX-V7 C into compact EM code [1].
+The language accepted is described in [2] and [3].
+This document describes which implementation dependent choices were
+made in the Ack-C frontend and
+some restrictions and additions.
+.CH "The language"
+.PP
+Under the same heading as used in [2] we describe the
+properties of the Ack-C frontend.
+.IT "2.2 Identifiers"
+External identifiers are unique up to 7 characters and allow
+both upper and lower case.
+.IT "2.4.3 Character constants"
+The ASCII-mapping is used when a character is converted to an
+integer.
+.IT "2.4.4 Floating constants"
+To prevent loss of precision the compiler does not perform
+floating point constant folding.
+.IT "2.6 Hardware characteristics"
+The size of objects of the several arithmetic types and the two
+pointer types depend on the EM-implementation used.
+The ranges of the arithmetic types depend on the size used,
+the C-frontend assumes two's complement representation for the
+integral types. All sizes are multiples of bytes.
+The calling program \fIack\fP[4] passes information about the
+size of the types to the compiler proper.
+.br
+However, a few general remarks must be made:
+.sp 1
+.IS
+.PT (a)
+Two different pointer types exist: pointers to data and
+pointers to functions.
+The latter type is twice as large as the former.
+Pointers to functions use the same format as Pascal procedure
+parameters, thereby allowing C to use Pascal procedure
+parameters and vice-versa.
+The extra information passed indicates the scope level of the
+procedure.
+.PT (b)
+The size of pointers to data is a multiple of
+(or equal to) the size of an \fIint\fP.
+.PT (c)
+The following relations exist for the sizes of the types
+mentioned:
+.br
+.ti +5
+\fIchar<=short<=int<=long\fP
+.PT (d)
+Objects of type \fIchar\fP use one 8-bit byte of storage,
+although several bytes are allocated sometimes.
+.PT (e)
+All sizes are in multiples of bytes.
+.PT (f)
+Most EM implementations use 4 bytes for floats and 8 bytes
+for doubles, but exceptions to this rule occur.
+.IE
+.IT "6.1 Characters and integers"
+Objects of type \fIchar\fP are unsigned and do not cause
+sign-extension when converted to \fIint\fP.
+The range of characters values is from 0 to 255.
+.IT "6.3 Floating and integral"
+Floating point numbers are truncated towards zero when
+converted to the integral types.
+.IT "6.4 Pointers and integers"
+When a \fIlong\fP is added to or subtracted from a pointer and
+longs are larger then data pointers the \fIlong\fP is converted to an
+\fIint\fP before the operation is performed.
+.IT "8.5 Structure and union declarations"
+The only type allowed for fields is \fIint\fP.
+Fields with exactly the size of \fIint\fP are signed,
+all other fields are unsigned.
+.br
+The size of any single structure must be less then 4096 bytes.
+.IT "8.6 Initialization"
+Initialization of structures containing bit fields is not
+allowed.
+There is one restriction when using an 'address expression' to initialize
+an integral variable.
+The integral variable must have the size of a data pointer.
+Conversions altering the size of the address expression are not allowed.
+.IT "10.1 External function definitions"
+The total amount for storage used for parameters
+in any function must be less then 4096 bytes.
+The same holds for the total amount of storage occupied by the
+automatic variables declared inside any function.
+.sp
+Using formal parameters whose size is smaller the the size of an int
+is less efficient on several machines.
+At procedure entry these parameters are converted from integer to the
+declared type, because the compiler doesn't know where the least
+significant bytes are stored in the int.
+.IT "11.2 Scope of externals"
+Most C compilers are rather lax in enforcing the restriction
+that only one external definition without the keyword
+\fIextern\fP is allowed in a program.
+The Ack-C frontend is very strict in this.
+The only exception is that declarations of arrays with a
+missing first array bounds expression are regarded to have an
+explicit keyword \fIextern\fP.
+.IT "14.4 Explicit pointer conversions"
+Pointers may be larger the ints, thus assigning a pointer to an
+int and back will not always result in the same pointer.
+The process mentioned above works with integrals
+of the same size or larger as pointers in all EM implementations
+having such integrals.
+Note that pointers to functions have
+twice the size of pointers to data.
+When converting data pointers to an integral type or vice-versa,
+the pointers is seen as an unsigned with the same size a data-pointer.
+When converting function pointers to anything else the static link part
+of the pointer is discarded,
+the resulting value is treated as if it were a data pointer.
+When converting a data pointer or object of integral type to a function pointer
+a static link with the value 0 is added to complete the function pointer.
+.br
+EM guarantees that any object can be placed at a word boundary,
+this allows the C-programs to use \fIint\fP pointers
+as pointers to objects of any type not smaller than an \fIint\fP.
+.CH "Frontend options"
+The C-frontend has a few options, these are controlled
+by flags:
+.IS
+.PT -V
+This flag is followed by a sequence of letters each followed by
+positive integers. Each letter indicates a
+certain type, the integer following it specifies the size of
+objects of that type. One letter indicates the wordsize used.
+.IS
+.sp 1
+.TS
+center tab(:);
+l l16 l l.
+letter:type:letter:type
+
+w:wordsize:i:int
+s:short:l:long
+f:float:d:double
+p:pointer::
+.TE
+.sp 1
+All existing implementations use an integer size equal to the
+wordsize.
+.IE
+The calling program \fIack\fP[4] provides the frontend with
+this flag, with values depending on the machine used.
+.sp 1
+.PT -l
+The frontend normally generates code to keep track of the line
+number and source file name at runtime for debugging purposes.
+Currently a pointer to a
+string containing the filename is stored at a fixed place in
+memory at each function
+entry and the line number at the start of every expression.
+At the return from a function these memory locations are not reset to
+the values they had before the call.
+Most library routines do not use this feature and thus do not
+ruin the current line number and filename when called.
+However, you are really unlucky when your program crashes due
+to a bug in such a library function, because the line number
+and filename do not indicate that something went wrong inside
+the library function.
+.br
+Providing the flag -l to the frontend tells it not to generate
+the code updating line number and file name.
+This is, for example, used when translating the stdio library.
+.br
+When the \fIack\fP[4] is called with the -L flag it provides
+the frontend with this flag.
+.sp 1
+.PT -Xp
+When this flag is present the frontend generates a call to
+the function \fBprocentry\fP at each function entry and a
+call to \fBprocexit\fP at each function exit.
+Both functions are provided with one parameter,
+a pointer to a string containing the function name.
+.br
+When \fIack\fP is called with the -p flag it provides the
+frontend with this flag.
+.IE
+.CH References
+.IS
+.PT [1]
+A.S. Tanenbaum, Hans van Staveren, Ed Keizer and Johan
+Stevenson \fIDescription of a machine architecture for use with
+block structured languages\fP Informatica report IR-81.
+.sp 1
+.PT [2]
+B.W. Kernighan and D.M. Ritchie, \fIThe C Programming
+language\fP, Prentice-Hall, 1978
+.PT [3]
+D.M. Ritchie, \fIC Reference Manual\fP
+.sp
+.PT [4]
+UNIX manual ack(I).

+ 622 - 0
doc/install.doc

@@ -0,0 +1,622 @@
+.nr LL 7.5i
+.nr PD 1v
+.TL
+Amsterdam Compiler Kit installation guide
+.AU
+Ed Keizer
+.AI
+Wiskundig Seminarium
+Vrije Universiteit
+Amsterdam
+.NH
+Introduction
+.PP
+This document
+describes the process of installing Amsterdam Compiler Kit.
+It depends on your combination of hard- and software how
+hard it will be to install the kit.
+This description is intended for a PDP 11/44 running
+.UX
+Version 7.
+Installation on other PDP 11's should be easy, as long
+as they have separate instruction and data space.
+Installation on machine's without this feature, like PDP 11/34,
+PDP 11/60 requires extensive surgery on some programs and is
+thought of as impossible.
+See chapter 6 for installation on other systems.
+.NH
+Restoring tree
+.PP
+The process of installing Amsterdam Compiler Kit is quite simple.
+It is important that the original Amsterdam Compiler Kit
+distribution tree structure is restored.
+Proceed as follows
+.IP "  -" 10
+Create a directory, for example /usr/em, on a device
+with at least 20000 blocks left.
+.IP "  -"
+Change to that directory (cd ...); it will be the working directory.
+.IP "  -"
+Extract all files from the distribution medium, for instance
+magtape:
+\fBtar x\fP.
+.IP "  -"
+Keep a copy of the original distribution to be able to repeat the process
+of installation in case of disasters.
+This copy is also useful as a reference point for diff-listings.
+.LP
+The directories in the tree contain the following information:
+.nr PD 1v
+.IP "lib" 14
+.br
+almost all binaries and shell files used by commands and
+library em_data.a from misc/data
+.IP "lib/ack"
+.br
+The command descriptor files used by the program ack.
+.nr PD 0
+.IP "bin"
+.br
+the few utilities that knot things together
+.IP "etc"
+.br
+The MAIN description of EM sits here.
+contains files (e.g. em_table) describing
+the opcodes and pseudos in use,
+the operands allowed, effect in stack etc. etc.
+Make in this directory creates most of the files in h
+.IP "include"
+.br
+More or less system independent include files needed by modules
+in the C library from lang/cem/libcc.
+Especially needed for "stdio".
+.IP "h"
+.br
+The #include files for:
+.nf
+as_spec.h    Used by EM assembler and interpreters.
+em_abs.h     Contains trap numbers and address for lin and fil
+em_flag.h    Definition of bits in array em_flag in lib/em_data.a
+             Describes parameters effect on flow of instructions
+em_mes.h     Definition of names for mes pseudo numbers
+em_mnem.h    instruction => compact mapping.
+em_pseu.h    pseudo instruction => compact mapping
+em_ptyp.h    Useful for compact code reading/writing,
+             defines classes of parameters
+em_spec.h    Definition of constants used in compact code
+local.h      Various definitions for local versions
+pc_err.h     Definitions of error numbers in Pascal
+pc_file.h    Macro's used in file handling in Pascal
+em_path.h    Pathnames used by \fIack\fP, intended
+             for all utilities
+pc_size.h    Sizes of objects used by Pascal compiler and
+             run-time system.
+em_reg.h     Definition of names for register types.
+.IP "doc"
+.br
+Documentation
+.nf
+cg.doc          Use and internal specification of the backend.
+.br
+regadd.doc      Update for cg.doc concerning register variables
+.br
+regadd.doc      Description of steps to add register variables.
+.br
+ack.doc         Layout of description files needed for each machine.
+.br
+cref.doc        C reference manual, addendum
+.br
+install.doc     Ack Installation Guide
+.br
+pcref.doc       Pascal reference manual, addendum
+.br
+peep.doc        Description of the peephole optimizer
+.br
+em.doc          EM reference manual
+.br
+toolkit.doc     A general overview of the toolkit
+.br
+v7bugs.doc      Bugs in the standard V7 system
+.br
+val.doc         Pascal validation suite version 3 report
+.nf
+.IP "doc/em.doc"
+.br
+The EM-manual IR-81
+.IP "doc/em.doc/int"
+.br
+The EM interpreter written in pascal
+.IP "mkun"
+.br
+The PUBMAC macro package for nroff/troff from the Katholieke Universiteit at
+Nijmegen.
+It is used for the EM reference manual,
+the Makefile installs the macro package in
+/usr/lib/tmac/tmac.mkun*.
+This package is in the public domain.
+.IP "mach"
+.br
+just there to group the directories for all machines
+these directories have sub-directories named:
+.nf
+  as      the assembler ( *.s + libraries => a.out )
+  cg      the new backend   ( *.m => *.s )
+  lib     the libraries for all run-time systems
+          these libraries are used by the assembler.
+  libpc   Used to create Pascal run-time system in 'lib'
+  libcc   Used to create C run-time system in 'lib'
+  libem   Sources for EM runtime system, result sits in 'lib'
+  test    Various tests
+  dl      Down-load programs
+  int     Source for an interpreter
+available are:
+    PMDS II 68000, wordsize 2, ptrsize 4
+        mach/m68k2
+        mach/m68k2/as
+        mach/m68k2/cg
+        mach/m68k2/libem
+        mach/m68k2/lib
+        mach/m68k2/dl
+        mach/m68k2/libpc
+        mach/m68k2/libcc
+        mach/m68k2/libsys
+    bare 6809
+        mach/6809
+        mach/6809/as
+    8080, wordsize 2, ptrsize 2
+        mach/8080
+        mach/8080/as
+        mach/8080/test
+        mach/8080/libcc
+        mach/8080/lib
+   bare 8086, wordsize 2, ptrsize 2
+        mach/i86
+        mach/i86/as
+        mach/i86/lib
+        mach/i86/libcc
+        mach/i86/dl
+        mach/i86/libem
+        mach/i86/libpc
+        mach/i86/saio  (library for stand-alone EM on 86/12A )
+    pdp 11, UNIX/V7, wordsize 2, ptrsize 2
+        mach/pdp
+        mach/pdp/test
+        mach/pdp/libem
+        mach/pdp/lib
+        mach/pdp/libcc
+        mach/pdp/libpc
+        mach/pdp/cg
+        mach/pdp/int         -PDP 11/44 EM interpreter
+    vax 780, UNIX V7, wordsize 4, ptrsize 4
+        mach/vax4
+        mach/vax4/cg
+        mach/vax4/lib
+        mach/vax4/libcc
+        mach/vax4/libem
+        mach/vax4/libpc
+    z80, CP/M, wordsize 2, ptrsize 2
+        mach/z80
+        mach/z80/as
+        mach/z80/libem
+        mach/z80/lib
+        mach/z80/libcc
+        mach/z80/libpc
+        mach/z80/int         -Z80 EM interpreter
+    z80, nascom
+        mach/z80a
+        mach/z80a/dl
+    vax 11/780, Berkeley UNIX, wordsize 2, ptrsize 4
+        mach/vax2
+        mach/vax2/cg
+        mach/vax2/lib
+        mach/vax2/libpc
+        mach/vax2/libem
+    bare 6500, wordsize 2, ptrsize 2
+        mach/6500
+        mach/6500/as
+        mach/6500/dl
+        mach/6500/libem
+        mach/6500/lib
+    bare 6800, wordsize 2, ptrsize 2
+        mach/6800
+        mach/6800/as
+    EM virtual machine code, wordsize 2, ptrsize 2
+        mach/int
+        mach/int/libcc
+        mach/int/libpc
+        mach/int/lib
+        mach/int/test
+    The directory proto contains files used by most machines.
+    e.g. makefiles for libraries for C and Pascal
+        mach/proto
+        mach/proto/libg
+.fi
+.IP "emtest"
+.br
+Contains prototype of em test set.
+.IP "man"
+.br
+Man files for various utilities
+.IP "lang"
+.br
+just there to group the directories for all front-ends
+.IP "lang/pc"
+.br
+Pascal front-end
+.IP "lang/pc/libpc"
+.br
+Source of Pascal run-time system ( in EM or C )
+.IP "lang/pc/test"
+.br
+Some test programs written in Pascal
+.IP "lang/pc/pem"
+.br
+The compiler proper
+.IP "lang/cem"
+.br
+C front-end
+.IP "lang/cem/libcc"
+.br
+Directories with sources of C runtime system, libraries (in EM or C)
+.IP "lang/cem/libcc/gen"
+.br
+Sources for routines in chapter III of UNIX programmers manual,
+excluding STDIO
+.IP "lang/cem/libcc/stdio"
+.br
+STDIO sources
+.IP "lang/cem/libcc/mon"
+.br
+Sources for routines in chapter II, written in EM
+.IP "lang/cem/comp"
+.br
+The compiler proper
+.IP "lang/cem/ctest"
+.br
+C test set
+.IP "lang/cem/ctest/cterr"
+.br
+Programs developed for pinpointing previous errors
+.IP "lang/cem/ctest/ct*"
+.br
+The test programs.
+.IP "util"
+.br
+Contains directories with various utilities
+.IP "util/opt"
+.br
+EM peephole optimizer (*.k => *.m)
+.IP "util/misc"
+.br
+Decode (*.[km] => *.e) + encode (*.e => *.k)
+.IP "util/data"
+.br
+The C-code for `lib/em_data.a`
+These sources are created by the Makefile in `etc`
+.IP "util/ass"
+.br
+The EM assembler ( *.[km] + libraries => e.out )
+.IP "util/arch"
+.br
+The archiver to be used for ALL EM utilities
+.IP "util/cgg"
+.br
+A program needed for compiling backends.
+.IP "util/cpp"
+.br
+The V7 C preprocessor.
+.LP
+All pathnames mentioned in the text of this document are relative to the
+working directory, unless they start with '/'.
+.PP
+The person doing the installation needs permission to write in the
+directories of the Amsterdam Compiler Kit distribution tree.
+Preferably you should log in as sys (uid=3,gid=0).
+.NH
+Pathnames
+.PP
+Absolute pathnames are concentrated in "h/em_path.h".
+Only the pascal runtime system and the utility \fIack\fP use
+absolute pathnames to access files in the kit.
+The tree is distributed with /usr/em as the working
+directory.
+The definition of EM_HOME in em_path.h should be altered to
+specify the root
+directory for the Compiler Kit distribution on your system.
+The trailing " in the definition of EM_HOME is intentionally
+missing!
+Em_path.h also specifies which directory should be used for
+temporary files.
+Most programs from the kit do indeed use that directory
+although some remain stubborn and use /tmp or /usr/tmp.
+.LP
+The shape of the tree should not be altered lightly because
+most Makefiles and the
+utility \fIack\fP know the shape of the ACK tree.
+All pathnames in all Makefiles are relative, that is do not
+have "/" as the first character.
+The knowledge of the utility \fIack\fP about the shape of the tree is
+concentrated in the files in the directory lib/ack.
+.NH
+Commands
+.PP
+The kit is distributed with all available commands in the bin
+directory.
+The commands distributed are:
+.IP "\fIack\fP, \fIacc\fP, \fIapc\fP and their links"
+.br
+They are used to compile the Pascal, C, etc... programs.
+.IP \fIarch\fP
+.br
+The archiver used for the EM- and universal assembler.
+.IP "\fIem\fP and \fIeminform\fP"
+.br
+The EM interpretator for the PDP-11 and the program to unravel
+its post-mortem information.
+.LP
+We currently make the kit available to our users by telling
+them that they should include the bin directory of the kit in
+their PATH shell variable.
+The programs will still work when moved to a different
+directory.
+The copying should preferably be done with tar, since links are
+heavily used.
+Renaming of the programs linked to \fIack\fP will not always
+produce the desired result.
+This program uses its call name as an argument.
+Any call name not being \fIcc\fP, \fIacc\fP, \fIpc\fP or \fIapc\fP will be
+interpreted as the name of a 'machine description' and the
+program will try to find a description file with that name.
+All recompilations will only touch the utilities in the bin
+directory, not your own copies.
+.NH
+Options
+.PP
+There is one important option in h/local.h.
+The utility \fIack\fP uses a default machine name when called
+as \fIacc\fP, \fIcc\fP, \fIapc\fP, \fIpc\fP or \fIack\fP.
+The machine name used for default is determined by the
+definition of ACKM in h/local.h.
+The current definition is \fIpdp\fP.
+.PP
+The distribution is tailored to one specific opreating system per CPU type.
+For some of these  CPU's it is possible to tailor the distribution to another
+operating system.
+The steps to be taken are described in READ_ME (or README) files in the
+subdirectories of the directory in EM_HOME/mach for that particular machine.
+For example: The vax2 distribution is tailoerd to BSD4.1, but has #define's
+for BSD4.1c and BSD4.2.
+For the names and places of these define's look in EM_HOME/mach/vax2/cg and
+EM_HOME/mach/vax2/libem.
+.NH
+Recompilation
+.PP
+The kit comes with binaries in the directories \fBbin\fP and
+\fBlib\fP.
+Some directories among mach/*/lib contain archives with object files,
+notably mach/pdp/lib.
+The binaries and object files are for a PDP 11/44 with floating
+point running UNIX V7.
+.PP
+Almost all directories contain a "Makefile" or a shell command file called
+"make".
+Apart from commands applying to that specific directory these
+files all recognize a few special commands.
+When called with one of these they will apply the command to
+their own directory and all subdirectories.
+The special commands are:
+.IP "install" 20
+recompile and install all binaries and libraries.
+.br
+Some Makefiles allow errors to occur in the programs they call.
+They ignore such errors and notify the user with the message
+"~....... error code n: ignored".
+Whenever such a message appears in the output you can ignore it
+too.
+.br
+The installation of the PUBMAC macro package is not done
+automatically from the higher level directory.
+.IP "cmp"
+recompile all binaries and libraries and compare them to the
+ones already installed.
+.IP pr
+print the sources and documentation on the standard output.
+.IP opr
+make pr | opr
+.br
+Opr should be an off-line printer daemon.
+On some systems it exists under another name e.g. lpr.
+The easiest way to call such a spooler is using a shell script
+with the name opr that calls lpr.
+This script should be placed in /usr/bin or EM_HOME/bin or
+one of the directories in your PATH.
+.IP clean
+remove all files not needed for day-to-day use,
+that is binaries not in bin or lib, object files etc.
+.LP
+Example:
+.nf
+.sp 1
+        make install
+.sp 1
+.fi
+given as command in the home directory will cause
+recompilation of all programs in the kit.
+.LP
+Recompilation of the complete kit lasts about 9 hours an a PDP
+11/44.
+.NH 2
+Recompilation on a different machine.
+.PP
+Installation on other systems will often require recompilation
+of all programs.
+The presence of a C compiler is essential for recompilation.
+Except the Pascal compiler proper all programs are written in C.
+Some modules are derived from \fIyacc\fP sources.
+Retranslating these programs from that yacc source is not
+necessary, although it might improve performance.
+Some versions of \fIyacc\fP 'know' that the resulting C programs will
+run on a 32-bit int machine.
+C modules produced by such a \fIyacc\fP are not portable and
+should not be used to (cross)compile programs for 16-bit machines.
+We assume a version UNIX which, apart from the C-compiler,
+contains most normal utilities, like ed, sed, grep, make, the
+Bourne shell etc.
+All Makefiles use the system C-compiler.
+The existence of a backend for your system is of course essential
+if you wish to produce executable files for that system.
+When the backend exists it is also possible to boot the Pascal
+Compiler,
+that is written in Pascal itself.
+The kit contains the compact code files for the 2/2 and 2/4
+versions of the Pascal compiler.
+The current version of this compiler can only be used on machines
+with a 16-bit word size and 16- or 32-bit pointers.
+The Makefile automatically tries to boot the Pascal compiler
+from one of these compact code files, if the compiler proves
+unable to compile itself.
+.PP
+The native assemblers and loaders are used on PDP-11 and VAX.
+The description files in lib/ack for other systems use our
+universal assembler.
+The load file produced by this assembler is not directly
+usable in any system known to us,
+but has to be converted before it can be put to use.
+The \fIdl\fP programs present for some machines unravel
+these load files and transmit commands to load memory
+to a microprocessor over a serial line.
+The PDP-11 version of our universal assembler is supplied
+with a conversion program.
+The file man/a.out.5 contains a description of the format of
+the universal assembler load file,
+it might be useful to those who wish or need to write their
+own conversion programs.
+.br
+Berkeley UNIX for the VAX'en has (at least) three different
+versions, BSD4.1a, BSD4.1c and BSD4.2. The READ_ME files in the
+directories mach/vax2/cg, mach/vax2/libem, mach/vax4/cg and
+mach/vax4/libem tell you how to adapt the vax2 and vax4 backend
+to these versions.
+.NH 2
+Recompiling libraries
+.PP
+The kit contains sources for part II and III of the C-library, except
+the math functions, they are grabbed from our V7 system and sometimes
+altered in a EM dependent way or replaced altogether when the original
+was in assembly.
+These files can be used to make libraries for the Ack C-compiler.
+The recompilation process uses a few include files.
+The include directory in the EM home directory contains a few more
+or less system independent include files.
+The system dependent include files are fetched from /usr/include
+on the system you use to recompile.
+This may lead to several problems.
+Sometimes the system differs so much from V7 that certain manifest constants
+do not exist any more.
+At other times these include files were written for a compiler without
+a restriction on name length.
+In that case - I've seen it happen - people tend to use differing
+identifiers that are identical in the first eight characters.
+All these problems you have to solve yourself,
+the libraries are only included as an extra and too much system
+dependent to give any guarantees.
+.NH
+Fixes to the UNIX V7 system
+.PP
+UNIX System V7 has a few bugs that prevent a part of or the whole kit
+from working properly.
+To be honest, we do not know which of the following changes are
+essential to the functioning of our kit.
+.PP
+The file "doc/v7bugs.doc" gives for each of the following bugs
+a small test program and a diff listing of the source files that have to be
+modified.
+.IP 1
+Bug in the C optimizer for unsigned comparison
+.nr PD 0
+.IP 2
+The loader 'ld' fails for large data and text portions
+.IP 3
+Floating point registers are not saved if more memory is needed.
+.IP 4
+Floating point registers are not copied to child in fork().
+.nr PD 1v
+.LP
+Use the test programs to see if the errors are present in your system
+and to check if the modifications are effective.
+.NH
+Testing
+.PP
+Test sets are available in Pascal, C and EM assembly.
+.IP em 8
+.br
+The directory emtest contains a few EM test programs.
+The EM assembly files in these tests must be transformed into
+load files, thereby avoiding use of the EM optimizer.
+These tests use the LIN and NOP instructions to mark the passing of each
+test.
+The NOP instruction prints the current line number during the
+test phase.
+Each test notifies its correctness by calling LIN with a unique
+number followed by a NOP which prints this line number.
+The test finishes normally with 0 as the last number printed
+In all other cases a bug showed its
+existence.
+.IP Pascal
+.br
+The directory lang/pc/test contains a few pascal test programs.
+All these programs print the number of errors found and a
+identification of these errors.
+.IP C
+.br
+The sub-directories in lang/cem/ctest contain C test programs.
+The idea behind these tests is:
+when you have a program called xx.c, compile it into xx.cem.
+Run it with standard output to xx.cem.r, compare this file to
+xx.cem.g, a file containing the 'ideal' output.
+Any differences will point to implementation differences or
+bugs.
+Giving the command "run gen" or plain "run" starts this
+process.
+The differences will be presented on standard output.
+The contents of the result files depend on the wordsize,
+the xx.cem.g files on the distribution are intended for a
+16-bit machine.
+.NH
+Documentation
+.PP
+Manual pages for Amsterdam Compiler Kit can be copied
+to "/usr/man/man?" by the
+following commands:
+.DS
+cd man
+make install
+.DE
+.LP
+Several documents are provided:
+.DS
+doc/toolkit.doc: a general overview
+doc/pcref.doc: the Pascal-frontend reference manual
+doc/val.doc: the results of running the Pascal Validation Suite
+doc/cref.doc: the C-frontend manual
+doc/em.doc: a description of the EM machine architecture
+doc/peep.doc: internal documentation for the peephole optimizer
+doc/cg.doc: documentation for backend writers and maintainers
+doc/regadd.doc: addendum to previous document describing register variables
+doc/install.doc: this document
+.DE
+.LP
+The Validation Suite is a collection of more than 200 Pascal programs,
+designed by Brian Wichmann and Arthur Sale to test Pascal compilers.
+We are not allowed to distribute it, but you may
+request a copy from
+.DS
+Richard J. Cichelli
+A.N.P.A.
+1350 Sullivan Trail
+P.O. Box 598
+Easton, Pennsylvania 18042
+USA
+.DE
+.LP
+Good luck.

+ 1511 - 0
doc/pcref.doc

@@ -0,0 +1,1511 @@
+.ds OF \\fBtest~off:~\\fR
+.ds ON \\fBtest~on:~~\\fR
+.ds AL \\fBtest~all:~\\fR
+.ll 72
+.wh 0 hd
+.wh 60 fo
+.de hd
+'sp 5
+..
+.de fo
+'bp
+..
+.tr ~
+.               TITLE
+.de TL
+.sp 15
+.ce
+\\fB\\$1\\fR
+..
+.               AUTHOR
+.de AU
+.sp 15
+.ce
+by
+.sp 2
+.ce
+\\$1
+..
+.               DATE
+.de DA
+.sp 3
+.ce
+( Dated \\$1 )
+..
+.               INSTITUTE
+.de VU
+.sp 3
+.ce 4
+Wiskundig Seminarium
+Vrije Universiteit
+De Boelelaan 1081
+Amsterdam
+..
+.               PARAGRAPH
+.de PP
+.sp
+.ti +5
+..
+.nr CH 0 1
+.               CHAPTER
+.de CH
+.nr SH 0 1
+.bp
+.in 0
+\\fB\\n+(CH.~\\$1\\fR
+.PP
+..
+.               SUBCHAPTER
+.de SH
+.sp 3
+.in 0
+\\fB\\n(CH.\\n+(SH.~\\$1\\fR
+.PP
+..
+.               INDENT START
+.de IS
+.sp
+.in +5
+..
+.               INDENT END
+.de IE
+.in -5
+.sp
+..
+.               DOUBLE INDENT START
+.de DS
+.sp
+.in +5
+.ll -5
+..
+.               DOUBLE INDENT END
+.de DE
+.ll +5
+.in -5
+.sp
+..
+.               EQUATION START
+.de EQ
+.sp
+.nf
+..
+.               EQUATION END
+.de EN
+.fi
+.sp
+..
+.               ITEM
+.de IT
+.sp
+.in 0
+\\fBISO~\\$1:\\fR~\\
+..
+.               IMPLEMENTATION 1
+.de I1
+.IS
+.ti -3
+1.~\\
+..
+.               IMPLEMENTATION 2
+.de I2
+.sp
+.ti -3
+2.~\\
+..
+.de CS
+.br
+~-~\\
+..
+.br
+.fi
+.TL "Amsterdam Compiler Kit-Pascal reference manual"
+.AU "Johan W. Stevenson"
+.DA "January 4, 1983"
+.VU
+.CH "Introduction"
+This document refers to the (March 1980) ISO standard proposal for Pascal [1].
+Ack-Pascal complies with the requirements of this proposal almost completely.
+The standard requires an accompanying document describing the
+implementation-defined and implementation-dependent features,
+the reaction on errors and the extensions to standard Pascal.
+These four items will be treated in the rest of this document,
+each in a separate chapter.
+The other chapters describe the deviations from the standard and
+the list of options recognized by the compiler.
+.PP
+The Ack-Pascal compiler produces code for an EM machine as defined in [2].
+It is up to the implementor of the EM machine to decide whether errors like
+integer overflow, undefined operand and range bound error are recognized or not.
+For these errors the reaction of some known implementations is given.
+.PP
+There does not (yet) exist a hardware EM machine.
+Therefore, EM programs must be interpreted, or translated into
+instructions for a target machine.
+For the following implementations the behavior is documented:
+.I1
+an interpreter running on a PDP-11.
+Normally the interpreter performs some tests to detect undefined
+integers, integer overflow, range errors, etc.
+However, an option of the interpreter is to skip these tests.
+Another option is to perform some extra tests
+to check for instance the number of actual parameter
+words against the number expected by
+the called procedure.
+We will refer to these modes of operation as 'test all', 'test on' and 'test off'.
+.I2
+a translator into PDP-11 instructions.
+.IE
+.CH "Implementation-defined features"
+For each implementation-defined feature mentioned in the ISO standard
+we give the section number, the quotation from that section and the definition.
+First we quote the definition of implementation-defined:
+.DS
+Those parts of the language which may differ between processors, but which
+will be defined for any particular processor.
+.DE
+.IT 6.1.7
+Each string-character shall denote an implementation-defined value of char-type.
+.IS
+All 7-bits ASCII characters except linefeed LF (10) are allowed.
+Note that an apostrophe ' must be doubled within a string.
+.IE
+.IT 6.4.2.2
+The values of type real shall be an implementation-defined subset
+of the real numbers denoted as specified by 6.1.5.
+.IS
+The format of reals is not defined in EM.
+Even the size of reals depends on the implementation.
+The compiler can be instructed, by the f-option, to use a different
+size for real values.
+The size of reals is preset by the calling program \fIack\fP
+[4] to
+the proper size.
+For each implementation of EM the following constants must be defined:
+     epbase: the base for the exponent part
+     epprec: the precision of the fraction
+     epemin: the minimum exponent
+     epemax: the maximum exponent
+.br
+These constants must be chosen so that zero and all numbers with
+exponent e in the range
+.EQ
+     epemin <= e <= epemax
+.EN
+and fraction-parts of the form
+.EQ
+     f = +_ f\d1\u.b\u-1\d + ... + f\depprec\u.b\u-epprec\d
+.EN
+where
+.EQ
+     f\di\u = 0,...,epbase-1 and f\d1\u <> 0
+.EN
+are possible values for reals.
+All other values of type real are considered illegal.
+(See [3] for more information about these constants).
+.br
+For the known EM implementations these constants are:
+.I1
+epbase = 2
+.br
+epprec = 24
+.br
+epemin = -127
+.br
+epemax = +127
+.I2
+ditto
+.IE
+.IT 6.4.2.2
+The type char shall be the enumeration of a set of implementation-defined
+characters, some possibly without graphic representations.
+.IS
+The 7-bits ASCII character set is used, where LF (10) denotes the
+end-of-line marker on text-files.
+.IT 6.4.2.2
+The ordinal numbers of the character values shall be values of integer-type,
+that are implementation-defined, and that are determined by mapping
+the character values on to consecutive non-negative integer values
+starting at zero.
+.IS
+The normal ASCII ordering is used: ord('0')=48, ord('A')=65, ord('a')=97, etc.
+.IE
+.IT 6.4.3.4
+The largest and smallest values of integer-type
+permitted as numbers of a value
+of a set-type shall be implementation-defined.
+.IS
+The smallest value is 0. The largest value is default 15, but can be
+changed by using the i-option of the compiler up to a maximum
+of 32767.
+The compiler allocates as many bits for set-type variables as are necessary
+to store all possible values of the host-type of the base-type of the set,
+rounded up to the nearest multiple of 16.
+If 8 bits are sufficient then only
+8 bits are used if part of a packed structure.
+Thus, the variable s, declared by
+.EQ
+     var s: set of '0'..'9';
+.EN
+will contain 128 bits, not 10 or 16.
+These 128 bits are stored in 16 bytes, both for packed and unpacked sets.
+If the host-type of the base-type is integer, then the
+number of bits depends on the i-option.
+The programmer may specify how many bits to allocate for these sets.
+The default is 16, the maximum is 32767.
+The effective number of bits is rounded up to the next multiple of 16, or up
+to 8 if the number of bits is less than or equal to 8.
+Note that the use of set-constructors for sets with more than 256 elements
+is far less efficient than for smaller sets.
+.IT 6.7.2.2
+The predefined constant maxint shall be of integer-type and shall denote
+an implementation-defined value, that satisfies the following conditions:
+.sp 1
+.in +5
+.ti -4
+(a)~All integral values in the closed interval from -maxint to +maxint
+shall be values in the integer-type.
+.ti -4
+(b)~Any monadic operation performed on an integer value in this interval
+shall be correctly performed according to the mathematical rules for
+integer arithmetic.
+.ti -4
+(c)~Any dyadic integer operation on two integer values in this same interval
+shall be correctly performed according to the mathematical rules for
+integer arithmetic, provided that the result is also in this interval.
+.ti -4
+(d)~Any relational operation on two integer values in this same interval
+shall be correctly performed according to the mathematical rules for
+integer arithmetic.
+.in -5
+.IS
+The representation of integers in EM is a \fIn\fP*8-bit word using
+two's complement arithmetic.
+Where \fIn\fP is called wordsize.
+The compiler can only generate code for EM with wordsize 2.
+Thus always:
+.EQ
+     maxint = 32767
+.EN
+Because the number -32768 may be used to indicate 'undefined', the
+range of available integers depends on the EM implementation:
+.I1
+\*(ON-32767..+32767.
+.br
+\*(OF-32768..+32767.
+.I2
+-32768..+32767.
+.IE
+.IT 6.9.4.2
+The default TotalWidth values for integer, Boolean and real types
+shall be implementation-defined.
+.IS
+The defaults are:
+     integer    6
+     Boolean    5
+     real      13
+.IT 6.9.4.5.1
+ExpDigits, the number of digits written in an exponent part of a real,
+shall be implementation-defined.
+.IS
+ExpDigits is defined as
+.EQ
+     ceil(log10(log10(2 ** epemax)))
+.EN
+For the current implementations this evaluates to 2.
+.IT 6.9.4.5.1
+The character written as part of the representation of
+a real to indicate the beginning of the exponent part shall be
+implementation-defined, either 'E' or 'e'.
+.IS
+The exponent part starts with 'e'.
+.IT 6.9.4.6
+The case of the characters written as representation of the
+Boolean values shall be implementation-defined.
+.IS
+The representations of true and false are 'true' and 'false'.
+.IT 6.9.6
+The effect caused by the standard procedure page
+on a text file shall be implementation-defined.
+.IS
+The ASCII character form feed FF (12) is written.
+.IT 6.10
+The binding of the variables denoted by the program-parameters
+to entities external to the program shall be implementation-defined if
+the variable is of a file-type.
+.IS
+The program parameters must be files and all, except input and output,
+must be declared as such in the program block.
+.PP
+The program parameters input and output, if specified, will correspond
+with the UNIX streams 'standard input' and 'standard output'.
+.PP
+The other program parameters will be mapped to the argument strings
+provided by the caller of this program.
+The argument strings are supposed to be path names of the files to be
+opened or created.
+The order of the program parameters determines the mapping:
+the first parameter is mapped onto the first argument string etc.
+Note that input and output are ignored in this mapping.
+.PP
+The mapping is recalculated each time a program parameter
+is opened for reading or writing by a call to the standard procedures
+reset or rewrite.
+This gives the programmer the opportunity to manipulate the list
+of string arguments using the external procedures argc, argv and argshift
+available in libpc [7].
+.IT 6.10
+The effect of an explicit use of reset or rewrite
+on the standard textfiles input or output shall be implementation-defined.
+.IS
+The procedures reset and rewrite are no-ops
+if applied to input or output.
+.CH "Implementation-dependent features"
+For each implementation-dependent feature mentioned in the ISO standard draft,
+we give the section number, the quotation from that section and the way
+this feature is treated by the Ack-Pascal system.
+First we quote the definition of 'implementation-dependent':
+.DS
+Those parts of the language which may differ between processors,
+and for which there need not be a definition for a particular processor.
+.DE
+.IT 5.1.1
+The method for reporting errors or warnings shall be implementation-dependent.
+.IS
+The error handling is treated in a following chapter.
+.IE
+.IT 6.1.4
+Other implementation-dependent directives may be defined.
+.IS
+Except for the required directive 'forward' the Ack-Pascal compiler recognizes
+only one directive: 'extern'.
+This directive tells the compiler that the procedure block of this
+procedure will not be present in the current program.
+The code for the body of this procedure must be included at a later
+stage of the compilation process.
+.PP
+This feature allows one to build libraries containing often used routines.
+These routines do not have to be included in all the programs using them.
+Maintenance is much simpler if there is only one library module to be
+changed instead of many Pascal programs.
+.PP
+Another advantage is that these library modules may be written in a different
+language, for instance C or the EM assembly language.
+This is useful if you want to use some specific EM instructions not generated
+by the Pascal compiler. Examples are the system call routines and some
+floating point conversion routines.
+Another motive could be the optimization of some time-critical program parts.
+.PP
+The use of external routines, however, is dangerous.
+The compiler normally checks for the correct number and type of parameters
+when a procedure is called and for the result type of functions.
+If an external routine is called these checks are not sufficient,
+because the compiler can not check whether the procedure heading of the
+external routine as given in the Pascal program matches the actual routine
+implementation.
+It should be the loader's task to check this.
+However, the current loaders are not that smart.
+Another solution is to check at run time, at least the number of words
+for parameters. Some EM implementations check this:
+.I1
+\*(ALthe number of words passed as parameters is checked, but this will not catch all faulty cases.
+.br
+\*(ONnot checked.
+.I2
+not checked.
+.IT 6.7.2.1
+The order of evaluation of the operands of a dyadic operator
+shall be implementation-dependent.
+.IS
+Operands are always evaluated, so the program part
+.EQ
+     if (p<>nil) and (p^.value<>0) then
+.EN
+is probably incorrect.
+.PP
+The left-hand operand of a dyadic operator is almost always evaluated
+before the right-hand side.
+Some peculiar evaluations exist for the following cases:
+.IS
+.ti -3
+1.~\
+the modulo operation is performed by a library routine to
+check for negative values of the right operand.
+.IE
+.sp
+.ti -3
+2.~\
+the expression
+.EQ
+     set1 <= set2
+.EN
+where set1 and set2 are compatible set types is evaluated in the
+following steps:
+.IS
+.CS
+evaluate set2
+.CS
+evaluate set1
+.CS
+compute set2+set1
+.CS
+test set2 and set2+set1 for equality
+.IE
+This is the only case where the right-hand side is computed first.
+.sp
+.ti -3
+3.~\
+the expression
+.EQ
+     set1 >= set2
+.EN
+where set1 and set2 are compatible set types is evaluated in the following steps:
+.IS
+.CS
+evaluate set1
+.CS
+evaluate set2
+.CS
+compute set1+set2
+.CS
+test set1 and set1+set2 for equality
+.IE
+.IT 6.7.3
+The order of evaluation, accessing and binding
+of the actual-parameters for functions
+shall be implementation-dependent.
+.IS
+The order of evaluation is from right to left.
+.IT 6.8.2.2
+If access to the variable in an assignment-statement involves the indexing of an array
+and/or a reference to a field within a variant of a record
+and/or the de-referencing of a pointer-variable
+and/or a reference to a buffer-variable,
+the decision whether these actions precede or follow the evaluation
+of the expression shall be implementation-dependent.
+.IS
+The expression is evaluated first.
+.IT 6.8.2.3
+The order of evaluation and binding of the actual-parameters for procedures
+shall be implementation-dependent.
+.IS
+The same as for functions.
+.IT 6.9.6
+The effect of inspecting a text file to which the page
+procedure was applied during generation is
+implementation-dependent.
+.IS
+The formfeed character written by page is
+treated like a normal character, with ordinal value 12.
+.IT 6.10
+The binding of the variables denoted by the program-parameters
+to entities external to the program shall be implementation-dependent unless
+the variable is of a file-type.
+.IS
+Only variables of a file-type are allowed as program parameters.
+.IE
+.CH "Error handling"
+There are three classes of errors to be distinguished.
+In the first class are the error messages generated by the compiler.
+The second class consists of the occasional errors generated by the other
+programs involved in the compilation process.
+Errors of the third class are the errors as defined in the standard by:
+.DS
+An error is a violation by a program of the requirements of this standard
+such that detection normally requires execution of the program.
+.DE
+.SH "Compiler errors"
+The error messages (and the listing) are not generated by the compiler itself.
+The compiler only detects errors and writes the errors in condensed form on
+an intermediate file.
+Each error in condensed form contains:
+.IS
+.CS
+an optional error message parameter (identifier or number).
+.CS
+an error number
+.CS
+a line number
+.CS
+a column number.
+.IE
+Every time the compiler detects an error that does not have influence
+on the code produced by the compiler or on the syntax decisions, a warning
+messages is given.
+If only warnings are generated, compilation proceeds and probably results
+in a correctly compiled program.
+.PP
+The intermediate error file is read by the interface program
+\fIack\fP [4],
+that produces the error messages.
+It uses an other file, the error message file,
+to find an error script line.
+Whenever this error script line contains the character '%', the error messages
+parameter is substituted.
+For negative error numbers the message constructed is prepended with 'Warning: '.
+.PP
+Sometimes the compiler produces several errors for the same file position
+(line number, column number).
+Only the first of these messages is given, because the others are probably
+directly caused by the first one.
+If the first one is a warning while one of its successors for that position
+is a fatal message, then the warning is promoted to a fatal one.
+However, parameterized messages are always given.
+.PP
+The error messages and listing come in three flavors, selected by flags
+given to \fIack\fP [4]:
+.in +10
+.sp
+.ti -8
+default:no listing, one line per error giving the file name
+of the Pascal source file, the line number and the error messages.
+.sp
+.ti -8
+-e:~~~~~for each erroneous line a listing of the line and its predecessor.
+The next line contains one or more characters '^' pointing to the
+places where an error is detected.
+For each error on that line a message follows.
+.sp
+.ti -8
+-E:~~~~~same as for '-e', except that all source lines are listed,
+even if the program is perfect.
+.IE
+.IE
+.SH "Other errors detected at compilation time"
+Two main categories: file system problems and table overflow.
+Problems with the file system may be caused by protection (you may not read
+or create files) or by space problems (no space left on device; out of inodes;
+too many processes).
+Table overflow problems are often caused by peculiar source programs:
+very long procedures or functions, a lot of strings.
+Table overflow problems can sometimes be cured
+by giving a flag (-sl when producing e.out files) to \fIack\fP [4].
+.PP
+Extensive treatment of these errors is outside the scope of this manual.
+.SH "Runtime errors"
+Errors detected at run time cause an error message to be generated on the
+diagnostic output stream (UNIX file descriptor 2).
+The message consists of the name of the program followed by a message
+describing the error, possibly followed by the source line number.
+Unless the l-option is turned off, the compiler generates code to keep track
+of which source line causes which EM instructions to be generated.
+It depends on the EM implementation whether these LIN instructions
+are skipped or executed:
+.I1
+LIN instructions are always executed. The old line number is saved and
+restored whenever a procedure or function is called.
+All error messages contain this line number, except when the l-option
+was turned off.
+.I2
+same as above, but line numbers are not saved when procedures and functions
+are called.
+.IE
+For each error mentioned in the standard we give the section number,
+the quotation from that section and the way it is processed by the
+Pascal-compiler or runtime system.
+.PP
+For detected errors the corresponding message
+and trap number are given.
+Trap numbers are useful for exception-handling routines.
+Normally, each error causes the program to terminate.
+By using exception-handling routines one can
+ignore errors or perform alternate actions.
+Only some of the errors can be ignored
+by restarting the failing instruction.
+These errors are marked as non-fatal,
+all others as fatal.
+A list of errors with trap number between 0 and 63
+(EM errors) can be found in [2].
+Errors with trap number between 64 and 127 (Pascal errors) are listed in [8].
+.IT 6.4.3.3
+It shall be an error if any field-identifier defined within a variant
+is used in a field-designator unless the value of the tag-field
+is associated with that variant.
+.IS
+This error is not detected.
+Sometimes this feature is used to achieve easy type conversion.
+However, using record variants this way is dangerous, error prone and not portable.
+.IT 6.4.6
+It shall be an error if a value of type T2 must be
+assignment-compatible with type T1, while
+T1 and T2 are compatible ordinal-types and the value of
+type T2 is not in the closed interval specified by T1.
+.IS
+The compiler distinguishes between array-index expressions and the other
+places where assignment-compatibility is required.
+.PP
+Array subscripting is done using the EM array instructions.
+These instructions have three arguments: the array base address,
+the index and the address of the array descriptor.
+An array descriptor describes one dimension by three values:
+the element size, the lower bound on the index and the number of elements
+minus one.
+It depends on the EM implementation whether these bounds are checked:
+.I1
+\*(ONchecked (array bound error, trap 0, non-fatal).
+.br
+\*(OFnot checked
+.I2
+not checked.
+.IE
+The other places where assignment-compatibility is required are:
+.IS
+.CS
+assignment
+.CS
+value parameters
+.CS
+procedures read and readln
+.CS
+the final value of the for-statement
+.IE
+For these places the compiler generates an EM range check instruction, except
+when the r-option is turned off, or when the range of values of T2
+is enclosed in the range of T1.
+If the expression consists of a single variable and if that variable
+is of a subrange type,
+then the subrange type itself is taken as T2, not its host-type.
+Therefore, a range instruction is only generated if T1 is a subrange type
+and if the expression is a constant, an expression with two or more
+operands, or a single variable with a type not enclosed in T1.
+If a constant is assigned, then the EM optimizer removes the range check
+instruction, except when the value is out of bounds.
+.PP
+It depends on the EM implementation whether the range check instruction
+is executed or skipped:
+.I1
+\*(ONchecked (range bound error, trap 1, non-fatal).
+.br
+\*(OFskipped
+.I2
+skipped
+.IE
+.IT 6.4.6
+It shall be an error if a value of type T2 must be
+assignment-compatible with type T1, while T1 and T2 are compatible
+set-types and any member of the value of type T2
+is not in the closed interval specified by the base-type
+of the type T1.
+.IS
+This error is not detected.
+.IT 6.5.4
+It shall be an error if
+the pointer-variable has a nil-value or is undefined at the time
+it is de-referenced.
+.IS
+The EM definition does not specify the binary representation of pointer
+values, so that it is not possible to choose an otherwise illegal
+binary representation for the pointer value NIL.
+Rather arbitrary the compiler uses the integer value zero to represent NIL.
+For all current implementations this does not cause problems.
+.PP
+The size of pointers depends on the implementation and is
+preset in the compiler by \fIack\fP [4].
+The compiler can be instructed, by the p-option, to use
+any size for pointer objects.
+NIL is represented here by the appropriate number of zero words.
+.PP
+It depends on the EM implementation whether de-referencing of a pointer
+with value NIL causes an error:
+.I1
+\*(ONfor every de-reference the pointer value is checked to be legal.
+The value NIL is always illegal.
+Objects addressed by a NIL pointer always cause an error, except
+when they are part of some extraordinary sized structure
+(bad pointer, trap 22, fatal).
+.br
+\*(OFde-referencing for fetching will not cause
+an error to occur.
+However, if the pointer value is used for a store operation,
+a segmentation violation probably results (memory fault, trap 21, fatal).
+(Note: this is only true if the interpreter is executed with coinciding
+address spaces and protected text part. The interpreter must therefore
+be loaded with the '-n' option of the UNIX loader [5]).
+.I2
+de-referencing for a fetch operation will not cause an error.
+A store operation probably causes an error if the '-n' flag is
+specified to \fIack\fP [4] or ld [5] while loading your program.
+.IE
+Some implementations of EM initialize all memory cells for newly
+created variables with a constant that probably causes an error if that variable
+is not initialized with a value of its own type before use.
+For each implementation we give whether memory cells are initialized,
+with what value, and whether this value causes an error if de-referenced.
+.I1
+each memory word is initialized with the bit representation 1000000000000000,
+representing -32768 in 2's complement notation.
+For most small and medium sized programs this value will cause a segmentation
+violation (memory fault, trap 21, fatal).
+.I2
+no initialization.
+Whenever a pointer is de-referenced, without being properly initialized,
+a segmentation violation (memory fault, trap 21, fatal)
+or 'bus error' are possible.
+.IE
+.IT 6.5.5
+It shall be an error if the value of a file-variable f is altered
+while the buffer-variable is an actual variable parameter, or
+an element of the record-variable-list of a with-statement, or both.
+.IS
+This error is not detected
+.IT 6.5.5
+It shall be an error if the value of a file-variable f is altered
+by an assignment-statement which contains the buffer-variable f^ in
+its left-hand side.
+.IS
+This error is not detected.
+.IT 6.6.5.2
+It shall be an error if
+the stated pre-assertion does not hold immediately
+prior to any use of the file handling procedures
+rewrite, put, reset and get.
+.IS
+For each of these four operations the pre-assertions
+can be reformulated as:
+.sp
+rewrite(f):~no pre-assertion.
+.br
+put(f):~~~~~f is opened for writing and f^ is not undefined.
+.br
+reset(f):~~~f exists.
+.br
+get(f):~~~~~f is opened for reading and eof(f) is false.
+.sp
+The following errors are detected for these operations:
+.sp
+rewrite(f):
+.in +10
+.ti -5
+more args expected, trap 64, fatal:
+.br
+f is a program-parameter and the corresponding
+file name is not supplied by the caller of the program.
+.ti -5
+rewrite error, trap 101, fatal:
+.br
+the caller of the program lacks the necessary
+access rights to create the file in the file system
+or operating system problems like table overflow
+prevent creation of the file.
+.in -10
+.sp
+put(f):
+.in +10
+.ti -5
+file not yet open, trap 72, fatal:
+.br
+reset or rewrite are never applied to the file.
+The checks performed by the run time system are not foolproof.
+.ti -5
+not writable, trap 96, fatal:
+.br
+f is opened for reading.
+.ti -5
+write error, trap 104, fatal:
+.br
+probably caused by file system problems.
+For instance, the file storage is exhausted.
+Because IO is buffered to improve performance,
+it might happen that this error occurs if the
+file is closed.
+Files are closed whenever they are rewritten or reset, or on
+program termination.
+.in -10
+.sp
+reset(f):
+.in +10
+.ti -5
+more args expected, trap 64, fatal:
+.br
+same as for rewrite(f).
+.ti -5
+reset error, trap 100, fatal:
+.br
+f does not exist, or the caller has insufficient access rights, or
+operating system tables are exhausted.
+.in -10
+.sp
+get(f):
+.in +10
+.ti -5
+file not yet open, trap 72, fatal:
+.br
+as for put(f).
+.ti -5
+not readable, trap 97, fatal:
+.br
+f is opened for writing.
+.ti -5
+end of file, trap 98, fatal:
+.br
+eof(f) is true just before the call to get(f).
+.ti -5
+read error, trap 103, fatal:
+.br
+unlikely to happen. Probably caused by hardware problems
+or by errors elsewhere in your program that destroyed
+the file information maintained by  the run time system.
+.ti -5
+truncated, trap 99, fatal:
+.br
+the file is not properly formed by an integer
+number of file elements.
+For instance, the size of a file of integer is odd.
+.ti -5
+non-ASCII char read, trap 106, non-fatal:
+.br
+the character value of the next character-type
+file element is out of range (0..127).
+Only for text files.
+.in -10
+.IT 6.6.5.3
+It shall be an error to change any variant-part of a variable
+allocated by the form new(p,c1,...,cn) from the variant specified.
+.IS
+This error is not detected.
+.IT 6.6.5.3
+It shall be an error if a variable to be disposed had been allocated
+using the form new(p,c1,...,cn) with more variants specified than
+specified to dispose.
+.IS
+This error can cause more memory to be freed then was allocated.
+Dispose causes a fatal trap 73 when memory already on the free
+list is freed again.
+.IT 6.6.5.3
+It shall be an error if the variants of a variable to be disposed
+are different from those specified by the case-constants to dispose.
+.IS
+This error is not detected.
+.IT 6.6.5.3
+It shall be an error if the value of the pointer parameter of dispose has
+nil-value or is undefined.
+.IS
+The same comments apply as for de-referencing NIL or undefined pointers.
+.IT 6.6.5.3
+It shall be an error if a variable that is identified by the pointer parameter
+of dispose (or a component thereof) is currently either an actual
+variable parameter, or an element of the record-variable-list of a
+with-statement, or both.
+.IS
+This error is not detected.
+.IT 6.6.5.3
+It shall be an error if a referenced-variable created using the second form
+of new is used in its entirety
+as an operand in an expression, or as the variable in an assignment-statement
+or as an actual-parameter.
+.IS
+This error is not detected.
+.IT 6.6.6.2
+It shall be an error if the mathematical defined result of an
+arithmetic function would fall outside the set of values
+of the indicated result.
+.IS
+Except for the errors for undefined arguments,
+the following errors may occur for the arithmetic functions:
+.in +16
+.ti -11
+abs(x):~~~~none.
+.ti -11
+sqr(x):~~~~real underflow, trap 5, non-fatal;
+.br
+real overflow, trap 4, non-fatal
+.ti -11
+sin(x):~~~~real underflow, trap 5, non-fatal
+.ti -11
+cos(x):~~~~real underflow, trap 5, non-fatal
+.ti -11
+exp(x):~~~~error in exp, trap 65, non-fatal (if x>10000);
+.br
+real underflow, trap 5, non-fatal;
+.br
+real overflow, trap 4, non-fatal
+.ti -11
+ln(x):~~~~~error in ln, trap 66, non-fatal ( if x<=0)
+.ti -11
+sqrt(x):~~~error in sqrt, trap 67, non-fatal (if x<0)
+.ti -11
+arctan(x):~real underflow, trap 5, non-fatal;
+.br
+real overflow, trap 4, non-fatal
+.in -16
+.IE
+.IT 6.6.6.2
+It shall be an error if x in ln(x) is not greater than zero.
+.IS
+See above.
+.IT 6.6.6.2
+It shall be an error if x in sqrt(x) is negative.
+.IS
+See above.
+.IT 6.6.6.2
+It shall be an error if
+the integer value of trunc(x) does not exist.
+.IS
+This error is detected (conversion error, trap 10, non-fatal).
+.IT 6.6.6.2
+It shall be an error if
+the integer value of round(x) does not exist.
+.IS
+This error is detected (conversion error, trap 10, non-fatal).
+.IT 6.6.6.2
+It shall be an error if
+the integer value of ord(x) does not exist.
+.IS
+This error can not occur, because the compiler will not allow
+such ordinal types.
+.IT 6.6.6.2
+It shall be an error if
+the character value of chr(x) does not exist.
+.IS
+Except when the r-option is turned off, the compiler generates an EM
+range check instruction. The effect of this instruction depends on the
+EM implementation as described before.
+.IT 6.6.6.2
+It shall be an error if the value of succ(x) does not exist.
+.IS
+Same comments as for chr(x).
+.IT 6.6.6.2
+It shall be an error if the value of pred(x) does not exist.
+.IS
+Same comments as for chr(x).
+.IT 6.6.6.5
+It shall be an error if
+f in eof(f) is undefined.
+.IS
+This error is detected (file not yet open, trap 72, fatal).
+.IT 6.6.6.5
+It shall be an error if
+f in eoln(f) is undefined, or if eof(f) is true at that time.
+.IS
+The following errors may occur:
+.IS
+file not yet open, trap 72, fatal;
+.br
+not readable, trap 97, fatal;
+.br
+end of file, trap 98, fatal.
+.IE
+.IT 6.7.1
+It shall be an error if any variable or function used as an operand in an expression is
+undefined at the time of its use.
+.IS
+Detection of undefined operands is only possible if there is at least one bit
+representation that is not allowed as legal value.
+The set of legal values depends on the type of the operand.
+To detect undefined operands, all newly created variables must be assigned
+a value illegal for the type of the created variable.
+The compiler itself does not generate code to initialize newly created variables.
+Instead, the compiler generates code to allocate some new memory cells.
+It is up to the EM implementation to initialize these memory cells.
+However, the EM machine does not know the types of the variables for which
+memory cells are allocated.
+Therefore, the best an EM implementation can do is to initialize with a value
+that is illegal for the most common types of operands.
+.PP
+For all current EM implementations we will describe whether memory cells
+are initialized, which value is used to initialize, for each operand type
+whether that value is illegal, and for all operations on all operand
+types whether that value is detected as undefined.
+.I1
+\*(ONnew memory words are initialized with -32768.
+Assignment of this value is always allowed. Errors may occur
+whenever undefined operands are used in operations.
+.br
+.ul
+integer:
+-32768 is illegal. All arithmetic operations (except unary +) cause
+an error (undefined integer, trap 8, non-fatal).
+Relational operations do not, except for IN when the left operand is undefined.
+Printing of -32768 using write is allowed.
+.br
+.ul
+real:
+the bit representation of a real, caused by initializing the constituent
+memory words with -32768, is illegal.
+All arithmetic and relational operations (except unary +) cause an error
+(real undefined, trap 9, non-fatal).
+Printing causes the same error.
+.br
+.ul
+char:
+the value -32768 is illegal. For objects of type 'packed array[] of char'
+half the characters will have the value chr(0), which is legal, and the
+others will have the value chr(128), outside the valid ASCII range.
+The relational operators, however, do not cause an error.
+.br
+.ul
+Boolean:
+the value -32768 is illegal. For objects of type 'packed array[] of boolean'
+half the booleans will have the value false, while the others have the value v,
+where ord(v) = 128, naturally illegal.
+However, the Boolean and relational operations do not cause an error.
+.br
+.ul
+set:
+undefined operands of type set can not be distinguished from
+properly initialized ones.
+The set and relational operations, therefore, can never cause an error.
+However, if one forgets to initialize a set of character, then spurious
+characters like '/', '?', 'O', '_' and 'o' appear.
+.sp
+\*(OFnew memory cells are initialized with -32768.
+The only cases where this value causes an error are when
+an undefined operand of type real is used in an arithmetic or relational
+operation (except unary +) or when an undefined real is used as an
+argument to a standard function.
+.I2
+Newly created memory cells are not initialized and therefore
+they have a random value.
+.IT 6.7.1
+It shall be an error if
+the value of any member denoted by any member-designator of the
+set-constructor is outside the implementation-defined limits.
+.IS
+This error is detected (set bound error, trap 2, non-fatal).
+.IT 6.7.1
+It shall be an error if
+the possible types of an set-constructor do not permit it
+to assume a suitable type.
+.IS
+The compiler allocates as many bits as are necessary to store all
+elements of the host-type of the base-type of the set, not the
+base-type itself.
+Therefore, all possible errors can be detected at compile time.
+.IT 6.7.2.2
+It shall be an error if j is zero in 'i div j'.
+.IS
+It depends on the EM implementation whether this error is detected:
+.I1
+\*(ONdetected (divide by 0, trap 6, non-fatal).
+.br
+\*(OFnot detected.
+.I2
+not detected.
+.IE
+.IT 6.7.2.2
+It shall be an error if
+j is zero or negative in i MOD j.
+.IS
+This error is detected (only positive j in 'i mod j', trap 71, non-fatal).
+.IT 6.7.2.2
+It shall be an error if the result of any operation on integer
+operands is not performed according to the mathematical
+rules for integer arithmetic.
+.IS
+The reaction depends on the EM implementation:
+.I1
+\*(ONerror detected if
+.EQ
+     (result >= 32768) or (result < -32768).
+.EN
+(integer overflow, trap 3, non-fatal).
+Note that if the result is -32768 the use of this value in further operations
+may cause an error.
+.br
+\*(OFnot detected.
+.I2
+not detected.
+.IT 6.8.3.5
+It shall be an error if none of the case-constants is equal to the value of the
+case-index upon entry to the case-statement.
+.IS
+This error is detected (case error, trap 20, fatal).
+.IT 6.8.3.9
+It shall be an error if the final-value of a for-statement is not
+assignment-compatible with the control-variable when the
+initial-value is assigned to the control-variable.
+.IS
+It is detected if the control variable leaves
+its allowed range of values while stepping
+from initial to final value.
+This is equivalent with the requirements if the
+for-statement is not terminated before
+the final value is reached.
+.IT 6.9.2
+It shall be an error if the sequence of characters read looking for an integer does not
+form a signed-integer as specified in 6.1.5.
+.IS
+This error is detected (digit expected, trap 105, non-fatal).
+.IT 6.9.2
+It shall be an error if the sequence of characters read looking for a real does not
+form a signed-number as specified in 6.1.5.
+.IS
+This error is detected (digit expected, trap 105, non-fatal).
+.IT 6.9.2
+It shall be an error if read is applied to f while f is undefined or
+not opened for reading.
+.IS
+This error is detected (see get(f)).
+.IT 6.9.4
+It shall be an error if write is applied to f while f is undefined or
+not opened for writing.
+.IS
+This error is detected (see put(f)).
+.IT 6.9.4
+It shall be an error if TotalWidth or FracDigits as specified in
+write or writeln procedure calls are less than one.
+.IS
+This error is not detected. Moreover, it is considered an extension to
+allow zero or negative values.
+.IT 6.9.6
+It shall be an error if page is applied to f while f is undefined or
+not opened for writing.
+.IS
+This error is detected (see put(f)).
+.CH "Extensions to the standard"
+.IS
+.ti -3
+1.~\
+Separate compilation.
+.sp
+The compiler is able to (separately) compile a collection of declarations,
+procedures and functions to form a library.
+The library may be linked with the main program, compiled later.
+The syntax of these modules is
+.EQ
+     module = [constant-definition-part]
+              [type-definition-part]
+              [var-declaration-part]
+              [procedure-and-function-declaration-part]
+.EN
+The compiler accepts a program or a module:
+.EQ
+     unit = program | module
+.EN
+All variables declared outside a module must be imported
+by parameters, even the files input and output.
+Access to a variable declared in a module is only possible
+using the procedures and functions declared in that same module.
+By giving the correct procedure/function heading followed by the
+directive 'extern' you may use procedures and functions declared in
+other units.
+.sp
+.ti -3
+2.~\
+Assertions.
+.sp
+The Ack-Pascal compiler recognizes an additional statement, the assertion.
+Assertions can be used as an aid in debugging and documentation.
+The syntax is:
+.EQ
+     assertion = 'assert' Boolean-expression
+.EN
+An assertion is a simple-statement, so
+.EQ
+     simple-statement = [assignment-statement |
+                         procedure-statement |
+                         goto-statement |
+                         assertion
+                        ]
+.EN
+An assertion causes an error if the Boolean-expression is false.
+That is its only purpose.
+It does not change any of the variables, at least it should not.
+Therefore, do not use functions with side-effects in the Boolean-expression.
+If the a-option is turned off, then assertions are skipped by the
+compiler. 'assert' is not a word-symbol (keyword) and may be used as identifier.
+However, assignment to a variable and calling of a procedure with that name will be impossible.
+.sp
+.ti -3
+3.~\
+Additional procedures.
+.sp
+Three additional standard procedures are available:
+.IS
+.IS
+.ti -8
+halt:~~~a call of this procedure is equivalent to jumping to the
+end of your program. It is always the last statement executed.
+The exit status of the program may be supplied
+as optional argument.
+.ti -8
+release:
+.ti -8
+mark:~~~for most applications it is sufficient to use the heap as second stack.
+Mark and release are suited for this type of use, more suited than dispose.
+mark(p), with p of type pointer, stores the current value of the
+heap pointer in p. release(p), with p initialized by a call
+of mark(p), restores the heap pointer to its old value.
+All the heap objects, created by calls of new between the call of
+mark and the call of release, are removed and the space they used
+can be reallocated.
+Never use mark and release together with dispose!
+.sp
+.in -10
+.ti -3
+4.~\
+UNIX interfacing.
+.sp
+If the c-option is turned on, then some special features are available
+to simplify an interface with the UNIX environment.
+First of all, the compiler allows you to use a different type
+of string constants.
+These string constants are delimited by double quotes ('"').
+To put a double quote into these strings, you must repeat the double quote,
+like the single quote in normal string constants.
+These special string constants are terminated by a zero byte (chr(0)).
+The type of these constants is a pointer to a packed array of characters,
+with lower bound 1 and unknown upper bound.
+.br
+Secondly, the compiler predefines a new type identifier 'string' denoting
+this just described string type.
+.PP
+The only thing you can do with these features is declaration of
+constants and variables of type 'string'.
+String objects may not be allocated on the heap and string pointers
+may not be de-referenced.
+Still these strings are very useful in combination with external routines.
+The procedure write is extended to print these zero-terminated strings correctly.
+.sp
+.ti -3
+5.~\
+Double length (32 bit) integers.
+.sp
+If the d-option is turned on, then the additional type 'long' is known to the compiler.
+Long variables have integer values in the range -2147483647..+2147483647.
+Long constants may be declared.
+It is not allowed to form subranges of type long.
+All operations allowed on integers are also
+allowed on longs and are indicated by the same
+operators: '+', '-', '*', '/', 'div', 'mod'.
+The procedures read and write have been extended to handle long arguments correctly.
+The default width for longs is 11.
+The standard procedures 'abs' and 'sqr' have been extended to work on long arguments.
+Conversion from integer to long, long to real,
+real to long and long to integer are automatic, like the conversion from integer to real.
+These conversions may cause a
+.IS
+conversion error, trap 10, non-fatal
+.IE
+This last error is only detected in implementation 1, with 'test on'.
+Note that all current implementations use target
+machine floating point instructions
+to perform some of the long operations.
+.sp
+.ti -3
+6.~\
+Underscore as letter.
+.sp
+The character '_' may be used in forming identifiers, if the u-option is turned on.
+.sp
+.ti -3
+7.~\
+Zero field width in write.
+.sp
+Zero or negative TotalWidth arguments to write
+are allowed.
+No characters are written for character, string or Boolean type arguments then.
+A zero or negative FracDigits argument for fixed-point representation of reals causes the
+fraction and the character '.' to be suppressed.
+.sp
+.ti -3
+8.~\
+Alternate symbol representation.
+.sp
+The comment delimiters '(*' and '*)' are recognized and treated like '{' and '}'.
+The other alternate representations of symbols are not recognized.
+.CH "Deviations from the standard"
+Ack-Pascal deviates from the (March 1980) standard proposal in the following ways:
+.IS
+.ti -3
+1.~\
+Only the first 8 characters of identifiers are significant,
+as requested by all standard proposals prior to March 1980.
+In that proposal, however, the sentence
+.DS
+"A conforming program should not have its meaning altered
+by the truncation of its identifiers to eight characters
+or the truncation of its labels to four digits."
+.DE
+is missing.
+.sp
+.ti -3
+2.~\
+The character sequences 'procedur', 'procedur8', 'functionXyZ' etc. are
+all erroneously classified as the word-symbols 'procedure' and 'function'.
+.sp
+.ti -3
+3.~\
+Standard procedures and functions are not allowed as parameters in Ack-Pascal,
+conforming to all previous standard proposals.
+You can obtain the same result with negligible loss of performance
+by declaring some user routines like:
+.EQ
+     function sine(x:real):real;
+     begin
+         sine:=sin(x)
+     end;
+.EN
+.sp
+.ti -3
+4.~\
+The scope of identifiers and labels should start at the beginning of the block
+in which these identifiers or labels are declared.
+The Ack-Pascal compiler, as most other one pass compilers, deviates in this respect,
+because the scope of variables and labels start
+at their defining-point.
+.CH "Compiler options"
+Some options of the compiler may be controlled by using "{$....}".
+Each option consists of a lower case letter followed by +, - or an unsigned
+number.
+Options are separated by commas.
+The following options exist:
+.in 8
+.sp
+.ti -8
+a~+/-~~~\
+this option switches assertions on and off.
+If this option is on, then code is included to test these assertions
+at run time. Default +.
+.sp
+.ti -8
+c~+/-~~~\
+this option, if on, allows you to use C-type string constants
+surrounded by double quotes.
+Moreover, a new type identifier 'string' is predefined.
+Default -.
+.sp
+.ti -8
+d~+/-~~~\
+this option, if on, allows you to use variables of type 'long'.
+Default -.
+.sp
+.ti -8
+f~<num>~\
+the size of reals can be changed by this option. <num> should be specified in 8-bit bytes.
+The default in most implementations is 8, but other values can
+occur.
+.sp
+.ti -8
+i~<num>~\
+with this flag the setsize for a set of integers can be
+manipulated.
+The number must be the number of bits per set.
+The default value is 16, just fitting in one word on the PDP and many other minis.
+.sp
+.ti -8
+l~+/-~~~\
+if + then code is inserted to keep track of the source line number.
+When this flag is switched on and off, an incorrect line number may appear
+if the error occurs in a part of your program for which this flag is off.
+These same line numbers are used for the profile, flow and count options
+of the EM interpreter em [6].
+Default +.
+.sp
+.ti -8
+p~<num>~the size of pointers can be changed by this option. <num> should be specified in bytes.
+Default 2 in most implementations.
+.sp
+.ti -8
+r~+/-~~~\
+if + then code is inserted to check subrange variables against
+lower and upper subrange limits.
+Default +.
+.sp
+.ti -8
+s~+/-~~~\
+if + then the compiler will hunt for places in your program
+where non-standard features are used, and for each place found
+it will generate a warning. Default -.
+.sp
+.ti -8
+t~+/-~~~\
+if + then each time a procedure is entered, the routine 'procentry'
+is called.
+The compiler checks this flag just before the first symbol that follows the
+first 'begin' of the body of the procedure.
+Also, when the procedure exits, then the procedure 'procexit' is called
+if the t flag is on just before the last 'end' of the procedure body.
+Both 'procentry' and 'procexit' have a packed array of 8 characters as a parameter.
+Default procedures are present in the run time library.
+Default -.
+.sp
+.ti -8
+u~+/-~~~\
+if + then the character '_' is treated like a lower case letter,
+so that it may be used in identifiers.
+Procedure and function identifiers starting with an underscore may cause problems,
+because they may collide with library routine names.
+Default -.
+.in 0
+.sp
+Seven of these flags (c, d, f, i, p, s and u) are only effective when they appear
+before the 'program' symbol. The others may be switched on and off.
+.PP
+A second method of passing options to the compiler ia available.
+This method uses the file on which the compact EM code will be written.
+The compiler starts reading from this file scanning for options
+in the same format as used normally, except for the comment delimiters and
+the dollar sign.
+All options found on the file override the options set in your program.
+Note that the compact code file must always exist before the compiler is called.
+.PP
+The user interface program \fIack\fP[4]
+takes care of creating this file normally
+and also writes one of its options onto this file.
+The user can specify, for instance, without changing any character in its
+Pascal program, that the compiler must include code for
+procedure/function tracing.
+.PP
+Another very powerful debugging tool is the knowledge that inaccessible
+statements and useless tests are removed by the EM optimizer.
+For instance, a statement like:
+.sp
+.nf
+        if debug then
+          writeln('initialization done');
+.fi
+.sp
+is completely removed by the optimizer if debug is a constant with
+value false.
+The first line is removed if debug is a constant with value true.
+Of course, if debug is a variable nothing can be removed.
+.PP
+A disadvantage of Pascal, the lack of preinitialized data, can be
+diminished by making use of the possibilities of the EM optimizer.
+For instance, initializing an array of reserved words is sometimes
+optimized into 3 EM instructions. To maximize this effect you must initialize
+variables as much as possible in order of declaration and array entries
+in order of decreasing index.
+.CH "References"
+.in +5
+.ti -5
+[1]~~\
+ISO standard proposal ISO/TC97/SC5-N462, dated February 1979.
+The same proposal, in slightly modified form, can be found in:
+A.M.Addyman e.a., "A draft description of Pascal",
+Software, practice and experience, May 1979.
+An improved version, received March 1980,
+is followed as much as possible for the
+current Ack-Pascal.
+.sp
+.ti -5
+[2]~~\
+A.S.Tanenbaum, J.W.Stevenson, Hans van Staveren, E.G.Keizer,
+"Description of a machine architecture for use with block structured languages",
+Informatica rapport IR-81.
+.sp
+.ti -5
+[3]~~\
+W.S.Brown, S.I.Feldman, "Environment parameters and basic functions
+for floating-point computation",
+Bell Laboratories CSTR #72.
+.sp
+.ti -5
+[4]~~\
+UNIX manual ack(I).
+.sp
+.ti -5
+[5]~~\
+UNIX manual ld(I).
+.sp
+.ti -5
+[6]~~\
+UNIX manual em(I).
+.sp
+.ti -5
+[7]~~\
+UNIX manual libpc(VII)
+.sp
+.ti -5
+[8]~~\
+UNIX manual pc_prlib(VII)

+ 505 - 0
doc/peep.doc

@@ -0,0 +1,505 @@
+.TL
+Internal documentation on the peephole optimizer
+.br
+from the Amsterdam Compiler Kit
+.NH 1
+Introduction
+.PP
+Part of the Amsterdam Compiler Kit is a program to do
+peephole optimization on an EM program.
+The optimizer scans the program to match patterns from a table
+and if found makes the optimization from the table,
+and with the result of the optimization
+it tries to find yet another optimization
+continuing until no more optimizations are found.
+.PP
+Furthermore it does some optimizations that can not be called
+peephole optimizations for historical reasons,
+like branch chaining and the deletion of unreachable code.
+.PP
+The peephole optimizer consists of three parts
+.IP 1)
+A driving table
+.IP 2)
+A program translating the table to internal format
+.IP 3)
+C code compiled with the table to make the optimizer proper
+.PP
+In this document the table format, internal format and 
+data structures in the optimizer will be explained,
+plus a hint on what the code does where it might not be obvious.
+It is a simple program mostly.
+.NH 1
+Table format
+.PP
+The driving table consists of pattern/replacement pairs,
+in principle one per line,
+although a line starting with white space is considered
+a continuation line for the previous.
+The general format is:
+.DS
+optimization : pattern ':' replacement '\en'
+.sp
+pattern : EMlist optional_boolean_expression
+.sp
+replacement : EM_plus_operand_list
+.DE
+Example of a simple one
+.DS
+loc stl $1==0 : zrl $2
+.DE
+There is no real limit for the length of the pattern or the replacement,
+the replacement might even be longer than the pattern,
+and expressions can be made arbitrarily complicated.
+.PP
+The expressions in the table are made of the following pieces:
+.IP -
+Integer constants
+.IP -
+$\fIn\fP, standing for the operand of the \fIn\fP'th EM
+instruction in the pattern,
+undefined if that instruction has no operand.
+.IP -
+w, standing for the wordsize of the code optimized.
+.IP -
+p, for the pointersize.
+.IP -
+defined(expr), true if expression is defined
+.IP -
+samesign(expr,expr), true if expressions have the same sign.
+.IP -
+sfit(expr,expr), ufit(expr,expr),
+true if the first expression fits signed or unsigned in the number
+of bits given in the second expression.
+.IP -
+rotate(expr,expr),
+first expression rotated left the number of bits given by the second expression.
+.IP -
+notreg(expr),
+true if the local with the expression as number is not a candidate to put
+in a register.
+.IP -
+rom(\fIn\fP,expr), contents of the rom descriptor at index expr that
+is associated with the global label that should be the argument of
+the \fIn\fP'th EM instruction.
+Undefined if such a thing does not exist.
+.PP
+The usual arithmetic operators may be used on integer values,
+if any operand is undefined the expression is undefined,
+except for the defined() function above.
+An undefined expression used for its truth value is false.
+All arithmetic on local label operands is forbidden,
+only things allowed are tests for equality.
+Arithmetic on global labels makes sense,
+i.e. one can add a global label and a constant,
+but not two global labels.
+.PP
+In the table one can use five additional EM instructions in patterns.
+These are:
+.IP lab
+Stands for a local label
+.IP LLP
+Load Local Pointer, translates into a 
+.B lol
+or into a 
+.B ldl
+depending on the relationship between wordsize and pointersize.
+.IP LEP
+Load External Pointer, translates into a 
+.B loe
+or into a 
+.B lde .
+.IP SLP
+Store Local Pointer,
+.B stl
+or 
+.B sdl .
+.IP SEP
+Store External Pointer,
+.B ste
+or
+.B sde .
+.PP
+There is only one peephole optimizer,
+so the substitutions to be made for the last four instructions
+are made at run time before the first optimizations are made.
+.NH 1
+Internal format
+.PP
+The translating program,
+.I mktab
+converts the table into an array of bytes where all
+patterns follow unaligned.
+Format of a pattern is:
+.IP 1)
+One byte for high byte of hash value,
+will be explained later on.
+.IP 2)
+Two bytes for the index of the next pattern in a chain.
+.IP 3)
+An integer\u*\d,
+.FS
+* An integer is encoded as a byte when less than 255,
+otherwise as a byte containing 255 followed by two
+bytes with the real value.
+.FE
+pattern length.
+.IP 4)
+The list of pattern opcodes, one per byte.
+.IP 5)
+An integer expression index, 0 if not used.
+.IP 6)
+An integer, replacement length.
+.IP 7)
+A list of pairs consisting of a one byte opcode and an integer
+expression index.
+.PP
+The expressions are kept in an array of triples,
+implementing a binary tree.
+The
+.I mktab
+program tries to minimize the number of triples by reusing
+duplicates and even reverses the operands of commutative operators
+when doing so would spare a triple.
+.NH 1
+A tour through the sources
+.PP
+Now we will walk through the sources and note things of interest.
+.NH 2
+The header files
+.PP
+The header files are the place where data structures and options reside.
+.NH 3
+alloc.h
+.PP
+In the header file alloc.h several defines can be used to select various
+kinds of core allocation schemes.
+This is important on small machines like the PDP-11 since a complete
+procedure must be in core at the same space,
+and the peephole optimizer should not be the limiting factor in
+determining the maximum size of procedures if possible.
+Options are:
+.IP -
+USEMALLOC, standard malloc() and free() are used instead of the own
+core allocation package.
+Not recommended unless the own package does not work on some bizarre
+machine.
+.IP -
+COREDEBUG, prints large amounts of information about core management.
+Better not define it unless you change the code and it stops working.
+.IP -
+SEPID, if you define this you will get an extra procedure that will
+go through a lot of work to scrape the last bytes together if the
+system won't provide more.
+This is not a good idea if memory is scarce and code and data reside
+in the same spaces, since the room used by the procedure might well
+be more than the room saved.
+.IP -
+STACKROOM, number of shorts used in stack space.
+This is used if memory is scarce and stack space and data space are
+different.
+On the PDP-11 a UNIX process starts with an 8K stack segment which
+cannot be transferred to the data segment.
+Under these conditions one can use a lot of the stack space for storage.
+.NH 3
+assert.h
+.PP
+Just defines the assert macro.
+When compiled with -DNDEBUG all asserts will be off.
+.NH 3
+ext.h
+.PP
+Gives external definitions of variables used by more than one module.
+.NH 3
+line.h
+.PP
+Defines the structures used to keep instructions,
+one structure per line of EM code,
+and the structure to keep arguments of pseudos,
+one structure per argument.
+Both structures essentially contain a pointer to the next,
+a type,
+and a union containing information depending on the type.
+Core is allocated only for the part of the union used.
+.PP
+The 
+.I
+struct line
+.R
+has a very compact encoding for small integers,
+they are encoded in the type field.
+On the PDP-11 this gives a line structure of only 4 bytes for most
+instructions.
+.NH 3
+lookup.h
+.PP
+Contains definition of the struct used for symbol table management,
+global labels and procedure names are kept in one table.
+.NH 3
+optim.h
+.PP
+If one defines the DIAGOPT option in this header file,
+for every optimization performed a number is written on stderr.
+The number gives the number of the pattern in the table
+or one of the four special numbers in this header file.
+.NH 3
+param.h
+.PP
+Contains one settable option,
+LONGOFF.
+If this is not defined the optimizer can only optimize programs
+with wordsize 2 and pointersize 2.
+Set this only if it must be run on a Z80 or something pathetic like that.
+.PP
+Other defines here should not be touched.
+.NH 3
+pattern.h
+.PP
+Contains defines of indices in a pattern,
+definition of the expression triples,
+definitions of the various expression operators
+and definition of the result struct where expression results are put.
+.PP
+This header file is the main one that is also included by
+.I mktab .
+.NH 3
+proinf.h
+.PP
+This one contains definitions 
+for the local label table structs
+and for the struct where all information for one procedure is kept.
+This is in one struct so it can be saved easily when recursive
+procedures have to be resolved.
+.NH 3
+types.h
+.PP
+Collection of typedefs to be used by almost all modules.
+.NH 2
+The C code itself.
+.PP
+The C code will now be the center of our attention.
+We will make a walk through the sources and we will try
+to follow the sources in a logical order.
+So we will start at
+.NH 3
+main.c
+.PP
+The main.c module contains the main() function.
+Here nothing spectacular happens,
+only thing of interest is the handling of flags:
+.IP -L
+This is an instruction to the peephole optimizer to perform
+one of its auxiliary functions, the generation of a library module.
+This makes the peephole optimizer write its output on a temporary file,
+and at the end making the real output by first generating a list
+of exported symbols and then copying the temporary file behind it.
+.IP -n
+Disables all optimization.
+Only thing the optimizer does now is filling in the blank after the
+.I END
+pseudo and resolving recursive procedures.
+.PP
+The place where main() is left is the call to getlines() which brings
+us to
+.NH 3
+getline.c
+.PP
+This module reads the EM code and constructs a list of 
+.I
+struct line
+.R
+records,
+linked together backwards,
+i.e. the first instruction read is the last in the list.
+Pseudos are handled here also,
+for most pseudos this just means that a chain of argument records
+is linked into the linked line list but some pseudos get special attention:
+.IP exc
+This pseudo is acted upon right away.
+Lines read are shuffled around according to instruction.
+.IP mes
+Some messages are acted upon.
+These are:
+.RS
+.IP ms_err 8
+The input is drained, just in case it is a pipe.
+After that the optimizer exits.
+.IP ms_opt
+The do not optimize flag is set.
+Acts just like -n on the command line.
+.IP ms_emx
+The word- and pointersize are read,
+complain if we are not able to handle this.
+.IP ms_reg
+We take notice of the offset of this local.
+See also comments in the description of peephole.c
+.RE
+.IP pro
+A new procedure starts, if we are already in one save the status,
+else process collected input.
+Collect information about this procedure and if already in a procedure
+call getlines() recursively.
+.IP end
+Process collected input.
+.PP
+The phrase "process collected input" is used twice,
+which brings us to
+.NH 3
+process.c
+.PP
+This module contains the entry point process() which is called at any
+time the collected input must be processed.
+It calls a variety of other routines to get the real work done.
+Routines in this module are in chronological order:
+.IP symknown 12
+Marks all symbols seen until now as known,
+i.e. it is now known whether their scope is local or global.
+This information is used again during output.
+.IP symvalue
+Runs through the chain of pseudos to give values to data labels.
+This needs an extra pass.
+It cannot be done during the getlines pass, since an
+.B exc
+pseudo could destroy things.
+Nor can it be done during the backward pass since it is impossible
+to do good fragment numbering backward.
+.IP checklocs
+Checks whether all local labels referenced are defined.
+It needs to be sure about this since otherwise the
+semi global optimizations made cannot work.
+.IP relabel
+This routine finds the final destination for each label in the procedure.
+Labels followed by unconditional branches or other labels are marked during
+the peephole fase and this leeds to chains of identical labels.
+These chains are followed here, and in the local label table each label
+has associated with it its replacement label, after this procedure is run.
+Care is taken in this routine to prevent a loop in the program to
+cause the optimizer to loop.
+.IP cleanlocals
+This routine empties the local label table after everything
+is processed.
+.PP
+But before this can all be done,
+the backward linked list of instructions first has to be reversed,
+so here comes
+.NH 3
+backward.c
+.PP
+The routine backward has a number of functions:
+.IP -
+It reverses the backward linked list, making two forward linked lists,
+one for the instructions and one for the pseudos.
+.IP -
+It notes the last occurrence of data labels in the backward linked list
+and puts it in the global symbol table.
+This is of course the first occurence in the procedure.
+This information is needed to decide whether the symbols are global
+or local to this module.
+.IP -
+It decides about the fragment boundaries of data blocks.
+Fragments are numbered backwards starting at 3.
+This is done to be able to make the type of an expression
+containing a symbol equal to its fragment.
+This type can then not clash with the types integer and local label.
+.IP -
+It allocates a rom buffer to every data label with a rom behind
+it, if that rom contains only plain integers at the start.
+.PP
+The first thing done after process() has called backward() and some
+of its own little routines is a call to the real routine,
+the one that does the work the program was written for
+.NH 3
+peephole.c
+.PP
+The first routines in peephole.c 
+implement a linked list for the offsets of local variables
+that are candidates for a register implementation.
+Several patterns use the notreg() function,
+since it is forbidden to combine a load of that variable
+with the load of another and
+it is not allowed to take the address of that variable.
+.PP
+The routine peephole hashes the patterns the first time it is called
+after which it doesn't do much more than calling optimize.
+But first hashpatterns().
+.PP
+The patterns are hashed at run time of the optimizer because of
+the
+.B LLP ,
+.B LEP ,
+.B SLP 
+and
+.B SEP
+instructions added to the instruction set in this optimizer.
+These are first replaced everywhere in the table by the correct
+replacement after which the first three instructions of the
+pattern are hashed and the pattern is linked into one of the
+256 linked lists.
+There is a define CHK_HASH in this module that you
+can set if you do not trust the randomness of the hashing
+function.
+.PP
+The attention now shifts to optimize().
+This routine calls  basicblock() for every piece of code between two labels.
+It also notes which labels have another label or a branch behind them
+so the relabel() routine from process.c can do something with that.
+.PP
+Basicblock() keeps making passes over its basic block
+until no more optimizations are found.
+This might be inefficient if there is a long basicblock with some
+deep recursive optimization in one part of it.
+The entire basic block is then scanned a lot of times just for
+that one piece.
+The alternative is backing up after making an optimization and running
+through the same code again, but that is difficult
+in a single linked list.
+.PP
+It hashes instructions and calls trypat() for every pattern that has
+a full hash value match,
+i.e. lower byte and upper byte equal.
+Longest pattern is tried first.
+.PP
+Trypat() checks length and opcodes of the pattern.
+If correct it fills the iargs[] array with argument values
+and calculates the expression.
+If that is also correct the work shifts to tryrepl().
+.PP
+Tryrepl() generates the list of replacement instructions,
+links it into the list and returns true.
+Why then the name tryrepl() if it always succeeds?
+Well, there is a mechanism in the optimizer,
+unused until today that makes it possible to do optimizations that cannot
+be described by the table.
+It is possible to give a number as a replacement which will cause the
+optimizer to call a routine special() to do some work.
+This routine might decide not to do an optimization and return false.
+.PP
+The last routine that is called from process() is putline()
+to write the optimized code, bringing us to
+.NH 3
+putline.c
+.PP
+The major part of putline.c is the standard set of routines
+that makes EM compact code.
+The extra functions performed are:
+.IP -
+For every occurence of a global symbol it might be necessary to
+output a 
+.B exa ,
+.B exp ,
+.B ina
+or 
+.B inp
+pseudo instruction.
+That task is performed.
+.IP -
+The
+.B lin
+instructions are optimized here,
+.B lni
+instructions added for 
+.B lin
+instructions and superfluous
+.B lin
+instructions deleted.
+

+ 131 - 0
doc/regadd.doc

@@ -0,0 +1,131 @@
+.TL
+Addition of register variables to an existing table.
+.NH 1
+Introduction
+.PP
+This is a short description of the newest feature in the
+table driven code generator for the Amsterdam Compiler Kit.
+It describes how to add register variables to an existing table.
+This assumes you have the distribution of October 1983 or later.
+It is not clear whether you should read this when starting with
+a table for a new machine,
+or whether you should wait till the table is well debugged already.
+.NH 1
+Modifications to the table itself.
+.NH 2
+Register section
+.PP
+You can add just before the properties of the register one
+of the following:
+.IP - 2
+regvar
+.IP -
+regvar ( pointer )
+.IP -
+regvar ( loop )
+.IP -
+regvar ( float )
+.LP
+All register variables of one type must be of the same size,
+and they may have no subregisters.
+.NH 2
+Codesection
+.PP
+.IP - 2
+Two pseudo functions are added to the list allowed inside expressions:
+.RS
+.IP 1) 3
+inreg ( expr ) has as a parameter the offset of a local,
+and returns 0,1 or 2:
+.RS
+.IP 2: 3
+if the variable is in a register.
+.IP 1:
+if the variable could be in a register but isn't.
+.IP 0:
+if the variable cannot be in a register.
+.RE
+.IP 2)
+regvar ( expr ) returns the register associated with the variable.
+Undefined if it is not in a register.
+So regvar ( expr ) is defined if and only if inreg (expr ) == 2.
+.RE
+.IP -
+It is now possible to remove() a register expression,
+this is of course needed for a store into a register local.
+.IP -
+The return out of a procedure may now involve register restores,
+so the special word 'return' in the table will invoke a user defined
+function.
+.NH 1
+Modifications to mach.c
+.PP
+If register variables are used in a table, the program
+.I cgg
+will define the word REGVARS during compilation of the sources.
+So the following functions described here should be bracketed
+by #ifdef REGVARS and #endif.
+.IP - 2
+regscore(off,size,typ,freq,totyp) long off;
+.br
+This function should assign a score to a register variable,
+the score should preferably be the estimated number of bytes
+gained when it is put in a register.
+Off and size are the offset and size of the variable,
+typ is the type, that is reg_any, reg_pointer, reg_loop or reg_float.
+Freq is the number of times it occurs statically, and totyp
+is the type of the register it is planned to go into.
+.br
+Keep in mind that the gain should be net, that is the cost for
+register save/restore sequences and the cost of initialisation
+in the case of parameters should already be included.
+.IP -
+i_regsave()
+.br
+This function is called at the start of a procedure, just before
+register saves are done.
+It can be used to initialise some variables if needed.
+.IP -
+f_regsave()
+.br
+This function is called at end of the register save sequence.
+It can be used to do the real saving if multiple register move
+instructions are available.
+.IP -
+regsave(regstr,off,size) char *regstr; long off;
+.br
+Should either do the real saving or set up a table to have
+it done by f_regsave.
+Note that initialisation of parameters should also be done,
+or planned here.
+.IP -
+regreturn()
+.br
+Should restore saved registers and return.
+The function result is already in the function return area by now.
+.NH 1
+Examples
+.PP
+Here are some examples out of the PDP 11 table
+.DS
+lol inreg($1)==2| |		| regvar($1)			| |
+
+lil inreg($1)==2| |		| {regdef2, regvar($1)}		| |
+
+stl inreg($1)==2| xsource2 |
+			remove(regvar($1))
+			move(%[1],regvar($1))              |       | |
+
+inl inreg($1)==2| |     remove(regvar($1))
+			"inc %(regvar($1)%)"
+			setcc(regvar($1))          |       | |
+.NH 1
+Afterthoughts.
+.PP
+At the time of this writing the tables for the PDP 11 and the M68000 and
+the VAX are converted, in all cases the two byte wordsize versions.
+No big problems have occurred, but experience has shown that it is
+necessary to check your table carefully for all patterns with locals in them
+because if you forget one code will be generated by that one coderule
+to use the memoryslot the local is not in.
+

+ 896 - 0
doc/toolkit.doc

@@ -0,0 +1,896 @@
+.RP
+.ND
+.nr LL 78m
+.tr ~
+.ds as *
+.TL
+A Practical Tool Kit for Making Portable Compilers
+.AU
+Andrew S. Tanenbaum
+Hans van Staveren
+E. G. Keizer
+Johan W. Stevenson
+.AI
+Mathematics Dept.
+Vrije Universiteit
+Amsterdam, The Netherlands
+.AB
+The Amsterdam Compiler Kit is an integrated collection of programs designed to
+simplify the task of producing portable (cross) compilers and interpreters.
+For each language to be compiled, a program (called a front end) 
+must be written to
+translate the source program into a common intermediate code.
+This intermediate code can be optimized and then either directly interpreted
+or translated to the assembly language of the desired target machine.
+The paper describes the various pieces of the tool kit in some detail, as well
+as discussing the overall strategy.
+.sp
+Keywords: Compiler, Interpreter, Portability, Translator
+.sp
+CR Categories: 4.12, 4.13, 4.22
+.sp 12
+Author's present addresses:
+  A.S. Tanenbaum, H. van Staveren, E.G. Keizer: Mathematics
+     Dept., Vrije Universiteit, Postbus 7161, 1007 MC Amsterdam,
+     The Netherlands
+
+  J.W. Stevenson: NV Philips, S&I, T&M, Building TQ V5, Eindhoven,
+     The Netherlands
+.AE
+.NH 1
+Introduction
+.PP
+As more and more organizations acquire many micro- and minicomputers,
+the need for portable compilers is becoming more and more acute.
+The present situation, in which each hardware vendor provides its own
+compilers -- each with its own deficiencies and extensions, and none of them
+compatible -- leaves much to be desired.
+The ideal situation would be an integrated system containing a family
+of (cross) compilers, each compiler accepting a standard source language and
+producing code for a wide variety of target machines.
+Furthermore, the compilers should be compatible, so programs written in
+one language can call procedures written in another language.
+Finally, the system should be designed so as to make adding new languages
+and new machines easy.
+Such an integrated system is being built at the Vrije Universiteit.
+Its design and implementation is the subject of this article.
+.PP
+Our compiler building system, which is called the "Amsterdam Compiler Kit"
+(ACK), can be thought of as a "tool kit."
+It consists of a number of parts that can be combined to form compilers
+(and interpreters) with various properties.
+The tool kit is based on an idea (UNCOL) that was first suggested in 1960
+[7], but which never really caught on then.
+The problem which UNCOL attempts to solve is how to make a compiler for
+each of
+.I N
+languages on
+.I M
+different machines without having to write 
+.I N
+x
+.I M
+programs.
+.PP
+As shown in Fig. 1, the UNCOL approach is to write
+.I N
+"front ends," each
+of which translates one source language to a common intermediate language,
+UNCOL (UNiversal Computer Oriented Language), and
+.I M
+"back ends," each
+of which translates programs in UNCOL to a specific machine language.
+Under these conditions, only
+.I N
++
+.I M
+programs must be written to provide all
+.I N
+languages on all
+.I M
+machines, instead of 
+.I N
+x
+.I M
+programs.
+.PP
+Various researchers have attempted to design a suitable UNCOL
+[2,8], but none of these have become popular.
+It is our belief that previous attempts have failed because they have been
+too ambitious, that is, they have tried to cover all languages
+and all machines using a single UNCOL.
+Our approach is more modest: we cater only to algebraic languages
+and machines whose memory consists of 8-bit bytes, each with its own address.
+Typical languages that could be handled include
+Ada, ALGOL 60, ALGOL 68, BASIC, C, FORTRAN,
+Modula, Pascal, PL/I, PL/M, PLAIN, and RATFOR,
+whereas COBOL, LISP, and SNOBOL would be less efficient.
+Examples of machines that could be included are the Intel 8080 and 8086,
+Motorola 6800, 6809, and 68000, Zilog Z80 and Z8000, DEC PDP-11 and VAX,
+and IBM 370 but not the Burroughs 6700, CDC Cyber, or Univac 1108 (because
+they are not byte-oriented).
+With these restrictions, we believe the old UNCOL idea can be used as the
+basis of a practical compiler-building system.
+.KF
+.sp 15P
+.ce 1
+Fig. 1.  The UNCOL model.
+.sp
+.KE
+.NH 1
+An Overview of the Amsterdam Compiler Kit
+.PP
+The tool kit consists of eight components:
+.sp
+  1. The preprocessor.
+  2. The front ends.
+  3. The peephole optimizer.
+  4. The global optimizer.
+  5. The back end.
+  6. The target machine optimizer.
+  7. The universal assembler/linker.
+  8. The utility package.
+.sp
+.PP
+A fully optimizing compiler,
+depicted in Fig. 2, has seven cascaded phases.
+Conceptually, each component reads an input file and writes a
+transformed output file to be used as input to the next component.
+In practice, some components may use temporary files to allow multiple
+passes over the input or internal intermediate files.
+.KF
+.sp 12P
+.ce 1
+Fig. 2.  Structure of the Amsterdam Compiler Kit.
+.sp
+.KE
+.PP
+In the following paragraphs we will briefly describe each component.
+After this overview, we will look at all of them again in more detail.
+A program to be compiled is first fed into the (language independent)
+preprocessor, which provides a simple macro facility,
+and similar textual facilties.
+The preprocessor's output is a legal program in one of the programming
+languages supported, whereas the input is a program possibly augmented
+with macros, etc.
+.PP
+This output goes into the appropriate front end, whose job it is to
+produce intermediate code.
+This intermediate code (our UNCOL) is the machine language for a simple
+stack machine called EM (Encoding Machine).
+A typical front end might build a parse tree from the input, and then
+use the parse tree to generate EM code, which is similar to reverse Polish.
+In order to perform this work, the front end has to maintain tables of
+declared variables, labels, etc., determine where to place the
+data structures in memory, and so on.
+.PP
+The EM code generated by the front end is fed into the peephole optimizer,
+which scans it with a window of a few instructions, replacing certain
+inefficient code sequences by better ones.
+Such a search is important because EM contains instructions to handle
+numerous important special cases efficiently
+(e.g., incrementing a variable by 1).
+It is our strategy to relieve the front ends of the burden of hunting for
+special cases because there are many front ends and only one peephole
+optimizer.
+By handling the special cases in the peephole optimizer, 
+the front ends become simpler, easier to write and easier to maintain.
+.PP
+Following the peephole optimizer is a global optimizer [5], which
+unlike the peephole optimizer, examines the program as a whole.
+It builds a data flow graph to make possible a variety of 
+global optimizations,
+among them, moving invariant code out of loops, avoiding redundant
+computations, live/dead analysis and eliminating tail recursion.
+Note that the output of the global optimizer is still EM code.
+.PP
+Next comes the back end, which differs from the front ends in a
+fundamental way.
+Each front end is a separate program, whereas the back end is a single
+program that is driven by a machine dependent driving table.
+The driving table for a specific machine tells how the EM code is mapped
+onto the machine's assembly language.
+Although a simple driving table might just macro expand each EM instruction
+into a sequence of target machine instructions, a much more sophisticated
+translation strategy is normally used, as described later.
+For speed, the back end does not actually read in the driving table at run time.
+Instead, the tables are compiled along with the back end in advance, resulting
+in one binary program per machine.
+.PP
+The output of the back end is a program in the assembly language of some
+particular machine.
+The next component in the pipeline reads this program and performs peephole
+optimization on it.
+The optimizations performed here involve idiosyncracies
+of the target machine that cannot be performed in the machine-independent
+EM-to-EM peephole optimizer.
+Typically these optimizations take advantage of special instructions or special
+addressing modes.
+.PP
+The optimized target machine assembly code then goes into the final
+component in the pipeline, the universal assembler/linker.
+This program assembles the input to object format, extracting routines from
+libraries and including them as needed.
+.PP
+The final component of the tool kit is the utility package, which contains
+various test programs, interpreters for EM code, 
+EM libraries, conversion programs, and other aids for the implementer and
+user.
+.NH 1
+The Preprocessor
+.PP
+The function of the preprocessor is to extend all the programming languages
+by adding certain generally useful facilities to them in a uniform way.
+One of these is a simple macro system, in which the user can give names to
+character strings.
+The names can be used in the program, with the knowledge that they will be
+macro expanded prior to being input to the front end.
+Macros can be used for named constants, expanding short "procedures"
+in line, etc.
+.PP
+Another useful facility provided by the preprocessor is the ability to
+include compile-time libraries.
+On large projects, it is common to have all the declarations and definitions
+gathered together in a few files that are textually included in the programs
+by instructing the preprocessor to read them in, thus fooling the front end
+into thinking that they were part of the source program.
+.PP
+A third feature of the preprocessor is conditional compilation.
+The input program can be split up into labeled sections.
+By setting flags, some of the sections can be deleted by the preprocessor,
+thus allowing a family of slightly different programs to be conveniently stored
+on a single file.
+.NH 1
+The Front Ends
+.PP
+A front end is a program that converts input in some source language to a
+program in EM.
+At present, front ends 
+exist or are in preparation for Pascal, C, and Plain, and are being considered
+for Ada, ALGOL 68, FORTRAN 77, and Modula 2.
+Each of the present front ends is independent of all the other ones,
+although a general-purpose, table-driven front end is conceivable, provided
+one can devise a way to express the semantics of the source language in the
+driving tables.
+The Pascal front end uses a top-down parsing algorithm (recursive descent),
+whereas the C and Plain front ends are bottom-up.
+.PP
+All front ends, independent of the language being compiled,
+produce a common intermediate code called EM, which is
+the assembly language for a simple stack machine.
+The EM machine is based on a memory architecture
+containing a stack for local variables, a (static) data area for variables
+declared in the outermost block and global to the whole program, and a heap
+for dynamic data structures.
+In some ways EM resembles P-code [6], but is more general, since it is
+intended for a wider class of languages than just Pascal.
+.PP
+The EM instruction set has been described elsewhere
+[9,10,11]
+so we will only briefly summarize it here.
+Instructions exist to:
+.sp
+  1. Load a variable or constant of some length onto the stack.
+  2. Store the top item on the stack in memory.
+  3. Add, subtract, multiply, divide, etc. the top two stack items.
+  4. Examine the top one or two stack items and branch conditionally.
+  5. Call procedures and return from them.
+.sp
+.PP
+Loads and stores come in several variations, corresponding to the most common
+programming language semantics, for example, constants, simple variables,
+fields of a record, elements of an array, and so on.
+Distinctions are also made between variables local to the current block
+(i.e., stack frame), those in the outermost block (static storage), and those
+at intermediate lexicographic levels, which are accessed by following the
+static chain at run time.
+.PP
+All arithmetic instructions have a type (integer, unsigned, real,
+pointer, or set) and an
+operand length, which may either be explicit or may be popped from the stack
+at run time.
+Monadic branch instructions pop an item from the stack and branch if it is
+less than zero, less than or equal to zero, etc.
+Dyadic branch instructions pop two items, compare them, and branch accordingly.
+.PP
+In addition to these basic EM instructions, there is a collection of special
+purpose instructions (e.g., to increment a local variable), which are typically
+produced from the simple ones by the peephole optimizer.
+Although the complete EM instruction set contains nearly 150 instructions,
+only about 60 of them are really primitive; the rest are simply abbreviations
+for commonly occurring EM instruction sequences.
+.PP
+Of particular interest is the way object sizes are parametrized.
+The front ends allow the user to indicate how many bytes an integer, real, etc.
+should occupy.
+Given this information, the front ends can allocate memory, determining 
+the placement of variables within the stack frame.
+Sizes for primitive types are restricted to 8, 16, 32, 64, etc. bits.
+The front ends are also parametrized by the target machine's word length
+and address size so they can tell, for example, how many "load" instructions
+to generate to move a 32-bit integer.
+In the examples used henceforth,
+we will assume a 16-bit word size and 16-bit integers.
+.PP
+Since only byte-addressable target machines are permitted,
+it is nearly
+always possible to implement any requested sizes on any target machine.
+For example, the designer of the back end tables for the Z80 should provide
+code for 8-, 16-, and 32-bit arithmetic.
+In our view, the Pascal, C, or Plain programmer specifies what lengths 
+are needed,
+without reference to the target machine,
+and the back end provides it.
+This approach greatly enhances portability.
+While it is true that doing all arithmetic using 32-bit integers on the Z80
+will not be terribly fast, we feel that if that is what the programmer needs,
+it should be possible to implement it.
+.PP
+Like all assembly languages, EM has not only machine instructions, but also
+pseudoinstructions.
+These are used to indicate the start and end of each procedure, allocate
+and initialize storage for data, and similar functions.
+One particularly important pseudoinstruction is the one that is used to
+transmit information to the back end for optimization purposes.
+It can be used to suggest variables that are good candidates to assign to
+registers, delimit the scope of loops, indicate that certain variables 
+contain a useful value (next operation is a load) or not (next operation is
+a store), and various other things.
+.NH 1
+The Peephole Optimizer
+.PP
+The peephole optimizer reads in unoptimized EM programs and writes out
+optimized ones.
+Both the input and output are expressed in a highly compact code, rather than
+in ASCII, to reduce the i/o time, which would otherwise dominate the CPU
+time.
+The program itself is table driven, and is, by and large, ignorant of the
+semantics of EM.
+The knowledge of EM is contained in a
+language- and machine-independent table consisting of about 400
+pattern-replacement pairs.
+We will briefly describe the kinds of optimizations it performs below;
+a more complete discussion can be found in [9].
+.PP
+Each line in the driving table describes one optimization, consisting of a
+pattern part and a replacement part.
+The pattern part is a series of one or more EM instructions and a boolean
+expression.
+The replacement part is a series of EM instructions with operands.
+A typical optimization might be:
+.sp
+  LOL  LOC  ADI  STL  ($1 = $4) and ($2 = 1) and ($3 = 2) ==> INL $1
+.sp
+where the text prior to the ==> symbol is the pattern and the text after it is
+the replacement.
+LOL loads a local variable onto the stack, LOC loads a constant onto the stack,
+ADI is integer addition, and STL is store local.
+The pattern specifies that four consecutive EM instructions are present, with
+the indicated opcodes, and that furthermore the operand of the first 
+instruction (denoted by $1) and the fourth instruction (denoted by $4) are the
+same, the constant pushed by LOC is 1, and the size of the integers added by
+ADI is 2 bytes.
+(EM instructions have at most one operand, so it is not necessary to specify
+the operand number.)
+Under these conditions, the four instructions can be replaced by a single INL
+(increment local) instruction whose operand is equal to that of LOL.
+.PP
+Although the optimizations cover a wide range, the main ones
+can be roughly divided into the following categories.
+\fIConstant folding\fR
+is used to evaluate constant expressions, such as 2*3~+~7 at
+compile time instead of run time.
+\fIStrength reduction\fR
+is used to replace one operation, such as multiply, by
+another, such as shift.
+\fIReordering of expressions\fR
+helps in cases like -K/5, which can be better
+evaluated as K/-5, because the former requires
+a division and a negation, whereas the latter requires only a division.
+\fINull instructions\fR
+include resetting the stack pointer after a call with 0 parameters,
+offsetting zero bytes to access the
+first element of a record, or jumping to the next instruction.
+\fISpecial instructions\fR
+are those like INL, which deal with common special cases
+such as adding one to a variable or comparing something to zero.
+\fIGroup moves\fR
+are useful because a sequence
+of consecutive moves can often be replaced with EM code
+that allows the back end to generate a loop instead of in line code.
+\fIDead code elimination\fR
+is a technique for removing unreachable statements, possibly made unreachable
+by previous optimizations.
+\fIBranch chain compression\fR
+can be applied when a branch instruction jumps to another branch instruction.
+The first branch can jump directly to the final destination instead of
+indirectly.
+.PP
+The last two optimizations logically belong in the global optimizer but are
+in the local optimizer for historical reasons (meaning that the local
+optimizer has been the only optimizer for many years and the optimizations were
+easy to do there).
+.NH 1
+The Global Optimizer
+.PP
+In contrast to the peephole optimizer, which examines the EM code a few lines
+at a time through a small window, the global optimizer examines the 
+program's large scale structure.
+Three distinct types of optimizations can be found here:
+.sp
+  1. Interprocedural optimizations.
+  2. Intraprocedural optimizations.
+  3. Basic block optimizations.
+.sp
+We will now look at each of these in turn.
+.PP
+Interprocedural optimizations are those spanning procedure boundaries.
+The most important one is deciding to expand procedures in line,
+especially short procedures that occur in loops and pass several parameters.
+If it takes more time or memory to pass the parameters than to do the work,
+the program can be improved by eliminating the procedure.
+The inverse optimization -- discovering long common code sequences and
+turning them into a procedure -- is also possible, but much more difficult.
+Like much of the global optimizer's work, the decision to make or not make
+a certain program transformation is a heuristic one, based on knowledge of
+how the back end works, how most target machines are organized, etc.
+.PP
+The heart of the global optimizer is its analysis of individual
+procedures.
+To perform this analysis, the optimizer must locate the basic blocks,
+instruction sequences which can be entered only at the top and exited
+only at the bottom.
+It then constructs a data flow graph, with the basic blocks as nodes and
+jumps between blocks as arcs.
+.PP
+From the data flow graph, many important properties of the program can be
+discovered and exploited.
+Chief among these is the presence of loops, indicated by cycles in the graph.
+One important optimization is looking for code that can be moved outside the
+loop, either prior to it or subsequent to it.
+Such code motion saves execution time, although it does not save memory.
+Unrolling loops is also possible and desirable in some cases.
+.PP
+Another area in which global analysis of loops is especially important is
+in register allocation. 
+While it is true that EM does not have any registers to allocate,
+the optimizer can easily collect information to allow the
+back end to allocate registers wisely.
+For example, the global optimizer can collect static frequency-of-use
+and live/dead information about variables.
+(A variable is dead at some point in the program if its current value is
+not needed, i.e., the next reference to it overwrites it rather than
+reading it; if the current value will eventually be used, the variable is
+live.)
+If two variables are never simultaneously live over some interval of code
+(e.g., the body of a loop), they can be packed into a single variable,
+which, if used often enough, may warrant being assigned to a register.
+.PP
+Many loops involve arrays: this leads to other optimizations.
+If an array is accessed sequentially, with each iteration using the next
+higher numbered element, code improvement is often possible.
+Typically, a pointer to the bottom element of each array can be set up
+prior to the loop.
+Within the loop the element is accessed indirectly via the pointer, which is
+also incremented by the element size on each iteration.
+If the target machine has an autoincrement addressing mode and the pointer
+is assigned to a register, an array access can often be done in a single
+instruction.
+.PP
+Other intraprocedural optimizations include removing tail recursion
+(last statement is a recursive call to the procedure itself),
+topologically sorting the basic blocks to minimize the number of branch
+instructions, and common subexpression recognition.
+.PP
+The third general class of optimizations done by the global optimizer is
+improving the structure of a basic block.
+For the most part these involve transforming arithmetic or boolean
+expressions into forms that are likely to result in better target code.
+As a simple example, A~+~B*C can be converted to B*C~+~A.
+The latter can often
+be handled by loading B into a register, multiplying the register by C, and
+then adding in A, whereas the former may involve first putting A into a
+temporary, depending on the details of the code generation table.
+Another example of this kind of basic block optimization is transforming
+-B~+~A~<~0 into the equivalent, but simpler, A~<~B.
+.NH 1
+The Back End
+.PP
+The back end reads a stream of EM instructions and generates assembly code
+for the target machine.
+Although the algorithm itself is machine independent, for each target
+machine a machine dependent driving table must be supplied.
+The driving table effectively defines the mapping of EM code to target code.
+.PP
+It will be convenient to think of the EM instructions being read as a
+stream of tokens.
+For didactic purposes, we will concentrate on two kinds of tokens:
+those that load something onto the stack, and those that perform some operation
+on the top one or two values on the stack.
+The back end maintains at compile time a simulated stack whose behavior
+mirrors what the stack of a hardware EM machine would do at run time.
+If the current input token is a load instruction, a new entry is pushed onto
+the simulated stack.
+.PP
+Consider, as an example, the EM code produced for the statement K~:=~I~+~7.
+If K and I are
+2-byte local variables, it will normally be LOL I; LOC 7; ADI~2; STL K.
+Initially the simulated stack is empty.
+After the first token has been read and processed, the simulated stack will
+contain a stack token of type MEM with attributes telling that it is a local,
+giving its address, etc.
+After the second token has been read and processed, the top two tokens on the
+simulated stack will be CON (constant) on top and MEM directly underneath it.
+.PP
+At this point the back end reads the ADI~2 token and
+looks in the driving table to find a line or lines that define the
+action to be taken for ADI~2.
+For a typical multiregister machine, instructions will exist to add constants
+to registers, but not to memory.
+Consequently, the driving table will not contain an entry for ADI~2 with stack
+configuration CON, MEM.
+.PP
+The back end is now faced with the problem of how to get from its
+current stack configuration, CON, MEM, which is not listed, to one that is
+listed.
+The table will normally contain rules (which we call "coercions")
+for converting between CON, REG, MEM, and similar tokens.
+Therefore the back end attempts to "coerce" the stack into a configuration
+that
+.I is
+present in the table.
+A typical coercion rule might tell how to convert a MEM into
+a REG, namely by performing the actions of allocating a
+register and emitting code to move the memory word to that register.
+Having transformed the compile-time stack into a configuration allowed for
+ADI~2, the rule can be carried out.
+A typical rule 
+for ADI~2 might have stack configuration REG, MEM
+and would emit code to add the MEM to the REG, leaving the stack
+with a single REG token instead of the REG and MEM tokens present before the
+ADI~2.
+.PP
+In general, there will be more than one possible coercion path.
+Assuming reasonable coercion rules for our example,
+we might be able to convert
+CON MEM into CON REG by loading the variable I into a register.
+Alternatively, we could coerce CON to REG by loading the constant into a register.
+The first coercion path does the add by first loading I into a register and
+then adding 7 to it.
+The second path first loads 7 into a register and then adds I to it.
+On machines with a fast LOAD IMMEDIATE instruction for small constants
+but no fast ADD IMMEDIATE, or vice
+versa, one code sequence will be preferable to the other.
+.PP
+In fact, we actually have more choices than suggested above.
+In both coercion paths a register must be allocated.
+On many machines, not every register can be used in every operation, so the
+choice may be important.
+On some machines, for example, the operand of a multiply must be in an odd
+register.
+To summarize, from any state (i.e., token and stack configuration), a
+variety of choices can be made, leading to a variety of different target
+code sequences.
+.PP
+To decide which of the various code sequences to emit, the back end must have
+some information about the time and memory cost of each one.
+To provide this information, each rule in the driving table, including
+coercions, specifies both the time and memory cost of the code emitted when
+the rule is applied.
+The back end can then simply try each of the legal possibilities (including all
+the possible register allocations) to find the cheapest one.
+.PP
+This situation is similar to that found in a chess or other game-playing
+program, in which from any state a finite number of moves can be made.
+Just as in a chess program, the back end can look at all the "moves" that can
+be made from each state reachable from the original state, and thus find the
+sequence that gives the minimum cost to a depth of one.
+More generally, the back end can evaluate all paths corresponding to accepting
+the next
+.I N
+input tokens, find the cheapest one, and then make the first move along
+that path, precisely the way a chess program would.
+.PP
+Since the back end is analogous to both a parser and a chess playing program,
+some clarifying remarks may be helpful.
+First, chess programs and the back end must do some look ahead, whereas the
+parser for a well-designed grammar can usually suffice with one input token
+because grammars are supposed to be unambiguous.
+In contrast, many legal mappings
+from a sequence of EM instructions to target code may exist.
+Second, like a parser but unlike a chess program, the back end has perfect
+information -- it does not have to contend with an unpredictable opponent's
+moves.
+Third, chess programs normally make a static evaluation of the board and
+label the
+.I nodes
+of the tree with the resulting scores.
+The back end, in contrast, associates costs with
+.I arcs
+(moves) rather than nodes (states).
+However, the difference is not essential, since it could 
+also label each node with the cumulative cost from the root to that node.
+.PP
+As mentioned above, the cost field in the table contains
+.I both
+the time and memory costs for the code emitted.
+It should be clear that the back end could use either one
+or some linear combination of them as the scoring function for evaluating moves.
+A user can instruct the compiler to optimize for time or for memory or
+for, say,  0.3 x time + 0.7 x memory.
+Thus the same compiler can provide a wide range of performance options to
+the user.
+The writer of the back end table can take advantage of this flexibility by
+providing several code sequences with different tradeoffs for each EM
+instruction (e.g., in line code vs. call to a run time routine).
+.PP
+In addition to the time-space tradeoffs, by specifying the depth of search
+parameter,
+.I N ,
+the user can effectively also tradeoff compile time vs. object
+code quality, for whatever code metric has been chosen.
+In summary, by combining the properties of a parser and a game playing program,
+it is possible to make a code generator that is table driven,
+highly flexible, and has the ability to produce good code from a
+stack machine intermediate code.
+.NH 1
+The Target Machine Optimizer
+.PP
+In the model of Fig 2., the peephole optimizer comes before the global
+optimizer.
+It may happen that the code produced by the global optimizer can also
+be improved by another round of peephole optimization.
+Conceivably, the system could have been designed to iterate peephole and
+global optimizations until no more of either could be performed.
+.PP
+However, both of these optimizations are done on the machine independent
+EM code.
+Neither is able to take advantage of the peculiarities and idiosyncracies with
+which most target machines are well endowed.
+It is the function of the final 
+optimizer to do any (peephole) optimizations that still remain.
+.PP
+The algorithm used here is the same as in the EM peephole optimizer.
+In fact, if it were not for the differences between EM syntax, which is
+very restricted, and target assembly language syntax,
+which is less so, precisely the same program could be used for both.
+Nevertheless, the same ideas apply concerning patterns and replacements, so
+our discussion of this optimizer will be restricted to one example.
+.PP
+To see what the target optimizer might do, consider the
+PDP-11 instruction sequence sub #2,r0;  mov (r0),x.
+First 2 is subtracted from register 0, then the word pointed to by it
+is moved to x.
+The PDP-11 happens to have an addressing mode to perform this sequence in
+one instruction: mov -(r0),x.
+Although it is conceivable that this instruction could be included in the
+back end driving table for the PDP-11, it is awkward to do so because it
+can occur in so many contexts.
+It is much easier to catch things like this in a separate program.
+.NH 1
+The Universal Assembler/Linker
+.PP
+Although assembly languages for different machines may appear very different
+at first glance, they have a surprisingly large intersection.
+We have been able to construct an assembler/linker that is almost entirely
+independent of the assembly language being processed.
+To tailor the program to a specific assembly language, it is necessary to
+supply a table giving the list of instructions, the bit patterns required for
+each one, and the language syntax.
+The machine independent part of the assembler/linker is then compiled with the
+table to produce an assembler and linker for a particular target machine.
+Experience has shown that writing the necessary table for a new machine can be
+done in less than a week.
+.PP
+To enforce a modicum of uniformity, we have chosen to use a common set of
+pseudoinstructions for all target machines.
+They are used to initialize memory, allocate uninitialized memory, determine the
+current segment, and similar functions found in most assemblers.
+.PP
+The assembler is also a linker.
+After assembling a program, it checks to see if there are any
+unsatisfied external references.
+If so, it begins reading the libraries to find the necessary routines, including
+them in the object file as it finds them.
+This approach requires libraries to be maintained in assembly language form,
+but eliminates the need for inventing a language to express relocatable
+object programs in a machine independent way.
+It also simplifies the assembler, since producing absolute object code is
+easier than producing relocatable object code.
+Finally, although assembly language libraries may be somewhat larger than
+relocatable object module libraries, the loss in speed due to having more
+input may be more than compensated for by not having to pass an intermediate
+file between the assembler and linker.
+.NH 1
+The Utility Package
+.PP
+The utility package is a collection of programs designed to aid the
+implementers of new front ends or new back ends.
+The most useful ones are the test programs.
+For example, one test set, EMTEST, systematically checks out a back end by
+executing an ever larger subset of the EM instructions.
+It starts out by testing LOC, LOL and a few of the other essential instructions.
+If these appear to work, it then tries out new instructions one at a time,
+adding them to the set of instructions "known" to work as they pass the tests.
+.PP
+Each instruction is tested with a variety of operands chosen from values 
+where problems can be expected.
+For example, on target machines which have 16-bit index registers but only
+allow 8-bit displacements, a fundamentally different algorithm may be needed
+for accessing
+the first few bytes of local variables and those with offsets of thousands.
+The test programs have been carefully designed to thoroughly test all relevant
+cases.
+.PP
+In addition to EMTEST, test programs in Pascal, C, and other languages are also
+available.
+A typical test is:
+.sp
+   i := 9; \fBif\fP i + 250 <> 259 \fBthen\fP error(16);
+.sp
+Like EMTEST, the other test programs systematically exercise all features of the
+language being tested, and do so in a way that makes it possible to pinpoint
+errors precisely.
+While it has been said that testing can only demonstrate the presence of errors
+and not their absence, our experience is that 
+the test programs have been invaluable in debugging new parts of the system
+quickly.
+.PP
+Other utilities include programs to convert
+the highly compact EM code produced by front ends to ASCII and vice versa,
+programs to build various internal tables from human writable input formats,
+a variety of libraries written in or compiled to EM to make them portable,
+an EM assembler, and EM interpreters for various machines.
+.PP
+Interpreting the EM code instead of translating it to target machine language
+is useful for several reasons.
+First, the interpreters provide extensive run time diagnostics including
+an option to list the original source program (in Pascal, C, etc.) with the
+execution frequency or execution time for each source line printed in the
+left margin.
+Second, since an EM program is typically about one-third the size of a
+compiled program, large programs can be executed on small machines.
+Third, running the EM code directly makes it easier to pinpoint errors in 
+the EM output of front ends still being debugged.
+.NH 1
+Summary and Conclusions
+.PP
+The Amsterdam Compiler Kit is a tool kit for building
+portable (cross) compilers and interpreters.
+The main pieces of the kit are the front ends, which convert source programs
+to EM code, optimizers, which improve the EM code, and back ends, which convert
+the EM code to target assembly language.
+The kit is highly modular, so writing one front end
+(and its associated runtime routines)
+is sufficient to implement
+a new language on a dozen or more machines, and writing one back end table
+and one universal assembler/linker table is all that is needed to bring up all
+the previously implemented languages on a new machine.
+In this manner, the contents, and hopefully the usefulness, of the toolkit
+will increase in time.
+.PP
+We believe the principal lesson to be learned from our work is that the old
+UNCOL idea is basically a sound way to produce compilers, provided suitable
+restrictions are placed on the source languages and target machines.
+We also believe that although compilers produced by this technology may not
+be equal to the very best handcrafted compilers,
+in terms of object code quality, they are certainly
+competitive with many existing compilers.
+However, when one factors in the cost of producing the compiler,
+the possible slight loss in performance may be more than compensated for by the
+large decrease in production cost.
+As a consequence of our work and similar work by other researchers [1,3,4],
+we expect integrated compiler building kits to become increasingly popular
+in the near future.
+.PP
+The toolkit is now available for various computers running the
+.UX
+operating system.
+For information, contact the authors.
+.NH 1
+References
+.LP
+.nr r 0 1
+.in +4
+.ti -4
+\fB~\n+r.\fR Graham, S.L.
+Table-Driven Code Generation.
+.I "Computer~13" ,
+8 (August 1980), 25-34.
+.PP
+A discussion of systematic ways to do code generation,
+in particular, the idea of having a table with templates that match parts of
+the parse tree and convert them into machine instructions.
+.sp 2
+.ti -4
+\fB~\n+r.\fR Haddon, B.K., and Waite, W.M.
+Experience with the Universal Intermediate Language Janus.
+.I "Software Practice & Experience~8" ,
+5 (Sept.-Oct. 1978), 601-616.
+.PP
+An intermediate language for use with ALGOL 68, Pascal, etc. is described.
+The paper discusses some problems encountered and how they were dealt with.
+.sp 2
+.ti -4
+\fB~\n+r.\fR Johnson, S.C.
+A Portable Compiler: Theory and Practice.
+.I "Ann. ACM Symp. Prin. Prog. Lang." ,
+Jan. 1978.
+.PP
+A cogent discussion of the portable C compiler.
+Particularly interesting are the author's thoughts on the value of
+computer science theory.
+.sp 2
+.ti -4
+\fB~\n+r.\fR Leverett, B.W., Cattell, R.G.G, Hobbs, S.O., Newcomer, J.M.,
+Reiner, A.H., Schatz, B.R., and Wulf, W.A.
+An Overview of the Production-Quality Compiler-Compiler Project.
+.I Computer~13 ,
+8 (August 1980), 38-49.
+.PP
+PQCC is a system for building compilers similar in concept but differing in
+details from the Amsterdam Compiler Kit.
+The paper describes the intermediate representation used and the code generation
+strategy.
+.sp 2
+.ti -4
+\fB~\n+r.\fR Lowry, E.S., and Medlock, C.W.
+Object Code Optimization.
+.I "Commun.~ACM~12",
+(Jan. 1969), 13-22.
+.PP
+A classic paper on global object code optimization.
+It covers data flow analysis, common subexpressions, code motion, register
+allocation and other techniques.
+.sp 2
+.ti -4
+\fB~\n+r.\fR Nori, K.V., Ammann, U., Jensen, K., Nageli, H.
+The Pascal P Compiler Implementation Notes.
+Eidgen. Tech. Hochschule, Zurich, 1975.
+.PP
+A description of the original P-code machine, used to transport the Pascal-P
+compiler to new computers.
+.sp 2
+.ti -4
+\fB~\n+r.\fR Steel, T.B., Jr. UNCOL: the Myth and the Fact. in
+.I "Ann. Rev. Auto. Prog."
+Goodman, R. (ed.), vol 2., (1960), 325-344.
+.PP
+An introduction to the UNCOL idea by its originator.
+.sp 2
+.ti -4
+\fB~\n+r.\fR Steel, T.B., Jr.
+A First Version of UNCOL.
+.I "Proc. Western Joint Comp. Conf." ,
+(1961), 371-377.
+.PP
+The first detailed proposal for an UNCOL.  By current standards it is a
+primitive language, but it is interesting for its historical perspective.
+.sp 2
+.ti -4
+\fB~\n+r.\fR Tanenbaum, A.S., van Staveren, H., and Stevenson, J.W.
+Using Peephole Optimization on Intermediate Code.
+.I "ACM Trans. Prog. Lang. and Sys. 3" ,
+1 (Jan. 1982) pp. 21-36.
+.PP
+A detailed description of a table-driven peephole optimizer.
+The driving table provides a list of patterns to match as well as the
+replacement text to use for each successful match.
+.sp 2
+.ti -4
+\fB\n+r.\fR Tanenbaum, A.S., Stevenson, J.W., Keizer, E.G., and van Staveren, H.
+Description of an Experimental Machine Architecture for use with Block
+Structured Languages.
+Informatica Rapport 81, Vrije Universiteit, Amsterdam, 1983.
+.PP
+The defining document for EM.
+.sp 2
+.ti -4
+\fB\n+r.\fR Tanenbaum, A.S.
+Implications of Structured Programming for Machine Architecture.
+.I "Comm. ACM~21" ,
+3 (March 1978), 237-246.
+.PP
+The background and motivation for the design of EM.
+This early version emphasized the idea of interpreting the intermediate
+code (then called EM-1) rather than compiling it.

+ 302 - 0
doc/v7bugs.doc

@@ -0,0 +1,302 @@
+.wh 0 hd
+.wh 60 fo
+.de hd
+'sp 5
+..
+.de fo
+'bp
+..
+.nr e 0 1
+.de ER
+.br
+.ne 20
+.sp 2
+.in 5
+.ti -5
+ERROR \\n+e:
+..
+.de PS
+.sp
+.nf
+.in +5
+..
+.de PE
+.sp
+.fi
+.in -5
+..
+.sp 3
+.ce
+UNIX version 7 bugs
+.sp 3
+This document describes the UNIX version 7 errors fixed at the
+Vrije Universiteit, Amsterdam.
+Several of these are discovered at the VU.
+Others are quoted from a list of bugs distributed by BellLabs.
+.sp
+For each error the differences between the original and modified
+source files are given,
+as well as a test program.
+.ER
+C optimizer bug for unsigned comparison
+.sp
+The following C program caused an IOT trap, while it should not
+(compile with 'cc -O prog.c'):
+.PS
+unsigned	i = 0;
+
+main() {
+	register j;
+
+	j = -1;
+	if (i > 40000)
+		abort();
+}
+.PE
+BellLabs suggests to make the following patch in c21.c:
+.PS
+/* modified /usr/src/cmd/c/c21.c */
+
+189		if (r==0) {
+190	/* next 2 lines replaced as indicated by
+191	 * Bell Labs bug distribution ( v7optbug )
+192			p->back->back->forw = p->forw;
+193			p->forw->back = p->back->back;
+194	  End of lines changed */
+195			if (p->forw->op==CBR
+196			  || p->forw->op==SXT
+197			  || p->forw->op==CFCC) {
+198				p->back->forw = p->forw;
+199				p->forw->back = p->back;
+200			} else {
+201				p->back->back->forw = p->forw;
+202				p->forw->back = p->back->back;
+203			}
+204	/* End of new lines */
+205			decref(p->ref);
+206			p = p->back->back;
+207			nchange++;
+208		} else if (r>0) {
+.PE
+Use the previous program to test before and after the modification.
+.ER
+The loader fails for large data or text portions
+.sp
+The loader 'ld' produces a "local symbol botch" error
+for the following C program.
+.PS
+int	big1[10000] = {
+	1
+};
+int	big2[10000] = {
+	2
+};
+
+main() {
+	printf("loader is fine\\n");
+}
+.PE
+We have made the following fix:
+.PS
+/* original /usr/src/cmd/ld.c */
+
+113	struct {
+114		int	fmagic;
+115		int	tsize;
+116		int	dsize;
+117		int	bsize;
+118		int	ssize;
+119		int	entry;
+120		int	pad;
+121		int	relflg;
+122	} filhdr;
+
+/* modified /usr/src/cmd/ld.c */
+
+113	/*
+114	 * The original Version 7 loader had problems loading large
+115	 * text or data portions.
+116	 * Why not include <a.out.h> ???
+117	 * then they would be declared unsigned
+118	 */
+119	struct {
+120		int	fmagic;
+121		unsigned	tsize;		/* not int !!! */
+122		unsigned	dsize;		/* not int !!! */
+123		unsigned	bsize;		/* not int !!! */
+124		unsigned	ssize;		/* not int !!! */
+125		unsigned	entry;		/* not int !!! */
+126		unsigned	pad;		/* not int !!! */
+127		unsigned	relflg;		/* not int !!! */
+128	} filhdr;
+.PE
+.ER
+Floating point registers
+.sp
+When a program is swapped to disk if it needs more memory,
+then the floating point registers were not saved, so that
+it may have different registers when it is restarted.
+A small assembly program demonstrates this for the status register.
+If the error is not fixed, then the program generates an IOT error.
+A "memory fault" is generated if all is fine.
+.PS
+start:	ldfps	$7400
+1:	stfps	r0
+	mov	r0,-(sp)
+	cmp	r0,$7400
+	beq	1b
+	4
+.PE
+You have to dig into the kernel to fix it.
+The following patch will do:
+.PS
+/* original /usr/sys/sys/slp.c */
+
+563		a2 = malloc(coremap, newsize);
+564		if(a2 == NULL) {
+565			xswap(p, 1, n);
+566			p->p_flag |= SSWAP;
+567			qswtch();
+568			/* no return */
+569		}
+
+/* modified /usr/sys/sys/slp.c */
+
+590		a2 = malloc(coremap, newsize);
+591		if(a2 == NULL) {
+592	#ifdef FPBUG
+593			/*
+594			 * copy floating point register and status,
+595			 * but only if you must switch processes
+596			 */
+597			if(u.u_fpsaved == 0) {
+598				savfp(&u.u_fps);
+599				u.u_fpsaved = 1;
+600			}
+601	#endif
+602			xswap(p, 1, n);
+603			p->p_flag |= SSWAP;
+604			qswtch();
+605			/* no return */
+606		}
+.PE
+.ER
+Floating point registers.
+.sp
+A similar problem arises when a process forks.
+The child will have random floating point registers as is
+demonstrated by the following assembly language program.
+The child process will die by an IOT trap and the father prints
+the message "child failed".
+.PS
+exit	= 1.
+fork	= 2.
+write	= 4.
+wait	= 7.
+
+start:	ldfps	$7400
+	sys	fork
+	br	child
+	sys	wait
+	tst	r1
+	bne	bad
+	stfps	r2
+	cmp	r2,$7400
+	beq	start
+	4
+child:	stfps	r2
+	cmp	r2,$7400
+	beq	ex
+	4
+bad:	clr	r0
+	sys	write;mess;13.
+ex:	clr	r0
+	sys	exit
+
+	.data
+mess:	<child failed\\n>
+.PE
+The same file slp.c should be patched as follows:
+.PS
+/* original /usr/sys/sys/slp.c */
+
+499		/*
+500		 * When the resume is executed for the new process,
+501		 * here's where it will resume.
+502		 */
+503		if (save(u.u_ssav)) {
+504			sureg();
+505			return(1);
+506		}
+507		a2 = malloc(coremap, n);
+508		/*
+509		 * If there is not enough core for the
+510		 * new process, swap out the current process to generate the
+511		 * copy.
+512		 */
+
+/* modified /usr/sys/sys/slp.c */
+
+519		/*
+520		 * When the resume is executed for the new process,
+521		 * here's where it will resume.
+522		 */
+523		if (save(u.u_ssav)) {
+524			sureg();
+525			return(1);
+526		}
+527	#ifdef FPBUG
+528		/* copy the floating point registers and status to child */
+529		if(u.u_fpsaved == 0) {
+530			savfp(&u.u_fps);
+531			u.u_fpsaved = 1;
+532		}
+533	#endif
+534		a2 = malloc(coremap, n);
+535		/*
+536		 * If there is not enough core for the
+537		 * new process, swap out the current process to generate the
+538		 * copy.
+539		 */
+.PE
+.ER
+/usr/src/libc/v6/stat.c
+.sp
+Some system calls are changed from version 6 to version 7.
+A library of system call entries, that make a version 6 UNIX look like
+a version 7 system, is provided to enable you to run some
+useful version 7 utilities, like 'tar', on UNIX-6.
+The entry for 'stat' contained two bugs:
+the 24-bit file size was incorrectly converted to 32 bits
+(sign extension of bit 15)
+and the uid/gid fields suffered from sign extension.
+.sp
+Transferring your files from version 6 to version 7 using 'tar'
+will fail for all files for which
+.sp
+	( (size & 0100000) != 0 )
+.sp
+These two errors are fixed if stat.c is modified as follows:
+.PS
+/* original /usr/src/libc/v6/stat.c */
+
+11		char  os_size0;
+12		short os_size1;
+13		short os_addr[8];
+
+49		buf->st_nlink = osbuf.os_nlinks;
+50		buf->st_uid = osbuf.os_uid;
+51		buf->st_gid = osbuf.os_gid;
+52		buf->st_rdev = 0;
+
+/* modified /usr/src/libc/v6/stat.c */
+
+11		char  os_size0;
+12		unsigned os_size1;
+13		short os_addr[8];
+
+49		buf->st_nlink = osbuf.os_nlinks;
+50		buf->st_uid = osbuf.os_uid & 0377;
+51		buf->st_gid = osbuf.os_gid & 0377;
+52		buf->st_rdev = 0;
+.PE

+ 752 - 0
doc/val.doc

@@ -0,0 +1,752 @@
+.ll 72
+.wh 0 hd
+.wh 60 fo
+.de hd
+'sp 5
+..
+.de fo
+'bp
+..
+.tr ~
+.               PARAGRAPH
+.de PP
+.sp
+..
+.               CHAPTER
+.de CH
+.br
+.ne 15
+.sp 3
+.in 0
+\\fB\\$1\\fR
+.in 5
+.PP
+..
+.               SUBCHAPTER
+.de SH
+.br
+.ne 10
+.sp
+.in 5
+\\fB\\$1\\fR
+.in 10
+.PP
+..
+.               INDENT START
+.de IS
+.sp
+.in +5
+..
+.               INDENT END
+.de IE
+.in -5
+.sp
+..
+.               DOUBLE INDENT START
+.de DS
+.sp
+.in +5
+.ll -5
+..
+.               DOUBLE INDENT END
+.de DE
+.ll +5
+.in -5
+.sp
+..
+.               EQUATION START
+.de EQ
+.sp
+.nf
+..
+.               EQUATION END
+.de EN
+.fi
+.sp
+..
+.               TEST
+.de TT
+.ti -5
+Test~\\$1:~
+.br
+..
+.               IMPLEMENTATION 1
+.de I1
+.br
+Implementation~1:
+..
+.               IMPLEMENTATION 2
+.de I2
+.br
+Implementation~2:
+..
+.de CS
+.br
+~-~\\
+..
+.br
+.fi
+.sp 5
+.ce
+\fBPascal Validation Suite Report\fR
+.CH "Pascal processor identification"
+The ACK-Pascal compiler produces code for an EM machine
+as defined in [1].
+It is up to the implementor of the EM machine whether errors like
+integer overflow, undefined operand and range bound error are recognized or not.
+Therefore it depends on the EM machine implementation whether these errors
+are recognized in Pascal programs or not.
+The validation suite results of all known implementations are given.
+.PP
+There does not (yet) exist a hardware EM machine.
+Therefore, EM programs must be interpreted, or translated into
+instructions for a target machine.
+The following implementations currently exist:
+.IS
+.I1
+an interpreter running on a PDP-11 (using UNIX).
+The normal mode of operation for this interpreter is to check
+for undefined integers, overflow, range errors etc.
+.sp
+.I2
+a translator into PDP-11 instructions (using UNIX).
+Less checks are performed than in the interpreter, because the translator
+is intended to speed up the execution of well-debugged programs.
+.IE
+.CH "Test Conditions"
+Tester: E.G. Keizer
+.br
+Date: October 1983
+.br
+Validation Suite version: 3.0
+.PP
+The final test run is made with a slightly
+modified validation suite.
+.SH "Erroneous programs"
+Some test did not conform to the standard proposal of February 1979.
+It is this version of the standard proposal that is used
+by the authors of the validation suite.
+.IS
+.TT 6.6.3.7-4
+The semicolon between high and integer on line 17 is replaced
+by a colon.
+.sp
+.TT 6.7.2.2-13
+The div operator on line 14 replaced by mod.
+.CH "Conformance tests"
+Number of tests passed = 150
+.br
+Number of tests failed = 6
+.SH "Details of failed tests"
+.IS
+.TT 6.1.2-1
+Character sequences starting with the 8 characters 'procedur'
+or 'function' are
+erroneously classified as the word-symbols 'procedure' and 'function'.
+.sp
+.TT 6.1.3-2
+Identifiers identical in the first eight characters, but
+differing in ninth or higher numbered characters are treated as
+identical.
+.sp
+.TT 6.5.1-1
+ACK-Pascal requires all formal program parameters to be
+declared with type \fIfile\fP.
+.sp
+.TT 6.6.6.5-1
+Gives run-time error eof seen at call to eoln.
+A have a hunch that this is a error in the suit.
+.sp
+.TT 6.6.4.1-1
+Redefining the names of some standard procedures leads to incorrect
+behaviour of the runtime system.
+In this case it crashes without a sensible error message.
+.sp
+.TT 6.9.3.5.1-1
+This test can not be translated by our compiler because two
+non-identical variables are used in the same block with the same first eight
+characters.
+The test passed after replacement of one of those names.
+.IE
+.CH "Deviance tests"
+Number of deviations correctly detected = 120
+.br
+Number of tests not detecting deviations = 20
+.SH "Details of deviations"
+The following tests are compiled without a proper error
+indication although they do
+not conform to the standard.
+.IS
+.TT 6.1.6-5
+ACK-Pascal allows labels in the range 0..32767.
+A warning is produced when testing for deviations from the
+standard.
+.sp
+.TT 6.1.8-5
+A missing space between a number and a word symbol is not
+detected.
+.sp
+.TT 6.2.2-8
+.TT 6.3-6
+.TT 6.4.1-3
+.TT 6.6.1-3
+.TT 6.6.1-4
+Undetected scope error. The scope of an identifier should start at the
+beginning of the block in which it is declared.
+In the ACK-Pascal compiler the scope starts just after the declaration,
+however.
+.sp
+.TT 6.4.3.3-7
+The values of fields from one variant are accessible from
+another variant.
+The correlation is exact.
+.sp
+.TT 6.6.3.3-4
+The passing as a variable parameter of the selector of a
+variant part is not detected.
+A runtime error is produced because the variant selector is not
+initialized.
+.sp
+.TT 6.8.2.4-2
+.TT 6.8.2.4-3
+.TT 6.8.2.4-4
+.TT 6.8.2.4-5
+.TT 6.8.2.4-6
+The ACK-Pascal compiler does not restrict the places from where
+you may jump to a label by means of a goto-statement.
+.sp
+.TT 6.8.3.9-5
+.TT 6.8.3.9-6
+.TT 6.8.3.9-7
+.TT 6.8.3.9-16
+There are no errors produced for assignments to a variable
+in use as control-variable of a for-statement.
+.TT 6.8.3.9-8
+.TT 6.8.3.9-9
+Use of a controlled variable after leaving the loop without
+intervening initialization is not detected.
+.IE
+.CH "Error handling"
+The results depend on the EM implementation.
+.sp
+Number of errors correctly detected =
+.in +5
+.I1
+32
+.I2
+17
+.in -5
+Number of errors not detected =
+.in +5
+.I1
+21
+.I2
+36
+.in -5
+Number of errors incorrectly detected =
+.in +5
+.I1
+2
+.I2
+2
+.in -5
+.SH "Details of errors not detected"
+The following test fails because the ACK-Pascal compiler only
+generates a warning that does not prevent to run the tests.
+.IS
+.TT 6.6.2-8
+A warning is produced if there is no assignment to a function-identifier.
+.IE
+With this test the ACK-Pascal compiler issues an error message for a legal
+construct not directly related to the error to be detected.
+.IS
+.TT 6.5.5-2
+Program does not compile.
+Buffer variable of text file is not allowed as variable
+parameter.
+.IE
+The following errors are not detected at all.
+.IS
+.TT 6.2.1-11
+.I2
+The use of an undefined integer is not caught as an error.
+.sp
+.TT 6.4.3.3-10
+.TT 6.4.3.3-11
+.TT 6.4.3.3-12
+.TT 6.4.3.3-13
+The notion of 'current variant' is not implemented, not even if a tagfield
+is present.
+.sp
+.TT 6.4.5-15
+.TT 6.4.6-9
+.TT 6.4.6-10
+.TT 6.4.6-11
+.TT 6.5.3.2-2
+.I2
+Subrange bounds are not checked.
+.sp
+.TT 6.4.6-12
+.TT 6.4.6-13
+.TT 6.7.2.4-4
+If the base-type of a set is a subrange, then the set elements are not checked
+against the bounds of the subrange.
+Only the host-type of this subrange-type is relevant for ACK-Pascal.
+.sp
+.TT 6.5.4-1
+.I2
+Nil pointers are not detected.
+.sp
+.TT 6.5.4-2
+.I2
+Undefined pointers are not detected.
+.sp
+.TT 6.5.5-3
+Changing the file position while the window is in use as actual variable
+parameter or as an element of the record variable list of a with-statement
+is not detected.
+.sp
+.TT 6.6.2-9
+An undefined function result is not detected,
+because it is never used in an expression.
+.sp
+.TT 6.6.5.3-6
+.TT 6.6.5.3-7
+Disposing a variable while it is in use as actual variable parameter or
+as an element of the record variable list of a with-statement is not detected.
+.sp
+.TT 6.6.5.3-8
+.TT 6.6.5.3-9
+.TT 6.6.5.3-10
+It is not detected that a record variable, created with the variant form
+of new, is used as an operand in an expression or as the variable in an
+assignment or as an actual value parameter.
+.sp
+.TT 6.6.5.3-11
+Use of a variable that is not reinitialized after a dispose is
+not detected.
+.sp
+.TT 6.6.6.4-4
+.TT 6.6.6.4-5
+.TT 6.6.6.4-7
+.I2
+There are no range checks for pred, succ and chr.
+.sp
+.TT 6.6.6.5-6
+ACK-Pascal considers a rewrite of a file as a defining
+occurence.
+.sp
+.TT 6.7.2.2-8
+.TT 6.7.2.2-9
+.TT 6.7.2.2-10
+.TT 6.7.2.2-12
+.I2
+Division by 0 or integer overflow is not detected.
+.sp
+.TT 6.8.3.9-18
+The use of the some control variable in two nested for
+statements in not detected.
+.sp
+.TT 6.8.3.9-19
+Access of a control variable after leaving the loop results in
+the final-value, although an error should be produced.
+.sp
+.TT 6.9.3.2-3
+The program stops with a file not open error.
+The rewrite before the write is missing in the program.
+.sp
+.TT 6.9.3.2-4
+.TT 6.9.3.2-5
+Illegal FracDigits values are not detected.
+.CH "Implementation dependence"
+Number of tests run = 14
+.br
+Number of tests incorrectly handled = 0
+.SH "Details of implementation dependence"
+.IS
+.TT 6.1.9-5
+Alternate comment delimiters are implemented
+.sp
+.TT 6.1.9-6
+The equivalent symbols @ for ^, (. for [ and .) for ] are not
+implemented.
+.sp
+.TT 6.4.2.2-10
+Maxint = 32767
+.sp
+.TT 6.4.3.4-5
+Only elements with non-negative ordinal value are allowed in sets.
+.sp
+.TT 6.6.6.1-1
+Standard procedures and functions are not allowed as parameters.
+.sp
+.TT 6.6.6.2-11
+Details of the machine characteristics regarding real numbers:
+.IS
+.nf
+beta =       2
+t =         56
+rnd =        1
+ngrd =       0
+machep =   -56
+negep =    -56
+iexp =       8
+minexp =  -128
+maxexp =   127
+eps =     1.387779e-17
+epsneg =  1.387779e-17
+xmin =    2.938736e-39
+xmax =    1.701412e+38
+.fi
+.IE
+.sp
+.TT 6.7.2.3-3
+.TT 6.7.2.3-4
+All operands of boolean expressions are evaluated.
+.sp
+.TT 6.8.2.2-1
+.TT 6.8.2.2-2
+The expression in an assignment statement is evaluated
+before the variable selection if this involves pointer
+dereferencing or array indexing.
+.sp
+.TT 6.8.2.3-2
+Actual parameters are evaluated in reverse order.
+.sp
+.TT 6.9.3.2-6
+The default width for integer, Boolean and real are 6, 5 and 13.
+.sp
+.TT 6.9.3.5.1-2
+The number of digits written in an exponent is 2.
+.sp
+.TT 6.9.3.6-1
+The representations of true and false are (~true) and (false).
+The parenthesis serve to indicate width.
+.IE
+.CH "Quality measurement"
+Number of tests run = 60
+.br
+Number of tests handled incorrectly = 1
+.SH "Results of tests"
+Several test perform operations on reals on indicate the error
+introduced by these operations.
+For each of these tests the following two quality measures are extracted:
+.sp
+.in +5
+maxRE:~~maximum relative error
+.br
+rmsRE:~~root-mean-square relative error
+.in -5
+.sp 2
+.IS
+.TT 1.2-1
+.I1
+25 thousand Whetstone instructions per second.
+.I2
+169 thousand Whetstone instructions per second.
+.sp
+.TT 1.2-2
+The value of (TRUEACC-ACC)*2^56/100000 is 1.4 .
+This is well within the bounds specified in [3].
+.br
+The GAMM measure is:
+.I1
+238 microseconds
+.I2
+26.3 microseconds.
+.sp
+.TT 1.2-3
+The number of procedure calls calculated in this test exceeds
+the maximum integer value.
+The program stops indicating overflow.
+.sp
+.TT 6.1.3-3
+The number of significant characters for identifiers is 8.
+.sp
+.TT 6.1.5-8
+There is no maximum to the line length.
+.sp
+.TT 6.1.5-9
+The error message "too many digits" is given for numbers larger
+than maxint.
+.sp
+.TT 6.1.5-10
+.TT 6.1.5-11
+.TT 6.1.5-12
+Normal values are allowed for real constants and variables.
+.sp
+.TT 6.1.7-14
+A reasonably large number of strings is allowed.
+.sp
+.TT 6.1.8-6
+No warning is given for possibly unclosed comments.
+.sp
+.TT 6.2.1-12
+.TT 6.2.1-13
+.TT 6.2.1-14
+.TT 6.2.1-15
+.TT 6.5.1-2
+Large lists of declarations are possible in each block.
+.sp
+.TT 6.4.3.2-6
+An 'array[integer] of' is not allowed.
+.sp
+.TT 6.4.3.2-7
+.TT 6.4.3.2-8
+Large values are allowed for arrays and indices.
+.sp
+.TT 6.4.3.3-14
+Large amounts of case-constant values are allowed in variants.
+.sp
+.TT 6.4.3.3-15
+Large amounts of record sections can appear in the fixed part of
+a record.
+.sp
+.TT 6.4.3.3-16
+Large amounts of variants are allowed in a record.
+.TT 6.4.3.4-4
+Size and speed of Warshall's algorithm depend on the
+implementation of EM:
+.IS
+.I1
+.br
+size: 122 bytes
+.br
+speed: 5.2 seconds
+.sp
+.I2
+.br
+size: 196 bytes
+.br
+speed: 0.7 seconds
+.IE
+.TT 6.5.3.2-3
+Deep nesting of array indices is allowed.
+.sp
+.TT 6.5.3.2-4
+.TT 6.5.3.2-5
+Arrays can have at least 8 dimensions.
+.sp
+.TT 6.6.1-8
+Deep static nesting of procedure is allowed.
+.sp
+.TT 6.6.3.1-6
+Large amounts of formal parameters are allowed.
+.sp
+.TT 6.6.5.3-12
+Dispose is fully implemented.
+.sp
+.TT 6.6.6.2-6
+Test sqrt(x): no errors.
+The error is within acceptable bounds.
+.in +5
+maxRE:~~2~**~-55.50
+.br
+rmsRE:~~2~**~-57.53
+.in -5
+.sp
+.TT 6.6.6.2-7
+Test arctan(x): may cause underflow or overflow errors.
+The error is within acceptable bounds.
+.in +5
+.br
+maxRE:~~2~**~-55.00
+.br
+rmsRE:~~2~**~-56.36
+.in -5
+.sp
+.TT 6.6.6.2-8
+Test exp(x): may cause underflow or overflow errors.
+The error is not within acceptable bounds.
+.in +5
+maxRE:~~2~**~-50.03
+.br
+rmsRE:~~2~**~-51.03
+.in -5
+.sp
+.TT 6.6.6.2-9
+Test sin(x): may cause underflow errors.
+The error is not within acceptable bounds.
+.in +5
+maxRE:~~2~**~-38.20
+.br
+rmsRE:~~2~**~-43.68
+.in -5
+.sp
+Test cos(x): may cause underflow errors.
+The error is not within acceptable bounds.
+.in +5
+maxRE:~~2~**~-41.33
+.br
+rmsRE:~~2~**~-46.62
+.in -5
+.sp
+.TT 6.6.6.2-10
+Test ln(x):
+The error is not within acceptable bounds.
+.in +5
+maxRE:~~2~**~-54.05
+.br
+rmsRE:~~2~**~-55.77
+.in -5
+.sp
+.TT 6.7.1-3
+.TT 6.7.1-4
+.TT 6.7.1-5
+Complex nested expressions are allowed.
+.sp
+.TT 6.7.2.2-14
+Test real division:
+The error is within acceptable bounds.
+.in +5
+maxRE:~~0
+.br
+rmsRE:~~0
+.in -5
+.sp
+.TT 6.7.2.2-15
+Operations of reals in the integer range are exact.
+.sp
+.TT 6.7.3-1
+.TT 6.8.3.2-1
+.TT 6.8.3.4-2
+.TT 6.8.3.5-15
+.TT 6.8.3.7-4
+.TT 6.8.3.8-3
+.TT 6.8.3.9-20
+.TT 6.8.3.10-7
+Static deep nesting of function calls,
+compound statements, if statements, case statements, repeat
+loops, while loops, for loops and with statements is possible.
+.sp
+.TT 6.8.3.2-2
+Large amounts of statements are allowed in a compound
+statement.
+.sp
+.TT 6.8.3.5-12
+The compiler requires case constants to be compatible with
+the case selector.
+.sp
+.TT 6.8.3.5-13
+.TT 6.8.3.5-14
+Large case statements are possible.
+.sp
+.TT 6.9-2
+Recursive IO on the same file is well-behaved.
+.sp
+.TT 6.9.1-6
+The reading of real values from a text file is done with
+sufficient accuracy.
+.in +5
+maxRE:~~2~**~-54.61
+.br
+rmsRE:~~2~**~-56.32
+.in -5
+.sp
+.TT 6.9.1-7
+.TT 6.9.2-2
+.TT 6.9.3-3
+.TT 6.9.4-2
+Read, readln, write and writeln may have large amounts of
+parameters.
+.sp
+.TT 6.9.1-8
+The loss of precision for reals written on a text file and read
+back is:
+.in +5
+maxRE:~~2~**~-53.95
+.br
+rmsRE:~~2~**~-55.90
+.in -5
+.sp
+.TT 6.9.3-2
+File IO buffers without trailing marker are correctly flushed.
+.sp
+.TT 6.9.3.5.2-2
+Reals are written with sufficient accuracy.
+.in +5
+maxRE:~~0
+.br
+rmsRE:~~0
+.in -5
+.IE
+.CH "Level 1 conformance tests"
+Number of test passed = 4
+.br
+Number of tests failed = 1
+.SH "Details of failed tests"
+.IS
+.TT 6.6.3.7-4
+An expression indicated by parenthesis whose
+value is a conformant array is not allowed.
+.IE
+.CH "Level 1 deviance tests"
+Number of deviations correctly detected = 4
+.br
+Number of tests not detecting deviations = 0
+.IE
+.CH "Level 1 error handling"
+The results depend on the EM implementation.
+.sp
+Number of errors correctly detected =
+.in +5
+.I1
+1
+.I2
+0
+.in -5
+Number of errors not detected =
+.in +5
+.I1
+0
+.I2
+1
+.in -5
+.SH "Details of errors not detected"
+.IS
+.TT 6.6.3.7-9
+.I2
+Subrange bounds are not checked.
+.IE
+.CH "Level 1 quality measurement"
+Number of tests run = 1
+.SH "Results of test"
+.IS
+.TT 6.6.3.7-10
+Large conformant arrays are allowed.
+.IE
+.CH "Extensions"
+Number of tests run = 3
+.SH Details of test failed
+.IS
+.TT 6.1.9-7
+The alternative relational operators are not allowed.
+.sp
+.TT 6.1.9-8
+The alternative symbols for colon, semicolon and assignment are
+not allowed.
+.sp
+.TT 6.8.3.5-16
+The otherwise selector in case statements is not allowed.
+.IE
+.CH "References"
+.ti -5
+[1]~~\
+A.S.Tanenbaum, E.G.Keizer, J.W.Stevenson, Hans van Staveren,
+"Description of a machine architecture for use with block structured
+languages",
+Informatica rapport IR-81.
+.ti -5
+[2]~~\
+ISO standard proposal ISO/TC97/SC5-N462, dated February 1979.
+The same proposal, in slightly modified form, can be found in:
+A.M.Addyman e.a., "A draft description of Pascal",
+Software, practice and experience, May 1979.
+An improved version, received March 1980,
+is followed as much as possible for the
+current ACK-Pascal.
+.ti -5
+[3]~~\
+B. A. Wichman and J du Croz,
+A program to calculate the GAMM measure, Computer Journal,
+November 1979.