-*-Text-*-  MIDAS Node: Top, Up: (DIR), Next: Basic Overview of MIDAS MIDAS is a PDP-10 assembler. It takes as its input an ASCII file, and produces a binary file in any of several formats (*Note Out: Output). NOTE: Numbers used in this document are assumed to be octal, unless followed by a "." in which case they are decimal. E.G. 12 = 10. = ten. * Menu: * Invoke:: How to invoke MIDAS. Commands strings. * Basic:: Introduction to MIDAS input syntax. * Example:: Simple example of MIDAS code. * Frame:: The beginning and end of a MIDAS program. * Words:: Syntax of the "Word" -- the fundamental MIDAS construct. * Fields:: Words are made up of fields, which are made of syllables. * Syllables:: A syllable is a number, symbol, etc. * DDT:: Communicating to DDT. * LocnCtr:: The "location counter" is used to assign storage locations to the words which MIDAS assembled. * Relocation:: Relocatable assemblies. * Symbols:: Defining symbols. * Numbers:: Hairy ways of writing numbers. * Literals:: Generating constants in memory where you want to use them. * Bytes:: Pseudos for working with bytes and byte pointers. * FileInfo:: How filenames can be accessed at assembly time. * Terminal:: Typing on the terminal. Reading from the terminal. * Macros:: MIDAS macros: definition and use. * Loops:: Assembly-time iterations for use with macros. * Cond:: Assembly conditionals. * .I.F:: .I and .F: the "arithmetic assignment" statements. * FASL:: Assembling code to be loaded by MacLisp. * Blocks:: Symbol table block structure. * Constructs:: Alphabetical index of constructs (special characters). * Pseudos:: Alphabetical index of pseudo-ops. * Changes: (MIDAS ARCHIV)* MIDAS changes in chronological order.  MIDAS Node: Output, Up: Top Output formats MIDAS can produce its binary output in any of several different formats. The format used is specified by the user with pseudo-ops (see section on pseudo-ops). The currently available formats are: SBLK the usual format in ITS. FASL used for programs which are meant to be loaded by LISP. .DECREL compatible with the D.E.C. operating system. .DECSAV SAV files produced directly, without taking time to link. RELOCATABLE relocatable binary to be loaded by STINK. Any MIDAS output format consists primarily of 36-bit storage words, which are intended for loading into memory locations of a job. The output also includes a symbol table (a list of the names and values of all the symbols defined by the programmer), and some information on how to load the file into core memory. SBLK format is documented in ITSDOC;BINFMT >, and the format of the SBLK file symbol table in .INFO.;DDTORD >.  MIDAS Node: Invoke, Up: Top, Next: Switches MIDAS Command Strings Once you have run the program MIDAS, it will ask for a command line on which you must specify the names of the input and output files. In addition to the filenames, the command line usually contains switches. *Note Switches: Switches. MIDAS can write four output files for each assembly: a binary output file, an error file containing whatever would normally appear on the terminal, a listing file, and a cross-reference table file. The cross-reference table file (a compact binary file, not a DEC cref listing) is not really useful now that the @ program exists (*Note @: (@)Top.). The listing output file is also inferior to an @ listing, but it is sometimes useful for debugging hairy macros. To facilitate this use, it is possible to ask for a listing of both passes (some macros cause fatal errors on the first pass). The binary output file is essential; an error output file is also very useful as a permanent record of the assembly errors. Normally, one specifies either just the input file or the input file and the binary output file. The error output file name is allowed to default from them. MIDAS tries hard to default all filename components so as to minimize your type-in. Not specifying the binary file name is equivalent to letting each component of the name default based on the input file name. Defaulting in MIDAS works bidirectionally; the input file name can default from the binary file name, and the binary file name can default from the input file name. This is actually useful. Note how the Twenex GTJFN-from-the-terminal scheme of things cannot provide this! The binary file's device defaults to DSK. The directory defaults to your working directory. The second filename defaults based on the type of output format used: BIN for SBLK files, FASL for FASL output files, or REL for relocatable output files. The first filename defaults to the input files's first filename. One exception: if TTY: is specified as the input file, and the binary file name is not specified, no binary file is made. The input file's device and directory default to those of the binary file. The second filename defaults to ">" for ITS and "MID" on DEC systems. The first filename defaults to that of the binary file. If no first filename is specified for either file, the default is "PROG". This becomes relevant sometimes when TTY: is specified as the input device. Exception: if the binary file was on device PTP or NUL, the default is DSK. These defaulting rules make common things very convenient. To assemble a file FOO;BAR > onto the same directory, you can use FOO;BAR_ letting the input file names default. To assemble it onto your directory, just say FOO;BAR letting the binary file names default. * Menu: * Switches:: Command line switches. * Interrupts:: Terminal interrupt characters.  MIDAS Node: Switches, Previous: Invoke, Up: Top, Next: Interrupts Switches: Switches should be enclosed in parentheses or preceded by slashes, and may go anywhere in the command string. The effects of a switch in no way depend on where it appears, although it should not appear in the middle of a file name as that may confuse the filename parser. Any number of switches may be enclosed by one pair of parentheses, as in (ET) which is equivalent to (E)(T) or /E/T. Each slash is good for just one switch. It is sometimes significant whether a switch occurs once or twice: (TT) is not the same as (T). /C Produce a CREF file. /E Produce an error output file. /L Produce a listing. (LL) List on 1st pass as well as 2nd. /T Read assembly input from the terminal after the TITLE statement, on pass 1. You can type in parameter assignments to control conditional assembly. (TT) Read from the terminal on both passes. /W Do not print on the terminal. This implies the (E) switch, so your errors are not lost. /W works by setting the .TTYFLG variable initially to 1.  MIDAS Node: Interrupts, Previous: Switches, Up: Top Terminal Interrupt Characters. In the ITS and Twenex (I believe) versions, the characters ^H, ^V and ^W have an instantaneous effect if typed on the terminal while MIDAS is running. ^H Causes an error message "^H-BREAK" (which says where the assembly has reached) followed by the .INSRTion of TTY:. Thus, this is a sort of "break-loop" you can use to debug runaway macros. To exit, cause an end-of-file on the terminal input. ^V Decrements .TTYFLG. Since type-out on the terminal happens only when .TTYFLG is negative or zero, this undoes the effect of one ^W. (some very bad errors that .INSRT TTY: also zero .TTYFLG before typing an error message.) ^W Increments .TTYFLG, suppressing terminal type-out. It is not wise to do this if you don't have an error output file (since after the assembly has been started it is too late to start writing one). In the Bottoms-10 version, you can get a ^H-break by typing ^C and then Reenter.  MIDAS Node: Basic, Previous: Top, Up: Top, Next: Example Machine Instructions in MIDAS The main body of a MIDAS program is composed primarily of machine instructions -- just as you would expect. The PDP-10 machine language instruction breaks down into five fields of bits: a nine bit opcode field, a four bit accumulator (AC) field, a one bit indirect field, a four bit index register field, and an 18 bit memory address field. The instruction set is documented very clearly in the "DecSystem-10 System Reference Manual" (DEC-10-HGAC-D, and the later versions), which is published by the manufacturer, Digital Equiptment Corp. ("DecSystem-10" is a pretentious salesman's name for the PDP-10). In MIDAS, the fundamental syntactic construct is the word. Its components parallel the fields of a machine instruction, but it is flexible enough to be used for all other purposes as well. This is because the subunits or "fields" which compose a word are simply added together, into parts of the 36-bit word determined by the pattern of spaces and commas that separate them. Every word of data assembled into the binary program is written in MIDAS as a syntactical word of some sort or other, with the sole exception of multi-word text strings. *Note Words: Words, for full details. Words are terminated and separated by the "line terminators", which are Return, Linefeed, and "?". Return and Linefeed should always be used together, to prevent confusion when editing the program. Strictly speaking, Return Linefeed contains a blank line, but blank lines are ignored anyway. The value of the words that appear in a MIDAS program become the words of the binary program output. Each word is assembled at the address specified by the MIDAS "location counter", which increments by one after each word to put consecutive words in consecutive locations. This is called "assembling a storage word". The ultimate goal of assembling a program is to assemble storage words, but word quantities can appear in other contexts such as to be passed as arguments to functions. Before each word in the MIDAS input, at the beginning of the line, there may be one or more "labels", which are symbols which are defined to equal the current value of the location counter. Thus, a label preceding a word is defined to be the address of that word. *Note LocnCtr: LocnCtr. The other most important constituent of a MIDAS program is the comment. A comment starts with a semicolon ";" and ends with the following Return. The whole thing is equivalent to a single Return. Another way to think of it is that you can put a comment at the end of any line in the file; but "lines" terminated by the "?" character do not count. A few other MIDAS constructs may appear in place of a word. One is the parameter assignment, which defines a symbol with an explicitly specified value at assembly time. *Note Assign: Symbols. Another is the "Statement". Everything that must be specified in a MIDAS program aside from the contents of words to be loaded and the values of symbols is specified by means of statements. A statement begins with a symbol which is the name of a "pseudo-op"; it is a sort of escape which directs MIDAS to perform some special function. Some pseudo-ops read arguments. The syntax of the arguments depends on which pseudo-op it is. An example of a statement is the END statement, which must appear at the end of every program. It starts with the symbol END. After that comes the program's starting address, which is syntactically a word (and thus, terminated by a "?" or Return or Linefeed). If a Return immediately follows the symbol END, then there is no argument (and no starting address). The separation into lines should not be thought of as a hard-and-fast rule. The "line-separating" characters USUALLY have that effect, but in some contexts (such as text-string constants) they may have NO special effect. and "?" are both "line-separators", but in a semicolon-comment they do not act the same: a ends the comment, but a "?" is ignored as "part" of the comment. Semicolon usually starts a comment, but not inside a text string. Thus, MOVE A,B ;COMMENT ? MOVE C,D assembles only a single instruction. The moral is that the meaning of a character depends on its context, which depends on the characters IN FRONT of it. MIDAS does not work by BNF-like grammatical rules ("a MUMBLE can be either a FOO or three BARs in a row") although a few constructs can be approximated by them. It works like a finite-state machine: "In the normal input-reading state, if a is read, terminate the line and process it; if a question-mark is read, terminate the line and process it; if a semicolon is read, enter the comment-reading state. In the comment-reading state, if anything but a is read, ignore it; if a is read, return to the normal input-reading state and terminate the line and process it."  MIDAS Node: Example, Previous: Basic, Up: Top, Next: Frame Simple examples of MIDAS code MOVE C,COUNTA TLNE B,100 SETZ C, JUMPGE A,@DISTAB(B) JRST LABEL1 Each of these lines will generate one storage word in the output. The first line will generate a MOVE instruction that will load the contents of memory location COUNTA into accumulator C. This is accomplished by putting the value of the symbol C in the instruction's AC field, and the value of the symbol COUNTA in the address field, and then adding the value of the symbol MOVE (which supplies the appropriate value in the op-code field). The second line is similar, except that the address field is specified by the octal number 100 instead of a symbol. That is a common thing to do with instructions like TLNE which use the address as a bit-mask. The third line is a SETZ instruction. The address field has been omitted, because the SETZ instruction ignores its address. In fact, the address field will be assembled as zero. The SETZ has been indented one space as a note to humans that the preceding TLNE instruction can skip over it. The fourth line is a JUMPGE instruction which demonstrates indexing and indirect addressing. The "@" turns on the instruction's indirect-bit, selecting indirect addressing. The "(B)" puts B's value in the index field. Presumably, B is the number of an accumulator which is to be used as an index register. The fifth line shows a JRST instruction, for which it is not necessary to specify an accumulator. In fact, the accumulator field of the instruction will be assembled as zero; but instructions that actually use accumulator zero should say so explicitly. So in the simple cases, MIDAS agrees with the format used in the "DecSystem-10 System Reference Manual."  MIDAS Node: Frame, Previous: Example, Up: Top, Next: Words The Framework of Every MIDAS Program A MIDAS program consists primarily of PDP-10 instructions and data, together with labels and comments. But other things are usually or always needed at the beginning and end of the program. The first thing in every MIDAS program (or every subfile of one, for that matter) is a line containing ";-*-MIDAS-*-" to tell EMACS how the file is to be edited. The second thing in a MIDAS program, which is not actually needed for small programs, is a .SYMTAB statement which says how large a symbol table is required. The argument to .SYMTAB is the desired number of entries in the symbol table. This must include the predefined symbols, the user-defined symbols, and some extra to make hashing efficient. It should also be prime. To help you set up your .SYMTAB, MIDAS prints the symbol table size and the number of entries used at the end of the assembly. Next, in every MIDAS program, should come the TITLE statement, which consists of TITLE followed by a line of text, and performs these functions: 1) for relocatable assemblies, the first symbol following TITLE becomes the name of therelocatable program being assembled; 2) the text following TITLE is printed on the terminal on each pass. 3) when the /T switch is used to request input from the terminal, this input is read when the TITLE statement is reached. Because of 3), it is sometimes useful to define a few symbols before the TITLE statement so that they can be used when giving input on the terminal. If there is no TITLE statement, /T won't do anything! After the TITLE statement, you should define names for the accumulators. Single letters starting with A=1 are best. Accumulator 0 should also have a name, but not in sequence with 1, since 0 can only be used for special purposes. But don't ever write an instruction which actually USES accumulator 0 without putting in the name of that accumulator. The stack pointer should be in accumulator 17, which should be named P. Putting the accumulator definitions on page 1 will produce the best results in @ listings. After this point, you are on your own. But at the end of the program, you need an END statement. The END statement consists of END followed by the starting address of the program (this is an old assembler tradition). You can omit the starting address if you don't want your program to have one (in a relocatable program, this is often the case). If you don't have an END statement, you get an error. This catches many errors in assembly conditionals and macro definitions which cause the END statement not to be recognized as such. Any text which follows the END statement will be ignored completely by MIDAS.  MIDAS Node: Words, Previous: Example, Up: Top, Next: Fields Words, and Their Syntax The "word" is the most commonly used MIDAS construct, as a storage word to be assembled must be, syntactically, a word, and an ordinary PDP-10 instruction is an example of a word. However, the word construct includes other things than instructions, and is used in other contexts besides that of storage words. This section of the manual describes how to put a WORD together. The concept of a WORD is tied closely to those of SYLLABLES and FIELDS, out of which WORDS are made. Loosely, a syllable is a number or symbol, and a field is an arithmetic expression. Words are made up of fields, and fields are made up of syllables. Do not confuse a MIDAS field with a "field" of bits in a PDP-10 machine language word. A word is one or more fields connected by field separators, with optionally an indirect bit or index field anywhere among them. There are two field separators, space (or horizontal tab) and comma. (Space and horizontal tab are identical and will both be referred to as space.) To improve readability, spaces before and after a word and spaces adjacent to a comma are ignored, and more than one space in a row are treated as one. The values of the fields are combined to form the values of the word according to the number of fields and the pattern of separators. These formats are described in the following table, in which A, B, and C are fields. "TR(x)" is used to represent the result of truncating x to 18. bits. pattern format # value in octal ====== ======= ===== ,,C 13 TR(C) ,B 14 TR(B) ,B C 15 MEANINGLESS ,B, 16 MEANINGLESS ,B,C 17 MEANINGLESS A 20 A A B 24 A+TR(B) A B C 25 A+TR(B)+TR(C) A B, 26 A+_23. A B,C 27 A+_23.+TR(C) A, 30 A A,, 32 _18. A,,C 33 _18.+TR(C) A,B 34 A+TR(B) A,B C 35 MEANINGLESS A,B, 36 MEANINGLESS A,B,C 37 MEANINGLESS Here are some examples of what these formats are most useful for: A B,C This is the normal instruction format, e.g., CAMN A,FOO A B This is good for instructions with no accumulator field, e.g., JRST BAR A B, and this is for instructions with no address field, e.g., SETZ D, A,,C This is the standard way to specify the contents of a storage word by half-words, e.g., BLETCH: -PDL,,PDB NOTES: 1) All addition done here is special in that carry from bit 18 to bit 17 is suppressed. In other words, when the user specifies a field which is supposed to be a right half-word field, he can rest assured that his quantity didn't carry over into the left half. 2) A word may have more than three fields. In that case, the fourth and following fields are added in with the third field. Thus, if the third field is truncated to 18. bits and added in, so are the following fields. Only spaces may be used for separating fields after the third field; a comma after the third field is an error, but will be treated as a space. Commas are flagged so as to catch places where the accidental omission of a has run two lines together. 4) The user can redefine these formats by using the .FORMAT pseudo-op. That is what the "Format number" of a format is used for. See PSEUDO-OPS. In addition to the fields and separators that make up a word, there can be an indirect bit and an index field. These subconstructs resemble the fields of the word in that their values are merged into the value of the word. They differ from the fields in that they are marked out by their own special syntax, and are interpreted in the same way no matter where in the word they appear (unlike fields, which are all the same and are interpreted according to their position in sequence). a. The Indirect bit The character @ (atsign) is a special character. It may occur anywhere inside a word. Whenever MIDAS encounters an @ inside a word, a 1 is ORed into bit 22. of the word, i.e., the indirect bit. The @ does not terminate syllables or fields, nor is it taken as part of a syllable or field. Its position in the word is totally irrelevant. However, the normal convention is to put it in front of the field specifying the right half of the word (the address) if there is one; if not, put the @ where the address would go. b. The Index field To get a certain quantity into the index field, the easy, convntional way is to use a bracketed word of the parentheses type. For example, MOVE A,FOO(D) will put the value of D into the storage word's index field. As explained in section C.2.d, the parenthesis bracketed word works in its strange way because the index field of the machine word is the lowest four bits in the left halfword. The index field, used this way, may appear anywhere in the word except in the middle of a syllable or following an arithmetic operator, but the normal convention is to put it at the end of the field specifying the right half of the word (the address) if there is one. When "(" appears following an arithmetic operator, it signifies a type of bracketed word, rather than an index field.  MIDAS Node: Fields, Previous: Words, Up: Top, Next: Syllables Fields A "field" in MIDAS is essentially an arithmetic expression. A field may be either a single syllable, or two or more syllables combined arithmetic operators. Many MIDAS pseudo-ops take arguments that are syntactically fields. These are the arithmetic operators, in their order by priority: char. operator ===== ======== highest _ left shift 1st operand by # of bits specified by 2nd operand. (Negative 2nd operand shifts right) & bitwise AND # bitwise XOR \ bitwise OR * and / 36. bit integer multiplication and subtraction lowest + and - 36. bit integer addition and subtraction Thus all _'s are done first, then &'s, then #'s, then \'s, then *'s and /'s, and finally +'s and -'s. Operators of the same priority will be performed in left-to-right order. Examples: (assuming that A, B and FOO are numerically defined symbols with the values 1, 2, and 53 respectively.) Field Value ===== ===== 3+4 7 1+4&FOO+1 2 1+4& 5 The first example is rather trivial. The second and third demonstrate the use of angle brackets as algebraic parentheses (actually, part of the syntax of syllables). In the second, 4 is anded with FOO, giving zero, then 1+0+1 equals 2. In the third example, first FOO is added to 1, giving 54. Then 54&4 gives 4, and then the 4 is added to the 1, giving 5. Note that there may NOT be spaces within a field; so "4 * 5" is not the same as "4*5".  MIDAS Node: Syllables, Previous: Fields, Up: Top, Next: LocnCtr Syllables There are several types of MIDAS syllables. A symbol may be a NUMBER, a NUMERICALLY DEFINED SYMBOL, a QUOTED CHARACTER, a BRACKETED WORD, or a call to a PSEUDO-OP (but see MACROS) (Note: only "value-returning" pseudo-ops can be used to make syllables. Other pseudo-ops will either be ignored by the process of building words and fields out of syllables (except for their side effects), or illegal to be used except alone on a line). Each syllable has a value, which is a 36.-bit quantity. a. NUMBERS The simplest form of number is an octal integer, which is just a string of digits. Following them with a "." makes it a decimal integer instead. *Note Numbers: Numbers, for other sorts of numbers, which you won't need very often. b. SYMBOLS A symbol is a string of SQUOZE characters which is not a number. More precisely, it is a string of characters from the SQUOZE character set of length 1 or greater which contains at least one letter, or at least one % (percent) or $ (dollarsign), or at least two .'s (periods). The SQUOZE set includes all 26. letters, all 10. digits, and the characters $ (dollar sign), % (percent sign), and "." (period). (Note that the symbol "." (a single period) is special; *Note LocnCtr: LocnCtr.). Here are some examples of symbols: LOC3 GOHERE $END A%LOCATION 35X 1.2.3 .$Z%.G (The last example is NOT considered an example of good programming style.) A symbol has no length restriction, but MIDAS only looks at the first six characters, so the symbols THISLOCN and THISLO, for example, are effectively identical. MIDAS symbols can have several sorts of definitions. The symbols that can appear as syllables are those with numeric definitions (other sorts of symbols might appear at the same places, but they would be interpreted differently and would constitute different constructs). MIDAS provides many predefined numeric symbols (including all the PDP-10 instructions, and others specific to the operating system), and programmer can define others (*Note Define: Symbols.). An example of numerically defined symbols: In the word MOVE B,FOO , there are three symbols: MOVE, B, and FOO. The symbol MOVE is predefined; the other two must be defined by the programmer. c. Quoted Characters: A quoted character starts with any one of the characters ' (single quote), " (double quote), or ^ (upasrrow) followed by a character. The quote or uparrow and the character following are taken as a syllable. A ' followed by a character has the value of the SIXBIT representation of the character. A " followed by a character has as its value the ASCII representation of the character. ^ works the same way as " except that the ASCII value is ANDed with 77 octal; that is, only the low six bits are kept. ^ is used for generating the ASCII code for "control" characters. Examples of quoted characters: Syllable Value ======== ===== 'A 41 octal "+ 53 octal ^C 3 octal d. Bracketed words: A word surrounded by ( ) (parentheses), < > (angle brackets), or [ ] (square brackets) is a syllable called a BRACKETED WORD. Each works in its own way: is simply a syllable whose value is that of the word between the brackets. Angle brackets act much like algebra's parentheses, and are usually used that way. (word) works two different ways. If the preceeding character is an arithmetic operator, the value of the word has its halves swapped, and this becomes the value of the syllable, on which the arithmetic operator acts. If the preceeding character is not an arithmetic operation, the value of the word is swapped and saved, and at the end of the outer word, it is added into the word being formed. This quirk is so that (5) stuck at most places in a word will put 5 in the index field. [word] is a LITERAL, or CONSTANT. *Note Literals: Literals. The value of the syllable is the location where MIDAS put the literal. It is hard to give examples of ( ) and < > until some further concepts have been introduced, so these have been delayed. e. Pseudo-ops which return a value: Pseudo-ops are instruction given by the programmer to MIDAS in the input ASCII file about how to assemble various things. They are described in section E, "Pseudo-ops that every programmer needs," and in the section on pseudo-ops. They are the "built-in functions" of the MIDAS assembly-time programming language. Some pseudo-ops are used for their side-effects; some, to compute values. Calls to value-returning pseudo-ops constitute syllables, whose value, of course, is the value returned by the pseudo-op.  MIDAS Node: LocnCtr, Previous: Syllables, Up: Top, Next: Relocation The Location Counter Normally, when MIDAS finishes reading a Word at top level in the input file, the value of that word is assembled into the binary program output. The place where it will be loaded is specified by the location counter, which is normally an 18.-bit number. After assembling each such word, MIDAS increments the location counter. The value of location counter is explicitly available as the value of the symbol ".". It refers to the address of the current word, not the following one. A label defines a symbol to equal the current value of ".". The location counter can be set with a LOC statement, or by assigning a value to the symbol "." (*Note .=: Symbols, for how to do that). These have slightly different effects when an offset is in effect. In a relocatable program, the location counter can be set to a relocatable value or to an absolute value. The usual way to leave space for non-constant data in a program is the BLOCK statement. BLOCK 200 leaves 200 words of space, by incrementing the location counter by 200 . It is an error to ask for a block of negative length. In relocatable assemblies, the location counter starts out at relocatable zero. In absolute assemblies, it starts out at absolute 100 octal. Sometimes it is necessary to assemble code at one location and copy it to another before using it. When that is done, all references to labels in the code (whether from within it or outside it) should be arranged so as to be correct when the code has been moved to its ultimate position. This can be done by defining an offset. The statement OFFSET 200 causes all references to the location counter -- the symbol ".", labels, etc. -- to add 200 to the real value of the location counter. If the code being assembled is moved 200 words upward, it will be at the addresses at which the program will refer to it. Offsets do not affect the actual location counter, which is the place at which code will actually be loaded. They affect the value of the location counter as seen by references to it from within the program. The difference between LOC and assigning a value to "." is that LOC sets the real location counter, whereas assigning "." sets the value of ".": that is, it subtracts the offset and then sets the real location counter, so that when the offset is added in again to get the value of "." it will equal the value assigned. An offset can be cancelled by setting the offset to zero. A frequent use of the offset is for error checking. If there are a series of symbols FOO, BAR, QUUX ... with values 0, 1, 2 ... intended to be the values of a particular table index, with MAX being 1 larger than the largest legal index, the table can be defined with TABLE: OFFSET -. FOO:: BAR::
QUUX::
Standard DEC two-segment relocatable. is the segment boundary, usually 400000 . .DECSAV Standard DEC SAV file format. Absolute. .FASL MACLISP FASL file format. Relocatable. The names of the formats are all pseudo-ops which you can put in the program to specify those formats. If the format you want is the default for your particular system, you don't need to specify it, but if you can anticipate that your program will be assembled on other systems it might be wise to do so anyway. There are also the RIM and RIM10 formats, which I may document some day if I figure out once again what they do. A few functions are available for manipulation of relocatable quantities. These include .ABSP, .RELP, and .RL1. .ABSP and .RELP return the absolute and relocatable parts of a quantity (the relocatable part is the relocation factor. .RL1 is a symbol whose value is a pure relocatability of 1; that is, a relocatable zero. You can think of these as analogous to the the complex number functions Re, Im and the constant i. .RELP .RL1 is nonzero if the asembly is relocatable.  MIDAS Node: Symbols, Previous: Relocation, Up: Top, Next: DDT Defining Symbols You have already been told how to use symbols and what names they are allowed to have. Here is how to define them. A symbol can have these types of definition (or none at all): numerically defined symbols, pseudo-op names (*Note Pseudos:Pseudos.), and macroinstruction names (*Note Macros: Macros.). Here we are concerned only with numerically defined symbols. New pseudo-ops cannot be defined by the user, so the initial supply is all you get, but pseudo-op definitions can be copied from one symbol to another using EQUALS. There are basically two ways to define a symbol numerically: as a LABEL, and as a PARAMETER. 1. Labels. The primary use of symbols is to hold the address of an instruction or variable in the program. MIDAS has a special construct, the LABEL, for defining such symbols. A label is simply a symbol followed by a colon, and it can appear at the beginning of any line. Its effect is to give the symbol a value equal to the address where the next storage word will go. A line can have several labels in it, but a label may not appear after any other construct has begun. A label may be followed by anything at all, or it may be the only thing on its line. An example is: FOO: MOVE A,TABLE(C) which assembles a storage word containing a MOVE instruction, and also defines FOO as the address of that instruction. If a symbol is defined as a label, it can have only one value. If anything in the program tries to define the symbol with a different value, either before or after the symbol's appearance as a label, an error message will be typed. It is legal to define the symbol again with the SAME value. In fact, that happens to every label, since it is seen on both passes of the assembly. The parameter assignment "=:." has the exact same effect as the label ":", which is allowed for convenience's sake. 2. Parameters. There are other uses of numerically defined symbols besides their use as labels. MIDAS also allows definition of symbols by PARAMETER ASSIGNMENT. A parameter assignment is a line of the form = or == which tells MIDAS to compute the value of and make that the value of . This is similar to the "assignment" statement of most mathematical languages, such as FORTRAN. Using the == construction makes the symbol half-killed in DDT (this is explained in the section on OUTPUT; for now, suffice to say that the == form is the one you probably want to use.) Here is one of the ways to use this feature: Say a programmer is writing a program which knows how to handle four FOOBAR's. If in the future he should want to modify the program to handle five or six FOOBAR's, there might be many places where the program would have to be changed. Now if he had made the number of FOOBAR's an assembly parameter, by defining a symbol as in: NFOOBR==4 and writing all of the program to work for NFOOBR FOOBAR's Whenever there is a table or block of data whose length must be referred to by the program, that length should be expressed by a numeric symbol. Symbol definitions actually have a static scoping or block structure as in Algol or PL/I. *Note Blocks: Blocks.  MIDAS Node: DDT, Previous: Symbols, Up: Top, Next: Numbers Communicating Information about Symbols to DDT One of the most important things about symbols in assembler programs is that they are passed to DDT. MIDAS has several features designed specifically for communicating with DDT. If DDT, needing to print the value 205, chose at random a symbol whose value was close to 205, it would be likely to find several names for bits in various registers. It is essential to have a way to tell DDT which symbols ought to be used for such type-out. This is done by "half-killing" the symbols which ought not to be used. The most common way to half-kill a symbol is to duplicate the colon or equal sign used to define it. Thus, FOO==200 says that FOO is to be half-killed and should never be printed out, while FOO=200 allows FOO to be printed out. FOO:: defines FOO as a half-killed label. If those methods of half-killing are not convenient, the .HKILL statement is available. .HKILL followed by a list of symbols half-kills those symbols. If the symbol .HKALL is nonzero, then all labels defined are half-killed. .KILL can be used to avoid sending a symbol to DDT at all. It is followed by a list of symbols to kill. MIDAS does not forget the value of a symbol when you .KILL it, so .KILL is not the same as EXPUNGE. .KILL causes the symbol to be forgotten only when the symbol table is written into the output file. The NOSYMS statement can be used to avoid outputting any symbol table at all.  MIDAS Node: Numbers, Previous: DDT, Up: Top, Next: Literals Details of the Syntax of Numbers A string of digits in which no digit is preceeded by a period forms an INTEGER, a type of syllable whose value is the value of the number interpreted in the CURRENT RADIX (octal by default, but see PSEUDO-OPS). However, an integer followed by ' (single quote) is interpreted as octal, and one followed by . (period) is interpreted as decimal, regardless of the current radix. A string of digits with a . (period) to the left of some digit forms a FLOATING-POINT NUMBER, interpreted in decimal. Either of these may be followed by a ^ (uparrow) which works something like scientific notation. An integer may be followed by an integer as A^B which would have the value of B A*R where R is the radix in which A is expressed. The result is fixed-point. A floating point number may also be followed by a ^ and an integer, as in X.Y^A which is interpreted as A X.Y*10. that is, as scientific notation. The result is still floating-point. Also, any of the preceeding numeric formats may be followed by a _ (backarrow, or underscore) and an integer, which multiplies the value by integer 2 The integer is interpreted in the current radix, but may be forced to decimal or octal by terminating it with . or ' as explained above. The result is always a fixed-point number, even if the first number was floating-point! Examples of NUMBERS: (the current radix is taken to be octal) Syllable Value ======== ===== 23 23 octal 23. 27 octal 3^3 3000 octal 3.^3 5760 octal (3000. decimal) 1_3 10 octal 23_10. 46000 octal 3.5 3.5 floating-point 3.5^4 35000.0 floating-point 3^3_4 60000 octal 1.5_3 14 octal (Note: NOT floating point!)  MIDAS Node: Literals, Previous: Numbers, Up: Top, Next: Bytes Literals Normally, when you write a machine instruction in an assembler, you specify the memory operand by its address. Sometimes, it is desirable to refer to "a word containing X" without worrying about where that word is going to be stored. The LITERAL is a construct that permits just this. A literal consists of any number of lines enclosed in square brackets ("[" and "]"). MIDAS assembles the lines enclosed into locations of its own choosing. The value of the literal, where it appears, is the address of the location chosen by MIDAS to hold the first word of the literal. For example, MOVEI A,[1 ? 2 ? 3] would load accumulator A with the address of a three-word table whose contents are 1, 2 and 3 in successive words. It is equivalent to MOVEI A,FOO1 .... FOO1: 1 ? 2 ? 3 where FOO1 is a non-existent label by which you can imagine that MIDAS connects the usage of the literal with the location of its contents. Unless you request otherwise, all literals will actually appear at the end of your program (that is, at wherever the location counter was set when the END statement was encountered). However, you can alter this with the pseudo-op CONSTANTS. Whenever CONSTANTS appears, all saved-up literals will be "dumped out" or assigned locations starting at the current location counter. CONSTANTS may appear any number of times (up to 75 or so), but must appear the same number of times and at the same locations on both passes. On pass 1, MIDAS doesn't know where a literal is going to be located until the CONSTANTS statement is seen. On pass 2, the location of the CONSTANTS statement is known in advance (remember, it must be the same as on pass 1), but the location of the literal is still not known until the end of the literal (so that recursive literals can work). For these reasons, labels inside literals cannot work, so they are not allowed. The symbol "." inside a literal refers to the location from which the literal is being referred to, not the location where the literal will appear. If you set the variable .LITSW nonzero, any use of a literal is an error (until you set the symbol to zero again).  MIDAS Node: Bytes, Previous: Literals, Up: Top, Next: FileInfo Manipulating Bytes and Byte Pointers. MIDAS provides several built-in functions for making and using byte pointers of the form suitable for the LDB and DPB instructions. When you want to make a byte pointer from a given numeric position and size, simply write the byte pointer left half as an octal constant. There is really no way to improve on that, given that you are going to be using numbers. For example, 440700,,FOO is suitable for ILDB'ing the ASCII string starting at word FOO. It is common practice to define symbols for byte pointer left halves and then use them to represent fields, as in ASCBP==440700 ... MOVE A,[ASCBP,,FOO] A more sophisticated symbolic way of referring to fields uses the .BP function. .BP takes as an argument a mask for a field in a word, and returns a byte pointer to that field (in address zero). Thus, <.BP 7770> would return 031100,,000000. When the argument to .BP is terminated with a comma, the comma is not eaten, as it would be with most functions. Instead, the comma turns into a space. Thus, .BP 7770,FOO returns 031100,,FOO, a byte pointer to the 7770 field in address FOO. In addition, parentheses inside the argument to .BP are part of the argument to .BP, not part of the word in which .BP occurs. .BP is most useful with symbolic names for fields or bits in a word. For example, LDB A,[.BP (%TOERS),TTYOPT] would get into A the contents of the %TOERS bit in the left half of TTYOPT (%TOERS being a bit symbol suitable for use in a TLNE instruction). The reverse of .BP is .BM. It takes a byte pointer (ignoring the address) and produces a mask for the specified byte. The left half of a byte pointer may be passed in the right half of the argument word. This Is useful when you have defined a symbol for a byte pointer left half and want the corresponding mask. Unlike .BP, .BM follows the ordinary conventions for arguments. Example: .BM 030600 returns 770. Bytes can be extracted from and deposited into quantities at assembly time using the .LDB and .DPB functions. .LDB takes a byte pointer (ignoring the address) or a byte pointer left half in the right half, and also a quantity as second argument. It returns the contents in that quantity of the specified byte. .LDB 030600,1234 returns 23. .DPB takes as arguments a byte value, a byte pointer (or left half in right half, etc) and a quantity, and returns a new quantity made by changing the specified byte of the old quantity to contant the byte value. For example, .DPB 11,030600,4444 returns 4114. The .IBP function increments a byte pointer. It accepts a byte pointer and returns the incremented pointer. .IBP <440700,,> returns <350700,,>. The address supplied with the byte pointer is part of the incrementing process; thus, .IBP <440700,,FOO> returns <350700,,FOO> and .IBP <010700,,FOO> returns <350700,,FOO+1>. If the left half of the argument is zero, the argument is swapped, so .IBP 440700 returns <350700,,>. Two functions related two byte manipulation are .LZ and .TZ, which return the number of leading zero bits and trailing zero bits, respectively, in their arguments. .LZ SETZ is 0 and .TZ SETZ is <35.>. When applied to zero, both return <36.>. For assembling words into memory made by packing bytes together, you could use .DPB, but a special feature exists for this purpose, called .BYTE. .BYTE takes a list of byte sizes, and enters a special mode in which "words" assembled at top level are stored, not into successive whole words, but into successive bytes of the specified sizes. The sizes are used in the order specified, over and over cyclically. Here is an example: .BYTE 12.,6 2222 33 1111 44 .BYTE would assemble a single word, made up of a 12. bit byte, a 6 bit byte, a 12. bit byte, and a 6 bit byte. The contents would be 222233,,111144. Note that .BYTE with no arguments is used to return to ordinary non-byte mode. Byte mode inside literals and other bracketed groupings is independent of what is going on outside the grouping. That is, groupings always start out in ordinary (non-byte) mode, even if byte mode was in effect outside; byte mode may be turned on inside the grouping, but when the grouping ends the state of byte mode will be restored to what it was before the grouping. For example, <.BYTE 7 ? ^M ? ^J> is a quantity whose value is a CRLF in ASCII. It is equivalent to ASCII/ /. While byte mode is in effect, the location counter is a byte pointer. Its value is such that an ILDB instruction on it would fetch the next byte to be assembled. This is historic; it may well be that a better convention would be that the location counter be such that a LDB would fetch the next byte to be assembled. As it is, you must use .IBP to get such a byte pointer. It works to set the location counter to a different byte pointer, though it is recommended that you make the size correct. If the byte pointer is inconvenient for you, .BYTC may be more useful. Its value is the total number of bytes assembled since byte mode was entered. The insides of literals and groupings do not count. .WALGN (word-align, not wall-generate) in byte mode advances the location counter to the beginning of a fresh word. It does nothing in normal non-byte mode. .BYTE with no arguments automatically does a .WALGN.  MIDAS Node: FileInfo, Previous: Bytes, Up: Top, Next: Terminal Obtaining Information on Filenames at Assembly Time. One of the most common things one wants to do is to assemble a program's version number into the program. This can be done, on ITS and Twenex, using the symbol .FVERS, whose value is the version number of the main input file, and .IFVRS, whose value is the version number of the current input file if that file has done no .INSRTs, or the version number of the last file .INSRTed by the current input file. More information is available in the variables .FNAM1 and .FNAM2, which hold the sixbit filenames 1 and 2 of the main input file, and .IFNM1 and .IFNM2, which hold similar information for the same file as .IFVRS. These variables are available on Bottoms-10, where there are no version numbers, as well as on other systems. On ITS, the version number is a function of the filename 2, made by taking all the digits in it and converting them using base ten to a number. The names of the output file (in sixbit) can be found in .OFNM1 and .OFNM2. The version number is not available, since on ITS it does not exist.  MIDAS Node: Terminal, Previous: FileInfo, Up: Top Interaction with the Terminal. The simplest and standard way to print a message on the terminal is with the PRINTX operation. It takes a string, delimited as for ASCII, and types it out. For example, PRINTX /FOO/ will type FOO, with no carriage return. .TYO is a function that takes a single character, as a number, and types it. .TYO 101 will print an A. Another useful function is .TYO6, which takes an argument which is interpreted as sixbit and printed out. .TYO6 is useful primarily with .FNAM1 and .FNAM2. Error messages are printed on the terminal, of course. The .ERR function signals an error, taking the rest of the line as error message. Along with the error message will go the usual information of filenames, page and line number, location counter both absolute and relative, and macro depth. There are no special facilities for putting any variable information in the error message because the macro features can be used to do this. There are two ways to request input from the terminal. You can ask a specific question, or you can give the user the opportunity to enter any MIDAS code he wants. To allow him to enter arbitrary text, do .INSRT TTY: which reads input from the terminal, ended by ^C or ^Z. If you want it to be done only on pass 1, you must put it in an IF1 conditional. The /T switch can be used in the command line to cause a .INSRT TTY: to be done in a program which does not actually contain one. It will be done right after the TITLE statement. To ask a specific question, use .TTYMAC, which a sort of macro that reads its arguments from the terminal. .TTYMAC looks like a macro definition except that there is no macro name in the define line; just an argument list, followed of course by the macro body and a TERMIN. Instead of defining a macro which must be called later with arguments specified explicitly, .TTYMAC defines a nameless macro which is called immediately, getting the arguments by reading as many lines as are necessary from the terminal. *Note TTYMAC: Macros, for more information. Here is an example: PRINTX /Value of BAR = / .TTYMAC FOO BAR=FOO TERMIN  MIDAS Node: Macros, Up: Top MIDAS Macros. Maybe someday this file will be INFO-ized. @. GENERALITIES. It is often useful, when the text to be assembled has some pattern, to cause it to be computed, rather than putting it all in the file to be assembled. This reduces the number of possible typos and makes it easy to change all occurrences of a particular construct. To do this, one needs to be able to define a function which will be evaluated at assembly time, with the result being text to be assembled in place of the call to the function. Such a function is called a MACRO. In thes document, "EOL" means either CR or LF; "open" means "<", "(", "{" or "["; "close" means ">", ")", "}" or "]". "the EOL or CRLF is thrown away" means that the EOL encountered as should have been previously described is thrown away, and if the EOL is a CR and the following character is a LF, the LF is also thrown away. Thus, either a CR alone, a LF alone, or a crlf may be used, and will be flushed at that point. A. MACRO DEFINITIONS. 0. GENERALITIES. A function definition must specify the name of the function, the formal parameters (called DUMMY ARGUMENTS when macros are concerned) and the expression to be evaluated when the function is called - or in the case of a macro, the text to be assembled when the macro is called. In MIDAS, a macro definition is introduced by the pseudoop DEFINE, which should be followed by the macro name. After that, on the same line, come the names of the dummy arguments, perhaps followed by a comment. The text of the macro starts on the next line, and continues until the DEFINE is matched be a TERMIN. The character that ends the TERMIN is gobbled up. 1. MACRO DEFINITION EXAMPLE. DEFINE FOOBR AA,B MOVE A,AA CAIL A,B POPJ P, TERMIN A call to that macro might be: FOOBR ZZZ,10 which would assemble into MOVE A,ZZZ CAIL A,10 POPJ P, 2. THE DEFINE LINE The "DEFINE" line is the first component of a macro definition. It beginss with the "DEFINE" pseudo (which needn't actually be at the beginning of a line). Next comes the name of the macro to be defined, optionally preceded by an explicit block name (eg DEFINE FOO"BAR to define a macro BAR in the block named FOO, rather than in the current block). After the macro name come the dummy argument names, followed optionally by a comment. In any case, the define line extends through the first CRLF or EOL after the DEFINE. a. bindclasses - semantics. Most higher level languages have several bind classes. The function definition specifies one of the bind classes for each formal parameter, which is used in decoding a call to the function, to decide what value to give to the formal parameter. Macro dummy arguments also have bind classes, which say three things: what to do if the dummy is UNSPECIFIED (that is, if, in a particular call, the argument list runs out before this dummy is reached) or NULLSPECIFIED (the argument for this dummy is left out), the alternatives being NULLIFIED, GENSYMMED and DEFAULTED (See B.8 for the meanings of the three options); which argument syntax to use for the dummy when processing calls to the macro (There are 6 different argument syntaxes available in MIDAS: NORMAL, WHOLELINE, BALANCED, STRUNG, KEEPSTRUNG, and EVALUATED. See B.2 through B.7 for descriptions of them.); and how the actual arguments are to be associated with the dummies, the alternatives being by ORDER and by KEYWORD. b. bindclasses - syntax. In MIDAS, it is not necessary to specify the complete bindclass of each dummy with that dummy's name. Only the ways in which its bindclass differs from that of the preceding dummy are specified, by means of special delimiters between the names of the dummies. The first dummy is given the default bindclass (nullified normal by order) unless special delimiters precede it. The delimiters are: {[(< which cause following dummies to be balanced, >)]} which cause following dummies to have normal syntax, * which causes following dummies to be strung, or, if strung was already the selected syntax, causes them to be normal (This is called "turning strungness on or off"), & which turns keepstrungness on or off, # which turns evaluatedness on or off, ? which turns balancedness on or off, - which turns wholelineness on or off, \ which complements gensymmedness, + which switches between by order and by keyword, : which reverts to the default in all ways (normal syntax, by order (not keyword), and not gensymmed). "/" is a delimiter which is like "-" except that if it follows a dummy immediately, wholelineness is complemented before the dummy rather than after. That is, "FOO/" is equivalent to "-FOO". This is mainly for compatability with older versions of MIDAS. A dummy is defaulted iff its name is followed by "=". The "=" should be followed by the desired default value, whose syntax is that of a normal macro argument. Beware: the dummy argument delimiters do not terminate default values, and default values are read in with the normal argument syntax regardless of the specified syntax of the dummy being defaulted. Thus, DEFINE FOO \(A,B=100)C makes B's default value be 100)C, which is probably not what you wanted. If a dummy is specified as gensymmed, and is also given an explicit default value, the explicit default overrides the gensymming. c. DEFINE line example. DEFINE FOBR \A#B\C:D,+E=BAR,F,G(H,I=X,)*J*+-K would give FOBR the dummies A,B,C,D,E,F,G,H,I,J,K as follows: dummy bindclass (argument syntax, what to do if unspecified). the first few dummies are by order: A normal, gensymmed B evaluated, gensymmed C evaluated, nullified D normal, nullified the next few dummies are by keyword: E normal, defaulted to "bar" F normal, nullified G normal, nullified H balanced, nullified I balanced, defaulted to "X" (note that the comma after "I=X" is necessary because the ")" would otherwise be part of the default value of I. after dummy names not given default values a comma is not necessary, although an extra one can't hurt.) J strung, nullified the next dummy is by order. K wholeline, nullified 3. THE MACRO BODY The macro body is the text string to be substituted in place of a call to the macro. The macro body specified in a macro definition starts with the first character after the CRLF or EOL that ends the define line, and continues through the character before the TERMIN that ends the macro definition. Remember that the character ending the symbol "TERMIN" is thrown away. WARNING: ANY occurrence of "DEFINE" or "TERMIN" inside a macro body will affect MIDAS's determination of where the body ends. This is true regardless of whether you intended them to or not. Just because the "DEFINE" was in a text string or a comment does not change this. "Terminate" and "Terminal" must also be avoided. If you need to put a "DEFINE" or "Terminal" into a macro body, use .QUOTE (See c., below). The same holds for any other MIDAS pseudo-ops that require a matching TERMIN, such as IRP and .TTYMAC. a. dummy argument substitution. Whenever the name of one of the dummy arguments appears in the macro body specified in the definition, it represents a request for the value of tht dummy to be inserted at that point when a macro call is expanded. Dummy argument names are recognized only when surrounded by non-squoze characters, so neither of the dummy names "A" and "B" occurs in the string " AB ", but both occur in " A B ". The way dummy argument substitution is implemented is tht the dummy argument names are recognized when the macro is defined, and replaced by special characters. Therefore, if the name of a dummy argument is created by the expansion of a macro call (perhaps part of the name came from the substitution of the value of another dummy) that dummy-name will not be replaced by the dummy's value. In other words, text produced by substitution for dummy arguments is not rescanned for occurrences of dummy argument names. b. concatenation. Suppose it is desired to have the substituted value of the dummy argument FOO followed immediately by the squoze character X. It will not do to put "FOOX" in the macro body, because "FOO" is not considered to occur in "FOOX". "FOO X" will cause the value of FOO to be substituted, but the space will remain between it and the "X". The way to win is to use the concatenation character "!". "!" can delimit the names of dummy arguments, as any other non-squoze character can, but it alone is thrown away after doing so. For example, "FOO!X" will cause FOO to be recognized, but followed immediately by an "X". Similarly, the TERMIN tht ends the macro definition must be preceded by a non-squoze character, which normally becomes part of the macro definition. If it is desired for the macro definiton to end with a squoze character, separate it from the TERMIN with an "!", which will be thrown away. "!"'s that appear in the macro body not adjacent to a dummy agument name, a .QUOTE, or the final TERMIN are not thrown away; this makes it possible to put "!"'s in macros. c. .QUOTE It is possible to prevent recognition of dummy argument names in a part of the macro body by using the .QUOTE pseudoop. The pseudo is followed by a text string like the argument to ASCII et al., which is not scanned for dummy argument names. The first character of the text string will follow the character before the "." of the .QUOTE, and the last character before the closing delimiter will come before the character after tht delimiter, in the macro as it will be defined. The .QUOTE, to be recognized, must be preceded by a non-squoze character, so in order to make it possible for a quoted string to follow a squoze character, an "!" before a .QUOTE is deleted. Not only dummy names, but TERMIN, .QUOTE, and the pseudos matched by TERMINs (DEFINE, .TTYMAC, and the various flavors of IRP) are not detected or treated specially when within a .QUOTE . d. inner macro definitions. In order to make it possible to define a macro which will, when called, define another macro, it is possible to insert matching DEFINE - TERMIN pairs in a macro definition. A definition is ended not by the first TERMIN after the DEFINE, but by the first TERMIN that is unmatched by previous DEFINEs (or other pseudos such as IRP and .TTYMAC that also expect to be matched by TERMINs). (DEFINEs, TERMINs, etc. within .QUOTEs are ignored in the matching-up.) Remember that when the outer macro is called and the inner one is defined, its TERMIN will gobble up one character. For that reason, when a macro definition ends with an inner macro definition or an IRP, "TERMIN TERMIN" should be used, rather than "TERMIN!TERMIN". If the latter is used, the main macro will end with "TERMIN", so when it is called the inner "TERMIN" will gobble an extra character after the call. Using the space gives the inner TERMIN a character to gobble, thus protecting all the other characters from being gobbled. e. .STOP The .STOP pseudo is used to exit from a macro. At macro expansion time, when .STOP is executed, the rest of the macro body will be ignored that time through. execution will continue with the first character after the macro call. For example, DEFINE FOO A,B 1 IFE A,.STOP 2 TERMIN FOO 1 ; 1 ; 2 ;note the .STOP isn't exectuted. FOO 0 ; 1 ;and that's all, because of the .STOP. Beware of putting a .STOP inside brackets ("[" and "]"). Because brackets are used for both literals and conditionals, MIDAS must keep a stack with an entry for each unmatched "[" saying what is was for. If a .STOP, which is like a jump to the end of the macro body, is within brackets inside the macro, then although those bracket pairs will be exited, the bracket stack will not be updated because the closebrackets will not be encountered. When a "]" is next seen, MIDAS may treat it the wrong way (eg, may think it closes a literal when it was supposed to close a conditional). The way to win is to use braces ("{" and "}") instead of brackets when conditionalizing a .STOP. Since braces are not used for anything but conditionals, there is no need for MIDAS to maintain such a stack, and thus no data base is invalidated if the brace depth is changed. Thus, this macro may cause problems: DEFINE FOO A,B 1 IFE A,[.STOP ] 2 TERMIN and this one should be preferred: DEFINE FOO A,B 1 IFE A,{.STOP } 2 TERMIN f. .TAG and .GO These two pseudos provide arbitrary trasfers at macro expansion time. That is, they do not assemble into jump instructions; rather, they tell MIDAS to jump around while expanding the macro. That can cause parts of the macro to be expanded more than once or not at all. The way to use them is to put .GO at the place MIDAS should transfer from, and .TAG at the place it should transfer to. Thus, .GO FOO will transfer to a .TAG FOO . Nonlocal transfers are allowed; if a .GO does not find a matching TAG in the macro it is in, it will exit that macro and search the macro which called the macro containing the .GO. Any number of levels may be popped up this way but popping into a file will cause lossage. There should be a space after the in both the .GO and the .TAG to prevent lossage. Note that .GO and .TAG may be used in REPEAT's and IRP's just as in macros, and nonlocal .GO's in macros are allowed to find .TAG's in IRP's and REPEST's, etc. Transfering from one level in brackets to another has dangers associated with it, just as with .STOP - see the detailed explanation under e. For example, DEFINE FOO BAR==5 .TAG BARF BAR==BAR-1 BLETCH IFN BAR,.GO BARF TERMIN when called, will do BLETCH 5 times (of course, a REPEAT could have been used in this case, and would have meant a simpler macro). B. MACRO CALLS. 0. GENERALITIES. A macro call is a request for the body of a macro to be substituted into the text to be assembled. The call must specify the name of the macro and the values to be given to the macro's dummy arguments (if it has any) 1. MACRO CALL SYNTAX. Every macro call begins with name of the macro. In order for the macro name to be recognized as such, it must be evaluated. Therefore, macro calls are possible only in those places where a symbol will be evaluated. (For example, putting the macro's name in the middle of an ASCII will not cause the macro to be called). a. macros with no dummies. A call to a macro without dummies consists of just the macro name. The character that terminates the name is left to be reprocessed after the text of the macro is processed. b. degenerate calls. A degenerate call to a macro with dummies consists of the macro name followed by an EOL. The EOL or CRLF will be thrown away. All the dummies of the macro will be unspecified (see B.7). c. normal calls. A normal call to a macro with dummies follows the macro name with anything but an EOL or OPEN. The character immediately after the macro name will be ignored. After it, the scanning for the values of the dummies will commence. MIDAS considers "by order" dummies one at a time, in the order they appeared in the macro definition. Each dummy is given a value obtained by scanning the text of the macro call according to the argument syntax determined by the dummy's bindclass (which is one of normal, balanced and wholeline). (See B.2 through B.7 for descriptions of the argument syntaxes). When a run of "by keyword" dummies is reached, MIDAS expects to see in the macro call expressions of the form =. MIDAS reads the dummy name and checks that the "=" is there; it then finds the dummy with that name and reads in the using that dummy's bindclass. When, instead of a dummy name, a terminator (comma, EOL, semicolon, CLOSE, etc) is seen, all the "by keyword" dummies in that particular run of them which have not been specified in the macro call are considered to be unspecified. If there are by order dummies after the run of by keyword ones, MIDAS then proceeds to read in their values. If the scan for one dummy detects the "end of the call" (see B.2.d) then the scan for all following dummies becomes trivial: they are all unspecified, regardless of their designated argument syntaxes, and no more characters will be read from the input stream for any of them. If a normal call is ended in this fashion by an EOL, the EOL or CRLF is thrown away. d. parenthesized calls. In these calls, the macro name is followed by an OPEN. The assignment of values to dummies procedes as in a normal call. At the end, though, characters are thrown away until and including a CLOSE that matches the OPEN. In the matching, parens and brackets within the values of dummies are not considered. Also, only the number of brackets seen is remembered - not what kind. There is nothing to stop a "(" from matching a ">" at this stage. Parenthesized calls are most useful with macros whose dummies are balanced - then the macro call is guaranteed to terminate precisely at that closeparen that matches the initial openparen, regardless of whether enough or too many argumentss are present in between. Note that where. below, the macro call is said to be "ended", in a parenthesized call that really means that scanning for the matching closeparen will begin. 2. THE "NORMAL" ARGUMENT SYNTAX. MIDAS begins scanning for a normal argument by examining the first character. a. first character is "[". All the text up to the matching "]", not including either of them, is part of the dummy's value, and the scanning of the next dummy begins with the character after the "]". If a normal argument is delimited by squarebrackets, it is never unspecified or nullspecified, even if the value between the squarebrackets is the null string. Thus, when a dummy has a default value, it is possible to specify the null string explicitly in the call, overriding the default. b. first character is "\". A field is read (leading spaces ignored) and the field's value, converted to a string using MIDAS's current radix, is used as the value of the dummy. In this case the scan of the next argument begins with the character after the field terminator. Arguments specified in this way are never unspecified or nullspecified. c. first char is ",". In this case, the dummy is nullspecified (see B.7). The scan for the next dummy, or the text to be handled after the macro call if there are no more dummies, starts after the comma. d. first character is an EOL or semicolon. This dummy is unspecified (see B.7), and so are all remaining dummies. The scan for the remaining dummies will not attempt to read any characters. If the terminator was an EOL, and the call is a normal one, the EOL or CRLF will be thrown away at the end of macro call processing (see B.1.c). e. otherwise. All text, including the first character, up to the first comma, semicolon or EOL goes into the argument, except that tabs and spaces before a semicolon are ignored. Then, depending on the terminating character, action is taken as in B.2.c or B.2.d, except that in neither case is the present dummy nullspecified or unspecified, since a nonnull value has already been specified for it. 3. THE "BALANCED" ARGUMENT SYNTAX. When a dummy uses the balanced syntax, MIDAS insists that its value contain no unbalanced brackets. That is, while scanning for the end of the argument, MIDAS counts opens and closes, and will not let anything terminate the argument when the count is nonzero. Also, unmatched closes will not be allowed into the argument - they will terminate the argument and the macro call. When the bracket count is zero - that is, when it is permissible for the argument to terminate - a comma, semicolon, or EOL will do it, just as if the dummy used the normal syntax. That is, unspecification or nullspecification of the present dummy or the remaining dummies may happen, as described in B.2.c-B.2.e. Termination by an unmatched close is like termination by an EOL (B.2.d). For balanced dummies, "[" or "\" as the first character have no special significance. 4. THE "WHOLELINE" ARGUMENT SYNTAX. The scan for a wholeline argument stops only when an EOL is encountered. Thus, the value of a wholeline argument is everything up to but not including the first eol. While an EOL that terminates a normal or balanced argument ends the macro call, thus making all remaining dummies unspecified, the EOL that ends a wholeline argument does not do so. The EOL or CRLF is thrown away, and scanning for the next dummy starts on the next line. A wholeline dummy is never unspecified or nullspecified (except that it will of course be unspecified if the macro call is terminated by an EOL ending some previous non-wholeline dummy). 5. THE "STRUNG" ARGUMENT SYNTAX. A strung argument looks just like the argument to ASCII or SIXBIT: it is bounded on both sides by an arbitrarily chosen delimiter. When the argument is scanned, first non-space character is taken to be the delimiter, and everything up to the second occurrence of that character is part of the argument's value. Semicolon, EOL, comma, and closebrackets of various kinds, cannot be used as the delimiter, because if they are seen when the opening delimiter is expected they will nullspecify the argument and (except for comma) end the macro call, as they would in the balanced syntax. The closing delimiter should be followed by an appropriate argument terminator such as comma, semicolon, EOL, or a closebracket (but spaces and tabs may intervene); all except comma end the macro call, while comma allows more arguments to follow. 6. THE "KEEPSTRUNG" ARGUMENT SYNTAX. A keepstrung argument is exactly like a strung argument, except that the delimiters are retained. This is useful for passing on such arguments to other macros or pseudos, without having to worry about what delimiters to use, since appropriate ones will be included with the argument itself. 7. THE "EVALUATED" ARGUMENT SYNTAX. An evaluated argument is passed by value instead of by name. When it is time to scan for such an argument, a field is read in and evaluated, and the value is converted to a string by expressing it as a number in the current radix. This is exactly like the treatment of a normal argument whose value starts with "\", except that the "\" is not present itself in the call (see B.2.b). 8. WHAT HAPPENS TO DUMMIES THAT ARE UNSPECIFIED. Whether a dummy is unspecified in a particular call depends on what came in the call before the place where the dummy's value should have been, and on the variety of argument syntax used by the dummy. Similarly, the criterion for being nullspecified depends on the argument syntax used. However, the consequences of being unspecified or nullspecified are independent of the argument syntax used. Instead, they depend on the other part of the bindclass of the dummy: whether it is to be nullified, gensymmed, or defaulted to a pre-specified value. a. nullified dummies. When a dummy defined as nullified is unspecified or nullspecified, it is given the null string as its value. Most dummies of most macros used are of bindclass nullified. b. gensymmed dummies. If a gensymmed dummy is unspecified, its value will be a GENERATED SYMBOL 6 characters long - the first character "G"; the rest, a number in the current radix whose value equals that of .GSCNT, which starts out as 0 and is incremented before each gensymming. Thus, in each call, an unspecified gensymmed dummy will provide a unique label. If nullspecified, a gensymmed dummy has the null string as a value. Gensymmed dummies are treated differently when nullspecified or unspecified for compatability with old versions of MIDAS. In fact, the distinction between unspecification and nullspecification is made only to handle this case. c. defaulted dummies. If a defaulted dummy is nullspecified or unspecified, its default value will be used as its value in that call. C. EXAMPLES OF MACRO DEFINITIONS AND CALLS. 1. NORMAL (NULLIFIED AND DEFAULTED) ARGUMENTS. DEFINE MACRO1 A,B=FOO,C ;3 DUMMIES; SECOND DEFAULTED. A ? B ? C TERMIN MACRO1 1,2,3 ; 1 ? 2 ? 3 MACRO1 [FOO,,BAR]2,3 ; FOO,,BAR ? 2 ? 3 ;Showing how to put commas, etc. in args. MACRO1 1,,3 ;2nd arg nullspecified and defaulted. ; 1 ? FOO ? 3 MACRO1 1,[]3 ;2nd specified as null, not nullspecified. ; 1 ? ? 3 MACRO1 1,2 ;3rd arg unspecified. ; 1 ? 2 ? MACRO1 1 ;2nd and 3rd args unspecified; 2nd defaulted. ; 1 ? FOO ? 2. BALANCED ARGUMENTS. DEFINE MAC2 ?A,B ;2 BALANCED DUMMIES. A ? B ? BLETCH TERMIN DEFINE MAC2(A,,B,,),, ;another way to define the same macro. A ? B ? BLETCH TERMIN DEFINE MAC2A A,B ;SIMILAR BUT DUMMIES NOT BALANCED. A ? B ? BLETCH TERMIN MAC2 , ; ? ? BLETCH MAC2A , ; ? BLETCH ; ;Note that the first dummy was bound to "". ;The "" wasn't even part of the call. MAC2(FOO,-1(P))+1 ; FOO ? -1(P) ? BLETCH+1 ;A parenthesized call. Note that the closeparen ;ends the second arg and the macro call, and is thrown away. MAC2 FOO,-1(P)+1 ; FOO ? -1(P)+1 ? BLETCH DEFINE SQR (X) <*>TERMIN ;this macro squares its arg. 1+SQR(2)*3 ;a parenthesized call. ;1+<<2>*<2>>*3 ;note that 1+SQR(2>*3 would have the same effect. 3*<1+SQR 2>-4 ;3*<1+<<2>*<2>>>-4 ;Here we have, not a parenthesized call, ;but an ordinary call within parens. ;The ">" ends the argument to SQR and is not thrown away. 3. GENSYMMING. DEFINE GENMAC \FOO,BAR FOO,,BAR TERMIN GENMAC X+1,Y ;Both args specified nonnull. ; X+1,,Y GENMAC X+1,, ;Second arg nullspecified. ; X+1,, ;Nullspecified args are not gensymmed. GENMAC X+1 ;Second arg unspecified. ; X+1,,G00001 GENMAC X+1 ;Note uniqueness of gensyms. ; X+1,,G00002 GENMAC() ;Both args unspecified ; G00003,,G00004 GENMAC(,) ;First arg nullspecified; second, unspecified. ; ,,G00005 4. WHOLELINE ARGUMENTS. DEFINE FOOWH A-B ;first arg normal; second, wholeline. A B TERMIN FOOWH 1,2,3,4 ; 1 ; 2,3,4 FOOWH 1 ; 1 ; DEFINE BARWH -A B ;both args wholeline. A B TERMIN BARWH 1,2,3 ;note that each arg requires a line. 4,5,6 ;a comment on the line is part of the arg. ;that is, semicolon isn't special. ; 1,2,3 ;note that each arg requires a line. ; 4,5,6 ;a comment on the line is part of the arg. 5. "BY KEYWORD" DUMMIES. DEFINE KWDM +A,B,C=FOO,+ ;all three arguments by keyword. A B C TERMIN KWDM B=1, A =2 ; 1 ; 2 ; FOO KWDM C=1 ; ; ; 1 DEFINE KWD1 A=1,+B=2,C=3,+D=4 ;B and C are by keyword; A and D are by order. A ? B ? C ? D TERMIN KWD1 100,,200 ;both A and D but neither B nor C specified. ; 100 ? 2 ? 3 ? 200 KWD1 10,C=11 ;A and C specified. ; 10 ? 2 ? 11 ? 4 KWD1 ,B=20,C=21,,40 ;B, C and D specified; A was nullspecified. ; 1 ? 20 ? 21 ? 40 6. STRUNG AND KEEPSTRUNG DUMMIES. DEFINE TYPEZ *STR* ;STR is strung. OUTUUO [ASCIZ ^@STR ^@]TERMIN ;note ctrl-@ used as delimiter of ASCIZ. TYPEZ /UNDEFINED SYMBOL/ ; OUTUUO [ASCIZ ^@UNDEFINED SYMBOL ;^@] FOO== ;Here a closebracket follows the string. ;FOO==< OUTUUO [ASCIZ ^@WHY FOO? ;^@]> TYPEZ(:MYSTERIOUS ERROR:) ;A parenthesized call, and a strange delimiter. ; OUTUUO [ASCIZ ^@MYSTERIOUS ERROR ;^@] DEFINE ASCNT &KSTR& ; KSTR is keepstrung. .LENGTH KSTR,,[ASCII KSTR]!TERMIN OUTUUO [ASCNT "String=^@"] ; Note that delimiters are kept with argument. ;OUTUUO [.LENGTH "String=^@",,[ASCII "String=^@"]] DEFINE 2STRS *A=UGH,B* ;Two strung arguments, one defaulted. ASCIZ /A,B/ TERMIN 2STRS =FOO= ;Call ended after 1st string ; ASCIZ /FOO,/ 2STRS .FOO.,-BAR- ; ASCIZ /FOO,BAR/ 2STRS ,/BAR/ ;Here no 1st argument is given ; ASCIZ /UGH,BAR/ 2STRS //,/BAR/ ;Here an explicit null string is given. ; ASCIZ /,BAR/ 7. EVALUATED DUMMIES. DEFINE TYPECH #CHAR ;CHAR is evaluated. MOVEI A,CHAR PUSHJ P,TYO TERMIN TYPECH 40 ;Print a space. ; MOVEI A,40 ; PUSHJ P,TYO TYPECH "; ;Print a semicolon ; MOVEI A,73 ;73 is the value of ";. ; PUSHJ P,TYO ;This would not be possible with normal ;or balanced syntax, since the ";" would ;be an argument terminator. DEFINE TYPEI (CHAR) ;CHAR balanced instead of evaluated MOVEI A,CHAR PUSHJ P,TYO TERMIN TYPECH "0(B) ;Print C(B) as a digit. ; MOVEI A,"0(B) ;This would not work with TYPECH, ; PUSHJ P,TYO ;Since CHAR would evaluate to B,,"0 ;giving MOVEI A, = MOVEI A,"0. D. THE "REMOTE MACRO" CONSTRUCTION. It is often desirable to use a macro as if it were a string variable, appending text to it little by little and then accessing the whole text as accumulated at some time. A way to do this is as follows: ;initialization: IF1 [DEFINE BNKBLK OP OP TERMIN ] ;BNKBLK accumulates text. DEFINE BLCODE NEWCFT BNKBLK [DEFINE BNKBLK OP OP]NEWCFT TERMIN TERMIN ;BLCODE adds its arg to the end of BNKBLK. ;add some text: BLCODE [FOO] ;add FOO. BLCODE [BAR] ;add BAR (note BLCODE inserts CRLF's, too). ;assemble what has been accumulated: BNKBLK ;which expands into ... ; FOO ; BAR In understanding this example, it is necessary to realize that MIDAS is a string-processing language that just happens to produce binary output as a side effect. It does not matter whether an expression appears to be properly nested with the various sorts of syntactic bracket (such as [-] and DEFINE-TERMIN) because the order the brackets are processed in may not be the order they appear in - especially since not all phases of processing look for all types of bracket. For example, when BLCODE is called, it calls BNKBLK with argument "DEFINE BNKBLK OPOP". That there is an unmatched DEFINE in that argument does not matter because DEFINE is not special at macro call time or macro expansion time. Since BNKBLK substitutes its arg in, there will be an unmatched DEFINE in the expansion of BNKBLK. So, when MIDAS expands BNKBLK, it will begin processing the DEFINE, and it will keep on reading for the new macro definition past the end of BNKBLK. That is not a problem, because AFTER the call to BNKBLK, within BLCODE, there is a TERMIN that will make MIDAS end the new macro definition. The inner DEFINE and TERMIN appear to match in a simple minded way, which is necessary since otherwise it would be difficult to define BLCODE containing them, but when BLCODE is called they actually match up in a much more complicated way. To get a full understanding of exactly what expands into what, assemble such a segment of program with the (L) switch. The listing will show not only macro calls but what they expand into. Two other examples using this construct follow. They use a modification of the remote-macro hack to accumulate things in the reverse of the order they are put in. ;Backwards IRP: to get the backwards version of ;IRP FO,BA,[mumble] ; body!TERMIN ;use ;IRPB FO,BA,[mumble][body] DEFINE IRPB X,Y,Z,BODY ;IRP BACKWARDS DEFINE 1IRPB1 FOO FOO!TERMIN DEFINE 2IRPB2 BAR 1IRPB1 [DEFINE 1IRPB1 FOO FOO BAR]TERMIN TERMIN IRP X,Y,[Z] 2IRPB2 [BODY] TERMIN 1IRPB1 TERMIN ;LISP-style PROGs in MIDAS - use these macros as follows: ; PROG [X,Y,Z] ;X, Y, and Z are the locals. ; body of subroutine ; ENDPROG DEFINE PROG VARS IRP X,,[VARS] PUSH P,X TERMIN DEFINE ENDPROG FOO FOO TERMIN DEFINE 2PROG2 BAR ENDPROG [DEFINE ENDPROG FOO FOO BAR]TERMIN TERMIN IRP X,,[VARS] 2PROG2 [POP P,X] TERMIN TERMIN  MIDAS Node: Loops, Up: Top MIDAS Assembly-time Loops Maybel someday this node will be INFO-ized. @. INTRODUCTION. Loops are useful for many reasons. One might merely wish to initialize the contents of a table in a simple pattern. One might also use a loop in conjuntion with macros, in all the ways loops are used in other programming languages. The loops that exist in MIDAS are REPEAT and the various kinds of IRP. Because MIDAS canned loops all begin with pseudoops, they will only be recognized and expanded where a symbol would be evaluated (not within comments, failing conditionals, macro definitions, text strings, etc.). A. REPEAT. 0. REPEAT is used to assemble a single string (called the REPEAT string) several times - like a DO in PL-1 or MACLISP. The REPEAT string need not assemble into the same thing each time, however, because each assembly of the string may have side effects that alter the action of the next. 1. SYNTAX. The REPEAT pseudoop should be followed by a field whose value is the number of times the REPEAT string is to be repeated. That string follows immediately after the field. The syntax of the REPEAT string is the same as that of the string in a conditional. If the first character after the space or comma that ends the field is a "[", then all characters up to the matching "]", not including either of the brackets, make up the string to be repeated. Otherwise, that first character itself and all characters up to the next EOL make up the REPEAT string. The EOL or CRLF is thrown away, and a CRLF is added to the end of the REPEAT string, in the case that square brackets are not used. 2. EXPANSION. A REPEAT expands by substituting the REPEAT string into the assembler input stream appropriately many times. For example, REPEAT 5, SETZ ? 500 is equivalent to SETZ ? 500 SETZ ? 500 SETZ ? 500 SETZ ? 500 SETZ ? 500 where the REPEAT string is "SETZ ? 500 ". Each time through except the last, the last character of the string will be followed immediately by the first character of the string. To illustrate, 0,,REPEAT 3,[.+1 10,,]0 expands into 0,,.+1 10,,.+1 10,,.+1 10,,0 This example also shows that there is no need for the boundary between one pass through the string and the next to coincide with any logical division in the resulting concatenated text (such as a word or field boundary); the several passes through the string may all be part of one syllable if they do not contain any syllable separators! (for example, REPEAT 3,['A] = 'A'A'A = (SIXBIT/AAA/)). 3. .RPCNT. During the expansion of a REPEAT, the symbol .RPCNT has the value of the number of completed passes through the REPEAT; that is, it is 0 the first time through, 1 the second, etc. When nested REPEATs are used, .RPCNT always refers to the innermost REPEAT. For example, REPEAT X,[.RPCNT+]0 is X*/2 for X >= 0. REPEAT X,[<.RPCNT+1>*]1 is FACTORIAL(X). 4. .STOP. When the pseudoop .STOP is executed in a REPEAT, the pass through the REPEAT then in progress is ended. .STOP is like a jump to the label on the END of a DO in PL-1. The character after the "P" of .STOP is ignored; the next character asembled will be the first character of the REPEAT string (if there are more repetitions to go) or the one after the "]", EOL or CRLF that ended the REPEAT string. Thus, REPEAT 5,[ FOO IFE BAR,.STOP ] is equivalent to (but assembles faster if BAR is 0 than) REPEAT 5,[ FOO IFN BAR,[ ]] Note that it currently loses to put .STOP (or .ISTOP) inside a bracketed conditional within the REPEAT. For details and reasons, see the documentation file on macros. The way to avoid this problem is to use braces instead of brackets in conditionals that surround .STOP's. The same applies to .ISTOP, .GO and .TAG. 5. .ISTOP. .ISTOP is like .STOP, but also inhibits all further repetitions of the REPEAT string. It is like a jump to a label after the END of a DO in PL-1. The character after the "P" is ignored; the next character assembled is the one after the "]", EOL or CRLF that ended the REPEAT string. For example, REPEAT 36.,[ FOO==.RPCNT IFN BAR&<1_.RPCNT>,.ISTOP ] sets FOO to the number of trailing zeros in BAR. 6. .GO AND .TAG The pseudos .GO and .TAG may be used inside REPEAT's just as in macros. See the documentation file for macros. B. IRP'S IN GENERAL. 0. IRP's in MIDAS are somewhat analogous to MAPCAR in LISP. In an IRP, a dummy name is supplied and also a string to repeat (called the IRP BODY) and a string (called the IRP STRING) to take substrings from according to a prespecified syntactical rule which depends on which IRP pseudoop is used. The IRP body is assembled several times, with the dummy name bound to successive substrings of the string being IRP'ed over. For example, IRP X,,[1,4,5] FOO+X ? TERMIN expands into FOO+1 ? FOO+4 ? FOO+5 X is the dummy, "1,4,5" is the IRP string, "1", "4", and "5" are the substrings, and "FOO+X ? " is the IRP body. 1. SYNTAX OF IRP'S. All kinds of IRP have the same syntax (except that IRPNC is slightly different). After the pseudoop itself come any number of IRP GROUPS, which make up the IRP HEADER (most IRP's have only one group). then comes the IRP body, which is just like a macro body (see MACROS A.3). 2. IRP GROUPS. Each IRP group specifies one repetition to be done. It contains one string to take substrings from, and two dummies to put them in. The dummy names come first, and should be terminated by commas. If one of the dummies would not be referred to in the IRP body, it may be omitted from the IRP group, but the comma in its position may not be omitted (if a comma is missing, MIDAS will sometimes be able to detect that fact, in which case MIDAS will print an error message and assume there is no second dummy. However, a missing comma is not always detectable). The string to take substrings from comes after the second comma, and its syntax is that of a normal macro argument, except that "\" is not special as the first character. f the first character encountered after the string is read is a squoze character or a comma, MIDAS assumes that it begins another group. Otherwise, the group just ended is the last one. This means that if the string is terminated by a "]" or comma, the character following determines whether another group follows, while if the string is ended by an EOL or ";", there are automatically no more groups. The EOL or ";", or whatever character follows the comma or "]", is thrown away. If the next character is a LF, it too is discarded. A comment following the IRP header will lose. The best possibility is that it will merely go in the IRP body. The worst is that the ";" will be one of the characters thrown away and, causing total lossage. An example of an IRP with several groups is IRP X,,[1,2,3]Y,,[4,5] ASCIZ \X+Y\ TERMIN which expands into ASCIZ \1+4\ ASCIZ \2+5\ ASCIZ \3+\ 3. THE IRP BODY. The body of an IRP is just like the body of a macro definition. The dummy arguments mentioned in the IRP header may be used in the IRP body, representing requests for the corresponding substrings of the IRP strings to be substituted in. Concatenation with "!", and .QUOTE, may be used as in macro definitions. The IRP body is ended by a TERMIN, just like a macro body. Because of this, the character after the "N" of the TERMIN wil be discarded. Also for that reason, IRP's are expected to be matched by TERMIN's within macro bodies and IRP bodies. For example, in DEFINE INSIRP INSN,ADDR IRP X,,[ADDR] INSN,ADDR TERMIN TERMIN the first TERMIN matches the IRP; the second, the DEFINE. When the DEFINE executes, it increments its counter on seeing the IRP, and decrements it on seeing the first TERMIN, so the second TERMIN ends the macro body. A call to INSIRP expands into a string containing the IRP and the first TERMIN, which closes the IRP body when the IRP executes. The result is that in INSIRP PUSH P,[A,B,C] NSN's value is "PUSH P" and ADDR's is "A,B,C". The macro call expands into IRP X,,[A,B,C] PUSH P,X TERMIN which expands into PUSH P,A PUSH P,B PUSH P,C 4. IRP EXPANSION An IRP should be thought of as first defining an internal macro whose body is the IRP body, and whose dummy args are the dummies mentioned in the IRP header, and then calling that macro repeatedly with arguments which are substrings of the IRP strings, chosen according to the rule for the particular IRP pseudoop that was used. Each call made to the internal macro constitutes one pass through the IRP. When an IRP has several groups, on every pass through the IRP each group is stepped to its next substring, independently of the other groups. The expansion of the IRP stops (that is, no more passes through it are made) only when ALL of the groups are exhausted (the ends of all the IRP strings have been reached). 5. .STOP, .ISTOP, .GO AND .TAG. These pseudoops, when executed in an IRP expansion, act the way they do in REPEAT's. That is, .STOP ends only the current pass of the IRP, while .ISTOP also prevents any future passes from starting. See A.4 and A.5. 6. .IRPCNT. While an IRP is being expanded, .IRPCNT has the value of the number of completed passes through the IRP (0 the first pass, 1 on the next, etc.). When nested IRP's are used, .IRPCNT refers to the innermost one. Thus, IRP AC,,[NIL,A,B,C,D,E,F,G,H,I,J,K,L,M,N,P] AC==.IRPCNT TERMIN defines all the ACs with the specified names. C. PARTICULAR TYPES OF IRP. 0. The previous section described what all the IRP pseudoops have in common. This section describes the peculiar details of each IRP pseudoop. The IRP pseudoops differ in how they divide the IRP strings into substrings, and in how they choose the values to be given to the two dummies of each group. 1. IRPC (INDEFINITE REPEAT ON CHARACTERS). IRPC scans the IRP strings a character at a time. Each time through the IRP body, the first dummy of each group is set to the next successive character of the group's IRP string, (or to the null string if the IRP string is exhausted), and the second dummy is set to the remainder of the IRP string - the part that follows the character that the first dummy is set to. For example, in IRPC X,Y,[ABCDE]A,B,1234,U,,[+-+-] ASCIZ /X,Y,A!U!B/ TERMIN the dummies are X and Y in the first group, A and B in the second, and U in the third (which has no second dummy). The IRP strings are "ABCDE", "1234", and "+-+-". The expansion is ASCIZ /A,BCDE,1+234/ ASCIZ /B,CDE,2-34/ ASCIZ /C,DE,3+4/ ASCIZ /D,E,4-/ ASCIZ /E,,/ 2. IRPW (INDEFINITE REPEAT ON WORDS). IRPW takes the IRP strings a line at a time (ignoring null lines). On each pass, the next nonnull line of every IRP string is used up. The first dummy of each group is set to the part of the line up to the first semicolon, and the second dummy is set to the part that follows the semicolon (or to the null string if there is no semicolon on the line). The semicolon, if any, does not become part of either dummy. Unfortunately there is no way to tell whether the line contained no semicolon, or there was only one semicolon and it was the last character - in either case the second dummy will be null. For example, IRPW X,Y,[ FOO ;BAR FOO1 ;MUMBLE ] [X] ;; Y TERMIN expands into [ FOO ] ;; BAR [ FOO1 ] ;; MUMBLE 3. IRPS (INDEFINITE REPEAT ON SYLLABLES). IRPS attempts to scan the IRP strings a syllable at a time. However, it is not smart enough to duplicate the actions of the MIDAS syllable reader perfectly. In actuality, it divides the IRP string into syllables which are strings of consecutive squoze characters separated by strings of consecutive nonsquoze characters. On each pass, the first dummy of each group is set to the next string of consecutive squoze characters found in the IRP string of the group, or to the null string if the group's IRP string is exhausted, and the second dummy is set to the non-squoze character that terminates the run of squoze characters (or to the null string if there is none, because the first dummy's value reaches to the end of the IRP string or the IRP string is exhausted). For example, IRPS X,Y,[A+B+C+ D+,E+ ,, &/!,F-G- H-I+] X==Y!100 TERMIN sets A, B, C, D, E, and I to +100 and F, G, and H to -100. The extra spaces, commas, and "&/!" in the IRP string do not matter, because only the first non-squoze character after each syllable becomes the value of the second dummy Y. Extra CRLF's or + or - signs could also have been inserted at the same places without effect. 4. IRP (INDEFINITE REPEAT (ON ELEMENTS)). IRP regards the IRP string as a list of elements separated by commas, and scans the IRP string an element at a time. An EOL or CRLF will also separate elements but since null elements are not ignored the CRLF or EOL should be used instead of a comma, not in addition to one. Square brackets are also special in the scan of the IRP string. The actual algorithm used by IRP to find the end of the next element is that a comma, EOL or CRLF (or the end of the IRP string) ends the element, and an "[" is flushed but causes commas and EOLs (and therefore CRLFs) not to be special until the matching "]", which is flushed. Note that this resembles but is distinctly different from the normal macro argument syntax rules. On each pass through the IRP, the first dummy of each group is set to the next element in the IRP string of that group, and the second dummy is set to the rest of the IRP string (starting after the comma, EOL or CRLF that ended the element). Note that the commas, EOLs and CRLFs that separate the remaining elements will be present in the second dummy's value, as will square brackets that are doomed to be flushed when the elements they are part of are reached by the scan. For example, IRP X,Y,[123 4,56789 ABCD[EF]GH,[IJ,],K] ASCIZ /X:Y/ TERMIN expands into ASCIZ /123 4:56789 ABCD[EF]GH,[IJ,],K/ ASCIZ /56789:ABCD[EF]GH,[IJ,],K/ ASCIZ /ABCDEFGH:[IJ,],K/ ASCIZ /IJ,:K/ ASCIZ /K/ 5. IRPNC (INDEFINITE REPEAT ON CHARACTERS). IRPNC is similar to IRPC, but more general. It allows the characters of the IRP strings to be taken not only one at a time, but any fixed number at a time. Also, it may be told to ignore any number of characters at the beginning of each of the IRP strings, or to limit the number of passes to be made to a specified maximum value. IRPNC may be used to take an arbitrary substring of a string, or to index into a string. a. Syntactic Differences between IRPNC and Other IRP's IRPNC's syntax differs from that described in B.1 in that after the IRPNC pseudoop itself, before the first IRP group, there come three numeric arguments, terminated by commas. They specify the number of characters to ignore at the beginning of each IRP string (to be referred to as ), the number of characters to take from each IRP string per pass (to be referred to as ), and the maximum number of passes allowed (to be referred to as

).

may be -1, meaning that the number of passes is not numerically limited. If

is 0, the IRPNC is not expanded at all. If is less than 1, it is defaulted to 1. If is negative, it is defaulted to 0. b. Expansion. On each pass, the first dummy of each group is set to the next characters of the group's IRP string (or the whole remainder of the IRP string if fewer than characters remain). On the first pass, instead of using the first characters of the IRP string, which would be like all the other kinds of IRP, characters are skipped and the next are used. (If the IRP string contained fewer than characters to begin with, it is considered to be exhausted starting from the first pass). The second dummy is set to the remainder of the IRP string, following the characters forming the first dummy's value, but containing only those characters that will eventually get into the first dummy. That is, if the number of passes has been limited, the characters of the IRP string that will never appear in the first dummy because it would take too many passes to get that far, will not appear in the value of the second dummy on any pass. c. Applications. To take an arbitrary substring of a string, limit the IRPNC to a single pass. To select characters FOO through FOO+10 of the dummy name BAR, IRPNC FOO,11,1,X,,[BAR] ;in here, use X to refer to the desired substring TERMIN To convert a SIXBIT value to text, index into a string of all the SIXBIT characters in order. This IRPNC will type on the terminal the version number of the program (using .FNAM2). REPEAT 6,[ IFE .FNAM2_<6*.RPCNT>,.ISTOP ;GIVE UP IF ONLY SPACES REMAIN. TEMP==77&<.FNAM2_<6*<5-.RPCNT>>> ;ISOLATE THE NEXT CHAR TO BE TYPED IRPNC TEMP,1,1,X,,[ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_] PRINTX aXa ;NOTE LOWER CASE "a" IS NOT SIXBIT TERMIN ] To XOR together all the words of an ASCII string, use this macro: DEFINE FOO STRING < IRPNC 0,5,-1,BAR,,[STRING] ASCII /BAR/#TERMIN >TERMIN 6. A COMPLICATED IRP EXAMPLE This shows how to assign several symbols default values (that is, set them only if they haven't already been set). It allows each symbol to accompany its value, and either = or == may be used for each symbol independently. IRPW X,,[ FOO==1 ;mumble BAR==500 ;bletch ] IRPS Y,,[X] IFNDEF Y,X .ISTOP TERMIN TERMIN expands into IRPS Y,,[ FOO==1 ] IFNDEF Y, FOO==1 .ISTOP TERMIN IRPS Y,,[ BAR==500 ] IFNDEF Y, BAR==500 .ISTOP TERMIN which expands into IFNDEF FOO, FOO==1 IFNDEF BAR, BAR==500 Note that the expansion is described as a two-step process only to make it easier to understand the effects of the various IRP's. In fact, it all goes on at once, coroutine-style. The flow of control is approximately: read in the IRPW's arguments, set up the first pass through the IRPW, encounter the IRPS and read its arguments (which come out of the IRPW's body), begin the first pass through the IRPS, perform the IFNDEF, hit the .ISTOP which exits from the IRPS, preventing further passes through it, try again to read from the IRPW body, reach the end of it and then set up for the next pass through the IRPW.  MIDAS Node: Cond, Up: Top Conditional Assembly in MIDAS Maybe someday this node will be INFO-ized. @. OVERVIEW. It is often desirable to decide at assembly time, rather than at editing time, whether a particular piece of code is to be assembled. One might wish to assemble different versions of a program, usually based on the value of some symbol. Also, in order for arbitrary functions to be expressed by macros, conditionals are needed. When thinking about MIDAS conditionals, one should always remember that MIDAS is a string-processing language which simply happens to output the values of most expressions evaluated into the binary file. A. CONDITIONALS IN GENERAL. 1. SYNTAX OF CONDITIONALS. Every MIDAS conditional construct begins with a pseudo which introduces the condition. This pseudo may require arguments which are part of the condition - a given conditionalizing pseudo always requires a particular number of arguments. After those arguments, if any, comes the text to be conditionalized, in a format independent of which condition was tested. 2. WHERE CONDITIONALS MAY BE USED. Because the constructs begin with pseudos, they are only recognized as such in places where symbols' values are being examined. Those are exactly the places in which macro calls will be recognized. explicitly, something that looks like a conditional but appears inside a macro definition, a text string, a comment, a macro call, etc. will not be treated as a conditional but as part of the macro body, text string, comment, or macro argument, etc. Of course, if the conditional appears inside a macro definition, when the macro is called the conditional will be recognized unless there is something else to stop it. The point is that in DEFINE FOO IFN 0,TERMIN the TERMIN shown does end the definition of FOO even though it is inside what appears to be a failing conditional, because that conditional is not recognized at macro definition time. The definition of FOO is "IFN 0,". When the macro FOO is called, it will expand into a conditional, which WILL be recognized that time. Thus, FOO BAR will not assemble the BAR because the BAR will be inside a failing conditional. 3. SYNTAX OF THE CONDITIONALIZED TEXT. The conditional pseudo, together with arguments if any, are usually arranged to end with a field-terminator (SPACE or COMMA). The first character after that field-terminator is the beginning of the conditionalized text. The extent of the conditionalized text is determined in one of three ways, depending on whether that first character is one of "[" and "{". a. one line conditionals. If the first character is not "[" or "{", then the conditionalized text is the rest of the line containing the conditional. For example, IFN X,FOO+BAR conditionalizes the string "FOO+BAR" on the value of X. It does not matter how many "["'s or "]"'s there are in the line. There may be other conditionals in the line, but it isn't wise to have any multi-line bracketed ones start in the conditionalized line. b. bracketed conditionals. If the first character is "[", the conditional is called "bracketed". In this case, the conditionalized text runs up to the "]" that matches the "[". The opening "[" and the closing "]" are ignored except for their function as delimiters of the conditionalized text. Other "["'s and "]"'s in the conditionalized text act as normal, as well as being counted to find the end of the conditional. The conditional may span many lines, or may be only a part of a line. For example, IFN X,[BAR-]FOO assembles either FOO or BAR-FOO depending on the value of X. However, IFN X, [BAR-]FOO conditionalizes the string " [BAR-]FOO" because the first character of the conditionalized text is not a "[". Note that though when the conditional fails, the brackets inside the conditional are just those that are visible, since macros, etc., are not expanded if the condition fails, if the condition succeeds the expansion of macros may cause other brackets to appear inside the conditionalized text. If such brackets are unbalanced, they may cause the opening "[" of the conditional to match a bracket other than the intended one, which may in obscure circumstances ruin the assembly. If the "]" of a failing bracketed conditional is missing, the assembly will by a complete loss. In that case, the error message will say where the beginning of the conditional was located. If the "]" of a successful bracketed conditional is missing, no harm results unless a literal was in progress. However, it means that if in another assembly the same conditional failed (perhaps due to different parameter settings), lossage would occur. Therefore, MIDAS prints a message at the end of the assembly stating that there was an unterminated successful conditional, and says where the first one was. Fixing that one and reassembling will cause MIDAS to find the second one, if there are any more. The reason that MIDAS must remember unterminated successful bracketed conditionals is that a "]" in MIDAS may terminate a literal or a conditional, and MIDAS has to be able to decide which whenever a "]" is seen. This means that when a .STOP, .ISTOP, .GO or .TAG is inside "[" - "]" pairs, lossage can result because brackets are skipped over, causing the "[" stack to get out of phase with the position in the macro or loop. For this reason, bracketed conditionals should never be used to conditionalize those four pseudos. Braced conditionals should be used instead. c. braced conditionals. Braced conditionals look just like bracketed conditionals except that braces ("{" and "}") are used instead of brackets. Braced conditionals count ONLY braces when matching up - brackets have no effect on them. Semantically, braced conditionals are almost the same as bracketed conditionals but the few differences are important in some situations. The differences come from the fact that MIDAS does not keep a stack of all unterminated successful braced conditionals, whereas for bracketed conditionals it does. MIDAS can get away without such a stack because braced conditionals cannot be confused with literals, unlike brackets. This has two consequences: first, MIDAS cannot warn the user about unintentionally unterminated successful braced conditionals; second, intentionally unterminated braced conditionals are possible. If that boggles your mind, note that in IFE X,{.STOP } the conditional is unterminated if it is successful. Also, because brackets do not interfere with braced conditionals, constructions such as IFE X,{ASCII/ [/} are possible. While overall unbalanced brackets are unwise, it may be reasonable to have such constructions in parts of a macro which as a whole has balanced brackets. There are reasonable constructions which can sometimes result in unmatched braces/brackets, and for which therefore only braces should be used. An example is the hack for OR'ing two condions: IFN X,{IFNDEF A,} If the IFN succeeds but the IFNDEF fails, the "}" will not be assembled. If brackets were used, that might cause trouble. 4. .SUCCESS, .ALSO, .ELSE. After the testing of the condition, when it has been decided whether the conditional has succeeded or failed, the symbol .SUCCESS is given a value automatically - 0 if the conditional failed, and -1 if it suceeded. Also, after the "]" terminating a bracketed conditional, .SUCCESS is again set to the same value. The conditionals .ALSO and .ELSE test the symbol .SUCCESS's value, and may be used to generate IF-THEN-ELSE constructs as follows: IFN X,FOO .ELSE BAR ;assembles either FOO or BAR. IFN X,[ FOO ] .ELSE [ BAR ] ;similar, but now it works even if ;"FOO" is a macro containing conditionals ;that clobber .SUCCESS. IFN X,IFN Y,FOO .ELSE BAR ;assembles FOO if both X and Y are nonzero. ;assembles BAR otherwise IFN X,[IFN Y,[FOO]] .ELSE BAR ;if X=1 and Y=0, assembles nothing. IFN X,FOO ;assembles either FOO and MUMBLE, or BAR .ELSE BAR ;because .ELSE sets .SUCCESS. .ELSE MUMBLE IFN X,FOO .ALSO BAR ;assembles FOO and BAR, or nothing. B. THE CONDITIONS AVAILABLE. This section describes all the conditional pseudos in MIDAS and their conditions and arguments. 1. ARITHMETIC CONDITIONALS. These conditionals all test the sign of an expression. They are: IFN X,FOO ;assemble FOO if X is nonzero IFG X,FOO ;assemble FOO if X is positive IFGE X,FOO ;assemble FOO if X is nonnegative IFL X,FOO ;assemble FOO if X is negative IFLE X,FOO ;assemble FOO if X is nonpositive IFE X,FOO ;assemble FOO if X is zero 2. STRING CONDITIONALS. These take two string arguments and compare them for equality. IFSE succeeds if the strings are equal; IFSN, if they are not. The case of alphabetic characters is ignored, so "a" and "A" match. The syntax of the string arguments is the same as that of normal macro arguments except that "\" is not special as the first character. Examples: IFSE FOO,BAR,[BLETCH] ;assembles BLETCH if FOO and BAR are equal ;strings (which obviously can't be the case ;unless either FOO or BAR is a macro dummy ;argument which will be replaced by something). IFSE FOO,[BAR][BLETCH] ;has the same meaning, but now "[]" are used to ;delimit the second string argument. This makes ;it possible to win if BAR contains commas or ;CRLF's. Note that, as with bracketed macro ;arguments, a comma is not needed after [BAR]. ;In fact, a comma there would be wrong: IFSE FOO,[BAR],[BLETCH] ;conditionalizes the string ",[BLETCH]", because ;the first character of the conditionalized text ;is the comma, so the "[" in front of the ;"BLETCH" is not recognized. IFSE [FOO][BAR][BLETCH] ;this is just like the first example, but now ;FOO and BAR may contain commas or CRLF's. 3. CONDITIONALS ON SYMBOL DEFINITION. These conditionals test whether a specified symbol is defined. The symbol should follow the conditional name, ended by a field-terminator, which is followed by the conditionalized text. The pseudos are IFDEF, which succeeds if the symbol is defined, and IFNDEF, which has the opposite sense. For example, IFNDEF FOO,FOO=1 ;defines FOO to be 1 if it isn't defined ;already. it is a good idea to define all the ;assembly parameters of a program in this way so ;that it is not necessary to edit the program to ;assemble it with different settings - instead, ;just assemble the program with the "T" switch ;in the command string and then type the desired ;definitions in from the TTY. IFNDEF FOO,.M"FOO=1 ;if FOO isn't defined, defines it in the main ;block (the previous example would define it in ;the current block. IFNDEF XX"FOO,XX"FOO=1 ;if FOO isn't defined in block XX, defines it to ;be 1. IFDEF FOOBAR,PUSHJ P,FOOBAR .ELSE JFCL ;call the FOOBAR routine if the user has one. ;this might appear in a package that is ;.INSRT'ed by several programs. ;The .ELSE is needed because on pass 1 it will ;not in general be known yet whether the user ;has a FOOBAR routine. 4. "BLANKNESS" CONDITIONALS. These conditionals take a single string argument, using macro argument syntax (just like IFSE), and test whether it contains any SQUOZE characters (letters, digits, and ".", "$", "%"). The string is "blank" if it has no SQUOZE characters. The conditionals are IFB "If Blank" and IFNB "If Not Blank". Examples: IFB X,FOO ;assembles FOO unless X contains a SQUOZE ;character. Since "X" IS a SQUOZE character, the ;conditional will always fail unless X is a ;macro dummy argument. IFB [X]FOO ;has the same semantics, but X may now contain ;commas, CRLF's, etc. 5. SQUOZENESS CONDITIONALS. These conditionals are somewhat like the blankness conditionals, but instead of testing whether any of the characters in the argument is squoze, they test whether all of the characters are squoze. The conditionals are IFSQ "If all SQuoze" and IFNSQ "If Not all SQuoze". Examples: DEFINE FOO X 1+< IFSQ X,[1] > TERMIN FOO BAR ;assembles 2 FOO BAR BLETCH ;assembles 1 6. PASS CONDITIONALS. These two conditionals allow different things to be assembled on pass 1 and pass 2. IF1 succeeds only on pass 1, and IF2 only on pass 2. Note that the conditionalized text starts with the character after the space or comma that ends the name of the pseudo. One use is to avoid defining macros on pass 2: if a macro is never to be redefined, there is no need to define it on pass 2, because it already has the correct definition, given to it on pass 1. Thus, IF1 [ DEFINE FOO .... TERMIN ] Another use might be: have a macro to make entries in the FOO table. On pass 1, simply have the macro count up the number of times it is called. Then, at the end of the file, allocate enough words for the table. From then on, the address of the table is known, so on pass 2 the macro can actually assemble values into the words of the table. Caution is needed when using pass conditionals, because, by assembling more words on one pass than on the other, it is easy to cause all the labels in the rest of the program to yield "MDT" errors, because their addresses on pass 2 are not the same as they were on pass 1. Also, one should avoid using any literals on pass 2 that were not used on pass 1 (but doing the opposite can't do worse than make the constants area waste some space). 7. .ELSE AND .ALSO. .ELSE and .ALSO exist to make a generalized IF-THEN-ELSE construction possible. They act just like "IFE .SUCCESS" and "IFN .SUCCESS" respectively. The conditionalized text starts after the space or comma that terminates the pseudo itself. See section A.4. for more details.  MIDAS Node: .I.F, Up: Top The arithmetic-statement pseudo-ops: .I and .F B.K.P. Horn This is a feature of MIDAS which facilitates the rapid writing and debugging of programs involving much nmerical calculation. The statements used are ALGOL-like and easy to interpret. [ Note: This was originally written as AI Memo #179, Aug 1969, and has been copied into this file with as much verisimilitude as possible] --------------------------------------------------------------------------- An arithmetic-statement expander: Since the Incompatible Timesharing System (ITS) does not support an ALGOL style compiler, it is very tedious to perform even the simplest algorithms of numerical analysis. To alleviate this problem without an inordinate amount of effort, two pseudo-ops were added to MIDAS (the macro-assembly language). The pseudo-ops are .F and .I. The first of these will have the arithmetic in the arithmetic statement following it performed in floating point, the latter in fixed point. Each statement is treated without reference to any of the others. Spaces may apear in a statement almost everywhere and are ignored. Exceptions are in the continue part of a continuation statement and in a subscript. (see later on) Arithmetic statements are combinations of variable names, numbers, function names and operators. Normally each statement specifies the calculation of one or more values and where they are to be stored. The operators are: = ( ) < > ^ / * + - # $ , A number is a character-string starting with a numberic character (0, 1 ... 9) followed by non-operators. This number should make sense to MIDAS. The operator ^ is permitted to appear in the number, being the separator used in MIDAS for the exponent of a number. A variable (or function) name is a character-string starting with a character which is neither numeric nor a operator and consists of up to six non- operators. / * + - have the usual meaning of divide, multiply, add and subtract. ^ is used for exponentiation. ( and ) are used to force the precedence as usual, ie normal evalutaion proceeds from left to right, with exponentiation being performed first, then multiplications and divisions, and additions and subtractions last, except that expressions in parentheses are evaluated first. This is strictly adhered to and thus A^B^C = (A^B)^C unlike the FORTRAN convention A**B**C = A**(B**C). Nested pairs of parentheses are evaluated from the inside out. Intermediate results are kept in a stack which has to be in the accumulators and is defined by the user. These accumulators are called A0, A1, ... A9. If fixed point arithmetic is used, Ai must not be = Aj+1 if i surround the arguments of a function. The arguments are separated by commas. Thus a name as defined above is a function name if it is followed by a <. For example: MAX and RANDOM<> If used not directly following a name, < and > act exactly like ( and ). Functions return a single value in A0. The assembled code includes a PUSHJ P, to the function, the user being responsible for providing a subroutine which accepts the arguments as presented in A0, A1, etc., does not disturb any accumulators other than those in which the arguments were passed and returns the result in A0 before executing a POPJ P, . A variable name followed directly by a ( is considered to be a vector. The subscript between the ( and the matching ) can be of the following form: ACxNUM xNUM+AC where "x" is either "+" or "-". Where AC is the variable name of an accumulator in which the subscript is assumed to have been loaded. NUM is a number, acting as a displacement. = indicates that the value available at this point (as calculated by the portion of the arithmetic statement to he right) is to be stored as the value of the variable name to its left. More than one = may thus appear in one arithmetic statement. Fo example: .F A=B=ARM-LOSS=FOO*BARF This invokes the multiplication of FOO by BARF, storage of the result in LOSS. Next LOSS is subtracted from ARM and the result stored in both A and B. More complicated constructs are possible by making use of parentheses. Some care is required in arranging the right sequence of storage operations so as not to overwrite values needed further on. (perhaps a more intuitive structure could be given to multiple equals if one did not adopt the FORTRAN like convention of having the statement follow the equals). = permits the passing of arguments by name rather than value, ie it performs a quoting action. This is particularly useful for subroutines operating on vectors (dotproduct for example), or subroutines executed for their effect rather than their value. It also permits the passing of a function address as a argument. This is achieved by surrounding the variable name with [ and ]. $ indicates a continuation and must be directly followed by a carriage-return and linefeed (usually supplied by TECO anyway) and either .I or .F (which is ignored), a space or tab and the continuation of the statement. For example: .F ZANSWER=273.0/T $ .F -IN*VEST*MENT Unitary + and * are ignored. Unitary / and - are interpreted as 1.0/ and 0.0- respectively. = and ^ may not appear unitarily. Since @ and ' may be part of a variable name, one can make full use of MIDAS's indirect addressing and automatic variable storage assignment conventions. The use of @ comes in very handy when working with multi-dimensional arrays addressed through margin-arrays. ^ normally generates a call to a function called EXPLOG, which gets two arguments. To facilitate generation of fast inline exponentiation one may follow the ^ directly by the single digits 1, 2, 3, or 4. For example: .F R=SQRT  MIDAS Node: FASL, Up: Top Assembling Files to be Loaded by MacLisp Midas can now assemble FASL files that can be loaded by LISP in the same manner as LAP FASL output. This mode is entered by the .FASL pseudo op, which must appear at the beginning of the file before any storage words. After .FASL has been seen, the assembly becomes a two pass relocatable assembly. However, certain restrictions and "changes of interpretation" apply. Global symbols (declared as usual with " or .GLOBAL) are persmissible. However, since the output is to be loaded with FASLOAD using DDT's symbol table instead of STINK, there are quite a few differences in detail. For symbols defined within the current assembly, the only effect of being declared GLOBAL is that the GLOBAL information is passed on to FASL when the symbol table is written at the end of pass 2. This in combination with the SYMBOLS switch in FASLOAD determines whether the symbol gets loaded into DDT's symbol table. If SYMBOLS is NIL, no symbols will be loaded; if SYMBOLS is EQ to SYMBOLS, only globals will be loaded; and if SYMBOLS is T, all symbols (local and global) will be loaded. Once the symbol is loaded (or not), the information as to its GLOBALness is lost and, of course, makes no further difference. The initial state when LISP is loaded is NIL. GLOBAL symbols not defined in the current assembly are also legal, but there are additional restrictions as to where in a storage word they may appear and what masking may be specified (as compared to a normal relocatable assembly). Briefly, they may appear as in a storage word as a full word, a right half, a left half, or an accumulator. They may be negated, but can not be operated on with any other operator. Error printouts will be produced if they appear elsewhere. When the symbol is encountered by FASLOAD, DDT's symbol table is consulted. If it is defined at that time, OK, otherwise FASLOAD will generate an error. Any sort of global parameter assignment or location assignment is Forbidden. .LOP, .LVAL1, .LVAL2, etc are not available. New Pseudo OPs Available only in FASL assemblies. The following pseudos are available to facilitate the communication between MIDAS assembled programs and LISP (particularily with regard to list structure). .ENTRY function type args Function is an atom and is taken as the name of a function beginning at the current location. Type should be one of SUBR, FSUBR or LSUBR, and has the obvious interpretation. Args is a numeric-valued field which is passed thru to FASLOAD and used to construct the args property of the function. If it is zero, no args property is created. Otherwise it is considered to be a halfword divided into two 9 bit bytes, each of which is converted as follows: byte result 0 nil 777 777 otherwise n n-1 These two items are then CONSed and from the args property. The following pseudos may appear in constants!! .ATOM atom followed by a LISP atom in "MIDAS" format (see below). May only appear in right half (or entire word) of a storage word. Assembles into a pointer to the atom header of the specified atom. .SPECI atom similar to .ATOM but assembles into a pointer to the SPECIAL value cell of the specified atom. .FUNCT atom similar to .ATOM, but invokes special action by FASLOAD in case the PURESW is on. Normally used in function calls. Briefly, if FASLOAD is going to purify the function it is loading, it must "snap the links" first. If .FUNCT is used, the location will be examined by FASLOAD and the link snapped if possible before purification. Typical usage: CALL 2,.FUNCT EQUAL ;calls equal as a function of 2 args ; note: the CALL is not defined ; or treated specially by MIDAS. .ARRAY atom similar to .ATOM, but assembles into a pointer to the Array SAR. .SX S-expression similar to .ATOM, but handles a LISP S-expression. (See below). .SXEVA S-expression reads S expression. This S expression is EVALed (for effect presumably) at FASLOAD time. The resulting value is thrown away. Does not form part of storage word. .SXE S-expression Similar to .SX but list is EVALed at FASLOAD time. The resulting value is assembled into storage word. The MIDAS "LISP READER" By a conspiracy between MIDAS and FASLOAD, a version of the LISP reader is available. However, due to historical reasons (mostly, i.e. the FASLOAD format was originally intended only to deal with COMPLR type output), there are a number of "glitches" (see below for list). These will probably tend to go away in the fullness of time. a) numeric ATOM The first character of a LISP atom is examined specially. If it is a # or &, the atom is declared to be numeric and either fixed (#) or floating (&). Midas then proceeds to input a normal numberic field (terminated, note, by either space or comma). This value is then "stored" in the appropriate "space" (fixnum space or flonum space). b) other ATOMs (also known as PNAME atoms or (LISP) SYMBOLS) If the first character of the atom is not # or &, the atom is a "PNAME" atom. / becomes a single character quote character as in LISP. The atom may be indefinitely long. The atom will be terminated by an unquoted space, carrige return, tab, (, ), or semicolon. Unquoted linefeeds are ignored and do not become part of the atom. The character that terminates the atom is "used up" unless it is a ( or ). Note that period is a legal constituent of a atom and does not terminate it or act specially. c) lists. Work normally, but note following caution relative to dot notation: . does not terminate atoms. Thus, to invoke dot notation, the dot must be left delimited by a space, tab, parenthesis, or other character that does terminate atoms. Glitches: 1) Restriction on pass dependant list structure -- In any list reading operation, no new atoms not previously encountered may be encountered for the first time on pass 2. However, this restriction does not apply to atom-only reading operations (.ATOM, .SPECI, .FUNCT etc). 2) Single quote for quoting does not exist (no other macro characters exist either.) 3) Numbers must be flagged as above always. MOVEI A,.ATOM 123 ;LOSES - gives pointer ; to PNAME type atom ; with PNAME 123. it is ; not numeric. use: MOVEI A,.ATOM #123 ;WINS 4) No provision exists to reference "GLOBALSYMS" in FASLOAD. This mostly means only that DDT must be present to load a MIDAS assembled FASL file. (some simple COMPLR and LAP FASL files can successfully be FASLOADed by, for example, a disowned LISP running without a DDT. 5) LOC is illegal in a FASL assembly. BLOCK of a non-relocatable quantity is ok. 6) Currently, symbol loading is VERY slow. Thus use SYMBOLS nil, (the initial state) unless symbols are necessary. 7) Midas does not know about any LISP symbols or UUOs specially. Use them as globals until someone gets around to fixing up a .INSRT file with the appropriate defs. 8) .ATOM "should" be a special case of .SX . However, it is handled separately because of the following "reasons": a) The previously noted restriction on pass dependent LISTS. b) Midas can do constants optimization on atoms ppearing in constants (on both pass one and pass two) but not on LISTS. Therefore, each list is guaranteed to take a separate word in the constants area even if it is identical to some other list which also appears in a constant. c) Each list takes an additional entry in FASLOAD's "atom" table. This is a temporary table that is flushed after the FASLOADing is complete. Of course, .SX still works for atoms modulo the above noted restrictions and inefficencies.  MIDAS Node: Blocks, Up: Top Symbol Table Block Structure The MIDAS symbol table allows blocks of code to be defined within which local definitions of symbols can be made. Local definitions are normally visible within the blocks they belong to, including other smaller blocks included in them, but are normally invisible outside. However, it is possible to examine or set the local value of any symbol in any block explicitly, whether inside the block or outside it. The intended application of block structure is for libraries that are to be assembled into other programs with .INSRT. Because there is a natural tendency to use block structure in assemblers for purposes that do not merit it, any temptation to use block structure for any other reason should be entertained only with great self-restraint. A block is entered with a .BEGIN and exited with a .END. Both the .BEGIN and the .END should be followed by the name of the block. It is not usually wise for two blocks to have the same name, although it is legal if the two are contained in different blocks. .BEGINs and .ENDs must match. .BEGINs and .ENDs serve as a sort of parentheses, and impose a tree structure on all blocks, so that each block has a direct superior and any number of direct inferiors. Initially, even if you never use .BEGIN and .END, there are two blocks in the structure: .INIT, which contains the predefined MIDAS symbols, and .MAIN, which is the one which your program is in. .MAIN is a subblock of .INIT, and any other blocks you .BEGIN are direct or indirect inferiors of .MAIN. .END should not be confused with END, which ends the whole assembly. Block names do not conflict with any other kinds of names. A simple example of block structure will explain much: A=1 A ;Value of A is now 1. .BEGIN FOO ;Enter a block named FOO. A ;Value of A is 1 on pass 1, but 2 on pass 2. A=2 A ;Value of A is now 2. .END FOO ;Exit block FOO. Now back in main block. A ;Value of A is now 1 again. END This program will assemble four words: 1, 2, 2 and 1. This is because, on pass 2, the local definition of A in block FOO becomes visible as soon as the .BEGIN FOO is passed, and ceases to be visible when the .END FOO is passed. The definition of A as 1 in the main block is always visible, except that within FOO it is "shadowed" by a more local one. Whenever a symbol's value is used, the most local definition which is visible determines the value. That is, within block FOO, where both the local definition in FOO and the definition in the main block are visible, the more local one (in FOO) wins out. When a symbol is defined, however, it is always defined in the current block unless you specify otherwise. All operations that affect the symbol's value in any way are counted as definitions in this regard; this includes such things as .HKILL, .KILL, EQUALS, DEFINE, :, and =. When you wish explicit control of shadowing, you can use .BIND. .BIND is followed by a list of symbols, and forcibly markes them as local to the current block, if they were not already defined locally therein. Definitions in outer blocks are hidden by this, so that a symbol defined outside the current block can become undefined inside it, after a .BIND, until a definition in that block is seen. .BIND can be used to force shadowing of some predefined symbols which it is normally an error to shadow. One use of .BIND is to force forward references in a one pass assembly to a symbol defined in an outer block which is going to be defined locally in the current block later on. One pass assemblies and block structure are a can of worms anyway. Normally, a symbol defined in an outer block is NOT visible in lower blocks, unless it is a macro or pseudo, or you mention it in a .DOWN statement. If it is a macro, and you don't want to see it in an inner block, you must .BIND it. The distinctive feature of MIDAS block structure is the ability to look at or set the definition of any symbol in any block at any time. This makes it possible for a block to define symbols in its containing block, or in the main block (a practice whose wisdom is currently a subject of debate). It also allows an outer block to define and refer to symbols in an inner block, which is the main way of communicating with .INSRTed libraries, and is essential. The way to refer to a symbol in a specific block is to prefix the symbol's name with the block name and a doublequote. Thus, FOO"BAR means the value of BAR in block FOO. This construct can be used wherever a symbol name can appear, in both references and definitions. If there is or might be more than one block named FOO, it can be qualified by the name of the containing block, as in UGH"FOO"BAR, which means the value of BAR in that block named FOO which is directy inside a block named UGH. In addition, there are a few special "block names": .C signifies the current block, and .U signifies the direct superior of the current or specified block. Thus, .U"BAR means the value of BAR in the block containing the current one. FOO".U"BAR means the value of BAR in the direct superior of the block FOO. .U"FOO"BAR means the value of BAR in the block FOO which is a sibling of the current one (that is, it and the current one have the same direct superior).  MIDAS Node: Constructs, Up: Top MIDAS constructs, in alphabetical order: ! is the concatenation character inside macro definitions, IRP bodies, and .TTYMAC's. An ! next to either a dummy name or the final TERMIN will be thrown away. For example, inside DEFINE FOO A,B, A!!B will concatenate A's value and B's, as will just A!B. A!!!B will leave one ! between them (the middle ! is not adjacent to either A or B). That may be what you want to do if you are expanding an inner macro definition and A or B wil expand into one of that definition's dummies. " has four constructs: " makes the global, as well as referring to the 's value. " refers to the value of in the specified block. Also, .C refers to the current block, .M to the main block, and .U to the block containing the current one. Multiple use of this construct is allowed: FOO".U"BAR"BLETCH refers to BLETCH in the block named BAR which is contained in the block which is the father of the block FOO. " assembles right-justified ASCII for . contains at least one character in any case, and all following squoze characters. This construct exists only if .QMTCH is zero (as it initially is); otherwise, the next construct exists instead: "" assembles right-justified ASCII for . may contain anything; doublequotes may be put in using the PL/1 quoting convention ("""" gives the ASCII for a doublequote). # XOR operator. # gives the XOR of and . # gives the complement of . ## therefore gives "neither nor ". & AND operator. ' has several constructs, syntactically distinguished. ' makes a variable; like < .SCALAR ? > This construction is a bad one because it makes it easy to assign a storage word without commenting what its contents will mean. It exists for historical reasons. ' forces the use of base 8 in the number, regardless of the current radix. ' like ", but generates SIXBIT instead of ASCII. '' like "", but generates SIXBIT instead of ASCII. (,) () has the value of with its halves swapped, if preceded by an arithmetic operator. Otherwise, it takes that halves-swapped value and adds it into the current word, and is invisible to its neighbors. For example, 1(2)+3 == 1+3(2) == 4(2), and all are the same as 4 except that 2 is added to the left half of the current word. * Multiplication operator. + Addition operator. , Field terminator. It is used for separating the fields of a word, and also terminates the arguments to many pseudos and macros. - Subtraction operator, and unary negation operator. / Division operator. : indicates a label. : defined to be equal to the current value of ".", which is equal to the location being loaded into plus the offset (normally 0, but see .OFFSET). There may not be any spaces before the colon. Once a symbol has been defined as a label, it is an error to give it a different value in any way. :: is similar but "half-kills" , so DDT will not use it for type-out. ; begins a comment, which is ended by the following carriage return. That carriage return is not gobbled; it has its normal effect. ";", like all other MIDAS constructs, is not recognized inside of text strings; also, it is recognized in macro argument scanning only in certain specific situations (see MACROS >). <,> in MIDAS are like parentheses in algebra. They for a "grouping" (other groupings are made by (,) and [,]). They are generalized to allow more than one expression to be within them; the last one's value is the value of the grouping. This makes it possible to do assignments, etc. before computing the ultimate value. = is the assignment operator. = sets 's value to 's. If there are undefined symbols in the assignment is not performed. This construct is illegal where a value is needed, but if it is the last thing in a grouping it does supply the value of the grouping. Thus, FOO= is legal, though FOO=BAR=1 is not. == is similar but half-kills =: is like "=" but makes it an error if ever gets (or previously had) a different value (this is what labels do; =:. is just like :). ==: makes half-killed and unredefinable. ? separates words. ? is just as good as a carriage-return for most purposes, the exceptions being termination of macro arguments and conditionals (? does not terminate them). That facilitates constructs like IFN FOO, MOVE A,B ? JRST BAR which conditionalizes both instructions. @ sets the indirect bit of the word it is in. [,] delimit a literal. Their value is the address of the space MIDAS allocates to contain whatever is assembled inside them. There may be any number of lines or words in the literal. Example: MOVEI A,[.BYTE 7 ? ^M ? ^J] loads A with the address of a word containing the ASCII for carriage-return linefeed. \ Inclusive-or operator. ^ has several constructs: ^ has the value of the control-character associated with . Thus, ^M is 15 . ^ multiplies by 's own radix to the power. Thus, 1.^6 is 1 million. 777^11 is the op-code field. This construct works for floating point numbers as well: 1.0^6 = 1000000.0 . _ left-shift operator.  MIDAS Node: Pseudos, Up: Top Alphabetical list of MIDAS pseudo-ops $. Location being loaded into. Works only via STINK. $L. REAL LOCATION (WITHOUT OFFSET) (only in STINK format) $O. GLOBAL OFFSET (only in STINK format) $R. The relocation factor (only in STINK format) . = address of current code word. In a literal, . refers to the location of the wrd containing the literal, not the word in the literal. The offset is included in the value of .. .1STWD put before a text-generating pseudo (SIXBIT, ASCII, ASCIZ, ASCIC, .ASCII) to throw away all but the first word of text. .ABSP , returns the "absolute part" of . .ALSO conditional: "If the previous conditional succeeded". See MIDAS;COND >. .AOP is like .OP, but returns no value. However, all the information is still available in .AVAL1 and .AVAL2. .ARRAY reference a lisp array (.FASL feature) .ASCII /text/ Like ASCIZ, but when the character "!" is encountered in the text, the following it is evaluated and the value inserted into the assembled string as a sequence of digits in the current radix, replacing the "!" and the expression. Terminate with a space or comma, which unfortunately will become part of the assembled string. .ASCVL / (Yes, only one "/") returns the ascii value of . .ASKIP -1 if instruction executed by most recent .OP or .AOP skipped; 0 if it didn't skip. .ATOM refer to header of named LISP atom - see MIDAS;FASL > .AUXIL does nothing - it exists for the sake of the listing program "@". .AVAL1 What was left in the ac by the instruction executed by the most recent .OP or .AOP .AVAL2 What was left in the memory location by the .OP or .AOP. .BEGIN begin a symbol-scope block. defaults to most recent label. .BIND ,... Create bindings for these symbols in the current block. Must be used when it is desired to shadow a built-in symbol under certain circumstances. Also sometimes needed in 1-pass assemblies when symbol is defined in higher block and will be defined later in current block, to force a forward reference to be made. .BM , returns a mask to the byte pointed to by the specified byte pointer (address field ignored). If arg's LH is 0, the arg will be swapped first to get a byte pointer. The comma is thrown away except for ending the arg. .BP , returns a byte pointer to the byte which the argument is a mask to. The address field of the value is 0. The comma which terminates the argument is not flushed, so that .BP , will produce a byte pointer to in location . For those who understand .FORMAT, that contrives to use the format field-space-field rather than the problematic field-comma-field format, which many users like to redefine. .BYTC The number of bytes assembled since .BYTE mode was entered. .BYTE N assemble N bit bytes. That is, take the assembled "words" and pack them into N-bit bytes to get what is really output. When another byte won't fit in the current word, the word is output and a new one is started. .BYTE M,N,O,P,... assemble an M bit byte, then an N bit one, then an O bit one, etc., returning to an M bit one after using the last of the specified sizes. If a negative "byte size" is specified, it causes a block of zero bits to be assembled right after the previous byte; the number of zero bits is the abs. value of the specified number. This can cause an extra zero word to be assembled if .byte mode is left right away. In byte mode, "." is a byte pointer which could be ILDB'd to get the next byte. .BYTE with no arg leaves byte mode, returning to the initial state. .C Current block (as in .C"FOO). .CRFIL .CRFOFF CREF off .CRFON CREF on .CURLN current line number minus 1 .CURPG current page number minus 1 .DECREL selects DEC relocatable output format .DECSAV selects DEC/TNX SAV output format. Symbols are deposited where the location counter points when END is reached, and location 116 (.JBSYM) given a pointer to them. Location 120 (.JBSA) is given the start address unless the instruction furnished to the END pseudo has something in the LH, in which case it is treated as an entry vector pointer (only meaningful on TNX systems). .DECTW Two-segment DEC relocatable output format. Arg is address of bottom of high segment (normally 400000). .DOWN ,... Causes the symbols to be visible in subblocks in 1PASS mode. In 2-pass assemblies, symbols are always visible in subblocks of the blocks they are defined in. In 1PASS mode, they are usually not (except for macros), in case the same name is defined later on in the subblock itself. .DPB ,,, deposits into the byte in specified by , and returns the result. Thus, .DPB 0,30300,-1, returns -1,,777707 .ELDC End a load-time conditional - RELOCATABLE format only. .ELSE conditional: "If the previous conditional failed". See MIDAS;COND > .END terminate symbol-scope block, if its name is . Error if the current block's name isn't . .ENTRY .FASL feature - declare a LISP entry point (SUBR beginning, etc). .ERR Causes an error with error message .F floating mode Fortran arithmetic statement. *Note .I.F: .I.F, for details. .FASL Selects FASL output format, loadable by MACLISP. .FATAL Causes a fatal error with as the error code. The output buffers are written out and the output files are closed, though only the error output file is renamed. .FNAM1 numeric value of sixbit for first file name of main input file. .FNAM2 numeric value of sixbit for second file name of main input file. .FORMAT specify interpretation of fields in a word. See the old MIDAS manual (AI memo 90). .FUNCT refers to the specified function, in FASL format. See MIDAS;FASL > .FVERS version number of main input file. .GLOBAL ,... Makes the specified symbols global. .GO assembly continues at .TAG tag (within macro body) Non-local .GO's outward are allowed. .GSCNT The value of the generated symbol counter - may be read or set. .GSSET same as .GSCNT= .HKALL If nonzero, causes ":" to be treated as "::". .HKILL ,... Half-kills the specified symbols. Does not define them. Acts only on the last pass. Does shadow definitions in outer blocks, like .BIND. .I integer mode Fortran arithmetic statement *Note .I.F: .I.F, for details. .IBP returns incremented a la IBP instruction. .IFNM1 numeric value of sixbit for first file name of insert file (the file most recently .INSRT'ed by the current input file, or the current file's name if it hasn't .INSRT'ed any others yet). .IFNM2 numeric value of sixbit for second file name of insert file .IFVRS version number of insert file.. .INEOF In an .INSRT file, acts just like EOF. .INIT The outermost block (as in .INIT"MOVE). All the predefined symbols are defined in this block. Symbol definitions in this block are not output to the binary file. .INSRT Pushes the current input file and begins reading from the specified file. After the end of that file, reading from the inserting file will resume. If the sname of the file to be inserted is not specified, that of the file being read will be used. If the file is not found, the user will be asked to respecify the names. .INSRT'ing the TTY is a good way to let the user make arbitrary redefinitions at some point in the assembly. .IRPCNT # of completed iterations of innermost indefinite repeat .ISTOP stop REPEAT or IRP - see MIDAS;LOOPS > .KILL ,... The specified symbols will not go in the symbol table. .LDB ,, returns as a value the contents of the byte in specified by . may be either a byte pointer or the left half of one, as in .BM. .LENGTH /text/ returns the number of characters in the specified string. .LIBRA ?? .LIBRQ ?? .LIFE, .LIFG, .LIFGE, .LIFL, .LIFLE, .LIFN, .LIFND, .LIFS Load-time conditionals. Matched by .ELDC .LITSW if nonzero, using a literal causes an error message. .LNKOT ?? .LOP ,, like .OP, but the instruction is executed in STINK rather than in MIDAS. The results are available as the eventual values of the global symbols .LVAL1 and .LVAL2. .LSTOF listing off .LSTON listing on .LVAL1 .LOP value left in accumulator. .LVAL2 .LOP value in memory location. .LZ , the number of leading zeros in the value of . The comma serves only to terminate . .M Main block (as in .M"FOO) .MLLIT set positive to allow multi-line [], (), and <>. Set negative for the old-fashioned mode where they didn't need to be terminated. Zero selects "error mode" useful in converting an old-fashioned program to multi-line mode. Now initially positive. .MRUNT MIDAS's runtime so far, in milliseconds. .NSTGW sets .STGSW to cause error message if any storage words are assembled. .NTHWD , returns the 'th word of the text string. Thus, .NTHWD 1, is equivalent to .1STWD. By is meant an invocation of ASCIZ, ASCII, ASCIC, .ASCII or SIXBIT. .OFNM1 = SIXBIT// .OFNM2 = SIXBIT// .OP ,, executes on an AC containing and a memory location containing , and returns what this leaves in the AC. Thus, <.OP SUB,5,2> equals 3. This value is also made the value of .AVAL1, while .AVAL2 contains what was left in the memory location: .OP SUBM,5,2 sets .AVAL2 to 3, and returns 5. .ASKIP will be nonzero if the instruction skipped. If an instruction is supplied with a nonzero AC field, that AC field will be used unchanged, and the number of the AC used for the argument and value will not be substituted. Similarly, if the address field or index field in is nonzero, the address of .AVAL2 will not be substituted. This is useful for immediate instructions, including such ITS UUOs as .RDATE which equals .OPER 46: ASDATE=.OP .RDATE sets ASDATE to today's date in SIXBIT. Note that is read in as a field, and thus cannot contain any spaces or commas (unless they are inside brackets). .OSMIDAS is the sixbit name of the operating system MIDAS is running under. It is SIXBIT of ITS, TENEX, SAIL, CMU or DEC. Twenex is considered the same as Tenex. Programs that have versions for more than one operating system should by default assemble to run on the one in .OSMIDAS, but they should make it possible to override that default with the use of the T switch: IFNDEF RUNOS, RUNOS==.OSMIDAS DEFINE IFITS IFE RUNOS-SIXBIT/ITS/TERMIN .PASS is 1 or 2, depending on which pass MIDAS is in. .PPASS is 1 in a 1-pass assembly; 2, in a 2-pass assembly. .QMTCH if set nonzero, causes ' and " text constants to use the newer fail-style syntax. .QUOTE /text/ inhibit checking for TERMIN and macro dummies. .RADIX ,, evaluates , using as the radix. .RELP , returns 's relocation. Always 0 in an absolute assembly. For any X, X = .ABSP X,+.RL1*.RELP X, .RL1 in a relocatable assembly, returns a relocatable 0. In an absolute assembly, returns 0. .ABSP .RL1 is always 0. .RELP RL1 is 0 iff the assembly is absolute. .RPCNT = # iterations of REPEAT completed .RSQZ , generates right-justified SQUOZE such as the DEC system likes. .SCALAR (),,... makes the symbols "variables", like the ' construct, causing them to have storage words allocated for them later (at the time of the next VARIAB or END). An optional may be specified in parentheses after a symbol, reserving that many words for it rather than the default of just one. See also .VECTOR, which is identical except for the way sizes default. .SBLK Specifies ITS SBLK output format. For details, see ITSDOC;BINFMT > and the "Symbol table format" section of .INFO.;DDTORD >. .SEE ,... Has no effect except to make cref entries for the specified symbols. .SITE returns word (origin 0) of a SIXBIT string that says the name of the machine MIDAS is running on. If is out of range 0 is returned. The format of the string is operating system dependent; on I.T.S. .SITE 0, will return the standard I.T.S. "machine name" which is SIXBIT of "AI", "ML", "DM", or "MC". Programs with different versions for different sites should by default assemble to run on the one specified by .SITE, but they should make it possible to override that default using the T switch: IFNDEF RUNSITE,RUNSITE==.SITE 0, then later on IFE RUNSITE-SIXBIT/ML/,... .SLDR selects SBLOCK output format, but outputs a loader in front of the file. .SPECI .FASL special variable reference. .STGSW set nonzero => it is illegal to generate storage words. .NSTGW and .YSTGW act by setting this flag. .STOP stop current iteration of REPEAT or IRP, go on to next. .SUCCESS flag, used to make .ELSE and .ALSO work. .SX .FASL quoted S-expression reference. .SXE .FASL S-expression load time evaluated and value assembled in. .SXEVA .FASL S-expression load time evaluated and value thrown away. .SYMCNT returns the number of symbol table entries in use. This is the number of user-defined symbols plus the number of initial symbols (not counting symbols that have been expunged). It is useful for determining what argument to give to .SYMTAB (below); .SYMTAB , makes sure the symbol table can hold symbols and the literal table can hold words of literal. If either table actually needs to be enlarged, both are re-initialized, so that all user symbol definitions are lost. For this reason, a .SYMTAB should come at the beginning of the program. If both tables are already big enough (for example, when the same .SYMTAB is seen on pass 2), .SYMTAB is a no-op. The normal version of MIDAS starts out with space for 2700. symbols, and has about 1200. initial symbols, so only programs using more than 1500. symbols need a .SYMTAB. To decide what symtab you need, try a very large value (10000.). The number of symbols including initial symbols, printed at the end of the assembly, is the minimum value you can use; for best results choose an arg at least 20% larger. The literal table size you need is usually the size of the largest constants area; this can be computed from the constants area addresses printed at the end of the assembly. Sometimes, that size may cause a "Constants Global Table Full" error, and a larger size must be used. .TAG see .GO .TTYFLG if greater than zero, TTY typeout is inhibited (but not output to error output file if any). .TTYMAC allows the program to read a few arguments from the TTY at assembly time, and refer to them as dummy arguments. .TTYMAC is used the way DEFINE is used (see MIDAS;MACROS >) but without a macro name; the macro definition is read in and then immediately evaluated, with arguments read in from the TTY. Try .TTYMAC FOO BAR=FOO TERMIN .TYO , Like TYO n MACLISP; prints on the TTY the character whose ASCII code is . Thus, .TYO 61 prints a "1". .TYO6 , Prints the word, regarded as a sixbit. Try .TYO6 .FNAM1,.TYO 40,.TYO6 .FNAM2,PRINTX/ / .TYPE , is -1 if the "symbol" is really a number. Otherwise, it says what the definition status of the symbol is. (-1 number, 0 common, 1 pseudo/macro, 2 defined, 10 global and defined, 17 or other odd number undefined) .TZ , is the number of trailing zeros in the value of . .U containing block (as in .U"FOO) .WALGN word-align; in byte mode, move up to a word boundary. .VECTOR (), (),... Makes be the name of a vector words long. The space is actually allocated by the next VARIAB, or by the END statement. Like .SCALAR, more than one vector can be specified at a time. If no size is specified, or size is zero, the default size is used (initially 1, always set to last size used). e.g. in ".VECTOR FOO(3),BAR" the vector BAR will have size 3. This defaulting scheme is the only difference from .SCALAR. .XCREF ,... Suppress creffing of the specified symbols. .YSTGW OK to generate storage words 1PASS one pass assembly. Implies RELOCA ASCIC /text/ like ASCIZ but fill with ^C. ASCII /text/ generate ascii character string. ASCIZ /text/ ascii character string, 0 byte at end. BLOCK reserve words - increment "." by . COMMEN /text/ ignores the text. CONSTA dump out literals seen so far. DEFINE define a macro. See MIDAS;MACROS > END terminates tha assembly, and sets the program starting address to the argument (which is optional). EQUALS , sym1 gets same meaning as sym2. EXPUNGE ,... forgets the definitions of the specified symbols. IF1 ifbody assem if pass 1. IF2 ifbody assem if pass 2. IFB assemble if string blank (has no squoze chars). IFDEF assemble if sym defined. IFE exp, ifbody assem if = 0. IFG exp, ifbody assem if > 0. IFGE exp, ifbody assem if >= 0. IFL exp, ifbody assem if < 0. IFLE exp, ifbody assem if <= 0. IFN exp, ifbody assem if ^= 0. IFNB assemble if string not blank. IFNDEF assemble if sym not defined. IFNSQ arg, Assemble if arg is not all squoze chars. IFSE string,string, ifbody assem if strings equal. IFSN string,string, ifbody assem if strings not equal. IFSQ arg, Assemble if arg is all squoze chars (that is, has no non-squoze). IRP indefinite repeat (like macro args sort of). see MIDAS; MIDAS LOOPS. IRPC indefinite repeat (characters). IRPNC indefinite repeat (groups of characters). IRPS indefinite repeat (symbols). IRPW indefinite repeat (words - i.e. code lines). LOC set value of "." to . NOSYMS don't put symbols in output. NULL is a "conditional" that always fails. OFFSET offset . and labels by specified amt (code to be moved before run). PRINTC /text/ type out the text PRINTX /text/ type out the text. RADIX set number radix to . RELOCA relocatable assembly. REPEAT ,[] repeat times. See MIDAS;LOOPS > RIM readin mode output format. RIM10 readin mode output format. SBLK simple block loader output format (this is the default). SIXBIT /text/ generate sixbit character string. SQUOZE , value is a word containing the squoze-code for with /4 put in the top 4 bits. SUBTTL ignores the line. This pseudo is for @'s sake. TERMIN terminate macro body or indefinite repeat. TITLE specify name of program as (relocatable only). Types and on the TTY. It is at the TITLE that TTY will be .INSRT'ed by the (T) switch. VARIAB leave space for, and define, the "variables" seen so far. "Variables" are symbols not defined and seen with singlequotes and symbols seen in .SCALAR and .VECTOR pseudos. WORD outputs the argument directly to the binary file. Allows writing of nonstandard binary formats. XWD , returns a word with the specified halfwords.  Local Modes: Fill Column:75 Page Delimiter:  End: