Page Numbers: Yes X: 530 Y: 10.5" First Page: 13
Margins: Top: 1.3" Bottom: 1"
Heading:
Micro: Machine-Independent MicroAssembler11 July 1980
7.3 Tokens
The rules for delimiting clauses into tokens have been carefully chosen to permit the user of Micro to write readable programs. The parsing of statements is strictly right-to-left and the following definitions are required in explanation:
An L-token terminates the token to its left.
An R-token terminates the token to its right.
Then:
(Rgroup delimiter
)Lgroup delimiter
[Lbuiltin argument list delimiter
]builtin argument list delimiter
,LRclause delimiter
:LRclause delimiter which takes the preceding token as an address in the current memory at the current address
LRseparator which is part of the symbol to its left
Any text with an R-token to its left and an L-token to its right constitutes a token called a symbol whose meaning is determined by looking it up in the symbol table. Text enclosed in parentheses is lexically independent of anything outside, and a parenthesized string of text is lexically equivalent to the "tail" which its evaluation produces. The following example clarifies this.
In the expression:
FOO5(FOOl[FOO2]FOO3[FOO4])FOO6[FOO7]
the order in which expansions are recognized assuming that each FOO expansion leaves behind no text is:
FOOl[FOO2]
FOO3[FOO4]
FOO5FOO6[FOO7]
7.4 Neutrals and Tails
The handling of tails, a distinguishing peculiarity of Micro, works as follows. The tail is initialized to the nulstring at the start of processing a clause. When a neutral symbol is recognized using the rules for delimiting tokens (previous section), it is concatenated on the left of a string called the tail thusly:
temp ← concatenate (symbol, tail);
if tail eq null do;
tail ← temp;
else do;
tail ← null;
treat temp as a symbol;
end;
Parentheses push down the current tail and start a new null one. When the text inside is completely processed, its tail (null or neutral) is treated as though it were a string which had appeared without parentheses.
The use of neutral tails permits complicated machines like Maxc and Dorado to be described by a relatively small number of macros and neutrals. The following example shows how this works.
Maxc has about 30 bus sources and 30 bus destinations, but not all combinations of source and destination are legal (a slow source may not feed a slow destination). An example using the bus is:
MDR←X
X is a macro that expands to a store into the bus source field of the microinstruction and leaves behind the neutral symbol B. MDR←, the next token recognized, is a macro that expands into a store into the bus destination field and leaves behind the neutral symbol B←. B←B is the next token recognized. Since the connection of a fast bus source to a fast bus destination is legal, B←B has also been entered into the symbol table as a macro equivalent to the neutral symbol B.
If B← could not have been legally connected to B, then the B←B macro would not have been defined, and Micro would have output an error like "B←B undefined" when assembling the statement.
Thus the number of symbols which must be defined for describing bus sources and destinations is roughly l/source plus l/destination plus a small number of macros to describe legal connections of a class of sources to a class of destinations. Each class of objects is represented by a neutral symbol.
In other words, the connection concept, which neutral tails implement, decouples sources and destinations inside the language definition file. In conjunction with the peculiar handling of "←", this permits a natural assembly language to be defined in which the programmer thinks of sources flowing over buses to destinations. It is impossible to create a natural language of this type with an ordinary macroassembler.
Here is a more complicated example:
STEMP←MDR←(RTEMP←P) U (X)
In this example (from Maxc1), there is an interior routing of data from P (a register) to RTEMP (an address in the RM memory); this routing moves data from P through the ALU and into RTEMP. The ALU data is also routed onto B (a bus) where it is or’ed with data from X (a register). Then the bus data is written into MDR (a register) and into STEMP (an address in the SM memory). A crude outline of the way this is assembled is as follows:
P is a macro that stores the P control in the ALUF field of the microinstruction and leaves the neutral ALU;
RTEMP← is recognized as an RM destination (details later); its address is stored in the RA field leaving the neutral RB←;
RB←ALU is a (connection) macro, leaving the neutral ALU behind;
X is a macro that stores the code for B←X into the BS field of the microinstruction leaving the neutral B;
ALUUB is a (connection) macro that stores the code for B←ALU into the F1 field and leaves the neutral B;
MDR← is a macro that stores the code for MDR←B into the BD field leaving the neutral B←;
B←B is a (connection) macro leaving the neutral B;
STEMP← is recognized as an SM destination (details later); its address is stored in the SA field leaving the neutral SB←;
SB←B is a (connection) macro that stores the code for loading SM into the F2 field leaving the neutral B;
B is the final tail which is thrown away.
This example is as complicated as any we have used in real assemblers thus far. The construction of "(..) U (..)" to represent merging different sources on a bus is used systematically throughout the Maxc microlanguage; sources can be given in arbitary order so, in the above example, (X) U (RTEMP←P) would also assemble. All of these factors contribute to an easily readable, easily rememberable assembly language.
In the above example, the assembler also successfully concealed some complicated alternate encoding issues from the programmer. B←ALU could have been encoded in either the BS or F1 fields; the assembler picked F1 since BS was needed for B←X. SB←B could have been encoded in either BD, F1, or F2; the assembler picked F2 because BD and F1 had already been used. These are some of the issues that the designer of a microlanguage must consider.
7.5 Clause Evaluation
When a clause is broken into top level tokens, the possible resulting symbol types and actions are given by the table below:
Table 2: Top Level Evaluation
Symbol typeAction
undefinedSee section 7.7
integerError message and abort clause expansion
address[clauselist]Carry out a store of the word assembled by the clauselist at the location and memory of the address, and then increment the integer part of the address symbol.
address SYMReplace by sourcemacro[SYM] (section 13)
address SYM←Replace by sinkmacro[SYM] (sections 7.7, 13)
unbound addressError message
MNAME[SYM,integer]Create an address symbol "SYM" in memory MNAME with value "integer"
FNAME[address]Store IP[address] in field FNAME (section 11)
FNAME[integer]Store integer in field FNAME
FNAME[undefined]Generate forward reference for eventual field assignment at end of assembly or by MIDAS.
macro [args]Expand it (section 9)
macroExpand it
neutralSee sections 7.4, 10
neutral [args]Error message
builtin [args]Call the builtin function (Table 1) with arguments handled as discussed in section 7.6
Ultimately, the original clause must reduce through macro and neutral expansions to a series of field assignments, preassignments, and builtin calls with a neutral symbol in the "tail." The neutral symbol is then thrown away and the next clause is evaluated.
7.6 Treatment of Arguments
Many symbol types may be followed by argument lists. The only difference among these is that fields, memories, addresses, and most builtins must be followed by an exact number of arguments. Macros, on the other hand, may have surplus arguments (ignored) or deficient arguments (nulstrings supplied). Conditionals may omit arguments (nulstrings supplied).
The nulstring argument is special in the following sense. If it appears where an integer result is wanted, it is equivalent to the value 0 (except for the AND builtin, where it is equivalent to 177777); if it appears where a string is wanted, it is the nulstring; and, if it is looked up, it is undefined. Micro does not allow the programmer to define the nulstring as a symbol.
Each builtin may choose one of three basic ways to receive its arguments: quoted, looked up in the symbol table, or evaluated. Some languages have a step short of evaluation which might be called "macro expansion", but Micro does not make any distinction between macro expansion and complete evaluation of an argument. However, if a string of the form
NAME[arguments]:
occurs in a clause being evaluated, NAME[arguments] is expanded until a string is left without brackets or parentheses, and then this string is the one affected by the ":". However,
IFDEF[NAME[arguments], ...]
which looks up its first argument, will look up the entire string including the brackets. This is a limitation of Micro which may someday be repaired. It prevents symbol names from being generated in some situations.
The exact meaning of "look up" and "evaluate" changes with the builtin. Those builtins which "lookup" an argument generally do so for a symbol type check or to decide what action to carry out based upon the symbol type. There is no way for macro definitions to get at symbol types. Only builtins can do this. This is an unfortunate limitation of Micro.
Argument evaluation is slightly different from clause evaluation. For example, evaluating the argument for the field assignment FNAME[VALUE] takes place as follows: evaluate the tokens in the argument right-to-left expanding all macros and neutrals, looking for one of the following:
l)Address: Use its integer part to complete the field assignments discussed in section 11.
2)Unbound address: Generate a forward reference.
3)Undefined symbol: Create an unbound address and generate a forward reference.
4)Integer: Complete the assignment as discussed in section 11.
If the argument is the nulstring, put the integer 0 into the field. If the argument is a neutral symbol, if any text is left when the address, integer, or undefined symbol is found, generate an error.
Note that a neutral symbol results in no error for clause evaluation, but an error for a field assignment while an integer results in an error in a clause but no error in an assignment. Other builtins which evaluate their arguments may have different requirements.
For example, the integer builtin ADD (see section 8) accepts only integer arguments. Address [clauselist] evaluates the clauselist exactly as if it had occurred at the top level. In all cases, if part of the argument being evaluated is in parentheses, that part is evaluated exactly as if it had occurred at the top level.
7.7 Undefined Symbols
The print-name of a symbol is a character string by which the symbol can be referred to in the source. However, when the lexical scan finds a string S of characters which is a symbol token (delimited by L or R-tokens), it looks for a symbol with print-name S. If no such symbol exists, an error is indicated except in the following cases:
7.7.l Destination Addresses
S ends with ←. In this case the ← is stripped off and the resulting string S’ is looked up. If S’ is an address in memory MEM, S is replaced by MEMSINK[S’] as discussed in section 11.
7.7.2 Octal Numbers
S consists entirely of octal characters with an optional leading "-" sign. In this case it is treated like a symbol of type integer whose value is the octal number. Note that integers may not be larger than l6 bits. Micro does not allow an integer string to be entered into the symbol table, which would usurp the natural use of that integer.
7.7.3 Literals
S starts with an octal character or with a "-" followed by an octal character. In this case the "-" (if any) is stripped off and the rest is split into a head OCT and a tail SYM such that OCT consists entirely of octal characters and SYM does not start with an octal character. Then the macro SYM or -SYM is called as described below.
The first argument of SYM is the four right-most octal characters. The second argument is the next four octal characters, and so on until the octal characters are used up. For example,
3743652l000Vand
-1234567V
are replaced by
V[l000,3652,374]and
-V[4567,123].
The awkwardness of the l6-bit limitation for integers is clearly pointed out by this kludge. Clearly V[3743652l000] would have been much easier to work with and would have been possible if the integer size was greater than or equal to the memory size. Also, going from a three-integer 36-bit result back to a text string is made impractical by the integer size limit.
8. Integers
Micro permits use of integer variables constrained to l6 bits.
SET[NAME,VALUE]
looks up its first argument and evaluates its second with the following results:
Type of NameType of ValueAction
UndefinedIntegerEnter NAME in the symbol table with type integer and value VALUE.
IntegerIntegerChange the value of NAME to VALUE.
All other combinations are errors.
The following builtins accept integers as arguments and produce an integer as value:
ADD[i0, i1, ... , i7]Sums i0 ... i7
SUB[i0, i1, ... , i7]
Subtracts the sum of i1 ... i7 from i0
NOT[i0]
1’s complement of i0
OR[i0, i1, ... , i7]
Inclusive-or of i0 ... i7
XOR[i0, i1, ... , i7]
Exclusive-or of i0 ... i7
AND[i0, i1, ... , i7]
And of i0 ... i7
LSHIFT[i0, i1]
Logical left-shifts the integer i0 by i1 bits
RSHIFT[i0, i1]
Logical right-shifts the integer i0 by i1 bits
In these, omitted arguments are 0’s for every operation except AND, which supplies 177777 (i.e., -1) for omitted arguments. Note that octal strings may begin with an optional "-". However, the negative of an integer-valued symbol cannot be obtained by inserting a leading "-"; -(ISYM) will not work, either.
The value of these integer operations is the unsigned octal string representing the result. Example: ADD[3, 4, l5]S is equivalent to 24S.
IP[ANAME], where ANAME must be an address, is the integer part of the address. This must be done when an address is used in an arithmetic or set expression. (It is not reasonable to automatically take the integer part of an address because of confusion between its use as a source and its use as an integer).
FVAL[FNAME], where FNAME must be a field, is the integer contents of the field FNAME in the word currently being assembled. If nothing has been stored in that field yet, then the contents are whatever value was setup by the DEFAULT statement for the current memory, or are 0, if no DEFAULT statement applies.
9. Macros
A symbol can be given a macro value by the clause
M[NAME, body]
where the body is an arbitrary balanced string of characters (i.e., parentheses and brackets match up and are nested). Occurrences of the text
#digit
in the body will be replaced by the corresponding actual parameters (counting left-to-right from l) when the macro is called. Unsupplied arguments are nulstrings, surplus arguments are ignored, and #0 will be replaced by the number of arguments supplied.
The lexical scan of a statement is done from right to left. Whenever a symbol S is detected, it is looked up. If S turns out to be a macro, then the macro body replaces both S and the bracketed argument list immediately to the right of S, if there is one. Thus after
M[FOO, MUMBLE#l];
the text FOO[E]D; expands into MUMBLEED; note that D is not a symbol since ] is not an R-token. Note that the macro body is quoted and that Micro has no provision for getting any part of it expanded at definition time.
Due to the way in which macro bodies are stored in the Micro symbol table symbols used in the macro body should be defined before the macro is defined when feasible. Assembly will be quicker if this rule is followed.
10. Neutrals
A symbol which has been declared neutral by a clause of the form
NEUTRAL[SYM]
is concatenated with the tail and handled as discussed in section 7.4.
11. Fields, Assignments, and Preassignments
FIELD[FNAME, leftbit, rightbit] causes a symbol of type field to be created. Leftbit and rightbit must evaluate to integers. Also, because of the Alto’s l6-bit integer size, the field should not be wider than l6 bits or else some bits of the field could never be set. Finally, leftbit must be in the range [0, 255] and rightbit in the range [leftbit, min(leftbit+l5, 255)].
Clauses of the form
FNAME[integer];
FNAME[address];
FNAME[unbound address]; or
FNAME[undefined];
where FNAME is a field, are used to construct memory words. A field assignment evaluates its argument in the manner discussed in section 7.6.
Field assignments also have the property that attempting more than one assignment to a field in a statement will cause an error unless the new value = old value. (When an error occurs, the value ultimately left in a field is that of the final assignment to it.) Forward references fixup the true value later.
The preassignment
PF[FNAME, integer]
does nothing if any bits of FNAME have previously been assigned. Otherwise, it is equivalent to FNAME[integer] except that a later assignment will overrule the preassignment and cause no error. Forward references are illegal in preassignments.
The integer value stored in any field of the memory word currently being assembled may be obtained by using
FVAL[FNAME].
If the field has not yet been set, FVAL returns the default value.
13. Conditionals
There are a number of builtins which will substitute the text represented by one of their arguments if the other arguments meet some condition. These are called conditionals, summarized in Table 2.
A conditional and the argument list to its right are equivalent to the "true" string, if the specified condition is met, or the "false" string, if it is not met. Note that any number of arguments may be omitted. The true and false strings may be any balanced strings of characters.
Although these conditionals can be used at the top level, they are intended for use inside macro definitions, and the string compare conditional could be used sensibly only inside macro definitions.
Table 2: Conditionals
FormCondition
IFE[il, i2, (true), (false)]il = i2
IFG[il, i2, (true), (false)]
il > i2
IFDEF[sl, (true), (false)]
sl in symbol table and not unbound address
IFSE[sl, s2, (true), (false)]
sl = s2
IFA[field, (true), (false)]
any bit of field previously assigned
IFME[address, sl, (true), (false)]
memory name for address = string
Note that the text in the selected arm of a conditional is concatenated with the text to the right of the conditional before evaulation, so
IFE[2,1,FOO,GLOT]AB
will evaulate GLOTAB.
13. Memories, Addresses, and Stores
MEMORY[MEM, wordlength, length, sourcemacro, sinkmacro]
causes creation of a memory. Micro can manage a reasonable number (l5) of these memories, subject to a 255-bit word-length limit and 64K-l length limit. Once MEM has been defined, symbols can be defined as addresses in MEM and words of MEM can be initialized.
An address ANAME in MEM is created by an expression of the form:
MEM[ANAME, integer]
or by using
ANAME:
in a clauselist which is stored in MEM.
Stores into MEM are generated either by selecting an address in MEM as the target (see section 13.1) or by writing
ANAME[(clauselist)]
which stores the word assembled by the clauselist into MEM at the location of the address ANAME and then increments ANAME. Note that the memory store and incrementing the address are done iff one or more field assignments or preassignments result from the clauselist.
The value stored is generated as follows: It is initialized according to the value assembled by the DEFAULT statement (0 if there has been no DEFAULT statement). Next, the clauselist is evaluated. Then the post macro for the memory, declared by the SETPOST builtin, is evaluated. Finally, if ANAME is out-of-bounds, an error message will occur.
The sourcemacro MSRC and sinkmacro MSINK are applied when the address ANAME appears in a clauselist. If ANAME is evaluated as a token in a clauselist without a following argument list, it is replaced by the string
MSRC[ANAME].
If ANAME← appears and is undefined, it is replaced by
MSINK[ANAME].
Note, however, that forward and external references can be generated only in the context
FNAME[ANAME],
not when ANAME is used as a source or sink.
13.1. Target Memory
At any time TARGET[ANAME] will set the target address to ANAME which means that a statement of the form
X: mumble;
where mumble must do at least one field assignment, is equivalent to
ANAME[(X: mumble)];
Otherwise, the target has no effect. Note that the target memory is not preserved in the /R file and must be given again for each assembly.
13.2. Default Statement
Before assembly of a clauselist for storage into a memory MEM, the word is initialized to a value which may be overruled by the various assignments in the clauselist. Normally, the initial value is 0, but this may be changed by the statement
DEFAULT[MEM, (clauselist)];
which assembles clauselist into a value that will subsequently initialize words being assembled for MEM. Note that forward references are not permitted in the clauselist and that any of the default settings may be overruled by explicit assignments in a statement being assembled.
13.3. Post Macros
SETPOST[MNAME,POSTMACRO]
arranges things so that the macro POSTMACRO will be called just after a word has been assembled for the memory named MNAME but just before the word is output to the binary file. If POSTMACRO is null, SETPOST simply turns off this feature for the memory MNAME.
14. Repeat and While
REPEAT[il,TEXT]
assembles TEXT il times. This is used primarily for initializing blocks of memory and for replicating nearly-identical instructions in diagnostics.
Since TEXT cannot include ";" stores to the target memory must be put in explicitly. In other words, the program cannot rely on the TARGET directive to insert "ILC[TEXT]" or whatever each time TEXT is repeated. Note that the statement buffer is cleared after each assembly of TEXT.
WHILE[il,TEXT]
evaluates the expression i1, which must evaluate to an integer; so long as the result is non-zero, TEXT will be evaluated and the while will repeat.
15. Select
The SELECT builtin corresponds to the Bcpl switchon (case selection) statement. Its form is
SELECT[index,text0,text1, ... , textn]
and its effect is to replace itself with one of text0, text1, ..., textn depending on whether the value of index is 0, 1, ..., n. Note that although index is evaluated and must produce an integer result, the text arguments may be any balanced strings, just as in the comparison builtins IFE, IFG, etc. If the index does not have a value in the range 0 through n, an error results.
16. Bit Tables
Several builtins manipulate bittables. The rationale for bittables in Micro is the existence of microprocessors (such as the Alto) in which the addressing structure imposes constraints on the locations of certain instructions, and for which the assembler must therefore keep track of precisely which locations have already been used for instructions. The bittable facilities in Micro are adequate for this task in simple cases.
The builtin
BITTABLE[table,n]
makes table a bittable of size n (the bits are numbered from 0 through n-1). All the bits in the bittable are initially zero.
GETBIT[table,i]
returns the value of the i’th bit in the table, 0 or 1. Setting bits is a little more complicated.
SETBIT[table,i,n,delta,val]
sets n bits in table starting with the i’th bit and going up by increments of delta (i.e., bits i, i+delta, ..., i+(n-1)*delta) to val; however, SETBIT may be called with any number of arguments from 2 to 5, with the omitted trailing arguments defaulted as follows: n=1, delta=1, val=1.
There is a builtin similar to SETBIT for locating patterns of 0-bits (available locations) in a table:
FINDBIT[table,i,n,delta,hop,count]
starts out seeing if bits i, i+delta, ..., i+(n-1)*delta in table are all zero. If so, FINDBIT returns the initial location i. If not, it increments i by hop and tries again, until it has tried a total of count times. If the search fails, FINDBIT returns a null string. As for SETBIT, FINDBIT will supply default values for trailing arguments: n=1, delta=1, hop=1, count=177777 (infinity, i.e., until the size of the bit table is reached). The idea is that, for example, to find a pair of consecutive free locations whose last 3 address bits are 110, 111 respectively, you would use FINDBIT[table,6,2,1,10].
17. Multi-Statement Conditionals
The ASMMODE builtin is used for multi-statement conditional assemblies. ASMMODE[0] is normal and is the initial setting; in this case all statements are assembled normally. ASMMODE[1] disables normal assembly; in this case only statements beginning with the ":" character are evaluated--other statements are flushed.
The following collection of macros shows how conditional assembly of statements nested up to four levels deep can be accomplished:
SET[ALEV,0];*Number of nested :IF’s
SET[ASMF,1];
*1 if assembling, 0 if not assembling
SET[ASML,1];
*1 if assembling at this level, 0 if ignoring
SET[L1,0]; SET[L2,0]; SET[L3,0]; SET[G1,0]; SET[G2,0]; SET[G3,0];
M[NOIF,ER[No.:IF.preceding.:#1]];
M[IF,SELECT[ALEV,,
SET[L1,ASML] SET[G1,ASMF],
SET[L2,ASML] SET[G2,ASMF],
SET[L3,ASML] SET[G3,ASMF],
ER[:IF’s.nested.more.than.4.levels,1]]
SET[ALEV,ADD[ALEV,1]] SET[ASML,ASMF]
IFE[ASML,1,
IFE[#1,0,ASMMODE[1] SET[ASMF,0],ASMMODE[0] SET[ASMF,1]]]
];
M[ELSEIF,IFE[ALEV,0,NOIF[ELSEIF],
IFE[ASML,1,IFE[ASMF,1,SET[ASMF,0] SET[ASML,0] ASMMODE[1],
SET[ASMF,#1] ASMMODE[IFE[ASMF,0,1,0]]]]]
];
M[ELSE,IFE[ALEV,0,NOIF[ELSE],
IFE[ASML,1,IFE[ASMF,1,SET[ASMF,0] SET[ASML,0] ASMMODE[1],
ASMMODE[0] SET[ASMF,1]]]]
];
M[ENDIF,SELECT[ALEV,
NOIF[ENDIF],
SET[ASMF,1] SET[ASML,1],
SET[ASML,L1] SET[ASMF,G1],
SET[ASML,L2] SET[ASMF,G2],
SET[ASML,L3] SET[ASMF,G3]]
SET[ALEV,SUB[ALEV,1]]
IFE[ASMF,1,ASMMODE[0]]
];
Using these macros, programs can use the following statements for conditional assembly:
:IF[IM16K];
... statements for IM16K ne 0 ...
:ELSEIF[IM8K];
... statements for IM8K ne 0 ...
:ELSE;
... statements for IM16K and IM8K both 0 ...
:ENDIF;
... undonditionally assembled statements ...
18. Trace Mode
The TRACEMODE builtin is used to produce a trace of the assembly on the .ER file. This aims at debugging complicated macros and at performance tuning of definition files. The format of the trace output is not particularly pretty but is self-explanatory.
TRACEMODE[n,v] turns on tracing feature n if v is unequal to 0, or turns it off if v is zero. n=0 traces symbol table insertions; n=1 traces all applications of the form name[args].

Appendix 1. Micro Error Messages
Micro error messages are enumerated below, in which the character @ should be replaced by the printname of the token related to the error. Unless marked with a 1, assembly continues from the error with no special action; errors marked with 1 terminate assembly.
Program Organization Errors
SOURCE FILE @ DOES NOT EXIST1
COULD NOT OPEN FILE @ FOR ’INSERT’1
STORAGE FULL1
Storage required during the assembly is roughly proportional to the following computation:
l/2*Sum [namelength +l] for all symbols
+ 6* no. symbols
+ l/2*Sum [length +l] of all macro definitions.
When this number is greater than the size of the buffer (approx. ? Alto words), the STORAGE FULL message results.
TOO MANY MEMORIES1
Limit is currently l5 memories.
Declaration Errors
@ ALREADY DEFINED
The new definition will replace the old and this warning message will be printed.
MACRO @ REDEFINED
Just a warning (doesn’t increment error count)
ARG NOT A MEMORY NAME
For DEFAULT, which requires an argument to be of type memory.
UNDEFINED SYMBOL @ IN ’DEFAULT’1
BAD PARAMETERS FOR ’F’
A field may not be larger than l6 bits nor a memory wider than 256 bits, so rightbit > 255 or rightbit-leftbit > l6 are field definition errors.
MEMORY @ ALREADY USED1
ILLEGAL WIDTH OR SIZE FOR ’MEMORY’1
Limits are 256 bits wide and 64K-l in size
WRONG NO. ARGS FOR ’@’
Only for those builtins which must have correct number of arguments.
Macros may have too many or too few.
ILLEGAL BUILTIN NUMBER FOR ’@’1
Statement Assembly Errors
END OF FILE INSIDE COMMENT
Terminates comment and forges ahead
INPUT STATEMENT TOO LONG
Maximum length is 500 characters. Text to the right of the 500th character is truncated.
STATEMENT TOO LONG
During macro expansion of the input statement, the unprocessed text is never permitted to exceed 500 characters. Text to the right is truncated.
MACRO ARGUMENT STORAGE FULL
Truncates characters right-to-left up to matching ’[’ and proceeds.
SYMBOL @ NOT LEGAL AS TOKEN
Symbol appears without its required argument list.
@ MAY NOT BE FOLLOWED BY [ ]
Only macros, builtins, fields, addresses, and memories may have ’[’ to their right.
UNPAIRED ) OR ] IN ARGUMENT LIST
UNPAIRED )
UNPAIRED (
TOO MUCH NESTING OF ( ) AND [ ] IN CLAUSE
Limit is 8 levels
MISSING MACRO NAME OR TAG SYMBOL
No symbol to the left of a : or [.
MACRO ’@’ NOT DEFINED
Symbol to the left of a "[" wasn’t defined
TAG @ ALREADY DEFINED
’TARGET’ GIVEN AFTER FIELD SET1
NO TARGET FOR FIELD SET1
’TARGET’ NOT LEGAL INSIDE A STORE1
@ UNDEFINED
Not including forward references. Plunges ahead with value 0 and type integer
FIELD @ DOES NOT FIT IN MEMORY @
Right bit of field > right bit of memory
VALUE @ DOES NOT FIT IN FIELD @
Left bits of value truncated before store
ARG IN FIELD STORE NOT INTEGER OR ADDRESS
Doesn’t do field assignment and plunges ahead
FIELD @ ALREADY SET
The new value is stored into the field. This message will occur iff new value # old value.
ARG DOES NOT YIELD INTEGER VALUE
Assumes 0 and proceeds. Syntax OK but undefined symbol or address instead of integer.
BAD SYNTAX WHERE VALUE REQUIRED
Something complicated where a simple value expected
FIRST ARG OF ’PF’ NOT FIELD
No action
FORWARD REFERENCE NOT LEGAL IN ’PF’
No action
STORE TO @ OUT OF RANGE FOR @
@ BAD FIRST ARG FOR ’SET’
Must be integer or undefined symbol. However, redefinition will take place.
INTEGER ’@’ TOO LARGE
Integer MOD 2**l6 is used.
ARG NOT A FIELD NAME IN ’IFSET’

Appendix 2. Limitations of the Language
Micro lacks some features and possesses certain limitations discussed below:
1. It is impossible to relocate a microprogram at load time.
2. Forward and external references are permitted only on field assignments which means that the occurrence of
MDR←STEMP, or STEMP←MDR
where STEMP is an address in SM, cannot be assembled if STEMP is a forward or external reference. Forward references to symbols that are not addresses are also impossible.
3. Significant size limits:
a.Symbol table storage is tight.
b.Integers are limited to 16 bits.
4. It is impossible to check the memory part of an address on forward or external references. Nor is it possible for programs to get at the type of a symbol, at the parameters of a field or memory, or at the name of the target memory. The ’lookup’ capability of builtins is not available through any language constructs.
5. Macros which expand to more than one statement are impossible.
6. It is impossible to pull print names apart or to construct print names except by using neutral subsymbols. In particular, it is impossible to construct constants larger than 16 bits parametrically such that, if several constants contain the same value they can be assigned the same location. This is true because one cannot generate the print name "l420000S" (a literal) either directly from an integer or indirectly from the value assembled by assignments. (Note that if integers were large enough ADD[Pl, P2, ... , P7]S would generate the literal in S.)
7. There are a number of situations when part of an otherwise quoted argument wants to be expanded and there is no way to do this. For example,
IFDEF[FOO[E],(true clause),(false clause)]
should lead to expansion of the macro FOO[E] before checking for a defined symbol.
8. Blanks in user-defined error messages are impossible.
9. The REPEAT builtin should supply a ";" after each repetition of the text, so that the ILC[...] in REPEAT[n,(ILC[...])] can be omitted.
10. PF [field, value] was a bad choice because it makes parameterizing the values of a field impractical. For example, suppose that the function P←Pl is accomplished by setting the PS field to 50. What we would like to do is to define neutrals P← and Pl and then define the macro P←Pl as PS[50]. If the hardware is changed so that P←Pl is accomplished by PS[20] instead of PS[50], we would prefer to change only the one macro P←Pl. However, there are also several instances of PF[PS,50] which have to be found and changed and this is the reason why PF[field, value] was a bad choice. Instead, a preset-clauselist operation would have been better because then no other usage than P←Pl would be needed.
To prevent some of the above limitations or to otherwise streamline or augment the language, the following changes should be considered (the ones followed by ? or ?? or ??? are not serious proposals).
1. Make integers at least 36 bits long for MAXC, and consider variable length integers. Currently, considerable inconvenience results from "making do" with l6-bit integers. Also this would make it possible to get the literal equivalent of a constant constructed from parameters, which would allow merging identically-valued constants.
2. Provide a builtin like the one for defining fields except that it takes an additional argument which is a memory name:
AFIELD[AFNAME, leftbit, rightbit, memory].
AFNAME[address] works like FNAME[integer] except that its argument must expand to an address in "memory" rather than an integer, or if its argument is undefined, a forward address reference is assumed. Forward references to FNAME[undefined] would be illegal and FNAME[address] would be illegal. Unbound addresses would contain the memory type. This would permit memory checking of addresses very conveniently (currently it is cumbersome) and would permit forward references to be checked also (??).
3. Multi-statement macro definitions should be added. Perhaps "{" and "}" could be used syntactically to enclose multi-statement stuff.
4. It should be permissible for an argument list to appear to the right of a neutral symbol because of the following usage:
P←LB RSH [1]
where LBRSH is a neutral symbol, P← is a neutral symbol, and P←LBRSH is a macro. The argument list [1] should be preserved until P←LB RSH [1] is expanded.
5. In every place where an argument string is "looked up" for a builtin, all macros and neutrals should be expanded. In other words, "looking up" an argument should be identical to evaluating an argument, except that occurrence of any builtin causes an error. Expansion stops when a non-neutral non-macro symbol without brackets, parentheses, ←, or : is left.
6. Currently address← is handled by the assembler, but undefined← and macro← are not handled in any special way. Similarly, an undefined source is not handled. It might be useful to have these cases result in the substitutions UDEST[undefined], MDEST[macro] and USRC[undefined]. This would permit forward or external references to succeed where they don’t currently and would permit macros which expand to addresses to be used. MDEST, UDEST, and USRC should be macro names selectable by the programmer.
7. Currently the TARGET directive causes a top level statement to be equivalent to
TARGLC[(#1)];
where #1 stands for the top level statement. This could be changed to a general macro whose first argument is the clauselist of the statement. However, this would slow assembly.
8. Instead of causing an error, integer results should be treated at the top level as neutral symbols equal to the octal text string for the integer. This would permit arithmetic to be performed and the result concatenated with text to select one of many macros or address symbols.

Appendix 3. Binary Output Format
Micro outputs binary memory images as a series of short blocks of l6-bit words. Each block begins with a word that specifies the type of the block; the number and format of following words depend on the block type. During its pass through the source files, Micro outputs a message to the file Micro.fixups whenever it encounters an assignment
FNAME [NAME]
and NAME is undefined. At the end of processing the source files, Micro reads back Micro.fixups and outputs either a type 3 or type 6 message (see below) to the binary file depending upon whether the symbol was a forward reference or undefined. Finally, it orders new or changed address symbols by memory and outputs them to the binary file.
Midas can link up external address references at load time. Address symbols for Midas to use in linking up external references are output as described below.
Table 4: Micro Binary Output File Format
TypeFollowed byUse
0nothingIndicates the end of the binary file.
1source line # (1 word);
data (N words)Specifies a data word to go in the current memory at the current location. The current location is to be incremented. N is just large enough to cover the width of the memory, and the value is left-justified, e.g., for a 36-bit memory N=3 and the first word goes in bits 0:15, the second in 16:31, and bits 0:3 of the third in 32:35.

The source line # is zero if the word was generated by an INSERT file, and has bit 0 set if the word was generated in the main file by a STORE.
2memory # (1 word);
location (1 word)Sets the current memory and the current location. Memory numbers are related to memory names by type 4 blocks (see below).
3memory # (1 word);
location (1 word);
first bit * 256 + last bit (1 word);
value (1 word)Specifies a forward reference fixup. The value is to be stored into the given bits at the given location in the given memory. (Current memory and location settings are not affected.)
4memory # (1 word);
width of memory in bits (1 word);
symbolic name of memory (L words)
Correlates a memory number with a user-supplied name.
The name is packed 2 8-bit characters per word terminated by a null (all 0’s) character; L=(C+2)/2 where C is the number of characters in the name. The type 4 block defining a memory will appear before any type 2 or 3 blocks storing into that memory.
5memory # (1 word);
value (1 word);
address symbol name (L words)
Gives the definition of an address symbol. There is a type 5 block for every new or changed address symbol. All type 5 blocks appear together at the end of the binary file.
6memory # (1 word);
location (1 word);
first bit * 256 + last bit (1 word);
undefined symbol name (L words)
Specifies a reference to an undefined (external) symbol. The first three words have the same interpretation as for block type 3.
The Midas program accepts any of the block types above. In addition, Midas accepts the following compact block types which are more compact than the ones above and use less storage.
11block address (l word);
word count N (l word);
N data words;The left-half of the word containing the type is the memory #. The N data words are in the same form as block type 1.
12address (l word);
Bcpl string (L words);The left-half of the word containing the type is the memory #. The first word of the Bcpl string contains a character count in the first byte (0:7), followed by the characters of the string.