[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
To define functions by an user himself, ‘def’ statement must be used. Syntactical errors are detected in the parsing phase of Asir, and notified with an indication of where Asir found the error. If a function with the same name is already defined (regardless to its arity,) the new definition will override the old one, and the user will be told by a message,
afo() redefined.
on the screen when a flag verbose
is set to a non-zero value by
ctrl()
.
Recursive definition, and of course, recursive use of functions are
available.
A call for an yet undefined function in a function definition is not
detected as an error. An error will be detected at execution of the
call of that yet undefined function.
def f(X) { if ( !X ) return 1; else return X * f(X-1); } def c(N) { A = newvect(N+1); A[0] = B = newvect(1); B[0] = 1; for ( K = 1; K <= N; K++ ) { A[K] = B = newvect(K+1); B[0] = B[K] = 1; for ( P = A[K-1], J = 1; J < K; J++ ) B[J] = P[J-1]+P[J]; } return A; } def add(A,B) "add two numbers." { return A+B; }
In the second example, c(N)
returns a vector, say A
, of length
N+1
. A[I]
is a vector of length I+1
, and
each element is again a vector which contains
ICJ
as its elements.
help
.
In the following, the manner of writing Asir programs is exhibited for those who have no experience in writing C programs.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A program variable is a string that begins with a capital alphabetical letter followed by any numbers of alphabetical letters, digits and ‘_’.
A program variable is thought of a box (a carrier) which can contain Asir objects of various types. The content is called the ‘value’ of that variable. When an expression in a program is to be evaluated, the variable appearing in the expression is first replaced by its value and then the expression is evaluated to some value and stored in the memory. Thus, no program variable appears in objects in the internal form. All the program variables are initialized to the value 0.
[0] X^2+X+1; 1 [1] X=2; 2 [2] X^2+X+1; 7
An indeterminate is a string that begins with a small alphabetical letter followed by any numbers of alphabetical letters, digits and ‘_’.
An indeterminate is a transcendental element, so-called variable, which is used to construct polynomial rings. An indeterminate cannot have any value. No assignment is allowed to it.
[3] X=x; x [4] X^2+X+1; x^2+x+1 [5] A='Dx'*(x-1)+x*y-y; (y+Dx)*x-y-Dx [6] function foo(x,y); [7] B=foo(x,y)*x^2-1; foo(x,y)*x^2-1
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
def sum(N) { for ( I = 1, S = 0; I <= N; I++ ) S += I; return S; }
This is an example definition of a function that sums up integers
from 1 to N
. The N
in sum(N)
is called the
(formal) parameter of sum(N)
.
The example shows a function of the single argument.
In general, any number of parameters can be specified by separating
by commas (‘,’).
A (formal) parameter accepts a value given as an argument (or an actual
parameter) at a function call of the function.
Since the value of the argument is given to the formal parameter,
any modification to the parameter does not usually affect the argument
(or actual parameter). However, there are a few exceptions: vector
arguments and matrix arguments.
Let A
be a program variable and assigned to a vector value
[ a, b ]
.
If A is given as an actual parameter to a formal parameter, say V
,
of a function, then an assignment in the function to the vector element
designator V[1]
, say V[1]=c;
, causes modification of the
actual parameter A
resulting A
to have an altered value
[ a c ]
. Thus, if a vector is given to a formal parameter of
a function, then its element (and subsequently the vector itself) in
the calling side is modified through modification of the formal parameter
by a vector element designator in the called function.
The same applies to a matrix argument.
Note that, even in such case where a vector (or a matrix) is given to
a formal parameter, the assignment to the whole parameter itself has
only a local effect within the function.
def clear_vector(M) { /* M is expected to be a vector */ L = size(M)[0]; for ( I = 0; I < L; I++ ) M[I] = 0; }
This function will clear off the vector given as its argument to the
formal parameter M
and return a 0 vector.
Passing a vector as an argument to a function enables returning multiple results by packing each result in a vector element. Another alternative to return multiple results is to use a list. Which to use depends on cases.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The text enclosed by ‘/*’ and ‘*/’ (containing ‘/*’ and ‘*/’) is treated as a comment and has no effect to the program execution as in C programs.
/* * This is a comment. */ def afo(X) {
A comment can span to several lines, but it cannot be nested. Only the first ‘/*’ is effective no matter how many ‘/*’’s in the subsequent text exist, and the comment terminates at the first ‘*/’.
In order to comment out a program part that may contain comments in it,
use the pair, #if 0
and #endif
. (See section preprocessor.)
#if 0 def bfo(X) { /* empty */ } #endif
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An user function of Asir is defined in the following form.
def name(parameter, parameter,...,parameter) { statement statement ... statement }
As you can see, the statement is a fundamental element of the function. Therefore, in order to write a program, you have to learn what the statement is. The simplest statement is the simple statement. One example is an expression with a terminator (‘;’ or ‘$’.)
S = sum(N);
A ‘return
statement’ and ‘break
statement’ are also
primitives to construct ‘statements.’
As you can see the syntactic definition of ‘if
statement’ and
‘for
statement’, each of their bodies consists of a single
‘statement.’ Usually, you need several statements in such a body.
To solve this contradictory requirement, you may use the ‘compound
statement.’ A ‘compound statement’ is a sequence of ‘statement’s
enclosed by a left brace ‘{’ and a right brace ‘}’.
Thus, you can use multiple statement as if it were a single statement.
if ( I == 0 ) { J = 1; K = 2; L = 3; }
No terminator symbol is necessary after ‘}’,
because ‘{’ statement sequence ‘}’ already forms a statement,
and it satisfies the syntactical requirement of the
‘if
statement.’
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
return
statementThere are two forms of return
statement.
return expression; return;
Both forms are used for exiting from a function. The former returns the value of the expression as a function value. The function value of the latter is not defined.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
if
statementThere are two forms of if
statement.
if ( expression ) if ( expression ) statement and statement else statement
The interpretation of these forms are obvious. However, be careful
when another if
statement comes at the place for ‘statement’.
Let us examine the following example.
if ( expression1 ) if ( expression2 ) statement1 else statement2
One might guess statement2
after else
corresponds with the
first if ( expression1 )
by its appearance of indentation.
But, as a matter of fact, the Asir
parser decides that it
correspond with the second if ( expression2 )
.
Ambiguity due to such two kinds of forms of if
statement is
thus solved by introducing a rule that a statement preceded by an
else
matches to the nearest preceding if
.
Therefore, rearrangement of the above example for improving readability according to the actual interpretation gives the following.
if ( expression1 ) { if ( expression2 ) statement1 else statement2 }
On the other hand, in order to reflect the indentation, it must be written as the following.
if ( expression1 ) { if ( expression2 ) statement1 } else statement2
When if
is used in the top level, the if
expression should be
terminated with $
or ;
.
If there is no terminator, the next expression will be skipped to be evaluated.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
loop
, break
, return
, continue
There are three kinds of statements for loops (repetitions):
the while
statement, the for
statement, and the
do
statement.
while
statement
while ( expression ) statement
This statement specifies that statement
is repeatedly evaluated
as far as the expression
evaluates to a non-zero value.
If the expression 1 is given to the expression
, it forms an
infinite loop.
for
statement
for ( expr list-1; expr; expr list-2 ) statement
This is equivalent to the program
expr list-1 (transformed into a sequence of simple statement) while ( expr ) { statement expr list-2 (transformed into a sequence of simple statement) }
do
statement
do { statement } while ( expression )
This statement differs from while
statement by the location of
the termination condition: This statement first execute the
statement
and then check the condition, whereas while
statement does it in the reverse order.
As means for exiting from loops, there are break
statement and
return
statement. The continue
statement allows to move
the control to a certain point of the loop.
break
break
statement is used to exit the inner most loop.
return
return
statement is usually used to exit from a function call
and it is also effective in a loop.
continue
continue
statement is used to move the control to the end
point of the loop body.
For example, the last expression list will be evaluated in a for
statement, and the termination condition will be evaluated in a
while
statement.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A structure data type is a fixed length array and each component of the array
is accessed by its name. Each type of structure is distinguished by its name.
A structure data type is declared by struct
statement.
A structure object is generated by a builtin function newstruct
.
Each member of a structure is accessed by an operator ->
.
If a member of a structure is again a structure, then the specification
by ->
can be nested.
[1] struct rat {num,denom}; 0 [2] A = newstruct(rat); {0,0} [3] A->num = 1; 1 [4] A->den = 2; 2 [5] A; {1,2} [6] struct_type(A); 1
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Major elements to construct expressions are the following:
2/3
results in a rational number 2/3
.
For integer division and polynomial division, both including remainder
operation, built-in functions are provided.
x+1 A^2*B*afo X/3
V[0] M[1][2]
A = 2 A *= 3 (the same as A = A*3; The others are alike.)
A++ the expression value is the previous value of A, and A = A+1 A-- the expression value is the previous value of A, and A = A-1 ++A A = A+1, and the value is the one after increment of A --A A = A-1, and the value is the one after decrement of A
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
he Asir user language imitates C language. A typical features of
C language include macro expansion and file inclusion by the
preprocessor cpp
. Also, Asir read in user program files
through cpp
. This enables Asir user to use
#include
, #define
, #if
etc. in his programs.
#include
#include
so that no arguments are passed to cpp
.
#define
#if
/*
and */
,
because such comments cannot be nested.
the following are the macro definitions in ‘defs.h’.
#define ZERO 0 #define NUM 1 #define POLY 2 #define RAT 3 #define LIST 4 #define VECT 5 #define MAT 6 #define STR 7 #define N_Q 0 #define N_R 1 #define N_A 2 #define N_B 3 #define N_C 4 #define V_IND 0 #define V_UC 1 #define V_PF 2 #define V_SR 3 #define isnum(a) (type(a)==NUM) #define ispoly(a) (type(a)==POLY) #define israt(a) (type(a)==RAT) #define islist(a) (type(a)==LIST) #define isvect(a) (type(a)==VECT) #define ismat(a) (type(a)==MAT) #define isstr(a) (type(a)==STR) #define FIRST(L) (car(L)) #define SECOND(L) (car(cdr(L))) #define THIRD(L) (car(cdr(cdr(L)))) #define FOURTH(L) (car(cdr(cdr(cdr(L))))) #define DEG(a) deg(a,var(a)) #define LCOEF(a) coef(a,deg(a,var(a))) #define LTERM(a) coef(a,deg(a,var(a)))*var(a)^deg(a,var(a)) #define TT(a) car(car(a)) #define TS(a) car(cdr(car(a))) #define MAX(a,b) ((a)>(b)?(a):(b))
Since we are utilizing the C preprocessor, it cannot properly preprocess expressions
with $
.
For example, even if LIST
is defined, LIST
in the expression
LIST$
is not replaced. Add a blank before $
, i.e.,
write as LIST $
to make the proprocessor replace it properly.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If a user defined function is declared with N arguments, then the function is callable with N arguments only.
[0] def factor(A) { return fctr(A); } [1] factor(x^5-1,3); evalf : argument mismatch in factor() return to toplevel
A function with indefinite number of arguments can be realized by using a list or an array as its argument. Another method is available as follows:
% cat factor def factor(F) { Mod = getopt(mod); ModType = type(Mod); if ( ModType == 1 ) /* 'mod' is not specified. */ return fctr(F); else if ( ModType == 0 ) /* 'mod' is a number */ return modfctr(F,Mod); }
[0] load("factor")$ [1] factor(x^5-1); [[1,1],[x-1,1],[x^4+x^3+x^2+x+1,1]] [2] factor(x^5-1|mod=11); [[1,1],[x+6,1],[x+2,1],[x+10,1],[x+7,1],[x+8,1]]
In the second call of factor()
, |mod=11
is placed
after the argument x^5-1
, which appears in the declaration of
factor()
. This means that the value 11
is assigned to
the keyword mod
when the function is executed. The value
can be retrieved by getopt(mod)
. We call such machinery
option. If the option for mod is not specified,
getopt(mod)
returns an object whose type is -1. By this
feature, one can describe the behaviour of the function when
the option is not specified by if statements.
After ‘|’ one can append any number of options separated by ‘,’.
[100] xxx(1,2,x^2-1,[1,2,3]|proc=1,index=5);
Optional arguments may be given as a list
with the key word option_list
as
option_list=[["key1",value1],["key2",value2],...]
.
It is equivalent to pass the optional arguments as
key1=value1,key2=value2,...
.
[101] dp_gr_main([x^2+y^2-1,x*y-1]|option_list=[["v",[x,y]],["order",[[x,5,y,1]]]]);
Since getopt()
returns an option list,
the optional argument option_list=...
is useful when
we call functions with optional arguments from
a function with optional arguments to pass
the all optional parameters.
% cat foo.rr def foo(F) { OPTS=getopt(); return factor(F|option_list=OPTS); }
[3] load("foo.rr")$ [4] foo(x^5-1|mod=11); [[1,1],[x+6,1],[x+2,1],[x+10,1],[x+7,1],[x+8,1]]
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Function names and variables in a library may be encapsulated by module. Let us see an example of using module
module stack; static Sp $ Sp = 0$ static Ssize$ Ssize = 100$ static Stack $ Stack = newvect(Ssize)$ localf push $ localf pop $ def push(A) { if (Sp >= Ssize) {print("Warning: Stack overflow\nDiscard the top"); pop();} Stack[Sp] = A; Sp++; } def pop() { local A; if (Sp <= 0) {print("Stack underflow"); return 0;} Sp--; A = Stack[Sp]; return A; } endmodule; def demo() { stack.push(1); stack.push(2); print(stack.pop()); print(stack.pop()); }
Module is encapsulated by the sentences
module
module name
and
endmodule
.
A variable of a module is declared with the key word static
.
The static variables cannot be referred nor changed out of the module,
but it can be referred and changed in any functions in the module.
The static
variables must be declared before the definitions of functions,
because the one-path parser of asir automatically assume variables as local variables
if there is no declaration for them.
A global variable which can be referred and changed in or out of the module
is declared with the key word extern
.
Any function defined in a module must be declared forward
with the keyword localf
.
In the example above, push
and pop
are declared.
This declaration is necessary.
A function functionName
defined in a module moduleName
can be called by the expression
moduleName.functioName(arg1, arg2, ...)
out of the module.
Inside the module, moduleName.
is not necessary.
In the example below, the functions push
and pop
defined
in the module stack
are called out of the module.
stack.push(2); print( stack.pop() ); 2
Any function name defined in a module is local. In other words, the same function name may be used out of the module to define a different function.
The module structure of asir is introduced to develop large libraries.
In order to load libraries on demand, the command module_definedp
will be useful.
The below is an example of demand loading.
if (!module_definedp("stack")) load("stack.rr") $
It is not necessary to declare local variables in asir.
As you see in the example of the stack module,
we may declare local variables by the key word local
.
Once this key word is used, asir requires to declare all the
variables.
In order to avoid some troubles to develop a large libraries,
it is recommended to use local
declarations.
When we need to call a function in a module before the module is defined, we must make a prototype declaration as the example below.
/* Prototype declaration of the module stack */ module stack; localf push $ localf pop $ endmodule; def demo() { print("----------------"); stack.push(1); print(stack.pop()); print("---------------"); } module stack; /* The body of the module stack */ endmodule;
In order to call functions defined in the top level from the inside
of a module, we use ::
as in the example below.
def afo() { S = "afo, afo"; return S; } module abc; localf foo,afo $ def foo() { G = ::afo(); return G; } def afo() { return "afo, afo in abc"; } endmodule; end$ [1200] abc.foo(); afo, afo [1201] abc.afo(); afo, afo in abc
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] |
This document was generated on December 14, 2024 using texi2html 5.0.