TECHNICAL DESCRIPTION FOR THE SIRIUS PROGRAMMING LANGUAGE TECHNICAL DESCRIPTION FOR THE SIRIUS PROGRAMMING LANGUAGE Part Number: P00DM0 Copyright (c) 1990 by Conroy & Conroy Co. and Robin Kundert This document is freely distributable SO LONG AS it is distributed in UNMODIFIED form. CONTENTS Preface ..................................................................... 1 Introduction ................................................................ 2 Technical Description ....................................................... 3 Errors ..................................................................... 39 Sirius BNF Description ..................................................... 44 Index ...................................................................... 47 Page 1 Preface This document describes the Sirius computer language. A compiler may only be called a conforming Sirius compiler if the compiler conforms to this document. Certain allowances are made for some features. Where allowed, a compiler may restrict or leave out a feature and still be a conforming compiler. In this case it is a conforming subset. If there are extensions then the compiler is a conforming superset. If the compiler has both subset and superset features, it is considered to be a conforming subset compiler. In all other cases, the compiler is a nonconforming Sirius compiler. All listed formats may use braces {} to indicate optional operands and are not to be included in source code. The terms "identifier" and "variable" are used interchangably in this document and refer to named memory locations used for data storage. This document is not intended to be a tutorial guide for the use of the Sirius language. However, every effort has been made to make the document readable to most programmers, regardless of technical level. Page 2 Introduction Sirius is a general purpose computer programming langauge that avoids the syntatical tedium of langauges such as C, APL, and assembly, but includes the useful features of these languages. The three main goals of the Sirius language are 1) ease of use, 2) efficiency, and 3) portability. The syntax will be most familiar to Pascal and BASIC users. Like C, only program structures (such as loops, IF...THEN constructs, identifier declarations, etc) are defined by the compiler itself. Most "statements" are routines linked in at link-time. The richness of Sirius is derived from its small number of compiler constructs, the flexibility of the variable definitions, and the number of standard library functions. The compiler knows about these standard routines and performs automatic data type conversion where necessary, yet allows the programmer to redefine any routine as if it had never been defined in the first place. Sirius makes no effort to adhere to the silly notion that programs should be readable by non-programmers (such as COBOL proponents claim), nor does it go to the other extreme and become unreadable by the author (as can C and LISP). Nor is Sirius an attempt to be all things to all people (like PL/I). Sirius is designed to be flexible enough to meet any need efficiently, but special languages may excell in certain applications. Sirius is more portable than any other language since even the internal representation of the primary data types is defined. This may be a problem on machines with strange word sizes (such as 12 or 36) but only in the difficulty of implementation and possibly floating-point efficiency. The elegance of dynamic structure management (such as strings) is similar to BASIC, but has additional features. Hence, string handling is not as painful as it is in assembly, C, or Pascal. For those concerned about efficiency (especially in regards to garbage collection), strings can still be implemented in the same manner as C and/or Pascal if this is desirable. Page 3 CHAPTER 1 TECHNICAL DESCRIPTION 1.1. Source Code Format All Sirius source code is free format, where spaces and tabs are ignored, (ASCII values 9 and 32) except where noted and within quotes ('). Any statement may reside on several physical lines except that carriage returns (ASCII 13), linefeeds (ASCII 10), formfeeds (ASCII 12), vertical tabs (ASCII 11) serve to separate tokens in all cases and may not occur in the middle of a literal or keyword. All other non-printing characters of the ASCII set are not allowed outside of quotes. All lowercase letters outside of quotes are internally converted to uppercase automatically by Sirius before parsing. Opening parentheses may be (, {, or [. Closing parentheses may be ), }, or ]. 1.2. Directives A Sirius directive is a compiler-only "statement". That is, it is only acted on by the compiler and produces no code or data directly. Text from another file may be included in a Sirius source program via the "INCLUDE" directive. The format is: INCLUDE filename where filename is the name of the file with text to insert into the source code of the program during compilation. Example: INCLUDE EXTRAS.SIR 1.2.1. Options Compiler option directives allow the programmer to activate or deactivate various features of the compiler. These features degrade program performance when active, but aid in detecting problems. It is recommended that they be set to an active status while coding and CHAPTER 1 Page 4 debugging. Features are activated with the ACTIVATE directive and are deactived with the DEACTIVATE directive. All features are active by default. Format: ACTIVATE x DEACTIVATE x where "x" is one of the following features. Feature Description ------- ----------- ARRAY When active, array subscripts are checked to be in bounds, and the program aborts with an error if the subscript is out of range. NAME When active, the program can process call by name parameter passing. OVERFLOW When active, any numeric overflows or underflows cause the program to abort with an error. Otherwise, the result is adjusted and the over/underflow is ignored. RANGE When active, all accesses to the heap are checked to be within proper ranges. Incorrect heap access will result in an error which will abort the program. 1.3. Identifiers Identifiers are user-defined symbols which are used to reference memory locations for the storage of data. 1.3.1. Identifier Names Identifier names may not exceed 255 characters in length and must consist solely of letters (A-Z), digits (0-9), dollar signs ($), and underscores (_). An identifier name may not begin with a digit. Locating any other character while scanning an identifier will cause the scan to end there, with all previous characters being considered the identifier name and the following characters (beginning with the non-identifier character) being considered the next token(s). An identifier is defined before its use in the source code with a declaration statement. A declaration statement may appear anywhere in the source code, but must preceed any references to the identifiers declared. The declaration statement has the format: DECLARE i AS t where i is the identifier name to define and t is the identifier's data type. i may also be a list of identifiers, separated by commas. Examples: DECLARE OK AS LOGICAL DECLARE Credit, Debit, Total AS REAL CHAPTER 1 Page 5 1.3.2. Global, Static, and External Identifiers An identifier is not normally available to an external routine unless explicitly passed. To define an identifier to be accessible by name, from all external routines, without having to specifically pass it, the "GLOBAL" keyword must be placed immediately after the "AS" keyword. Note that a link error will result if two or more modules define an identifier this way. To reference a global identifier defined elsewhere, the "EXTERNAL" keyword must follow the "AS" keyword. EXTERNAL and GLOBAL may also be used for constants. If a GLOBAL constant is declared then it is placed in a special part of memory that is read-only. No constant may be modified by a program which defines it as a constant. A variable may be defined as STATIC, in which case it is not zeroed or over-written upon entry into the procedure in which it is defined. It is zeroed only when the program execution initially begins. This allows a procedure to keep internal information across calls to the procedure. Examples: DECLARE GLOBAL Shared_Data AS REAL DECLARE EXTERNAL Semaphore AS LOGICAL DECLARE STATIC Context AS INTEGER 1.3.3. Scope Of Identifiers All identifiers must be declared before being referenced. Identifiers are global with respect to all called routines, except where redefined. External programs do not have access to local identifiers in the calling program, nor does the calling program have access to the identifiers of the external program. Files opened in subroutines or sub programs remain open as if opened globally. The representation of the file may be defined differently in the subroutine. However, if the identifier name used to open the file is defined locally then the file is closed upon exiting the routine. 1.4. Data Types Data typing is one of the major advantages to the Sirius language. A flexible definition facility plus numerous built-in data types allow quick development of efficient code. 1.4.1. Simple and Compound data types There are five families of data types. Except where noted, data may not be moved between identifiers of different families. Movement between identifiers of different types within the same family is allowed but has certain restrictions. CHAPTER 1 Page 6 1.4.1.1. UNDEFINED Family The UNDEFINED data type family consists only of one data type (UNDEFINED). It has no pre-defined length and is allocated and deallocated from dynamic memory as needed. An identifier of this type may be assigned to any identifier, regardless of type, and may be assigned from any identifier, regardless of type. This type is used only for data manipulation and cannot be input or output. In order to provide compatible source code across a wide variety of machines, the internal representation of certain data types is strictly defined. This does not mean that the data must be stored in this format, but it does mean that when data is moved to or from an undefined identifier, it must be converted to or from the appropriate internal representation. 1.4.1.2. LOGICAL Family The LOGICAL data type family also consists only of one data type (LOGICAL). It is logically only one bit in length; however, it may or may not be packed. The internal representation is 8 bits of zero for false; if any bits are ones it is considered true. Variables of the LOGICAL type can only be assigned the values TRUE and FALSE. 1.4.1.3. CHARACTER Family The CHARACTER data type family consists of two data types - STRINGs and CHARACTERs. These data types can contain any valid ASCII characters. STRING data types may be of fixed or undefined length. If they are undefined length, they are allocated and deallocated from dynamic memory as needed. The CHARACTER data type is a string with a fixed length of one. Fixed length strings are always the same length and are allocated by the compiler from static memory. By using BYTES n as a modifier after the declaration, a string is defined to be a fixed string of n bytes long. n may have a value of 1 to 65536. This value may be restricted by the compiler, in which case the compiler is a conforming subset of Sirius. If larger values are allowed the compiler is a conforming superset of Sirius. Moving a larger string to a smaller fixed string results in the data being truncated on the right. When moving a string into a fixed length string of greater size, the data in the fixed string is padded with nulls (ASCII 0) on the right. Sirius also handles CHARACTER arrays as if they were fixed strings with a length equal to the maximum array offset. If the array's lower bound is 0, the string's length is stored as a value from 0 to 255 in that offset. If the array's lower bound is -1, the string's length is stored as a value from 0 to 65535 in the two lowest array offsets. CHAPTER 1 Page 7 1.4.1.4. NUMERIC Family The NUMERIC family consists of eight data types - INTEGER, REAL, RATIONAL, FIXED, IMAGINARY, IMRAT, COMPLEX, and COMRAT. INTEGER data defaults to a length of two (2) bytes (optionally larger), and has a minimum size of one (1) byte. UNSIGNED may preceed the type specifier, in which case the indentifier will always be positive (zero or above) and will be one order of magnitude larger in the positive range than signed equivalents. The internal representation is two's complement (the high order bit being the sign, if there is one). The BYTES n specification will change the default to n bytes of mantissa. Moving data from an integer identifier of one size to another of smaller size will result in the highest bits being lost from the larger value. Expressions which use more than one type of numeric data cause the compiler to promote the various values to the largest-common denominator of all numeric types used in the expression and, in the case of assignments, the type of the identifier being assigned the value is also considered. The following table lists the data types in the order of promotion. The compiler promotes all values to the data type highest in the table which is being used: COMRAT COMPLEX RATIONAL, IMRAT REAL, IMAGINARY FIXED INTEGER literals Further, once the data type is determined, the compiler also determines the size of the data type to be the minimum necessary to maintain the precision of the largest data type within the expression. Finally, if some values are signed and some are unsigned, all values are promoted to signed. The extra bit for the sign in unsigned values is taken into consideration when the size of the promotion is determined. Once the expression is evaluated, the result is converted from the promotion type to the assignment type, if necessary. 1.4.1.4.1. INTEGER Variables of INTEGER type are whole numbers within the range dependent upon the number of bytes of length. For signed numbers the range is -2^(size x 8) to 2^((size x 8)-1)-1. For unsigned numbers the range is 0 to 2^(size x 8)-1. 1.4.1.4.2. REAL REAL data is stored as mantissa and exponent. The highest order bit of the exponent is the sign bit (unless it is unsigned, in which case the high order bit extends the range of the exponent). The highest order bit of the exponent is the exponent sign. The CHAPTER 1 Page 8 default size is 3 bytes of mantissa and 1 byte of exponent. The format is standard floating point format and is always normalized after each operation. The BYTES n specification defines the size of the mantissa. If EXPONENT n follows the data type specifier, the exponent will be of n bytes in length. Comforming superset compilers may default REAL data to 2 bytes of exponent and 6 bytes of mantissa. The size of the exponent may be from 1 to 65536 bytes. The minimum size is one byte of exponent and one byte of mantissa. Moving a real to an integer results in the real value being tuncated to be integer and then truncated in the high bits if needed. When a large integer or real value is moved to a real with a smaller mantissa, accuracy is lost and the exponent makes up the difference. If the exponent is also too small, an error will occur (see Numeric Error). Variables of the REAL type have whole and/or fractional parts (floating point). 1.4.1.4.3. FIXED FIXED data is stored as a whole part and a fractional part. The highest order bit of the whole part is the sign bit (for SIGNED variables). The default size is two (2) bytes for the whole part and two (2) bytes for the fractional part. The WHOLE n modifier defines a different size for the whole part in bytes. The FRACTIONAL n modifier defines a different size for the fractional part in bytes. 1.4.1.4.4. RATIONAL RATIONAL data is a compound data type (consisting of more than one element), which consists of two integer values. One serves as a denominator and one as a numerator. This allows higher resolution of floating point numbers in less memory space. The values are simplified automatically by the compiler OTS upon completion of each arithmetic operation but are never evaluated by division except when being output or being used in an expression that is assigned to a non-RATIONAL identifier. Each of the two integer elements have the exact same format of the INTEGER data type and may be signed (default) or unsigned. The BYTES n specification is rounded down to the nearest even value (if odd) and divided by two. This value then becomes the length of each integer value. The default size is 4 (2 for each integer) and the minimum is 2 (1 for each integer). The default size may optionally be larger in conforming superset compilers. 1.4.1.4.5. IMAGINARY IMAGINARY data is exactly the same as REAL, except that it is considered imaginary. It is incompatible with all other data types except numeric literals (which will be considered imaginary when used in expressions relating to this data type) and IMRAT. CHAPTER 1 Page 9 1.4.1.4.6. IMRAT IMRAT data is exactly the same as the RATIONAL data type except that is considered an imaginary value. As a result, it is incompatible with all other data types except numeric literals (which will be considered imaginary when used in expressions relating to this data type) and IMAGINARY. 1.4.1.4.7. COMPLEX COMPLEX data is a compound data type that consists of one element of REAL and one element of IMAGINARY. Its default size is therefore 8, and its minimum size is 4. If BYTES n is specified, the value is rounded down to the nearest multiple of 4 (if it isn't already) and divided by two. This is then used as the length of the mantissa for both elements. If EXPONENT n is specified, it is rounded down to the nearest even number (if it is odd) and divided by two. This value is then used for both exponent sizes. 1.4.1.4.8. COMRAT COMRAT data is a compound data type consisting of one element of IMRAT and one element of RATIONAL. The default size is 8 (optionally larger) and the minimum size is 4. If BYTES n is specified, the value is rounded down to the nearest mulitple of 4 (if it isn't already), and this value is halved to determine the size of both elements. Moving from COMPLEX or COMRAT to REAL or INTEGER results in only the non-imaginary part being assigned. Moving from COMPLEX or COMRAT to IMAGINARY or IMRAT results in only the imaginary part being assigned. 1.4.1.5. PROCEDURE Family The PROCEDURE data type is a way to indirectly execute procedures. Internally, it is stored as the address of a procedure. Identifiers of this type can only be assigned the names of procedures and are incompatible with all other data types. Pointers to procedures are undefined. Variables of PROCEDURE type are different from other variables because they can be used in the DO statement. The internal size of this data type is hardware dependant, being as large as code addresses can be. The DO statement has the format: DO i where i is a variable of PROCEDURE type. When this statement is executed, the procedure assigned to i is executed. If i is undefined, an error results (See Undefined Procedure). For example: DO Routine CHAPTER 1 Page 10 1.4.2. Composite Data Types Composite data types (not to be confused with compound data types) are collections of simple and/or compound data types. They are specified with a type modifier between the keyword "AS" and the type specifier. There are eight different modifiers allowed. They may also be nested to create compound-composite data types. o The LIST OF defines a linked list of a data type. The list is doubly linked and circular. For example: DECLARE MyList AS LIST OF INTEGER o The FILE OF defines a set of data that is of undefined length and exists on a device other than memory. For example: DECLARE External_File AS FILE OF REAL o The INTERNAL FILE OF is the same as FILE OF except that memory is the device that is used. Therefore the data written to it is valid only so long as the program is executing. For example: DECLARE Internal_File AS INTERNAL FILE OF IMAGINARY o The STACK OF defines a push/pop stack of a data type. For example: DECLARE MyStack AS STACK OF COMRAT o The QUEUE OF defines a set of data that is stored in queue. For example: DECLARE MyQue AS QUEUE OF RATIONAL o The ARRAY (x,y) OF defines a set of data that is y-x+1 elements long. x represents the lowest subscript that may be used, while y represents the highest subscript value that may be used. For example: DECLARE X AS ARRAY (1,100) OF INTEGER o The SPARSE ARRAY (x,y) OF defines a set of data that is from zero to x elements long but is allocated from dynamic memory and can be sparse. The only elements kept in memory are as follows: For UNDEFINED: Only those elements which have been assigned a value. For LOGICAL: Only those elements which are TRUE. For CHAR: Only non-null characters are kept. For STRING: Only those elements which are non-zero CHAPTER 1 Page 11 length. For NUMERIC: Only those elements which are non-zero. For PROCEDURE: Only defined elements are kept. For example: DECLARE Y AS SPARSE ARRAY (1,100) OF INTEGER 1.4.3. Records and Objects Objects are a combination of data and routines. The simplest form is a standard record with no routines defined. You may define routines within a record to create objects, whose data and routines can be inherited by other objects. Records contain a collection of one or more data types. Individual items in a record are referenced by the identifier name followed immediately by a period, followed immediately by the field name. Each field is defined following the RECORD keyword. The record defines a type which variables can later be cast as. For example: RECORD Vehicle DECLARE Color AS INTEGER DECLARE Body AS INTEGER DECLARE Model AS STRING END DECLARE Bus AS Vehicle The components of the record can now be accessed as Bus.Color, Bus.Body, and Bus.Model. Further, you can define other records which are supersets of a record. In these cases the original record is referred to as an "object" and the superset record is said to "inherit" the fields of the object. In this case, one or more fields are defined as "OBJECT o", where "o" is the object name. The object MUST be a user defined type that is (and ONLY is) a record. For example, given the type definition above, Vehicle can be considered an object and can be referenced in another record like so: RECORD Car OBJECT Vehicle Wheels AS LOGICAL Back_Seat AS LOGICAL END DECLARE Porshe AS Car Since the variable "Car" inherits the fields in object "Vehicle", we can now refer to the following fields: Porshe.Color, Porshe.Body, Porshe.Model, Porshe.Wheels, and Porshe.Back_Seat. The keyword "LOCAL" can be used to define all following record fields as only accessable to routines defined within the record. The keyword "PRIVATE" can be used to define all following record fields as available only to routines defined in the routine and those defined in records which inherit these fields. All routines defined before the END of the record are encapsulated in the record. A specific routine within an object is called a method and can be referenced by name for variables defined as the object within which the method is defined, and for an descendant objects. A Method of one name will hide a method of the same name in an ancestor object. However, the ancestor method can be specifically referenced by placing the object name and a dot in front of the method name (eg Car.Init calls the CHAPTER 1 Page 12 Init method defined in object Car). Although methods can be over-ridden in descendants, fields may not be. To reference an element in an array or a sparse array, the identifier must be followed by the element within parentheses. Nested arrays (multiple dimensions) have their elements specified with each element from the most outward (the first) to the most inward (the last), within the parentheses and separated by commas. Lists, queues, and stacks are accessable only via Sirius functions. The nesting of composite data types is allowed to eight levels. More levels may be allowed in conforming superset compilers. 1.4.4. User-defined Data Types Data types may be defined in the source code by using the DECLARE statement with a TYPE OF type modifier before the type specification. All user-defined types muat be specified before they are referenced. In this case, a RANGE modifier is allowed on the end of the type information, followed by a literal that represents the lowest possible value, a comma and a literal that represents the highest possible value. For example: DECLARE Age_Range AS TYPE OF INTEGER RANGE 0,120 DECLARE Old_Age, New_Age AS Age_Range Old_Age and New_Age are thus defined as variables that can store an integer number between 0 and 120, inclusive. 1.4.4.1. Scalar (enumerated) data types Scalar data types are allowed by using the word "SCALAR" as the type. The valid values for the type then follow within parentheses. For example: DECLARE Color AS SCALAR (red, blue, green) would declare an identifier named "Color" with the possible values of "red", "blue" or "green". The names used may not be reserved words, but are otherwise considered local to the definition. That is, another scalar may use one or more of the same words as possible values. Different scalars are considered to be different data types and cannot be used in the same expression, even if both have the exact same possible values. When doing input using a scalar, Sirius converts the input to the proper internal value representing the input, non-valid input results in an error. When doing output, Sirius converts the internal representation of the scalar to the proper word as defined at compile time. Scalars passed to external routines lose all but their internal representation within the external routine. CHAPTER 1 Page 13 1.5. Literals There are three types of literals: STRING, NUMERIC, and LOGICAL. A string literal is a set of characters bounded by quotes (') at each end. Quotes may also be embedded by placing two of them adjacent to each other. They are then considered to be one quote within the quotes that delimit the string. Any characters, except where otherwise noted, are allowed in the string literal. For example: 'This is a string literal.' Numeric literals simply consist of a series of digits, with or without a decimal point, that represent a number. They may be signed but if not, are assumed to be positive. (+ represents positive and - represents negative). Scientific notation is allowed by placing an E immediately at the end of the number, followed by a plus (+) or minus (-) and a number representing the power to raise 10 by and then muliply the preceeding number by. For example: 2.436756E+3 Logical literals are "TRUE" and "FALSE". 1.6. Constants Constants are identifiers that are of a fixed value and must be defined before they are referenced. They are defined with the statement: CONSTANT i AS t := v where i is the constant identifier name and v is the value to use, which must be a literal, a previously defined constant, or an expression using literals or previously defined constants. t is the data type of the constant. For example: CONSTANT X AS REAL := 4.2567 Structured constants are defined with the format: CONSTANT i AS ARRAY(x,y) := v v is a list of values, each separated by a comma. The first item is assigned to the zeroeth element of the last dimension of the array. For example: CONSTANT Table AS ARRAY(1,2) OF ARRAY(1,2) OF INTEGER := 0,0,1,1 CHAPTER 1 Page 14 1.7. Operators In conditional expressions, all possible operators of all families may be employed. Within a family, the operator precedence and other rules follows in the text. In a multi-family situation, the order is always left to right and with the following order of precedence (listed in order from highest to lowest). All operators have a precedence between 0 and 32767. The higher the value, the higher the precedence. Two operators next to each other in an expression and with the same precedence evaluate from left to right. Tilde (~) - described below Numeric and String operators Relational operators Logical operators 1.7.1. Numeric Operators Numeric operators apply to all data types in the numeric family, except where noted. They are listed in order of precedence from highest to lowest as follows: :(x,y) Bit subset. This must immediately follow the identifier name which it is to act upon. This may only be used on integers and always returns an unsigned integer value. It returns an integer value that is represented beginning at bit x for y bits in the integer (see internal representation for integers). This operator may also be used on the destination (or target) side of an assignment in order to set certain bits. Precedence=15000. (, ) Parentheses. Precedence=14900. ! Factorial. This works on the value immediately preceeding it. Precedence=14800. +, - Unary plus and minus. These must immediately preceed the indentifier on which they are to act. Unary plus ha no effect, whereas unary minus negates the value of the following identifier. Precedence=14700. ^ Exponentation. This works from right to left as opposed to all other operators which work from left to right. In other words, the rightmost exponentation is done first. Precedence=14600. CHAPTER 1 Page 15 *, /, % Multiplication, division, and percentage (divide by 100). Precedence=14500. +, - Addition and subtraction. Precedence=14400. 1.7.2. String Operators String operators in order of precendence from highest to lowest: :(x,y) Substring. This operator may be used on the target and/or source side of the assignment and represents the substring beginning at byte x for y bytes in the identifier that immediately preceeds it. Precedence=15000. \ Concatenation. Precedence=14800. 1.8. Relational Operators Relational operators have no order of precendence and are as follows. They work on comparisons of any data type except undefined. In the case of logical data types, false is considered less than true. In the case of strings, the ASCII collating sequence determines the result. < Less than. Precedence=12000. > Greater than. Precedence=12000. = Exactly equal to. Precedence=12000. # or <> Not equal to. Precedence=12000. <= or =< Less than or equal to. Precedence=12000. >= or => Greater than or equal to. Precedence=12000. == Equal to. When this is used on an integer or logical data type, it works exactly as the = operator. When used on real numbers, some of the least significant bits are zeroed. This results in an "almost equal to" condition and helps avoid cumulative round-off errors. The bits that are zeroed are the lowest two in the mantissa, where "lowest" is defined as the lowest set bit and the one immediately more significant than it. On string data, the strings have all spaces (ASCII 32) and nulls (ASCII 0) ignored during the comparison. Precedence=12000. CHAPTER 1 Page 16 1.8.1. Logical Operators Logical operators have no precedence except for NOT, which has a higher precedence than all other logical operators. NOT Complements the value (changes true to false or false to true). This works on the expression which follows it. Precedence=10000. & AND. If the expressions on both sides of the operator are true, the result is true. It is false otherwise. Precedence=9900. N& NAND. If the expressions on both sides of the operator are true, the result is false. It is true otherwise. Precedence=9900. OR If either expression to either side of the operator are true, the result is true, otherwise it is false. Precedence=9900. NOR If either expression to each side of the operator are true, the result is false, otherwise it is true. Precedence=9900. XOR Exclusive OR. If both expressions to either side of the operator are unequal (one is true and one is false), the result is true, otherwise it is false. Precedence=9900. XNOR Exclusive NOR. If both expressions to either side of the operator are equal, the result is true, otherwise it is false. Precedence=9900. One additional operator exists for all identifiers, regardless of type. It is ~ (a tilde), which must immediately preceed the identifier name and returns an unsigned integer value which is the memory address of the variable (or in the case of dynamically allocated items), the pointer address. Pointer addresses are the location of pointers to the header information for the item in question. The ~ operator has a precedence of 16000. 1.8.2. User-defined operators All operators mentioned in the preceeding sections may be redefined by the programmer. Additional operators may be defined in the same way. The way to define the operator is to use the DEFINE statement. The definition of an operator ends with the ENDDEFINE statement. The general form is: DEFINE o AS p {t} statements... CHAPTER 1 Page 17 ENDDEFINE where o is the operator to define. It must be enclosed in quotes ('' means to define ' as an operator. This is allowed but not recommended.) p is the precedence level of the operator. t is the type of operator it is and also defines how the operand(s) are processed within the same precedence level: RIGHT means a monadal that operates on the operand to its immediate right. LEFT means a monadal that operates on the operand to its immediate left. LEFTRIGHT means a dydatic whose precedence proceeds from left to right (the default). RIGHTLEFT means a dydatic whose precedence proceeds from right to left. IF...THEN statements may be used to determine the action performed dependent upon the data type being used. No compile-time errors will result from using the operator in an invalid context. The error will occur at run time. The left-hand operand will be referred to by the identifier name: LHS and the right-hand operand will be referred to by the identifier name: RHS. The result of the operation is defined by assigning the desired result to the identifier: RESULT. The type of the operand is determined by using the IF...THEN and the function TYPE(). TYPE() is a scalar which has the possible values of any user-defined typename, and the data types CHARACTER, STRING, IMAGINARY, COMPLEX, REAL, RATIONAL, FIXED, COMRAT, IMRAT, INTEGER, UNDEFINED, LOGICAL, RECORD, and PROCEDURE. The FAMILY() function is a scalar which has the possible values of: NUMERIC, UNDEFINED, LOGICAL, CHARACTER, PROCEDURE, and USER (for user-defined structures). USER is also returned for the RECORD structure. User-defined operators (and redefined operators) may not be defined recursively. The use of a user-defined (or redefined) operator within an operator definition results in one of the two following possibilities: 1) If the operator used is not a redefinition of a pre-defined operator, an error occurs. 2) If the operator used is a pre-defined operator, the operator performs its pre-defined operation. For example: DEFINE '+' AS 24001 @ Redefine the plus operator to include string concatenation @ IF TYPE(LHS)<>TYPE(RHS) THEN ERROR := 16384 ELSE IF TYPE(LHS)=STRING THEN RESULT := LHS\RHS ELSE IF FAMILY(LHS)=NUMERIC THEN RESULT := LHS+RHS ENDIF ENDIF ENDIF ENDDEFINE CHAPTER 1 Page 18 1.9. Assignment Statements An assignement statement has two sides. The target (or destination) and the object (or source). It has the format: target := object First the object expression is evaluated and the result is then assigned to the target idnetifier. The identifier and object expression must be in the same data type family. Literals and constants are not allowed on the target side of the statement. For example: This_Year := Last_Year + 1 1.10. Expression Evaluation Expressions are analyzed based on the orders of precedence and the order in which operators are encountered. The right hand side of an expression is always evaluated first, then the left hand side. During evaluation of a numeric expression, the data types of the individual elements are converted (or forced) to the same data type. The data type they are converted to is the size of the largest data type found in the expression. Reals are considered larger than integers in all cases and compound data types are considered larger than simple data types. Note that this method may result in overflow or truncation in certain special cases. 1.11. Memory Though this feature can make for non-portable programs, the very use of it indicates either poor programming or an application which will never be ported exactly as is anyway (such as an operating system). The MEMORY statement allows the programmer to define an array that maps all of memory. The format is: MEMORY i IS t {AS v} where i is the identifier to be used in accessing memory, and t is the type of each element of memory. v, if present, is either "VIRTUAL" (default) or "PHYSICAL". VIRTUAL means that the array never accesses memory outside the virtual job (program) space. PHYSICAL means all addressable physical memory. Since this maps over existing memory (including the program potentially), it takes up no space, and several arrays may be defined to partition memory in several ways. Note that on systems with separate code and data segments, the memory arrays will be defined solely in the data segments if the array is virtual. An identifier may also be defined as occupying a specific address in memory by using: ABSOLUTE a CHAPTER 1 Page 19 followed by the identifier declaration, where a is a constant representing the byte in memory where the following identifier is to begin. For example: ABSOLUTE 10240 Image_Prefix AS INTEGER 1.12. Array Operations Operations on arrays, without subscripts provided, result in the operation begin performed on each element of the array. Therefore an entire array may be moved with one assignment statement. Moving a larger array to a smaller one results in only that portion of the larger one being moved that fits into the smaller one. 1.13. Initialization Upon beginning to run a program, all numeric variables are set to a value of zero (0). Strings are either null or filled with nulls (ASCII 0) if they are of fixed length. Logical variables are set to false and undefined variables are left undefined and should be initialized before use. Any variables subject to RANGE constrictions will be initialized to their lowest possible value. Nulls are not considered to be part of the range, and strings will still be filled with them. Scalars will be initialized to the first enumerated item. 1.14. Nesting and Recursion All sirius routines are recursive, that includes functions, procedures, and the main program itself. All local identifiers are saved upon any call to a function or procedure in a stack frame (note that a "stack frame" does not physically have to be on the stack). Three possible situations will activate a stack frame: 1) a call to a function, 2) a call to a procedure, or 3) an error (effectively a call to the current error routine). When a stack frame is activated, the appropriate stack for the call type (1, 2, or 3) has the return address pushed on it. The end of a particular call will result in the return address being popped from the appropriate stack and the current stack frame being deallocated. The last stack frame becomes the new current one. 1.15. Comments Comments may occur beginning anywhere and ending anywhere except in the middle of a token. Upon encountering a comment, the parser determines that the current token ends there. Comments are included between commercial "at-signs" (@). CHAPTER 1 Page 20 1.16. External Modules Since Sirius is a compiled language, allowances are made for linking in separately compiled modules. These modules must be defined before they are referenced in the source code. The statement for doing this is: EXTERNAL t IS CALLED n {BY c} where t is the type of the module (OBJECT FUNCTION, TARGET FUNCTION or PROCEDURE), n is the name and the optional c is the call type. Call types are (REFERENCE, VALUE, and NAME). REFERENCE is the default. When calling an external module, regardless of call type, three items are passed to the module: 1) module type (0= Object function, 1=Target function, 2=Procedure), 2) call type (0=Reference, 1=Value, 2=Name), and parameters passed. The rest of the record passed is dependent upon the call type. For reference calls the record contains a data type and a pointer to the value in memory. For value calls the record contains a data type, a length, and then the information in the identifier. For name calls, the record conatins a data type, a name length and the name of the identifier. Object function call records contain one additional piece of data before the pointers, etc, and that is a pointer to the memory management table, where the result is to be stored. 1.17. Labels A label is a non-excutable name which may be referred to by a GOTO statement. The label must be after the end of the previous statment, before the beginning of the next, and must be alphanumeric, ending with a colon (:). For example: Loop: 1.18. Statements A program begins with the PROGRAM statement. END terminates the program source code. Note that one program may be considered a procedure for another. Formats: PROGRAM name END where name is the name of the program or external procedure. END will cause all wrap-up operations necessary, including the closing of files and error information, if appropriate. CHAPTER 1 Page 21 1.18.1. STOP Statement Execution of a program may be terminated with the STOP statement. This has the same run-time effect as the END statement, but the compiler does not stop execution when encountered. Examples: PROGRAM Payroll STOP END 1.18.2. FIELD and UNFIELD Statements Identifiers may be reassigned to point to a file buffer during run-time. This allows for very flexible file I/O. Each identifier retains a place in memory which it recovers when unfielded. When it is fielded, it will point to an address which is some point within a file buffer. Attempting to field an identifier past the end of a buffer will result in an error. Attempting to unfield an identifier which has not been fielded has no effect. To field: FIELD i {AS l} OFFSET n where i is the identifier to assign. If the identifier is a string, the AS modifier may be used to specify a length l. n represents the offset into the file's buffer (0 is the beginning of the buffer). To unfield: UNFIELD i where i is the identifier to unfield. Examples: FIELD Name AS 16 OFFSET 0 UNFIELD Name 1.18.3. Branching Several types of branching constructs are allowed in Sirius. 1.18.3.1. GOTO Statement Unconditional branching occurs with the GOTO statement. The format is: GO TO label CHAPTER 1 Page 22 where label is the label to transfer control to. The label specified must be within the same scope as the code block where the GOTO occurred. 1.18.3.2. CASE Statement The CASE statement allows conditional execution of code dependent upon the contents of an identifier. The format is: CASE identifier ON expression {,expression...} : statements {OTHERWISE : statements} ENDCASE where identifier is the determining value. expression is an expression, which (if identifier matches) causes the statements following the colon (:) to be executed. If OTHERWISE is included, the statements following it are executed in the case that no values specified matched the identifier specified. ON specifiers following the OTHERWISE specifier within the same CASE structure are ignored. Note that "ENDCASE" must be one word. If multiple expressions are used, they are effectively ANDed together. For example: CASE Age ON <13 : OUTPUT('You''re young') ON >12, <20 : OUTPUT('You''re a teenager') ON >19, <30 : OUTPUT('You''re a young adult') ON >29 : OUTPUT('You''re old') ENDCASE 1.18.3.3. IF Statement Conditional branching is done with the IF...THEN...ELSE...ENDIF construct. Following the IF must be an expression that when evaluated results in a logical TRUE or FALSE condition. If the condition is true, then the statements following the THEN are executed. If the condition is false and ELSE is included, the statments following the ELSE are executed. Statements after the ELSE are terminated by the ENDIF. Statements after the THEN are terminated by the ELSE (if present) or the ENDIF. Format: IF logicalexpression THEN statements ELSE statements ENDIF CHAPTER 1 Page 23 1.19. Loops Loops constructs begin with a loop type statement and end with a NEXT. The NEXT statement defines the terminal point of a loop and refers to the last matching loop (since loops may be nested). Format: WHILE (logicalexpression) statements NEXT where "logicalexpression" is an expression which determines the number of times the statements within the loop body are executed. Loop expression testing occurs at the beginning of the the loop with the loop type statement, if the logical expression exists there. Loop expression testing occurs at the beginning of the loop with the NEXT statement if the logical expression exists there. The logical expression must appear at one and only one end of a loop. The NEXT statement causes execution to go back to the loop type statement. When the logical expression results in a loop end, the statement following the matching NEXT statement will be executed. Loop types: WHILE (condition) Loop until condition is false. (or NEXT condition) UNTIL (condition) Loop until condition is true. (or NEXT condition) FOR {i=start TO} end {STEP n} Loop end times. If the optional (or NEXT {i=start TO} end {STEP n} elements are included, the variable i is assigned the value start and is incremented until it equals end. If STEP is included, the variable is incremented by the value n. To leave a loop without the terminating condition, use the EXIT statement. Examples (each loop performs the same function): WHILE (A=B) Destination(A) := Source(B) A := A+1 NEXT FOR C=A TO B Destination(C) := Source(B) NEXT CHAPTER 1 Page 24 C := A FOR Destination(C) := Source(B) NEXT C=A TO B UNTIL Destination(A) := Source(B) A := A+1 NEXT A>=B WHILE Destination(A) := Source(B) A := A+1 NEXT A0) OUTPUT NEXT END A procedure which allows a variable number of parameters may be defined as: PROCEDURE n IS i ({s,...}) where n is the name of the procedure and s is a specification for data passed. i is an identifier that is an integer array. This array is filled with pointers to the passed data when the procedure is called. Procedures are ways of defining non-external program modules and may appear as the only code in an external procedure. They end with the END statement. Each specification defines what the valid data types are that may be passed. They have the format: data-type-name {data-type-name ...} and each specification is separated from the next with a comma. A data-type name may be "ANY" to allow all data-types. An asterisk may be placed in front of the data-type name for any parameter to indicate to the compiler that the specified value will be modified and should not be constant if the data type matches (will generate an error). At compile time, any reference to a procedure with invalid data-types will result in an error. The size of the pointer array defines the maximum number of data elements that may be passed, but fewer may be passed with no compile-time errors. The identifier PASSED holds the number of passed elements. If there are more data-type specifications than elements in the pointer array, the extra are ignored. If there are fewer data-type specifications than elements in the pointer array, the extra data elements (if any) are allowed to be any type. An external procedure may be defined in the same way by placing the word EXTERNAL in the front and changing i to a numeric literal which represents the maximum number of allowable data elements for the procedure. The TYPE() and FAMILY() functions are used to determine the type of some passed data. "GLOBAL" prior to the PROCEDURE keyword indicates a procedure which will be global. When a parameter can vary in data type, the "CAST" statement is used to inform the compiler that a variable is to be treated as a specific data type, regardless of how it was defined in the DECLARE statement. For example: DECLARE Print_Array AS ARRAY (1,8) OF REAL PROCEDURE PRINT IS Print_Array (ANY, ANY, ANY, ANY, ANY, ANY, ANY, ANY) @ This procedure outputs the print array, rounding all real data @ CHAPTER 1 Page 27 DECLARE A AS INTEGER FOR A=1 TO PASSED IF TYPE(Print_Array(A))=REAL CAST Print_Array AS REAL THEN OUTPUT(ROUND(Print_Array(A),2),NCM) CAST Print_Array AS INTEGER ELSE OUTPUT(Print_Array(A),NCM) ENDIF OUTPUT NEXT END 1.24. Functions Sirius has two kinds of functions: target and object. Like procedures, there are two types. The first form is defined as: {t} FUNCTION AS d (list) "t" is "TARGET" or "OBJECT" (default). "d" is the function's return data type (or accepting data type in the case of a target function). "list" is a list of parameters, separated by commas, each of which is in the form: {type} name The second form is defined as: {t} FUNCTION n AS d IS i ({s,...}) where t is "TARGET" or "OBJECT" (default), n is the function name, d is the function's return data type (or accepting data type in the case of a target function), i is the pointer array, and s is specifications. The specifications and pointer array are described in the section on procedures. EXTERNAL may be placed in front of the function definition to define the qualities of an external function. Internal functions end with an END statement. Target functions are only allowed on the left-hand-side of an assignment statement while object functions are only allowed on the right-hand-side of an assignment statement. Within the function body, a target function may reference the value assigned to it by placing the function name on the right-hand-side of an assignment statement. The value of an object function may be set by placing it on the left-hand-side of an assignment statement within the function's code. "GLOBAL" may preceed the FUNCTION statement to define a global function. Example: DECLARE Percentage_Array AS ARRAY (0,0) OF INTEGER; FUNCTION Percentage AS INTEGER IS Percentage_Array (REAL) @ Return a percentage in form 0.nn as nn (.99 becomes 99, etc) @ Percentage := Percentage_Array(0)*100 END CHAPTER 1 Page 28 1.25. Sorting Lists, arrays, stacks, and queues are sorted with the sort procedure. The format of this procedure is: SORT(i{,t}) where i the identifier to sort, and t is optionally ASCENDING (default) or DESCENDING. Lists, stacks, and queues are sorted within their range, while arrays are sorted with the lowest offset being the first value of the sort result. For example: SORT(Population_Samples,DESCENDING) 1.26. Sirius Standard Routines Sirius has several standard routines which can act either as procedures or functions. The procedure is a means of extending the small, but robust, set of statements. 1.26.1. Co-Processing Sirius supports co-processing with the COBEGIN procedure. Execution of this procedure causes a separate run-stream to begin execution while the original code continues after the COBEGIN invocation. Additional run-streams can be started by the original run-stream or any co-procedures. All run-streams started directly or indirectly by the original run-stream share the same global variables, but have separate local copies of other variables. An attempt to COBEGIN a procedure which references variables that are not local in scope to that procedure or GLOBAL will cause an error and the new run-stream will not start. The format of the COBEGIN procedure is: COBEGIN(procedure) where "procedure" is the name of the procedure to invoke in the new run-stream. Implementation details are left to the implementers. The number of simultaneous run-streams allowed is entirely up to the implementers. A run-stream created by COBEGIN runs until the procedure passed to COBEGIN exits. The procedure can call any number of other functions or procedures however. To synchronize operations between different run-streams, the TEST function is used (see later section on functions). Any I/O done via the same file identifier by two or more run-streams is done in order of access to the identifier. While an I/O operation is executing for one run-stream, any attempt to access that identifier in another run-stream will cause the second run-stream to pause until the current I/O operation has completed. The BUSY function can be used to determine if an I/O operation is currently executing on a file identifier. It returns TRUE or FALSE. The optional second CHAPTER 1 Page 29 parameter can be TRUE to indicate that the file identifier is to be reserved for this run-stream. Reserving the file identifier makes the identifier busy for all run-streams until the run-stream calls BUSY again with the second parameter FALSE. Attempts to reserve a busy file identifier fail. Format: x = BUSY(identifier {,boolean}) To avoid excess CPU time used in testing semaphores for synchronization between run-streams, the WAIT and SIGNAL procedures can be used. WAIT will pause execution of the current run-stream until a signal is received from another run-stream. SIGNAL is used to resume execution of a run-stream which has been paused with WAIT. Both procedures accept an integer value. A WAIT invocation with a specific value requires a SIGNAL with the same value. A SIGNAL with an integer value that does not correspond to a paused run-stream has no effect. Formats: WAIT(integer) SIGNAL(integer) 1.26.2. I/O operations I/O may be masked or unmasked. It is unmasked by default. By masking it, it will be encrypted or decrypted as necessary. Encryption consists of a byte substitution specified in a mask string of exactly 256 bytes. Extra bytes are ignored; fewer bytes cause error 32. To remove a mask from a file, use the statement: UNMASK(file) To add a mask to a file, use the statement: MASK(file,maskstring) where file is the file identifier and maskstring is the string identifier to be used during the mask. All data is masked during output (if selected) and unmasked during input (if selected). Masks remain on files even if they are closed, therefore UNMASK should be used upon closing a file. To open a file, use the format: OPEN(i,n,{,a{,r}}) where i is the identifier that defines the file, n is a string containing the name of the file to open, a (if included) is a string which defines the access to the file, and r (if included) is an integer that defines the size of the file's buffer in bytes. r defaults to 512. a has the following possible values: W Write-only access R Read-only access A Append (implies W) RW or WR allow read and write (this is default) CHAPTER 1 Page 30 Closing a file results in flushing the file buffer (if necessary). All files are closed automatically by the END or EXIT statements. The format is: CLOSE(i) where i the file identifier. To force file flushing, use the statement: FLUSH(file) File use may require being able to advance the file pointer either direction within a file buffer. Going beyond either end of the file buffer results in the appropriate section of the file being loaded before the advancement will continue. The format is: ADVANCE(i,n) where i is the file identifier and n is the number of bytes to advance. A negative value advances backwards through the file. An attempt to advance back past the beginning of the file or an attempt to advance past the end of the file results in an end-of-file error (error 4). Sirius allows transfering files with one procedure which is optimized to perform the transfer as quickly as possible given the buffer size of the input file specified. The format is: TRANSFER(i,o) where i is the input file identifier and o is the output file identifier. Note that all data within the output file's buffer is untouched and the output file pointer will be left exactly where it was before the transfer. To output to a file, the following format is used: OUTPUT(f,list) where f is the file identifier and list is a series of expressions, separated by commas, which define the data to be output. A file identifier is only allowed in the first position and if not present identifies output to the standard output device. The special symbol NCM is defined such that placing it as the last element in the list results in no newline character(s) being output. Output of composite data types or user-defined data types results in each element being displayed (as defined) as if it were specifically specified and separated by a comma. Input from a file uses the format: INPUT(f,list) where f is the file identifier and list is a series of expressions, separated by commas, which define the data to be input. A file identifier is only allowed in the first position and if not present identifies input from the standard input device. Each element in the list must be supplied and separated from others by a comma or newline CHAPTER 1 Page 31 character. Execution continues with the next statement after the INPUT only after all requested data elements have been supplied. A special case is the input of a string, in which case the string is the only item allowed on the line and in the list. Another special case is the character array. This functions as a string, with each element filled with the consecutive bytes of the input line. The exception being that the first two elements of the array are used to store the size of the input string. The first character of the string begins in the third element. This is mostly compatible with Pascal string handling. Entering incorrect data for the requested type (alpha characters for a numeric variable for example) results in error 5. Formatted input and output statements are allowed, of the format: OUT(f,s,list) and IN(f,s,list) where f is the file identifier (if absent, it indicates the standard input or output device), s is the formatting string, and list is a list of the data elements. The output will conform exactly to the specified formatting string and the input must match the formatting string exactly or data will be lost. All other rules applying to OUTPUT and INPUT apply to OUT and IN. The formatting string contains special characters which will determine the format. All non-special characters are printed in their place (for OUT) or must be supplied in place (for IN) or error 33 will occur. All special characters must be contained within parentheses to be valid field specifications, they are considered literal data otherwise. The special characters are: xD Integer with x digits (if x is not present, it defaults to 6). . Position of decimal point. , Position of a comma within a number. - Preceeding minus if negative (must preceed the D specifier). -- Trailing minus if negative (must preceed the D specifier). + Preceeding plus if positive (must preceed the D specifier). ++ Trailing plus if positive (must preceed the D specifier). +- Preceeding sign displayed (must preceed the D specifier). -+ Trailing sign displayed (must preceed the D specifier). ?D Any number of digits (and decimal point). ,, Divide following number specification into sets of three digits separated by commas). .. A decimal portion of a number of any size. R All following fields to be right-justified. L All following fields to be left-justified. xC x characters (if x is not present, it defaults to 1). ?C Any number of characters. CHAPTER 1 Page 32 xS x spaces (if x is not present, it defaults to 1). $ Dollar sign to preceed field (must preceed the specifier). $$ Dollar fill empty portion of following field. * Asterisk to preceed field (must preceed the specifier). ** Asterisk fill empty portion of following field. 1.26.3. Other operations The following standard procedures perform miscellaneous operations. BREAK Exits from all currently nested procedure and function calls. This is useful for exiting in the case of a severe error. CHAIN(string) Causes execution of the program to terminate and then passes control to the program specified as the string. DELETE(string) Deletes the file named in the passed string. READ(list) Reads from the data block into the identifiers specified in the list. See the section on data blocks. RESUME Continues execution after the instruction which resulted in an error. If the error occured within a routine, this will cause the next statement after the call to the routine to be executed. RETRY Attempts to perform the action that caused the last error. PUSH(i,x) Pushes item x onto stack i. ADD(l,x,y) Adds item x to list l, position y. QUE(q,x{,y}) Adds item x to queue q. If y=0 or isn't included, then the item is added to the q at position y (the head is position 1). REMOVE(l,x) Removes item number x from list l. DEQUE(q{,x}) Removes item number x from queue q. If x isn't included, the item at the head of the queue is removed. 1.26.4. Misc Functions POP(i) Returns top item from stack i and removes it from the stack. READ_QUE(q{,x}) Returns item x from queue q. If x isn't included, the item at the head of the queue CHAPTER 1 Page 33 is returned. READ_LIST(l,x) Returns item number x from queue q. READ_STACK(s{,x}) Returns item number x from stack s. If x is not included or is 0 then this performs as a non-destructive POP. Item number 1 is just below the top of the stack, etc. FOLLOW(l,x) Returns the number of next item in list l, following item number x. PRECEED(l,x) Returns the number of the preceeding item in list l, preceeding item number x. Item 0 is considered the head of the list and therefore the preceeding item on the list will be the last item in the list. 1.26.5. Error functions The following functions serve to define errors at run-time. ERROR Returns the number of the last error. This returns an unsigned integer. If assigned a value, the value assigned becomes a forced error (as if the error occured). If the assigned value is negative, the value is made positive and the error is forced back - that is, it appears to the calling program/statement as an error there. Zero (0) is a special value that indicates that all further errors will automatically be forced back. Assigning ERROR a non- zero value defeats this feature. ERROR_TEXT Returns the text of the error whose number appears in ERROR. This is a string. ERROR_TYPE Returns the type of the error whose number appears in ERROR. This returns a character value as follows: I : I/O error R : Run-Time (OTS) error O : O/S or other error 1.26.6. Bit Manipulation The following functions manipulate bits within integer values. CLEAR(i,v) This proceudre resets all bits in the identifier i that match the bit configuration in v. This only works on integers. CHAPTER 1 Page 34 COMPARE(i,v) This function returns an unsigned integer that represents the the bit pattern of v and identifier i ANDed together. This only works on integers and is used to check for the condition of certain bits. SET(i,v) This procedure sets all bits in the identifier i that match the bit configuration in v. This only works on integers. 1.26.7. Heap functions The heap is an area of memory (real or virtual) where data can be dynamically allocated or deallocated. The heap has both allocated and deallocated areas. If sufficient space exists, allocation will be from the deallocated area, otherwise new space is allocated. Each allocated space has a length that prevents improper pointer use from damaging other areas, however if the pointer used does not point to the proper place, the heap may become garbaged anyway. The following routines provide for heap management. ALLOC(x) Returns an integer which is to be used as a pointer to the heap. It allocates enough space for identifier x. DEALLOC(x) This procedure deallocates heap space pointed to by integer pointer x. HREAD(x) Returns data from the heap via integer pointer x. Amount of data returned is dependent upon the left-hand-side identifier. If a string is on the left-hand side, the amount returned is the current length of the string. HWRITE(x,y) This procedure writes identifier y onto the heap at position pointed to by integer pointer x. ZERO Zeros the entire heap. Everything is lost. This is a procedure. 1.26.8. Numeric Functions The following functions provide mathematical functionality. ABS(x) Returns absolute value of x. Return type matches x. ARCCOS(x) Returns arc-cosine of x. CHAPTER 1 Page 35 ARCSIN(x) Returns arc-sine of x. ARCTAN(x) Returns arc-tangent of x. BINARY(x) Converts string identifer x into a numeric data type as defined by the contents of the string (an ASCII to numeric conversion). BYTE(x) Returns current byte position within the file buffer defined by file x. COSINE(x) Returns cosine of x. CVT(x,b1,b2) Returns a string consisting of a converted string x. x is assumed to be a value in base b1. It is converted to base b2. E Constant equal to 2.7182818284590452353602874. Accuracy depends upon the format of the left-hand-side variable. EQUAL(x) Converts string identifier x into a numeric data type as defined by the left-hand-side of the expression (if there is one) or as a signed real. The value is determined by the bit configuration in string variable x. EXP(x) Returns the exponential of x. FRAC(x) Returns the fractional portion of x (x-INT(x)). INFINITY Constant equal to infinity. Only valid with floating-point numbers. INSTR(x,y,z1{,z2...}) Returns the location of string z1 within string y, beginning at character position x. Value returned is always absolute rather than relative to x. It returns 0 if z1 is not found. Up to six (6) search strings may be specified, in which case, the function returns the position of the first matching string. RINSTR(x,y,z1{,z2...}) Returns the location of string z1 within string y, beginning at character position x. Value returned is always absolute rather than relative to x. It returns 0 if z1 is not found. The search begins at position x of the string and moves backwards until the search string is CHAPTER 1 Page 36 found (ie reverse of INSTR). Up to six search strings can be specified. INT(x) Returns the integer portion of the real variable x. LENGTH(x) Returns length of string x. LOG(x) Returns the natural logrithm of x. LOG(x,y) Returns the logrithm of x, base y. MAX(x,y) Returns the minimum value of either x or y. MIN(x,y) Returns the maximum value of either x or y. PASSED Number of arguments passed to the current routine. PI Constant equal to 3.14159365358979323846264338. Accuracy depends on variable format. RANDOM(x) Returns a random number whose value is 0 to x. RECORD(f) Returns current record pointer within file f. File format declaration defines what a record is. 0 is the first record, -1 means the file is not open. ROOT(x,y) Returns the y root of x. If y=2 then it returns the square root, if y=3 then it returns the cube root. ROUND(x,y) Returns x rounded to y places past the decimal. SINE(x) Returns sine of x. SIGN(x) Returns sign of x as follows: if x<0 then SIGN(x)= -1 if x=0 then SIGN(x)= 0 if x>0 then SIGN(x)= 1 The data type returned is equal to data type passed. SIZEOF(x) Returns the number of bytes occupied by identifier x in memory. 1.26.9. String functions The following functions provide for string manipulation. ASCII(x) Returns ASCII character for number x. CHAPTER 1 Page 37 BIN(x) Returns numeric value of x in a string format representing the bit pattern in x. CHAR(x) Returns numeric (ASCII) value for x. EBCDIC(x) Returns EBCDIC character for x (the character is converted to ASCII). EDIT(x,y) Returns string x edited according to the value in y. Bit values for y: & 1 = Trim high bit & 2 = Discard all spaces and tabs & 4 = Discard all nulls, deletes, linefeeds, formfeeds, escapes, and carriage returns. & 8 = Discard leading spaces and tabs. & 16 = Reduce multiple spaces and tabs to one space. & 32 = Convert lowercase characters to upper case. & 64 = Convert [ to ( and ] to ) & 128 = Discard trailing spaces & 256 = Don't alter characters within quotes ("). & 512 = Convert uppercase characters to lowercase. & 1024 = Convert [ to { and ] to } & 2048 = Convert ( to [ and ) to ] & 4096 = Convert ( to { and } to ) & 8192 = Convert { to ( and } to ) & 16384 = Convert { to [ and } to ] Note that for conflicting options, the lower bit value has precedence. EMPTY(w,x,y{,z}) Removes all occurances of string w from string x starting at position y and optionally ending at position z. FAMILY(x) Returns family type of identifier x: NUMERIC, UNDEFINED, LOGICAL, CHARACTER, or COMPOSITE. This is evaluated at compile-time and CHAPTER 1 Page 38 therefore can only be used in comparisons against constants. LEFT(x,y) Returns leftmost y characters of string x. RIGHT(x,y) Returns rightmost y characters of string x. STRING(x,y) Returns a string of CHAR(x) that is y bytes long. TEST(x,y) Used to manipulate semaphores. The semaphore tested is x. If x is zero it is set to value y, otherwise it is left alone. If x is of type LOGICAL, then if it is false, it is set to the value of y. TEST returns a logical value which represents whether or not the function succeeded in setting the semaphore. TYPE(x) Returns type of identifier x. This is evaluated at compile-time and therefore can only be used in comparisions against constants. Page 39 APPENDIX A Errors Errors may happen almost anywhere within a program. Errors may be trapped or left to be handled by the Sirius OTS. Sirius errors are the same no matter what the operating environment is. Sirius Run-Time Errors: Number Type Name Description ------ ---- ---- ----------- 1 I File doesn't exist A file, directory, or pathname does not exist. 2 I File not open Attempt to do I/O on a channel that isn't open. 3 I File exists Attempt to create a new file when an old one by the same name exists. 4 I End of file Attempt to do I/O past the end of a file. 5 R Illegal number Attempt to convert an ASCII value to a numeric value, where the ASCII value isn't a valid numeric value. 6 I Length mismatch I/O request size was not compatible with reality. 7 I File cannot grow A file, directory, or device is full and the write operation cannot be completed. 8 I Write protect violation An attempt to write to a protected, read-only, or hung device. 9 I Data error Parity error occurred during an I/O operation. 10 I Invalid file name An illegal filename, path name, or directory name was supplied. 11 R Too many files An attempt to open more files than are allowed by the O/S. APPENDIX A Page 40 12 I Device type incompatible File-structured I/O was attempted on a non-file- structured-only device, or non-file-structured I/O was attempted on a file-structured-only device. 13 R Division by zero Attempt to divide by 0. 14 O Not enough memory Attempt to use more memory than was available to the program. 15 I Bad directory format A directory had a bad format. 16 I/O Object in use Attempt to access a file or device that is in use by another user, or a similar attempt on some other resource. 17 O Protection violation A protection violation occurred. 18 R/O Input wait exhausted A timed input request was not met in the given time constraints. 19 O Memory data error A parity error occurred in memory. 20 O Stack overflow A stack operation caused an error due to an overflow. 21 R/O Line too long An attempt to input a line that would have caused a "Not enough memory" error, or an attempt to input a line that exceeded the O/S abilities. 22 R Numeric error A numeric operation generated an invalid result. 23 R Imaginary number An expression generated an imaginary number and the destination type was not compatible. 24 R Real number An expression generated a non-imaginary number and the destination type was not compatible. 25 R Subscript out of range A subscript was outside its bounds. 26 R Data exhausted Attempt to read past the end of a data block. 27 I Undefined I/O error Catch-all for I/O errors. 28 O Undefined O/S error Catch-all for O/S errors. 29 R Undefined run-time error Catch-all for run-time errors. 30 R Undefined procedure A DO statement was executed that referenced an undefined PROCEDURE variable. 31 R Heap exhausted The heap was filled. 32 R Mask too short A string used as a file mask was less than 256 characters. 33 I Format error A formatted input statement was passed incorrect data for the current input field. 34 R Stack underflow A POP was attempted on an empty stack. APPENDIX A Page 41 35 R Numeric overflow Numeric overflow occurred. 36 R Numeric underflow Numeric underflow occurred. 37 R Illegal heap access The heap was accessed incorrectly. 38 R Subscript out of range One or more subscripts of an array were outside of the range of values declared by the identifier declaration. 39 R Cannot co-begin procedure An attempt was made to call COBEGIN with a procedure that referenced non-local, non-GLOBAL variables. 40 through 16383 reserved. 16384 through 32767 reserved for implementation specific errors. Sirius Compile-Time Errors: Types: W=warning, E=Error, F=Fatal Number Type Name Description ------ ---- ---- ----------- 1 W Unexpected end of file The end of the source file was encountered before an END statement. 2 E Unterminated data structures An END statement was encountered before all current data structures had been properly terminated (WHILEs require NEXTs, etc). 3 E Syntax error This general error indicates a general source code formatting error. 4 E Reserved word A keyword was used in a non-keyword position. 5 E Expected AS keyword The AS keyword was expected but not found. 6 E Expected data type A data type was expected in a declaration statement but was not found. 7 E Expected OF keyword The OF keyword was expected but not found. 8 E Value out of range A value in a BYTES, EXPONENT, RANGE, etc was less than or greater than the allowed limits. 9 E Type mismatch A DO statement was followed by a non-procedure type identifier, or an assignment statement had two different families on each side of the ":=". 10 E Symbol multiply defined An identifier was defined more than once. 11 E Undefined symbol A symbol was referenced before it was defined. 12 E Expected '(' A left-parenthesis was APPENDIX A Page 42 expected but not found. 13 E Missing right parenthesis A left-parenthesis had no matching right-parenthesis. 14 W Unterminated literal A string literal had no closing quote. 15 E Expected ":=" A ":=" was expected but not found. 16 E Illegal reference A non-label identifier followed a GOTO or RESTORE. 17 E Expected CALLED keyword The keyword "CALLED" was expected but not found. 18 E Expected IS keyword The keyword "IS" was expected but not found. 19 E Multiple loop specifications not allowed The beginning and end of a loop both had a loop specification. 20 E Expected TO keyword The TO keyword was expected but not found. 21 E Expected "," A comma was expected but not found. 22 E Expected "=" An equal sign was expected but not found. 23 E Inverted range An array range specification had the first element larger than the second, or a RANGE modifier had the first value greater than the second value. 24 F Structures nested too deeply Data structures were nested too deeply for the compiler. 25 F Stack overflow The compiler's stack overflowed. 26 E Expected identifier An identifier was expected but was not found. 27 E Expected PROGRAM keyword The PROGRAM keyword must be the first non-comment line in a program. 28 E Expected a label or statement A new statement (or label) was expected but not found. 29 E Expected string expression A string expression was expected but not found. 30 E Expected Numeric Expression A numeric expression was expected but not found. 31 W Text after program END ignored Text was found in the source file after the program END. 32 E Expression too complex An expression was too large or complex for the compiler. Break the expression into two or more smaller ones. 33 E Missing left parenthesis A right parenthesis was found without a matching left parenthesis. 34 E Expected THEN Keyword "THEN" must immediately follow the conditional expression of an "IF" statement. 35 E Illegal nesting of structures Source attempted to define APPENDIX A Page 43 certain structures within others (such as a PROCEDURE inside an IF statement). 36 E Expected a literal A literal was expected but not found. 37 E Cannot co-begin procedure An attempt was made to call COBEGIN with a procedure that referenced non-local, non-GLOBAL variables. 38 - 32767 Reserved. Page 44 APPENDIX B Sirius BNF Description The following is the BNF description of the Sirius language. program ::= program-header statements "END" program-header ::= "PROGRAM" identifier identifier ::= letter | letter letter-or-other letter ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" letter-or-other ::= letter | digit | other | letter letter-or-other | digit letter-or-other | other letter-or-other digit ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0" digits ::= digit | digit digits other ::= "$" | "_" statements ::= statement | statement statements statement ::= declare | goto | label | "EXIT" | "STOP" | when | data | constant | do | memory | absolute | "RETRY" | case | assignment | field | unfield | if | while | until | for | function | procedure | external | restore | define | record restore ::= "RESTORE" | "RESTORE" identifier label ::= identifier ":" left-parenthesis ::= "(" | "[" | "{" right-parenthesis ::= ")" | "]" | "}" variable ::= variables | "~" variables variables ::= identifier | identifier subscript | identifier subset | identifier subscript subset subset ::= left-parenthesis digits "," digits right-parenthesis subscript ::= left-parenthesis list right-parenthesis list ::= numeric-expression | numeric-expression "," list goto ::= "GO" "TO" identifier identifier-list ::= identifier | identifier "," identifier-list absolute ::= "ABSOLUTE" digits declare declare ::= declaration | "GLOBAL" declaration | "EXTERNAL" declaration declaration ::= "DECLARE" declaration-list declaration-list ::= identifier-list "AS" data-types record ::= "RECORD" identifier record-declarations "END" | "RECORD" identifier record-declarations statements "END" record-declaration ::= declaration-list | "OBJECT" identifier record-declarations ::= record-declaration | record-declaration record-declarations APPENDIX B Page 45 data-types ::= data-definition | data-definition size-definition data-definition ::= identifier | data-identifier "OF" data-definition | scalar | type | array | "UNDEFINED" | "LOGICAL" | "CHARACTER" | "STRING" | "REAL" | "INTEGER" | "FIXED" | "RATIONAL" | "IMAGINARY" | "IMRAT" | "COMPLEX" | "COMRAT" | "PROCEDURE" | "DECIMAL" data-identifier ::= "LIST" | "QUEUE" | "STACK" | "FILE" | "INTERNAL" "FILE" type ::= types | types "RANGE" literal "," literal literal ::= string-literal | number | logical-literal numeric-value ::= variable | number | functional-value types ::= "TYPE" "OF" data-definition scalar ::= "SCALAR" left-parenthesis identifier-list right-parenthesis real-definition ::= "EXPONENT" digits other-definition ::= "BYTES" digits size-definition ::= real-definition | other-definition | real-definition other-definition array ::= arrays | "SPARSE" arrays arrays ::= "ARRAY" left-parenthesis declare-subscript right-parenthesis "OF" data-definition declare-subscript ::= digits "," digits | digits "," digits "," declare-subscript assignment ::= variable ":=" expression expression ::= string-expression | numeric-expression | logical-expression | left-parenthesis expression right-parenthesis string-expression ::= string | string "\" string-expression | left-parenthesis string-expression right-parentheesis string ::= string-literal | variable | functional-value string-literal ::= "'" ANYTEXT "'" | "'" ANYTEXT "'" string-literal number ::= sign number-data | number-data number-data ::= numbers | numbers E-portion numbers ::= digits | digits "." | digits "." digits sign ::= "+" | "-" E-portion ::= "E" sign digits numeric-expression ::= expressive | sign expressive expressive ::= numeric-value | left-parenthesis numeric-expression right-parenthesis | numeric-expression monadic-operator | numeric-value numeric-operator numeric-expression numeric-operator ::= "+" | "-" | "^" | "*" | "/" monadic-operator ::= "!" | "%" logical-literal ::= "FALSE" | "TRUE" logical-value ::= variable | logical-literal | functional-value logical-expression ::= logical-value | relational-expression | left-parenthesis logical-expression right-parenthesis | logical-value logical-operator logical-expression | "NOT" logical-expression logical-operator ::= "&" | "N&" | "OR" | "NOR" | "XOR" | "XNOR" relational-expression ::= expression relational-operator expression | left-parenthesis relational-expression right-parenthesis relational-operator ::= "<" | ">" | "=" | "#" | "<>" | "<=" | "=<" | ">=" | "=>" | "==" memory-type ::= "VIRTUAL" | "PHYSICAL" memory ::= memorys | memorys "AS" memory-type memorys ::= "MEMORY" identifier-list "IS" data-types call-type ::= "REFERENCE" | "VALUE" | "NAME" module-type ::= "PROCEDURE" | "OBJECT" "FUNCTION" | "TARGET" "FUNCTION" external ::= externals | externals "BY" call-type externals ::= "EXTERNAL" module-type "IS" "CALLED" identifier APPENDIX B Page 46 do ::= "DO" variable literal-list ::= literal | literal "," literal-list constant ::= constants literal | constants literal-list constants ::= "GLOBAL" constant-def | "EXTERNAL" constant-def | constant-def constant-def ::= "CONSTANT" identifier ":=" field ::= "FIELD" variable "OFFSET" digits | "FIELD" variable "AS" digits "OFFSET" digits unfield ::= "UNFIELD" variable case ::= "CASE" variable case-statements "ENDCASE" case-statements ::= "ON" case-values ":" statements | "ON" case-values ":" statements case-statements | "OTHERWISE" ":" statements case-values ::= relational-operator expression if ::= "IF" logical-expression "THEN" statements "ENDIF" | "IF" logical-expression "THEN" statements "ELSE" statements "ENDIF" while ::= "WHILE" statements next-loop | "WHILE" relational-expression statements "NEXT" until ::= "UNTIL" statements next-loop | "UNTIL" relational-expression statements "NEXT" for ::= "FOR" statements next-for | "FOR" end-value statements "NEXT" | "FOR" variable "=" numeric-expression "TO" end-value statements "NEXT" end-value ::= numeric-expression | numeric-expression "STEP" numeric-expression next-loop ::= "NEXT" relational-expression next-for ::= "NEXT" variable "=" numeric-expression "TO" end-value when ::= "WHEN" "INTERRUPT" statement | "WHEN" "ERROR" statement | "WHEN" "EOF" variable statement data ::= "DATA" literal-list procedure ::= procedure-def | "GLOBAL" procedure-def | "EXTERNAL" procedure-def procedure-def ::= "PROCEDURE" identifier procedure-list statements "END" function ::= function-def | "GLOBAL" function-def | "EXTERNAL" function-def function-def ::= "OBJECT" functions | "TARGET" functions | functions functions ::= "FUNCTION" identifier "AS" data-types procedure-list statements "END" procedure-list ::= "IS" identifier left-parenthesis variable-list right-parenthesis | left-parenthesis parameter-list data-types right-parenthesis variable-list ::= type-specification | type-specification "," variable-list type-specification ::= "*" type-reference | type-reference type-reference ::= data-types | "ALL" functional-value ::= identifier | identifier left-parenthesis function-list right-parenthesis function-list ::= expression | expression "," function-list define ::= "DEFINE" "'" identifier "'" "AS" numbers defines statements "ENDDEFINE" defines ::= "" | "RIGHT" | "LEFT" | "RIGHTLEFT" | "LEFTRIGHT" parameter-list ::= identifier | identifier "," modified-parameter-list modified-parameter-list ::= data-types parameter-list | identifier Page 47 INDEX & & Operator 16 A ABS Function 34 ABSOLUTE Statement 19 ACTIVATE Directive 4 ADD Procedure 32 Addition 15 ADVANCE Procedure 30 ALLOC Procedure 34 ANY Keyword 26 ARCCOS Function 35 ARCSIN Function 35 ARCTAN Function 35 ARRAY Modifier 10 Array Operations 19 Array Subscript Checking 4 Arrays 10 Arrays As Strings 6 AS Keyword 10 ASCENDING Keyword 28 ASCII Function 37 Assignment Statements 18 Asynchronus Events 24 B BIN Function 37 BINARY Function 35 Bit Manipulation 33 Bit Subsets 14 Branching 21 BREAK Procedure 32 BUSY Function 28 BYTE Function 35 BYTES Modifier 6,7,8,9 C CASE Statment 22 CAST Statement 26 CHAIN Procedure 32 CHAR Funcion 37 CHARACTER Data Type 6 CHARACTER Family 6 CLEAR Procedure 34 CLOSE Procedure 30 Co-Processing 28 COBEGIN Procedure 28 Comments 19 COMPARE Function 34 COMPLEX Data Type 9 Composite Data Types 10 INDEX Page 48 Compound Data Types 5 COMRAT Data Type 9 Concatenation 15 Conditional Expressions 14 Constants 13 COSINE Function 35 CVT Function 35 D Data Blocks 24 DATA Statement 24 DEACTIVATE Directive 4 DEALLOC Procedure 34 Declaration 4 DECLARE Statement 4 DEFINE Statement 16 DELETE Procedure 32 DEQUE Procedure 32 DESCENDING Keyword 28 Direct Memory Reference 18 Directives 3 Division 15 DO Statement 9 E E Constant 35 EBCDIC Function 37 EDIT Function 37 ELSE Keyword 22 EMPTY Function 37 Encapsulation 11 END Statement 20,26 ENDDEFINE Statement 16 ENDIF Keyword 22 Enumerated Data Types 12 EOF Keyword 24 EQUAL Function 35 ERROR Function 33 ERROR Keyword 24 ERROR_TEXT Function 33 ERROR_TYPE Function 33 EXIT Statement 23,24 EXP Function 35 EXPONENT Modifier 8,9 Exponentiation 15 Expression Evaluation 18 External Identifiers 5 EXTERNAL Keyword 5 EXTERNAL Modifier 26,27 External Modules 20 EXTERNAL Statement 20 INDEX Page 49 F Factorials 14 FALSE Literal 13 FALSE Value 6 FAMILY Function 38 FAMILY() Function 17 FIELD Statement 21 FILE OF Modifier 10 Files 10 FIXED Data Type 8 FLUSH Procedure 30 FOLLOW Function 33 FOR Statement 23 FRAC Function 35 FRACTIONAL Modifier 8 FUNCTION Statement 27 Functions 27 G Global Identifiers 5 GLOBAL Keyword 5 GLOBAL Modifier 26,27 GOTO Statement 21 H Heap Access 4 Heap Functions 34 HREAD Function 34 HWRITE Procedure 34 I I/O Operations 29 Identifier Names 4 Identifiers 4 IF Statement 22 IMAGINARY Data Type 8 IMRAT Data Type 9 IN Procedure 31 INCLUDE Directive 3 INFINITY Constant 35 Initialization 19 INPUT Procedure 30 INSTR Function 35 INT Function 36 INTEGER Data Type 7 INTERNAL FILE OF Modifier 10 INTERRUPT Keyword 24 Introduction 2 INDEX Page 50 L Labels 20 LEFT Function 38 LEFT Modifier 17 LEFTRIGHT Modifier 17 LENGTH Function 36 LHS Keyword 17 LIST OF Modifier 10 Lists 10 Literals 13 LOCAL fields 11 LOG Function 36 LOGICAL Data Type 6 Logical Operators 16 Loops 23 M MASK Procedure 29 MAX Function 36 MEMORY Statement 18 Methods 11 MIN Function 36 Multiplication 15 N N& Operator 16 NAME Keyword 20 Name Parameters 4 NCM Keyword 30 Nesting 19 NEXT Statement 23 NOR Operator 16 NOT Operator 16 NUMERIC Family 7 Numeric Functions 34 Numeric Operators 14 Numeric Overflow 4 Numeric Underflow 4 O OBJECT 11 OBJECT Keyword 27 OBJECT Modifier 11 Objects 11 OFFSET Modifier 21 OPEN Procedure 29 Operators 14 OR Operator 16 OUT Procedure 31 OUTPUT Procedure 30 Overflow 4 INDEX Page 51 P Parentheses 14 PASSED Keyword 26,36 Percentage 15 PHYSICAL Modifier 18 PI Constant 36 Pointers 25 POP Function 32 Precedence 14 PRECEED Function 33 Preface 1 PRIVATE fields 11 PROCEDURE Data Type 9 PROCEDURE Statement 26 Procedures 25 PROGRAM Statement 20 PUSH Procedure 32 Q QUE Procedure 32 QUEUE OF Modifier 10 Queues 10 R RANDOM Function 36 Range Checking 4 RANGE Modifier 12 RATIONAL Data Type 8 READ Procedure 32 READ Statement 24 READ_LIST Function 33 READ_QUE Function 33 READ_STACK Function 33 REAL Data Type 7 RECORD Function 36 Records 11,17 Recursion 19 REFERENCE Keyword 20 Relational Operators 15 REMOVE Procedure 32 RESULT Keyword 17 RETRY Procedure 32 RHS Keyword 17 RIGHT Modifier 17 RIGHTLEFT Modifier 17 RINSTR Function 36 ROOT Function 36 ROUND Function 36 S SCALAR Data Type 12 Scalar Data Types 12 Scope of Identifiers 5 INDEX Page 52 SET Procedure 34 SIGN Function 36 SIGNAL Procedure 29 Simple Data Types 5 SINE Function 36 SIZEOF Function 36 SORT Procedure 28 Sorting 28 Source Code Format 3 SPARSE ARRAY Modifier 10 Sparse Arrays 10 STACK OF Modifier 10 Stacks 10 Standard Routines 28 Statements 20 Static Identifiers 5 STOP Statement 21 STRING Data Type 6 STRING Function 38 String Functions 36 String Operators 15 Subscript Checking 4 Substrings 15 Subtraction 15 T TARGET Keyword 27 Tecnical Description 3 TEST Function 38 THEN Keyword 22 Tilde 14 Tilde Operator 16 TRANSFER Procedure 30 TRUE Literal 13 TRUE Value 6 TYPE Function 38 TYPE OF Modifier 12 TYPE() Function 17 U Unary Minus 14 Unary Operators 14 Unary Plus 14 UNDEFINED Data Type 6 Underflow 4 UNFIELD Statement 21 UNMASK Procedure 29 UNSIGNED Modifier 7 UNTIL Statement 23 User-defined Data Types 12 User-Defined Operators 16 INDEX Page 53 V VALUE Keyword 20 VIRTUAL Modifier 18 W WAIT Procedure 29 WHEN Statement 24 WHILE Statement 23 WHOLE Modifier 8 X XNOR Operator 16 XOR Operator 16 Z ZERO Procedure 34