769 lines
20 KiB
Plaintext
769 lines
20 KiB
Plaintext
|
|
|
|
################ ############ ###### ######
|
|
## ## ## ## ## ## ## ##
|
|
###### ###### ####### ## ## ### ##
|
|
## ## ## ## ## ##
|
|
## ## ####### ## ## ### ##
|
|
## ## ## ## ## ## ## ##
|
|
######## ############ ###### ######
|
|
|
|
----==[ A MINIMAL PROCEDURAL LANGUAGE ]==----
|
|
|
|
|
|
PROGRAM
|
|
*-------*
|
|
|
|
A program is a set of declarations followed by a compound
|
|
statement. Here is the minimal T3X program:
|
|
|
|
DO END
|
|
|
|
|
|
COMMENTS
|
|
*--------*
|
|
|
|
A comment is started with an exclamation point (!) and extends
|
|
up to the end of the current line. Example:
|
|
|
|
DO END ! Do nothing
|
|
|
|
|
|
DECLARATIONS
|
|
*------------*
|
|
|
|
-----[ CONST name = cvalue, ... ; ]-----------------------------
|
|
|
|
Assign names to constant values.
|
|
|
|
Example: CONST false = 0, true = %1;
|
|
|
|
|
|
VAR name, ... ;
|
|
-----[ VAR name[cvalue], ... ; ]--------------------------------
|
|
VAR name::cvalue, ... ;
|
|
|
|
Define variables, vectors, and byte vectors, respectively.
|
|
Different definitions may be mixed. Vector elements start at
|
|
an index of 0.
|
|
|
|
Example: VAR stack[STACK_LEN], ptr;
|
|
|
|
-----[ STRUCT name = name_1, ..., name_N; ]---------------------
|
|
|
|
Shorthand for CONST name_1 = 0, ..., name_N = N-1, name = N;
|
|
Used to impose structure on vectors and byte vectors.
|
|
|
|
Example: STRUCT POINT = PX, PY, PCOLOR;
|
|
VAR p[POINT];
|
|
|
|
|
|
-----[ DECL name(cvalue), ... ; ]-------------------------------
|
|
|
|
Declare functions whose definitions follow later, where the
|
|
cvalue is the number of arguments. Used to implement mutual
|
|
recursion.
|
|
|
|
Example: DECL odd(1);
|
|
even(x) RETURN x=0-> 1: odd(x-1);
|
|
odd(x) RETURN x=1-> 1: even(x-1);
|
|
|
|
|
|
-----[ name(name_1, ...) statement ]----------------------------
|
|
|
|
Define function "name" with arguments "name_1", ... and a
|
|
statement as its body. The number of arguments must match
|
|
any previous DECL of the same function.
|
|
|
|
The arguments of a function are only visible within the
|
|
(statement) of the function.
|
|
|
|
Example: hello(s, x) DO VAR i;
|
|
FOR (i=0, x) DO
|
|
writes(s);
|
|
writes("\n");
|
|
END
|
|
END
|
|
|
|
(Writes() writes a string; it is defined later in this text.)
|
|
|
|
|
|
STATEMENTS
|
|
*----------*
|
|
|
|
-----[ name := expression; ]------------------------------------
|
|
|
|
Assign the value of an expression to a variable.
|
|
|
|
Example: DO VAR x; x := 123; END
|
|
|
|
|
|
-----[ name[value]... := value; ]-------------------------------
|
|
name::value := value;
|
|
|
|
Assign the value of an expression to an element of a vector
|
|
or a byte vector. Multiple subscripts may be applied to to a
|
|
vector:
|
|
|
|
vec[i][j]... := i*j;
|
|
|
|
In general, VEC[i][j] denotes the j'th element of the i'th
|
|
element of VEC.
|
|
|
|
Note that the :: operator is right-associative, so v::x::i
|
|
equals v::(x::i). This is particularly important when mixing
|
|
subscripts, because
|
|
|
|
vec[i]::j[k] := 0;
|
|
|
|
would assign 0 to the j[k]'th element of vec[i]. (This makes
|
|
sense, because vec[i]::j would not deliver a valid address.)
|
|
|
|
|
|
-----[ name(); ]-------------------------------
|
|
name(expression_1, ...);
|
|
|
|
Call the function with the given name, passing the values of the
|
|
expressions to the function. An empty set of parentheses is used
|
|
to pass zero arguments. The result of the function is discarded.
|
|
|
|
For further details see the description of function calls in the
|
|
expression section.
|
|
|
|
|
|
-----[ IF (condition) statement_1 ]-------------------
|
|
IE (condition) statement_1 ELSE statement_2
|
|
|
|
Both of these statements run statement_1, if the given
|
|
condition is true.
|
|
|
|
In addition, IE/ELSE runs statement_2, if the conditions is
|
|
false. In this case, IF just passes control to the subsequent
|
|
statement.
|
|
|
|
Example: IE (0)
|
|
IF (1) RETURN 1;
|
|
ELSE
|
|
RETURN 2;
|
|
|
|
The example always returns 2, because only an IE statement can
|
|
have an ELSE branch. There is no "dangling else" problem.
|
|
|
|
|
|
-----[ WHILE (condition) statement ]----------------------------
|
|
|
|
Repeat the statement while the condition is true. When the
|
|
condition is not true initially, never run the statement.
|
|
|
|
Example: ! Count from 1 to 10
|
|
DO VAR i;
|
|
i := 0;
|
|
WHILE (i < 10)
|
|
i := i+1;
|
|
END
|
|
|
|
|
|
---[ FOR (name=expression_1, expression_2, cvalue) statement ]--
|
|
FOR (name=expression_1, expression_2) statement
|
|
|
|
Assign the value of expression_1 to name, then compare name to
|
|
expression_2. If cvalue is not negative, repeat the statement
|
|
while name < expression_2. Otherwise repeat the statement while
|
|
name > expression_2. After running the statement, add cvalue
|
|
to name. Formally:
|
|
|
|
name := expression_1;
|
|
WHILE ( cvalue > 0 /\ name < expression \/
|
|
cvalue < 0 /\ name > expression )
|
|
DO
|
|
statement;
|
|
name := name + cvalue;
|
|
END
|
|
|
|
When the cvalue is omitted, it defaults to 1.
|
|
|
|
Examples: DO VAR i;
|
|
FOR (i=1, 11); ! count from 1 to 10
|
|
FOR (i=10, 0, %1); ! count from 10 to 1
|
|
END
|
|
|
|
|
|
-----[ LEAVE; ]-------------------------------------------------
|
|
|
|
Leave the innermost WHILE or FOR loop, passing control to the
|
|
first statement following the loop.
|
|
|
|
Example: DO VAR i; ! Count from 1 to 50
|
|
FOR (i=1, 100) IF (i=50) LEAVE;
|
|
END
|
|
|
|
|
|
-----[ LOOP; ]--------------------------------------------------
|
|
|
|
Re-enter the innermost WHILE or FOR loop. WHILE loops are
|
|
re-entered at the point where the condition is tested, and
|
|
FOR loops are re-entered at the point where the counter is
|
|
incremented.
|
|
|
|
Example: DO VAR i; ! This program never prints X
|
|
FOR (i=1, 10) DO
|
|
LOOP;
|
|
T.WRITE(1, "x", 1);
|
|
END
|
|
END
|
|
|
|
|
|
-----[ RETURN expression; ]-------------------------------------
|
|
|
|
Return a value from a function. For further details see the
|
|
description of function calls in the expression section.
|
|
|
|
Example: inc(x) RETURN x+1;
|
|
|
|
|
|
-----[ HALT cvalue; ]-------------------------------------------
|
|
|
|
Halt program and return the given exit code to the operating
|
|
system.
|
|
|
|
Example: HALT 1;
|
|
|
|
|
|
-----[ DO statement ... END ]-------------------
|
|
DO declaration ... statement ... END
|
|
|
|
Compound statement of the form DO ... END are used to place
|
|
multiple statements in a context where only a single statement
|
|
is expected, like selection, loop, and function bodies.
|
|
|
|
A compound statement may declare its own local variables,
|
|
constant, and structures (using VAR, CONST, or STRUCT). A
|
|
local variable of a compound statement is created and
|
|
allocated at the beginning of the statement is ceases to
|
|
exist at the end of the statement.
|
|
|
|
Note that the form
|
|
|
|
DO declaration ... END
|
|
|
|
also exists, but is essentially an empty statement.
|
|
|
|
Example: DO var i, x; ! Compute 10 factorial
|
|
x := 1;
|
|
for (i=1, 10)
|
|
x := x*i;
|
|
END
|
|
|
|
|
|
-----[ DO END ]-------------------------------------------------
|
|
;
|
|
|
|
These are both empty statements or null statements. They do not
|
|
do anything when run and may be used as placeholders where a
|
|
statement would be expected. They are also used to show that
|
|
nothing is to be done in a specific situation, like in
|
|
|
|
IE (x = 0)
|
|
;
|
|
ELSE IE (x < 0)
|
|
statement;
|
|
ELSE
|
|
statement;
|
|
|
|
Examples: FOR (i=0, 100000) DO END ! waste some time
|
|
|
|
|
|
EXPRESSIONS
|
|
*-----------*
|
|
|
|
An expression is a variable or a literal or a function call or
|
|
a set of operators applied to one of these. There are unary,
|
|
binary, and ternary operators.
|
|
|
|
Examples: -a ! negate a
|
|
b*c ! product of b and c
|
|
x->y:z ! if x then y else z
|
|
|
|
In the following, the symbols X, Y, and Z denote variables or
|
|
literals.
|
|
|
|
These operators exist (P denotes precedence, A associativity):
|
|
|
|
+--------------------------------------------------------+
|
|
| OPERATOR | P | A | DESCRIPTION |
|
|
|===========+============================================|
|
|
| X[Y] | 9 | L | the Y'th element of the vector X |
|
|
| X::Y | 9 | R | the Y'th byte of the byte vector X |
|
|
|-----------+---+---+------------------------------------|
|
|
| -X | 8 | - | the negative value of X |
|
|
| ~X | 8 | - | the bitwise inverse of X |
|
|
| \X | 8 | - | logical NOT of X |
|
|
| @X | 8 | - | the address of X |
|
|
|-----------+---+---+------------------------------------|
|
|
| X*Y | 7 | L | the product of X and Y |
|
|
| Y/Y | 7 | L | the integer quotient of X and Y |
|
|
| X mod Y | 7 | L | the division remainder of X and Y |
|
|
|-----------+---+---+------------------------------------|
|
|
| X+Y | 6 | L | the sum of X and Y |
|
|
| X-Y | 6 | L | the difference between X and Y |
|
|
|-----------+---+---+------------------------------------|
|
|
| X&Y | 5 | L | the bitwise AND of X and Y |
|
|
| X|Y | 5 | L | the bitwise OR of X and Y |
|
|
| X^Y | 5 | L | the bitwise XOR of X and Y |
|
|
| X<<Y | 5 | L | X shifted to the left by Y bits |
|
|
| X>>Y | 5 | L | X shifted to the right by Y bits |
|
|
|-----------+---+---+------------------------------------|
|
|
| X<Y | 4 | L | %1, if X is less than Y, else 0 |
|
|
| X>Y | 4 | L | %1, if X is less than Y, else 0 |
|
|
| X<=Y | 4 | L | %1, if X is less/equal Y, else 0 |
|
|
| X>=Y | 4 | L | %1, if X is greater/equal Y, else 0|
|
|
|-----------+---+---+------------------------------------|
|
|
| X=Y | 3 | L | %1, if X equals Y, else 0 |
|
|
| X\=Y | 3 | L | %1, if X does not equal Y, else 0 |
|
|
|-----------+---+---+------------------------------------|
|
|
| X/\Y | 2 | L | if X then Y else 0 |
|
|
| | | | (short-circuit logical AND) |
|
|
|-----------+---+---+------------------------------------|
|
|
| X\/Y | 1 | L | if X then X else Y |
|
|
| | | | (short-circuit logical OR) |
|
|
|-----------+---+---+------------------------------------|
|
|
| X->Y:Z | 0 | - | if X then Y else Z |
|
|
+--------------------------------------------------------+
|
|
|
|
Higher precedence means that an operator binds stronger, e.g.
|
|
-X::Y actually means -(X::Y).
|
|
|
|
Left-associativity (L) means that x+y+z = (x+y)+z and
|
|
right-associativity (R) means that x::y::z = x::(y::z).
|
|
|
|
|
|
CONDITIONS
|
|
*----------*
|
|
|
|
A condition is an expression appearing in a condition context,
|
|
like the condition of an IF or WHILE statement or the first
|
|
operand of the X->Y:Z operator.
|
|
|
|
In an expression context, the value 0 is considered to be
|
|
"false", and any other value is considered to be true. For
|
|
example:
|
|
|
|
X=X is true
|
|
1=2 is false
|
|
"x" is true
|
|
5>7 is false
|
|
|
|
The canonical truth value, as returned by 1=1, is %1.
|
|
|
|
|
|
FUNCTION CALLS
|
|
*--------------*
|
|
|
|
When a function call appears in an expression, the result of
|
|
the function, as returned by RETURN is used as an operand.
|
|
|
|
A function call is performed as follows:
|
|
|
|
Each actual argument in the call
|
|
|
|
function(argument_1, ...)
|
|
|
|
is passed to the function and bound to the corresponding formal
|
|
argument ("argument") of the receiving function. The function
|
|
then runs its statement, which may produce a value via RETURN.
|
|
When no RETURN statement exists in the statement, 0 is returned.
|
|
|
|
Function arguments evaluate from the left to the right, so in
|
|
|
|
f(a,b,c);
|
|
|
|
A is guaranteed to evaluate before B and C and B is guaranteed
|
|
to evaluate before C.
|
|
|
|
Example: pow(x, y) DO VAR a;
|
|
a := 1;
|
|
WHILE (y) DO
|
|
a := a*x;
|
|
y := y-1;
|
|
END
|
|
RETURN a;
|
|
END
|
|
|
|
DO VAR x;
|
|
x := pow(2,10);
|
|
END
|
|
|
|
|
|
LITERALS
|
|
*--------*
|
|
|
|
INTEGERS
|
|
|
|
An integer is a number representing its own value. Note that
|
|
negative numbers have a leading '%' sign rather than a '-' sign.
|
|
While the latter also works, it is, strictly speaking, the
|
|
application of the '-' operator to a positive number, so it may
|
|
not appear in cvalue contexts.
|
|
|
|
Integers may have a '0x' prefix (after the '%' prefix, if
|
|
that also exists). In this case, the subsequent digits will
|
|
be interpreted as a hexa-decimal number.
|
|
|
|
Examples: 0
|
|
12345
|
|
%1
|
|
0xfff
|
|
%0xA5
|
|
|
|
|
|
CHARACTERS
|
|
|
|
Characters are integers internally. They are represented by
|
|
single characters enclosed in single quotes. In addition, the
|
|
same escape sequences as in strings may be used.
|
|
|
|
Examples: 'x'
|
|
'\\'
|
|
'''
|
|
'\e'
|
|
|
|
|
|
STRINGS
|
|
|
|
A string is a byte vector filled with characters. Strings are
|
|
delimited by '"' characters and NUL-terminated internally. All
|
|
characters between the delimiting double quotes represent
|
|
themselves. In addition, the following escape sequences may be
|
|
used to include some special characters:
|
|
|
|
\a BEL Bell
|
|
\b BS Backspace
|
|
\e ESC Escape
|
|
\f FF Form Feed
|
|
\n LF Line Feed (newline)
|
|
\q " Quote
|
|
\r CR Carriage Return
|
|
\s Space
|
|
\t HT Horizontal Tabulator
|
|
\v VT Vertical Tabulator
|
|
\\ \ Backslash
|
|
|
|
Examples: ""
|
|
"hello, world!\n"
|
|
"\qhi!\q, she said"
|
|
|
|
|
|
PACKED TABLES
|
|
|
|
A packed table is a byte vector literal. It is a set of cvalues
|
|
delimited by square brackets and separated by commas. Note that
|
|
string notation is a short and portable, but also limited,
|
|
notation for byte vectors. For instance, the byte vectors
|
|
|
|
"HELLO"
|
|
PACKED [ 'H', 'E', 'L', 'L', 'O', 0 ]
|
|
|
|
are identical. Byte vectors can contain any values in the range
|
|
from 0 to 255.
|
|
|
|
Examples: PACKED [ 1 ]
|
|
PACKED [ 1, 2, 3 ]
|
|
PACKED [ 14, 'H', 'i', 15 ]
|
|
|
|
|
|
TABLES
|
|
|
|
A table is a vector literal, i.e. a sequence of values. It is
|
|
delimited by square brackets and elements are separated by
|
|
commas. Table elements can be cvalues, strings, and tables.
|
|
|
|
Examples: [1, 2, 3]
|
|
["5 times -7", %35]
|
|
[[1,0,0],[0,1,0],[0,0,1]]
|
|
|
|
|
|
DYNAMIC TABLES
|
|
|
|
The dynamic table is a special case of the table in which one
|
|
or multiple elements are computed at program run time. Dynamic
|
|
table elements are enclosed in parentheses. E.g. in the table
|
|
|
|
["x times 7", (x*7)]
|
|
|
|
the value of the second element would be computed and filled
|
|
in when the table is being evaluated. Note that dynamic table
|
|
elements are being replaced in situ, and remain the same only
|
|
until they are replaced again.
|
|
|
|
Multiple dynamic elements may be enclosed by a single pair of
|
|
parentheses. For instance, the following tables are the same:
|
|
|
|
[(x), (y), (z)]
|
|
[(x, y, z)]
|
|
|
|
|
|
CVALUES
|
|
*-------*
|
|
|
|
A cvalue (constant value) is an expression whose value is known
|
|
at compile time. In full T3X, this is a large subset of full
|
|
expressions, but in T3X9, it it limited to the following:
|
|
|
|
* integers
|
|
* characters
|
|
* constants
|
|
|
|
as well as (given that X and Y are one of the above):
|
|
|
|
* X+Y
|
|
* X*Y
|
|
|
|
|
|
NAMING CONVENTIONS
|
|
*------------------*
|
|
|
|
Symbolic names for variables, constants, structures, and
|
|
functions are constructed from the following alphabet:
|
|
|
|
* the characters a-z
|
|
* the digits 0-9
|
|
* the special characters '_' and '.'
|
|
|
|
The first character of a name must be non-numeric, the remaining
|
|
characters may be any of the above.
|
|
|
|
Upper and lower case is not distinguished, the symbolic names
|
|
|
|
FOO, Foo, foo
|
|
|
|
are all considered to be equal.
|
|
|
|
By convention,
|
|
|
|
* CONST names are all upper-case
|
|
* STRUCT names are all upper-case
|
|
* global VAR names are capitalized
|
|
* local VAR names are all lower-case
|
|
* function names are all lower-case
|
|
|
|
Keywords, like VAR, IF, DO, etc, are sometimes printed in upper
|
|
case in documentation, but are usually in lower case in actual
|
|
programs.
|
|
|
|
|
|
SHADOWING
|
|
*---------*
|
|
|
|
There is a single name space without any shadowing in T3X:
|
|
|
|
* all global names must be different
|
|
* no local name may have the same name as a global name
|
|
* all local names in the same scope must be different
|
|
|
|
The latter means that local names may be re-used in subsequent
|
|
scopes, e.g.:
|
|
|
|
f(x) RETURN x;
|
|
g(x) RETURN x;
|
|
|
|
would be a valid program. However,
|
|
|
|
f(x) DO VAR x; END !!! WRONG !!!
|
|
|
|
would not be a valid program, because VAR x; redefines the
|
|
argument of F.
|
|
|
|
|
|
BUILT-IN FUNCTIONS
|
|
*------------------*
|
|
|
|
The following built-in functions exist in T3X9. They resemble
|
|
the functions of the T3X core module of the full language, i.e.
|
|
a T3X9 program can be compiled by a T3X compiler by adding the
|
|
following code to the top of the program:
|
|
|
|
MODULE name(t3x);
|
|
OBJECT t[t3x];
|
|
|
|
These functions are built into the T3X9 compiler, though, and
|
|
do not have to be declared in any way. The '.' in the function
|
|
names resembles the message operator of the full language.
|
|
|
|
T3X9r3 accepts (and ignores) the above declarations at the
|
|
beginning of a program. A program containing these declarations
|
|
can be compiled by any T3X compiler.
|
|
|
|
|
|
MEMORY FUNCTIONS
|
|
|
|
-----[ T.MEMCOMP(b1, b2, len) ]---------------------------------
|
|
|
|
Compare the first LEN bytes of the byte vectors B1 and B2.
|
|
Return the difference of the first pair of mismatching bytes.
|
|
A return code of 0 means that the compared regions are equal.
|
|
|
|
Example: t.memcomp("aaa", "aba", 3) ! gives 'b'-'a' = %1
|
|
|
|
|
|
-----[ T.MEMCOPY(bs, bd, len) ]---------------------------------
|
|
|
|
Copy LEN bytes from the byte vector BS (source) to the byte
|
|
vector BD (destination). Return 0.
|
|
|
|
Unlike in the full T3X language, BS and BD may not overlap.
|
|
|
|
Example: DO VAR b::100; t.memcopy(b, "hello", 5); END
|
|
|
|
|
|
-----[ T.MEMFILL(bv, b, len) ]----------------------------------
|
|
|
|
Fill the first LEN bytes of the byte vector BV with the byte
|
|
value B. Return 0.
|
|
|
|
Example: DO VAR b::100; t.memfill(b, 0, 100); END
|
|
|
|
|
|
-----[ T.MEMSCAN(bv, b, len) ]----------------------------------
|
|
|
|
Locate the first occurrence of the byte value B in the first LEN
|
|
bytes of the byte vector BV and return its offset in the vector.
|
|
When B does not exist in the given region, return %1.
|
|
|
|
Example: t.memscan("aaab", 'b', 4) ! returns 3
|
|
|
|
|
|
INPUT/OUTPUT FUNCTIONS
|
|
|
|
-----[ T.CREATE(path) ]-----------------------------------------
|
|
|
|
Create a file with the given PATH, open it, and return its file
|
|
descriptor. In case of an error, return -1.
|
|
|
|
Example: t.create("new-file");
|
|
|
|
|
|
-----[ T.OPEN(path, mode) ]-------------------------------------
|
|
|
|
Open file PATH in the given MODE, where 0=read-only, 1=write-
|
|
only, and 2=read/write. Return -1 in case of an error.
|
|
|
|
Example: t.open("existing-file", 0);
|
|
|
|
|
|
-----[ T.CLOSE(fd) ]--------------------------------------------
|
|
|
|
Close the file descriptor FD. Return 0 for success and -1 in
|
|
case of an error.
|
|
|
|
Example: DO var fd;
|
|
fd := t.create("file");
|
|
if (fd >= 0) t.close();
|
|
END
|
|
|
|
|
|
-----[ T.READ(fd, buf, len) ]-----------------------------------
|
|
|
|
Read up to LEN characters from the file descriptor FD into the
|
|
buffer BUF. Return the number of characters actually read.
|
|
Return %1 in case of an error.
|
|
|
|
Example: DO b::100; t.read(0, b, 99); END
|
|
|
|
|
|
-----[ T.WRITE(fd, buf, len) ]----------------------------------
|
|
|
|
Write LEN characters from the buffer BUF to the file descriptor
|
|
FD. Return the number of characters actually written. Return %1
|
|
in case of an error.
|
|
|
|
Example: t.write(1, "hello, world!\n", 14);
|
|
|
|
|
|
-----[ T.RENAME(path, new) ]------------------------------------
|
|
|
|
Rename the file given in PATH to NEW. Return 0 for success and
|
|
-1 in case of an error.
|
|
|
|
Example: t.rename("old-name", "new-name");
|
|
|
|
|
|
-----[ T.REMOVE(path) ]-----------------------------------------
|
|
|
|
Remove the file given in PATH. Return 0 for success and -1 in
|
|
case of an error.
|
|
|
|
Example: t.remove("temp-file");
|
|
|
|
|
|
VARIADIC FUNCTIONS
|
|
*------------------*
|
|
|
|
T3X implements variadic functions (i.e. functions of a variable
|
|
number of arguments) using dynamic tables. For instance, the
|
|
following function returns the sum of a vector of arguments:
|
|
|
|
sum(k, v) DO var i, n;
|
|
n := 0;
|
|
FOR (i=0, k)
|
|
n := n+v[i];
|
|
RETURN n;
|
|
END
|
|
|
|
Its is an ordinary function returning the sum of a vector. It
|
|
can be considered to be a variadic function, because a dynamic
|
|
table can be passed to it in the V argument:
|
|
|
|
sum(5, [(a,b,c,d,e)])
|
|
|
|
|
|
EXAMPLE PROGRAM
|
|
*---------------*
|
|
|
|
var ntoa_buf::100;
|
|
|
|
ntoa(x) do var i, k;
|
|
if (x = 0) return "0";
|
|
i := 0;
|
|
k := x<0-> -x: x;
|
|
while (k > 0) do
|
|
i := i+1;
|
|
k := k/10;
|
|
end
|
|
i := i+1;
|
|
if (x < 0) i := i+1;
|
|
ntoa_buf::i := 0;
|
|
k := x<0-> -x: x;
|
|
while (k > 0) do
|
|
i := i-1;
|
|
ntoa_buf::i := '0' + k mod 10;
|
|
k := k/10;
|
|
end
|
|
if (x < 0) do
|
|
i := i-1;
|
|
ntoa_buf::i := '-';
|
|
end
|
|
return @ntoa_buf::i;
|
|
end
|
|
|
|
str.length(s) return t.memscan(s, 0, 32767);
|
|
|
|
writes(s) t.write(1, s, str.length(s));
|
|
|
|
fib(n) do var r1, r2, i, t;
|
|
r1 := 0;
|
|
r2 := 1;
|
|
for (i=1, n) do
|
|
t := r2;
|
|
r2 := r2 + r1;
|
|
r1 := t;
|
|
end
|
|
return r2;
|
|
end
|
|
|
|
do var i;
|
|
for (i=1, 11) do
|
|
writes(ntoa(fib(i)));
|
|
writes("\n");
|
|
end
|
|
end
|