This document is a fairly rigorous description of the syntax of the PLASYD language together with informal descriptions of the semantics, programmer's viewpoint and implementation notes. Each section is therefore divided into up to four subsections.
Loosely speaking the syntax metalanguage is as follows :-
Thus <Asymbol> ::= A
<name> ::=<A symbol>41
would allow <name> to take one of the forms A, AA, AAA or AAAA while
<name> ::=<A symbol>*0
would allow a null name or A or AA or AAA or .... etc.
<I assignment> ::= <I Register> ← <I address> (I =:: INTEGER | LONG INTEGER)
means that the subsidiary definee should be replaced consistently
by one of its definitions throughout the main definition. Thus the example
above is equivalent to
<INTEGER assignment> ::= <INTEGER Register> ← <INTEGER address>
and
<LONG INTEGER assignment> ::= <LONG INTEGER Register> ← <LONG INTEGER address>
We can think of =:: as "stands for".Within PLASYD spaces and new lines or end of card (72 characters) are significant and are used, together with other non-alphanumeric symbols, to terminate identifiers, numbers and reserved words. New lines do not however terminate statements. Lines from whatever medium must not be greater than 72 characters, or character positions. Tabs are considered to be at 6 character intervals.
K =:: INTEGER | REAL | LONG INTEGER | LONG REAL
<K register> ::= <K register identifier>
means
INTEGER register ::= INTEGER register identifier
REAL register ::= REAL register identifier etc.
INTEGER corresponds to the 1900 24 bit signed integer
REAL corresponds to the 1900 48 bit floating point number
LONG INTEGER corresponds to the 1900 48 bit double length integer
LONG REAL corresponds to the 1900 48 bit double length floating point number
<character> ::=
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|
0|1|2|3|4|5|6|7|8|9|
+|-|*|/|<|=|>|#|←|,|.|;|:|@|%|"|&|(|)|[|]|£|$|?|'|!
<basic symbol> ::= <character>|
AND|OR|ER|NOT|NEG|SLL|SRL|SLA|SRA|SRAV|SLC|SRC|IF|THEN|ELSE|CASE|OF|
CASEND|WHILE|DO|FOR|STEP|UNTIL|BEGIN|END|GOTO|OBEY|GO|TO|FIX|FLOAT|
REAL|LOGICAL|INTEGER|CHAR|FUNCTION|PROCEDURE|GLOBAL|LOWER|LONG|EX|
SYN|ACC|LOWEND|GLOBEND|MINUS|UNDER|FROM|CARRY|CNT|CH|INTERPRET|INCLUDE|
BASE|OVERFLOW|FOVERFLOW|EXTERNAL|ENTRY|GLABEL|DEFINE|DATA|NULL|SA|LA|
PURE|PUREND|RETURN|BRINGOVERLAY|NONPLASYD
All characters within the symbols [ and ] are ignored as comment, except within strings and character sequences where [ ] are normal characters. Fixed word symbols are terminated by any non alpha-numeric character, including space.
The symbols := are allowed as an alternative to ←. The full form of all reserved words must be presented to the compiler.
There is a facility in the language for conditional compilation. The sequence ?<n> (other than in a string or character sequence, where <n> is a positive integer less than 11, will cause the following PLASYD statements up to sequence )?<n> outside a string or character sequence, to be compiled if system switch <n> is on.
This can be used for optionally compiled calls to a TRACE package if required.
<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|% <identifier> ::= <letter>|<identifier><letter>|<identifier><digit> <K accumulator identifier> ::= <identifier> <K cell identifier> ::= <identifier> <procedure identifier> ::= <identifier> <block identifier> ::= <identifier> <lower K cell identifier> ::= <identifier> <upper K cell identifier> ::= <identifier> <label identifier> ::= <identifier> <instruction identifier> ::= <procedure identifier>|<label identifier>
Identifiers are associated with a K accumulator, a K cell, a procedure or function by an appropriate declaration. They may also be associated with a disc subfile in which case they must also conform to other conventions. Identifiers are restricted to 32 characters in any case.
The fixed words of section 2 may not be used as identifiers, nor may the fixed accumulator identifiers of section 5.
Identifiers may only be re-used for quantities with absolutely disjoint scopes. Temporary redefinition of identifiers as in Algol is not permitted.
<digit> ::= 0|1|2|3|4|5|6|7|8|9
<unsigned integer number> ::= <digit>*1
<unsigned long integer number> ::= <unsigned integer number>.<digit>D
<fractional number> ::= <unsigned integer number>.<digit>|
<fractional number><digit>
<exponent> ::= <integer number>
<unsigned real number> ::= <fractional number>|
<fractional number>>&<exponent>|
<unsigned integer number>&<exponent>
<unsigned long real number> ::= <unsigned integer number>L|
<unsigned real number>L
<K number> ::= <unsigned K number>|MINUS <unsigned K number>
<octal digit> ::= 0|1|2|3|4|5|6|7
<octal value> ::=#<octal digit>*1
<truncated number> ::= <integer number>T<unsigned integer number>
<count> ::= <integer number> CNT
<string> ::= "<character>*1"
<character sequence> ::= '<character>41'
<integer value> ::= <integer number>|<octal value>|<truncated number>|
<count>|<character sequence>
<long integer value> ::= <integer number> D|<octal value> D
<real value> ::= <real number>|<octal value> R
<long real value> ::= <real number> L|<octal value> L
<unsigned integer> ::= <unsigned integer number>
#270 45CNT "STRING" MINUS 31T15 '%' 37 13725.21&24 MINUS 1D 3.14159L
Exponents denote an integral power of ten.
MINUS indicates that the quantity following is to be stored as a negative number. CNT followed by a number means "Store in the top nine bits". This is different to the operator CNT (See Section 8 below).
Numbers must lie within the limits imposed by hardware.
A string is a sequence of six bit characters which is stored starting at character position zero of a 1900 word. Strings are space filled to the right to a multiple of four characters. Character sequences normally contain one character only although they may contain up to four. They are a type of integer value and can be considered as a sequence of 6 bit characters zero filled to the left to produce 24 bits. " within a string, and ' within a character sequence are represented by "" and '' respectively.
A truncated number is formed by producing the binary equivalent of the integer number (which may be signed) and truncating the most significant end to leave only the number of bits indicated by the unsigned integer number.
<INTEGER accumulator> ::= X0|X1|X2|X3|X4|X5|X6|X7 <modifier> ::= X1|X2|X3 <LONG INTEGER accumulator> ::= X01|X12|X23|X34|X45|X56|X67|X70 <REAL accumulator> ::= A1 <LONG REAL accumulator> ::= A12
The integer accumulators correspond to the fixed point accumulators of the 1900 in an obvious way. Similarly for the other types. The LONG REAL accumulator is available only on machines with that hardware.
The accumulators may be assigned other names by the SYN declaration (see 12 below)
<integer type> ::= INTEGER|LOGICAL
<long integer type> ::= LONG INTEGER|LONG LOGICAL
<real type> ::= REAL
<long real type> ::= LONG REAL
<K cell declaration> ::= <K type><item>|<K cell declaration>,<item>
<simple item> ::= <identifier>|<identifier> = <initial value>
<array item> ::= <identifier>(<array length>)|
<identifier>(<array length>) = (<initial value list>)>
<item> ::= <simple item>|<array item>
<array length> ::= <unsigned integer number>
<inital value list> ::= <initial value>|
<initial value>=<array length>|
<initial value list>,<initial value list>
<initial value> ::= <K value>|<string>|<fixed address>|<function statement>|
<count> + <fixed address>|<count> + <integer number>|
<count> + <truncated number>|<count> + <octal value>
<declaration list> ::= <K cell declaration>|<base declaration>|
<declaration list>;<declaration list>
<base declaration> ::= BASE
<block declaration>::= <block identifier>:<declaration list>
<global tail> ::= <block declaration>GLOBEND|<block declaration>;<global tail>
<global declaration> ::= GLOBAL <global tail>
<lower block> ::= <declaration list>|<global declaration>|
<lower block>;<lower block>
<lower declaration> ::= LOWER <lower block> LOWEND
REAL X, Y, Z; INTEGER I, J = 13,K; LONG REAL P(L); REAL XAR(20), NEXT, YAR(10)=(4.3,2.4,0.0,* 6, 1.0); BASE; INTEGER Z(20) = (@I,257CNT + @J, 131CNT + 7, MINUS 4,!LDX(1,0); LOWER REAL VW, MGB; GLOBAL BUFF:INTEGER B(32) GLOBEND LOWEND ;
A cell declaration introduces identifiers and associates them with calls of the specified type. The validity is throughout the block in the head of which the declaration occurs. Moreover the declaration may specify an initial value to be stored in the cell. This is permanent in the sense that it will be reset by any overlay. Initial values may only be assigned to quantities in an outer block or a segment. A string is stored in successive character positions beginning at character 0 and is space filled to a multiple of four characters.
Initial values must be of the same type as the cell and for this purpose addresses, strings, function statements and values with <count> as a component are considered to be integer.
If a cell identifier is followed by an integer or an absolute quantity (see section 24) in parenthesis, that number of storage cells will be allocated to make a one dimensional array. The number of 1900 words assigned to each cell is as follows :-
INTEGER, LOGICAL - 1 word REAL, LONG INTEGER - 2 words LONG REAL - 4 words
An initial list of m entries specifies initial values for the first m elements of the array. If an initial value is followed by *n it is equivalent to n identical initial values. Each initial value will correspond to one element of the array, unless the initial value is a string, in which case it will fill as many words as necessary.
All identifiers (except label or procedure identifiers) must be declared before they are used. Thus in the examples I had to be declared before @I was used as an initial value. <fixed address> is the location (to 22 bits) of the K cell or label or procedure concerned, and may possibly also involve a character address. For details see 7, 8 below. The L in the LONG REAL declaration is assumed to have been set by a define statement - see 24 below.
A global declaration makes COMMON blocks of all the block declarations it contains. The block identifier is the common block name and the decision on whether the block is permanent or overcommon is delayed until consolidate time. Block declarations with the same identifier are added sequentially.
A block identifier and a cell identifier must not have the same name e.g. GLOBAL JACK: JACK is not allowed.
All items within a LOWER declaration are forced into the first 4096 words.
Upper (i.e. non LOWER) non-GlOBAL locations are dealt with in the following way :- the address of the first upper storage location mentioned. is stored in lower and this becomes the base of a "domain" of up to 4096 words. All subsequent cells are stored in consecutive locations and are addressed by their "displacement" from this base. If a base declaration appears a new base is stored and subsequent addresses are relative to that. If 4096 words are declared without a base statement appearing a new base is inserted by default and a comment listed.
Each non-lower block declaration has a new base associated with its first word and this base is stored in a location which is associated with the block identifier. Additional bases may be introduced by base declarations.
All lower quantities have a base of zero and a displacement which is their address, regardless of whether they are global or not.
Upper non-global items will be stored in successive words in the order of declaration. So will items within a global block.
Either the initial values given to the variables in global block should be identical in all segments or they must be assigned in one segment only.
The compiler must deal with what are effectively a number of compile time stacks. These are:
For each stack there must be a stack pointer to the last used (or first unused) word of the stack. This will be incremented as declarations are encountered. and decremented as blocks are left. The pointer for the lower stack is a simple (relative) address. For the upper stack and for each global stack is the current base address (which is stored in lower and will be a relative address) plus an absolute displacement. Exit from block may well cause alteration of the current base as well as the displacement. Obviously the maximum reached by any stack at any point must also be recorded. The cell symbol table entries must contain the following information.
On exit from a block corresponding symbol table entries will be destroyed. Both the items under 2 are needed, the first for compile time calculated, the second for run time use.
The blocks within a procedure declaration may share storage with each other but the maximum amount of storage declared throughout the definition of the procedure must be reserved throughout the life of the block in which the procedure is declared. (As a first shot, which would probably not waste much in practice, all declarations at any depth would constitute declarations at the level of the block in which the procedure is declared). Character arrays must begin in the first character of a word. Once an array has been declared there is no reason to distinguish between arrays and simple variables.
All non-global variables go into upper or lower preset. However, global blocks should go into preset if any initial values are set, variable otherwise.
<K cell designator> ::= <simple K cell designator>|(<free SMO index>)|
<K cell identifier>(<SMO index>)
<simple K cell designator> ::= <lower K cell identifier>|(<free index>)|
<lower K cell identifier>(<fixed index>)|
<K cell identifier>(<variable index>)
<variable index> ::= <modifier>|<modifier>+<unsigned integer>|
<modifier>-<unsigned integer>
<free index> ::= <unsigned integer>|<modifier>|<modifier>+<unsigned integer>
<fixed index> ::= <unsigned integer>|-<unsigned integer>
<simple SMO index> ::= <simple integer cell designator>|
£<K cell identifier>|<block identifier>
<free SMO index> ::= <simple SMO index>|<simple SMO index>+<free index>
<SMO index> ::= <free SMO index>|<simple SMO index>-<unsigned integer>|
<simple SMO index>+<modifier>-<unsigned integer>
A (X1) (X1 +5) (30) A(8) A(-8) A(X1) A(X1-10) U(X2) U(X3+5) B((6)) A(B) A(B+X1-1) U(B+X3-1) (B) U(B(X1-5)+X2-1) U(£U) (BLOCK+3) ((X3)) U(£U+X1-70) U(V(X1))
Cells are denoted by cell designators. In the case of cells of simple lower type (i.e. declared within a LOWER declaration) the designator can consist simply of the identifier associated with that cell. In the case of lower arrays the array name is followed by an index which designates an element of the array. The index value is divided by the number of memory units (words) occupied by each cell and this is used as the element number of the array to be addressed. The first element of an array has number zero. The result of the division must be positive and the remainder zero. Indices can also be applied to simple variables. The simple variable is then treated as an array with an indefinite number of elements whose first element is the simple variable itself. Similarly references can be made to array elements outside the declared size of the array. In the case of upper variables and arrays a special course is adopted to overcome the 12-bit address field of the 1900. This works in the following way :-
The address of an element A in upper is known as @A and consists of two parts. The first is the base of the domain in which A exists and will be in general a 22 bit address. This is referred to as £A. The displacement of the element from this base in storage units (words) is referred to as $A. This must always be ≤ 4095. If an upper quantity is to be referenced it must have an index following the identifier and this must contain the £A part of the address either as an explicit quantity e. g. U(£U), or by reference to a store location which contains this quantity e.g. U(B+3) where B contains £U possibly as a constituent of its value, or by reference to a modifier e.g. U(X1) where the contents of X1 are similar to B. Thus the reference to an upper quantity outside the index is really only a reference to its $ part. The user is required to set up the store location or the modifier with the correct value himself. Attempts to refer to upper quantities without subscripts or with constant subscripts will be faulted.
Indices with no preceding address are taken as a reference to an element of the untyped array which begins at word zero of the store and runs to the end of the store. Thus(30) indicates word 30 of tbe store and ((X3)) indicates the word whose address is held in the word whose address is held in the modifier X3. Integer accumulators may be treated as store locations by this means e.g. (1)
Note that all use of SMO indices will produce a SMO instruction in the object code. The appropriate method of compilation should therefore be in use.
The constant parts of indices when added into or subtracted from the displacement must produce a result between 0 and 4095 inclusive.
Assuming that A is a lower quantity, B is a lower integer, U and V are upper quantities and V is an integer, and BLOCK is a block identifier the examples of part b are equivalent PLAN addresses in non literal instructions as follows :-
PLASYD PLAN NOTES
------ ---- -----
A A
1. (X1) 0(1)
2. (X1+5) 5(1)
3. (30) 30
4. A(8) A+8 1
5. A(-8) A-8 2
6. A(X1) A(1)
1. A(X1-10) A-10(1)
8. U(X2) $U(2)
9. U(X3+5) $U+5(3)
10. B((6)) SMO 6 3
B
11. A(B) SMO B
A
12. A(B+X1-1) SMO B
A-1(1)
13. U(B+X3+1) SMO B
$U+1(3) 1
14. (B) SMO B
0
15. U(B(X1-5)+X2-1) SMO B-5(1)
$U-1(2) 2
16. U(£U) SMO £U
$U 4
17. (BLOCK +3) SMO BLOCK A
3 5
18. ((X3)) SMO (3)
0
19. U(£U+X1-70) SMO £U
$U-70(1)
20. U(V(X1)) SMO $V(X1)
$U
The pseudo SMO macros for
SMO N1(N1) XXX X N2(N2)
where SMO has not been produced by !SMO are as follows :-
STO M WS [some workspace]
LDX M N1(M1)
XXX X N2(M)
LDX M WS
Where M is an modifier other than X
STO M2 WS
ADX M2 N1(M1)
BVSR * + 1 [in the case of overflow]
XXX X N2(M2)
LDX M2 WS
STO M3 WS
LDX M3 N1(M1)
ADX M3 M2
BVSR * + 1
XXX M2 N2(M3)
LDX M3 WS
Note that any previous overflow will be lost in cases (ii) and (iii) and that carry will be cleared by the pseudo SMO which is different from the actual SMO and if carry is set the accumulator M is corrupted by the addition of 1.
<K primary> ::= <I accumulator>|<K value>|<K cell designator>
(I=::INTEGER|LONG INTEGER)
<simple K accumulator assignment> ::= <A accumulator>+<K primary>|
<A accumulator>←NEG<K primary>|<R accumulator>←<R accumulator>|
<integer accumulator>←CNT<C operand>|<address assignment>
(A=::K|LONG K; R=::REAL|LONG REAL)
<address assignment> ::= <integer accumulator>←<address>|
<integer accumulator>←<integer accumulator>+<address>
<integer accumulator>←<integer accumulator>-<K word address>
<K word address> ::= @<K cell designator>|$<K cell designator>|
£<K cell identifier>|@<K cell identifier>(<fixed index>)|
$<K cell identifier>(<fixed index>)
<address> ::= <K word address>|CHAR <unsigned integer>|
CHAR <unsigned integer> OF <K word address>
@ <instruction identifier>
<fixed K word address> ::= @<fixed K cell designator>|
$<fixed K cell designator>|£<K cell identifier>|
<fixed address> ::= <fixed K word address>|CHAR <unsigned integer>|
CHAR <unsigned integer> OF <fixed K word address>|
@<instruction identifier>
<monadic operator> ::= CARRY|EX|CH|NEG CARRY
<K accumulator asssignment> ::= <simple K accumulator assignment>|
<long integer accumulator assignment>/<integer cell designator>|
<A accumulator assignment><arithmetic operator><K primary>|
<real accumulator assignment><reverse operator><real primary>|
<integer accumulator assignment><logical operator><integer primary>|
<I accumulator assignment><shift operator><C operand>
<real accumulator>←FLOAT<I cell designator>
(I=::integer|long integer;A=::INTEGER|REAL|LONG REAL)
<arithmetic operator> ::= <add operator>|*|/
<add operator> ::= +|-|++|--
<reverse operator> ::= FROM|UNDER
<LOGICAL OPERATOR ::= AND|OR|ER
<shift operator> ::= SLL|SRL|SRA|SRAV|SLA|SLC|SRC
<c operand> ::= <unsigned integer number>|<octal value><modifier>|
<simple integer cell designator>
X1 ← 3 X1 ← X2 X1 ← A(B+X1-3) A1 ← 3.14159 X12 ← 1D X2 ← NEG 1 X6 ← CNT 12 X0 ← CARRY V(£V) X70 ← U(X3) X7 ← CH B(X1) X6 ← '%' X1 ← CNT X1 X1 ← @A(3) X3 ← CHAR 1 OF £C X6 ← X6+$U X6 ← A/B-213 A1 ← A1 UNDER PI X0 ← B AND #6617 X4 ← X1 SLL 6 A1 ← FLOAT B X1 ← X1*X6 X12← X12/B X4 ← CNT (6) X7 ← X7 SRA B(X1+3)
An assignment statement allows the values designated on the right of the ← symbol to be assigned to the accumulator on the left. Operators in general parallel closely available machine functions.
In this document the syntax given in (a) may not bo completely rigorous in that certain operations may not be (im)possible although (not) specified above. Attempts will be made to clear this up in later editions. As a general rule combinations which produce one 1900 machine instruction per operand, possibly with a preceding SMO order, are allowed. The syntax also fails to define certain limitations imposed by the operation of the 1900 e.g. the value following the shift operator should be less than 10 bits. More details of the meanings of operators are given below and in (d).
Assignments are carried strictly from left to right including the initial assignment. Thus
X1 ← X1+X2 is quite different from X1 ← X2+X1 which is however, the same as the sequence X1 ← X2 and X1 ← X1+X1
Unnecessary load instructions will not be compiled and the two similar sequences will produce identical machine code.
Operators have their obvious or PLAN meanings where these exist. Possibly unfamiliar operators are as follows :-
NEG Negate the following operand
CNT Place the following operand in the top 9 bits
CARRY Use a load-setting-carry instruction
EX Consider only the bottom 9 bits of the operand
++ ) Use a carry setting instruction with integers
-- ) undefined for other types at present
FROM Reverse subtraction - reals only
UNDER Reverse division - reals only
CH The following operand designates a 6-bit character.
FLOAT Convert the integer in the first word and the fraction in the
second to real.
Address assignments place, subtract or add an address into or from an accumulator. i.e. the same accumulator must be specified. on both sides of ←. The @ $ and £ symbols are explained in section 7. CHAR <integer number> indicates a 1900 character modifier for that number of characters and the integer number must be in the range 0 to 3. The only way of designating a particular character storage cell is by use of a character address set up in this fashion as an initial value or by assignment as an index.
For some instructions, multiplication and division of integers in particular, the 1900 order code places some nasty restrictions on operands and introduces messy side effects. If N and X are lower integers the following holds:
A1←FLOAT N expects N (1) to be cleared (or set to a fraction)
X1←N*X produces an integer result in X1 but destroys X2 (sets it to zero)
and involves a shift instruction. To obtain a long integer result
more conveniently a function (see 10) should be used.
X1←N/X produce an unrounded integer result in X1 and a remainder in X0
or X01←X01/X (DVS or DVD)
Assignment of a character sequence to an integer accumulator puts it in the least significant bits with zeros elsewhere.
Note that FLOAT accesses either an integer and the next word or a non-standard long integer. K cells whose type is not obvious e.g. (3),(X1) are assumed to be of the correct type for the L.H.S.
The primary aim in defining the syntax is to allow only operations which are easily reduced. to machine orders without redundancies. Only where the 1900 order code shows pathological deficiencies is this aim dropped.
General rules for compilation of assignment statements are :-
The following is the code produced for the examples of (b) assuming the same declarations as in section 6, plus a lower real PI. More detailed notes follow.
PL 1900 PLAN EQUIVALENT
1. X1 ← 3 LDN 1 3
2. X1 ← X2 LDX 1 2
3. 1 ← A(B+X1-3) SMO B
LDX 1 A-3(1)
4. A1 ← 3.14159 LFP '.3145159E1'
5. X12 ← 1D LDN 2 1
LDN 1 0
6. X2 ← NEG 1 NGN 2 1
7. X6 ← CNT 12 LDCT 6 12
8. X0 ← CARRY V(£V) SMO £V
LDXC 0 $V
9. X70 ← U(X3) LDX 0 $U+1(3)
LDX 7 $U(3)
10. X7 ← CH B(X1) LDCH 7 B(1)
11. X6 ← '%' LDN 6 #25
12. X1 ← CNT X1 LDCT 1 (1)
13. X1 ← @A(3) LDN 1 A+3
14. X3 ← CHAR 1 OF £C LDCT 3 128
ADX 3 £C
15. X6 ← X6+$U ADN 6 $U
16. X6 ← A/B-213 LDX 6 A
DVS 5 B
SBN 6 213
17. A1 ← A1 UNDER PI FDVD 4 PI
18. X0 ← B AND #6617 LDX 0 B
ANDN 0 #6617
19. X4 ← X1 SLL 6 LDX 4 1
SLL 4 6
20. A1 ← FLOAT B FLOAT B
21. X1 ← X1*X6 MPY 1 6
SLA 12 23
22. X12 ← X12/B DVD 1 B
23. X4 ← CNT X1 LDCT 4 0(1)
24. X7 ← X7 SRA B(X1+3) SMO B+3(1)
SRA 7 0
Long integer operations are similar to the corresponding PLAN macro except that constant loading is more efficient. When the right hand side is an integer the sign bit is removed and propagated through the first word. X12 ← N where N is an integer should produce
LDXC 2 N NGN 1 0
If any long integer facility produces problems we should modify the specification rather than introduce inefficiencies into the compiler or object program. Note that CNT can be used as an operator or as part of an integer value. They produce the same results for a simple assignment but by different means e.g.
X1 ← 324CNT ⇒ LDX 1 '324/0' X1 ← CNT324 ⇒ LDCT 1 324
The second is obviously better although the other form is essential for
X1 ← X1 + 324CNT ⇒ ADX 1 '324/0'
EX indicates a LDEX instruction.
<simple K cell assignment> ::=
<K cell designator>←<K accumulator>|
<I cell designator>←<0|
<real cell designator>←0.0|
<Integer cell designator>←<store operator><integer accumulator>|
<Integer cell designator>←<part operator><integer accumulator>|
<I cell designator>←<I cell designator>|
<simple I cell assignment><add operator><I accumulator>
<simple I cell designator><logical operator><I accumulator>
<Long integer cell designator>←NEG<long integer accumulator>
(I=:: Integer|long Integer)
<store operator> ::= NEG|CARRY|NEG CARRY
<part operator> ::= EX|SA|LA|CH
<K cell assignment> ::= <simple K cell assignment>|
<long integer cell designator>←FIX<real accumulator>
A ← X1 U(B(X2)+1) ← 0 B ← NEG X2 XX ← LA X3 A(3) ← X3+X2 AND X5 C(X1) ← CH X7 X ← A1 W(X1) ← FIX A1 B(4) ← B(4) ++ X0 (3) ← FIX A1 (3) ← A1 (X1) ←SA X6
A cell assignment is used to assign a value to a designated cell. The values must normally be accumulator values. If an I cell designator appears on each side of the ← symbol then these designators must be identical. (Thus the fifth simple K cell assignment form is X ← X and is useful only as part of the two forms which follow). The designators must also appear on the same line.
The operators NEG, CARRY, EX and CH are similar to those for accumulator assignments except that EX does not disturb the remaining bits of the cell and the bottom six bits of the accumulator are used for CH, the character position of the cell being determined by the modifier if any. SA and LA mean the bottom 12 and 15 bits respectively, again without disturbing the remaining bits. The FIX operator, causes the largest integer less than the real number to be left in the first word of the long integer cell and a fractional part in the second. Note that it is inefficient to use assignments involving several logical or add operators with cells involving SMO indices.
K cells whose type is not obvious e.g. (3), (X1) are assumed to be of the correct type for the R.H.S.
The implementation is fairly obvious. Plan equivalents of (b) assuming suitable declarations are as follows:-
PLASYD PLAN
------ ----
A1 ← X1 STO 1 A
U(B(X2)+1) ← 0 SKO B(2)
STOZ $U+1
B ← NEG X2 NGS 2 B
XX ← LA X3 DLA 3 XX
A(3) ← X3+X2 AND X5 STO 3 A+3
ADS 2 A+3
ANDS 5 A+3
C(X1) ← CH X7 DCH 7 C(1)
X ← A1 SFP X
W(X1) ← FIX A1 FIX $W(1)
B(4) ← ++ X0 ADSC 0 B+4
(3) ← FIX A1 FIX 3
(3) ← A1 SFP 3
(X1) ← SA X6 DSA 6 (1)
c) By providing all the 1900 machine functions as standard the need to provide for an alternative method of labelling them is lessened. This section is therefore omitted from this document. The function definition may however, form a convenient way of providing simple local macro facilities which could be incorporated in versions of the compiler other than the first.
All the machine codes are available to the programmer as functions with their PLAN names preceded by the symbol ! with the exceptions that machine codes 111, 113, 115 are the PLAN name followed by the symbol 2, e.g. !SLC2, !NORM2, etc. Additional mnemonics for writing Trusted programs have been introduced namely: !SPP { (set PUC parameter) !ACT (Activate PUC) and !RMS (Request console message).
The method of calling these functions is defined in the next section.
<function statement> ::= <function identifier>(<X parameter>,<N parameter>)
<function identifier> ::= !(identifier>
<X parameter) ::= <octal digit)|<integer accumulator>|<1ong integer accumulator>
<N parameter> ::= <simple K cell designator>|<unsigned integer number>|
<octal value>|<character sequence>|<instruction identifier>
!CDB (X34,C(X1)) !LDN (X1,4) !GIVE(0,A(X2+3)) !FAD(3,B) !LFPZ !NULL.
The function statement calls for the execution of one 1900 machine instruction. Note that the use of SMO indices in the cell designator is strictly forbidden. The octal digit and following ',' can be omitted in functions which do not require them (e.g. BVSR). The digit but not the comma may be omitted to imply zero. The N parameter must not exceed 12 bits plus an optional modifier, or must be an instruction identifier.
Note that !LFPZ and !NUL !SUSAR do not have X or N parameters and !ACT and !SPP have only N parameters as X7 is assumed.
<K cell synonym declaration> ::=
<K type> <identifier> <synonymous cell>|
<K cell synonym declaration>,<identifier><synonymous cell>
<synonymous cell> ::= SYN(<fixed K cell designator|
SYN(<integer value>=<initial value>
<K accumulator synonym declaration> ::=
ACC<identifier> SYN <K accumulator>|
<K accumulator synonym declaration>,<identifie>SYN <K accumulator>
<fixed K cell designator> ::= <K cell identifier>|<K cell identifier>(<fixed index>)
INTEGER A16 SYN A(16) INTEGER MEM SYN(0) REAL FP SYN (0) INTEGER SWITCHES SYN(30)=#770047 ACC SUM SYN A1 INTEGER B1 SYN A(-4) REAL X = 1.7385 INTEGER XTOP SYN X, XBUTT SYN X(1)
Synonym declarations associate extra names with cells or accumulators. The types associated with synonymous cells need not agree. The last examples show a use of this facility.
The synonymous cell must have been declared before the synonym declaration. When the original is an integer value the synonym is taken as referring to that absolute location of the program. Only with this type of synonymous declaration can an initial value be set. The synonym given to an absolute location can be used wherever a normal K cell identifier could be used. In particular this facility can be used to make the fixed point accumulators act as K cells as in the second and third example above. Thus although X0←(X1) produces LDX 0 (1), X0←(MEM(1)) produces SMO 1, LDX 0 0. A fixed K cell designator using a fixed index should not be such that the cell designated is in a different domain to the cell designated by the identifier alone.
Synonym declarations need to operate as normal declarations except that the storage, base and displacement assigned to the new identifier are the same as the original or are the absolute value stated. The type bits will however not be similar. Note that SYN<integer value> = <initial value> is accepted.
<relation> ::= <|≤|=|≥|>|NOT=
<character relation> ::= <CH|≤CH|>CH|≥CH
<condition> ::= <K accumulator><relation><K primary>|
<I accumulator><relation><part address>|
<I accumulator><character relation><I primary>|
OVERFLOW|FOVERFLOW|CARRY|NOT OVERFLOW|NOT FOVERFLOW|
NOT CARRY (I=:: INTEGER| LONG INTEGER)
<part address> ::= £<K cell identifier>|$<K cell designator>
<combined condition> ::= <condition>|<combined condition> AND <condition>
<alternative condition> ::= <condition>|<alternative condition> OR <condition>
<compound condition> ::= <combined condition>|<alternative condition>
<if clause> ::= IF <compound condition> THEN
<true part> ::= <simple statement> ELSE
<if statement> ::= <if clause> <statement>|
<if clause><true part><statement>
IF X0≤0 THEN X2←3 IF A1 > MINUS 3.75 AND X1 < A(4) THEN A(4)←0 ELSE A(X1)←0 IF X1 NOT = 0 THEN X3←X3 SLL 2 ELSE IF NOT OVERFLOW THEN A1←0.0 IF X7>'%' THEN GO TO BED
<case clause> ::= CASE <modifier> OF <case sequence> ::= <statement>|<case sequence>;<statement> <case statement> ::= <case clause><case sequence> CASEND
CASE I OF
A1 ← A1 + B;
A1 ← A1 - B;
A1 ← A1 * B;
A1 ← A1 / B;
A1 ← A1 UNDER B;
CASEND
<go to statement> ::= GOTO <instruction identifier>
GOTO L3
If the goto crosses block boundaries the blocks are effectively closed. GOTO <procedure> means that no return will be made automatically. The effect of the statement is to transfer control to the labelled statement or to the first instruction of the procedure. GOTO may be written as one or two words.
Procedures and labels need not be declared before use unless they are external (see section 20).
GOTO a local quantity produces a straight BRN, GOTO a non-local (but previously declared) procedure name produces
BRN <cue>
where the cue is for the quantity <procedure name> @ unless the <procedure name> has been declared in a LOCAL statement. <procedure name> @ is an associated common area explained in section 20. If a reference is made to a label or procedure name which has not been declared it should be treated as an internal quantity. If the procedure has been declared as LOCAL then <cue> is <procedure name>. This enables segments which do not have associated common areas to be incorporated. Outstanding labels at the end of the segment are errors.
<obey statement> ::= OBEY<integer cell designator>
OBEY U(V(X1)+1)
<increment> ::= <integer primary>|-<integer primary>| CHAR
<limit> ::= <integer primary>|<part address>
<for clause> ::= FOR <integer accumulator assignment>
STEP <increment>
UNTIL <limit> DO
<for statement> ::= <for clause><statement>
FOR I ← 1 STEP 2 UNTIL 7 DO A1 ← A1+X(I) FOR X1 ← CHAR 1 OF @ BUFF STEP CHAR UNTIL ENDBUFF DO (X1) ← CH X7 FOR X3 ← S STEP -1 UNTIL 0 DO BEGIN A(X3) ← 0;B(X3+1) ← 0 END FOR X3 ← $FRED STEP 1 UNTIL $JACK DO X1 ← X1+X3;
For statements allow a statement to be executed repeatedly while the integer accumulator takes varying values. At each execution except the last, the accumulator is increased by the increment and tested for non-equality with the limit. If this test succeeds the statement is executed, if not the statement is executed once more and control then passes to the next statement. Note that to terminate the loop other than by jumping out the integer variable must reach exactly the value of the limit (if this cannot be guaranteed a WHILE statement should be used). A step of CHAR, means that the accumulator is considered as a modifier and stepped on by one character address. Note that if a complicated expression is to be used as a limit it must be first calculated and then held in an accumulator or stored. A limit of zero will be more efficient than any other.
There are several ways of implementing this and no one seems to stand out. If the limit is zero a straight 05 group can be used as a test. The restriction that the accumulator must "hit" the limit means that for K cells, a large constant or another accumulator a TXU can be used. It could also be used for small constants although this might produce a lower problem with literals. If so a SBN, 05, ADN could do it at the expense of one instruction. Steps of CHAR should use a BCHX instruction.
<while clause> ::= WHILE <compound condition> DO|DO <while statement> ::= <while clause><statement>
WHILE A1 < MAX (X1) DO A1 ← A1 + STEP
WHILE X1 < ENDBUFF DO BEGIN
X7 ← (X1)
IF X7 = END1SEQ THEN Go To OUT;
X1 ← X1 + CHAR 1
END
This can be considered as :-
label: IF condition THEN BEGIN
statement
goto label
end
with the IF condition omitted for a DO.
<declaration> ::= <K cell declaration>|<function declaration>|
<procedure declaration>|<K cell synonym declaration>|
<K accumulator synonym declaration>|<external declaration>|
<base declaration>|<global declaration>|
<lower declaration>|<define declaration>
<simple statement> ::= <K accumulator assignment>|<K cell assignment>|
<function statement>|<procedure statement>|
<case statement>|<block>|<goto statement>|<data statement>|
<obey statement>|NULL|<label definition><simple statement>
<statement> ::= <simple statement>|<if statement>|<include statement>|
<interpret statement>|<while statement>|<for statement>|
<label definition><statement>
<label definition> ::= <label identifier> |GLABEL<label identifier> :|ENTRY <digit>:
<block head> ::= BEGIN|<block head><declaration>;
<data statement> ::= DATA <initial value>|DATA(<initial value list>)
<block body> ::= <statement>|<block body>;<statement>|<block body>;<label definition>
<block> ::= <block head><block body>END
<program> ::= <statement>
<compilable segment> ::= <program>|<procedure declaration>
BEGIN REAL X ; INTEGER I; I ← 0; PROCA; DATA(3,5);
L: X ← A1; I ← I+X2 AND X3; X4 ← X4+1
ENTRY 3: IF X4=0 THEN GO TO L;IF X4 = 1 THEN GO TO OUT ;
CASE X1 OF A1 ← Z;
A1 ← Z(1);
NULL
CASEND;
GLABEL OUT: END
Blocks, labels and statements are similar to Algol. Identifiers can only be used within the. blocks in which they are declared. Semi-colons must be used to terminate statements although extra semi-colons will normally be ignored. NULL is a statement defining no action.Labels define instructions within a block or the end of a block. A GLABEL label is a label which can be referred to in sections of program compiled at different times. Glabels can be "goto"ed. or, if they occur in a procedure, can be called as a procedure. The effect of the latter is as if another similar procedure were declared with the glabel as name and with its first instruction a goto to the glabeled instruction.
A data statement causes the initial values specified to be stores in successive words at that point. Note that the number of words stored per item is foun,d from the item type so that 0 is not the same as 0.0 and that the programmer must arrange not to obey data statements.
An ENTRY label specifies an entry point for the program and the digit that follows indicates which entry.
Most of this is dealt with elswhere. NULL generates a 123 order. Algol-like dummy statements generate nothing. Although the syntax is strict about semi-colons the compiler can afford to be generous. For example an extra semi-colon) after NULL or one missing after CASEND (which must end a statement) could be commented on but allowed. Since there is no comment after END facility a great many bogies are removed from that e.g.
END
LABEL1 : END
although having a semi-colon missing could be dealt with properly. The guiding light is: if you expect a terminator and none appears, or if two cell designators or accumulators occur without an operator, insert a semi-colon between the operators and comment. Data can use the initial value mechanism without a type check.
An ENTRY label merely places the correct jump in one of the words 20-29 and a GLABEL is equivalent to the PLAN ## CUE. It should generate a satisfied cue and unlike PLAN, a local label as well. See also section 20 below. There is in general little distinction between labels and procedure names and each can be used interchangeably.
<procedure heading> ::= PROCEDURE<procedure identifier>(<integer accumulator>);|
PROCEDURE<procedure identifier>(<integer accumulator>,
<unsigned integer number>);
<procedure declaration> ::= <procedure heading><statement>|
GLABEL <procedure heading><statement>
<external specification> ::= <instruction identifier>|
<instruction identifier>(<integer accumulator>)
<external declaration> ::= EXTERNAL <external specification>|
<external declaration>,<external specification>
PROCEDURE SORT (X0);
FOR X1 ← £A STEP 1 UNTIL ENDA DO
BEGIN X6 ← A(X1);X3 ← X1;
FOR X2 ← X1 + 1 STEP 1 UNTIL ENDA DO
IF X6 ≤ A(X2) THEN BEGIN X6 ← A(X2); X3 ← X2 END;
X2 ← A(X1); A(X1) ← X6; A(X3) ← X2;
END
PROCEDURE SUM (X1,2);
BEGIN X2 ← (X1); X5 ← (X1+1);X7 ← 0;
FOR X2 ← 1 STEP 1 UNTIL X5 DO X7 ← X7+(X2);
RETURN;
END;
EXTERNAL FRED (X1), OUT, JOE (X5);
A procedure declaration serves to define a sequence of instructions and to associate an identifier with them. This sequence can then be invoked by a procedure statement or a goto <procedure identifier>. For a procedure statement the accumulator specified in the procedure heading is used as a link and when the end of the sequence of instructions is encountered, a return will be made to the next instruction after the procedure statement, unless the unsigned integer is present. In this case the return is to (n+1)th instruction after the procedure statement where n is the unsigned integer and 0 ≤ n ≤ 63. RETURN is described in 25.
Procedure declarations can appear in the declarations at the beginning of a block or can be a separately compiled section of program. In the first case communication can be via any variables declared in outer blocks or the accumulators. In the second case communication can only be via accumulators or GLOBALly declared variables. If the link accumulator is used in the procedure body for any other purpose it must be dumped and restored before the end of the procedure is encountered.
If a separately compiled procedure, or a glabel in a separately compiled segment, is used in another segment the calling segment must contain an external declaration, which specifies the link accumulator to be used where necessary. If a goto only is to be made to a procedure it can be specified as a label and glabels within procedures can be specified as procedures if required. External labels and procedure names must be specified before use.
In general a jump or call to an external procedure or glabel will cause entry to the overlay mechanism. This can be avoided if it is known that particular procedures or glabels will always be in permanent or always called from the same unit, by preceding the segment by a non-PLASYD directive. This takes one of the following forms:
LOCAL:<label list>;
LOCAL ALL;
LOCAL ALL BUT:<label list>;
where
<label list> ::= <procedure identifier>|<glabel identifier>|
<label list>,<label list>
This will inhibit the call of the overlay mechanism when this segment is entered from another for: the identifiers in the label list; all glabels and the segment name itself, or all labels and the segment name except those in the glabel list, respectively. When exit is made from a procedure the unit from which it was called must be in store. If the label list contains instruction identifiers referred to in the external declaration then CALLs and GOTOs to these identifiers will address the <procedure name> and not <procedure name>@
For a locally compiled procedure only, the identifier can be treated as a label associated with the link accumulator. Goto statements then produce normal jumps and procedure statements call instructions. Glabels (and in fact all labels) within procedures should have the same link accumulator as the procedure associated with them.
Separately compiled procedures and all glabels produce in addition a common area called <identifier>@ e.g. PROCEDURE JACK produces COMMON JACK@. This is a five word permanent common area containing the following information:
STO 1 %AAX1 [This is a LOWER COMMON AREA]
CALL 1 %EROL [The overlay package]
Area/unit no. [Handled by s/c.]
LDX 1 %AAX1 [cue for the procedure]
BRN JACK
This ensures that the program segments can be mixed into (almost) any order of overlays. If no overlay calls are in fact made little extra code is executed but this can be eliminated and storage space saved by the LOCAL directive. This should be checked for before the BEGIN or PROCEDURE which starts a segment and the compiler must be capable of compiling either the sequence described above for glabels and segment names or no common area but a program cue<identifier>@ which is identical to the program cue for the identifier itself. In either mode of operation identifiers in a special list, or marked specially, must be treated in the other mode. No directive or a LOCAL; directive causes the first mode to be entered. LOCAL ALL; and LOCAL ALL BUT: involve the second mode and a label list if present is noted for exception treatment.
Note that local procedures and labels or glabels must always be jumped to directly.
All external procedures and glabels must be specified before use. This specification could cause a blank cue to be generated whether or not the specified quantity is later used.
<procedure statement> ::= <instruction identifier>
SORT
This involves the execution of the appropriate procedure body using the designated link. A label or glabel identifier could be used in place of a procedure identifier providing the link was correctly taken care of. A procedure can only be called in this way if it is
Procedures declared within parallel blocks cannot be called unless no return is expected since crossing block boundaries will cause the loss of corresponding storage.
This produces a
CALL <link> <identifier>
for a local procedure or a call to the associated common area <identifer>@ for external quantities. This latter will need revision for EBM (Mode 4 compilation).
Undefined identifiers are assumed to be local and both the address and the link will need to be filled in when the label or procedure is encountered.
<include statement> ::= INCLUDE (<identifier>)|INCLUDE(<identifier>,SL)
INCLUDE (DATASTATMNTS)
Sections of PLASYD program which do not contain include statements may be stored by the PLASYD system and assigned an identifier. These sections can then be included in any segment that requires them by mentioning the identifier in an include statement. The facility is particularly useful for common data declarations and define declarations. The include statement should appear on a line by itself and the identifier must conform with 1900 subfile names.
Action should be to switch off the listing and call in the operating system with the subfile identifier as a parameter. The subfile will then be accessed by the operating system and passed to the compiler as normal source. When the end of the subfile is reached the operating system should cause the listing to be switched on again. Alternatively, possibly at the user's request, listing of the included section should continue without increasing the line number, to aid editing. If SL is present the INCLUDE subfile is short listed.
<return statement> ::= RETURN | RETURN(<unsigned integer>)
RETURN RETURN (3)
The first form of RETURN causes the compiled program to exit from the procedure in which the RETURN statement appears and return to the (n+1)th statement after the procedure call. n is specified in the procedure heading (see 20), or is 0 if absent. In the second form of the statement the unsigned integer, m, overrides n and control is returnd to the (m+1)th instruction after the procedure statement. The link must if necessary be restored into the accumulator before the RETURN statement. Note that a RETURN is automatically compiled at the end of a procedure so that an explicit RETURN statement is only needed for exit from the body of the procedure or in order to override the n of the procedure heading.
RETURN is compiled as EXIT X n where X is the link accumulator and n defined in the procedure heading. RETURN (m) is compiled as EXIT Xm.
<define declaration> ::= DEFINE<equation>|<define declaration>,<equation>
<equation> ::= <definee> = <expression>
<definee> ::= <identifier>
<term> ::= <integer value>|<definee>
<expression> ::= <absolute expression>|<term>|
<expression><D operator><term>
<absolute expression> ::= $<upper K cell identifier>|
$<upper K cell identifier><fixed index>|
@<fixed K cell designator>-@<fixed K cell designator>|
£<K cell identifier>-£<K cell identifier>|
@<instruction identifier>-@<instruction identifier>
<D operator> ::= + | - | * | /
DEFINE I = 3,A=1 DEFINE J = I + 5/2 DEFINE K = @X - @ Y*I
The expression is evaluated from left to right over twenty four bits and the resulting value is associated with the definee. All items in the expressions, including labels, must have been previously defined or declared. There is no need for the types of the cell identifiers of an absolute expression to agree but the two cells specified must either both be in the same common block or both in non-common lower storage or both in non-common upper storage. The difference between two addresses is a number of 1900 words. After a define statement the definee can be used wherever an integer value is allowed in the rest of the segment. If the value of the expression is positive it can be used where an unsigned integer is allowed. In particular it can be used as an assignment operand, an array length or an initial value, e.g.
INTEGER A(I) = (K*I) ; X1←J
The expression is evaluated strictly from left to right and whenever the definee is subsequently met it is replaced by the corresponding integer. The sign of the integer must be tested in cases where unsigned integers are required (e.g. array lengths). DEFINE x =$FRED is not allowed if FRED is declared in LOWER as the displacement of FRED is dependent on the address in lower and is not an absolute quantity when the DEFINEE is declared.
<nonplasyd identifier> ::= <identifier>
<nonplasyd specification> ::= <nonplasyd identifier> |
<nonplasyd identifier> (<integer accumulator>)
<nonplasyd declaration> ::= NONPLASYD <nonplasyd specification>|
<nonplasyd declaration>, <nonplasyd specification>
<nonplasyd GOTO statement> ::= GOTO <nonplasyd identifier>|
GOTO <nonplasyd identifier>(<unsigned integer number>)
<nonplasyd procedure statement> ::= <nonplasyd identifier>|
<nonplasyd identifier>(<unsigned integer number>)
NONPLASYD JACK, JOHN (X0), JOE (X1) JACK; JOHN; JOE (3); GOTO JOE; GOTO JACK (6);
Nonplasyd declarations serve to introduce separately compiled procedures or glabels in the same way as an external declaration (see 20), but also specify that these are not in a standard plasyd form (e.g. they may have been compiled in PLAN). Such procedures may have multiple entry points.
If no integer follows the nonplasyd identifier in a goto or procedure statement the identifier will be branched to or called in the same way as an external procedure. If an integer, n, follows the identifier, however, the branch or call will be made to the nth word following that specified by the identifier.
JACK (3); produces CALL <link><identifier+3> GO TO JACK (3); produces BRN <identifier+3>
<priority> ::= <unsigned integer number> <member number> ::= <unsigned integer number> <member statement> ::= MEMBER (<member number>,<priority>)
MEMBER(2,25)
The member statement allows the user when compiling multimember programs to specify the member number and priority of individual members. The statement must appear before the head of a procedure similar to LOCAL. It need only appear once for each member although there may be more than one segment in a member.
<bringoverlay statement> ::= BRINGOVERLAY <instruction identifier>
BRINGOVERLAY JACK
The bringoverlay statement allows users to bring into core store an overlay without actually entering the overlay. Any instruction identifier in the required overlay can be specified, provided this identifier has been specified in an overlay list.
The code produced is
STO 1 %AAX1 [This is a LOWER COMMON area]
CALL 1 %EROL [The overlay package]
Area/Unit no.[Handled by s/c]
LDX 1 %AAX1