.sthl 6,1,6 .LO 1,2 .PS 60,75 .set date .set time .flags substitute .TITLE A Detailed Guide to VAX/VMS STOIC ($$date $$time) .no flags substitute .st Introduction .hl 1 Introduction .x Introduction .p,1 Evolutionary theory suggests that new animal (or plant) species evolve whenever new, unexploited environmental niches appear. Programming languages appear to follow the same rule: new application areas require new programming languages. Creation of new programing languages is limited by a variety of factors such as significantly large user population, funding, necessary personnel for implementation, time, and effective programming tools to expedite creation and debugging of the new language. The STOIC (STack Oriented Interactive Compiler) system is a programming language which appears to make it possible to create special purpose languages rapidly. .p,1 The STOIC language is uniquely suited to special applications because of its ability to be expanded by adding new words (operators). In the text to follow all of the words (operators) which make up the STOIC language are either tabulated with brief descriptions (when their mode of operation is obvious), or are given with detailed descriptions. To begin the exposition of the STOIC language a brief review of reverse Polish notation and stacks is in order. .hl 2 Reverse Polish and stacks .x Reverse Polish .x Stacks .p,0 Reverse Polish notation differs in appearance from the more familiar "infix" notation of algebra, although users of HP calculators will find reverse Polish quite familiar. Normal "infix" notation separates operands by an operator, e.g. "a + b". Reverse Polish would denote the same phrase as "a b +". In practice, a stack (LIFO) receives the operands and is modified by the operators. The string of operators, or STOIC words, is compiled into stack-oriented code, that is, code in which the various operators are applied to the top entries of a stack. Variables are are used to save and access data. As results on a stack are combined by means of operators, the arguments in the stack are usually lost (removed) and the TOP of the stack is replaced by the result of the computation. This approach is quite general, and although a little awkward at first, it quickly becomes a convenient notation. Reverse Polish notation has an added advantage in that no parentheses are required for expressions. For example: .lt a*(b+c)-d would be written as: a b c + * d - and the stack would look like this (a dynamic snapshot): .el .tp 20 .lt Operand/operator Stack ---------------- ----- a a b b c c + | V a b+c * | V (b+c)*a d d - | V (b+c)*a-d .el Functions may take the top N elements of a stack as arguments, and unary operators act on the top element of the stack, often without removing it. (In the early 1960's Bauer and Samelson gave an elementary method for converting from infix notation to reverse Polish. A possible extension to the STOIC system could be an implementation of that algorithm to translate between the two systems.) .pg .hl 2 A STOIC Primer .x Primer .hl 3 Constants and variables .x Primer >Constants .x Constants .x Constants >Primer .x Constants >Address .x Literals .x Literals >Numerical .x Literals >Numerical >Decimal .x Literals >Numerical >Octal .x Literals >Numerical >Hexadecimal .hl 4 Constants .p,0 The current implementation of STOIC provides facilities for integer and address arithmetic, for floating-point arithmetic, and for string manipulation. Constants are of three types: numerical literal, address, and string literal. The numerical literal may be one of: .list 1 .le;Integer .le;Floating-point number (if decimal radix) .le;Address (or pointer) .els Integers may take one of the following forms depending on the current RADIX: .list 1 .le;RADIX is hex: signed hex integer .le;RADIX is decimal: signed decimal integer .le;RADIX is octal: signed octal integer .le;RADIX is other than the above: signed integer in current radix .els .x Radix >^X .x Radix >^D .x Radix >^O .x ^X .x ^O .x ^D Regardless of the current radix, conversion of integer literals can be forced to be interpreted in hex, decimal, or octal by means of a "local-qualifier" as follows: .list 1 .le;_^X -- forces conversion of in base 16 .le;_^D -- forces conversion of in base 10 .le;_^O -- forces conversion of in base 8 .els Numerical literals may have an optional "+" or "-" sign at the head and may contain only digit symbols allowable under the current radix. .p,1 If the current radix is decimal, floating-point numbers may be entered in D, E, F, or G (Fortran) formats. Only single precision floating point is used. A decimal local-qualifier can be used to force conversion of floating point numbers without regard to the current radix. .p,1 .x Literals >String The string literal, containing up to 65K bytes, is stored internally in an ASCIC-like notation: .s 1 .lt name: .WORD .ASCII "String to be used" .el Examples of numerical literals: .s 1 .lt -1234 -- signed literal integer +321 -- signed literal integer A32F -- unsigned literal integer (taken to be +) ^D123 -- decimal integer 144.34 -- floating point decimal number ^X0AAB -- hex integer .el Examples of strings are: .s 1 .lt 'ABC_DEF -- note termination by a space (can use a tab also) "This one has spaces in it as well as ^&*()" .el .x Primer >Variables .x Variables .x Variables >Primer .hl 4 Variables .p,0 .x VARIABLE Variables may be of either the numerical or string type. Two items of information are required for a numerical variable declaration: .s 1 .list 0 .le;An initial value for the variable .le;The name of the variable .els The format employed is: .s 1 .lt VARIABLE .el .x Variables >Naming rules Here the notation indicates that the initial value is given first, then the name. Names of STOIC words, of which the variable is but a special case, consist of any characters except: .s 1 .list 0 .le;Space (Hex 20) .le;Tab (Hex 09) .le;Carriage return (Hex 0D) .le;Form feed (Hex 0C) .le;Line feed (Hex 0A) .le;Rubout (Hex 7F) .le;Null (Hex 00) .els .x Variables >Declaring A legal name for a variable may consist of up to 255 characters. Some examples are: .s 1 .lt ^D123 'Simple_123 VARIABLE AF2301 'Hex_variable VARIABLE 0 'Temp_1 VARIABLE .el In each of the examples, "VARIABLE" is a built-in STOIC word which reserves four bytes in the user data area for the named variables. Note that in all cases an initial value is required before the name of the variable, and that the variable name is of the "apostrophe-type". .x SVARIABLE .p,1 To define a string variable, use the notation: .lt SVARIABLE .el Note that there in no initial value associated with a string variable. Once defined, you may move a string literal, or another pre-defined string, to the string variable. It is necessary to define the maximum length for the string variable for two reasons: first, to allocate space in the user data area (since strings are not dynamically moved as is done by the system procedure LIB$SCOPY__DXDX when using strings of class DSC$K__CLASS__D), and second, it provides the STOIC system a means for checking for overflow when appending or moving one string to another. As an example: .lt 20 'String_32 SVARIABLE .el defines a 32 byte space in the user data area for the string variable "String__32". .p,1 .x ARRAY .x Variables >Array The final kind of variable which may be designated in STOIC is the array. In this case the format used is: .lt ARRAY .el This declaration reserves the specified number of long words under the given name in the user data area. When the name of the array appears in a STOIC command, the address of the first longword is returned as the value. (This is true of the simple numerical variable and the string variable also.) It is your responsibility to do the appropriate address calculation to take care of subscripting. An example of an array declaration: .lt 100 'Array_256 ARRAY .EL defines a 256 longword array under the name "Array__256". .p,1 A convenient technique for defining small arrays is: .s 1 .lt 0 '3VEC VARIABLE 1 ,D 2 ,D .EL This definition sets up a 3-vector, called "3VEC", as three consecutive longwords in the user data area. The vector is initialized to (0,1,2). The operator ",D" gets a new longword from the user data area and pops the TOP of the stack into it. .p,1 .x Arrays >Filling .x FILL .x 0FILL The contents of an array may be initialized to zero, or any constant value (on TOP of the stack), by using one of: .s 1 .lt FILL -- Fills the array whose address is at TOP-2, whose length (in words) is at TOP-1, and whose fill-value is at TOP. 0FILL -- Zero-fills the array whose address is at TOP-1 and whose length (in words) is at TOP. For example: 100 'X ARRAY X 100 -1 FILL .el .p,1 .x Arrays >Indexing Because of the way in which they are defined, arrays all have "zero-based" indexing. To get the K-th element of array X one computes X+K-1. The usual formula for locating elements in an array .s 1 .lt Base + Imax * Jmax * (K - 1) + Imax * (J - 1) + (I - 1) or Base + Imax * (Jmax * (K - 1) + (J - 1)) + (I - 1) .el may be used. This simple formula may be made into a STOIC word using 6 arguments, remembering to adjust the "offset" to the base to be longwords (i.e. multiplying by 4 before adding to the Base). .hl 3 Stacks .x Primer >Stacks .p,0 STOIc possesses three stacks (or LIFOs): .list 1 .le;Parameter stack -- main source of operands .le;Loop stack -- for iteration .le;Vocabulary stack -- for vocabulary entries .els Of these, only the first will be of immediate concern. It is a longword LIFO used to hold arguments ad results invoked by a sequence of STOIC words. In a STOIC command line, each word which is a variable or literal causes an address or value, respectively, to be pushed onto the stack. Any STOIc word which is a stack-oriented operator will cause some transformation of the entities on the stack, and of the state of the stack itself. .p,1 The loop stack is used in connection with iteration words, and the vocabulary stack with searching for STOIc words. Both of these stacks will be discussed later in the text. .hl 3 Stack operations .p,1 .x Stack .x Stack >Operations Three common storing operations (out of a much larger vocabulary) permit you to save and modify values represented on the stack. Recall that a reference to an integer literal causes its ^&value\& to be pushed onto the TOP of the stack. A reference to a string literal or any variable name causes its address to be pushed onto the TOP of the stack. To manipulate the stack values and addresses the simplest operations are: .list 1," " .x Stack >@ .x @ .le;_@ -- replace the address on the TOP of the stack by the ^&contents of that address\&. This operation is used to load the contents of a memory location onto the TOP of the stack. .x Stack >! .x ! .le;_! -- store the value at TOP-1 at the location specified by the ^&address\& on TOP of the stack. Both stack entries are removed. (This STOIC word might well be replaced by a synonym: "->" ) .x Stack ><- .x <- .le;_<- -- store the value on TOP of the stack at the ^&address\& at TOP-1. Both stack entries are removed. .els Other similar operators are available which are specialized for byte, word, and quadword operations. These are described in Section 4.17 . A few examples should clarify the use of these STOIC words. Let X, Y, and Z be integer variables. .lt 100 X ! -- causes the location specified by X to be loaded with 100 X 100 <- -- has the same effect as the previous case X 100 ! -- will generally cause an access violation exception because you are trying to put the address of X into location 100 X @ Y ! -- the "X @" portion fetches the value of X (^¬\& its address). The "Y !" segment takes that value and puts it into the variable Y, leaving the stack empty. X Y ! -- the address of X becomes the new value of Y X @ Y @ + Z ! -- "X @" gets the current value of X "Y @" gets the current value of Y "+" adds the two values, leaving the result on TOP of the stack "Z !" stores TOP-1 (i.e. X+Y) at Z, leaving the stack empty .el Note that the appearance of a variable name causes the address of the datum to be pushed onto the stack, whereas the appearance of an integer literal causes that value to be pushed. .p,1 .x Stack >Operators .x DUP .x OVER .x 2OVER .x 3OVER .x UNDER .x 2UNDER .x 3UNDER .x DROP .x 2DROP .x 3DROP .x SWAP .x 2SWAP .x FLIP .x +ROT .x -ROT .x DDUP Operators whose sole function is to reorganize the stack are: .s 1 .lt Stack Stack Name before after Description ---- ------ ----- ----------- DUP A A Duplicates the TOP of the stack A OVER A B Duplicates TOP-1 onto TOP of stack B A B 2OVER A C Duplicates TOP-2 onto TOP of stack B A C B C 3OVER A D Duplicates TOP-3 onto TOP of stack B A C B D C D UNDER A A Removes TOP and stores it at TOP-1 B 2UNDER A B Removes TOP and stores it at TOP-2 B A C 3UNDER A B Removes TOP and stores it at TOP-3 B C C A D DROP A B Removes TOP from stack B 2DROP A C Removes TOP and TOP-1 from stack B C 3DROP A D Remove TOP, TOP-1, and TOP-2 from stack B C D SWAP A B Interchange TOP and TOP-1 B A 2SWAP A A Interchanges TOP-1 and TOP-2 B C C B FLIP A C Interchange TOP and TOP-2 B B C A +ROT A B Upward circular rotation of top 3 B C stack elements C A -ROT A C Downward circular rotation of top 3 B A stack elements C B DDUP A A Duplicate TOP and TOP-1 B B A B .el .hl 3 Arithmetic operations .p,0 .x Primer >Arithmetic operations .x Stack >Arithmetic operations The two major classes of arithmetic operations represented in STOIC are unary and binary. The unary operators are: .x MINUS .x MINUS. .x ABS .x ABS. .x NOT .x 2* .x 2/ .x 1+ .x 1- .s 1 .lt Stack Stack Name before after Description ---- ------ ----- ----------- MINUS A -A Twos complement of A MINUS. ABS A |A| Absolute value of A ABS. NOT A ^A Ones complement of A 2* A 2*A Multiply A by two 2/ A A/2 Divide A by two 1+ A A+1 Add one to A 1- A A-1 Subtract one from A .el .x Primer >Tests .x Stack >Tests .p,1 The tests "XXX" and ".XXX." apply to integers and floating-point values respectively. .s 1 .X EQZ .X .EQZ. .X NEZ .X .NEZ. .X GTZ .X .GTZ. .X LTZ .X .LTZ. .X GEZ .X .GEZ. .X .LEZ. .X LEZ .X EQ .X .EQ. .X NE .X .NE. .X .LT. .X LT .X GT .X .GT. .X LE .X .LE. .X GE .X .GE. .lt Stack Stack Name before after Description ---- ------ ----- ----------- EQZ A -1 if A = 0 Test A for zero .EQZ. 0 if A ^= 0 NEZ A -1 if A ^= 0 Test A for non-zero .NEZ. 0 if A = 0 LTZ A -1 if A < 0 Test A for less than zero .LTZ. 0 if A ^< 0 GTZ A -1 if A > 0 Test A for greater than zero .GTZ. 0 if A ^> 0 LEZ A -1 if A ^> 0 Test A for greater than or equal .LEZ. 0 if A < 0 to zero GEZ A -1 if A ^< 0 Test A for less than or equal to .GEZ. 0 if A > 0 zero EQ A -1 if B = A Compares TOP and TOP-1 for equality .EQ. B 0 if B ^= A Replaces TOP with result NE A -1 if B ^= A Compares TOP and TOP-1 for inequality .NE. B 0 if B = A Replaces TOP with result LT A -1 if B < A Compares TOP-1 and TOP for less than .LT. B 0 if B ^< A Replaces TOP with result LE A -1 if B ^> A Compares TOP-1 and TOP for < or = .LE. B 0 if B < A Replaces TOP with result GT A -1 if B > A Compares TOP-1 and TOP for > .GT. B 0 if B ^> A Replaces TOP with result GE A -1 if B ^< A Compares TOP-1 and TOP for > or = .GE. B 0 if B > A Replaces TOP with result .el .p,1 Binary operators combine the top two stack members, replacing the TOP one with the result of the operation. .s 1 .x Stack >Arithmetic operators .x + .x +. .x - .x -. .x * .x *. .x / .x /. .x /MOD .x MAX .x MAX. .x MIN .x MIN. .x OR .x AND .x XOR .lt Stack Stack Name before after Description ---- ------ ----- ----------- + | +. A B+A Sum of TOP and TOP-1 replaces TOP B - | -. A B-A TOP-1 less TOP replaces TOP B * | *. A B*A TOP-1 times TOP replaces TOP B / | /. A B/A TOP-1 divided by TOP replaces TOP B (quotient only) /MOD A B/A TOP-1 divided by TOP replaces TOP B REM(B/A) Remainder of (TOP-1/TOP) MAX A Max(B,A) Replaces TOP with maximum of TOP MAX. B and TOP-1 (signed) MIN A Min(B,A) Replaces TOP with minimum of TOP MIN. B and TOP-1 (signed) AND A B AND A Logical and of TOP and TOP-1 replaces B TOP OR A B OR A Logical or of TOP and TOP-1 replaces B TOP XOR A B XOR A Exclusive or of TOP and TOP-1 replaces B TOP .el .p,1 With these operators it is possible to perform most elementary integer and floating-point arithmetic operations. Note that the STOIC words which have a dot associated with them apply to floating-point arithmetic. The integer arithmetic words listed are part of a larger set which has special cases for dealing with bytes and words, and a few other special operations such as adding 4, subtracting 4, etc. .p,1 .x Radix >Changing .x DECIMAL .X OCTAL .X RADIX .X HEX STOIC also has a set of special purpose words which may be used to change to current radix. The STOIC variable RADIX determines the current radix. To change radix it is necessary to alter RADIX, and this is conveniently done by means of the following operations: .lt Name Description ____ ___________ DECIMAL Changes RADIX to decimal base. The code used is: 'DECIMAL : ^X0A RADIX ! ; OCTAL Changes RADIX to octal base. The code is: 'OCTAL : ^X8 RADIX ! ; HEX Changes RADIX to hexadecimal base. The code is: 'HEX : ^X10 RADIX ! ; .el One may preserve the current radix by means of this code-bracket: .lt RADIX @ NOTE ... code which changes radix and uses it ... RECALL RADIX ! or RADIX @ ... code ... RADIX ! .el The first code-bracket stores the current radix on the loop stack, and the second stores it on the parameter stack. .p,1 .x Stack >Memory operators .x Memory >Operators .x 0<- .x -1<- .x +! .x 1+! .x 1-! .x MOVE .x EXCHANGE Several operators are available which manipulate memory locations. These operators are: .lt Stack Stack Name before after Description ---- ------ ----- ----------- 0<- A B Store zero in location A (A <- 0) B -1<- A B Store -1 in location A (A <- -1) B +! A C Add B to contents of location A B (A <- A + B) C 1+! A B Increment contents of A by 1 B (A <- A + 1) 1-! A B Decrement contents of A by 1 B (A <- A - 1) MOVE A C Replace contents of A by contents of B B (A <- B) C EXCHANGE A C Exchange contents of A and B B C .el .hl 3 String manipulations .p,0 .X Strings .x String manipulation .x Primer >String manipulation Internally, strings are represented by the following form: .x Strings >Internal representation .s 1 .lt .WORD Name: .WORD .ASCII "The string itself" .el Note that the name is associated with the word. The string resides in the user data area. .x Strings >Literals .x Literals >Strings When the STOIC compiler encounters a string literal, it causes the same information to be generated, but in the compile buffer. The address of the byte-count of the literal is pushed onto the stack when the string literal is subsequently "executed". A literal string, however, does not have a maximum length word associated with it, as it cannot vary in length once it has been defined. The string literal in the dictionary space looks like this: .s 1 .lt .WORD .ASCII "The string itself" .el .p,1 .x COUNT It is possible with a simple STOIC operation to convert the internal format for a string to one which may be used as a string descriptor by the VAX system routines. By means of "COUNT" the string pointer on the TOP of the stack is changed into: 1) a byte-count on the TOP of the stack, and 2) the address of the first byte (FBA) of the string itself on TOP-1 of the stack. Now a (pseudo-) descriptor for the string is in the stack. .p,1 .x Strings >Manipulation .x Strings >Operators Several elementary string manipulation operators are available: .s 1 .x MOVE_STRING .X .MOVE_STRING .X STRAP .X .STRAP .X STAB .lt Stack Stack Name before after Description ---- ------ ----- ----------- MOVE_STRING S_1 A The contents of string S_2 replaces S_2 that of string S_1 A ( S_1 <- S_2 ) .MOVE_STRING S_1 A The contents of string S_2, whose Count(S_2) byte count is at TOP-1 and whose S_2 FBA is at TOP-2 replaces S_1. A ( S_1 <- S_2 ) STRAP S_1 A Append the contents of string S_2 to S_2 string S_1. A ( S_1 <- S_1 || S_2 ) .STRAP S_1 A Append the contents of string S_2, Count(S_2) whose byte count is at TOP-1 and S_2 FBA is at TOP-2 to string S_1 A ( S_1 <- S_1 || S_2 ) STAB S_1 A Append the byte (bits 0-7) at TOP-1 Byte to string S_1 A ( S_1 <- S_1 || Byte ) .el .p,1 Here are a few examples to illustrate the use of the string manipulations (note that other operations, such as searching, are described in Section 4.18). .s 1 .lt 40 'S_1 SVARIABLE 40 'S_2 SVARIABLE % defines two string variables "This is a string" S_1 MOVE_STRING % Loads S_1 with string literal "with an appendix..." S_2 MOVE_STRING % Loads S_2 S_1 MSG % Will output: This is a string 20 S_1 STAB % Appends a space to S_1 S_2 S_1 STRAP % Appends S_2 to S_1 S_1 MSG % Types: This is a string with an appendix... .el .hl 3 Defining new STOIC words .p,0 .X Words .x Words >Defining .x Words >STOIC .x Primer >Defining new words The most powerful tool in the STOIC toolchest is the ability to define new words (operators) which may use any of the previously defined ones. New STOIC words (operators) are defined by means of the colon-semicolon bracket. The formalism used is: .x :..._; .s 1 .lt 'Name : ; .el The name of the new word is entered in "short literal" form: 'Name. Any number of lines of code may be introduced in the definition of the new operator. The only restriction is that any operator used in the definition be defined previously. If there is an error in compiling the definition, an error message is emitted which looks like this: .s 1 .lt undefined, compiling word... ...in line .el .p,1 .x Words >Redefining A word may be redefined at any time. All previous definitions using that word will use the old version, whereas all subsequent uses will invoke the new definition. If the name of the word being redefined appears in the new definition then the old version will be used by the definition. .p,1 A few examples: .s 1 .lt 'Average : + 2 / ; % Computes the average of two integers 'Space : 20 TYO ; % Types out a space 'MSG : COUNT TYPE ; % Types out the string on TOP of stack .el .hl 3 Input/output operations .p,0 .x I/O .x Input .x Input >Operators .x Output .x Output >Operators .x Primer >Input/output The input/output operations fall into three main classes: 1) Communications with the user's terminal, 2) Communications with files, and 3) Number conversions. More sophisticated operations are described in Section 4.13 . .hl 4 Terminal I/O .p,0 .x I/O >Terminal .x TYI .x TYO .x I/O >Terminal >TYI .x I/O >Terminal >TYO .x Primer >Input/output >Terminal i/o At the lowest level of terminal I/O we find the "TYI" and "TYO" words. The former causes a character to be input from the terminal and pushed on TOP of the stack as the low-order byte of a zero-filled longword. The latter, "TYO", causes the low-order byte of the longword on TOP of the stack to be typed on the user's terminal. .p,1 .x I/O >Terminal >TYPE .x TYPE More complicated is the word "TYPE", which takes a byte count on TOP of the stack, the address of the first byte of the string in TOP-1, and outputs the whole string to the user's terminal. To output a string use "COUNT" and then "TYPE". To avoid having to do this each time, it is convenient to define the "MSG" operator: .x I/O >Terminal >MSG .x MSG .s 1 .lt 'MSG : COUNT TYPE ; .el which is just the way in which it is defined in the KERNEL module of STOIC. .x I/O >Terminal >= .x = .x I/O >Terminal >? .x ? To output the TOP of the stack (as an integer) use the operator "=". It will convert the (signed) integer on TOP of the stack under the current radix to ASCII and output it on the user's terminal. If an address of a number is on TOP of the stack and you wish to output the value of that number (not the address) use the "?" operator. Both "=" and "?" remove the entry on TOP of the stack. Some examples: .s 1 .lt 123 = --> 123 23 X ! X ? --> 23 "Output me" MSG --> Output me "And me, too" COUNT TYPE --> And me, too .el .s 1 Other convenient definitions can be made: .x SPACE .x CR .x BELL .s 1 .lt 'SPACE : 20 TYO ; % Outputs a space 'CR : 0D TYO ; % Outputs a carriage return 'BELL : 07 TYO ; % Outputs a bell '8_BELLS : 8 ( BELL ) ; % Eight bells are sounded .el .p,0 .x Floating-point .x Floating-point >Output conversion .x Floating-point >G format .x Floating-point >#F .x _#F .x Primer >Floating-point output To output a floating-point number use the conversion word "_#F". The action of this word is to take the floating-point number on TOP of the stack and convert it to an ASCII string according to the Fortran "G" format rules for output. The TOP of the stack is replaced by the address of the resulting string. Output to the terminal is then accomplished by means of "MSG" : .s 1 .lt '=. : #F MSG ; .el will define the floating-point equivalent of the "=" word. .hl 4 File I/O .p,0 .x Input .x Output .x I/O .x I/O >File .x Primer >Input/output >File i/o Other than the LOAD operator (see below, Sections 1.2.11 and 4.13.3.4), STOIC provides an adequate range of file-oriented I/O operations. They are listed in brief form below, and details may be found in Section 4.13. .s 1 .x I/O >File >OPEN .x OPEN .list 1 .le;OPEN -- opens an input file, whose name is given by the string at TOP-1 and relates it to the channel whose number is on TOP of the stack. Errors in performing the OPEN are trapped internally and are reported by means of a call to LIB$STOP. .x I/O >File >.OPEN .x .OPEN .le;_.OPEN -- same action as OPEN except that the completion code is not trapped internally but is returned on TOP of the stack. A file name descriptor must be pointed to by TOP-1 and not just a simple string address. .x I/O >File >WOPEN .x WOPEN .le;WOPEN -- opens an output file, whose name is given by the string at TOP-1 and relates it to the channel whose number is on TOP of the stack. Errors encountered in performing the open are trapped internally and are announced by means of a call the LIB$STOP. .x I/O >File >.WOPEN .x .WOPEN .le;_.WOPEN -- same action as WOPEN except that the completion code is returned on TOP of the stack instead of being trapped internally; TOP is the channel number, and TOP-1 must be the address of a string descriptor for the file name. .x I/O >File >APPEND .x APPEND .le;APPEND -- open a file in append mode. The TOP of the stack is the channel number to be associated with the file name whose address is at TOP-1. Errors encountered in trying to open the file are trapped internally and an error messsage issued by means of LIB$STOP. .x I/O >File >.APPEND .x .APPEND .le;_.APPEND -- same action as APPEND except that the completion code is returned on TOP of the stack; TOP is the channel number, and TOP-1 and TOP-2 contain the length of the file name and the address of the first character of that name, respectively. .x I/O >File ROPEN .x ROPEN .le;ROPEN -- open a file for random access. The TOP of the stack contains the channel number to be associated with the file name pointed to by the entry at TOP-1 of the stack. Errors encountered in opening the file are trapped internally and are announced by means of a call to LIB$STOP. .x I/O >File >INCH .x INCH .le;INCH -- returns the current input channel number on TOP of the stack. .x I/O >File >NEXTINCH .x NEXTINCH .le;NEXTINCH -- gets the next sequential channel number and returns it on TOP of the stack. .x I/O >File >LASTINCH .X LASTINCH .le;LASTINCH -- backs up the input channel number to the one previous and returns that value on TOP of the stack. .X I/O >File >CLOSE .X CLOSE .le;CLOSE -- close the channel whose number is on TOP of the stack. Errors encountered in closing the channel are trapped internally and are reported by means of a call to LIB$STOP. .X I/O >File >GET .X GET .le;GET -- gets the next input line from the file whose channel number is on TOP of the stack and puts that string into the buffer whose maximum length is in TOP-1 and whose first byte address is at TOP-2. Upon completion, the TOP of the stack contains and end__of__file indicator (-1 if not EOF, 0 if EOF), and TOP-1 will contain the actual length of the input line in bytes. Errors encountered during the GET process are trapped internally and are processed by means of a call to the STOIC word SYSERR. .X I/O >File >.GET .X .GET .le;_.GET -- same action as GET except that the completion code is returned on TOP of the stack instead of an end__of__file indicator. .X I/O >File >GET__STRING .X GET__STRING .le;GET__STRING -- gets the next input line associated with the channel whose number is on TOP of the stack and moves it to the string variable whose address is at TOP-1. On completion, the same end__of__file code used by GET is returned on TOP of the stack. Errors encountered during performance of this operation are trapped internally and processed by means of a call to SYSERR. .X I/O >File >RANDOGET .X RANDOGET .le;RANDOGET -- accesses a selected record in a random access file. There is no channel number associated with this file. TOP contains the maximum length of the buffer to receive the input record, TOP-1 the address of the first byte of the receiving buffer, and TOP-2 the number of the record being read. Upon completion of the operation the TOP of the stack contains the completion code and TOP-1 contains the actual length of the record transferred. .X I/O >File >PUT .X PUT .le;PUT -- writes a record to the specified file (must have been opened by means of WOPEN or _.WOPEN). On TOP of the stack is the channel number, TOP-1 contains the maximum length of the record, and TOP-2 the address of the source buffer. .X I/O >File >RANDOPUT .X RANDOPUT .le;RANDOPUT -- writes a record to a random access file in &^update\& mode. The TOP of the stack contains the maximum length of the record to be output, TOP-1 the address of the first byte of the source buffer, and TOP-2 the record number to be written (or rewritten). Upon completion of the operation the completion code is returned on TOP of the stack. As in the case of RANDOGET the channel number is not specified (even though it was used in the ROPEN operation). .els .hl 2 Number conversion .p,0 .x Primer >Number conversion .X Number conversion Although this might be considered a part of input/output, it will be described separately, as the result of these operations is a string. The string may be moved to a string variable and thus be preserved, or it may be used directly as an argument to TYPE and thereby output to the user's terminal. The result of the number conversion operations is a (pseudo) string descriptor on the stack: TOP being the character count, and TOP-1 the pointer to the first byte of the string. Fundamental to using the operators listed below is the idea that digits are generated one by one starting in the units position of the number being converted. This is the usual method of "divide by the radix, keep the remainder, and repeat until the quotient is zero". The ASCII digits resulting from this process are stored on the number conversion stack (OCONSTACK -- a byte-oriented stack set up by "<_#", and accessed like a string). The conversion words are: .tp 8 .s 1 .x RADIX .x Number conversion ><_# .x <_# .x Number conversion >_#PUT .x _#PUT .x Number conversion >_#A .x _#A .x Number conversion >_# .x _# .x Number conversion >_#S .x _#S .x Number conversion >_#_> .x _#_> .lt Name Description ---- ----------- RADIX Name of the variable containing the current radix <# Initiate number conversion by setting up OCONSTACK #PUT Output a character from the TOP of the stack to the OCONSTACK string (prefixed to string) #A Convert byte on TOP of the stack to an ASCII digit and prefix it to the output string # Compute the next digit and prefix its ASCII equivalent to the number string. The number on TOP of the stack is divided by RADIX. The remainder is the digit to be converted to ASCII and appended, and the quotient is restored to the TOP of the stack. #S Compute digits sequentially, convert them to ASCII, and prefix them to the output string. Conversion completes when the quotient is zero. At least one digit is always output. #> Terminates number conversion. Pushes address of first byte of number (ASCII) string onto stack, followed by the byte-count: TOP = byte_count; TOP-1 = pointer. .el .p,1 .x Number conversion >U<_#_> .x U<_#_> .x Number conversion ><_#_> .x <_#_> .x Number conversion >U= .x U= .x Number conversion >U? .x U? A useful set of higher-level words may be constructed from these primitive operations: .tp 10 .s 1 .lt Name Description ---- ----------- U<#> Converts the unsigned number on the TOP of the stack to an ASCII string and leaves the byte-count and first byte address on TOP and TOP-1 of the stack, respectively. It is defined by: 'U<#> : <# #S #> ; <#> Converts the signed number on the TOP of the stack to an ASCII string and leaves the byte-count and first byte address on TOP and TOP-1 of the stack, respectively. It is defined by: '<#> : DUP DUP LTZ_IF MINUS THEN <# #S SWAP LTZ_IF ^X2D #PUT THEN #> TYPE ; U= Converts and types out the number on the TOP of the stack in unsigned format. It is defined by: 'U= : <# #S #> TYPE ; U? Converts and types out the number referred to by the pointer on TOP of the stack in unsigned format. It is defined by: 'U? : @ U= ; .el As an example of using the elementary conversion operations, the following definition outputs the unsigned integer on TOP of the stack in a "dollars and cents" format: .s 1 .lt '$= : <# # # ^X2E #PUT #S ^X24 #PUT #> TYPE ; .el In this example, number conversion is initialized by <_#. The cents part of the field is converted by "_##_#". Next a decimal point is put into the string by means of _^X2E _#PUT (_^X2E is Hex for ".") and this is followed by the remaining digits (dollars) as indicated by the _#S word. A dollar sign (_^X24) is prefixed to the string by the _#PUT and the string rearranged for typing by the _#> word. A test case shows: .s 1 .lt 0> 1234 $= ---> $12.34 .el .p,1 .x Number conversion >$FAO .x $FAO More general facilities for output of integers are provided by the $FAO system service. This operator is described in detail in Section 4.20.3 below. Floating-point conversion is effected by means of the "_#F" STOIC word. Its output is an ASCII string whose address is left on TOP of the stack. .p,1 .x Number conversion >Floating-point .x Floating-point >Conversion .x Number conversion >_#F .x _#F To output floating point values requires the use of the "_#F" word. This word is part of the kernel module. It takes as its argument the floating point number on the TOP of the stack and returns the address of the STOIC-compatible ASCII string corresponding to the original value. The conversion rules are those for Fortran "G" format with a maximum of six digits to the right of the decimal point. The scale factor is set to zero. As an example of its use, consider: .s 1 .lt 0> 1.23456 8.76544 +. #F MSG --> 10.00000 .el .hl 3 Conditionals .p,0 .x Conditionals .x Conditionals >IF .x IF .x Conditionals >THEN .x THEN .x Conditionbals >ELSE .x ELSE .x Truth values .x Conditionals >Truth values .x Primer >Conditionals STOIC has an extensive set of conditional operators. Users accustomed to the usual appearance of "IF....THEN....ELSE...." clauses may find the notation used by STOIC a little confusing on first sight. The general idea is this: the TOP of the stack can be compared with zero or with the value at TOP-1. The result of this test (an even, or odd, value) is put on TOP of the stack. If the comparison operation was true the value will be odd; otherwise it will be even. The STOIC "IF" operator indicates the beginning of the code to be used if the TOP of the stack is "true" (i.e. odd). The STOIC "ELSE" operator indicates the segment of code to be used if the test was "false" (even value). Regardless of the branch taken, both converge to common code at the "THEN" word. Mnemonically this may be described by: .s 1 .lt IF ELSE THEN .el The "ELSE" part may be omitted. For example: .s 1 .lt N IF T1 T2 T3 ... TN THEN C1 C2 C3 ... .el will cause N (on TOP of the stack) to be tested for "true" (odd) or "false" (even). If N is "true" then words T1, T2, T3, ... will be executed. If N is "false" the set of words T1,... are skipped. In either case execution is continued at words C1, C2, C3,#... . Including the "ELSE" word gives a construction like this: .s 1 .lt N IF T1, ..., Tm ELSE F1, ..., Fn THEN C1, C2, ... .el If N is "true" (odd) then words T1 through Tm are executed. If N is "false" (even) then words F1 through Fn are executed. In either case control is returned to the words C1, C2, etc. .p,1 In order to make good use of this facility it is necessary to have a group of tests. These come in two varities: comparisons of TOP with zero, and comparisons of TOP-1 and TOP elements. If the result of the comparison is "true" the TOP of the stack is replaced by an odd value, otherwise an even value is used. This value may then be used as a parameter to the "IF" word. The built-in comparisons are: .s 1 .x Stack >Comparisons .x Tests .x Comparisons with zero .x EQZ .x .EQZ. .X NEZ .X .NEZ. .X LTZ .X .LTZ. .X GTZ .X .GTZ. .X LEZ .X .LEZ. .X GEZ .X .GEZ. .list 1 .le;Comparisons with zero .LT Stack Stack Name before after Description ---- ------ ----- ----------- EQZ A -1 if A = 0 Test A for zero .EQZ. 0 if A ^= 0 NEZ A -1 if A ^= 0 Test A for non-zero .NEZ. 0 if A = 0 LTZ A -1 if A < 0 Test A for less than zero .LTZ. 0 if A ^< 0 GTZ A -1 if A > 0 Test A for greater than zero .GTZ. 0 if A ^> 0 LEZ A -1 if A ^> 0 Test A for greater than or equal .LEZ. 0 if A < 0 to zero GEZ A -1 if A ^< 0 Test A for less than or equal to .GEZ. 0 if A > 0 zero .el .X Comparisons TOP:TOP-1 .x EQ .X .EQ. .X NE .X .NE. .X LT .X .LT. .X LE .X .LE. .X GT .X .GT. .X GE .X .GE. .le;Comparisons between TOP and TOP-1 .LT Stack Stack Name before after Description ---- ------ ----- ----------- EQ A -1 if B = A Compares TOP and TOP-1 for equality .EQ. B 0 if B ^= A Replaces TOP with result NE A -1 if B ^= A Compares TOP and TOP-1 for inequality .NE. B 0 if B = A Replaces TOP with result LT A -1 if B < A Compares TOP-1 and TOP for less than .LT. B 0 if B ^< A Replaces TOP with result LE A -1 if B ^> A Compares TOP-1 and TOP for < or = .LE. B 0 if B < A Replaces TOP with result GT A -1 if B > A Compares TOP-1 and TOP for > .GT. B 0 if B ^> A Replaces TOP with result GE A -1 if B ^< A Compares TOP-1 and TOP for > or = .GE. B 0 if B > A Replaces TOP with result .el .X Comparisons and tests .x Conditionals combined with tests .le;Test and IF combined. In this mode the test codes listed above may be concatenated with "IF" so that a single word may be used in place of two, thereby improving efficiency. The construction follows this format: .s 1 .lt _IF ._IF. .el where may be any of the listed tests. E.g. EQ__IF, LTZ__IF, etc. If the is a zero comparison, the TOP value may be restored by means of the UNDROP word. If the is a comparison of TOP-1 and TOP, the two values may be restored by using 2UNDROP. The same remarks apply to the _.__IF_. words used for floating-point comparisons. .els Two examples are given to illustrate the use of the tests and "IF": .s 1 .lt 'ABS : DUP LTZ_IF MINUS THEN ; % Takes absolute value of TOP 'MAX. : DDUP .GT_IF. DROP ELSE UNDER THEN ; % Max(TOP, TOP-1) --> TOP .el .hl 3 Iteration .p,0 .x Iteration .x Iteration >(...) .x Iteration >BEGIN...END .X Iteration >BEGIN...IF...REPEAT .X Iteration >DO...LOOP .X Iteration >DO...+LOOP .x Iteration >EXIT .X (...) .X BEGIN .X END .X IF .X REPEAT .X DO .X LOOP .X +LOOP .x Primer >Iteration Several facilities are provided for iteration: .s 1 .list 1 .le;Count controlled interation -- N#(#...#) .le;BEGIN#...#END -- condition controlled iteration .le;BEGIN#...#IF...#REPEAT -- condition controlled iteration .le;DO#...#LOOP -- a "do loop" iteration .le;DO#...#N#+LOOP -- special form for "do loop" incrementation .le;EXIT -- exit an inner loop of any kind .els .p,1 .X (...) .x Iteration .x ( The simplest form is the parenthesis loop. Here, the TOP of the stack is a value which indicates how many times the string of STOIC words contained within the parentheses are to be executed. This loop format may be nested to any depth and is subject to the usual restrictions on overlapping of ranges. If the parameter value (on TOP of the stack) is negative or zero, the sequence of STOIC words is not executed at all and control is passed to the word following the right parenthesis. The format used for this operation is: .s 1 .lt N ( Word_1 Word_2 Word_3 ... Word_n ) Continuation_words .el Some examples: .s 1 .lt '8BELLS : 8 ( BELL ) ; % Causes 8 bells to be rung 'N_BELLS : ( BELL ) ; % Uses TOP of stack as count .el .p,1 .X BEGIN...END .x BEGIN .X END The "BEGIN#...#END" bracket permits control of iteration by means of the last value value computed. All of the STOIC words following the "BEGIN" are executed. When the "END" is reached, the TOP of the stack is popped and tested: if "true", execution continues following the "END" word; if "false", execution returns to to first STOIC word following the "BEGIN". For example: .s 1 .lt 'EXAMPLE : BEGIN 1- DUP DUP = EQZ END ; can be invoked as follows: 0> 5 EXAMPLE --> 4 3 2 1 0 .el The order of computation is to decrement the TOP of the stack by 1 (1-), make two copies of it (DUP DUP), type out (and pop) one copy (=), test the second copy by comparison with zero (EQZ), and either return to "1-", if the condition tested is false, or proceed on through the "END" if the test is true. In either case the TOP of the stack is popped revealing the original TOP value as decremented prior to the "DUP#DUP" pair. .p,1 .x BEGIN .X IF .X REPEAT .X BEGIN...IF...REPEAT The "BEGIN#...#IF#...#REPEAT" construction is similar to the "BEGIN#...#END" one except that the test is made at the "IF". The order of execution is: first, execute all STOIC words following the "BEGIN" and preceeding the "IF". At the "IF", the TOP of the stack is tested for truth or falsity. If the TOP of the stack is "true" (odd) then the STOIC words between the "IF" and the "REPEAT" are executed and control is returned to the word following the "BEGIN". If the result of the test at the "IF" is false (even), then control is passed to the STOIC word following the "REPEAT". As an example, suppose it is desirable to read a sequence of records from a (possibly null) file until an end of file (EOF) condition is encountered. Assume that the file has been opened and the STOIC word "READ__RECORD" has been defined. EOF will be assumed to be initially zero and is set to -1 if an end of file conditon is encountered by "READ__RECORD". .s 1 .lt ... BEGIN EOF NOT IF READ_RECORD REPEAT ... .EL By testing for an end of file condition at the beginning of the loop, the zero length file condition is properly accounted for. .p,1 .x Do loop .X DO .X LOOP .X DO...LOOP Controlled-variable "do loops" require either two or three parameters (depending on the type), may be nested to depth three, and permit access to controlled variables containing the current "index values", or counts. The simplest case assumes a high limit (called "HIGH"), a low limit (called "LOW"), and an automatic step size of one. The format is: .s 1 .lt DO Word_1 Word_2 ... Word_n LOOP .el Here TOP-1 holds the upper limit of the iteration and TOP the lower limit. The STOIC words Word__1 through Word__n are executed. The "LOOP" word causes LOW to be incremented by one and compared with HIGH. If LOW is greater or equal to HIGH the loop is terminated by transferring control to the STOIC word following "LOOP"; otherwise, control is returned to the word following "DO". Note that the comparison of HIGH and LOW happens after incrementation at "LOOP" so the enclosed string of STOIC words will be executed at least once. .p,1 .x Do loop .X DO .X +LOOP .X DO...+LOOP The "do loop" format with the "+LOOP" ending bracket performs the same set of functions with the added ability to use an explicitly given incrementation constant. The format is: .s 1 .lt DO Word_1 ... Word_n +LOOP .el Here the STOIC words (Word__1 through Word__n and ) are executed once. The value on TOP of the stack (usually left there by ) is added to (in lieu of the value one used in the previous form) and the usual comparison and transfer of control made. This permits a reasonably general incrementation for the controlled variable. .p,1 .X Controlled variables .x I .x J .x K To access the controlled variable within the range of the loop, the current value is available in a STOIC word called "I". If do loops are nested, I always contains the value of the controlled variable of the ^&innermost\& do loop. Working from within outward the controlled variable values are available in words "J" and "K". Note the restriction of do loop nesting to a maximum of three levels. .x I' .x J' .x K' In order to obtain indices that are running in reverse order (from HIGH to LOW) three STOIc words are available: I', J', and K'. These are computed according to the form (shown only for I'): .s 1 .lt I' <- HIGH+LOW-I-1 .el .x LAST_I When parentheses are nested within do loops, they count as one level of nesting. If "I" is used within an inner parenthesized iteration, it will return the current iteration count, which runs from its maximum value downward to one. The STOIC word "LAST__I", ^&if executed immediately upon leaving a loop\&, will push the value of "I" onto the stack (this is usually HIGH unless the word EXIT terminated the loop). .p,1 .X EXIT The STOIC word "EXIT" causes the innermost loop in which it is embedded to be unconditionally terminated on the next cycle. This applies to both do loops and parenthesized iteration. .p,1 Here are a few examples (in DECIMAL radix): .s 1 .lt 0> 5 0 DO I = LOOP --> 0 1 2 3 4 0> 24 0 DO I = 4 +LOOP --> 0 4 8 12 16 20 0> 24 0 DO I' = 4 +LOOP --> 23 19 15 11 7 3 .el .hl 3 Including comments in STOIC .x Primer >Comments .p,0 To include comments in STOIC one makes use of the "%" STOIC word. A comment .X Cmments .X % starts with the "%" symbol followed by a blank or a tab and then the comment. To end the comment there are two alternatives: the end of the line (as indicated by a ), or an occurrence of a balancing "%". Two examples will clarify the two modes: .s 1 .lt 'ABC : RADIX @ % Get the radix (this is a line-terminated comment) = ; 'BCD : CR CR % Do two s % MSG ; % Interpolated comment .el Note that a string such as %ABC is ^¬\& a STOIC comment, but is a legitimate STOIC word. This sort of name should be avoided for reasons of program clarity and readability. .hl 3 Executing STOIC programs .p,0 .x Programs .x STOIC programs .x Execution .x LOAD .x _;F .x Primer >STOIC programs .x STOIC source files LOAD causes STOIC to accept input lines from the designated file rather than from the terminal. Execution of a source program stored as a file is controlled by the two STOIC words "LOAD" and ";F". The "LOAD" word takes the address of the string on TOP of the stack as the name of the file to be executed. As each line is read, it is executed by the STOIC main loop. The end of file condition is signalled by the presence of the ";F" word in the file or a physical end of file. This signals termination of the current input file and transfers control to the caller (i.e. that which initiated the loading). If loading was initiated from the user's terminal, control will be returned to the terminal. Should the user type ";F" at his terminal, control will be returned to the VAX/VMS operating system. A variant of "LOAD", called "LOAD/L", causes the loading and execution process to be executed as above but with an output message preceeding the action. The message announces the name of the file being loaded. .p,1 STOIC maintains a small "file stack", and each time "LOAD" is executed a new file is opened. When STOIC finishes compiling and executing the input line containing the LOAD word, compilation will continue with lines taken from the newly opened file. Upon reaching the end of that file, or the word ";F", the file will be closed and popped from the file stack. Compilation now continues from the file now on top of the file stack. The file stack has a defined maximum depth of 4 (this is the number of FAB and RAB blocks provided in the RMS module). Initially the file stack has only one entry: the user's terminal. To illustrate the use of LOAD look at STOIC.CRE, and the following: .s 1 .lt 'DEFS LOAD % This will cause loading of the DEFS file 'A LOAD 'B LOAD 'C LOAD % Load C, then B, then A .el The second example loads in the order given because A, B, and C are stacked in order of appearance and the successive loads are compiled (because STOIC is not in colon definition mode). The first LOAD executed will take the TOP of the stack (i.e. "C"), and so on. .p,1 .x LOAD__RESET Under some circumstances it may be necessary to stop loading nested input files. This may be accomplished through the use of the "LOAD__RESET" word. Execution of this word will cause each input file to be closed (by forcing a ";F" command). The operation will terminate when the level of the user's terminal has been reached. .p,1 .X LIST To list the contents of a file without loading it use: .s 1 .lt LIST .el .hl 3 Recursion .p,0 .x Recursion .x EXEC .x Primer >Recursion STOIC being a stack oriented language, permits recursion to be handled quite easily. The STOIC word "EXEC" takes as its argument (on TOP of the stack) the address of a STOIC word to be executed and calls it (by means of a JSB (P)+). By placing the address of the calling routine itself on the stack, a recursive call is generated. For example (that old standby FACTORIAL!): .s 1 .lt 0 'SELF VARIABLE 'FACTORIAL : DUP 1 NE_IF DUP 1- SELF @ EXEC * THEN ; () FACTORIAL SELF ! 5 FACTORIAL = --> 120 (78 Hex) .el .hl 3 Interactive compiling .P,0 .x Compilation .x Compilation >Interactive .x Primer >Interactive compiling Athough STOIC will compile directly from the keyboard, this is often a difficult procedure because of the lack of editing facilities. In general, long programs should be prepared with an editor and then LOADed into STOIC with debugging or execution taking place under control of the user at the terminal. .p,1 There are several reasons why interactive compiling is useful. For example, it permits on-line check-out of new STOIC words, and it provides a useful top-level command language for other, perhaps more complex processes, amd it provides a handy calculator mode of operation. .hl 4 Using STOIC .p,0 .x STOIC .x STOIC >Use .x Primer >Using STOIC When typing a command from the terminal, the "delete" key may be used to delete the last character(s) typed. Typing a _^U will delete the entire command line. .p,1 When activated, STOIC introduces itself and then types a prompt message consisting of a number (called the "current nesting depth") and the symbol ">" . The user may now type in a command line. As soon as is typed, STOIC compiles the line and, providing it is not in the middle of a STOIC word definition, proceeds to execute it. Having done this, STOIC reissues its prompt symbol to indicate that further input may be accepted. .p,1 .x Nesting depth counter STOIC maintains a nesting depth counter that is used for syntax checking, and to determine when a multi-line definition has been completed and is ready for execution. Initially the nesting depth is set to zero. It is incremented whenever any one of the following STOIC words is encountered: .s 1 .lt IF ELSE BEGIN ( DO : .el The nesting count is decremented upon occurence of: .s 1 .lt THEN ELSE ) END LOOP +LOOP ; REPEAT .el Should the nesting depth ever become negative the fatal error message: .s 1 .x Syntax errors .lt SYNTAX ERROR .el is emitted. This message is also generated if the nesting depth is nonzero at the beginning or at the end of a colon definition. After compiling a line STOIC checks the nesting depth. If it is zero the line is executed; otherwise compilation is continued to the next input line thereby postponing execution until the nesting depth reaches zero. A multi-line colon definition includes all words up to the matching semicolon. .p,1 Typing a line feed causes STOIC to recompile and re-execute the last command line executed. This operation is defined by: .s 1 .lt *****Can one define ??? .el .p,1 .x Error handling .x I__ABORT .x ERR Two STOIC words are available for handling errors: .s 1 .list 1 .le; I__ABORT -- this operator clears the parameter, return, and loop stacks, resets the nesting depth to zero, and forces control to return to the user's terminal. "I__ABORT" is invoked whenever _^C is typed to escape from STOIC execution. .le; ERR -- types out the string (message) on TOP of the stack followed by the name of the STOIC word last scanned from the input stream. If the input is not from the user's terminal the line last compiled from the input file will be listed. "ABORT" is then invoked to reset STOIC. .els .hl 4 Debugging STOIC programs .x Debugging .x Debugging >Guidelines .x Primer >Debugging hints .p,0 The following debugging procedure can be recommended: .s 1 .list 1 .le;Use an editor to create long files of definitions. The interactive mode is alright if the definition is about a line long. The "FORGET" operation can be used to remove previously defined, but faulty, operations. .le;To test a STOIC word, put some parameters on the stack and execute the word. Use '?', '??', or '=' to look at the result(s). .le;If a word fails, type in the words which make it up, one at a time, examining the stack as you go along and restoring it by typing the parameters back in, in reverse order. .le;After executing a word and examining the results on the stack, type an extra '=' to make sure that the stack is empty. You should get the "Stack empty" message. The loop stack should be examined in an analogous manner by typing 'RECALL' to elicit the "Loop stack empty" message. .le;Keep track of the radix you are using! ^&This is a frequent source of errors.\& Within a file being executed, save the radix, set it to the value that the program expects, and when done restore it. For example .s 1 .lt RADIX @ DECIMAL . . . RADIX ! ;F .EL .le;The proper selection of lower level words is of enormous importance. They will have a marked effect on all higher level definitions in which they appear. .le;Test all lower level words thoroughly before testing higher level ones making use of them. .le;Be especially careful with words which modify memory. Make sure that the word is modifying only the intended locations and not part of the program! (the runaway subscript problem). .els .hl 4 Utilities available .p,0 .x Debugging >Utilities .x Primer >Utilities Several different STOIC words are available to help you debug programs. They are, briefly: .x Debugging >Utilities >WHAT .x WHAT .x Debugging >Utilities >WHERE .x WHERE .x Debugging >Utilities >ERROR__TRACE .X ERROR__TRACE .X Debugging >Utilities >INVENTORY .X INVENTORY .X Debugging >Utilities >() .x () .x Debugging >Utilities >LAST__WORD .X LAST__WORD .s 1 .list 1 .le;WHAT -- provides the name of the STOIC word associated with the given constant (address) on TOP of the stack. .le;WHERE -- locates the STOIC word, whose string address is on TOP of the stack, in the dictionary. .le;ERROR__TRACE -- provides an error tracing mechanism using the standard VAX/VMS backtrace information. .le;INVENTORY -- lists the contents of the vocabulary on TOP of the vocabulary stack .le;() -- puts the dictionary address of the STOIC word following it on TOP of the stack. .le;LAST__WORD -- causes a type out of the last STOIC word defined (i.e. the one indicated by CURRENT) .els The examples below will illustrate the use of these debugging aids. .s 1 .lt 0A234 WHAT --> A234 A227 TEST_CASE (The two Hex values typed out ahead of the STOIC word are: 1) the original argument and 2) the "linkage word" for this dictionary entry.) 'TEST_CASE WHERE --> TEST_CASE: A227 () TEST_CASE = --> A227 (Note lack of apostrophe in front of "TEST_CASE".) LAST_WORD MSG --> TEST_CASE .el .pg .hl 2 Defining STOIC words .hl 3 The dictionary .P,0 .x Words .x Words >STOIC .x Words >Defining .x Dictionary The fundamental data structure in STOIC is the dictionary. It is here that all STOIC words are stored, and when a STOIC word is encountered during the compiling process it is the dictionary that is searched. In essence the dictionary is a one-way linked list. There is a STOIC variable (called "CURRENT") which points to the most recently defined word, i.e. to the growing head of the list. The end of the list is signalled when the link word points to a zero. As new words are defined they are added onto the growing head of the list. In this way new definitions, which may supercede old ones are nearest the head of the list. Figuratively the dictionary list looks like this: .X Dictionary >Structure .s 1 .tp 15 .lt CURRENT | v +-------+ <-- +-------+ <-- ... <-- +-------+ <-- Branch_name | 0 | | link | | link | +-------+ |-------| |-------| | string| | string| |-------| |-------| |attribt| |attribt| |-------| |-------| |defn_n | |defn_1 | +-------+ +-------+ .el .s 1 The primary list of words is set up at assembly time in the modules named "KERNEL" and "SS". To these words are added definitions of subsequent words using any words that are currently defined at the time the new word is being defined. This bootstrapping procedure permits the user to build up a highly flexible and specialized system of operators dependent on a hierarchy of definitions. It is clear that the primary list of operators must be very carefully chosen, as must the various levels of "supporting" words. The definition contained within a dictionary entry is a sequence of machine code instructions. How this sequence is generated will be described in detail when discussing the compiling process (Section 1.4.3). .p,1 .x Dictionary >Attribute byte Associated with each dictionary entry is an "attribute" which determines how the STOIC system will interpret a word. The default attribute is called "jump__to__me" and it causes a subroutine jump to the definition of the word to be compiled. .hl 3 Vocabularies .x Dictionary >Vocabulary .x Vocabulary .x Dictionary >Branches .x Branches .x Vocabulary stack STOIC provides the user with the facility to subdivide the dictionary into units called "branches". By enabling a branch for use it becomes a vocabulary for the system. Initially the system is primed so that the main branch is active and goes under the name of "STOIC<" (sic). A branch may be used in two ways: it may be one of the vocabularies that is active, or it may be the current branch to which new definitions are being appended. When it is necesssary to search the dictionary for a STOIC word all branches whose names are in the vocabulary stack are searched. Since the system is primed to have STOIC< as the current branch, any new branch definition will be linked to STOIC<. Figuratively the branch and vocabulary structures of STOIC might look like this: .tp 10 .s 1 .lt STOIC< -----+------+----------- ... | | | Assembler< IORB< Branch_A< ---------+ | | Branch_B< Branch_C< | Branch_D< <-- CURRENT .el In this figure the current branch is Branch__D< and all new definitions will be appended to it. In order to access Branch__D< , branches "Branch__A<", "Branch__B<", and "Branch__D<" must be on the vocabulary stack. In essence, the vocabulary stack provides a search list for STOIC words. .p,1 .X Current branch .x DEFINITIONS Putting the name of a branch onto the vocabulary stack does not make that branch the current one. To make a branch the current one two criteria must apply: .list 1 .le;The name of the branch must be on TOP of the vocabulary stack .le;The STOIC word (operator) "DEFINITIONS" must be invoked. .els The current branch is terminated and the one on the top of the vocabulary stack is made CURRENT. .p,1 .X Vocabulary stack .x _> Removing entries from the the vocabulary stack is effected by means of the ">" STOIC word. This word merely pops the top entry off the vocabulary stack. (It is not possible to remove all entries from the stack. The "STOIC<" vocabulary is permanently on top of the vocabulary stack; but note that this is not true if just the kernel is being executed.) .hl 3 How dictionary entries are made .p,0 .X Dictionary >Entries To make a dictionary entry one uses the pair of operators ":" and ";". The colon indicates that the string name preceeding it wil become the name of a new STOIC dictionary entry and the semicolon closes the definition. In general the short notation for strings is used, e.g. 'NAME. Once the definition has been completed (the compiler has seen the semicolon) the compile buffer contains the sequence of subroutine jumps to the various constituent STOIC words, the move instructions necessary to put values or addresses on the stack, in-line code, and so on. The name of the new STOIC word is then entered into the dictionary, an attribute byte assigned (usually "jump__to__me"), and the compiled code copied from the compile buffer to the dictionary area. The attribute byte may be modified after the word and its definition have been entered. This is usually done immediately after the definition phase has been terminated (by the semicolon operator). Typically one finds the "IMMEDIATE" word following a ";" to alter the attribute byte from the default subroutine jump to the "immediate execution" mode. .p,1 The sequence of diagrams below illustrate the manner in which the various STOIC words cause new words to be entered into the dictionary and the way in which the dictionary is altered by a new entry. The example assumes that the STOIC< branch of the dictionary is already present. First, the new branch name "ABC<" is enrolled as a branch of the current vocabulary (as indicated by CURRENT). Second, that branch is made current (namely CURRENT is modified); and finally, two definitions ("AA" and "BB") are entered into the dictionary. .tp 8 .s 1 .lt INITIAL STATE User data area Dictionary area CURRENT -------------- --------------- ------- .D --> a: .LONG 0 DICT_PNTR --> b: .LONG ??? prev. def. 'ABC< BRANCH User data area Dictionary area CURRENT -------------- --------------- ------- a: .LONG 0 b: .LONG a b .D --> a+4: .LONG 0 .ASCIC /ABC c: .LONG ??? c: .LONG a .ASCIC /AA/ CURRENT: b -> c .BYTE jump_to_me JSB NULL RSB DICT_PNTR -> d: .LONG ??? 'BB : AA ; Dictionary before Dictionary after ----------------- ---------------- b: .LONG c b: .LONG c .ASCIC /ABC d: .LONG ??? d: .LONG a .ASCIC /BB/ CURRENT: c -> d .BYTE jump_to_me JSB AA RSB DICT_PNTR -> e: .LONG ??? .el .hl 3 Redefining previously defined operators .p,0 .x Words >Redefining .x Dictionary .x Dictionary >Searching .x Dictionary >Vocabulary stack .x Vocabulary stack Searching the dictionary is controlled by the vocabulary stack. Only those branches whose names have been pushed onto the "V__stack" are eligible for searching. The branches (vocabularies) are searched from most recent definition to first definition. If the STOIC word is not found in the current vocabulary then the next vocabulary in the "V__stack" is searched, and so on. If there is no match then an "undefined word" condition exists. What happens if a word defined in one branch is the same as that defined earlier in the same branch (or one available in the "V__stack")? The rule is that the first one encountered becomes the definition. This provides the user with a redefinition facility: the new definition will take precedence over previous ones. It should be noted that a previous definition may be used in the definition which is redefining it! As an example consider the "BRANCH" STOIC word. This operator makes a branch entry in the current dictionary branch. It is defined as follows: .lt 'BRANCH : .D@ SWAP 0 ,D BRANCH ; .el The .D@ gets the address of the next available byte in the user data area. SWAP puts the name of the branch on TOP of the stack and the address of the next free area below it (in TOP-1). A zero is pushed onto the stack and entered (,D) into the user data area at ".D" (this address also resides at TOP-1 in the stack). The ,D operation also updates .D by 4 bytes. Finally the ^&old\& definition of BRANCH (found in the KERNEL) is invoked. From this point onwards, the new definition to BRANCH will be seen before the old one. .p,1 .x Dictionary >Synonyms .x Synonyms Synonyms are easy to make in STOIC. For example, one might find the word "!" somewhat non-mnemonic and might desire to provide an alternative definition. Here are two ways: .s 1 .lt '-> : ! ; % Generate a call to !, or '-> : INLINE< MOVL (P)+ R0 MOVL (P)+ (R0) >INLINE ; IMMEDIATE .el The latter recreates the code associated with "!" as coding to be put in-line whenever "->" is encountered. .pg .hl 2 Advanced topics .p,0 .x Advanced topics In this section some advanced topics are covered. In particular, the storage organization with respect to stacks, dictionary, and user data space; how to use system services within the STOIC context; compiling; making a new system; and direct execution of programs will be described. .hl 3 Storage organization in STOIC .p,0 .x Advanced topics >Storage organization .x Storage organization Three different storage spaces are used by STOIC: stacks, dictionary, and the user data space. The stacks and dictionary occupy a fixed, predefined number of bytes; but, the user data space can grow dynamically as necessary. .hl 4 Stacks .x Advanced topics >Storage organization >Stacks .x Stacks .x Stacks >Parameter .x Stacks >Loop .x Stacks >Return .x Stacks >Vocabulary .x Parameter stack .x Loop stack .x Return stack .x Vocabulary stack .p,0 STOIC makes use of four different stacks: .list 1 .le;Parameter .le;Loop .le;Return .le;Vocabulary .els The parameter stack is controlled through general register 10 using autodecrement mode for pushing objects onto the stack and autoincrement mode for popping objects off the stack. In terms of the ASSEMBLER< branch STOIC words these register operations are defined by means of (P), -(P), and (P)+. The parameter stack can accomodate 400 longwords -- more than adequate for most applications. The origin of the parameter stack can be obtained from the constant P__STACK__0 (use P__STACK__0 _@ ). .p,1 .x Stacks >Moat .x Moat Separating the parameter stack from the loop stack is an empty page called a "moat". The moat traps stack overflow and underflow. The loop stack is used by the iteration mechanisms, and is also accessible by means of NOTE, MARK, RECALL, and RESTORE words. In terms of the ASSEMBLER< codes, it is accessed through (L), -(L), (L)+ register operations. The depth of the loop stack is 30 longwords. The origin of the loop stack may be obtained by means of the constant L__STACK__0. .p,1 A moat also separates the loop stack from the vocabulary stack. The vocabulary stack is used in conjunction with the branches/vocabularies of the dictionary (q.v.) and has a depth of 10 longwords. Access to the vocabulary stack is through the constant VOCAB__SP (access the TOP element of the vocabulary stack by using VOCAB__SP _@ ). The origin of the vocabulary stack is available through the constant V__STACK__0 and is accessed in the usual way (vide supra). A moat separates the vocabulary stack from the user tables in the impure _.psect of the kernel module. .p,1 .x MOAT .x P__STACK .x L__STACK .x V__STACK A few built-in STOIC words provide convenient access to certain parameters related to the stacks. First, MOAT will provide the address of the moat in front of the parameter stack. P__STACK provides the origin of the parameter stack (and also that of the moat between the parameter and loop stacks). L__STACK returns the address of the origin of the loop stack on the TOP of the parameter stack (this value is also the address of the moat separating the loop and vocabulary stacks). V__STACK returns the address of the origin of the vocabulary stack on TOP of the parameter stack (this address is the same as that of the stack separating the vocabulary stack from the remainder of the impure .psect). .p,1 .x = .x PROTECT__STACKS If the "=" operator is applied to an empty parameter stack, the fact that the stack is empty is announced. If, however, the definition of a STOIC word causes an illegal stack access, an "access violation" system message will be emitted. Under some circumstances this message will loop. To stop it, use _^C several times in succession. Protection of stacks is effected by removing the buffer pages (moats) surrounding the stacks from accessible storage. This is done by means of a single invocation of the PROTECT__STACKS word. .hl 4 Dictionary and tables .p,0 .X Advanced topics >Storage organization >Dictionary and tables .x DICT__PNTR The dictionary consists of 60 pages ( approximately 32KB) in the impure .psect. It grows from low addresses towards higher ones. No mechanism exists to expand the dictionary space should it be exhausted by definitions. The current head of the dictionary is pointed to by the constant DICT__PNTR, and is accessed indirectly (i.e. use DICT__PNTR @ ) to get whatever it is pointing to (usually garbage since it is pointing to the next available byte for storing an entry). Also residing in the impure .psect is a table of constants used by STOIC. This table is described in Section 2.3 below and may be modified by the user to include more definitions by reassembling the kernel module. There is also a dispatch table which determines how the various attributes of dictionary entries are to be interpreted. This table is also expandable at assembly time (see Section 2.3). .hl 4 User data space .p,0 .x Advanced topics >Storage organization >User data area .x User data area A dynamic virtual address space, called the "data region" is provided for the storage of variables and arrays (as well as zero-valued longwords to start a new vocabulary branch). This space is accessed through the symbol "_.D". A number of commands are provided which manipulate the user data region: .s 1 .x .D .x .D@ .x .M .x .D+! .x ,D .x B,D .x INITIALIZE__DATA__REGION .list 1 .le;_.D -- address of the address of the next free byte in the data region .le;_.D@ -- returns the address of the next free byte on TOP of the stack .le;_.M -- address of the address of the top of available unassigned storage in the data region (used to create more space when needed). .le;MEMORY -- returns the address of the "top" of unassigned data region .le;_.D+! -- reserves the number of bytes specified by the value on the TOP of the stack in the data region .le;,D -- pushes the longword on TOP of the stack into the data region and updates the _.D pointer .le;B,D -- pushes the byte on TOP of the stack into the data region and updates the _.D pointer .le;INITIALIZE__DATA__REGION -- initializes the data region for use. Should be executed only once before using the data region. Usually used with DEF__INIT and USER__INIT (q.v.). .els If a definition of a STOIC word causes _.D to exceed _.M, additional storage will be created automatically, provided the ".D+!", ",D" , and "B,D" words are used for storage allocation. .hl 4 User stacks .p,0 .X Advanced topics >Storage organization >User stacks .x User stacks .x STACK .x BPUSH .x BPOP STOIC provides facilities for the user to define byte-oriented stacks for his own use. Three words are available for this service: .list 1 .le;STACK -- defines the user stack .le;BPUSH -- pushes a byte onto the stack .le;BPOP -- removes a byte from the stack .els To define a stack the following format is used: .lt STACK .el The number of bytes is stacked first, to be followed by the string which names the stack. The STOIC operator "STACK" then creates the stack. The form of the stack is: .s 1 .lt Name: .LONG Name+12 ;Lower limit .LONG Name+12+N ;Pointer .LONG Name+12+N ;Upper limit .BLKB N ;Byte storage space .el .p,1 To push a byte onto a user-defined stack, the byte value must be stacked and then the name of the stack: .lt BPUSH .el If the stack has overflowed its defined capacity, an error message is sent to the user's terminal and the current STOIC command is aborted. .p,1 Recovering a byte from a stack is accomplished by stacking the name of the user-defined stack and invoking BPOP. The current top of the user-defined stack is pushed onto the parameter stack: .lt BPOP .el If the stack is empty, BPOP will send an error message to the user's terminal and abort the current STOIC command. .p,1 The example below illustrates defining a stack, pushing a byte onto it and then recovering the byte: .lt ^X10 'Demo STACK % Defines the stack named "Demo" ^XFF Demo BPUSH % Pushes the byte "FF" onto Demo Demo BPOP % Pops Demo and puts byte onto % parameter stack .el .hl 3 Using the system services .x Advanced topics >System services .x System services .x System services >Calling .p,0 System services are invoked by means of the following instruction: .s 1 .lt CALLG (r10), .el This indicates that the parameter list must be built in the parameter stack. If the system service requires an address, the name of a variable is pushed onto the stack by merely stating the variable name. If a value is required by the system service, either a literal is pushed onto the stack or the form .s 1 .lt Variable_name @ .el is used. For strings, a descriptor is usually required. A string descriptor may be built in the stack by means of the following sequence: .x System services >String descriptor .s 1 .lt (Assume string address on TOP of stack.) COUNT % Make a string descriptor: .LONG length,FBA MARK % Location of length to L_stack .... (additional parameters) RECALL % Get P_stack descriptor address from L_stack .... (additional stuff) SYS$SERVICE % Call the system service n ( DROP ) % Dump stack junk if necessary .el .x System services >Parameter list As an example of building a parameter list in the stack, consider calling the system service which gets the message associated with a condition code returned by a system service. The system service to do this is called "$GETMSG" and is defined by: .s 1 .lt $GETMSG msgid,msglen,bufadr,[flags],[outadr] where msgid -- condition code for which a message is to be returned. Passed by value. msglen -- address of a word to receive the length of the message string. bufadr -- address of a character string descriptor pointing to the string destined to receive the message string. Maximum length will not exceed 256 bytes. flags -- mask defining message content (optional, value) outadr -- address of a 4 byte array (optional) .el The STOIC word "SYSMSG" is defined by: .s 1 .x SYSMSG .lt 'SYSMSG : NOTE % transfer condition code to L_stack BUF 100 % result-string descriptor MARK % address of string descriptor to L_stack 0 % outadr not used (last parameter stacked first) ^X0F % flags (return full message) RECALL % points to result_string descriptor (from L_stack) DUP % return count into same descriptor RECALL % condition code restored from L_stack 5 % Number of parameters required $GETMSG % call system service 6 (DROP) % clean up stack: 5 parameters and parameter count ; .el .p,1 .x System services >Parameter block .x IORB As an alternative to building a parameter list in the stack, it is possible to define a vector in the user data area into which the parametric values are to be loaded. To illustrate this technique, consider the following definitions for an Input/Output Request Block. CUR__IORB points to the current IORB being used and is defined as: .s 1 .lt 0 'CUR_IORB VARIABLE .el .s 1 The current IORB must be first initialized by means of INIT__IORB: .s 1 .lt 'INIT_IORB : CUR_IORB @ DUP @ 1+ 1 DO DUP I 4 * + 0<- LOOP DROP ; .el Space for the IORB in the data area of STOIC is created by invoking the STOIC word "IORB". Its definition is: .s 1 .lt 'IORB : 0C SWAP VARIABLE 0C 4 * .D+! ; .el .s 1 Once established, the IORB can be used by QIO; note, that in the list of IORB entry point filling operators below they are in order of occurrence of the parameters in the parameter-list given for $QIO. .s 1 .lt 'EFN! : CUR_IORB @ 04 + ! ; 'CHAN! : CUR_IORB @ 08 + ! ; 'FUNC! : CUR_IORB @ 0C + ! ; 'IOSB! : CUR_IORB @ 10 + ! ; 'ASTADR! : CUR_IORB @ 14 + ! ; 'ASTPRM! : CUR_IORB @ 18 + ! ; 'P1! : CUR_IORB @ 1C + ! ; 'P2! : CUR_IORB @ 20 + ! ; 'P3! : CUR_IORB @ 24 + ! ; 'P4! : CUR_IORB @ 28 + ! ; 'P5! : CUR_IORB @ 2C + ! ; 'P6! : CUR_IORB @ 30 + ! ; .el .s 1 The general format for loading the IORB is: .lt XXXX! .el .s 1 where XXXX corresponds to one of the operators above. For example to set up channel 3 in the current IORB one would use: .s 1 .lt 3 CHAN! .el .hl 3 Compiling .p,0 .x Advanced topics >Compiling .x Compiling .x Compile buffer .x IMMEDIATE attribute byte The first phase of the STOIC cycle is that of compiling a definition for a new STOIC word. This takes place in the "compile__buffer", an area consisting of 400 bytes. Once a command line (which may be either a command to the STOIC system or a new word definition) has been compiled it may be executed. Some previously defined STOIC words are assigned an "IMMEDIATE" attribute byte. This means that no subroutine call to that word (which is the usual case) is to be compiled, but that the definition in the dictionary is itself to be executed. In this way certain actions may be instituted which can alter the way in which compiling is to proceed or the nature of previously compiled code. As an example, the "B_^" word may be cited: the action of this word is to change the addressing mode of the last compiled byte from "(X)" to "B_^(X)" and to insert the next integer on the command line as the next byte in the compile buffer, thereby making it a byte offset. This example points out that in the compile buffer offsets follow register usage bytes. .hl 3 Making a new system .p,0 .x Advancted topics >Making a new system .x Making a new system Once a set of STOIC words has been defined and debugged it is often convenient to make a new executable module containing those definitions so that they need not be compiled each time they are to be used. To this end the "IHEAD" file has been provided. The usual procedure is to build a command file which will cause either the STOIC kernel or main STOIC to be copied, extended, and renamed as a new system. Each of these steps will be discussed below. .hl 4 Including predefined files .p,0 .x Making a new system >Including files ***How to insert user-defined calls similar to those in the "SS" module *** .hl 4 Loading definition files .p,0 .x Making a new system >Loading files In general the user will cause a series of files to be loaded by STOIC. Each file will define part of the system being built. Typically the .s 1 .lt 'Name LOAD or 'Name LOAD/L .el words are used for this. It is the responsibility of the user to make sure that the order of loading files is such that the definitions appear in proper dependency order; i.e., that the more "primitive" definitions appear before the more complicated ones calling on them. The very last file of definitions to be loaded is "IHEAD_.". Following this file is the STOIC command "BREAK" which causes the new system to be created. .hl 4 BREAK and a _.COM file .p,0 .x Making a new system >BREAK and .COM file .x BREAK To illustrate the creation of a new system consider the "STOIC_.CRE" file used to make the basic STOIC system: .s 1 .lt $ COPY KERNEL.EXE BREAK.EXE ! copy of executable image as it now exists $ RUN KERNEL CR "Loading DEF" MSG 'DEF LOAD CR 'OBUF LOAD/L 'VT100 LOAD/L 'IHEAD LOAD/L BREAK % copy newly compiled code into new executable image ;F $ RENAME BREAK.EXE STOIC.EXE .el .p,0 The first line causes a copy of the kernel to be made under the standard name of "BREAK_.EXE" -- ^&no other name is permissable without altering the definition of the STOIC word "BREAK" in the "IHEAD" definition file\&. Next the STOIC kernel is executed, taking as its initial input the lines following the "RUN" command. "DEF", "OBUF", "VT100", and "IHEAD" are loaded by the kernel and the definitions contained in them are added to the dictionary. The "BREAK" command causes the new system to be written out under the name "BREAK_.EXE". Input is then terminated by the ";F" word and control returns to VMS. The newly created (altered?) "BREAK_.EXE" file is renamed to "STOIC_.EXE". This procedure may be used to create other systems based on STOIC simply by adding your special definition files to the load list just before the "IHEAD" definition file, and by changing the "STOIC_.EXE" name to the desired one in the "RENAME" command at the end of the "_.COM" file. .hl 3 Direct execution .x Advanced topics >Direct execution .x Direct execution .x Direct execution >INLINE .x Direct execution >IMMEDIATE (Making use of INLINE< ... >INLINE ; IMMEDIATE ) .hl 2 Some examples and exercises (elem fcns as CFs, infix -> postfix) .x Examples .x Exercises .s 1 .lt % Floating point operations % W. Wiitanen, GMR % 17.XII.81 % ASSEMBLER< DEFINITIONS 4F 'ACBF AC 40 'ADDF2 AC 41 'ADDF3 AC D4 'CLRF AC 51 'CMPF AC 4C 'CVTBF AC 48 'CVTFB AC 4A 'CVTFL AC 49 'CVTFW AC 4E 'CVTLF AC 4B 'CVTRFL AC 4D 'CVTWF AC 46 'DIVF2 AC 47 'DIVF3 AC 54 'EMODF AC 52 'MNEGF AC DE 'MOVAF AC 50 'MOVF AC 44 'MULF2 AC 45 'MULF3 AC 55 'POLYF AC DF 'PUSHAF AC 42 'SUBF2 AC 43 'SUBF3 AC 53 'TSTF AC > DEFINITIONS 'FLOATING_POINT< BRANCH ASSEMBLER< FLOATING_POINT< DEFINITIONS % Floating point add '+. : INLINE< ADDF2 (P)+ (P) >INLINE ; IMMEDIATE % Floating point subtract '-. : INLINE< SUBF2 (P)+ (P) >INLINE ; IMMEDIATE % Floating point multiplication '*. : INLINE< MULF2 (P)+ (P) >INLINE ; IMMEDIATE % Floating point division '/. : INLINE< DIVF2 (P)+ (P) >INLINE ; IMMEDIATE % Floating point unary minus 'MINUS. : INLINE< MNEGF (P) (P) >INLINE ; IMMEDIATE % Convert floating to long 'FIX : INLINE< CVTFL (P) R0 MOVL R0 (P) >INLINE ; IMMEDIATE % Convert long to floating 'FLOAT : INLINE< CVTLF (P) R0 MOVL R0 (P) >INLINE ; IMMEDIATE % Output floating point as integer '=I : FIX = ; % Output floating point number on TOP of stack '=. : #F COUNT TYPE ; % Floating point tests '.NEZ. : TSTF (P)+ BNEQ ITEFT ; '.EQZ. : TSTF (P)+ BEQL ITEFT ; '.GTZ. : TSTF (P)+ BGTR ITEFT ; '.LEZ. : TSTF (P)+ BLEQ ITEFT ; '.GEZ. : TSTF (P)+ BGEQ ITEFT ; '.LTZ. : TSTF (P)+ BLSS ITEFT ; '.NE. : CMPF (P)+ (P)+ BNEQ ITEFT ; '.EQ. : CMPF (P)+ (P)+ BEQL ITEFT ; '.GT. : CMPF (P)+ (P)+ BGTR ITEFT ; '.LE. : CMPF (P)+ (P)+ BLEQ ITEFT ; '.GE. : CMPF (P)+ (P)+ BGEQ ITEFT ; '.LT. : CMPF (P)+ (P)+ BLSS ITEFT ; % Tests combined with conditionals % (values may be UNDROPed after execution of combined conditionals) '.EQ_IF. : % value1, value2, .EQ_IF. (combines function of .EQ. and IF) +CHECK INLINE< CMPF (P)+ (P)+ BNEQ >INLINE TARGET ; IMMEDIATE '.NE_IF. : +CHECK INLINE< CMPF (P)+ (P)+ BEQL >INLINE TARGET ; IMMEDIATE '.GT_IF. : +CHECK INLINE< CMPF (P)+ (P)+ BLEQ >INLINE TARGET ; IMMEDIATE '.LE_IF. : +CHECK INLINE< CMPF (P)+ (P)+ BGTR >INLINE TARGET ; IMMEDIATE '.GE_IF. : +CHECK INLINE< CMPF (P)+ (P)+ BLSS >INLINE TARGET ; IMMEDIATE '.LT_IF. : +CHECK INLINE< CMPF (P)+ (P)+ BGEQ >INLINE TARGET ; IMMEDIATE '.EQZ_IF. : % value, .EQZ_IF. (combines compare to zero with IF) +CHECK INLINE< TSTF (P)+ BNEQ >INLINE TARGET ; IMMEDIATE '.NEZ_IF. : +CHECK INLINE< TSTF (P)+ BEQL >INLINE TARGET ; IMMEDIATE '.GTZ_IF. : +CHECK INLINE< TSTF (P)+ BLEQ >INLINE TARGET ; IMMEDIATE '.LEZ_IF. : +CHECK INLINE< TSTF (P)+ BGTR >INLINE TARGET ; IMMEDIATE '.GEZ_IF. : +CHECK INLINE< TSTF (P)+ BLSS >INLINE TARGET ; IMMEDIATE '.LTZ_IF. : +CHECK INLINE< TSTF (P)+ BGEQ >INLINE TARGET ; IMMEDIATE % Some simple operators 'MAX. : DDUP .GT_IF. UNDER ELSE DROP THEN ; 'MIN. : DDUP .LT_IF. UNDER ELSE DROP THEN ; 'ABS. : DUP MINUS. MAX. ; ;F .el .pg .hl 1 Operational details .x Operational details .hl 2 Making STOIC into a subroutine .p,0 .x STOIC >Use as a subroutine .x STOIC >Reentrant STOIC may be made into a subroutine by changing the entry point name from "start" to whatever is desired by the user. Be sure to remove the word "start" from the ".end" line at the end of KERNEL. Do not insert anything in its place. .hl 2 Global register usage in STOIC kernel .x STOIC >Register conventions .list 0,"*" .le;R11 -- User table (for symbols and built in operators) .le;R10 -- Parameter stack pointer (P) .le;R9 -- Loop stack pointer (L) .le;R8 -- Dictionary pointer (DICT__PNTR) .els .hl 2 STOIC dictionary and user tables .p,0 .x STOIC >Dictionary and user tables .x Dictionary The user tables are divided into two sections: an impure one, and a kernel. In the impure psect one finds pointers to STOIC objects. The pure psect contains PIC for the various STOIC words defined by the user and the dictionary. The chart below enumerates the dictionary and user__table correspondences. An asterisk following an entry in the user__table column indicates that the object pointed to by the longword is accessible as a STOIC word of the same name as that used as the argument to the longword. The associated attribute in the STOIC kernel dictionary is "push__this__word", indicating that the TOP of the parameter stack will contain the ^&address\& of the longword in the user__table. In general, routines such as Lookup, Compile, and the like, can be executed in two ways: .s 1 .list 1 .le;By invoking them by their "internal" names: "I__" .le;By the sequence _@ EXEC .els .s 1 .lt STOIC word User_table entry STOIC word ---------- ---------------- ---------- Ctrl_C_handler -> .long (I_ctrl_C_hndlr) * Lookup -> .long A(I_lookup) * Compile -> .long A(I_compile) * Execute -> .long A(I_execute) * Literal -> .long A(I_literal) * Errchk -> .long A(I_errchk) * Readline -> .long A(I_readline) * Abort -> .long A(I_abort) * Compile_error -> .long A(I_compile_error) * Enter -> .long A(I_enter) * User_init -> .long A(I_user_init) * Cond_handler -> .long A(I_cond_handler) * Ctrl_C_temp -> .quad 0 Ctrl_C_flag -> .long 0 P_stack_0 -> .long A(Parameter stack) R_stack_0 -> .long 0 L_stack_0 -> .long A(Loop stack) V_stack_0 -> .long A(vocabulary stack) Vocab_SP -> .long A(vocabulary stack first entry = KERNEL) Assembler -> .long 0 STOIC -> .long 0 Free_user_space -> .long 30 Free_lkp_space -> .long 30 Dispatch_adr -> .long A(Lookup_dispatch table) Comp_buf_0 -> .long A(Compile buffer) Comp_buf_pntr -> .long A(Current compile buffer byte) End_of_cmd -> .long 0 End_of_line -> .long 0 Check -> .long 0 Error_PC -> .long 0 Cond_code -> .long 0 Dict_pntr -> .long A(Dictionary space start) Current -> .long B_kernel Prompt -> .long Prompt0 U_ifi -> .long 0 U_ifm -> .long 3 U_ift -> .long A(channel list -- external) Line_buffer -> .quad discriptor for line_buffer string Rest_of_line -> .long 0,A(line_buffer string) Word_buffer -> .long A(word_buffer descsriptor) U_sgn -> .long 0 U_mag -> .long 0 U_rad -> .long 16 .D -> .long 0 (next free data location) .M -> .long 0 (first unavail. mem. locn.) Ust_temp -> .long 0 (space for user entries) .el .s 1 .tp 10 .s 1 .x STOIC >Dispatch table .x Dispatch table .x Dictionary >Attributes .x Attribute bytes .lt STOIC word Dispatch_table entry STOIC word ---------- -------------------- ---------- Jump_to_me -> .long A(I_jump_to_me) * Compile_byte -> .long A(I_compile_byte) * Push_this_word -> .long A(I_push_this_wd) * Push_vocab -> .long A(I_push_vocab) * Immediate -> .long A(I_immediate) Lkp_dsp_temp -> .long 0 .el By invoking the STOIC word in the left hand column, the longword in the middle column is pushed onto the TOP of the parameter stack. If the table entry is marked as a STOIC word, that operation may be accessed as a regular STOIC word by using "I__", or by using .s 1 .lt @ EXEC .el .hl 2 Structure of entries in STOIC tables .s 1 .x STOIC >Table structure .x Header block .x STOIC >User table .x User table The STOIC header block, used throughout the program takes the form: .s 1 .literal .PSECT KERNEL ;THIS IS THE STANDARD PSECT .LONG KERNEL ;POINTS BACK TO PREVIOUS DEFINITION KERNEL=.-4 ;ADDRESS OF THIS HEADER FOR BACK REF. .ASCIC /DICTIONARY_NAME/ ;NAME OF DICTIONARY ENTRY .BYTE LOOK_UP_ATTRIBUTE ;TYPE OF ENTRY & ACTION ON LOOKUP .end literal .s 1 The macro used to generate these headers is: .s 1 .x HEADER macro .literal .MACRO HEADER MACNAME,NAME=<>,LOOKUP_ATR=JUMP_TO_ME,- BRANCH=KERNEL .LONG BRANCH ;POINTER TO PREVIOUS DEFINITION BRANCH=.-4 ;FOR NEXT BACK REF. POINTER .NCHR NCHR,^!NAME! ;LENGTH(NAME) .IF LE,NCHR ;TEST FOR EXISTENCE OF AUXILIARY NAME .ASCIC /MACNAME/ ;NONE. USE PRINCIPAL NAME .ENDC .IF GT,NCHR ;TEST FOR EXISTENCE OF AUXILIARY NAME .ASCIC /NAME/ ;YES. USE SECONDARY NAME .ENDC .BYTE LOOKUP_ATR ;SET LOOKUP ATTRIBUTE MACNAME: ;ENTRY POINT TO THE DEFINITION CODE .ENDM .END LITERAL .s 1 To Define a Longword Table Entry ("DLTE") which may be used either as a value, pointer, or code dictionary entry, a special format is used. This format is found only in "user__table" and "lookup__dispatch". It is used in conjunction with the "NEWTAB" macro used to initialize a new table: .s 1 .x NEWTAB macro .literal .MACRO NEWTAB TABLE_OFFSET=0 .ENDM .END LITERAL .S 1 The table entry created looks like this: .s 1 .literal (.psect current psect name) **: .LONG initial value (a pointer or a value) .PSECT KERNEL HEADER ,- Name_of_table_entry,- Push_this_word ;Force address to be pushed .LONG address of ** ;This address is pushed (.psect current psect name restored, PC = **+4) .end literal .s 1 and the macro like this: .s 1 .x DLTE macro .literal .MACRO DLTE NAME,INIT=0,?P1 NAME=TABLE_OFFSET ;RELATIVE POSITION IN THE TABLE DUMMY=. ;KEEP ADDRESS TEMPORARILY .LONG INIT ;VALUE OR POINTER HERE TABLE_OFFSET=TABLE_OFFSET+4 ;UPDATE TABLE OFFSET .SAVE ;SAVE CURRENT .PSECT HEADER P1,- ;DUMMY NAME GENERATED BY MACRO NAME,- ;NAME OF TABLE ENTRY PUSH_THIS_WORD ;LOOKUP ATTRIBUTE BYTE .LONG DUMMY ;ADDRESS OF TABLE ENTRY .RESTORE ;RECOVER PREVIOUS .PSECT .ENDM .END LITERAL .hl 2 Lookup attributes .p,0 .x Attributes .x Words >Attributes .x LOOKUP .x LOKUP >Attributes Upon encountering what is presumed to be a STOIC word, the LOOKUP routine is called with a pointer to the string on TOP of the parameter stack. If the word is undefined in any branch on the vocabulary stack the parameter stack is modified so that the TOP entry is zero ("false") and TOP-1 is the original string pointer. If the word is found in some branch represented in the vocabulary stack, the TOP of the parameter stack is set to one ("true") and TOP-1 is set to the ^&address\& of the definition (usually compiled, i.e. executable, code) associated with the definition. To interpret the dictionary entry properly the various entries are classified by an attribute byte. This is obtained by invoking "Lookup__attribute @". Distributing control to the various subroutines to handle the attribute codes is done in the "Compile" subroutine in the kernel. Each attribute byte is an offset to an address in the Dispatch__table (see above) and control is effected through a "JSB _@Lookup__dispatch(R0)" where R0 contains the attribute value. Note that "Lookup__dispatch" is an alias for the head of the Dispatch__table. .s 1 .list 1 .x Jump__to__me .x Attributes >Jump__to__me .le;Jump__to__me -- compiles a jump to its argument (=0) .s 1 On TOP of the parameter stack is the address of the (code) definition of the looked up STOIC word. This address is modified so that it is a word displacement from the head of the dictionary (subtract contents of R8 -- address of dictionary head -- from the TOP of the stack and convert long to word). The following code is then entered into the compile buffer: .s 1 .lt JSB W^(R8) ;R8=A(Dictionary head) .el .s 1 This effectively transfers control to the specified coding in the dictionary definition of the STOIC word. After execution of the code (which may itself have many "JSB's" to other STOIC word definitions, control will be returned to the byte following the instrution. .x Immediate .x Attributes >Immediate .le;Immediate -- executes at compile time (=4) .s 1 In this case, the definition (code) associated with the STOIC word under consideration is executed immediately (i.e. ^&no\& entry is made in the compile buffer by "Compile"). The TOP of the stack will be cleared of the entry point to the definition (code) and control will be returned to the beginning of the "Compile" (= I__compile) subroutine to look for another STOIC word. This attribute is most frequently associated with the .s 1 .lt INLINE< ... >INLINE .el pair. .x Compile__byte .x Attributes >Compile__byte .le;Compile__byte -- compiles a byte (=8) .s 1 Here, the byte on TOP of the parameter stack in pushed into the compile buffer and the buffer pointer is updated. Control is returned to the beginning of the "Compile" subroutine to look for another STOIC word. This attribute is used in the "AC" word. .x Push __this__word .x Attributes >Push__this__word .le;Push__this__word -- pushes a constant on the stack (=_^X0C) .s 1 This attribute causes the word on TOP of the parameter stack to be compiled into the following code: .s 1 .lt MOVL # -(R10) .el .s 1 into the compile buffer. Essentially it forces a number onto the TOP of the parameter stack ^&when the compiled code is executed\&. This is the standard mechanism for entering numerical literals. .x Push__vocab .x Attributes >Push__vocab .le;Push__vocab -- push vocabulary branch on top of vocab stack (=_^X10) .s 1 Creates an entry in the ^&compile buffer\& which takes the form: .s 1 .lt MOVL # -(R10) .el .s 1 Then the operation .s 1 .lt JSB W^(R8) .el .s 1 is entered into the ^&compile buffer\&. These two operations, ^&when executed\& will cause the TOP of the parameter stack (at the time of execution of the compiled code) to be pushed onto the TOP of the vocabulary stack (action of V__push). This attribute byte is used when a vocabulary is invoked. .els .hl 2 Main loop of STOIC .x STOIC .x STOIC >Main loop .x Top__loop The main program is a loop called "top__loop" which: .s 1 .list 0 .le;Invokes ERRCHK (currently does nothing) .le;Initializes the compile buffer pointer .le;Clears "CHECK", "END__OF__CMND", and "END__OF__LINE" .le;Reads an input line (via "READLINE") .br (Note: current implementation does not permit "continuation" lines.) .le;Checks for end of file on input. If so: .list 0 .le;Executes the operation "SEMIF" to go down a level on the file stack .le;Returns to step 4 above .els .le;If not end of file: .br Calls the "COMPILE" operator and checks to see if the end of the command has been reached. If so, control returns to step 4 above for new input. If not, the "CHECK" level is examined to test for pending ";" or "THEN" etc. If this is the case, then control again returns to step 4 above. Otherwise the line is executed (via "EXECUTE") and control is returned to step 1 above. .els .pg .hl 1 Conventions to be used .p,0 .x Conventions .x STOIC .x STOIC >Operations >Conventions .x STOIC >Words >Conventions The operator name is listed in CAPITALS. To the left of the name is the list of input arguments (enclosed <...>); the left-most one being the farthest from the TOP of the parameter stack and the one nearest the operator being on TOP. To the right of the operator are the results of its action (if any). Here the item nearest the operator name is deepest in the stack and the rightmost one is on TOP. E.g. .s 1 .literal TOP (before oprn.) TOP (after oprn.) | | V V +ROT .end literal .s 1 In general the parameter stack contains literals and addresses of entities (in the case of strings, a descriptor is used). .s 1 The outline below illustrates how the remaining sections of this guide are organized. .nmlv 4,0,1,1,1,1 .x STOIC .x STOIC >Words >Guide .hl 2 Arithmetic and logic operations .hl 3 Memory .hl 4 Unary .hl 3 Special constants .hl 4 Unary .hl 3 Stack .hl 4 Binary .hl 4 Unary .hl 3 Stack : memory .hl 4 Binary .hl 4 Unary .hl 2 Assembler .hl 2 Compilation .hl 2 Comparison .hl 2 Conditionals .hl 2 Constants .hl 3 Computed .hl 3 Kernel .hl 3 VAX/VMS system services .hl 4 Event flag .hl 4 I/O Operations .hl 4 I/O Modifiers .hl 4 Status codes .hl 4 System global sections .hl 2 Conversion .hl 2 Dictionary lookup attribute actions .hl 2 Dictionary manipulation .hl 2 Exceptions .hl 2 Execution .hl 2 Initialization/re-initialization .hl 2 Input/Output .hl 3 Channels .hl 3 Close files .hl 3 Input .hl 3 Open files .hl 3 Output .hl 3 Prompt text .hl 3 Request blocks (in branch IORB_<) .hl 2 Iteration .hl 3 Iterations depending on truth values .hl 3 Count-controlled iterations .hl 3 Do loops .hl 3 Special values associated with loops .hl 2 Redefinitions for efficiency .hl 2 Stack manipulation .hl 3 Definition of user stacks and operations .hl 3 Kernel stack operations .hl 3 In-stack manipulations .hl 3 Protection .hl 2 Storing and fetching .hl 3 Memory .hl 3 Stack .hl 2 String manipulation (including WORD) .hl 2 System services .hl 3 Change branch .hl 3 Creating a new STOIC system .hl 3 VAX/VMS services .hl 4 Event flags .hl 4 Input/output .hl 4 Logical name .hl 4 Status codes .hl 4 Process control .hl 4 Timer and Time conversion .hl 4 CLI service .hl 2 Tests .hl 3 Arithmetic .hl 3 Compiler .hl 3 Stack .hl 3 String .hl 2 Variables (defining) .hl 3 Array .hl 3 Dictionary .hl 3 Simple .hl 3 String .hl 2 VT100 definitions and operations .hl 3 Definitions .hl 3 Operations .hl 3 Control sequences .hl 2 VT100 Editor definitions .pg .nmlv 3,1,1,1,1,1 .ts 4,16,24,32,40,48,56,64,72 .hl 1 Definitions of the components of STOIC .x STOIC .x STOIC >Words .x STOIC >Words >Arithmetic and logic .hl 2 Arithmetic and logic operations .hl 3 Operations involving just memory .hl 4 Unary .x 1+! .hl 5 Add one to memory .lt Format:
1+! Branch: STOIC< Description: Increments the value at the Address by 1. Definition: '1+! : INCL @(P)+ ; .el .x 1-! .hl 5 Subtract one from memory .lt Format:
1-! Branch: STOIC< Description: Decrements the value at Address by 1. Definition: '1-! : DECL @(P)+ ; .el .x 0<- .hl 5 Clear memory longword .lt Format:
0<- Branch: STOIC< Description: Stores a zero at the longword specified by the Address. Definition: '0<- : CLRL @(P)+ ; .el .x 0W<- .hl 5 Clear memory word .lt Format:
0W<- Branch: STOIC< Description: Stores a zero at the word specified by the Address. Definition: '0W<- : CLRW @(P)+ ; .el .x 1<- .hl 5 Store longword 1 in memory .lt Format:
1<- Branch: STOIC< Description: Store a longword 1 at location specified by Address. Definition: '1<- : MOVL S^ 1 @(P)+ ; .el .x -1<- .hl 5 Store longword -1 in memory .lt Format:
-1<- Branch: STOIC< Description: Store a longword -1 at location specified by Address. Definition: '-1<- : MNEGL S^ 1 @(P)+ ; .el .hl 3 Special constants .hl 4 Unary .x +CHECK .hl 5 Increment "Check" by 1 .lt Format: +CHECK Branch: STOIC< Description: Adds one to the kernel-defined constant "CHECK". Definition: '+CHECK : CHECK 1+! ; .el .x -CHECK .hl 5 Decrement "Check" by one .lt Format: -CHECK Branch: STOIC< Description: Subtracts one from the kernel-defined constant "CHECK". Definition: '-CHECK : CHECK 1-! ; .el .hl 3 Stack to stack operations .hl 4 Binary operations .X AND .hl 5 And TOP and TOP-1 together: result on TOP .lt Format: AND Branch: STOIC< Description: Performs the logical AND of TOP and TOP-1 and places the result on the stack. The previous TOP entry is destroyed and what was TOP-1 has been overwritten by the result. Definition: 'AND : MCOML (P) (P) BICL2 (P)+ (P) ; .end literal .X MOD .hl 5 Mod calculates the modulus .lt Format: MOD Branch: STOIC< Description: This operator calculates (Value)MOD(Modulus), which is computationally the same as REMAINDER(Value/Modulus). The result is placed on the TOP of the parameter stack. Note that UNDROP can be used to recover . Definition: 'MOD : MOVQ (P)+ R0 CLRL R2 EDIV R0 R1 R1 -(P) ; .end literal .X MAX .hl 5 Max finds the maximum of two integers .lt Format: MAX Branch: STOIC< Description: The Max operator computes the maximum of the top two values in the parameter stack. The TOP becomes the maximum. Definition: 'MAX : DDUP GT IF % is value2 greater? UNDER ELSE % yes DROP THEN % no ; .el .X MIN .hl 5 Min finds the minimum of two integers .lt Format: MIN Branch: STOIC< Description: The Min operator calculates the minimum of the top two values in the parameter stack. The TOP becomes the minimum. Definition: 'MIN : DDUP LT IF % is value2 lesser? UNDER ELSE % yes DROP THEN % no ; .el .X OR .hl 5 Or performs the inclusive or .lt Format: OR Branch: STOIC< Description: Performs the logical OR of TOP and TOP-1, and places the result on the stack. The previous TOP entry is destroyed and what was TOP-1 has been overwritten with the new result. Definition: 'OR : BISL2 (P)+ (P) ; .end literal .X XOR .hl 5 Xor calculates the exclusive or .lt Format: XOR Branch: STOIC< Description: Performs the exclusive-or of TOP and TOP-1, placing the result on the stack. The previous TOP entry is destroyed and what was TOP-1 is overwritten by the new result (truth_value). Definition: 'XOR : XORL2 (P)+ (P) ; .end literal .X + .hl 5 Add (+) -- add two integers .lt Format: + Branch: STOIC< Description: Integer arithmetic add of TOP and TOP-1. Result replaces , and has been popped. Definition: '+ : ADDL2 (P)+ (P) ; .end literal .X - .hl 5 Subtract (-) -- difference two integers .lt Format: - Branch: STOIC< Description: Simple subtraction of the two integers on TOP and TOP-1 of stack. The difference replaces the former TOP-1 (making the difference TOP) and the minuend is popped. Description: '- : SUBL2 (P)+ (P) ; .end literal .X * .hl 5 Multiply (_*) -- form product of two integers .lt Format: * Branch: STOIC< Description: Integer multiplication. The product replaces the multiplier, and the multiplicand is popped. Definition: '* : MULL2 (P)+ (P) ; .end literal .X / .hl 5 Divide (_/)-- form quotient of two integers .lt Format: / Branch: STOIC< Description: Binary integer divide yielding a quotient. No remainder. Divisor is replaced by the quotient and the dividend is popped. Definition: '/ : DIVL2 (P)+ (P) ; .end literal .X /MOD .hl 5 Divide with remainder -- quotient _& remainder of two integers .lt Format: /MOD Branch: STOIC< Description: Performs a full binary integer division retaining the remainder. TOP will have the remainder and TOP-1 the quotient. Definition: '/MOD : MOVQ (P)+ R0 CLRL R2 EDIV R0 R1 R1 R0 MOVQ R0 -(P) ; .end literal .hl 4 Unary operations on TOP of stack .X ABS .hl 5 Abs computes the absolute value .lt Format: ABS <|Value|> Branch: STOIC< Description: Abs takes the absolute value of the TOP of the parameter stack. The new value replaces the TOP of the stack. Definition: 'ABS : DUP MINUS MAX ; .el .X MINUS .hl 5 Minus -- negates top value of stack .lt Format: MINUS <-Value> Branch: STOIC< Description: Performs twos-complement negation of Value (longword). Definition: 'MINUS : MNEGL (P) (P) ; .end literal .X NOT .hl 5 Not -- complements the top of the stack .lt Format: NOT Branch: STOIC< Description: Forms ones-complement of the TOP of the parameter stack. Definition: 'NOT : MCOML (P) (P) ; .end literal .X 1+ .hl 5 Increment value of TOP of stack by one .lt Format: 1+ Branch: STOIC< Description: Adds one to the value of the item on the TOP of the parameter stack. Definition: '1+ : INCL (P) ; .end literal .X 2+ .hl 5 Increment value of TOP of stack by two .lt Format: 2+ Branch: STOIC< Description: Adds two to the value of the item on the TOP of the parameter stack. Definition: '2+ : ADDL2 S^ 2 (P) ; .end literal .X 4+ .hl 5 Increment value of TOP of stack by four .lt Format: 4+ Branch: STOIC< Description: Adds four to the value of the item on the TOP of the parameter stack. Definition: '4+ : ADDL2 S^ 4 (P) ; .end literal .X 1- .hl 5 Decrement value of TOP of stack by one .lt Format: 1- Branch: STOIC< Description: Subtracts one from the value of the item on the TOP of the parameter stack. Definition: '1- : DECL (P) ; .end literal .X 2- .hl 5 Decrement value at TOP of stack by two .lt Format: 2- Branch: STOIC< Description: Subtracts two from the value of the item on the TOP of the parameter stack. Definition: 2- : SUBL2 S^ 2 (P) ; .end literal .X 4- .hl 5 Decrement value on TOP of stack by four .lt Format: 4- Branch: STOIC< Description: Subtracts four from the value of the item at the TOP of the parameter stack. Definition: '4- : SUBL2 S^ 4 (P) ; .el .X 2* .hl 5 Double the value on TOP of the stack .lt Format: 2* Branch: STOIC< Description: Doubles the value on TOP of the parameter stack. Definition: '2* : ADDL2 (P) (P) ; .EL .hl 3 Stack to memory operations .hl 4 Binary .X +! .hl 5 Add value to specified memory location .lt Format:
+! Branch: STOIC< Definition: Adds Value to the contents of Address. Description: '+! : MOVL (P)+ R0 % r0-> memory location ADDL2 (P)+ (R0) % do it ; .end literal .X +<- .hl 5 Add value to specified memory location .lt Format:
+<- Branch: STOIC< Description: Adds Value to the contents of Address. Note change of order of parameters. Definition: '+<- : ADDL2 (P)+ @(P)+ ; .end literal .X -! .hl 5 Subtract value from specified memory location .lt Format:
-! Branch: STOIC< Description: Subtracts value from contents of Address. Definition: '-! : MOVL (P)+ R0 SUBL2 (P)+ (R0) ; .end literal .X -<- .hl 5 Subtract value from specified memory location .lt Format:
-<- Branch: STOIC< Description: Subtracts Value from contents of Address. Note change in order of parameters. Definition: '-<- : SUBL2 (P)+ @(P)+ ; .end literal .hl 4 Unary .X 1+! .hl 5 Add one to value specified by address .lt Format:
1+! Branch: STOIC< Description: Increments the value at the Address by one. Definition: '1+! : INCL @(P)+ ; .end literal .X 1+<- .hl 5 Add one to value specified by address .lt Format:
1+<- Branch: STOIC< Description: Increments the value at Address (identical in operation to "1+!"). Definition: '1+<- : INCL @(P)+ ; .end literal .X 1-! .hl 5 Subtract one from value specified by address .lt Format:
1-! Branch: STOIC< Description: Decrements value at Address by one. Definition: '1-! : DECL @(P)+ ; .end literal .X 1-<- .hl 5 Subtract one from value specified by address .lt Format:
1-<- Branch: STOIC< Description: Decrements value at address by one (identical to "1-!" in operation). Definition: '1-<- : DECL @(P)+ ; .end literal .hl 2 STOIC assembler related operations .P,0 .X STOIC >Words >Assembler related The assembler portion of STOIC is accessed through the dictionary branch called "ASSEMBLER_<" (use ASSEMBLER_< to set up this vocabulary). Operations found in the assembler branch of the dictionary are described below. .X AC .hl 3 AC -- defines ^assembler ^constant (one byte) .lt Format: AC Branch: ASSEMBLER< Description: The number and name on the top of the parameter stack are used to create new assembly constants. The name is entered into the dictionary with the lookup attribute of "compile_byte". Each reference to the name will cause the byte defined by the entry in the stack to be inserted at the current position in the compile buffer (U_cpb). E.g. D0 'MOVL AC will cause definition of the word "MOVL" and every invocation of that word in subsequent definitions will cause the byte "D0" to appear in the compile buffer. The compile buffer pointer (U_cpb) will be updated by 1 byte. .el .X Assembler addressing modes .hl 3 Assembler addressing modes .literal Format: Branch: ASSEMBLER< Description: Creates MACRO-like register and addressing symbols which, when executed, define the addressing bytes for an operation. Definition: 40 '[R0] AC 50 'R0 AC 51 'R1 AC 52 'R2 AC 53 'R3 AC 59 'L AC 5A 'P AC 5E 'SP AC 60 '(R0) AC 61 '(R1) AC 62 '(R2) AC 63 '(R3) AC 69 '(L) AC 6A '(P) AC 70 '-(R0) AC 79 '-(L) AC 7A '-(P) AC 80 '(R0)+ AC 81 '(R1)+ AC 89 '(L)+ AC 8A '(P)+ AC 8E '(SP)+ AC 8F '(PC)+ AC 9A '@(P)+ AC 9F '@# AC .end literal .X CPOP .hl 3 Remove last compiled byte from buffer and stack it .lt Format: CPOP Branch: ASSEMBLER< Description: Removes the last byte in the compile buffer (U_cpb) and places it on TOP of the parameter stack. Definition: MACRO code in kernel. .el .X CPUSH .hl 3 Put a byte into the compile buffer .lt Format: CPUSH Branch: ASSEMBLER< Description: Pushes the byte on TOP of the parameter stack into the compile buffer (U_cpb) and updates the compile buffer pointer. Definition: MACRO code in kernel .el .X B^(P) .hl 3 Byte displacement address .lt Format: B^(P) Branch: ASSEMBLER< Description: Compiles a byte displacement address in the compile buffer with respect to the parameter stack register. Definition: 'B^(P) : ^X0AA CPUSH % byte displacement w.r.t. P-stack pointer % (= B^(R10)) WORD DROP ILITERAL DROP CPUSH % byte ; IMMEDIATE .end literal .X S^ .hl 3 Short literal displacement mode .lt Format: S^{Next number in input line} Branch: ASSEMBLER< Description: Short literal operator which compiles the next number on a line into the compile buffer as a short literal. This operator does not check the validity of the operand! Definition: 'S^ : WORD DROP ILITERAL DROP CPUSH % literal ; IMMEDIATE .end literal .X B^ .hl 3 Byte displacement mode .lt Format: B^ {Next number in input line} Branch: ASSEMBLER< Description: This is a byte displacement operator. It compiles the next number on the input line into the compile buffer. Definition: 'B^ : COMP_BUF_PNTR SUBL3 S^ 1 @(P)+ -(P) %address of last compiled byte ADDB2 (PC)+ S^ ^X40 @(P)+ % transform it from (X) to B^(X) WORD DROP ILITERAL DROP CPUSH % displacement byte ; IMMEDIATE .end literal .X W^ .hl 3 Word displacement mode .lt Format: W^ {Next number in input line} Branch: ASSEMBLER< Description: This is a word displacement operator. It compiles the next number in the input line into a word displacement in the compile buffer. Definition: 'W^ : COMP_BUF_PNTR SUBL3 S^ 1 @(P)+ -(P) % address of last compiled byte ^X60 ADDL2 (P)+ @(P)+ % transform it from (X) to W^(X) WORD DROP ILITERAL DROP % get and convert next # on line DUP CPUSH % compile low-order byte INCL P MOVZBW (P)+ -(P) CPUSH % compile high-order byte ; IMMEDIATE .end literal .X Assembler operation codes .hl 3 Assembler op codes .literal Format: Branch: ASSEMBLER< Description: Presence of a typical MACRO-type operation code causes the associated constant byte to be compiled. Definition: 05 'RSB AC 11 'BRB AC 12 'BNEQ AC 13 'BEQL AC 14 'BGTR AC 15 'BLEQ AC 16 'JSB AC 17 'JMP AC 18 'BGEQ AC 19 'BLSS AC 1C 'BVC AC 1D 'BVS AC 28 'MOVC3 AC 29 'CMPC3 AC 39 'MATCHC AC 3A 'LOCC AC 3C 'MOVZWL AC 7B 'EDIV AC 7D 'MOVQ AC 80 'ADDB2 AC 90 'MOVB AC 91 'CMPB AC 9A 'MOVZBL AC 9B 'MOVZBW AC B4 'CLRW AC C0 'ADDL2 AC C1 'ADDL3 AC C2 'SUBL2 AC C3 'SUBL3 AC C4 'MULL2 AC C6 'DIVL2 AC C8 'BISL2 AC CA 'BICL2 AC CC 'XORL2 AC CE 'MNEGL AC D0 'MOVL AC D1 'CMPL AC D2 'MCOML AC D4 'CLRL AC D5 'TSTL AC D6 'INCL AC DE 'MOVAL AC D7 'DECL AC E9 'BLBC AC F2 'AOBLSS AC F4 'SOBGEQ AC F6 'CVTLB AC F7 'CVTLW AC '@BRB : 11 ; 4F 'ACBF AC 40 'ADDF2 AC 41 'ADDF3 AC D4 'CLRF AC 51 'CMPF AC 4C 'CVTBF AC 48 'CVTFB AC 4A 'CVTFL AC 49 'CVTFW AC 4E 'CVTLF AC 4B 'CVTRFL AC 4D 'CVTWF AC 46 'DIVF2 AC 47 'DIVF3 AC 54 'EMODF AC 52 'MNEGF AC DE 'MOVAF AC 50 'MOVF AC 44 'MULF2 AC 45 'MULF3 AC 55 'POLYF AC DF 'PUSHAF AC 42 'SUBF2 AC 43 'SUBF3 AC 53 'TSTF AC .end literal .hl 2 Compilation operators .X STOIC >Words >Compilation operators .X ARCHER .hl 3 Computes and stores byte displacement .lt Format: ARCHER Branch: STOIC< Description: Stores displacement between pointers as a byte at "target". Used in conjunction with CMARK or TARGET. Definition: 'ARCHER : OVER - 1- B<- % store the byte BVC (TARGET) % displacement overflow? "Byte-displacement overflow." I_COMPILE_ERROR (CMARK) (ARCHER) % yes ; .end literal .x (ARCHER) .hl 3 Immediate version of ARCHER .lt Format: (ARCHER) Branch: STOIC< Description: Stores displacement between pointers as a byte at "target". Used by ARCHER. Definition: '(ARCHER) : OVER - 1- B<- ; IMMEDIATE .end literal .X CMARK .hl 3 Stacks next compile-buffer byte address .lt Format: CMARK Branch: STOIC< Description: Places the address of the next byte in the compile buffer in TOP of the stack. Used to calculate the length in bytes of compiled code. Compare: ARCHER and TARGET. Definition: 'CMARK : COMP_BUF_PNTR @ ; .end literal .X (CMARK) .hl 3 Immediate version of CMARK .lt Format: (CMARK) Branch: STOIC< Description: Immediate version of CMARK. Definition: '(CMARK) : CMARK ; IMMEDIATE .end literal .X I__COMPILE .hl 3 Compile word from input buffer .lt Format: I_COMPILE Branch: KERNEL Description: Compile a word from the line buffer. Note that the parameter stack is not used as a source of arguments but the input line buffer is. The actions taken by this operation are: .el .lm 4 .s 1 .list 0 .le;If the end of line flag is set, exit to caller .le;Get next word from input line buffer (via "word") .le;If no more words exit to caller .le;Lookup the word (via "lookup") .le;If word was not found in dictionary, then .list 0 .le;Check to see if it is a numeric or string literal (via "literal") .le;If so, go to step 1 of main line .le;If not, type out bad word (via "type") .le;Output the "undefined" string .le;Execute "compile__error" .els .le;If word was found in dictionary then .list 0 .le;Find its lookup attribute (byte following end of string) .le;Convert to a long__word in R0 .le;Execute "lookup__dispatch" (q.v.) and return to step 1 of main line above .els .els .lm 0 .lt Definition: MACRO code in kernel .el .X COMPILE__BYTE .hl 3 Compile__byte enters a byte into compile buffer .lt Format: COMPILE_BYTE Branch: STOIC< Description: Converts next WORD of input line. The word must be either an integer literal which fits into 8-bits, or an ASCII literal of the form 'X. Definition: 'COMPILE_BYTE : WORD IF ILITERAL IF % integer literal? -1 ELSE % yes DROP DUP B@ 27 EQ IF % no, ASCII literal? 1+ B@ -1 ELSE % yes DROP 0 THEN THEN ELSE % no, failure 0 THEN % no word on line, failure NOT IF "Literal Error" I_COMPILE_ERROR THEN ; .el .X CONSTANT .hl 3 Constant enters a constant into the dictionary .lt Format: CONSTANT Branch: KERNEL Description: This operator compiles a longword constant. First it enters the name of the constant into the dictionary. Sets the attribute byte to "push_this_longword", and returns. Definition: MACRO code in kernel .el .X CPOP .hl 3 Pop last compiled byte from buffer and stack it .lt Format: CPOP Branch: KERNEL Description: Removes the last byte in the compile buffer (U_cpb) and places it on top of the parameter stack. Definition: MACRO code in kernel. .el .X CPUSH .hl 3 Push a byte into the compile buffer .lt Format: CPUSH Branch: KERNEL Description: Pushes the byte on top of the parameter stack into the compile buffer (U_cpb) and updates the compile buffer pointer. Definition: MACRO code in kernel .el .X ICOMPILE .hl 3 Compile number on TOP of stack .lt Format: ICOMPILE Branch: KERNEL Description: Compiles converted numeric literal. The actual code entered into the compile buffer is: MOVL #,-(R10) The user table entry U_cpb points to the current position in the compile buffer. U_cpb is updated to the next free byte address. Definition: MACRO code in kernel .el .X ILITERAL .hl 3 Compile current WORD as a an numeric literal .lt Format: ILITERAL Branch: KERNEL Description: This operator attempts to compile the current word as a number. If it is able to do so, the TOP of the parameter stack is replaced by the binary value of the number. Otherwise the parameter stack is left undisturbed. Definition: MACRO code in the kernel .el .X .hl 3 In-line code facility .lt Format: Branch: KERNEL Definition: Supports inline code facility. This operation is effected by having the address of a byte-count word (indicating the length of the code to be copied) on the return stack (=SP). This byte-count is removed and is used to cause the string following the byte-count word to be copied to the compile buffer. Execution of the compile buffer then continues following the code to be inserted into the definition. Description: MACRO code in the kernel .el .X INLINE< .hl 3 Generate in-line coding via .lt Format: INLINE< Branch: STOIC< Description: Create 'inline' code beginning. Definition: 'INLINE< : +CHECK % compile call to internal inline S^ 4 S^ 0 % move 4 bytes TARGET 0 CPUSH % reserve word for count and mark position ; IMMEDIATE .end literal .X _>INLINE .hl 3 Close in-line code block .lt Format: >INLINE Branch: STOIC< Description: End of 'inline' code block. INLINE< ... >INLINE are used like a BEGIN ... END pair for in-line code. Definition: '>INLINE : -CHECK CMARK 1- ARCHER % fill count byte provided by INLINE< ; IMMEDIATE .end literal .s 1 The following diagram illustrates the contents of the Compile__buffer after encountering the "INLINE<...>INLINE" pair: .s 1 .lt ... INLINE< {usually ASSEMBLER codes} >INLINE ... Compile_buffer: ... ><.LONG N>{definition} ... .el .s 1 The "" subroutine copies, literally, the "{definition}" into the dictionary definition area. Precisely how INLINE<...>INLINE works is worth detailing. The definitions (in terms of previously defined STOIC words) is given above. The illustration below shows what is generated in the Compile__buffer for each STOIC word in the definition: .tp 15 .s 1 .lt Operator: |----------- : --------||- +CHECK -||- -| V VV VV V Compile_buffer: <.Word 0>> |-S^ 4--||-S^ 0--||- -||- TARGET -||----- 0 ------| V VV VV VV VV V <.BYTE 4><.BYTE 0>> |- CPUSH -||-:-||- IMMEDIATE -| V VV VV V ##### .EL .s 1 Upon execution (which actually creates the dictionary entry through "int__colon") one has the following code (here written in MACRO format): .s 1 .lt JSB +CHECK ;The addresses are actually offsets to code JSB ;in the dictionary relative to R8 .WORD 4 ;Formed from .BYTE 4 , .BYTE 0 JSB ;These 4 bytes are moved by previous JSB TARGET ;Form a .BYTE 0 and stack its address MOVL #0,-(R10) ;Stack a zero JSB CPUSH ;Enter TOP byte (=0) into compile_buffer RSB ;Two prev. ops. create .WORD 0 for .el .s 1 This code is entered with an "immediate" attribute which causes the Compile__buffer to look like this: .s 1 .lt Compile_buffer: ...><.WORD 0>### .el .s 1 and the TOP of the stack will have the address of the "_.WORD 0". .s 1 The >INLINE word is not as complicated, so only the code (in MACRO format) in the dictionary will be shown: .s 1 .lt JSB -CHECK ;Decrement CHECK JSB CMARK ;Stack the current end of the Compile_buffer JSB 1- ;Subtract one from that address JSB ARCHER ;Cause the number of bytes to be stored RSB ;in the .WORD 0 created for by ;INLINE< .el .s 1 This code is indicated to be "immediate" and when executed will cause the contents of the compile__buffer to be copied to the dictionary definition area of the STOIC word being defined. Execution will continue following the ">INLINE" word. .X I_LITERAL .hl 3 Compile string on TOP of stack as a literal .lt Format: I_LITERAL Branch: KERNEL Description: The object pointed to by the top of the parameter stack is used as an argument to either the numeric or string literal compilers. If it is possible to interpret it as a literal, it is compiled and a 1 is returned on the parameter stack; otherwise a zero is used. Definition: MACRO code in kernel .el .X SCOMPILE .X RUN__SLITERAL .hl 3 Compile a string literal .lt Format: SCOMPILE Branch: KERNEL Description: compiles a string literal. This is accomplished by: .el .lm 16 .s 1 .list 0 .le;Pushing A(run__sliteral) onto the parameter stack .le;Compiles a call to "run__sliteral" via I__JUMP__TO__ME (q.v.) .le;Creating the string literal in the compile buffer .le;Updating U__cpb appropriately .lm 0 .els .lm 0 .s 1 .lt The result in the compile buffer looks like this: JSB "run_sliteral" .ASCIC /string/ Run_sliteral -- run-time string literal processor puts the address of the string on TOP of the parameter stack, and jumps to the code following the string literal. Definition: MACRO code in kernel .el .X SLITERAL .hl 3 Compile current WORD as a string literal .lt Format: SLITERAL Branch: KERNEL Description: This operation attempts to compile the current word as a string literal. If it is successful a 1 is placed on top of the parameter stack; otherwise, a zero is entered. Definition: MACRO code in kernel .el .X TARGET .hl 3 Create a zero byte in compile buffer and stacks its address .lt Format: TARGET Branch: STOIC< Description: Compiles a zero byte and pushes its pointer on TOP of the stack. Used with ARCHER. Definition: 'TARGET : CMARK 0 CPUSH ; .end literal .X (TARGET) .hl 3 Immediate version of TARGET .lt Format: (TARGET) Branch: STOIC< Description: Immediate version of TARGET. Used with ARCHER Definition: '(TARGET) : CMARK 0 CPUSH ; IMMEDIATE .end literal .X STOIC >Words >Character comparison .hl 2 Single character comparison .X CEQ .hl 3 ASCII character comparison TOP:Input__string .lt Format: CEQ Branch: KERNEL Description: Compares the character on the top of the parameter stack with the current character in the input string. If the two are identical, the TOP of the parameter stack is set to 1 (success), otherwise it is set to zero (failure). Definition: MACRO code in kernel .el .hl 2 Conditionals .X STOIC >Words >Conditionals .X IF .hl 3 IF -- Tests TOP of stack for "true" .lt Format: IF Branch: STOIC< Description: Does a test of the low-bit of the value on TOP of the stack. If true the code following "if" is executed; otherwise a "then" or "else" is sought. Definition: 'IF : +CHECK INLINE< BLBC (P)+ >INLINE TARGET ; IMMEDIATE .end literal .X THEN .hl 3 THEN -- Common exit point for "IF...ELSE..." .lt Format: THEN Branch: STOIC< Description: Indicates where to continue after "if"..."else"... Definition: 'THEN : -CHECK CMARK ARCHER ; IMMEDIATE .end literal .X ELSE .hl 3 ELSE -- "False" continuation of the conditional .lt Format: ELSE Branch: STOIC< Description: The code following this operator will be executed if the truth value tested by the initial "if" was found to be "false". Definition: 'ELSE : INLINE< BRB >INLINE TARGET % unconditional branch SWAP % target from preceding if CMARK ARCHER % insert displacecent in if ; IMMEDIATE .end literal .X __IF .hl 3 Tests and conditionals combined .lt Format: _IF Branch: STOIC< Description: Intended to facilitate testing and conditional execution of code. Values may be UNDROPed after execution of these operations. Definitions: 'EQ_IF : +CHECK INLINE< CMPL (P)+ (P)+ BNEQ >INLINE TARGET ; IMMEDIATE 'NE_IF : +CHECK INLINE< CMPL (P)+ (P)+ BEQL >INLINE TARGET ; IMMEDIATE 'GT_IF : +CHECK INLINE< CMPL (P)+ (P)+ BLEQ >INLINE TARGET ; IMMEDIATE 'LE_IF : +CHECK INLINE< CMPL (P)+ (P)+ BGTR >INLINE TARGET ; IMMEDIATE 'GE_IF : +CHECK INLINE< CMPL (P)+ (P)+ BLSS >INLINE TARGET ; IMMEDIATE 'LT_IF : +CHECK INLINE< CMPL (P)+ (P)+ BGEQ >INLINE TARGET ; IMMEDIATE 'EQZ_IF : +CHECK INLINE< TSTL (P)+ BNEQ >INLINE TARGET ; IMMEDIATE 'NEZ_IF : +CHECK INLINE< TSTL (P)+ BEQL >INLINE TARGET ; IMMEDIATE 'GTZ_IF : +CHECK INLINE< TSTL (P)+ BLEQ >INLINE TARGET ; IMMEDIATE 'LEZ_IF : +CHECK INLINE< TSTL (P)+ BGTR >INLINE TARGET ; IMMEDIATE 'GEZ_IF : +CHECK INLINE< TSTL (P)+ BLSS >INLINE TARGET ; IMMEDIATE 'LTZ_IF : +CHECK INLINE< TSTL (P)+ BGEQ >INLINE TARGET ; IMMEDIATE .end literal .hl 2 Constants .X STOIC >Words >Constants .hl 3 Computed .X MILLISECONDS .hl 4 Convert hex integer in milliseconds to 100's of nS .lt Format: MILLISECONDS Branch: STOIC< Description: Used by system timer routines to convert the hex integer on TOP of the stack in milliseconds to hundreds of nanoseconds for system time. Definition: 'MILLISECONDS : ^X-2710 * ; % (2710 hex = 10000 decimal) .el .X 2 .hl 4 Constant 2 .lt Format: 2 Branch: STOIC< Description: Forces a 2 onto the TOP of the parameter stack without going through the literal compiler. Definition: '2 : INLINE< MOVL S^ 2 -(P) >INLINE ; IMMEDIATE .el .hl 3 Defined in kernel .X Ctrl__C__flag .X End__of__cmnd .X End__of__line .hl 4 Flags and counters .list 0 .le;Ctrl__c__flag -- flag set on _^C .le;End__of__cmnd -- compile end of command (value) .le;End__of__line -- compile end of line (value) .els .X P__stack__0 pointer .x R__stack__0 pointer .x L__stack__0 pointer .x V__stack__0 pointer .x Assembler pointer .x Stoic pointer .x Comp__buf__0 pointer .hl 4 Initial values .list 0 .le;P__stack__0 -- initial parameter stack pointer .le;R__stack__0 -- initial return stack pointer .le;L__stack__0 -- initial loop stack pointer .le;V__stack__0 -- initial vocabulary stack pointer .le;Assembler -- assembler dictionary branch pointer .le;Stoic -- STOIC branch in dictionary pointer .le;Comp__buf__0 -- initial compile buffer pointer (= A(comp__buf)) .els .x CRET .x LFEED .X BLANK .X FNSIZE .hl 4 Miscellaneous special values .lt 1. CRET -- carriage return code ^X0D 'CRET CONSTANT 2. LFEED -- line feed code ^X0A 'LFEED CONSTANT 3. BLANK -- a space ^X20 'BLANK CONSTANT 4. FNSIZE -- length of file name buffer ^X50 'FNSIZE CONSTANT .el .hl 4 Pointers .X COMP__BUF__PNTR pointer .x CURRENT pointer .x DICT__PNTR pointer .x Dispatch__adr pointer .x Line__buffer pointer .x PROMPT pointer .x U__ift pointer .x Vocab__sp pointer .x Word__buffer pointer .x .D .x .M .list 0 .le;Comp__buf__pntr -- current compile buffer pointer .le;Current -- current dictionary branch pointer .le;Dict__pntr -- dictionary pointer .le;Dispatch__adr -- pointer to dispatch table .le;Line__buffer -- descriptor for input (line) string .le;Prompt -- address of prompt string .le;U__ift -- file access table pointer .le;Vocab__sp -- vocabulary stack pointer .le;Word__buffer -- descriptor for current input word .le;_.D -- pointer to next free data location .le;_.M -- pointer to first unavailable memory location .els .hl 4 Temporaries and working storage .x BUF .list 0 .le;Buf -- string buffer .lt 100 'BUF SVARIABLE .el .X CHECK .le;Check -- IF level counter (value) .X COND__CODE .le;Cond__code -- condition code from error handler (value) .X CTRL__C__TEMP .le;Ctrl__c__temp -- 8-byte region required by _^C handler .X ERROR__PC .le;Error__PC -- PC saved by condition handler (value) .X FILE__NAME .le;File__name -- name of file (FNSIZE = ^X50) .lt FNSIZE 'FILE_NAME SVARIABLE .el .X FREE__LKP__SPACE .le;Free__lkp__space -- dispatch table space (initially 30 entries) .X FREE__USER__SPACE .le;Free__user__space -- number of free words left (initially 30 entries) .X U__IFI .le;U__ifi -- input FAB subscript number (initially 0) .X U__IFM .le;U__ifm -- Maximum FAB subscript number (set to 3) .X U__MAG .le;U__mag -- magnitude of integer literal .X U__RAD .le;U__rad -- radix (initially set to 16) .X U__SGN .le;U__sgn -- sign for integer literal .X UST__TEMP .le;Ust__temp -- space for user's entries (initially 30 entries) .els .hl 3 VAX/VMS system services .p,0 In this section the various services will be listed. For a technical description of these services, the user is referred to the VAX/VMS System Services manual (DEC AA-D018B-TE). .hl 4 Event flags .X __WASCLR .X __WASSET .list 0 .le;__WASCLR -- service unsuccessful (specified event flag 0) .le;__WASSET -- service successful (specified event flag 1) .els .hl 4 I/O operation codes .X __READVBLK .X __READPROMPT .X __WRITEVBLK .list 0 .le;__READVBLK -- read virtual block .le;__READPROMPT -- read with prompt .le;__WRITEVBLK -- write virtual block .els .hl 4 I/O operation modifiers .X M__NOECHO .X M__NOFILTR .X M__TIMED .X M__TRMNOECHO .X M__ NOFORMAT .list 0 .le;M__NOECHO -- do not echo characters for this read .le;M__NOFILTR -- do not process ^U, ^R or DEL for this read .le;M__TIMED -- "P3" specifies timeout period in seconds .le;M__TRMNOECHO -- do not echo terminating character for this read .le;M__NOFORMAT -- "PASSALL" mode for this write .els .hl 4 System service status codes and operations .X __NORMAL .X __TIMEOUT .X M__SYSGBL .list 0 .le;__NORMAL -- successful completion .le;__TIMEOUT -- operation timeout .le;M__SYSGBL -- system global section flag (default is group global section) .els .X STOIC >Words >Conversion operations .hl 2 Conversion operations .X ASCII .hl 3 Push ASCII value of first character of next WORD onto stack .lt Format: ASCII Branch: STOIC< Description: Pushes the ASCII value of first character of next word on TOP of the parameter stack. Assumes a single character word; i.e. ASCII acts as if it is a function acting on the single (non-blank) character following it on the command line. Definition: 'ASCII : WORD 2DROP % get next word on input line B@ % get first character ICOMPILE % compile as integer literal ; IMMEDIATE .el .X DIGIT .hl 3 Test current character for a valid digit .lt Format: DIGIT Branch: KERNEL Description: This STOIC word is a micro-operation used in the conversion of digit strings to integers under control of the current radix. The result is left in "U_mag". The current character in the current word is examined to see if it is a valid digit under the prevailing radix. If so, it is converted and added to (radix * current_magnitude) (="U_mag"), and the top of the parameter stack is set to 1. If not a valid digit character, the top of the parameter stack is set to zero (failure). Definition: MACRO code in kernel .el .X RADIX .hl 3 Current radix address pushed onto stack .lt Format: RADIX Branch: STOIC< Description: This operator places the address of the current radix on the TOP of the parameter stack. Definition: 'RADIX : U_RAD ; .end literal .X SIGN .hl 3 Extract sign of presumed integer .lt Format: SIGN Branch: KERNEL Description: Stores 0 as current magnitude ("U_mag") and puts sign of the digit string on TOP of the stack in "U_sgn". "+" or no sign will be a +1, whereas "-" will be a -1. Definition: MACRO code in kernel .el .X <_#_> .hl 3 Convert signed integer on TOP of stack .lt Format: <#> Branch: STOIC< Description: The signed number on TOP of the stack is converted to its ASCII equivalent and a pointer to the string is placed in TOP-1 and the length of the string (Count) in TOP. The expected use of this word is to prepare a string to be typed out. Definition: '<#> : DUP ABS % Make value positive <# #S SWAP LTZ IF ASCII - #PUT THEN #> ; .el .X _#F .hl 3 Convert floating point number on TOP of stack .lt Format: #F Branch: KERNEL Description: The floating point number on the TOP of the stack is converted to an ASCII string according to the Fortran "G" format rules. The number of digits to the right of the decimal point is set at 6, and the scale factor is zero. Definition: MACRO code in kernel .el .X = .hl 3 Type out integer value from TOP of stack .lt Format: = Branch: KERNEL Description: Converts the integer on TOP of stack to ASCII and outputs it to terminal. Definition: MACRO code in kernel .el .X ? .hl 3 Type out contents of address on TOP of stack .lt Format:
? Branch: STOIC< Description: Types contents at
. Destroys the TOP of the stack. Definition: '? : @ = ; Note that this could be rephrased to retain the TOP of the stack by using: '? : DUP @ = ; or defining '?? : DUP @ = ; .end literal .hl 3 Operations using the conversion stack (OCONSTACK) Number conversion proceeds from ^&right to left\& one digit at a time. The conversion takes place under the current radix. Digits are stored in the number conversion stack (OCONSTACK), which is a string variable. The result of the conversion is a string descriptor on TOP of the stack. .X <_# .hl 4 Begin number conversion .lt Format: <# Branch: STOIC< Description: Initialize number conversion. Sets up OCONSTACK, a string variable associated with conversion activities. OCONSTACK+4 contains the address of the head of the string. OCONSTACK+8 contains the address of the end of the string. The address of the end of the string is reset to the head of the string, and a copy of this address is left on TOP of the stack. Definition: '<# : % Start number conversion OCONSTACK 4 + DUP 4 + @ <- % reset stack ; .el .X _#_> .hl 4 Terminate number conversion .lt Format: #>
Branch: STOIC< Description: Terminates the number conversion. Leaves a pointer to the converted string at TOP-1 (put there by "<#") and the length of the string (in bytes) at TOP of the parameter stack. Definition: '#> : DROP % unconverted portion of number being converted OCONSTACK 4 + @ % beginning of string OCONSTACK 8 + @ % end of string OVER - % count ; .el .X _#PUT .hl 4 Output a character from TOP of stack .lt Format: #PUT Branch: STOIC< Description: Pushes byte from TOP of stack onto conversion stack. Definition: '#PUT : OCONSTACK BPUSH ; .el .X _#A .hl 4 Convert TOP of stack to ASCII digit .lt Format: #A Branch: STOIC< Description: Converts the integer on TOP of the stack (having a value less than the current radix) to the corresponding ASCII character(s). Definition: '#A : DUP RADIX @ GT IF DUP ^X0A GT IF % convert to number or letter? ASCII 0 + ELSE % number ^X0A - ASCII ^X0A + THEN ELSE % letter CR "Output conversion error." MSG ABORT THEN ; .el .X _# .hl 4 Compute next digit and output it .lt Format: # Branch: STOIC< Description: An integer is input from the TOP of the stack and divided by the current radix. The remainder is converted to a digit and output to OCONSTACK; the quotient remains on the stack. Definition: '# : RADIX @ /MOD #A #PUT ; .el .X _#S .hl 4 Convert entire number on TOP of stack .lt Format: #S <0> Branch: STOIC< Description: Computes all digits of the value and outputs them successively to OCONSTACK until the value becomes zero. At least one digit (0) will be output. Definition: '#S : BEGIN # DUP EQZ END ; .el .hl 3 Setting the radix .X DECIMAL .hl 4 Set radix to DECIMAL .lt Format: DECIMAL Branch: STOIC< Description: Forces the current radix to decimal. Definition: 'DECIMAL : ^X0A RADIX ! ; .el .X HEX .hl 4 Set radix to HEXADECIMAL .lt Format: HEX Branch: STOIC< Description: Sets current radix to hexadecimal. Definition: 'HEX : ^X10 RADIX ! ; .el .X OCTAL .hl 4 Set radix to OCTAL .lt Format: OCTAL Branch: STOIC< Description: sets current radix to octal. Definition: 'OCTAL : ^X8 RADIX ! ; .el .X STOIC >Words >Lookup__attribute actions .hl 2 Dictionary lookup__attribute actions .s 1 .list 1 .x Jump__to__me .le;Jump__to__me -- #I__JUMP__TO__ME .br Generates code in compile buffer to effect a jump to the STOIC operator defined by the entry at the TOP of the parameter stack. This jump is of the "JSB" type with a word offset. The code created is: .s 1 .literal JSB W^(R8) .end literal .s 1 where the locates the head of the code previously compiled into the dictionary. Remember that R8 is the dictionary pointer. The compile buffer pointer is updated. .x Immediate .le;Immediate -- #I__IMMEDIATE .br Execute at compile time, after the definition of the STOIC word has been entered in the currently active dictionary branch, by performing a jump through the TOP of the parameter stack and popping the TOP of the stack. .x Compile-_byte .le;Compile__byte #I__COMPILE__BYTE .br Compiles the byte specified by the TOP of the parameter stack directly into the compile buffer. The code compiled is: .s 1 .lt .BYTE .el .s 1 The buffer pointer is updated by 1 byte. .x Push__this__word .le;Push__this__word -- #I__PUSH__THIS__WD .br This compiles code to move the value of the defined word directly onto the stack. The code created in the compile buffer is: .s 1 .literal MOVL @ -(R10) .end literal .x Push__vocab .le;Push__vocab -- #I__PUSH__VOCAB .br The "push__vocab" attribute causes compilation of code which pushes the value onto the TOP of the parameter stack (uses I__PUSH__THIS__WD). Then it executes the operation V__PUSH to enter TOP-1 of the parameter stack onto the TOP of the vocabulary stack. .le;Lkp__dsp__temp -- temporaries for user's use (initially 30 entries) .els .x STOIC >Words >Dictionary manipulation .hl 2 Dictionary manipulation .x B, .hl 3 Append byte to end of dictionary .lt Format: B, Branch: KERNEL Description: Append the byte on TOP of the stack to the end of the dictionary. This is useful for entering a literal byte into the dictionary a datum (usually as an attribute byte). Definition: MACRO code in kernel .el .X , .hl 3 Append longword value to end of dictionary .lt Format: , Branch: KERNEL Description: Append the value (a longword) on TOP of the stack to the end of the dictionary. Used with "push_this_word" attribute. Definition: MACRO code in kernel .el .X ASSEMBLER< .hl 3 Assembler branch to top of vocabulary stack .lt Format: ASSEMBLER< Branch: KERNEL Description: Pushes the pointer to the assembler branch onto the vocabulary stack. Uses "assembler" entry in User_table. Definition: MACRO code in kernel .el .X STOIC< .hl 3 Make a dictionary branch entry in dictionary .lt Format: BRANCH Branch: STOIC< Description: This operator enters the name of the branch into the dictionary and sets the attribute byte to "branch" (i.e. "push vocabulary"). Definition: MACRO code in kernel; lated redefined as: 'BRANCH : .D@ SWAP 0 ,D BRANCH ; .el .X :..._; .hl 3 Colon/semicolon definition pair .P,0 This pair of operators, always occuring together, is one of the most important STOIC "words" inasmuch as it causes new STOIC words and their definitions to be entered into the dictionary. For that reason their operation will be discussed in detail. This pair of words is defined by MACRO code in the kernel branch. .s 1 Two forms of the colon/semicolon operator pair are available: .s 1 .list 1 .le;Immediate -- the defined word is made a dictionary entry when the semicolon is reached .le;Deferred -- the colon/semicolon operations are done at execution time .els For immediate entry of the definition into the dictionary the pair ":...;" is used. For deferred entry the pair "(:)...(;)" is used. In both cases the ellipsis indicates the words of the definition. .hl 4 Immediate definition of a STOIC word .p,0 The use of the ":...;" pair will be explained by means of an example. Suppose that the STOIC word "Name" is to be added to the current dictionary branch. The format used is: .s 1 .lt 'Name : ; {more code -- optional} ^ ^ ^ ^ ^ ^ | | | | | | |-1-| 2 |---- 3 ---| 4 .el .s 1 Where the numbers 1#-#4 refer to the steps indicated below. .s 1 .list 0 .le;The "Name" string has been stacked on TOP of the parameter stack prior to encountering the colon. .le;CHECK is tested for zero: if not, there is a syntax error. If zero: .list 0 .le;CHECK is incremented by 1 to indicate a definition in progress. .le;A "JSB" to the internal subroutine "int__colon" is entered into the Compile__buffer. .le;A space is made in the Compile__buffer for a "_.WORD". .le;The address of this empty _.WORD is stacked. The stack now looks like this: .lt STACK ----- A(Name string) A(".WORD") .el .s 1 .le;The Compile__buffer pointer is updated. .els .le;The user's is compiled (i.e. executable code is created and entered into the Compile__buffer following the empty "_.WORD"). .le;An "RSB" is entered into the Compile__buffer at the end of the code. The TOP of the stack is duplicated and the number of bytes in the (including the "RSB") is computed (this value is referred to below as "N"). That length (N) is entered at the reserved "_.WORD", whose address was placed on the stack earlier. The stack has undergone the transition shown below: .s 1 .lt STACK STACK ----- ----- A(Name string) ----> A(Name string) A(Pntr__1) ----> A(Pntr__2) ----> .el .s 1 The diagram below shows how the Compile__buffer looks and the relationship of the two pointers, "Pntr__1" (from step 1) and "Pntr__2" (from step 4). .s 1 .lt Pointer: Pntr_1 Pntr_2 | | Operator: |-------- : ---+-------| ... |-;-|| V v V V Vv Compile_buffer: <.WORD 0>{Compiled code}### | ^ ^ V |-------- N --------| <.WORD N> .el .s 1 .els When the Compile__buffer is executed (signalled by a not inside a ":...;" block) the is encountered, causing the following to happen: .list 0 .le;The subroutine "ENTER" ("I__ENTER") is executed which: .list 0 .dle '',LL,'.' .le;Puts the ASCIC "Name" into the dictionary at the locations following the linkage longword. (The linkage to the last defined STOIC name is established via "CURRENT", whose contents are placed in the first longword of the new dictionary entry, and the ^&address\& of that longword becomes the new "CURRENT".) .le;The DICT__PNTR is updated appropriately so as to point to the next free dictionary word. .els .le;Sets the attribute byte to "jump__to__me" (i.e., when the "Name" is invoked a "JSB " will be entered into the Compile__buffer). .le;Copies the definition to the dictionary space (includes the "RSB"). .le;Updates the dictionary pointers. .le;Continues execution at code in Compile__buffer following the "RSB" (i.e. at Pntr__2 in the diagram above). .els .X (:) .hl 4 Deferred definition of a STOIC word .s 1 .list 0 .le;"(:)" -- #(:) .br This operator allows execution of the colon operation at execution time. It is effected by decrementing "Check" by one and calling ":". This operator can appear only inside an enclosing ":...;" pair. The effect is to provide for dynamic definition of new STOIC words depending on the flow of control in a program. For example consider the following: .s 1 .lt 'DEF_1 : 'ONE (:) "Defined ONE" MSG CG (;) ; 'DEF_2 : 'TWO (:) "Defined TWO" MSG CR (;) ; 'Exampl : GTZ IF DEF_2 ELSE DEF_1 THEN ; The call would be -- Exampl .el If the parameter on TOP of the stack is greated than zero, the new STOIC word "TWO" would be compiled and entered into the dictionary; otherwise "ONE" would be defined. This manipulation permits the tailoring of a STOIC vocabulary depending on various switch/parameter settings established at the beginning of a file (the STOIC equivalent of a SYSGEN!). .X (_;) .le;"(;)" -- (;) .br This operator permits execution of the semicolon operation at execution time. It is effected by executing the ";" code and then by incrementing "CHECK" by 1. .els .X DEFINITIONS .hl 3 Copy TOP of vocabulary stack to CURRENT .lt Format: DEFINITIONS Branch: KERNEL Description: Copies the TOP of the vocabulary stack to "CURRENT" thereby making it the current vocabulary. Definition: MACRO code in kernel .el .X I__ENTER .hl 3 Enter new STOIC word into dictionary branch .lt Format: I_ENTER Branch: KERNEL Description: Enters the named string into the current dictionary branch. Sets up the name and link parameters of the dictionary. (Refer to dictionary format given above.) Definition: MACRO code in kernel .el .X IMMEDIATE .hl 3 Apply "IMMEDIATE" attribute to STOIC word .lt Format: IMMEDIATE Branch: STOIC< Description: Applies the immediate attribute to the newly defined, and compiled, STOIC vocabulary word. Definition: 'IMMEDIATE : 4 LOOKUP_ATTRIBUTE B! ; .end literal .X INCLUDE .hl 3 Append named branch to current one .lt Format: INCLUDE Branch: STOIC< Description: Link the named branch to the current one. Definition: 'INCLUDE : CURRENT @ @ % ->last entry in current branch OVER BEGIN @ DUP @ EQZ END ! % put into link word of bottom entry of new branch CURRENT @ ! % point current branch at new branch ; .el .X I__LOOKUP .hl 3 Lookup STOIC word (string) in dictionary .lt Format: I_LOOKUP Branch: KERNEL Description: Lookup searches through the various branches of the vocabulary stack for the string described by the descriptor on top of the parameter stack. If there is an entry corresponding to the string, then the address of the corresponding "definition" at TOP-1 and "success" (=1) on the TOP of the parameter stack. If the search fails, TOP-1 amd TOP-2 have the original descriptor, and the TOP of the parameter stack is set to "failure" (=0). This operation makes use of a dictionary entry called "MATCH" which has the following characteristics: .el .s 1 .list 0 .le;#MATCH p.le;R4-R5 contain a pattern descriptor (source string to be matched) .le;R0-R1 contain an entry-name descriptor (obtained via TOP of parameter stack) .le;On match: TOP-1 <- address of code; TOP <- "success" (=-1) .le;On match failure: TOP-1 <- TOP; TOP <- "failure" (=0) .els .lt Note that LOOKUP does not put the attribute byte on the parameter stack, nor does it execute any dispatching based on the attribute byte and the dispatch table. Definition: MACRO code in kernel .el .X LAST__WORD .hl 3 Get the address of the last STOIC word defined .lt Format: LAST_WORD Branch: STOIC< Description: Types out the address of the last STOIC word defined. Definition: 'LAST_WORD : CURRENT @ @ 4+ BMSG ; .el .X INVENTORY .hl 3 List contents of dictionary on terminal .lt Format: INVENTORY Branch: STOIC< Description: Lists address and name of all entries in the current dictionary branch on the user's terminal. Definition: 'INVENTORY : CURRENT @ @ BEGIN % address of next entry DUP = SPACE SPACE % address of entry DUP 4 + BMSG CR % name of entry @ % address of next entry or 0 if no more DUP EQZ END % loop if more DROP ; .el .X LOOKUP__ATTRIBUTE .hl 3 Find attribute of last dictionary entry .lt Format: LOOKUP_ATTRIBUTE Branch: KERNEL Description: The last defined dictionary entry is examined (via "CURRENT") and its attribute byte is pushed onto the parameter stack. Definition: MACRO code in kernel .EL .X STOIC< .hl 3 Push STOIC branch onto vocabulary stack .lt Format: STOIC< Branch: KERNEL Description: Pushes the pointer to the STOIC branch onto the vocabulary stack. Uses "STOIC" entry in User_table. Definition: MACRO code in kernel .el .X V__PUSH .hl 3 Push branch onto vocabulary stack .lt Format: V_PUSH Branch: KERNEL Description: Pushes the branch value onto the vocabulary stack (V_stack). Definition: MACRO code in kernel .el .X _> .hl 3 Pop top of vocabulary stack .lt Format: > Branch: KERNEL Description: Pops the top of the vocabulary stack. If popping the vocabulary stack would remove the last entry, thereby making the system inoperable, the operation is not honored. Definition: MACRO code in kernel .el .X WHAT .hl 3 search for dictionary word containing given address .lt Format:
WHAT Branch: STOIC< Description: Searches the vocabularies in the vocabulary stack for the first STOIC word whose address preceeds that on the TOP of the parameter stack. The name of that STOIC word and its address are typed out. The output format is: Definition: 'WHAT : CURRENT @ @ BEGIN DDUP GT IF % is this the one @ REPEAT % no, loop SWAP = DUP = DUP NEZ IF % was it there? SPACE 4+ BMSG THEN % yes, type name ; .el .X WHERE .hl 3 Types out address of STOIC word on TOP of stack .lt Format: WHERE Branch: STOIC< Description: The STOIC word pointed to by the TOP of the stack is sought via the vocabulary stack. If it is found, the address is typed out; otherwise an error is flagged. The name of the word must be used in "'Name" format. .el .tp 5 .lt Definition: 'WHERE : DUP MSG ASCII : TYO SPACE COUNT I_LOOKUP IF % does it exist? = ELSE % yes, type address "Undefined." MSG THEN ; .el .X STOIC >Words >Exceptions .hl 2 Exceptions .X CTRL__C__HANDLER .hl 3 _^C catcher .lt Format: CTRL_C_HANDLER Branch: KERNEL Description: Enable the control_C catcher (requires presence of "ENABLE_CTRL_C" subroutine in system or LINK parameter list). The catcher sets "ctrl_c_flag" to 1 and calls the condition handler at "ctrl_c_handler". Definition: MACRO code in kernel .el .hl 3 Exception condition handler .P,0 This is a subroutine (entered by CALLS/CALLG) to take care of error conditions. It performs the following operations: .s 1 .list 0 .le;Saves the user PC in "user__PC" .le;Saves the condition code in "cond__code" .le;Sets the restart address to "abort" .le;Clears the severity code portion of the condition code .le;Signals "resignal" (SS$__RESIGNAL) .le;Returns to caller .els .X COMPILE__ERROR .hl 3 compilation error handler .lt Format: COMPILE_ERROR Branch: KERNEL Description: The subroutine types the indicated error message, returns to console level, and aborts the current command. This is done by performing the following sub-operations: .el .s 1 .list 0 .le;Emits a carriage return ("CR") .le;Outputs the error message pointed to by the top of the parameter stack (via "MSG") .le;Outputs the place in error (error in compiling... ERROR ...in line) .le;Outputs a carriage return ("CR") .le;Outputs the entire line in which the error was found ("MSG" + "CR") .le;Returns to console input level (via "LOAD__RESET") .le;Jumps to "I__ABORT" to restart system .els .lt Definition: MACRO code in kernel .el .hl 3 Error message .x ERR .lt Format: ERR Branch: STOIC< Description: Types out an error message string and then performs an ERROR_TRACE. Definition: 'ERR : MSG CR ERROR_TRACE ; .EL .X ERRCHK .hl 3 Error checking .lt Format: ERRCHK Branch: KERNEL Description: Error checker NOT IMPLEMENTED. Definition: MACRO code in kernel (="RSB") .el .X ERROR__TRACE .hl 3 Symbolic traceback for debugging .lt Format: ERROR_TRACE Branch: STOIC< Description: An abort routine which gives a symbolic traceback. Definition: 'ERROR_TRACE : RESET_REGISTERS CR LINE_BUFFER @ MSG CR WORD_BUFFER @ MSG CR ERROR_PC @ WHAT CR % show where the error occured MOVL SP -(P) % get the return stack R_STACK_0 @ OVER - 4 / ( % loop to get all entries DUP I 4 * + @ WHAT CR ) % type them all DROP I_ABORT % do conventional abort ; .el .X I__ABORT .hl 3 Abort the current operation sequence .lt Format: I_ABORT Branch: KERNEL Description: Abort process. This operator resets the registers (via "RESET_REGISTERS", q.v.), reinitializes the return stack, and returns to the main loop ("top_loop"). Definition: MACRO code in kernel .el .X FATAL .hl 3 fatal return from system subroutine call .lt Format: FATAL Branch: KERNEL Description: Expects message on return stack (pointed to by SP), types message and does an abort ("I_ABORT") Definition: MACRO code in kernel .el .X SYSERR .hl 3 system subroutine error processor .lt Format: SYSERR Branch: KERNEL Description: This subroutine signals the condition code (via LIB$SIGNAL), and aborts if the code is even. Definition: MACRO code in kernel .el .X SYSMSG .hl 3 get message associated with system condition code .lt Format: SYSMSG Branch: STOIC< Description: From the condition code left on the parameter stack by a call to a system service, this operator recovers the ASCII string which describes the error encountered. Definition: 'SYSMSG : NOTE % save code on L stack BUF ^X100 MARK % result-string descriptor 0 % outadr not used ^X0F % flags (return full message) RECALL % points to result_string descriptor DUP % return count into same descriptor RECALL % condition code 5 $GETMSG 6 (DROP) % do it, leave result descriptor on stack ; .el .X STOIC >Words >Execution words .hl 2 Execution words .X DISPATCH .hl 3 Dispatch execution via byte value .lt Format: DISPATCH Branch: STOIC< Description: compares the byte on the TOP of the parameter stack with the byte following the 'dispatch' on the command line. If the two are equal, control is sent (via a "JSB") to the STOIC word following the comparand. If the two are unequal, control is passed to the next command line of definition. E.g. DISPATCH ^X09 C.TAB DISPATCH ^X0A C.LINE_FEED ... DISPATCH '] C.] DROP ERR.NOT_DEFINED ; Definition: 'DISPATCH : COMPILE_BYTE % compile byte to be tested INLINE< CMPB (P) (PC)+ >INLINE CPUSH % match? INLINE< BNEQ >INLINE 7 CPUSH % no, skip next word call INLINE< TSTL (P)+ >INLINE % drop I_COMPILE % yes, execute action word INLINE< RSB >INLINE % exit ; IMMEDIATE .el .X EXEC .hl 3 Execute STOIC word .lt Format:
EXEC Branch: STOIC< Description: Executes the STOIC word whose address is on TOP of the parameter stack. Definition: 'EXEC : JSB @(P)+ ; .el .X I__EXECUTE .hl 3 Execute the code in the compile__buffer .lt Format: I_EXECUTE Branch: KERNEL Description: Execute compile buffer. This operation is carried out by entering an "RSB" byte (=^X5) at the current compile buffer position, updating the compile buffer pointer by 1 byte, and then jumping to the compiled code at "comp_buf". Definition: MACRO code in kernel .el .X I__IMMEDIATE .hl 3 Execute the STOIC word at compile (definition) time .lt Format: I_IMMEDIATE Branch: KERNEL Description: Execute at compile time, after the definition of the STOIC word has been entered in the currently active dictionary branch, by performing a jump through the TOP of the parameter stack and popping the TOP of the stack. Definition: MACRO code in kernel .el .X I__JUMP__TO__ME .hl 3 Effect a jump to a STOIC word .lt Format: I_JUMP_TO_ME Branch: KERNEL Description: Generates code in compile buffer to effect a jump to the STOIC operator defined by the entry at the TOP of the parameter stack. This jump is of the "JSB" type with a word offset. The code created is: JSB W^(R8) where the locates the head of the code previously compiled into the dictionary. Remember that R8 is the dictionary pointer. The compile buffer pointer is updated. Definition: MACRO code in kernel .el .X STOIC >Words >Initialization .hl 2 Initialization / re-initialization .X USER__INIT .hl 3 Initialize system for user .lt Format: USER_INIT Branch: KERNEL Description: This subroutine puts the address of the message of welcome to the STOIC kernel on top of the parameter stack and invokes the "CR" and "MSG" operations. Definition: MACRO code in kernel .el .X DEF__INIT .hl 3 user initialization for first STOIC invocation .lt Format: DEF_INIT Branch: STOIC< Description: Protects stacks, initializes data areas and string variable, gets and checks command line for a qualifier name. If none is present, the standard STOIC entry is taken. If one is present, that STOIC word is executed immediately in place of the standard STOIC entry. This provides a means of getting into a special portion of the program. Definition: 'DEF_INIT : PROTECT_STACKS INITIALIZE_DATA_REGION ^X100 BUF 2- ! % initialize string variable GETCMD % get command line OVER B@ ASCII / EQ_IF % is there a program name? 1- SWAP 1+ SWAP ( % yes, extract it DUP I + B@ ^X20 EQ_IF EXIT THEN ) LAST_I % find trailing blank BUF .MOVE_STRING BUF COUNT 'NODEB COUNT (SUBSTRING) % NODEB is not a program! UNDER UNDER UNDER UNDER ELSE % drop descriptors 2DROP -1 THEN % there was no slash, so its STOIC IF % STOIC? CR "Welcome to STOIC" MSG CR ELSE % yes, welcome BUF COUNT I_LOOKUP IF % does word exist? EXEC ELSE % yes, execute it BUF MSG " undefined." MSG CR ABORT THEN THEN % no, error ; 'DEF_INIT COUNT I_LOOKUP IF % Assign if DEF_INIT defined USER_INIT ! THEN ; .el .X RESET__REGISTERS .hl 3 Reset registers .lt Format: RESET_REGISTERS Branch: KERNEL Description: This subroutine performs the following operations: .el .s 1 .list 0 .le;A(User__table)->R11 -- sets up user table .le;A(Cond__handler)->(FP) -- sets up condition handler .le;A(P__stack__0)->R10 -- initializes parameter stack pointer .le;A(L__stack__0)->R9 -- initializes loop stack pointer .le;A(Dictionary)->R8 -- initializes dictionary pointer .els .lt Definition: MACRO code in kernel .el .X STOIC >Words >I/O .hl 2 Input/Output operations Operators defined here deal with the I/O interface and file handling. The I/O routines themselves are found in the modules named: RMS and TYIO. .hl 3 Channels .X INCH .hl 4 Get current input channel number .lt Format: INCH Branch: KERNEL Description: Puts the current input channel on TOP of the parameter stack. The input channel number is obtained from "U_ifi". Starts with channel 1. Definition: MACRO code in kernel .el .X NEXTINCH .hl 4 Get next input channel number .lt Format: NEXTINCH Branch: KERNEL Description: Obtains the next input/output channel. Uses "U_ifi" to do so. The maximum number of different channels which may be open at one time is 4. This is a limitation set in the RMS module by the number of defined FAB/RAB entities. Definition: MACRO code in kernel .el .X LASTINCH .hl 4 Get last input channel number .lt Format: LASTINCH Branch: KERNEL Description: Backs up to the previous input channel. Uses "U_ifi" to get it. If decremented through the first channel, STOIC executes a normal exit ("RET") to VMS. Definition: MACRO code in kernel .el .X REMSTART .hl 4 start remote terminal listener .lt Format: REMSTART Branch: KERNEL Description: Starts remote terminal listener. Calls TYIO routine "_remstart" and kernel subroutine "SYSERR". Definition: MACRO code in TYIO and kernel .el .hl 3 Close files .X CLOSE .hl 4 Close file associated with channel number .lt Format: CLOSE Branch: KERNEL Description: Closes the specified channel. Definition: MACRO code in kernel and RMS .el .X _;F .hl 4 Close input file being read .lt Format: ;F Branch: STOIC< Description: Acquires the current channel number (INCH), closes it (CLOSE), backs up to the previous channel (LASTINCH), pops that channel number off the parameter stack and exits. Definition: ';F : INCH CLOSE LASTINCH DROP ; IMMEDIATE (Actually MACRO code in kernel) .el .X LOAD__RESET .hl 4 cancel all active LOAD's .lt Format: LOAD_RESET Branch: KERNEL Description: Causes cancellation of all active LOAD's and forces input from user's terminal. Definition: MACRO code in kernel .el .hl 3 Input operations .X GET .hl 4 Get an input line .lt Format: GET {|<0>} Branch: KERNEL Description: Gets a line of input from the file associated with "Channel" and places it in the buffer whose maximum length is "Max. length". If no EOF, then the stack contains the actual length of the input line in TOP-1 and a success code (=-1) in TOP. If an EOF is encountered, the TOP of the stack will be set to zero. The operator uses RMS subroutine ".get" and kernel routine "SYSERR". Definition: MACRO code in kernel and RMS .el .X .GET .hl 4 Get an input line with condition code .lt Format: .GET Branch: KERNEL Description: Like GET this operator inputs a line from the file associated with the channel number; however, it returns the I/O condition code in place of a code on the TOP of the parameter stack. Definition: MACRO code in kernel and RMS .el .X GET__STRING .hl 4 Get next input line as a named string .lt Format: GET_STRING Branch: KERNEL Description: The next line of input from the file associated with the channel number is read into the named string. The associated EOF_code is returned on the TOP of the parameter stack. Uses RMS routine ".get" and kernel routine "SYSERR". Definition: MACRO code in kernel and RMS .el .X LOAD .hl 4 Load a named file as input .lt Format: LOAD Branch: KERNEL Description: Increments the channel number by calling NEXTINCH, and then executes OPEN. Definition: MACRO code in kernel and RMS .el .X LOAD/L .hl 4 Load a named file as input and type its name .lt Format: LOAD/L Branch: STOIC< Description: The same as LOAD except that the name of the file is output to the user's terminal during loading. Definition: 'LOAD/L : "Loading " MSG DUP MSG LOAD CR ; .el .X RANDOGET .hl 4 get a record from a random access file .lt Format: RANDOGET Branch: KERNEL Description: Gets the specified record from the random access file associated with the channel number and transfers it to the buffer. The parameter stack contains the condition code associated with this I/O operation on TOP and the actual length of the record at TOP-1. Makes use of RMS routine "_randoget". Definition: MACRO code in kernel and RMS .el .X RDL .hl 4 get line from input file and associate with string .lt Format: RDL Branch: STOIC< Description: Reads next input record and moves it to the named string. The TOP of the parameter stack will be "true" if an EOF was not encountered and "false" if an EOF was seen. Definition: 'RDL : DUP 2 + % buffer address DUP 4 - W@ % max. string length INCH % channel # GET IF % EOF? W<- -1 ELSE % store returned length, restore not(EOF) 0 THEN % restore EOF ; .el .X READLINE .hl 4 read an input line into "Line__buffer" .lt Format: READLINE Branch: KERNEL Description: This operator gets a new line from the current input file, puts it into the string "line_buffer", fills "rest_of_line" with a descriptor to remaining bytes in "line_buffer", nulls the current word ("word_buffer"), and finally leaves the EOF code on the TOP of the parameter stack (-1 => not EOF, 0 => EOF). Definition: MACRO code in kernel and RMS .el .X TYI .hl 4 get a character from user's terminal .lt Format: TYI Branch: KERNEL Description: Gets a byte from the terminal and puts it on TOP of the parameter stack. Definition: MACRO code in kernel and RMS .el .hl 3 open files .X APPEND .hl 4 open output file in append mode .lt Format: APPEND Branch: KERNEL Description: The specified file is opened for writing, just as in OPEN, but in append mode. Makes use of PREOPEN before calling RMS subroutine "_append". Errors encountered in openingthe file are trapped internally. Definition: MACRO code in kernel and RMS .el .X .APPEND .hl 4 open output file in append mode with condition code .lt Format: .APPEND Branch: KERNEL Description: Performs the same operation as APPEND but the condition code is returned on TOP of the parameter stack. It is not checked. Definition: MACRO code in kernel and RMS .el .X OPEN .hl 4 open input file on given channel .lt Format: OPEN Branch: KERNEL Description: This operator performs a call to "Preopen" (q.v.) and then "_open" in the "RMS" module. Errors encountered opening the fill are trapped internally. Definition: MACRO code in kernel and RMS .el .X .OPEN .hl 4 open input file on a given channel and return condition code .lt Format: .OPEN Branch: KERNEL Description: Performs the same operation as OPEN but the condition code is returned on the TOP of the parameter stack without checking it. Definition: MACRO code in kernel and RMS .el .X PREOPEN .hl 4 pre-open process .lt Format: PREOPEN Branch: KERNEL Description: This operator generates a count value for the file name string and converts the file name descriptor address to the address of the first byte of the actual string. Definition: MACRO code in kernel. Equivalent to: 'PREOPEN : SWAP COUNT -ROT ; .el .X ROPEN .hl 4 open random-access file .lt Format: ROPEN Branch: KERNEL Description: The specified file is opened on the given channel for random access. Uses the PREOPEN operation before calling RMS subroutine "_ropen". Errors encountered in opening the file are trapped internally. Definition: MACRO code in kernel and RMS .el .X WOPEN .hl 4 open output file .lt Format: WOPEN Branch: KERNEL Description: Opens the given file (via its name) for writing and associates with it a channel number. Makes use of PREOPEN before calling the RMS subroutine "_wopen". Errors encountered in opening the file are trapped internally. Definition: MACRO code in kernel and RMS .el .X .WOPEN .hl open output file, returning condition code .lt Format: .WOPEN Branch: KERNEL Description: Performs the same operation as WOPEN but the condition code is returned on the TOP of the parameter stack. It is not checked. Definition: MACRO code in kernel and RMS .el .hl 3 Output operations .X BELL .hl 4 Ring bell on terminal .lt Format: BELL Branch: ASSEMBLER< Description: rings bell on user's terminal. Definition: 'BELL : 7 TYO ; .el .X BMSG .hl 4 Output string having byte-sized count .lt Format: BMSG Branch: ASSEMBLER< Description: Output a string, having a byte-sized count, to the user's terminal. Definition: 'BMSG : BCOUNT TYPE ; .el .X CR .hl 4 Output a carriage-return to terminal .lt Format: CR Branch: KERNEL Description: Outputs a carriage return to user's terminal. Definition: MACRO code in kernel. Equivalent to: 'CR : ^X0D TYO ; .el .X LIST .hl 4 List specified file on terminal .lt Format: LIST Branch: STOIC< Description: Lists the contents of the named file on the user's terminal. Definition: 'LIST : LOAD BEGIN BUF RDL IF BUF MSG CR REPEAT ;F % close input file ; .el .X MSG .hl 4 Output string to SYS$COMMAND .lt Format: MSG Branch: KERNEL Description: Performs COUNT followed by TYPE to output named string to user's terminal. Definition: MACRO code in kernel .el .X PUT .hl 4 Output buffer to file associated with channel .lt Format: PUT Branch: KERNEL Description: Outputs the specified buffer to the file associated with Channel. Makes use of RMS routine "__put" and kernel routine "syserr". Definition: MACRO code in kernel and RMS .el .X RANDOPUT .hl 4 Output buffer to random-access file .lt Format: RANDOPUT Branch: KERNEL Description: Outputs the contents of the specified buffer to the selected record of the random access file associated with the STOIC channel number. The condition code describing the results of the operation is placed on the TOP of the parameter stack. Definition: MACRO code in kernel and RMS .el .X REMTYPE .hl 4 Output string to remote terminal .lt Format: REMTYPE Branch: KERNEL Description: Outputs string to previously opened remote device. Uses TYIO subroutine "_remtype". Assumes that the remote device has been opened by REMSTART. Definition: MACRO code in kernel and RMS .el .X SPACE .hl 4 Output a space to terminal .lt Format: SPACE Branch: KERNEL Description: Outputs a space to user's terminal. Definition: MACRO code in kernel. Equivalent to: 'SPACE : ^X20 TYO ; .el .X TYO .hl 4 Output byte to terminal .lt Format: TYO Branch: KERNEL Description: Outputs byte on TOP of stack to user's terminal. Definition: MACRO code in kernel and TYIO .el .X TYPE .hl 4 Output string to SYS$COMMAND .lt Format: TYPE Branch: KERNEL Description: Outputs string to SYS$COMMAND. Definition: MACRO code in kernel and RMS .el .hl 3 Prompting text .X NEWPROMPT .hl 4 Reset prompting text .lt Format: NEWPROMPT Branch: KERNEL Description: Takes string whose descriptor address is on top of the parameter stack and puts it into the "prompt" entry of the user table. The RMS subroutine "_prompt" (in "RMS" module) enters this data into the FAB prompt string entry corresponding to the current input channel ("INCH" finds it). Definition: MACRO code in kernel and RMS .el .X CUR__IORB .hl 3 I/O request blocks (used with $QIO system service) The following operations deal with I/O request blocks. They are all found in the branch IORB<. CUR__IORB points to the current IORB being used and is defined as: .s 1 .lt 0 'CUR_IORB VARIABLE .el .s 1 The current IORB must be first initialized by means of INIT in the IORB< branch: .X INIT .s 1 .lt 'INIT : CUR_IORB @ DUP @ 1+ 1 DO DUP I 4 * + 0<- LOOP DROP ; .el .s 1 Space for the IORB in the data area of STOIC is created by invoking the STOIC word "IORB". The name of the IORB must be on TOP of the stack. The definition of IORB is: .X IORB .s 1 .lt 'IORB : ^X0C SWAP VARIABLE ^X0C 4 * .D+! ; .el .s 1 Once established, the IORB can be used by QIO. Note that the list of IORB entry point filling operators is in the order of occurrence of the parameters in the parameter-list given for $QIO. .X EFN! .X CHAN! .X FUNC! .X ISOB! .X ASTADR! .X ASTPRM! .X P1! .X P2! .X P3! .X P4! .X P5! .X P6! .s 1 .lt % CUR_IORB @ has the value ^X0C -- the argument count 'EFN! : CUR_IORB @ 04 + ! ; 'CHAN! : CUR_IORB @ 08 + ! ; 'FUNC! : CUR_IORB @ 0C + ! ; 'IOSB! : CUR_IORB @ 10 + ! ; 'ASTADR! : CUR_IORB @ 14 + ! ; 'ASTPRM! : CUR_IORB @ 18 + ! ; 'P1! : CUR_IORB @ 1C + ! ; 'P2! : CUR_IORB @ 20 + ! ; 'P3! : CUR_IORB @ 24 + ! ; 'P4! : CUR_IORB @ 28 + ! ; 'P5! : CUR_IORB @ 2C + ! ; 'P6! : CUR_IORB @ 30 + ! ; .el .s 1 The general format for loading the IORB is: .s 1 .lt XXXX! .el .s 1 where XXXX corresponds to one of the operators above. For example to set up and IORB and to set up channel 3 in it, one would use: .s 1 .lt 'EXAMPLE_IORB IORB % Define IORB called EXAMPLE_IORB EXAMPLE_IORB CUR_IORB ! % Set CUR_IORB INIT % Clear EXAMPLE_IORB 3 CHAN! % Assign 3 to channel slot in EXAMPLE_IORB .el .X STOIC >Words >Iteration words .hl 2 Iteration operators .hl 3 Iterations dependent upon truth values .p,0 The BEGIN...END construction permits the user to execute the sequence of STOIC words found between the delimiters, and then (depending on the state of the computed ^&logical\& variable) to either continue on ("true" = odd) or to return to the beginning ("false" = even) for another iteration. The general format is .lt BEGIN Word_1 Word_2 ... Word_n END Word_n+1 ... .el The sequence "Word__1#Word__2#...#Word__n" is executed once. The result on the TOP of the stack, after execution of "Word__n", is tested for "true" (odd) or "false" (even). If "false", control is sent back to the BEGIN; otherwise, control is sent to "Word__n+1". For example: .lt 'EXZAMPLE : BEGIN 1- DUP DUP = EQZ END DROP ; 0> 5 EXZAMPLE ---> 4 3 2 1 0 .el .P,1 The second form of the "logically" controlled iteration is BEGIN...IF... REPEAT. It is similar to BEGIN...END except that the test is made in the middle of the loop (at the IF) rather than at the END. The STOIC words between the BEGIN and the IF are executed. If the TOP of the parameter stack is "true" (=odd) the STOIC words between IF and REPEAT are executed and control passes back to the BEGIN. If the TOP of the stack is "false" (=even) then control passes to the STOIC word following the REPEAT. For example: .lt BEGIN EOF NOT IF READ_RECORD REPEAT .el .S 1 will read records until an end-of-file is encountered. This sequence handles zero-length files correctly. .x BEGIN .hl 4 BEGIN .lt Format: BEGIN Branch: STOIC< Description: Marks the beginning of a BEGIN...END repeat pair. Definition: 'BEGIN : +CHECK CMARK ; IMMEDIATE .end literal .x END .hl 4 END .lt Format: END Branch: STOIC< Description: Causes the truth of the preceeding comparison to be tested. If true, the code following the "end" is executed; otherwise control is returned to the "begin". Definition: 'END : -CHECK INLINE< BLBC (P)+ >INLINE TARGET SWAP ARCHER ; IMMEDIATE .end literal .X REPEAT .hl 4 REPEAT .lt Format: REPEAT Branch: STOIC< Description: Forms the terminus for a BEGIN...IF...REPEAT sequence. Definition: 'REPEAT : % (at compile time, top is IF target, top-1 is BEGIN target) -CHECK -CHECK SWAP % (BEGIN target on top) INLINE< BRB >INLINE TARGET SWAP ARCHER % from here to BEGIN CMARK ARCHER % from IF to after REPEAT ; IMMEDIATE .end literal .hl 3 Iteration controlled by a count .P,0 In this case a sequence of words may be executed under the control of a simple counter. The format is .lt N ( Word_1 Word_2 ... Word_n ) .el The sequence of STOIC words, Word__1#...#Word__n, is repeated N times, where N is the number on the TOP of the parameter stack. If N is zero or negative the sequence is passed over. For example: .lt 'BELLS : ( BELL ) ; .el will cause a number of bells to be rung if invoked thus: .lt 8 BELLS "calls out the watch from below". .el .X ( .hl 4 Left parenthesis for iteration bracketing .lt Format: ( Branch: STOIC< Description: begins the simple iteration. Definition: '( : +CHECK INLINE< CLRL -(L) MOVL (P)+ -(L) CLRL -(L) >INLINE CMARK ; IMMEDIATE .el .X ) .hl 4 Right parenthesis for iteration bracketing .lt Format: ) Branch: STOIC< Description: closes the iteration group Definition: ') : -CHECK INLINE< AOBLSS (L) B^ 4 (L) >INLINE TARGET SWAP ARCHER INLINE< ADDL2 S^ ^X0C L >INLINE ; IMMEDIATE .el .hl 3 DO-loops .P,0 Two forms of the DO-loop are defined in the STOIC< branch of the dictionary: .lt High Low DO Word_1 Word_2 ... Word_n LOOP High Low DO Word_1 Word_2 ... Word_n INCR +LOOP .el .s 1 High and Low are the iteration limits. An implied loop index (accessible within the loop as I) is used to control the iteration. The order of operation is: .s 1 .list 0 .le;High and Low are compared. .br High _^> Low : control passes to word following LOOP .br High > Low : words 1 through n are executed .le;On reaching "LOOP" Low is incremented by 1 and compared with High .br Low _^< High : loop is terminated .br Low < High : control is returned to Word_1 .els +LOOP is similar to LOOP except that Low is incremented by the value on the TOP of the stack (represented by "INCR" in the format above) and then the comparison is made. .P,1 DO loops may be nested to depth 3. The loop index of the innermost loop is called "I". The next outermost indices are known as "J" and "K", respectively. The special value I' (and J', K') is defined as: .s 1 .lt I' = High + Low - I - 1 .el .s 1 and is used to the index ^&backward\& from High#-#1 to Low. When parentheses (see below) are nested within a DO loop, they count as one level of nesting. "I" used within the range of a parenthesized iteration will return the current value of its iteration count (which runs from its initial value downwards to one), inclusive. .P,1 The STOIC word EXIT causes the innermost loop in which it is embedded to unconditionally terminate on the next cycle, whether in a do loop or a parenthesis iteration. Note that EXIT can be encountered as an alternative in an IF....ELSE....END setting. .P,1 The STOIC word LAST__I will cause the value of the iteration index to be pushed on TOP of the stack. If termination was caused by EXIT then the value of the index at that time is used. If normal termination through LOOP, then High will be entered. .s 1 Some examples: .s 1 .lt 5 0 DO I = LOOP ---> 0 1 2 3 4 4 0 DO 4 0 DO J 4 * I + = LOOP CR LOOP ---> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 5 0 DO I' = LOOP ---> 4 3 2 1 0 11 1 DO I + DUP = +LOOP DROP ---> 1 4 9 16 25 36 49 64 81 100 .el .X DO .hl 4 DO .lt Format: DO Branch: STOIC< Description: Initializes loop stack with limiting values. Definition: 'DO : +CHECK INLINE< MOVL (P) -(L) % push low limit onto Lstack MOVQ (P)+ -(L) % push high & counter onto Lstack >INLINE CMARK % provide target for LOOP ; IMMEDIATE .el .X LOOP .hl 4 LOOP .lt Format: LOOP Branch: STOIC< Description: terminus of a DO-loop Definition: 'LOOP : {LOOP} ; IMMEDIATE .el .X +LOOP .hl 4 +LOOP .lt Format: +LOOP Branch: STOIC< Description: adds value to loop index and loops if index < High. Definition: '+LOOP : INLINE< SUBL2 S^ 1 (P) ADDL2 (P)+ (L) >INLINE % add (incr. - 1) to index {LOOP} ; IMMEDIATE .el .X {LOOP} .hl 4 Deferred version of DO-loop terminus .lt Format: {LOOP} Branch: STOIC< Description: Deferred version of the DO-loop terminus. Definition: '{LOOP} : -CHECK INLINE< AOBLSS (L) B^ 4 (L) % increment I, compare to high limit >INLINE TARGET SWAP ARCHER % jump to DO if high INLINE< ADDL2 S^ ^X0C L % blow off loop parameters >INLINE ; .el .X EXIT .hl 4 EXIT .lt Format: EXIT Branch: STOIC< Description: causes a loop to terminate the next time the LOOP word is executed. This is effected by setting High to I. Definition: 'EXIT : RECALL % I RECALL DROP % drop HIGH_LIMIT DUP NOTE NOTE % push I as HIGH_LIMIT & as I ; .el .hl 3 Special values associated with DO-loops .X I .hl 4 I .lt Format: I Branch: STOIC< Description: Index of innermost DO Definition: 'I : MOVL (L) -(P) ; .el .X J .X K .hl 4 J, K .lt Format: {J|K} Branch: STOIC< Description: values of counters of next innermost loops. Definition: 'J : MOVL (L) B^ ^X0C -(P) ; 'K : MOVL (L) B^ ^X18 -(P) ; .el .X I' .hl 4 I' .lt Format: I' Branch: STOIC< Description: reverse index of innermost DO Definition: 'I' : ADDL3 (L) B^ 4 (L) B^ 8 -(P) % high + low SUBL2 (L) (P) % high+low-index DECL (P) % high+low-index-1 ; .el .X LAST__I .hl 4 LAST__I .lt Format: LAST_I Branch: STOIC< Description: Last value for I in previous loop. Note -- not guaranteed unless invoked right after LOOP! Definition: 'LAST_I : MOVL (L) B^ -8 -(P) ; .el .X STOIC >Words >Redefinitions .hl 2 Redefinitions (for efficiency) The definitions listed below are included because they appear in the DEF file in order to improve the efficiency of certain operations. .s 1 .lt 'DUP : INLINE< MOVL (P) -(P) >INLINE ; IMMEDIATE 'DDUP : INLINE< MOVQ (P) -(P) >INLINE ; IMMEDIATE 'OVER : INLINE< MOVL B^(P) 4 -(P) >INLINE ; IMMEDIATE 'DROP : INLINE< ADDL2 S^ 4 P >INLINE ; IMMEDIATE '2DROP : INLINE< ADDL2 S^ 8 P >INLINE ; IMMEDIATE '+ : INLINE< ADDL2 (P)+ (P) >INLINE ; IMMEDIATE '- : INLINE< SUBL2 (P)+ (P) >INLINE ; IMMEDIATE '1+ : INLINE< INCL (P) >INLINE ; IMMEDIATE '1- : INLINE< DECL (P) >INLINE ; IMMEDIATE '1 : INLINE< MOVL S^ 1 -(P) >INLINE ; IMMEDIATE '2 : INLINE< MOVL S^ 2 -(P) >INLINE ; IMMEDIATE '-1 : INLINE< MNEGL S^ 1 -(P) >INLINE ; IMMEDIATE '@ : INLINE< MOVL @(P)+ -(P) >INLINE ; IMMEDIATE 'D@ : INLINE< MOVQ @(P)+ -(P) >INLINE ; IMMEDIATE 'W@ : INLINE< MOVZWL @(P)+ -(P) >INLINE ; IMMEDIATE 'B@ : INLINE< MOVZBL @(P)+ -(P) >INLINE ; IMMEDIATE 'I : INLINE< MOVL (L) -(P) >INLINE ; IMMEDIATE .el .x STOIC >Words >Stack manipulation .hl 2 Stack manipulation .hl 3 User stack definitions and operations .X Uset stack structure .p,0 User-defined stacks are byte-oriented and are manipulated by means of "BPUSH" and "BPOP". A user-defined stack has the following structure: .lt Name: .LONG Name+12 ;Lower limit .LONG Name+12+N ;Pointer to top of stack .LONG Name+12+N ;High limit .BLKB N ;Stack .el .X STACK .hl 4 Define user stack area .lt Format: STACK Branch: STOIC< Description: Creates a stack for user in the data area consisting of the number of bytes represented by the integer on TOP-1 of the parameter stack and having the name specified by the string whose address is on TOP of the stack. Definition: 'STACK : .D@ SWAP CONSTANT % Make pointer to stack .D@ C + % low limit DUP ,D OVER + DUP % high limit ,D ,D .D+! ; .el .X BPUSH .hl 4 push a byte onto a user stack .lt Format: BPUSH Branch: STOIC< Description: pushes the byte at TOP-1 onto the user stack whose address is on TOP of the parameter stack. Definition: 'BPUSH : DUP 4 + @ % pointer OVER @ % low limit GT IF % overflow? CR = "Stack overflow." MSG ABORT ELSE % yes 4 + DUP 1-<- % decrement pointer @ B! THEN % store byte ; .el .hl 4 pop a byte off of user stack .x BPOP .lt Format: BPOP Branch: STOIC< Description: Pops the byte on top of the user-defined stack onto the TOP of the the parameter stack. If the user-defined stack is empty, an error message is sent to the user's terminal and the current STOIC command is aborted (via "I_ABORT"). Definition: 'BPOP : % stack, BPOP, byte (pops byte from stack) 4+ DUP DUP 4+ @ SWAP @ % pointer:high preparation EQ_IF "User stack empty" MSG DROP I_ABORT ELSE DUP @ B@ SWAP 1+! THEN ; .el .hl 3 Loop stack manipulations .X MARK .hl 4 mark the current position in the parameter stack .lt Format: MARK Branch: STOIC< Description: Pushes the parameter stack pointer (pointing to the TOP of the stack) onto the L-stack (LOOP-stack). Definition: 'MARK : MOVL P -(L) ; .el .X RESTORE .hl 4 restore the parameter stack pointer .lt Format: RESTORE Branch: STOIC< Description: Pops L-stack value into the P-stack pointer. (Inverse of "MARK".) Definition: 'RESTORE : MOVL (L)+ P ; .el .X NOTE .hl 4 Push TOP of parameter stack onto L-stack .lt Format: NOTE Branch: STOIC< Description: Pushes the value at the TOP of the parameter stack on top of the L-stack. Definition: 'NOTE : MOVL (P)+ -(L) ; .el .X RECALL .hl 4 recall "NOTED" value to TOP of parameter stack .lt Format: RECALL Branch: STOIC< Description; Pops the value on top of the L-stack and pushes it onto the TOP of the parameter stack. (Inverse of "NOTE".) Definition: 'RECALL : MOVL (L)+ -(P) ; .el .X L__STACK .hl 4 get pointer to L__stack .lt Format: L_stack
Branch: KERNEL Description: Pushes the address of the loop stack onto the parameter stack. Definition: MACRO code in kernel .el .hl 3 Parameter stack .X MOAT .hl 4 get address of the "moat" before parameter stack .lt Format: MOAT Branch: KERNEL Description: Returns the address of the parameter stack moat. Note that the moat is a protective device to eliminate inadvertent stack destruction. The moad is enabled by deleting the buffer page from the user's virtual address space. Definition: MACRO code in kernel .el .X P__STACK .hl 4 get address of top of parameter stack .lt Format: P_STACK
Branch: KERNEL Description: Returns the address of the parameter stack (which is the same as the moat between the P_stack and the loop stack). Definition: MACRO code in KERNEL .el .hl 3 Vocabulary stack .X BRANCH .hl 4 put dictionary branch name on vocabulary stack .lt Format: BRANCH Branch: KERNEL Description: Creates a new vocabulary branch. This is accomplished by entering the name of the branch into the dictionary, appending a "push_vocab" attribute byte to the dictionary definition and then appending the address of the branch header from the (now) TOP of the parameter stack. Definition: MACRO code in kernel and a subsequent redefinition in the DEF file: 'BRANCH : .D@ SWAP 0 ,D BRANCH ; .el .X I__PUSH__VOCAB .hl 4 push vocabulary pointer onto vocabulary stack .lt Format: I_PUSH_VOCAB Branch: KERNEL Description: After a name, purported to be a dictionary branch, has been looked up in the dictionary, the word following the ASCII name string and attribute byte is pushed onto the the TOP of the parameter stack. The operator then pushes the word on the TOP of the parameter stack onto the TOP of the vocabulary stack. Definition: MACRO code in kernel .el .X V__PUSH .hl 4 push branch onto vocabulary stack .lt Format: V_PUSH Branch: KERNEL Description: Pushes the TOP of the parameter stack onto the TOP of the vocabulary stack and saves the vocabulary stack pointer in "vocab_sp". Definition: MACRO code in kernel .el .X _> .hl 4 pop TOP entry off vocabulary stack .lt Format: > Branch: KERNEL Description: Removes the TOP entry from the vocabulary stack. If popping the vocabulary stack would cause removal of the last entry, thereby making the system inoperable, the operation is not honored. Definition: MACRO code in kernel .el .X DEFINITIONS .hl 4 Make TOP of vocabulary stack the current vocabulary .lt Format: DEFINITIONS Branch: KERNEL Description: Make the current TOP of the vocabulary stack the active ("CURRENT") vocabulary. Definition: MACRO code in kernel .el .X ASSEMBLER< .hl 4 Invoke the ASSEMBLER< branch .lt Format: ASSEMBLER< Branch: KERNEL Description: Puts the pointer to the assembler branch of the dictionary on TOP of the vocabulary stack. Note: this does NOT make it the active vocabulary (DEFINITIONS must be invoked!). Definition: MACRO code in kernel .el .X STOIC< .hl 4 Invoke the STOIC< branch .lt Format: STOIC< Branch: KERNEL Description: Puts the pointer to the STOIC branch of the dictionary on TOP of the vocabulary stack. Note: this does NOT make it the active vocabulary (DEFINITIONS must be invoked!). Definition: MACRO code in kernel .el .X B__KERNEL .hl 4 Address of the base kernel vocabulary .lt Format: B_KERNEL
Branch: KERNEL Description: Address of a longword pointing to the head of the kernel branch. Definition: MACRO code in kernel .el .X V__STACK .hl 4 get pointer to vocabulary stack .lt Format: V_STACK
Branch: KERNEL Description: Pushes the address of the vocabulary stack onto the TOP of the parameter stack. Definition: MACRO code in kernel .el .X VOCAB__SP .hl 4 get current vocabulary stack pointer .lt Format: VOCAB_SP Branch: KERNEL Description: Places the address of the TOP of the vocabulary stack onto the TOP of the parameter stack Definition: MACRO code in kernel .el .X OCONSTACK .hl 4 get address of output conversion stack .lt Format: OCONSTACK
Branch: KERNEL Description: Puts the address of the TOP of the output conversion stack onto the parameter stack. OCONSTACK is a "user stack". I could have been defined as: ^D40 'OCONSTACK STACK . Definition: MACRO code in KERNEL .el .hl 3 In-stack operations The operations included here are all found in the STOIC< branch of the dictionary. They are simply listed with minimal descriptions in order to conserve space. .list 1 .X DROP .le;DROP -- #DROP .br Discard TOP of parameter stack .literal 'DROP : TSTL (P)+ ; .end literal .X DUP .le;DUP -- #DUP## .br Duplicate the top of the stack .literal 'DUP : MOVL (P) -(P) ; .end literal .X 2DROP .le;2DROP -- #2DROP .br Drops the parameter stack entries at TOP-1 and TOP. .literal '2DROP : ADDL2 S^ ^X8 P ; .end literal .X DDUP .le;DDUP#--##DDUP# .br Duplicates the TOP-1 and TOP entries on the parameter stack .literal 'DDUP : MOVQ (P) -(P) ; .end literal .X SWAP .le;SWAP -- #SWAP# .br Swaps TOP-1 and TOP entries in the parameter stack. .literal 'SWAP : MOVQ (P)+ R0 MOVL R0 -(P) MOVL R1 -(P) ; .end literal .X (SWAP) .le;(SWAP) -- #(SWAP)# .br This is an IMMEDIATE version of SWAP. .literal '(SWAP) : MOVQ (P)+ R0 MOVL R0 -(P) MOVL R1 -(P) ; IMMEDIATE .end literal .X OVER .le;OVER -- #OVER .br This operator takes the value entered in the parameter stack at TOP-1 and pushes it onto the TOP of the stack. .literal 'OVER : MOVL B^(P) 4 -(P) ; .end literal .X +ROT .le;+ROT -- #+ROT# .br This operator rotates the top three entries of the parameter stack so that the TOP entry becomes the TOP-2 entry, TOP-1 becomes TOP and TOP-2 becomes TOP-1. .literal '+ROT : MOVL (P) R0 % r0 is temporary stack pointer MOVQ B^(P) 4 (P) % move up arg1 & arg2 MOVL R0 B^(P) 8 % put arg3 underneath ; .end literal .X -ROT .le;-ROT -- #-ROT# .br A downward rotation is performed by this operator. It inverse to the +rot operator described above. .literal '-ROT : MOVL B^(P) 8 R0 % set arg1 aside MOVQ (P) B^(P) 4 % move arg2 & arg3 down MOVL R0 (P) % put arg1 on top ; .end literal .X (DROP) .le;(DROP) -- #(DROP) .br The number of items specified by the count argument on TOP of the parameter stack are dropped. .literal '(DROP) : MOVL (P)+ R0 % drop count MOVAL [R0] (P) P % drop (r0) items ; .end literal .X UNDER .le;UNDER -- #UNDER# .br The value at TOP-1 of the parameter stack is dropped. .literal 'UNDER : SWAP DROP ; .end literal .X FLIP .le;FLIP -- #FLIP# .br In this case TOP and TOP-2 of the parameter stack are swapped. .literal 'FLIP : MOVL (P) R0 MOVL (P) B^ 8 (P) MOVL R0 (P) B^ 8 ; .end literal .X UNDROP .le;UNDROP -- UNDROP# .br This operator restores the previous TOP of the stack after it has been dropped by DROP, EQ__IF, EQZ__IF, or an associated ELSE. .literal 'UNDROP : SUBL2 S^ 4 P ; .end literal .X 2UNDROP .le;2UNDROP -- 2UNDROP# .br Restores the previous two values to the stack. .literal '2UNDROP : SUBL2 S^ 8 P ; .end literal .els .X PROTECT__STACKS .hl 3 protect the STOIC stacks .lt Format: PROTECT_STACKS Branch: STOIC< Description: Dig moats behind stacks to prevent user from destroying the various stacks inadvertently. By deleting the buffer page between the stacks from the user's virtual address space (DELTVA), stack overflow or underflow will be trapped by the VAX/VMS operating system as an access violation. Definition: 'PROTECT_STACKS : MOAT DUP DELTVA % dig moat behind parameter stack P_STACK DUP DELTVA % between p-stack and loop stack L_STACK DUP DELTVA % between l-stack and vocabulary stack V_STACK DUP DELTVA % in front of v-stack ; .el .X STOIC >Words >Storing and fetching .hl 2 Storing and fetching operations Operations in this group are also found in the STOIC< branch of the dictionary. They are listed to conserve space. .list 1 .X B! .le;B_! (in STOIC branch) --
#_!B .br Stores the byte at TOP-1 at the address specified by TOP of parameter stack. .literal 'B! : MOVL (P)+ R0 CVTLB (P)+ (R0) ; .end literal .le;B_! (in ASSEMBLER branch) -- #B_! .br Moves the value at TOP-1 to the byte whose address is specified by TOP. .literal 'B! : MOVL (P)+ R0 CVTLB (P)+ (R0) ; .end literal .X _@ .le;_@ --
#_@# .br Performs an indirect addressing operation on the TOP of the stack, replacing the address with the contents of that address. .literal '@ : MOVL @(P)+ -(P) ; .end literal .X _@_@ .le;_@_@ -- #_@_@# .br This is a "double indirect" command. It is entirely equivalent to .literal @ @ ... .end literal but should be faster by elimination of subroutine linkage overhead. .literal '@@ : MOVL @(P)+ R0 MOVL (R0) -(P) ; .end literal .X B_@ .le;B_@ --
#B_@# .br This is the same as "_@" except that a byte rather than a longword is the form of the value placed on TOP of the stack. .literal 'B@ : MOVZBL @(P)+ -(P) ; .end literal .X W_@ .le;W_@ --
#W_@# .br This is the same as "_@" except that a ^&word\& (not a longword) is the form of the value placed on TOP of the stack. .literal 'W@ : MOVZWL @(P)+ -(P) ; .end literal .X _! .le;_! --
#_! .br Stores the specified value at the address on TOP of the stack. Both items are dropped (but may be recovered by means of "2UNDROP"). .literal '! : MOVL (P)+ R0 MOVL (P)+ (R0) ; .end literal .X <- .le;<- --
#<- .br Stores the (literal) quantity on TOP at the address specified by TOP-1. The top two entries of the stack are popped (but may be recovered by "2UNDROP"). .literal '<- : MOVL (P)+ @(P)+ ; .end literal Note that this operation is equivalent to .literal
SWAP ! .end literal but should save dictionary overhead time. .X B<- .le;B<- --
#B<- .br Stores byte at TOP in location specified by address in TOP-1. Both TOP and TOP-1 are popped (but may be recovered by "2UNDROP"). .literal 'B<- : CVTLB (P)+ @(P)+ ; .end literal .X W<- .le;W<- --
#W<- .br Stores the word (not longword) at TOP in the location specified by the address in TOP-1. Both TOP and TOP-1 are popped but may be recovered by "2UNDROP". .literal 'W<- : CVTLW (P)+ @(P)+ ; .end literal .X EXCHANGE .le;Exchange -- #EXCHANGE .BR Exchange the contents of the memory locations pointed to by the two addresses in the parameter stack. .literal 'EXCHANGE : MOVQ (P)+ R0 % pick up addresses MOVL (R0) R2 % save first value MOVL (R1) (R0) % transfer 2nd value MOVL R2 (R1) % store second value ; .end literal .X MOVE .le;Move -- #MOVE .br Move contents of origin to destination. .literal 'MOVE : MOVL (P)+ R0 % r0-> destination MOVL @(P)+ (R0) % do it ; .end literal .X D_@ .le;D_@ -- #D_@# .br Move the value of the quadword pointed to by the Top of the parameter stack to the TOP of the stack. .literal 'D@ : MOVQ @(P)+ -(P) ; .end literal .X D_! .le;D_! -- #D_! .br Stores the quadword value on TOP (and TOP-1) of the stack at the location specified by TOP-2. .literal 'D! : MOVL (P)+ R0 MOVQ (P)+ (R0) ; .end literal .X D<- .le;D<- --
#D<- .br Stores quadword at specified address. .literal 'D<- : MOVQ (P)+ @(P)+ ; .end literal .X W_! .le;W_! --
#W_! .br Stores low-order 16 bits of Value at Address. .literal 'W! : MOVL (P)+ R0 CVTLW (P)+ (R0) ; .end literal .X 0<- .le;0<- --
#0<- .br Stores zero longword at Address. .literal '0<- : CLRL @(P)+ ; .end literal .X 0W<- .le;0W<- --
#0W<- .br Stores zero word at Address. .literal '0W<- : CLRW @(P)+ ; .end literal .X -1<- .le;-1<- --
#-1<- .br Stores -1 longword at Address. .literal '-1<- : MNEGL S^ 1 @(P)+ ; .end literal .X 1<- .le;1<- --
#1<- .br Stores longword 1 at Address. .literal '1<- : MOVL S^ 1 @(P)+ ; .end literal .X ARCHER .le;ARCHER -- #ARCHER .BR Stores displacement between pointers as a byte at "TARGET". .literal 'ARCHER : OVER - 1- B<- % store the byte BVC (TARGET) % displacement overflow? "Byte-displacement overflow." I_COMPILE_ERROR (CMARK) (ARCHER) % yes ; .end literal .X (ARCHER) .le;(ARCHER) -- #(ARCHER) .br Immediate from of ARCHER. .literal '(ARCHER) : OVER - 1- B<- ; IMMEDIATE .end literal .X TARGET .le;TARGET -- TARGET .br Compiles a zero byte and pushes its pointer on TOP of the stack. Used with ARCHER. .lt 'TARGET : CMARK 0 CPUSH ; .end literal .X (TARGET) .le;(TARGET) -- (TARGET) .br Immediate version of TARGET. Used with ARCHER. .lt '(TARGET) : CMARK 0 CPUSH ; IMMEDIATE .end literal .X .D_@ .le;_.D_@#--#_.D_@# .br Gets the next free location in the (unassigned) data region. Recall that the data region is not the same as the dictionary region. .lt '.D@ : .D @ ; .el .X MEMORY .le;MEMORY#--#MEMORY# .br Puts the address of the "top" of useable memory in user data area on the stack. .lt 'MEMORY : .M @ ; .el .X .D+! .le;_.D+!#--##_.D+! .br This operator reserves bytes at the end of the data region. Used for definition of arrays and strings. .lt '.D+! : .D @ + DUP .D ! % advance pointer MEMORY - % if positive, amount of room needed DUP GTZ IF 1- 200 / 1+ EXPREG % expand region FREP0VA GETJPI .M ! ELSE % record new bound DROP THEN % don't need to expand region ; .el .X INITIALIZE__DATA__REGION .le; INTIALIZE__DATA__REGION#--#INITIALIZE__DATA__REGION .BR This operation initializes the data region for future use. It must be executed before arrays or strings may be assigned. .lt 'INITIALIZE_DATA_REGION : .D@ % one beyond data region expected FREP0VA GETJPI % one beyond actual data region DUP .D ! DUP .M ! % conform to reality temporarily - .D+! % make reality conform to expectations ; .el .X ,D .le;_,D -- #_,D .br Stores the TOP of the stack in the user data area. .lt ',D : .D @ % where to put it 4 .D+! % advance data-region pointer ! % store datum ; .el .X B,D .le;B,D#--##B,D .br Stores a byte in the user data area. .lt 'B,D : .D @ 1 .D+! B! ; .el .els .X STOIC >Words >String manipulation .hl 2 String manipulation (including "WORD") .p,0 .x String descriptor A string descriptor, when used as an argument on the stack, takes the form: .s 1 .lt TOP --> Count TOP-1 --> First Byte Address (FBA) .el The format .s 1 .lt .el implies this stack structure: .s 1 .lt TOP --> LENGTH(Destination string) TOP-1 --> FBA(Destination string) TOP-2 --> LENGTH(Source string) TOP-3 --> FBA(Source string) .el .x COUNT .hl 3 Get the count of the bytes in a string .lt Format: COUNT Branch: KERNEL Description: Alters the stack to split up the components of the STOIC string into a length and an address. Essentially the operator makes an in-stack descriptor for the string. Definition: MACRO code in kernel, equivalent to: 'COUNT : W@ SWAP 2+ SWAP ; .el .X WORD .hl 3 Get next STOIC word in input buffer .lt Format: WORD {|} Branch: KERNEL Description: This operator examines the next word in the "line_buffer" (uses the "rest_of_line" descriptor). The resulting word, as a STOIC string will be placed in "word_buffer" and descriptor to "word_buffer" will be put onto the parameter stack. If the next object on the input line is not a STOIC word (i.e. a literal) then a "failure" signal is placed on TOP of the stack. In case of a failure, the "rest_of_line" descriptor is restored to its original state, ready to be used in an attempt to compile a literal. Definition: MACRO code in kernel .el .X () .hl 3 Get dictionary address of next word of input .lt Format: ()
Branch: STOIC< Description: Places the address of the definition of the next STOIC word of input line on TOP of parameter stack. Definition: '() : WORD DROP I_LOOKUP DROP ; IMMEDIATE .end literal .X MOVE__BYTES .hl 3 Move source string to destination string .lt Format: MOVE_BYTES Branch: STOIC< Description: Moves source string to destination string. If the length of the source string exceeds the maximum number of bytes allowed by the system, only the maximum number is moved. NB: if the destination string is too small to hold the source string, copying proceeds and other values in the user data area will be destroyed. Definiton: 'MOVE_BYTES : SWAP ^X0FFFF % max. count GE_IF % is max count exceded? % short case MOVQ B^(P) -8 R0 MOVQ (P)+ R2 % no, collect arguments MOVC3 R1 (R3) (R2) ELSE % do it simply % long case MOVQ B^(P) -8 R0 % max. count to R0, full count to R1 CLRL R2 % prepare to divide EDIV R0 R1 -(L) R0 % # groups onto L-stack, initial count to R0 GE_IF % forward or backward move? % long forward case ADDL2 R1 -(P) % get end of destination ADDL2 R1 -(P) % get end of origin (CMARK) % loop MOVQ (P) R1 SUBL2 R0 R1 SUBL2 R0 R2 % next origin and destination MOVQ R1 (P) MOVC3 R0 (R2) (R1) % move group MOVL B^(P) -8 R0 % max. count SOBGEQ (L) (TARGET) (SWAP) (ARCHER) ELSE % all groups done? % long backward case MOVL -(P) R1 MOVL -(P) R3 % initial origin & destination (CMARK) % loop on number of groups +1 MOVC3 R0 (R1) (R3) % move a group MOVL B^(P) -8 R0 % max. count SOBGEQ (L) (TARGET) (SWAP) (ARCHER) THEN % through? ADDL2 S^ 4 L % clean loop stack ADDL2 S^ 8 P THEN % clean stack ; .el .X MOVE__WORDS .hl 3 Move a block of "N" long__words .lt Format: MOVE_WORDS Branch: STOIC< Description: Moves a block of "number" long_words from the source address to the destination address. Definition: 'MOVE_WORDS : 4 * SWAP MOVE_BYTES ; .el .X SEARCH__STRING .hl 3 Search a source string for a pattern string .lt Format: SEARCH_STRING Branch: STOIC< Description: This operation searches a source string for a given pattern string and constructs a descriptor to that pattern within the source string. The original pattern descriptor is left on TOP of the stack (for subsequent reuse). Definition: 'SEARCH_STRING : ^X0FFFF GT_IF % short or long search? % short search SUBL2 S^ 4 P % adjust stack MOVQ (P)+ R2 MOVQ (P) R0 % short, get descriptors MATCHC R0 (R1) R2 (R3) ELSE % do it % long search MOVL (P)+ R3 % address of source string to R3 SUBL3 (P) B^(P) -C R0 INCL R0 % # bytes per subsequent group MOVL B^(P) -8 R1 CLRL R2 % full count, prepare to divide EDIV R0 R1 -(L) R2 % initial count to R2, # groups to loop stack MOVL R0 B^(P) -C % save subsequent length MOVQ (P) R0 % pattern descriptor to R0, R1 (CMARK) % loop # groups + 1 MATCHC R0 (R1) R2 (R3) % try next group BEQL (TARGET) % success? MOVL B^(P) -C R2 % subsequent count to R2 SUBL2 R0 R3 INCL R3 % new starting address in source string SOBGEQ (L) (SWAP) (TARGET) (SWAP) (ARCHER) % no, all done? (CMARK) (ARCHER) % all done TSTL (L)+ THEN % clean loop stack ADDL2 -(P) B^(P) -4 % end of source string MOVL R3 (P) % address of remainder of source SUBL2 (P) -(P) % length of remainder MOVL R0 -(P) EQZ % return success code ; .el .X .STREQ .hl 3 Test for presence of pattern string within a source string .lt Format: .STREQ {|} Branch: STOIC< Description: The source string (on TOP of the stack) is searched for a specified pattern. If the pattern is found, the TOP of the stack is marked with "success"; otherwise it marked "false". Definition: '.STREQ : -ROT EQ_IF % are strings of equal length? 2UNDROP +ROT SEARCH_STRING 4 ( UNDER ) ELSE % yes, compare 2DROP 0 THEN % unequal length, fail ; .el .X STAB .hl 3 Attach a byte to a string .lt Format: STAB Branch: STOIC< Description: Attaches the byte on the TOP of the stack to the end of the specified string. Definition: 'STAB : COUNT OVER 4- W@ % max. count OVER LE IF % is there room? DDUP + % where to put the byte FLIP % stack = point, count, where, byte 2- SWAP 1+ W<- % store new count, stack = where, byte B! ELSE % store byte DROP 2DROP THEN % no room, clean stack ; .el .X .STRAP .hl 3 Append one string to another .lt Format: .STRAP Branch: STOIC< Description: Appends the source string, specified by its descriptor to the destination string specified by a pointer to the standard STOIC string. Definition: '.STRAP : +ROT GTZ_IF UNDROP ( % loop for each byte in source DDUP I + B@ SWAP STAB ) THEN 2DROP ; .el .X STRAP .hl 3 Append one string to another .lt Format: STRAP Branch: STOIC< Description: Appends the source string to the destination string. Both strings are specified by their addresses. Definition: 'STRAP : SWAP COUNT -ROT .STRAP ; .el .X .MOVE__STRING .hl 3 Move source string to destination string .lt Format: .MOVE_STRING Branch: STOIC< Description: Moves the source string, as specified by its descriptor, to the destination string. Definition: '.MOVE_STRING : DUP 0W<- % set destination count to zero +ROT ( % loop for each byte in source DDUP I + B@ SWAP STAB ) 2DROP ; .el .X MOVE__STRING .hl 3 Move one string to another .lt Format: MOVE_STRING Branch: STOIC< Description: Moves source string to destination. Definition: 'MOVE_STRING : SWAP COUNT -ROT .MOVE_STRING ; .el .X (SUBSTRING) .hl 3 Searches for a substring within a source string .lt Format: (SUBSTRING) {|} Branch: STOIC< Description: Searches a source string for a given substring, called a "pattern". If found, the stack has "success" on TOP of it, then the original pattern descriptor, and finally the descriptor of the remainder of the source string. Definition: '(SUBSTRING) : MOVQ (P)+ R2 MOVQ (P) R0 % load descriptors MATCHC R0 (R1) R2 (R3) % do match operation MOVQ R2 -(P) % return rest-of-source descriptor MOVL R0 -(P) EQZ % return success code ; .el .X BCOUNT .hl 3 Get length of string having a byte-sized count .lt Format: BCOUNT Branch: STOIC< Description: Makes a string descriptor on the stack for the special string which has a byte as the byte-count rather than a word. Definition: 'BCOUNT : DUP 1+ SWAP B@ ; .el .X STOIC >Words >System services .hl 2 System services accessing .X SYSTEM__SERVICES .hl 3 Change branch .lt Format: SYSTEM_SERVICES Branch: STOIC< Description: The address of the system services calls branch is placed on TOP of the parameter stack. To use the VAX/VMS SYSTEM SERVICES the operation SYSTEM_SERVICES is used as a constant to load the entry point of the system services module ("SS") on TOP of the parameter stack. By entering V_PUSH and DEFINITIONS the system services incorporated in module "SS" are made available as current vocabulary entries. Two access mechanisms are available for system services: 1. Invocation of a system service by means of a macro call to the subroutine. This call is of the $_G type and uses (R10) as the parameter list. 2. Acquisition of a datum associated with some previous system service call, or of a constant required for execution of a system service. The constant is returned on the TOP of the parameter stack. Definition: MACRO code in kernel .el .X HEAD .X FIRST__PAGE .X LAST__PAGE .X ISD .X ISD__LENGTH .X ISD__BVPN .X ISD__MVPN .X ISD__BVBN .X OFFSET .X GIH .X GISD .X DISD .X FIND__NEXT__IMAGE__SECTION .X FIND__NEXT__RESIDENT__SECTION .X FIND__RIGHT__RESIDENT__SECTION .X UPDATE__IMAGE .X BREAK .hl 3 Services needed to create new STOIC systems .p,0 The STOIC words listed below are needed whenever a new system is to be created. To use these words requires an understanding of the way in which VMS stores executable modules. The reader is referred to the appropriate VAX/VMS manual for a description. .s 1 The definitions of the various operations (from "IHEAD") are listed below: .s 1 .lt % ISD = Image Section Descriptor % BVPN = Base Virtual Page Number % MVPN = Maximum Virtual Page Number % BVBN = Base Virtual Block Number % GIH = Get Image Header % GISD = Get Image Section Descriptor % DISD = Display Image Section Descriptor 200 'HEAD ARRAY % header buffer (512 bytes = 1 page) 'FIRST_PAGE : COND_HANDLER 200 / ; 'LAST_PAGE : DICT_PNTR @ 1- 200 / 2+ ; HEAD 'ISD VARIABLE % pointer to image section descriptor 'ISD_LENGTH : ISD @ W@ ; 'ISD_BVPN : ISD @ 4 + W@ ; 'ISD_MVPN : ISD_BVPN ISD @ 2 + W@ + ; % max page number 'ISD_BVBN : ISD @ C + @ ; % base virtual block number 0 'OFFSET VARIABLE % amount to subtract from VPN to get VBN 'GIH : % name, GIH (gets image header from file named) 5 ROPEN % open the file 1 HEAD 200 RANDOGET % read the header HEAD ISD ! % initialize pointer to next ISD ; 'GISD : % number, GISD (gets section requested by number) HEAD % address of offset to first section descriptor SWAP ( % do it N times DUP B@ + ) % address of next section descriptor ; 'DISD : % pointer to ISD, DISD (displays ISD) GISD % pointer to ISD DUP W@ DUP = NEZ IF % is this one? DUP 2 + W@ = % yes, output BVPN DUP 4 + @ 100 * 100 / = % output # of pages DUP W@ 10 EQ IF % does this one include blocks in file? DUP C + @ = THEN THEN % yes, output BVBN CR ; 'FIND_NEXT_IMAGE_SECTION : ISD_LENGTH ISD +! % get next ISD ISD_LENGTH NEZ % any more ; 'FIND_NEXT_RESIDENT_SECTION : BEGIN FIND_NEXT_IMAGE_SECTION IF % any more? ISD_LENGTH 10 EQ IF % yes, is it a RESIDENT section -1 -1 ELSE % yes, exit, signal success 0 THEN ELSE % not resident, loop 0 -1 THEN % no more, exit, signal failure END ; 'FIND_RIGHT_RESIDENT_SECTION : BEGIN FIND_NEXT_RESIDENT_SECTION IF ISD_BVPN FIRST_PAGE GE ISD_MVPN LAST_PAGE LE AND IF % is this the one? -1 -1 ELSE % yes, exit, signal success 0 THEN ELSE % no, loop 0 -1 THEN % no more, exit, signal failure END ; 'UPDATE_IMAGE : LAST_PAGE ISD_BVPN DO % once for each page to be written I ISD_BVBN + ISD_BVPN - % block number I 200 * % core address 200 RANDOPUT % write page LOOP ; 'BREAK : 'BREAK.EXE GIH FIND_RIGHT_RESIDENT_SECTION IF % success? UPDATE_IMAGE ELSE % "BREAK failed." MSG CR THEN % no ; .el .hl 3 VAX/VMS services available .p,0 .x parameter blocks Parameter blocks for VAX/VMA system services may be constructed in two ways: by creating a parameter block within the parameter stack (see Section 1.4.2 for a description of this procedure), or by means of a set of special STOIC words patterned after those used for building an I/O record block (see Section 1.4.2 for an example). .p,1 .x System condition codes .x Condition codes Most system services return a condition code to the caller. STOIC places this code on the TOP of the parameter stack where it may be tested. This may be done with the "IF" word (which tests only the low bit). Further information may be obtained by using with the STOIC word "SYSMSG". .s 1 System services available are: .s 1 .list 1 .X $READEF .X $CLREF .X $WAITFR .le;Event flag services .list 0 .le;$READEF -- read event flag .le;$CLREF -- clear event flag .le;$WAITFR -- wait for event flag .els .X $TRNLOG .le;Logical name services .list 0 .le;$TRNLOG -- translate logical name .els .X $ASSIGN .X $DASSGN .X $QIO .X $QIOW .X $GETCHN .le;Input/Output services .list 0 .le;$ASSIGN -- assign I/O channel .le;$DASSGN -- deassign I/O channel .le;$QIO -- queue I/O request .le;$QIOW -- queue I/O request and wait for completion (event flag) .le;$GETCHN -- get information about device assigned to channel .els .X $GETMSG .le;System error messages .list 0 .le;$GETMSG -- returns text of system error message .els .X $FAO .le;Formatted ASCII output .list 0 .le;$FAO -- formatted ASCII output .els .X $CREPRC .X $DELPRC .X $WAKE .X $SCHDWK .X $EXIT .X $SETPRI .X $GETJPI .X $CPUTIM .X DIRIO .X FREP0VA .X GRP .X MEM .X UIC .le;Process control services .list 0 .le;$CREPRC -- creates subprocess or detached process .le;$DELPRC -- deletes the current process or a subprocess .le;$WAKE -- wake sleeping subprocess .le;$SCHDWK -- perform a scheduled wake .le;$EXIT -- exit to VMS .le;$SETPRI -- set process/subprocess priorities .le;$GETJPI -- get job/process information .le;CPUTIM -- returns accumulated CPU time in 10 mS tics .le;DIRIO -- returns direct I/O usage .le;FREP0VA -- first free page at end of program region .le;GRP -- group number of UIC .le;MEM -- member number of UIC .le;UIC -- process UIC .els .X $GETTIM .X $NUMTIM .X $ASCTIM .X $BINTIM .X $SETIMR .le;Timer and time conversion services .list 0 .le;$GETTIM -- get time .le;$NUMTIM -- convert 64-bit system time to binary integer date and time values .le;$ASCTIM -- convert 64-bit system time to standard ASCII string format .le;$BINTIM -- convert standard ASCII format time string to 64-bit system time format .le;$SETIMR -- set timer and execute a scheduled wakeup .els .X $EXPREG .X $CRETVA .X $DELTVA .X $CRMPSC .X $UPDSEC .X $MGBLSC .X $DGBLSC .X $SETPRT .le;Memory management services .list 0 .le;$EXPREG -- expand program region .le;$CRETVA -- create virtual address space .le;$DELTVA -- delete virtual address space .le;$CRMPSC -- create and map section .le;$UPDSEC -- update section file on disk .le;$MGBLSC -- map global section .le;$DGBLSC -- delete global section .le;$SETPRT -- set protection on pages .els .X GETCMD .le;CLI service .list 0 .le;GETCMD -- get command line from CLI (TOP of stack will have command string descriptor on it) .els .els .hl 3 VAX/VMS System Services use .X ASSIGN .hl 4 Assign a channel to a name .lt Format: ASSIGN Branch: STOIC< Description: The device name string, "Name", is used as a parameter to the $ASSIGN system service. The returned value is the associated i/o channel (if any) and the error code. For details see the $ASSIGN function in the System Services manual. Definition: 'ASSIGN : MARK 0 SWAP % save where to put channel # COUNT MARK % make string descriptor, pointer in L-stack OVER B@ ^X1B EQ_IF % is first byte of sting an ESC? 4- SWAP 4+ SWAP THEN % yes, drop first four bytes 0 0 RECALL RECALL SWAP 4 $ASSIGN NOTE 6 (DROP) RECALL ; .el .X QIO .hl 4 Perform QIO operation .lt Format: QIO Branch: STOIC< Description: Performs a $QIO operation on a previously created IORB (see above). The resulting error code is left on TOP of the stack. Definition: 'QIO : DUP @ DUP NOTE 4 * 1 + OVER + SWAP 3 - DO I' @ 4 +LOOP $QIO DROP RECALL (DROP) ; .el .X QIOW .hl 4 Perform $QIOW on IORB .lt Format: QIOW Branch: STOIC< Description: Causes a call to the $QIOW system service using a pre-defined IORB (see above). The condition code is left on TOP of the stack. Definition: 'QIOW : DUP @ DUP NOTE 4 * 1 + OVER + SWAP 3 - DO I' @ 4 +LOOP $QIOW DROP RECALL (DROP) ; .el .X TRNLOG .hl 4 Translate logical name .lt Format: TRNLOG Branch: STOIC< Description: Translates the logical name in the source string to its logical equivalent and places that string in the result string location. Uses the system service $TRNLOG. Note that SYSERR is called if the source string cannot be translated. Definition: 'TRNLOG : SWAP MARK COUNT -ROT % save source descriptor pointer DUP NOTE % save pointer for result length 2+ DUP 4- W@ MARK % save result descriptor pointer 0 0 0 RECALL RECALL RECALL 6 $TRNLOG SYSERR ^X0A (DROP) ; .el .X GETJPI .hl 4 Get job and process information .lt Format: GETJPI Branch: STOIC< Description: Retrieve information (item) from the job control blocks. See the write up for $GETJPI in the VAX/VMS System Services manual. Definition: 'GETJPI : NOTE % save item code on L-stack 0 MARK % buffer for returned item 0 MARK % buffer for length of returned item % build GETJPI-item descriptor RECALL % return length address RECALL % buffer address RECALL ^X10000 * % item code into left half OVER NOTE % address of returned item 4 + % buffer length into right half MARK % address of item descriptor % build $GETJPI argument list 0 0 0 RECALL 0 0 0 7 $GETJPI SYSERR RESTORE ; AS an example consider: FREP0VA GETJPI DUP .D ! .M ! sets beginning and end of user data area to free P0 virtual address. .el .X EXPREG .hl 4 Expand program region .lt Format: EXPREG Branch: STOIC< Description: Expands program region by the specified number of pages. See the system services manual for details. Definition: 'EXPREG : NOTE % save # of pages 0 0 0 RECALL 4 $EXPREG SYSERR 4 (DROP) ; .el .X DELTVA .hl 4 Delete virtual address space .lt Format: DELTVA Branch: STOIC< Description: Memory management aid. See VAX/VMA System Services manual for details. Definition: 'DELTVA : MARK % pointer to bounds array onto L Stack 0 0 RECALL 3 $DELTVA SYSERR 5 (DROP) ; .el .X GETTIM .hl 4 Get system time as quadword .lt Format: GETTIM <64-bit system time> Branch: STOIC< Description: Acquires the 64-bit standard system time. Definition: 'GETTIM : 0 MARK RECALL 4- 1 $GETTIM SYSERR ; .el .X ASCTIM .hl 4 Convert system time to ASCII .lt Format: <64-bit system time> ASCTIM Branch: STOIC< Description: Converts the 64-bit standard system time on TOP of the stack to the equivalent string. For absolute time the format is: dd-mmm-yyyy hh:mm:ss.cc and for delta time: dddd hh:mm:ss.cc Definition: 'ASCTIM : DUP 2+ SWAP 2- W@ MARK % output string descriptor 0 RECALL DUP 8 + SWAP DUP 4 $ASCTIM SYSERR % do it 4 (DROP) SWAP 2- W! 2DROP % cleanup stack and store byte count ; .el .X BINTIM .hl 4 Convert an ASCII time string to system 64-bit time .lt Format: BINTIM <64-bit system time> Branch: STOIC< Description: The time, represented by the string on TOP of the stack, is converted to system standard 64-bit binary time. Definition: 'BINTIM : MARK RECALL DUP 2 $BINTIM SYSERR % do it 2DROP % cleanup ; .el .X DELAY .hl 4 Suspend operation for specified number of mS .lt Format: DELAY Branch: STOIC< Description: The process is delayed by the specified number of milliseconds. Recall that the default radix is hex! Definition: 'DELAY : -1 SWAP MILLISECONDS MARK 0 0 % no ID, no AST RECALL % pointer to time quadword 0 % event flag 4 $SETIMR SYSERR 6 (DROP) 0 1 $WAITFR SYSERR DROP ; .el .X EFN .hl 4 Test and clear specified event flag .lt Format: EFN {Set => true | Not set => false} Branch: STOIC< Description: Tests the specified event flag for its condition and then clears it. Definition: 'EVENT_FLAG : 1 $CLREF DUP SYSERR UNDER $_WASSET EQ ; .el .X STOIC >Words >Tests on TOP of stack .hl 2 Tests on TOP stack value .X OVERFLOW? .hl 3 Arithmetic overflow .lt Format: OVERFLOW? Branch: STOIC< Description: Tests for the overflow bit set in the PSW. If so, the TOP of the stack is set to -1; otherwise 0. Definition: 'OVERFLOW? : BVS ITEFT ; .end literal .X ITEFT .hl 3 Compiler .lt Format: ITEFT Branch: STOIC< Description: IF_TRUE_ELSE_FALSE_THEN is a branch-on-condition machine instruction. It follows the form: IF_TRUE_ELSE_FALSE_THEN If the branch condition is met, -1 is pushed, if not met, 0 is pushed. Definition: 'ITEFT : CMARK 0 CPUSH % MARK POSITION AND PROVIDE TARGET INLINE< CLRL -(P) RSB >INLINE % FALSE PUSHES 0 CMARK OVER - 1- SWAP B! % ARCHER INLINE< MCOML S^ 0 -(P) >INLINE % TRUE PUSHES -1 ; IMMEDIATE .end literal .hl 3 Stack .P,0 The operators listed below all appear in the STOIC< branch of the system. They are just listed for convenience and space saving. .s 1 .list 1 .X NEZ .le;NEZ -- #NEZ#<-1/0> .br Tests Value for non-zero. If true, then -1 is left on TOP of stack; else 0. .literal 'NEZ : TSTL (P)+ BNEQ ITEFT ; .end literal .X EQZ .le;EQZ -- #EQZ#<-1/0> .br Tests Value for zero. If true, then -1 is left on TOP of the stack; else 0. .literal 'EQZ : TSTL (P)+ BEQL ITEFT ; .end literal .X GTZ .le;GTZ -- #GTZ#<-1/0> .br Tests Value for greater than zero. If true, then -1 is left on TOP of stack; else 0. .literal 'GTZ : TSTL (P)+ BGTR ITEFT ; .end literal .X LEZ .le;LEZ -- #LEZ#<-1/0> .br Tests Value for less than or equal to zero. If true, then -1 is left on TOP of the stack; otherwise 0. .literal 'LEZ : TSTL (P)+ BLEQ ITEFT ; .end literal .X GEZ .le;GEZ -- #GEZ#<-1/0> .br Tests Value for greater than or less than zero. If true, then -1 is left on TOP of the stack; else 0. .literal 'GEZ : TSTL (P)+ BGEQ ITEFT ; .end literal .X LTZ .le;LTZ -- #LTZ#<-1/0> .br Tests Value for less than zero. If true, then -1 is left on TOP of the stack; otherwise 0. .literal 'LTZ : TSTL (P)+ BLSS ITEFT ; .end literal .X NE .le;NE -- #NE#<-1/0> .br Compares Value__1 _^= Value__2. If true, then -1 is left on TOP of the stack; else 0. .literal 'NE : CMPL (P)+ (P)+ BNEQ ITEFT ; .end literal .X EQ .le;EQ -- #EQ#<-1/0> .br Makes comparison: Value__1 = Value__2. If true, then -1 is left on TOP of the stack; otherwise 0. .literal 'EQ : CMPL (P)+ (P)+ BEQL ITEFT ; .end literal .X GT .le;GT -- #GE#<-1/0> .br Makes comparison: Value__1 _> Value__2. If true, then -1 is left on TOP of the stack; else 0. .literal 'GT : CMPL (P)+ (P)+ BGTR ITEFT ; .end literal .X LE .le;LE -- #LE#<-1/0> .br makes the comparison: Value__1 _^> Value__2. If true, then -1 is left on TOP of the stack; else 0. .literal 'LE : CMPL (P)+ (P)+ BLEQ ITEFT ; .end literal .X GE .le;GE -- #GE#<-1/0> .br Makes the comparison: Value__1 _^< Value__2. If true, then -1 is left on TOP of the stack; else 0. .literal 'GE : CMPL (P)+ (P)+ BGEQ ITEFT ; .end literal .X LT .le;LT -- #LT#<-1/0> .br Makes the comparison: Value__1 _< Value__2. If true, then -1 is left on TOP of the stack; else 0. .literal 'LT : CMPL (P)+ (P)+ BLSS ITEFT ; .end literal .X DGE .le;DGE -- #DGE#<-1/0> .br Performs the same comparison as "GE" but on quadwords. .literal 'DGE : MOVQ (P)+ R0 MOVQ (P)+ R2 MOVL R2 -(P) MOVL R0 -(P) % low-order longwords to stack MOVL R3 -(P) MOVL R1 -(P) % high-order parts to stack DDUP EQ_IF % are high-order longwords equal DROP LTZ_IF SWAP THEN ELSE % yes, set up low-order longwords -ROT DROP -ROT DROP THEN % no, set up high-order longwords GE % compare ; .end literal .X .. GROUP .le; Need to add the .. set for floating point .els .X STOIC >Words >Variables .hl 2 Variables .x Variables .hl 3 Array .x Arrays .hl 4 Array definition .x Array definition .X ARRAY .lt Format: ARRAY Branch: STOIC< Description: Allocates the specified number of words for an array in the data space. Definition: 'ARRAY : .D@ SWAP CONSTANT % constant points to next free space 4 * .D+! % allocate 4*count bytes ; .el .hl 4 Initializing an array .x FILL .x Array initialization .x Initialization .lt Format: FILL Branch: STOIC< Description: Fills the named array (TOP-2) whose length in words is given at TOP-1 with the value spacified at TOP. Definition: 'FILL : +ROT ( DDUP ! 4+ ) 2DROP ; .el .hl 4 Zeroing an array .x Zeroing an array .x Array initialization .x Initialization .x 0FILL .lt Format: 0FILL Branch: STOIC< Description: Filles the named array (TOP-1) having length specified at TOP with zeros. Definition: '0FILL : 0 FILL ; .el .X BRANCH .hl 3 Dictionary .lt Format: BRANCH Branch: STOIC< Description: Makes a new dictionary branch. This is done by entering a zero word in the data space and forcing the linkage of the new branch first definition to point to it thereby terminating the branch list. Uses the kernel operator "BRANCH" in the definition, making it no longer available since the new definition will be seen first. Neat trick. Definition: 'BRANCH : .D@ SWAP 0 ,D BRANCH ; .el .X VARIABLE .hl 3 Simple arithmetical variable .lt Format: VARIABLE Branch: STOIC< Description: Reserves space for the named variable. Definition: 'VARIABLE : .D@ SWAP CONSTANT % constant points to next free space ,D % put value in that space ; .el .X SVARIABLE .hl 3 String variable .lt Format: SVARIABLE Branch: STOIC< Description: Allocates a string variable of specified maximum length in the user's data space. Definition: 'SVARIABLE : .D @ 2 + SWAP CONSTANT % associate address of count with name DUP ,D % store max count, null current count .D+! % allocate string ; .el .X STOIC >Words >VT100 .hl 2 VT100 definitions and operations .hl 3 Definitions .p,0 The definitions given below are for reference and are simply listed. .x O.FLAG .X O.BUFCUR .X O.BUFSIZE .X O.BUFSTRT .X O.BUFEND .lt 0 'O.FLAG VARIABLE 0 'O.BUFCUR VARIABLE 400 'O.BUFSIZE CONSTANT .D@ 'O.BUFSTRT CONSTANT .D@ 'O.BUFEND CONSTANT O.BUFSIZE .D+! .el .hl 3 Operations .p,0 These operations are listed for convenience. .X D<_#_> .lt 'D<#> : % value, D<#>, string ptr., count % (converts value to a decimal string) RADIX @ SWAP DECIMAL % save radix, switch to decimal <#> -ROT RADIX ! % convert number, restore radix ; .EL .X FLUSH .LT 'FLUSH : O.BUFSTRT O.BUFCUR @ OVER - NEZ_IF % anything there? UNDROP TYPE % output buffer O.BUFSTRT O.BUFCUR ! ELSE % reset buffer DROP THEN % no action ; .EL .X BUFFER__ON .LT 'BUFFER_ON : -1 O.FLAG ! O.BUFSTRT O.BUFCUR ! ; .EL .X BUFFER__OFF .LT 'BUFFER_OFF : FLUSH O.FLAG 0<- ; .EL .X TYO (redefinition) .LT 'TYO : O.FLAG @ IF % is buffering turned on? O.BUFCUR @ O.BUFEND OVER - LEZ_IF % yes, out of room? DROP FLUSH O.BUFSTRT THEN % yes, flush DUP 1+ O.BUFCUR ! B! ELSE % put byte in buffer TYO THEN % buffering turned off, do normal tyo ; .EL .X CR (redefinition) .lt 'CR : ^X0D TYO ^X0A TYO ; .el .X SPACE (redefinition) .LT 'SPACE : ^X20 TYO ; .EL .X SPACES (redefinition) .LT 'SPACES : GTZ_IF UNDROP ( SPACE ) THEN ; .EL .X TYPE (redefinition) .LT 'TYPE : O.FLAG @ IF % is buffering on? GTZ_IF % anything there? UNDROP ( % yes, loop through string DUP B@ TYO 1+ ) THEN % type next byte DROP ELSE TYPE THEN % buffering off, do normal TYPE ; .EL .X MSG (redefinition) .LT 'MSG : COUNT TYPE ; .el .hl 3 Control sequences These operations are listed for convenience. .X ESC .X ESC[ .X SC .X RC .X RI .lt 'ESC : ^X1B TYO ; 'ESC[ : ESC ASCII [ TYO ; 'SC : % SAVE CURSOR ESC ASCII 7 TYO ; 'RC : % RESTORE CURSOR ESC ASCII 8 TYO ; 'RI : % REVERSE INDEX ESC ASCII M TYO ; .EL .X STBM .LT 'STBM : % bottom margin, top margin, STBM ESC[ % OUTPUT PREFIX D<#> TYPE % output top line number ASCII ; TYO % separator D<#> TYPE % bottom line # ASCII r TYO % SUFFIX ; .EL .X SGR .X ED .X SET__MODE .LT 'SGR : % select graphic rendition ESC[ #A TYO ASCII m TYO ; 'ED : % erase in display ESC[ #A TYO ASCII J TYO ; 'SET_MODE : % value, SET_MODE ESC[ ASCII ? TYO #A TYO ASCII h TYO ; .EL .X RESET__MODE .X LIGHT__BACKGROUND .X DARK__BACKGROUND .LT 'RESET_MODE : % value, RESET_MODE ESC[ ASCII ? TYO #A TYO ASCII l TYO ; 'LIGHT_BACKGROUND : 5 SET_MODE ; 'DARK_BACKGROUND : 5 RESET_MODE ; .EL .X WRAP__OFF .X EL .X CUP .X DHLT .LT 'WRAP_OFF : 7 RESET_MODE ; 'EL : % erase in line ESC[ #A TYO ASCII K TYO ; 'CUP : % cursor position ESC[ D<#> TYPE ASCII ; TYO D<#> TYPE ASCII H TYO ; 'DHLT : % double-height line, top ESC '#3 MSG ; .EL .X DHLB .X DWL .X SWL .X GRAPHICS .X LCASE .LT 'DHLB : % double-height line, bottom ESC '#4 MSG ; 'DWL : % double-width line ESC '#6 MSG ; 'SWL : % single-width line ESC '#5 MSG ; 'GRAPHICS : ESC ASCII ( TYO ASCII 0 TYO ; 'LCASE : ESC ASCII ( TYO ASCII B TYO ; .EL .X ERASE__THIS__LINE .X ERASE__REST__OF__LINE .X ERASE__SCREEN .X ERASE__REST__OF__SCREEN .X BOLD .LT 'ERASE_THIS_LINE : 2 EL ; 'ERASE_REST_OF_LINE : 0 EL ; 'ERASE_SCREEN : 2 ED ; 'ERASE_REST_OF_SCREEN : 0 ED ; 'BOLD : 1 SGR ; .EL .X UNDERSCORE .X BLINK .X REVERSE .X STEADY .LT 'UNDERSCORE : 4 SGR ; 'BLINK : 5 SGR ; 'REVERSE : 7 SGR ; 'STEADY : 0 SGR ; .el .hl 3 Commands relating VT100 to Editor .P,0 These commands facilitate using the RED package. They are listed for the sake of completeness. .X TF .X WINDOW__SIZE .X SELECT__COMMAND .lt 6 'TF VARIABLE 'WINDOW_SIZE : % WINDOW_SIZE, # of lines in window TF @ 2* 1+ ; 'SELECT_COMMAND : % (sets up for command entry) 18 WINDOW_SIZE 3 + STBM ; .EL .X BAR .X DRAW__DIVIDER .X BUFFER_# .X DRAW__BUFFER .LT 'BAR : " " MSG ; 'DRAW_DIVIDER : % DRAW_DIVIDER % (draws bar dividing text pane from command pane) 0 TF @ 2* 3 + CUP % position cursor DWL SPACE GRAPHICS "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq" MSG LCASE ; 0 'BUFFER# VARIABLE 'DRAW_BUFFER# : 27 1 CUP ASCII X TYO BUFFER# @ <# # #> TYPE ; .EL .X SETSCREEN .X SET__MODE .X RESET__MODE .X SMOOTH__SCROLL .LT 'SETSCREEN : ERASE_SCREEN 3 ( 0 TYO ) 1 1 CUP % home SPACE SPACE 7 SGR SPACE SPACE FILE_NAME COUNT GTZ_IF % filename? UNDROP TYPE ELSE DROP THEN % yes, write it BAR DWL 0 SGR DRAW_BUFFER# DRAW_DIVIDER SELECT_COMMAND ; 'SET_MODE : ESC[ ASCII ? TYO TYO ASCII h TYO ; 'RESET_MODE : ESC[ ASCII ? TYO TYO ASCII l TYO ; 'SMOOTH_SCROLL : ASCII 4 SET_MODE ; .EL .X ANSI__VT100 .X RESET__VT100 .X APPLICATION__KEYPAD .X DMSG .LT 'ANSI_VT100 : % switch VT100 from VT52 to ANSI ESC ASCII < TYO ; 'RESET_VT100 : ESC ASCII c TYO ; 'APPLICATION_KEYPAD : ESC ASCII = TYO ; 'DMSG : % double-width, double-height message CR DWL DHLT DUP MSG CR DWL DHLB MSG ; .el .pg .X Classification of operations by branch .x Classification .hl 1 Classification of operations by branch .x Classification >STOIC< .hl 2 STOIC< (from file 'DEF') .st 8,16,24,32,40,48,56,64,72 .lt B! IMMEDIATE DROP DUP 2DROP DDUP SWAP (SWAP) OVER +ROT -ROT (DROP) UNDER FLIP UNDROP 2UNDROP MINUS 1+ 2+ 4+ 1- 2- 4- NOT AND OR XOR MOD RADIX + - * 2* / /MOD @ @@ B@ W@ D@ ? ! <- B<- W<- D<- EXCHANGE MOVE D! W! 1+<- +! +<- 1-! 1-<- -! -<- 0<- 0W<- -1<- 1<- +CHECK -CHECK () CMARK TARGET (TARGET) ARCHER (ARCHER) (CMARK) INLINE< >INLINE ITEFT **Z (tests) NE - LT (tests) OVERFLOW **_IF (tests) **Z_IF (tests) IF THEN ELSE BEGIN END REPEAT DGE COMPILE_BYTE DISPATCH 1 2 -1 I J K MARK NOTE RECALL RESTORE MIN MAX ABS DO {LOOP} LOOP +LOOP ( ) LAST_I EXIT INCLUDE GETJPI EXPREG DELTVA GETTIM ASCTIM BINTIM MILLISECONDS DELAY EVENT_FLAG PROTECT_STACKS .D@ .D+! ,D B,D MEMORY INITIALIZE_DATA_REGION VARIABLE ARRAY SVARIABLE BRANCH CUR_IORB IORB TRNLOG ASSIGN QIO QIOW STACK BPUSH ASCII <# #> #PUT #A #S # <#> MOVE_BYTES MOVE_WORDS SEARCH_STRING .STREQ STRAB .STRAP STRAP .MOVE_STRING MOVE_STRING (SUBSTRING) CRET LFEED BLANK RDL BUF BCOUNT BMSG LIST DECIMAL HEX INVENTORY SYSMSG WHERE WHAT ERROR_TRACE LAST_WORD BELL LOAD/L 2 EXEC DEF_INIT ****************************from file 'OBUF'**************************** O.FLAG O.BUFSIZE O.BUFCUR O.BUFSTRT O.BUFEND FLUSH BUFFER_ON BUFFER_OFF TYO CR SPACE SPACES TYPE MSG TYI ****************************from file 'VT100'*************************** D<#> ESC ESC[ SC RC RI STBM SGR ED SET_MODE RESET_MODE LIGHT_BACKGROUND DARK_BACKGROUND WRAP_OFF EL CUP DHLT DHLB DWL SWL GRAPHICS LCASE ERASE_THIS_LINE ERASE_SCREEN ERASE_REST_OF_LINE ERASE_REST_OF_SCREEN BOLD UNDERSCORE BLINK REVERSE STEADY TF WINDOW_SIZE SELECT_COMMAND BAR DRAW_DIVIDER FNSIZE BUFFER# DRAW_BUFFER SETSCREEN SET_MODE RESET_MODE SMOOTH_SCROLL ANSI_VT100 RESET_VT100 DMSG APPLICATION_KEYPAD ******************************from file 'IHEAD'************************ HEAD FIRST_PAGE LAST_PAGE ISD ISD_LENGTH ISD_BVPN ISD_MVPN ISD_BVBN OFFSET GIH GISD DISD FIND_NEXT_IMAGE_SECTION FIND_NEXT_RESIDENT_SECTION UPDATE_IMAGE BREAK .EL .x Classification >Assembler< .HL 2 ASSEMBLER< (sub-branch of STOIC< from file 'DEF') .LT [R0] R1 R2 R3 L P SP (R0) (R1) (R2) (R3) (L) (P) -(R0) -(L) -(P) (R0)+ (R1)+ (L)+ (P)+ (SP)+ (PC)+ @(P)+ @# RSB BRB BNEQ BEQL BGTR BLEQ JSB JMP BGEQ BLSS BVC BVS MOVC3 CMPC3 MATCHC LOCC MOVZWL EDIV MOVQ ADDB2 MOVB CMPB MOVZBL MOVZBW CLRW ADDL2 ADDL3 SUBL2 SUBL3 MULL2 DIVL2 BISL2 BICL2 XORL2 MNEGL MOVL CMPL MCOML CLRL DECL BLBC AOBLSS SOBGEQ CVTLB CVTLW @BRB B! B^(P) S^ B^ W^ ************************ from 'FLOAT.STO' ************************** ACBF ADDF2 ADDF3 CLRF CMPF CVTBF CVTFB CVTFL CVTFW CVTLF CVTRFL CVTWF DIVF2 DIVF3 EMODF MNEGF MOVAF MOVF MULF2 MULF3 POLYF PUSHAF SUBF2 SUBF3 TSTF .EL .x Classification >IORB< .HL 2 IORB< (sub-branch of STOIC<) (from file 'DEF') .LT INIT EFN! CHAN! FUNC! IOSB! ASTADR! ASTPRM! P1! P2! P3! P4! P5! P6! .EL .x Classification of operations by attribute .hl 1 Classification of operations by lookup__attribute .x Classification >Immediate .hl 2 Immediate .LT DROP DUP 2DROP DDUP (SWAP) OVER + 1+ - 1- @ B@ W@ D@ () (TARGET) (ARCHER) (CMARK) INLINE< >INLINE ITEFT **_IF **Z_IF IF THEN ELSE BEGIN END REPEAT DISPATCH 1 2 -1 I DO LOOP +LOOP ( ) ASCII (SUBSTRING)?? B^(P) S^ B^ W^ .EL .x Classification >Push__this__word .HL 2 Push__this__word .p,0 All literals and variables are entered with this attribute. .x Classification >Push__this__vocabulary .hl 2 Push__this__vocabulary .lt STOIC< ASSEMBLER< IORB< .EL .x Classification >Jump__to__me .HL 2 Jump__to__me .p,0 All other STOIC words default to this attribute. .pg .x Operations .x Operations >Alphabetical listing .x STOIC >Words >Alphabetical listing .hl 1 Alphabetical listing of operations .lt !
! # # #> #>
#A #A #F #F #PUT #PUT #S #S <0> $ASCTIM Convert 64-bit system time to standard ASCII string format $ASSIGN Assign I/O channel $BINTIM Convert standard ASCII format time string to 64-bit system time $CLREF Clear event flag $CREPRC Creates subprocess or detached process $CRETVA Create virtual address space $CRMPSC Create and map section $DASSGN Deassign I/O channel $DELPRC Deletes the current process or a subprocess $DELTVA Delete virtual address space $DGBLSC Delete global section $EXIT Exit to VMS $EXPREG Expand program region $FAO Formatted ASCII output $GETCHN Get information about device assigned to channel $GETJPI Get job/process information $GETMSG Returns text of system error message $GETTIM Get time $MGBLSC Map global section $NUMTIM Convert 64-bit system time to binary integer date and time $QIO Queue I/O request $QIOW Queue I/O request and wait for completion (event flag) $READEF Read event flag $SCHDWK Perform a scheduled wake $SETIMR Set timer and execute a scheduled wakeup $SETPRI Set process/subprocess priorities $SETPRT Set protection on pages $TRNLOG Translate logical name $UPDSEC Update section file on disk $WAITFR Wait for event flag $WAKE Wake sleeping subprocess ( ( () ()
(:) (:) (;) (;) (ARCHER) (ARCHER) (CMARK) (CMARK) (DROP) (DROP) (SUBSTRING) (SUBSTRING) {|} (SWAP) (SWAP) (TARGET) (TARGET) ) ) * * + + +!
+! +<-
+<- +CHECK +CHECK +LOOP +LOOP +ROT +ROT , , ,D ,D - - -!
-! -<-
-<- -1<-
-1<- -CHECK -CHECK -ROT -ROT .. .APPEND .APPEND .D Pointer to next free data location (user table) .D+! .D+! .D@ .D@ .GET .GET .M Pointer to first unavailable memory location (user table) .MOVE_STRING .MOVE_STRING .OPEN .OPEN .STRAP .STRAP .STREQ .STREQ {|} .WOPEN .WOPEN / / /MOD /MOD 0<-
0<- 0FILL 0FILL 0W<-
0W<- 1+ 1+ 1+!
1+! 1+<-
1+<- 1- 1- 1-!
1-! 1-<-
1-<- 1<-
1<- 2 2 2* 2* 2+ 2+ 2- 2- 2DROP 2DROP 2UNDROP 2UNDROP 4+ 4+ 4- 4- ;F ;F <# <# <#> <#> <-
<- _IF _IF = = > > >INLINE >INLINE ?
? @
@ @@ @@ ABS ABS <|Value|> AC AC AND AND ANSI_VT100 Switch VT100 from VT52 to ANSI APPEND APPEND APPLICATION_KEYPAD Enables application keypad mode ARCHER ARCHER ARRAY ARRAY ASCII ASCII ASCTIM <64-bit system time> ASCTIM ASSEMBLER Assembler dictionary branch pointer (user table) ASSEMBLER< ASSEMBLER< ASSIGN ASSIGN B!
!B B, B, B,D B,D B<-
B<- B@
B@ BAR Draws a bar BCOUNT BCOUNT BEGIN BEGIN BELL BELL BINTIM BINTIM <64-bit system time> BLINK Set cursor display mode to blink BOLD Set bold-face rendition BPOP BPOP BPUSH BPUSH BRANCH BRANCH BRANCH BRANCH (redefinition) BREAK BREAK BSMG BMSG BUF String buffer (user table) BUFFER# Variable BUFFER_OFF Turns off buffering BUFFER_ON Turns on buffering B^ B^ {Next number in input line} B^(P) B^(P) B_KERNEL B_KERNEL
B_PUSH V_PUSH CEQ CEQ CHECK IF level counter (value in user table) CLOSE CLOSE CMARK CMARK COMPILE_BYTE COMPILE_BYTE COMPILE_ERROR COMPILE_ERROR COMP_BUF_0 Initial compile buffer pointer (= A(comp__buf)) (user table) COMP_BUF_PNTR Current compile buffer pointer (user table) COND_CODE Condition code from error handler (value in user table) CONSTANT CONSTANT COUNT COUNT CPOP CPOP CPUSH CPUSH CPUTIM Returns accumulated CPU time in 10 mS tics CR CR CTRL_C_FLAG Flag set on _^C (user table) CTRL_C_HANDLER CTRL_C_HANDLER CTRL_C_TEMP 8-byte region required by _^C handler (user table) CUP Cursor position CURRENT Current dictionary branch pointer (user table) D! D! D<#> D<#> D<-
D<- D@ D@ DARK_BACKGROUND Sets screen to dark background DDUP DDUP DECIMAL DECIMAL DEFINITIONS DEFINITIONS DEF_INIT DEF_INIT DELAY DELAY DELTVA DELTVA DGE DGE <-1/0> DHLB Double-height line, bottom DHLT Double-height line, top DICT_PNTR Dictionary pointer (user table) DIGIT DIGIT DIRIO Returns direct I/O usage DISD DISD (displays ISD) DISPATCH DISPATCH DISPATCH_ADR Pointer to dispatch table (user table) DMSG DMSG (Double-width, double-height message) DO DO DRAW_BUFFER# Draws named buffer DRAW_DIVIDER Draws divider DROP DROP DUP DUP DWL Double-width line ED Erase in display EFN EFN {Set => true | Not set => false} EL Erase in line ELSE ELSE END END END_OF_CMND Compile end of command (value in user table) END_OF_LINE Compile end of line (value in user table) EQ EQ <-1/0> EQZ EQZ <-1/0> ERASE_REST_OF_LINE Erases remainder of current line ERASE_REST_OF_SCREEN Erases remainder of screen ERASE_SCREEN Erases screen ERASE_THIS_LINE Erases current line ERR ERR ERRCHK ERRCHK ERROR_PC PC saved by condition handler (value in user table) ERROR_TRACE ERROR_TRACE ESC Types out an escape code to user's terminal ESC[ Types [ EXCHANGE EXCHANGE EXEC
EXEC EXIT EXIT EXPREG EXPREG FATAL FATAL FILE_NAME Name of file (FNSIZE = ^X50) FILL FILL FIND_NEXT_IMAGE_SECTION FIND_NEXT_IMAGE_SECTION FIND_NEXT_RESIDENT_SECTION FIND_NEXT_RESIDENT_SECTION FIND_RIGHT_RESIDENT_SECTION FIND_RIGHT_RESIDENT_SECTION FIRST_PAGE FIRST_PAGE FLIP FLUSH Flushes buffer FREE_USER_SPACE Number of free words left (initially 30 entries) (user table) FREP0VA First free page at end of program region FRE__LKP_SPACE Dispatch table space (initially 30 entries) (user table) GE GE <-1/0> GET GET GETCMD Get command line from CLI (TOP of stack will have command string descriptor on it) GETJPI GETJPI GETTIM GETTIM <64-bit system time> GET_STRING GET_STRING GEZ GEZ <-1/0> GIH GIH (gets image header from file named) GISD GISD (gets section requested by number) GRAPHICS Set graphics mode GRP Group number of UIC GT GE <-1/0> GTZ GTZ <-1/0> HEAD Header buffer (512 bytes = 1 page) (Array) HEX HEX I I I' I' ICOMPILE ICOMPILE IF IF ILITERAL ILITERAL IMMEDIATE IMMEDIATE INCH INCH INCLUDE INCLUDE INLINE< INLINE< INTIALIZE_DATA_REGION INITIALIZE_DATA_REGION INVENTORY INVENTORY ISD Pointer to image section descriptor (Variable) ISD_BVBN ISD_BVBN ISD_BVPN ISD_BVPN ISD_LENGTH ISD_LENGTH ISD_MVPN ISD_MVPN ITEFT ITEFT I_ABORT ABORT I_COMPILE I_COMPILE I_COMPILE_BYTE I_COMPILE_BYTE I_ENTER I_ENTER I_EXECUTE I_EXECUTE I_IMMEDIATE I_IMMEDIATE I_JUMP_TO_ME I_JUMP_TO_ME I_LITERAL I_LITERAL I_LOOKUP I_LOOKUP I_PUSH_THIS_WORD I_PUSH_THIS_WD I_PUSH_VOCAB I_PUSH_VOCAB J J K K LASTINCH LASTINCH LAST_I LAST_I LAST_PAGE LAST_PAGE <(Dict_pntr-1)/^X200+2)> LAST_WORD LAST_WORD LCASE Set lower-case mode LE LE <-1/0> LEZ LEZ <-1/0> LIGHT_BACKGROUND Sets screen to light background LINE_BUFFER Descriptor for input (line) string (user table) LIST LIST LOAD LOAD LOAD/L LOAD/L LOAD_RESET LOAD_RESET LOOKUP_ATTRIBUTE LOOKUP_ATTRIBUTE LOOP LOOP LT LT <-1/0> LTZ LTZ <-1/0> L_STACK L_stack
L_STACK_0 Initial loop stack pointer (user table) MARK MARK MATCH MATCH MAX MAX MEM Member number of UIC MEMORY MEMORY
MILLISECONDS MILLISECONDS MIN MIN MINUS MINUS <-Value> MOAT MOAT MOD MOD MOVE MOVE MOVE_BYTES MOVE_BYTES MOVE_STRING MOVE_STRING MOVE_WORDS MOVE_WORDS MSG MSG M_NOECHO Do not echo characters for this read M_NOFILTR Do not process ^U, ^R or DEL for this read M_NOFORMAT "PASSALL" mode for this write M_SYSGBL System global section flag (default is group global section) M_TIMED "P3" specifies timeout period in seconds M_TRMNOECHO Do not echo terminating character for this read NE NE <-1/0> NEWPROMPT NEWPROMPT NEXTINCH NEXTINCH NEZ NEZ <-1/0> NOT NOT NOTE NOTE O.BUFCUR Variable O.BUFEND Constant O.BUFSIZE Constant O.BUFSTRT Constant O.FLAG Variable OCONSTACK OCONSTACK
OCTAL OCTAL OFFSET Amount to subtract from VPN to get VBN (Variable) OPEN OPEN OR OR OVER OVER OVERFLOW? OVERFLOW? PREOPEN PREOPEN PROMPT Address of prompt string (user table) PROTECT_STACKS PROTECT_STACKS PUT PUT P_STACK P_STACK
P_STACK_0 Initial parameter stack pointer (user table) QIO QIO QIOW QIOW RADIX RADIX RANDOGET RANDOGET RANDOPUT RANDOPUT RC Restore cursor RDL RDL READLINE READLINE RECALL RECALL REMSTART REMSTART REMTYPE REMTYPE REPEAT REPEAT RESET_MODE RESET_MODE RESET_REGISTERS RESET_REGISTERS RESET_VT100 Resets VT100 RESTORE RESTORE REVERSE Set reverse video RI Reverse index ROPEN ROPEN R_STACK_0 Initial return stack pointer (user table) SC Save cursor SCOMPILE SCOMPILE SEARCH_STRING SEARCH_STRING SELECT_COMMAND Sets up for command entry SETSCREEN Sets screen SET_MODE SET_MODE SGR Select graphic rendition SIGN SIGN SLITERAL SLITERAL SMOOTH_SCROLL Enables smooth scrolling SPACE SPACE STAB STAB STACK STACK STBM STBM STEADY Set cursor display mode to steady STOIC STOIC branch in dictionary pointer (user table) STOIC< STOIC< STRAP STRAP SVARIABLE SVARIABLE SWAP SWAP SWL Single-width line SYSERR SYSERR SYSMSG SYSMSG SYSTEM_SERVICES SYSTEM_SERVICES S^ S^{Next number in input line} TARGET TARGET TF Variable THEN THEN TRNLOG TRNLOG TYI TYI TYO TYO TYPE TYPE UIC Process UIC UNDER UNDER UNDERSCORE Set cursor to underscore UNDROP UNDROP UPDATE_IMAGE UPDATE_IMAGE USER_INIT USER_INIT UST_TEMP Space for user's entries (initially 30 entries) (user table) U_IFI Input FAB subscript number (initially 0) (user table) U_IFM Maximum FAB subscript number (set to 3) (user table) U_MAG Magnitude of integer literal (user table) U_RAD Radix (initially set to 16) (user table) U_SGN Sign for integer literal (user table) VARIABLE VARIABLE VOCAB_SP VOCAB_SP (user table) V_PUSH V_PUSH V_STACK V_STACK
V_STACK_0 Initial vocabulary stack pointer (user table) W!
W! W<-
W<- W@
W@ WHAT
WHAT WHERE WHERE WINDOW_SIZE WINDOW_SIZE <# of lines in window> WOPEN WOPEN WORD WORD {|} WORD_BUFFER Descriptor for current input word (user table) WRAP_OFF Turns off wraparound mode W^ W^ {next number in input line} XOR XOR _NORMAL Successful completion _READPROMPT Read with prompt _READVBLK Read virtual block _TIMEOUT Operation timeout _WASCLR Service unsuccessful (specified event flag 0) _WASSET Service successful (specified event flag 1) _WRITEVBLK Write virtual block {LOOP} {LOOP} .el .do index .pg