Algol-68 Interpreter March, 1987 The Algol-68 Interpreter is intented to provide a tool to run small (up to 60 lines) Algol-68 programs in order to become familiar with the general philosophy of the language. It is appropriate for students' programs in a two-term programming course, but not in an industrial scale. Not all the exotic features are implemented. In particular there are no semaphores, formats and parallel-clauses. The transput is restricted to the minimal one, namely formatless character transput to channels `stand in' and `stand out' only. This manual contains a brief description how the Interpreter can be used, a list of the restrictions on the Interpreter, how to interpret the dump informations, and a list of error messages. It also contains a few sample programs. History: the Interpreter originates from the one made by L. Ammeraal in the Mathematical Center, Amsterdam, in 1973. It was written in Algol-60. The interpreter was debugged and implemented on an ICL 1903A machine by L.Csirmaz in 1974. The present competely revised version was written in C. The lexical analyzer was written by Sam Rebelsky, the other parts by L. Csirmaz, both at the University of Chicago. Later it has been ported to DOS and Linux by L. Csirmaz. C O N T E N T S 1. How to use the Interpreter 2. Spelling an Algol-68 program, symbols 3. Restrictions, deviations from the REPORT 4. Standard prelude and transput 5. Internal representation 6. What the `dump' is good for 7. Error messages 8. Sample programs 1. How to use the Interpreter In the following we describe the commands that can used to run an Algol-68 program. We use `C:>' to denote the prompt symbol. The Interpreter consists of a lexical analyzer, the interpreter proper, two utility programs to print out dump information and legible error messages, a data file containing the standard prelude, and a driver. Different parts communicate through files named `#al#.##1', `#al#.##2', and `#dump.###' which will sit in the home directory of the calling process. The command C:> A68 filename invokes the Interpreter. It reads an Algol-68 program from the file `filename'. The `filename' cannot be `dump'. The program must start with an (i.e. 'begin' 'case' 'if' or `('), and the lexical analyzer reads until the end of file, or until the brackets become balanced, whichever comes first. The program text is printed, and, if no spelling error was detected, interpreted. All the transput initiated by the program goes to the standard output and comes from the standard input. Whenever an error is detected, the message *** ERROR xx.x *** at nnn closes the output. `xx.x' is a number referring to the type of the error, and `nnn' is the serial number of the symbol at which the error was detected (see Section 7; the program listing shows this number for the first symbol in every line). Also, dump information is placed in the binary file `#dump.###'. An edited listing of the dump may be printed by the command C:> A68 dump Also, a dump is made upon interrupt (control-C), but NOT upon normal termination. An unedited (rather lengthy and illegible) listing results from appending the parameter `-': C:> A68 dump - If you don't want the source program to be listed, use the `-' parameter: C:> A68 filename - The parameter has no effect if the program contains syntactical (spelling) error. 2. Spelling Algol-68 programs Every Algol-68 program is a sequence of symbols. The task of the lexical analyzer is to split up the program into these symbols, so that the interpreter need not bother with such nuisances as long identifiers, integers, or real numbers (denotations). In fact, the interpreter is working on a sequence of symbols, and not on the character form of the program -- this is why error messages refer to symbol number, and not the line number and character position in it. 2.1. Symbols Each symbol falls into one of the following categories: bold symbol, identifier, operator, denotation, and special character. 2.1.1. Bold symbol Since there is no such a thing in Algol-68 as a reserved word, such symbols as `begin' or `end' must be distinguished from the identifier with the same letters. Those words usually appear in bold face font, or are underlined in the printed form of programs. On the computer, however, only one font is available. To make a word bold, it must be surrounded by single quotation marks ('). Thus these quotation marks can occur only in pairs (except in a string or character denotation), and between them ONLY LETTERS can occur. Both lower and upper case letters are allowed. Thus 'ThisIsAGoodBoldSymbol' is an acceptable bold symbol, while none of 'bold symbol' '2' 'mybold5' or 'bold\ symbol' Lower and upper case bold words count different, and all the standard symbols are in lower case letters. The program 'BEGIN' print("Hello word") 'END' is spelled wrongly: it does not begin with an . There is no a priory upper bound on the length of a bold symbol. For easier reading we follow the policy to underline bold words rather than enclosing them by single quotes. In programs, however, bold words MUST always be enclosed: the Interpreter does not understand underlining. The following bold symbols have special "built-in" meaning and cannot be used as mode indicators or operators: 'true' 'false' 'empty' 'loc' 'heap' 'ref' 'struct' 'flex' 'proc' 'union' 'op' 'prio' 'mode' 'int' 'real' 'bool' 'char' 'void' 'bits' 'compl' 'string' 'begin' 'end' 'if' 'then' 'else' 'elif' 'fi' 'exit' 'of' 'case' 'in' 'out' 'ouse' 'esac' 'is' 'isnt' 'goto' 'go' 'skip' 'co' 'comment' 'for' 'from' 'by' 'to' 'while' 'do' 'od' 'at' 'nil' 2.1.2. Identifier An identifier is, as usual, a sequence of letters and digits starting with a letter. However no typographical features are of significance: white spaces (space, tabulator or newline) are disregarded in identifiers. Thus `stand in', `standin' and `s t a n d i n' spell the same identifier. An identifier can even be continued in the following line. Lower and upper case letters count different, and all the standard identifiers are in lower case letters. So `pi' is predeclared in the standard prelude, but `PI' is not. 2.1.3. Operator Operators may consists of up to four characters, and they are parsed according to the following syntax: : ; ; ; . : `+'; `-'; `%'; `^'; `&'; `?'; `!'; `~'. : `<'; `='; `>'; `/'; `*'. : `:='; `=:'; . Also, or cannot be used to denote a monadic operator. Thus `+/:=' is parsed as a single operator, while `+//:=' is a sequence of two operators, namely `+' and `//:='. However, to prevent unintentional parsing (or misleading spelling), operators cannot contain intervening white spaces (spaces, tabulators, newline characters). Thus `**' is a single operator, while `* *' is two applications of the `*' operator, the second of which is, erroneously, monadic. 2.1.4. Denotation Denotations are the constants written into the program text. Like identifiers, except for string and character denotations, they can also contain intervening white spaces. Integer denotations are simple (unsigned) digit sequences. Real denotations contain either fractional or exponent part, or both. The decimal point belongs to the fractional part, and must be followed by at least one digit. The exponent can be indicated by `e' or `E' which is followed by a signed integer. The exponent part must contain at least one digit. Bits denotations start with the character sequence `2', `4', `8', or `16', followed by either `r' or `R' (for RADIX), and by an appropriate digit sequence. In case of radix 2 only the digits `0'and `1' can be used; in radix 16 the letters from `a' to `f' and from `A' to `F' stand for digits of value 10 to 15. Strings are enclosed within double quotes ("), the double quote character within a string must be doubled. Strings cannot contain newline characters, a string must be closed in the same line where it was opened. There is no denotation for strings of length one; they are character denotations instead. 2.1.5. Special characters The following characters and character sequences fall into this category: ( ) [ ] , : ; # | |: := :=: :/=: There can be no intervening space between the elements of these sequences. 2.2. Comments Comments can be placed between symbols (but not inside them) anywhere in the program text between the first and the matching . A comment starts and ends with the same symbol which can be any of the the following: # 'co' 'comment' In a comment enclosed by one kind of a separator every other separator may occur. Comments are not restricted into a single line, so an unmatched causes to drop the whole remaining portion of the program text. 3. Restrictions, deviations from the REPORT The official definition of Algol-68 is the REPORT (Revised Report on the Algorithmic Language Algol-68, Edited by A.van Wijngaarden, B.J.Mailloux, J.E.L.Peck, C.H.A.Koster, M.Sintzoff, C.H.Lindsey, L.G.Meertens, and R.G. Fisker). The language was planned to compiled and not interpreted. Thus to maintain some kind of efficiency, not only are certain exotic constructs not implemented, but the Interpreter deviates from the official definitions in certain cases. 3.1. Restrictions a) 'bytes', 'sema', 'file', 'format' and 'channel' modes are NOT implemented, values of these modes cannot be used. (`stand in' and `stand out' are exceptions, see Section 4.4). b) Integers, reals, complex numbers, and bits can be used only in single precision. Thus the bold words 'short' and 'long' cannot occur in declarers. c) Synchronization operations are not available ('down' and 'up' operators for semaphores), consequently, no parallel clauses are allowed, i.e. a collateral clause cannot be preceded by the bold word 'par'. d) Pragmats cannot be used. e) No selection can be made from a row of structures, which is done twice in the following program: 'begin' [3]'struct'('int' s,t)a; s 'of' a := t 'of' a := (1,2,3) 'end' Instead, you can use displays as follows: 'begin' [3]'struct'('int' s,t)a; a:=((1,1),(2,2),(3,3)) 'end' f) The standard prelude, especially the transput, is restricted (see Section 4. for the details). 3.2. Deviations Since the program is interpreted and not compiled, errors, even serious syntactical ones, remain undetected if the control does not reach the spot where they reside. Thus symbol sequences, which are not programs in sense of the REPORT, are sometimes accepted. Also in cases when the elaboration is "undefined", or even if the construct is forbidden, the Interpreter behaves quite intelligently. In certain cases, however it does not work exactly according to the official definition. a) There are no local generators, every generator is global (even those which start with 'loc'). b) The mode is not implemented, so names sliced from flexible arrays can be remembered (but not necessarily refer to any actual element of that array). The following program is typical in this respect. ( 'string' a := "dear"; 'ref''char' a1 = a[1]; a1 := "b"; print(a); # bear # a := "duck"; a1:= "b"; print (a) #still duck # ) c) During elaboration of a declarer, no jump out of the declarer can occur. Thus the following program, reading a value outside the range, issues an error message instead terminating the run: 'begin' 'string' month = 'case' print("Type in the number of the month: "); 'int' m; read(m); m 'in' "Jan", "Feb","March","April","May","June", "July","Aug","Sept", "Oct", "Nov","Dec" 'out' stop 'esac'; print(month) 'end' d) Certain (standard) operators are mapped onto the same internal symbol, which means that these operators are, in fact, the same. Thus redeclaring one of them redeclares the other(s) automatically. Such operators are: <= and 'le' = and 'eq' /= and 'ne' >= and 'ge' & and 'and' ** and 'up' and ^ e) Balancing is done only in s. In an or each constituent is in the same syntactical position as the itself (mainly because only the executed part of the is consulted deciding the a priori mode of the result). Thus in the following program the `?' operator is not identified: 'begin''op'? = ('real')'void':'skip'; ?('true'| 1 | 0.5) 'end'. Similarly, having the declarations 'ref''int'ii; 'int'i,j; 'bool'b; in the assignation `( b | i | ii ) := j' the right hand side is dereferenced or not depending on whether the actual value of `b' is true or false, and in no case will `ii' be dereferenced prior to the assignation. Of course, 'ref''int'( b | i | jj ) := j; does the trick. f) The in a behaves (as far as the Interpreter is concerned) as a "black box", i.e. no search is made to determine its actual scope. Instead, the following rule is applied: the scope of the is that of the tightest range which contains an elaborated declaration. Thus the first printing out `2+j' has scope 1 (being the declaration of `pp' in this range); while the second one has the scope the body of `pp' only, since, in principle, it can reach `i' which was declared there. After deproceduring `pp', the yielded routine text has newer scope than the surrounding environment, thus calling the routine text (with `0' as parameter) causes a "scope violation error" and does not print anything: 'begin' #1# 'proc'pp='proc'('int')'void': 'begin' #2# print(1); ('int'j)'void': print(2+j); #scope is 1# 'int' i; ('int'j)'void': print(3+j) #scope is 2# 'end' #2#; pp(0) 'end' #1# The program runs as expected if the declaration `'int'i;' is missing. g) To avoid unintented scope violations, if an yields, by a MORF construct, a parameterless procedure whose scope is just the scope of the clause itself, then instead letting the routine text to slip out of the clause, the procedure is called (repeatedly if necessary). Thus the program 'begin' 'proc''proc''void'pp = 'proc''void': 'begin''int'i; print(1); 'void': print(2) 'end'; 'proc''void'(pp) 'end' prints out the numbers `1' and `2' since the scope of `'void':print(2)' happens to be that of the body of `pp'. The yield of the `'proc''void'(pp)' is a routine text coerced from the result 'void' (which, when called, issues an error message). This arrangement makes the following program work which prints out the numbers 1 and 2: 'begin' print(( 'proc' p = 'int': (print((1,newline)); 'goto' lbl); 'goto' end; lbl: 2 'exit' end: p )) 'end' h) The in a , in a , or in a always has the same scope as the enclosing clause, independently of the existence of other elaborated declarations. The scope of the routine text in the below is the same as that of range 1: 'begin' #1# 'int'n; read(n); 'begin' #2# 'proc'('int')'int'f = ('int'i)'int' : (i=0 | 1 | i*f(i-1) # here # ); print(f(n)) 'end' #2# 'end' #1# This means that when executing the of the routine text, declarations only at range 1 and outside are considered. Thus the application `f(i-1)' will find `f' "undeclared" since it is not declared there. Using `'proc'pp = ('int'i)'int': ...', the scope of `f' will be that of range 2, after which the program works correctly. 4. Standard prelude and transput 4.1. Standard modes The following modes are defined by the Interpreter: 'void' 'bool' 'int' 'real' 'char' 'compl' 'bits' 'string' Integers, reals and complexs are only of single precision, so neither 'short' nor 'long' can be used with the above declarers. Integers and bits are stored in 32 bit long words, reals occupy 64 bits (double in C). The bits of a mode value are counted from left to right, the leftmost (i.e. sign) bit has serial number 0, the following, most significant bit is the first, and the rightmost, i.e. parity bit is the 31st. 4.2. Operators The available standard operators are grouped here according to their operands. 4.2.1. Row 'lwb', 'upb', both monadic and dyadic, gives the lower and upper bound, respectively, of the i-th dimension (or the first dimension if the operator is monadic) of the right hand side operand, which must be a row. 4.2.2. Boolean The operators 'or', 'and', 'not', =, /= have their standard meaning. `'abs' b' is 1 if `b' is true, and 0 if `b' is false. 4.2.3. Integer The comparison operators <, <=, =, /=, >=, > yield boolean result. The arithmetical operators +, -, *, %, %*, ^ yield integer results. `%' denotes integer division, `i%*j' is the remainder when `i' is divided by `j'. Exponentiation is repeated multiplication; if the exponent is negative, the result will be -1, 0, or +1. `i/j' yields the quotient as a real number. The applicable monadic operators are +, -, 'abs', 'odd', and 'sign'. 4.2.4. Real The comparison operators <, <=, =, /=, >=, >, and the arithmetical operators +, -, *, / are all available. They may be applied to mixed parameters too. In the exponentiation `x^i' the exponent must be an integer, exponentiation is not defined with real exponent. For reals the defined monadic operators are +, -, 'abs', 'sign', 'round', and 'entier', the last two yielding an integer result. 4.2.5. Complex Only two comparison operators, = and /= are available. The arithmetical operators are +, -, *, and / . All the operators are defined for those cases when one of the operands is complex, and the other is either complex, integer or real. Exponentiation is also defined with integer exponent. The monadic operators are 're', 'im', 'abs', 'arg', 'conj'. The dyadic operator 'i', applied to reals or integers (mixed operands are allowed) gives the complex number with the first argument as real part, and the second argument as imaginary part. 4.2.6. Bits Bits can be compared by = or by /= . The operators 'and', 'or', and 'not' behave bitwise. `b1 <= b2' yields true if `b1 'or' b2 = b2'; similarly for `b1 >= b2'. 'up' and 'down' with integer second operand shift the first bits operand logically left and right, respectively. `i 'elem' b' yields true if the `i'-th bit of `b' (counted from left) is one. The monadic operator `'abs' b' gives the integer with the same bit pattern as `b'; the inverse operator is 'bin'. 4.2.7. Character and string Strings and characters can be compared by <, <=, =, /=, >=, >. They can be added up (concatenation), and multiplied by an integer (both from left and from right).`'abs' c' for a character `c' gives its ASCII code; the inverse operator is 'repr'. 4.2.8. Assignment operators They are +:=, -:=, *:=, %:=, %*:=, /:=, and are applicable where they can be applied reasonably. Moreover the operator +=: can be applied with a string or character left operand and a string variable right operand; the L.H.S. will be added to the content of the R.H.S from the left, and the result put back into the R.H.S. 4.3. Identifiers 4.3.1. Constants The real constant `pi' with value 3.1415926...; integer constant `bits width' with value 31; character constant `blank' with value the space character (= 'repr' 32). 4.3.2. Procedures The parameterless procedure `random' produces pseudorandom real numbers between 0.0 and 1.0. The mathematical functions `sin', `cos', `tan', `arcsin', `arccos', `arctan', `sqrt', `exp', `ln' are all predefined. Also, the function `bits pack' produces a bits value from a row of boolean. 4.3.3. Halting label The label `stop' is put immediately after the closing symbol of the program. Jumping to this label causes the program to terminate. 4.3.4. Transput The following identifiers are defined in connection with transput: `stand in', `stand out', `newpage', `newline', `space', `print', `write', and `read'. 4.4. Transput Only the simplest formatless transput has been implemented. There is no binary transput, both input and output uses character conversion. The input comes from the standard input, and the output goes to the standard output. There is also no way to define new channels or files, and the identifiers `stand in' and `stand out' are provided to identify the files at the standard channels. `newpage', `newline', and `space' are, in fact, procedures which require a file as a parameter. Since files cannot be declared, the only way to call them is using `stand in' or `stand out' as parameter. These calls are equivalent to `read()' and `print()', respectively. 4.4.1. Output Procedures `print' and `write' are identical, in fact they perform the same task. After straightening the parameter of the procedure, the actual printing is done through the C procedure "printf" with the following conversions: mode of the value conversion string integer "%ld " real "%lg " char "%c" bits "%#lo " bool the printed string is either "t " or "f " That is, integer, real, bits, and bool values are printed using the shortest possible form, which is followed by a space character. If the value to be printed is the procedure `newpage', `newline', or `space', then a newpage, newline, or space character (with ASCII code 12, 10, and 32) is written to the standard output. 4.4.2. Input The procedure `read' uses mainly the C procedure "scanf" to read an actual value with the following conversion strings: mode of the value conversion string integer "%ld" real "%lg" char "%c" (it reads a single character) bits "%lo" bool "%1s" requesting 1, t, or T for true, 0, f, or F for false. If the value to be read in is `space' then the next character is skipped (by calling "getchar()"); and if it is `newpage' or `newline' then the input is skipped until a newpage (newline) character is found. In contrast to the REPORT, reading into a flexible row of character (i.e. into a 'string') is done in the same way as reading into any other row. Namely, the Interpreter reads exactly as many characters as many elements the row has, the bounds of the row do not change during reading. For example, the program line 'string' s; read(s); reads nothing, since, after the declaration, `s' has lower bound 1 and upper bound 0, thus has no element. 5. Internal representation The Interpreter uses three main areas to store the values it has to deal with. The first one is the `Program text area', where the symbolic form of the program text resides. The second is the `Linkage area' which is the linking chain between the external and internal objects. Finally, the `Working area' contains the internal objects on which the program operates. These areas are dumped out in case of abnormal termination of the interpreted program. 5.1. Program text area The symbolic form of the program text resides here. All s (such as `(', `[', 'open', 'if', 'case') are replaced by `(', and all the s by `)'. The identifiers and the user defined bold words are replaced by certain numbers which uniquely identify them; denotations are represented as pointers into a separate table. There is always an extra 'begin' symbol just before the first symbol of the program text (this is why why symbol numbering starts at 2), and ; stop: 'skip' 'end' \0 is appended at the end. `\0', a zero character, is the last in the program text. 5.2. Linkage area This area serves to link the "external objects" residing in the Program text area to the "internal objects" of Working area. Each entry here consists of two fields: the "object" and the "value". The "object" is usually (the internal code of) an identifier or user-defined bold symbol as found in the Program text, and the "value" is a pointer to the Working area giving the address of the corresponding internal object (value). If the "object" is an identifier, which, in turn, is a label, then the corresponding "value" is negative, and the absolute value is the place where the label is found in the Program text area. During the elaboration of a declaration (or parameter passing), the newly declared objects are "masked" so that they are not recognized until the end of the declaration. The following program shows the effect of masking: ( 'int'a=1,b=0; ( 'int'b=a,a=b; print((a,b)) # 0, 1 #); ( 'int'b=a; 'int'a=b; print((a,b)) # 1, 1#) ) Masked object are signified by an asterisk (*) after their "value". This area also serves to handle multiple declarations of the same external object. The "object" of an entry can be "----" which simply signifies a boundary between different regions. In this case "value" is the address of the last entry of the dynamically preceding region. To find the actual binding of an external object, one has to start at the END of the area always going backward. If the "object" field of the entry happens to be the boundary mark "----", then the search continues at the address found in the "value" field. The Linkage area has room for 2000 entries. 204 of them are occupied by the bindings of the standard prelude. 5.3. Working area All the internal objects are stored here, both those which actually represent some value, and those which describe only a mode. No value is associated with the latter. Each entry in this area has three fields "A", "B", "C". Some objects occupy a single entry, others occupy more blocks consisting of consecutive entries. In the following description the ~ means that the content is immaterial. mode of the value A B C integer INT value ~ real REAL value in B and C bool (1=true, 0=false) BOOL value ~ bits BITS value ~ void VOID ~ ~ priority (n is between 1 and 9) PRIO n ~ reference REF M nil `M' is the Working area address of the referenced value. `nil' is 0 if the actual name is 'nil', otherwise it is 1. structured value STRUCT (|) n has `n' fields, `M1',...,`Mn' are the _____________| field's Working area addresses, `S1',... | `Sn' are the (codes of the) selectors. |-> ~ M1 S1 ... ... ... ~ Mn Sn collateral value COLL (|) n exists only until the elaboration of a ______________| collateral clause. It has `n' elements, | `M1',...,`Mn' are their Working area |-> ~ M1 ~ addresses. ... ... ... ~ Mn ~ rowed value ROW (|) flex has `dim' dimensions. `flex' is 0 if the ______________| row is flexible, otherwise it is 1. `m' | is the number of elements. If it is zero |-> dim M m there is a ghost element at `M', otherwise lw1 up1 st1 `M' is the Working area address of the ... ... ... first element. `lwi', `upi' and `sti' are lwdim updim stdim the lower, upper bounds, and steps for dimension `i'. procedure PROC (|) n has `n' parameters. `u' is a pointer into ______________| the Linkage area showing the dynamic range | `v' points to the beginning of the |-> u M0 v in the routine text, or negative if the ~ M1 P1 procedure standard. `M0' is the mode of the ... ... ... result, `M1',...,`Mn' are the modes of the ~ Mn Pn parameters, and are Working area pointers. `P1',...`Pn' are the formal parameters. united value UNION (|) M The possible modes are shown by `M1',... ______________| `Mn', all pointers to the Working area. `M' | is either 0 in which case it possesses no |-> ~ M1 n actual value; otherwise `M' is a Working ~ M2 ~ area address pointing a value with mode ... ... ... among the modes of `M1',...,`Mn'. ~ Mn ~ mode indicator MODE M v `M' is either -1, or the mode declarer is under elaboration, when `M' is a Working area pointer giving a value of the actual mode. `v' is the Program text area pointer to the actual declarer. operator OP (|) prio here `prio' is the priority which is 10 ______________| if the operator is monadic. The third line | is present only if the operator is dyadic. |-> u M0 v The other notations are the same as for M2 M1 P1 procedures. ~ M2 P2 The Working area is capable to store 16000 entries, the first 620 is occupied by values from the standard prelude. 6. What the `dump' is good for Whenever the interpreted program terminates abnormally, the Interpreter dumps out the three main areas it works with: the Program text area, the Linkage area and the Working area. There is also an error number (if applicable), the program address at which the error was detected (or the interrupt occurred), the Working area address of the last value the Interpreter dealt with, and a mystic line saying whether the last statement was MORF or COMORF. (A statement is MORF if the result should be deprocedured in voiding, and COMORF otherwise. In the latter group we find the assignment, identity relation, generator, cast, and denotation.) In the Program text area identifiers are replaced by numbers, user defined bold words by (underlined) capital letter words, all of them preceded by percentage marks (%). The s appear as `(', the s as `)'. The listed text can be used to determine the representation of the external objects (since they are used in the Linkage area), also to check for possible misspelling (e.g. 'rerp' instead of 'repr'). `\0' denotes the end of the program. Only that part of the Linkage area is listed which contains the bindings of the program, the unlisted part binds standard operators and identifiers. It can be used to determine the actual binding of identifiers and operators. Similarly, the Working area is listed only for the program-defined values. Since it is handled as a heap, the occupied locations do not necessary form consecutive entries. The missing entries simply do not contain living information. For each entry, the content of field `A' is given both by name and value (if applicable), the others by value only. It is marked by an asterisk (*) if it corresponds to the initial node of a recursive mode. In certain cases a Working area entry can refer to other entries which are unlisted. Usually they sit in the standard prelude part; the most frequently referred ones are i A B C 1 (28) 'void' 0 0 2 (37) 'int' 31 0 3 (38) 'real' 3.1415926 4 (39) 'bool' 1 0 (true) 6 (40) 'char' 32 0 (space) 7 (43) 'bits' 037777777777 0 (-1) 8 (28) 'void' 0 0 9 (48) 'row' 14 0 ('string') 10 (33) 'struct' 16 2 ('compl') 14 1 6 0 15 1 0 1 16 0 3 51 (`re') 17 0 3 52 (`im') 7. Error messages There are two kind of error messages the Interpreter can issue. The first one is given by the lexical analyzer, they appear INSIDE the program text, and their presence means that the program won't be interpreted. An error message AFTER the program text (there can be only one) means that your program started to run but something went wrong. In the first case the messages are textual, in the second besides the text a number is also given which is unique for all possible errors. 7.1. Messages from the Lexical Analyzer The error messages appear INSIDE the program text, and usually they refer to az erroneous situation which was detected at that point. If the Lexical Analyzer discovers an error, the program won't be interpreted. The error texts are the following: -- unrecognizable character either some control character, or one of { } ` $ \ _ outside a string or character denotation. -- the program must start with an open symbol -- end of file was hit unexpectedly -- parenthesis mismatch means an unmatching open/close symbol, an 'if' without closing 'fi', or 'else' without preceding 'then', etc. -- misplaced bold delimiter -- missing bold delimiter a bold word is enclosed by single quote symbols, and contains letters only -- too long string -- too long number -- too long operator sequence the Lexical Analyzer cannot handle so long constructs -- missing string delimiter a string or character denotation cannot contain newline or other control characters, except for the tabulator -- wrong bits denotation in a bits denotation the radix (base) is not 2, 4, 8 or 16 -- too many denotations -- hash table is full -- character table is full the internal tables are full. 7.2. Messages from the Interpreter A message is of the form `*** ERROR xx.x *** at nnn'. Here `xx.x' is a number referring to the type of the error, and `nnn' is the place where the error was DETECTED, which is not necessarily the same as where the error is. The first two digits of the error number refer to some general context, the third refines that one. Not all the possible numbers are listed here, and, as it is the case with any kind of error messages, the true reason for the appearance of that number might be absolutely different from what is given. The texts mainly refer to what the Interpreter THINKS about the actual construct, and not what it might intented to be. The textual error message relies on the first two digits only and differs slightly from those listed here. 7.2.1. System areas 11.X Linkage area is full, too many declarations or parameter calls 12.X Working area is full. 13.X Too difficult or too large recursive mode. 7.2.2. General constructs 22.X Enclosed clause 22.1 A unit or declaration is expected at this point. Maybe the enclosed clause starting here is syntactically wrong (a `;' is before the closing symbol). 22.2 A `;' is expected after a declaration; a declaration cannot be the last element in a closed clause. 22.3 An enclosed clause ends here and no is found. Maybe the preceding enquiry clause contains a label. 23.X Collateral clause 23.1 A collateral clause or display ends here and no was found. Maybe a wrong separator. 23.2 A missing or wrong unit. 24.X Choice clause 24.1 A choice clause ends here without a . 24.2 The 'else' ('out') part of a choice clause is syntactically wrong. 24.3 The 'elif' ('ouse') part of a choice clause is syntactically wrong. 24.4 In a conditional clause the 'then' part is syntactically wrong. 24.5 Wrong unit in a case clause. 24.6 Wrong enquiry clause after 'elif' or 'ouse'. 25.X Conformity clause 25.1 The unit following a declarer is wrong. 25.2 The declarer is of wrong format. 26.X Loop 26.1 Missing identifier after 'for'. 26.2 Wrong unit after 'from', 'by', 'to'. 26.5 The enquiry clause after 'while' is syntactically wrong (maybe a label is in it). 27.X The clause between 'do' and 'od' is wrong. 7.2.3. Declarer 31.X 'ref' must be followed by a virtual declarer. 32.X Syntax error in a 'struct' declarer. 33.X Syntax error in a 'union' declarer. 33.5 Circular chain of 'union' definitions. 34.X Wrong row declarer. 34.1 This is an actual declarer, you must supply the bounds. 34.2 A unit is missing after the colon (:). 34.3 A jump occurred during elaboration of the actual bounds. 35.X Wrong actual declarer for a mode indicator. 35.1 Circular chain of mode declaration. 36.X Syntax error in a plan. 36.4 Missing identifier in a routine text's plan. 7.2.4. Declarator 41.X A routine text is expected after `=' or `:=' in a routine declaration. 42.X A unit is expected after `=' in an identity declaration. 43.X Missing unit after `:=' in a variable declaration. 44.X Wrong priority declaration. 45.X Wrong operator declaration 45.1 The routine text must be either monadic or dyadic. 46.X Wrong mode declaration. 47.X A forbidden jump during elaboration of 47.1 an identity declaration, 47.2 a variable declaration, 47.3 an operator declaration. 48.X Missing identifier after a declarator. 7.2.5. Coercion 51.X 'nil' can be coerced into a name (i.e. a mode starting with 'ref') 52.X An attempt was made to dereference a name with actual value 'nil' 52.1 in an assignation, 52.2 in an identity relation. 53.X An operator cannot be identified. 53.5 The operator possesses no actual routine text. 54.X A meek integer is expected here. 55.X The yield of a construct cannot be coerced into the a posteriori mode 55.1 in an assignment, 55.2 in an identity declaration, 55.3 in a variable declaration, 55.4 in an operator declaration, 55.5 in a cast, 55.6 after the execution of the unit in a routine text, 55.7 for the actual parameter in a procedure call, 55.8 for the enquiry clause in a choice clause, 55.9 for the result of the enquiry clause between 'while' and 'do'. 7.2.6. Other constructs 61.X General 61.1 Undeclared identifier. 61.2 Neither procedure nor a row followed by an open symbol. Maybe you left out a semicolon. 61.3 Label used in inappropriate place. 62.X Assignation 62.1 Unrecognizable unit on the right hand side. 62.3 The left hand side is not a name. 62.4 Non-flexible arrays have different bounds. 63.X Identity relation 63.1 Wrong or missing tertiary on the right hand side. 63.3 The left hand side is not a name. 63.4 The right hand side in not a name. 64.X Slicing and trimming 64.1 Missing or syntactically wrong unit after `@'. 64.2 Some index is less than the actual lower bound. 64.3 Some index is greater than the actual upper bound. 64.4 Too many or too less dimensions in the slicing. 65.X Display 65.1 A collateral clause can be coerced into a row or struct only. 65.2 A structure display has a wrong number of elements. 65.3 An element of a structure display is of wrong mode. 65.4 An element in a row display is of wrong mode. 65.5 In a multidimensional row display elements have different bounds. 66.X Selection 66.1 Missing or wrong secondary after 'of'. 66.2 The secondary after 'of' is not a structure. 66.3 The identifier before 'of' is not found among the field selectors. 67.X Procedure call 67.1 Missing or wrong actual parameter. 67.2 Wrong number of actual parameters in a procedure call. 67.3 Scope error, a procedure was called outside its scope. 67.4 A procedure with no actual value (e.g. one coerced from 'skip') was called. 68.X Routine text 68.1 Wrong or missing unit in a routine text. 69.X Other 69.1 Missing or wrong argument after a monadic operator. 69.2 Missing or wrong argument after a dyadic operator. 69.3 Badly formed generator or misplaced 'loc' or 'heap'. 69.4 Wrong symbol after 'goto'. 7.2.7. Standard operators 71.X Mathematical functions (`sin', `sqrt', etc.) require a single 'real' parameter. 72.X When applying the standard `+=:' operator, the right hand side must be a non-nil, flexible row of char. 73.X The right hand side of a standard assignment operator must be a non-nil name. 73.2 The left hand side of `+:=' must be a flexible row of char. 74.X The first operand for lwb or upb does not correspond to a valid dimension of the second operand. 75.X `bitspack' must have a single parameter of mode []'bool'. 76.X Division by zero. 7.2.8. Transput 81.X Only `space', `newline' and 'newpage' may occur in `read', `print' and `write' as procedure with parameters; and the only parameters for `space', `newline' and `newpage' are the identifiers `stand in' and `stand out'. 82.X Wrong arguments to `read', `print' or `write'. 82.1 They require a single unit as parameter. 82.3 Forbidden jump during elaboration of the parameter. 83.X Inappropriate input object 83.1 An empty (uninitialized) 'union' was attempted to read. 83.2 A reference to a name, a name with actual value 'nil', or not a name. 84.X A read was attempted from the input file, but either there were no more characters, or did not correspond to the mode 84.1 integer 84.2 bool - no more character 84.3 bool - a character different from `t',`T',`f',`F',`0',`1' 84.4 real 84.5 char 84.6 bits. 85.X Inappropriate output object 8. Sample programs The main purpose of this section is to illustrate some of the features of Algol-68 without going into details. For easier readability bold words are underlined in the program texts, otherwise they can be run by the Interpreter without any change. Each program is followed by the output of a sample run. ------------------------------------------------------------------------------ 'begin' # 8.1. procedure variable # 'proc'('int')'int' myproc; myproc := ('int' i)'int': i+1; print(myproc(10)); myproc := ('int' j)'int': j-1; print(myproc(10)) 'end' ***** 11 9 ------------------------------------------------------------------------------ 'begin' # 8.2. greatest common divisor # 'proc' gcd = ('int' a,b)'int': (b=0 | 'abs' a | gcd(b,a 'mod' b)); 'while' 'int' a,b; print((newline,"two integers please : ")); read((a,b)); a>0 'or' b>0 'do' print((blank*15,"gcd of ",a,"and ",b,"is ",gcd(a,b))) 'od' 'end' ***** two integers please : 35 5555 gcd of 35 and 5555 is 5 two integers please : 777 7777777 gcd of 777 and 7777777 is 7 two integers please : 37 999 gcd of 37 and 999 is 37 two integers please : 0 0 ------------------------------------------------------------------------------ 'begin' # 8.3. summation procedure # 'proc' sum = ('int' n, 'proc'('int')'real' p)'real': 'begin''real' s:=0; 'for' i 'to' n 'do' s+:=p(i) 'od'; s 'end'; print((sum(10,('int' j)'real': sin(2*pi*j/10)),newline, sum(10,('int' j)'real': cos(2*pi*j/10)))) 'end' ***** -2.742152e-015 -6.661338e-015 ------------------------------------------------------------------------------ 'begin' # 8.4. drawing # 'real' c=2*pi; 'proc' f=('real' x)'real': exp(-x)*sin(c*x); 'real' d=.0625, s=32; 'int' h=34, lim=30; 'for' i 'from' 0 'to' lim 'do' 'real' y = f(d*i); print((blank*('round'(s*y)+h),"*",newline)) 'od' 'end' ***** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ------------------------------------------------------------------------------ 'begin' # 8.5. continued fraction # 'op' ? = ([]'real' a)'real': ('upb' a = 1 | a[1] | a[1]+1.0/ ?a[2:]); []'real' x=(1,1,1,1,1,1,1,1), y=(1,2,3,4,5,6,7,8); print((?x, newline, ?y)) 'end' ***** 1.619048 1.433127 ------------------------------------------------------------------------------ 'begin' # 8.6. sample program for united modes # 'mode''rc' = 'union'('real','compl'); 'proc' qe = ('real' a,b,c)[]'rc': # quadratic equation with real coefficients # 'if''real' d:=b^2-4*a*c; d>0 'then' d:=sqrt(d)/2/a; (-b/2/a+d, -b/2/a-d) 'elif' d=0 'then' -b/2/a 'else' d:=sqrt(-d)/2/a; 'real' re=-b/2/a; (re 'i' d, re 'i' -d) 'fi'; '_'w'hile' 'real' a,b,c; print((newline,"the coefficients, please : ")); read((a,b,c)); a/=0 'do' print(qe(a,b,c)) 'od' 'end' ***** the coefficients, please : 1 2 1 -1 the coefficients, please : 4 0 1 0 0.5 0 -0.5 the coefficients, please : 1 1 1 -0.5 0.866025 -0.5 -0.866025 the coefficients, please : 0 0 0 ------------------------------------------------------------------------------ 'begin' # 8.7. generating permutations # 'int' n; read(n); 'proc' perm =('ref'[]'int' a)'void': ('int' n = 'upb' a; 'if' n=1 'then' printperm 'else''to' n 'do' perm(a[:n-1]); 'int' a1=a[1]; a[:n-1]:=a[2:]; a[n]:=a1 'od' 'fi' ); 'proc' printperm = 'void': ('for' i 'to' n 'do' print(t[i]) 'od'; print(newline)); [n]'int' t; 'for' i 'to' n 'do' t[i]:=i 'od'; perm(t) 'end' ***** 3 1 2 3 2 1 3 2 3 1 3 2 1 3 1 2 1 3 2 ------------------------------------------------------------------------------ 'begin' # 8.8. procedure with itself as parameter # 'mode' 'p' = 'proc'('p')'int'; 'proc' fact = ('p' f)'int': (i=0|1|'int' j=i; i-:=1; j*f(f)); 'proc' q = ('int' n)'int': (i:=n; fact(fact)); 'int' i; 'for' i 'to' 10 'do' print((q(i),newline)) 'od' 'end' ***** 1 2 6 24 120 720 5040 40320 362880 3628800 ------------------------------------------------------------------------------ 'begin' # 8.9. calendar # 'proc' what = ('int' month,day,year)'void': ( 'bool' greg = year>1582 'or' year=1582 'and' month*100+day>=1015; 'bool' leap = year%*4=0 'and' ('not' greg 'or' year%*100/=0 'or' year%*400=0); 'int' r = day + year + 'case' month 'in' 0,3,3,6,1,4,6,2,5,0,3,5 'esac' + 'if' greg 'then' 'int' j = year-1600; year%4-j%100+j%400-10 'else' year%4 'fi' - 'abs'(leap 'and' month<3); print(( blank*17, "that day is ", 'case' r%*7 'in' "Friday","Saturday","Sunday","Monday","Tuesday","Wednesday" 'out' "Thursday" 'esac', newline)) ); 'while''int' month,day,year; print("your date (month, day, year)? "); read((month,day,year)); month>0 'and' month<13 'do' what(month,day,year) 'od' 'end' ***** your date (month, day, year)? 07 04 1776 that day is Thursday your date (month, day, year)? 12 31 1987 that day is Thursday your date (month, day, year)? 01 01 1988 that day is Friday your date (month, day, year)? 0 0 0 ------------------------------------------------------------------------------ 'begin' # 8.10. scope error # 'int' n; read(n); 'begin' 'proc'('int')'int' f = ('int' i)'int': (i=0|1|i*f(i-1)); 'proc' g = ('int' i)'int': (i=0|1|i*g(i-1)); print(g(n)); print(f(n)) 'end' 'end' ***** 7 5040 *** ERROR 61.1 *** at 35 Undeclared identifier; or unrecognizable unit ------------------------------------------------------------------------------ 'begin' # 8.11. magic quadrangle # 'proc' Q = ('int' n)'void': ('int' m=2*n+1; [0:m-1,0:m-1]'int' A; 'int' x:=n, y:=m, i:=0; 'to' m 'do' x-:=1; y-:=2; 'to' m 'do' A[(x+:=1)%*m,(y+:=1)%*m]:= i+:=1 'od''od'; print((newline, "The rank: ",m,newline)); 'for' k 'to' m 'do''for'j'to' m 'do' print(( (A[j-1,k-1]<10|" "|" "), A[j-1,k-1])) 'od'; print(newline) 'od' ); Q(1); Q(3) 'end' ***** The rank: 3 4 9 2 3 5 7 8 1 6 The rank: 7 22 31 40 49 2 11 20 21 23 32 41 43 3 12 13 15 24 33 42 44 4 5 14 16 25 34 36 45 46 6 8 17 26 35 37 38 47 7 9 18 27 29 30 39 48 1 10 19 28 ------------------------------------------------------------------------------ 'begin' # 8.12. alphabetical ordering # 'mode''stack'='struct'('ref''stack'left,'string'word,'ref''stack'right); 'ref''stack'roof:= 'nil'; 'proc'in=('string'a,'ref''ref''stack' b) 'void' : 'if''ref''stack' (b):=:'nil' 'then' b:='heap''stack' :=('nil',a,'nil') 'else' in(a,'if' a12 'or' day<1 'or' day>31 'then' print((newline,"Sorry, wrong date")); stop 'fi'; print((newline,newline)); 'string' f:="The weather tomorrow will be "; 'int' n='upb' f+1; f +:= 'if' random<.5 'then' "warm" 'else' "cold" 'fi' + "er than usual."; f := f + 'repr' 10 #newline# + 'if' random<.5 'then' "No precipitation" 'else' 'if' f[n:n+3]="warm" 'then' (month<3|"Some flurries"|:month<10|"Light rain"|"Wet snow") 'else' (month<5 'or' 9eps'then'y1:=y2; h/:=2; c:=0; out:='false'; L2'fi'; 'if'out'then'y3 'else' x+:=2*h; y:=y3; 'if'(c+:=1)>5 'then'c:=0; h*:=2 'fi'; 'if''abs'(x1-x)<2.01*'abs' h 'then' out:='true'; h:=(x1-x)/2 'fi'; L1 'fi' ); print(RK(0,1,('real' x,y)'real':y,3,.00001)); print((exp(3),newline)); print(RK(0,0,('real' x,y)'real':x+y,3,.00001)); print((exp(3)-4,newline)) 'end' ***** 20.085516 20.085537 16.085516 16.085537 ------------------------------------------------------------------------------ 'begin' # 8.15. a recursive procedure # 'proc' p = ('int' n, 'proc''int' t)'int': ( 'int' m=n-1; 'proc' B = 'int': (m>0|p(m,t)+p(m-1,t)|t); 'if' m>0 'then' p(m,B)+p(m-1,B) 'else' t 'fi' ); 'for' i 'to' 4 'do' print((p(i,'int':1),newline)) 'od' 'end' ***** 1 4 25 841 ------------------------------------------------------------------------------ 'begin' # 8.16. linear algebra # 'op' * = ([]'real' A,B)'real': #inner product# ('real' p:=0; 'for' i 'to''upb' A 'do' p+:=A[i]*B[i] 'od'; p); 'op' * = ([]'real' A, [,]'real' B)[]'real': # matrix product # ([1:'upb' A]'real'P; 'for'i'to''upb'A'do'P[i]:=A*B[,i]'od'; P); 'op' / = ([]'real'A,[,]'real'B)[]'real': # linear equation # 'begin' 'int' n='upb' A; 'int' n1=n+1; [1:n,1:n1]'real' P; P[,1:n]:=B; P[,n1]:=A; 'for' i 'to' n 'do' 'in'_t i1=i+1, 'real' m=1/P[i,i]; 'for' j 'from' i+1 'to' n1 'do' P[i,j]*:=m 'od'; 'for' j 'to' n 'do' 'if' i/=j 'then' 'real' m=P[j,i]; 'for'k'from'i1'to'n1'do' P[j,k]-:=m*P[i,k] 'od' 'fi' 'od' 'od'; P[,n+1] 'end'; [,]'real' A=((2,1,0),(1,2,1),(0,1,2)); []'real' B=(3,4,3), C = (3,1,-3); print(("A[1,] ",A[1,],newline,"A[2,] ",A[2,],newline)); print(("A[3,] ",A[3,],newline,newline)); print(("B = ",B," C = ",C," B*C = ",B*C,newline,newline)); print(("B/A = ",B/A,blank*5,"B/A*A = ",B/A*A,newline)); print(("C/A = ",C/A,blank*4,"C/A*A = ",C/A*A,newline)) 'end' ***** A[1,] 2 1 0 A[2,] 1 2 1 A[3,] 0 1 2 B = 3 4 3 C = 3 1 -3 B*C = 4 B/A = 1 1 1 B/A*A = 3 4 3 C/A = 1 1 -2 C/A*A = 3 1 -3 ------------------------------------------------------------------------------ 'begin' # 8.17. pancakes game # 'int' n; 'while' print("How many pancakes do you want to play with? "); read(n); n<3 'or' n>20 'do''skip''od' ; [n]'int' A; 'bool' again:='true'; 'proc' pancakes = 'void': 'begin' print(newline); 'for' i 'to' n 'do' 'int' ai=A[i]; print((newline,(i<10|" "|""),i," "*(n-ai+7),"*"*(2*ai-1))) 'od'; print(newline) 'end'; 'end'; 'while' again 'do' 'for' i 'to' n 'do' A[i]:=i 'od'; 'for' i 'to' n-1 'do' 'int' j=i+'entier'((n+1-i)*random), ai=A[i]; A[i]:=A[j]; A[j]:=ai 'od'; 'int' move:=0; 'while''bool'b:='true';'for'i'to'n'while'b'do'b:=A[i]=i'od';'not'b 'do' pancakes; 'int' k; 'while' print((newline,move," your move: ")); read(k); k<2 'or' k>n 'do'print(" wrong answer, try again")'od'; move +:= 1; 'for'i'to'k%2'do''int'ai=A[i];A[i]:=A[k+1-i];A[k+1-i]:=ai'od' 'od'; pancakes; print((newline,newline,"you win in ",move,"moves!!",newline)); 'char' c; 'while' print("more game (answer y or n)? "); read((newline,c)); c/="y" 'and' c/="n" 'do''skip''od'; again := c="y" 'od' 'end' ***** How many pancakes do you want to play with? 5 1 ********* 2 *** 3 * 4 ******* 5 ***** 0 your move: 5 1 ***** 2 ******* 3 * 4 *** 5 ********* 1 your move: 3 1 * 2 ******* 3 ***** 4 *** 5 ********* 2 your move: 4 1 *** 2 ***** 3 ******* 4 * 5 ********* 3 your move: 3 1 ******* 2 ***** 3 *** 4 * 5 ********* 4 your move: 4 1 * 2 *** 3 ***** 4 ******* 5 ********* you win in 5 moves!! more game (answer y or n)? n ------------------------------------------------------------------------------ 'begin' # 8.18. a package to implement compound lists # 'mode''atom' = 'union'('int', 'ref''list'), 'list' = 'struct'('atom' item, 'ref''list' rest); 'proc' size = ('ref''list' h)'int': 'if' h:=:'nil' 'then' 0 'else'size(rest'of'h)+(item'of'h|('int'):1,('ref''list'k):size(k)) 'fi'; 'proc' agree = ('atom' a,b)'bool': 'case' a 'in' ('int'i):(b|('int'j):i=j|'false'), ('ref''list'h1):(b|('ref''list'h2):eqn(h1,h2)|'false') 'esac'; 'proc' eqn = ('ref''list' h1,h2)'bool': 'if' h1:=:'nil''then' h2:=:'nil' 'elif' h2:=:'nil''then''false' 'elif' agree(item'of'h1,item'of'h2)'then'eqn(rest'of'h1,rest'of'h2) 'else''false' 'fi'; 'proc' delete = ('ref''list' h, 'atom' a)'ref''list': 'if' h:=:'nil''then''nil' 'elif' agree(item 'of' h,a) 'then' delete(rest 'of' h,a) 'else' rest 'of' h:=delete(rest 'of' h,a); 'case' item 'of' h 'in' ('ref''list' h1):item 'of' h:=delete(h1,a) 'esac'; h 'fi'; 'proc' out = ('ref''list' h)'void': 'if' h:=:'nil''then' print(" ~ ") 'else' print("("); (item 'of' h|('int' i):print((blank,i)), ('ref''list' h):out(h)); print("|"); out(rest 'of' h); print(")") 'fi'; 'proc' copy = ('ref''list' h)'ref''list': 'if' h:=:'nil''then''nil' 'else''heap''list':=((item'of'h|('int'i):i,('ref''list'h):copy(h)), copy(rest'of'h) ) 'fi'; 'atom' one:=1, two:=2, zero:=0; 'list' l1,l2,l3,l4,l5,l6,l7; 'list' head:=(one,l1); l1:=(l2,l3); l2:=(two,l4); l3:=(one,l5); l4:=(l6,'nil'); l5:=(l7,'nil'); l6:=(one,'nil'); l7:=(one,'nil'); out(head); print((newline," size=",size(head),newline)); 'ref''list' d1=delete(copy(head),one); out(d1); print((newline," size=",size(d1),newline)); 'ref''list' d2=delete(copy(head),two); out(d2); print((newline," size=",size(d2),newline)); 'ref''list' d3=delete(delete(head,l2),one); out(d3); print((newline," size=",size(d3),newline)) 'end' ***** ( 1 |(( 2 |(( 1 | ~ )| ~ ))|( 1 |(( 1 | ~ )| ~ )))) size=5 (( 2 |( ~ | ~ ))|( ~ | ~ )) size=1 ( 1 |((( 1 | ~ )| ~ )|( 1 |(( 1 | ~ )| ~ )))) size=4 ( ~ | ~ ) size=0 ------------------------------------------------------------------------------ 'begin' # 8.19. Euler summation # 'proc' euler = ('proc'('int')'real' f, 'real' eps, 'int' tim)'real': 'begin''int' n:=1,t; 'real' mn,ds:=eps; [1:16]'real' m; 'real' sum:=(m[1]:=f(1))/2; 'for' i 'from' 2 'while' (t:=('abs' ds < eps|t+1|1))<=tim 'do' mn:=f(i); 'for' k 'to' n 'do' mn:=((ds:=mn)+m[k])/2;m[k]:=ds 'od'; sum+:=(ds:=('abs'mn<'abs'm[n]'and'n<16|n+:=1;m[n]:=mn;mn/2|mn)) 'od'; sum 'end'; print(4*euler(('int' i)'real':('odd' i|1/(2*i-1)|-1/(2*i-1)),1e-6,2)) 'end' ***** 3.141592 ------------------------------------------------------------------------------ 'begin' # 8.20. formula manipulation # 'mode''E' = 'struct'('rF'L, 'int'op, 'rF'R); 'mode''F' = 'union'('real','char','E'); 'mode''rF' = 'ref''F'; 'F' zero:=0.0, one:=1.0; 'op' = = ('rF'a, 'int' b)'bool': 'case' a 'in' ('real' x): 'abs'(x-b)<1e-5 'out''false''esac'; 'op' + = ('rF'a,b)'rF': 'if'a=0'then'b'elif'b=0'then'a'else' 'heap''F':='E'((a,1,b)) 'fi'; 'op' - = ('rF'a,b)'rF': 'if'b=0'then'a'else' 'heap''F':='E'((a,2,b)) 'fi'; 'op' * = ('rF'a,b)'rF': 'if'a=0'or'b=0'then'zero'elif'a=1'then'b'elif'b=1'then'a'else' 'heap''F' := 'E'((a,3,b)) 'fi'; 'op' / = ('rF' a,b)'rF': 'if'a=0'then'zero'elif'b=1'then'a'else''heap' 'F':='E'((a,4,b)) 'fi'; 'prio' = =4, + =6,- =6,* =7,/ =7; 'proc' der = ('rF' f)'rF': 'case' f 'in' ('real'): zero, ('char'): one, ('E' e ): 'case''rF'Le=L'of'e, Re=R'of'e;'rF'dLe=der(Le), dRe=der(Re); op'of'e'in' dLe+dRe, dLe-dRe, Le*dRe+dLe*Re, (dLe-f*dRe)/Re 'esac' 'esac'; 'proc' value = ('rF'f,'real'x)'real': 'case' f 'in' ('real' y): y, ('char' ): x, ('E' e ): 'case' 'real'L=value(L 'of' e,x), R=value(R 'of' e,x); op 'of' e 'in' L+R, L-R, L*R, L/R 'esac' 'esac'; 'proc' write = ('rF' f)'void': 'case' f 'in' ('union'('real', 'char') y): print(y), ('E' e): (print("("); write(L 'of' e); print((op 'of' e|"+", "-", "*", "/")); write(R 'of' e); print(")") ) 'esac'; 'F' x:="x"; 'rF' f:=(one-x)/(one-x); 'rF' df=der(f); print(newline); write(f); print(newline); write(df); print(newline); print((value(f,0), value(df,0))) 'end' ***** ((1 -x)/(1 -x)) (((0 -1 )-(((1 -x)/(1 -x))*(0 -1 )))/(1 -x)) 1 0 ------------------------------------------------------------------------------