Chapter 17: Using Aldor interactively
17.1 How to use the interpreter
17.2 Directives for the interactive mode
17.3 Using the interactive mode
This chapter describes how to use a built-in interpreter to run
Aldor programs interactively. We shall assume that the reader is
familiar with at least the basic concepts of the Aldor programming
language.
17.1 : Using Aldor interactively
17.1.1 Running programs with the interpreter (-g interp)
17.1.2 Interactive mode (-g loop)
The interpreter is built into the Aldor compiler. It is used iin two differnet contexts:
17.1.1 : Running programs with interpreter (-g interp)
Suppose you write an Aldor program foo.as. One way to get it running is with the command:
% Aldorcmd -g run foo.as
When you call the compiler with this option, it compiles the program into a device-independent intermediate format called Foam (in this case, in the file foo.ao), which is then translated into C code (foo.c) and compiled with the C compiler available on your platform. Finally, the executable code generated by the C compiler is executed. If you call the compiler with the -g interp option, e.g,
% Aldorcmd -g interp foo.as
the intermediate file foo.ao is executed without any call to the C compiler. Since the instructions are interpreted, and not pure machine code instructions as when using -g run, execution will generally be slower than in the first case. Despite the low execution speed, there are reasons to use the interpreter instead of the compiler:
Using the interpreter is suggested especially for those who are learning Aldor, as it provides a quick way of testing small programs. Note that all the compiler options can be used with -g interp. All optimizations except -Qcc are still effective, because all optimizations in Aldor are performed on the intermediate code. So, for example, if the compiler is called using the -Q3 option, as in:
% Aldorcmd -Q3 -g interp foo.as
the program will generally run faster than without the -Q3 option.
Note that the semantics of the language are fully preserved by the
interpreter. The interpreter provides all of the Aldor language
features.
17.1.2 : Interactive mode (-g loop)
The interactive mode provides an interactive environment in which it is possible to define functions and domains, to use operations provided by the library, to evaluate expressions and to use other features. Users who are familiar with programming in languages that are usually interpreted, such as Lisp, already know the feeling of an interactive environment and how it can be used to gain confidence in the language.
Note that the interactive environment provided with this version of the compiler is still not completely reliable, partially due to the difficulties met in making interactive a language originally designed to be compiled. Despite these problems, it is a very useful tool for learning basic Aldor concepts, as well as developing and debugging complex Aldor programs. The command line to start the compiler in interactive mode is:
% Aldorcmd -g loop
A prompt will appear:
%1 >> _
At this point, you start typing the first line of your program, for example:
%1 >> #include "aldor"
After a few seconds the prompt appears again (the delay is due to the interpreter loading the base library):
%1 >> #include "aldor" %2 >> _
The number that appears immediately after %
which is incremented with each input line from the user.
As will be seen, this is useful when the history
mode is
on
. Now type:
%2 >> import from SingleInteger %3 >> 1 + 1
At this point the expression 1 + 1
will be evaluated and the
answer is:
2 @ SingleInteger
in which 2
is the result of the expression and
@ SingleInteger
means that its type is SingleInteger
.
To quit the interactive mode type:
%4 >> #quit
When the intepreter starts, it looks in the current directory (the
directory from which the command line is being entered) for an
initialization file. An initialization file is any Aldor program
named aldorinit.as
. If this file is present in the current
directory, it will be loaded and executed before the prompt appears.
An example initialization file could be:
#include "aldor" -- Commonly used macros SI ==> SingleInteger I ==> Integer
Note: the interpreter will display a message:
Reading aldorinit.as...
if an initialization file is read.
The majority of command line options are still active when -g loop is used. For example, the optimization option:
% Aldorcmd -Q3 -g loop
will invoke the optimizer before interpreting the generated Foam intermediate code, thereby affecting the execution speed.
We will now try a simple interactive session. Note that all the lines which do not start with the prompt have not been typed, but are part of the output.
%1 >> -- Example of interactive session -- %2 >> ------------------------------------ %3 >> #include "aldor" %4 >> import from Integer %5 >> 100 100 @ Integer %6 >> 100 + 100 -- using as a simple calculator 200 @ Integer %7 >> f(x:Integer):Integer == if x=0 then 1 else x*f(x-1) Defined f: (x: Integer) -> Integer %8 >> f 4 24 @ Integer %9 >> import from List Integer %10 >> reverse -- print the signature for `reverse' () @ List(Integer) -> List(Integer) %11 >> reverse [1,2,3,4,5] list(5, 4, 3, 2, 1) @ List(Integer)
17.2 : Directives for the interactive mode
This section provides a full description of some language directives available only in interactive mode.
The options available specifically for interactive mode are requested using #int. A brief help message displaying all available options may be obtained with:
#int help
The options are as follows:
#int verbose [on | off]
Default is: on
.
When verbose
is on
, the interpreter prints, if possible,
the value and the type of the current expression.
Example:
%4 >> 4 4 @ SingleInteger %5 >> 5 + 5 10 @ SingleInteger %6 >> foo(x : String) : Boolean == empty? x Defined foo: String -> Boolean
If the value of the expression is not printable (that is, its domain
does not export <<:(
value at all (for instance, in import from statements), nothing
is displayed.
#int history [on | off]
Default is: off
.
When history
is on
, the interpreter wraps, if possible,
an assignment around the current expression.
If, for example, %5 is the current interpretation step, the
prompt will change from %5 >> to %5 :=
which means that, if the current expression has a value, this is assigned to a new variable named %5. The variable %5 is implicitly declared and its type is inferred from the type of the right hand side.
Example:
%4 >> #int history on history is on %5 := SI ==> SingleInteger -- no value is assigned to %5 %6 := import from SI -- no value is assigned to %6 %7 := 5 + 5 -- 10 is assigned to %7 10 @ SingleInteger %8 := 10 + %7 -- you can use %7 20 @ SingleInteger %9 := %7 := %7 - 5 -- 5 is assigned to %7 and %9
Notes:
SPMquot
:=" operator in Aldor is observed.
#int confirm [on | off]
Default is: on
.
When confirm
is on
, the interpreter asks for confirmation
before executing some operations that are illegal in the compiled
Aldor language. Typical cases are the redefinition of constants and
functions: according to the language definition, these cannot be
redefined -- but it may be useful to relax this rule in interactive
mode.
Suppose, for example, that you write a definition for a function foo, later adding other functions using foo; at some point you want to provide a better implementation for foo: if your program is going to be compiled, then you can simply edit the file where foo is defined and change it but, unfortunately, this cannot be done if you wrote foo interactively. This is why, in interactive mode, you can enter a new definition for foo: a message will appear because you are doing something that is not normally allowed in Aldor and, at this point, you can confirm that you want to replace the old definition with the new one. If you do not want the message asking for a confirmation, you can enter:
#int confirm off
in which case a positive answer is assumed for each situation in which a confirmation would be needed.
Example:
%3 >> Int ==> Integer %4 >> import from Int %5 >> foo(x : Int) : Int == x Defined foo: Integer -> Integer %6 >> foo(x : Boolean) : Boolean == not x -- (see Note 1) Defined foo: Boolean -> Boolean %7 >> foo(x : Int) : Int == x * x Redefine ? (y/n): y -- (see Note 2) Defined foo: Integer -> Integer %8 >> foo 2 4 @ Integer
Notes:
n
causes the previous definition to be kept.
It is useful to set this option off
when, for some reason, a file
is included a second time. If this file contains
some function definitions, you will not then be prompted to confirm each
of them.
#int msg-limit number
Default is: 0 (no limit).
Set the maximum length, in characters, of Aldor messages. This is useful because some of them, such as error messages, could consist of several lines. A value of 0 means that there is no limit. The characters ... at the end of the message will warn you that it has been truncated.
Note that, if you limit the message length, then you will get incomplete messages when you use the interactive mode as a browser (see section section 17.3.5). You may also see long type-names cut off with ... in error messages. To see the types in full, use
#int options -M no-abbrev
#int gc
This command explicitly calls the garbage collector.
After the execution, a message showing the amount of memory not released
is shown, with additional details if the verbose option is on
.
This operation may take several seconds if the hardware is slow.
Note that the garbage collection may occur as needed at other times,
even though you have not specifically requested it.
#int options command-line options
Set one or more of the options normally available when the compiler is called -- for example, optimizations.
Example:
#int options -Q3
sets the optimizations on
. Note that, since the interactive mode
will be slower for simple expressions if all the optimizations are
active but the functions defined are considerably faster, you might want
to turn optimizations such as -Q3 on
before defining
time-intensive functions and to turn them off
or reset them to a
lower level (such as -Q1 or -Q0) after the definition.
#int cd
new-directory
Change the current directory. This is useful if, for example, you want to include files from another directory without typing the path in the #include directive.
Example: #int cd /tmp
#int shell "shell-command"
Execute the quoted string as a shell command. This is useful, for example, to start an editor session without exiting the interpreter.
Example: #int shell "vi"
will start the vi
editor under Unix.
You can also start an inferior shell passing it as a command. Under Unix, for example, you can say:
#int shell "csh"
to start a csh
inferior shell. To return to the interpreter,
type exit
.
17.3 : Using the interactive mode
17.3.1 Multi-line input
17.3.2 Initialization file
17.3.3 Macros
17.3.4 Running inside an editor
17.3.5 Using the interactive mode as a browser
17.3.6 Loading an Aldor file
17.3.7 The # symbol
17.3.8 Labels
17.3.1 : Multi-line input
In order to provide as comfortable an interactive mode as possible, the syntax of the Aldor language, as used interactively, differs slightly from that of the compiled language.
Interactive mode is, by default, indentation sensitive.
As a consequence, you do not need a semicolon (;) at the end of
each statement -- the newline is identified as a separator.
This is different from non-interactive use, where you need
to use SPMquot
#pile" to get indentation sensitivity.
Multi-line input can be performed using braces or with a == as the last symbol on a line.
If you begin a definition with the line
... %4 >> foo(x: Integer): Integer == {
then the definition will be considered complete when number of closing braces (}) matches the number of opening braces ({) that you entered. In this case, you must remember that braces always turn off indentation sensitivity so you must use a semicolon (;) to separate your statements.
If you enter
... %4 >> foo(x: Integer): Integer ==
Aldor interactive mode is smart enough to understand that you are going to write the body of the function, so the line is not analysed as a complete statement. In this case you need to use spaces or tabs to write your definition with appropriate indentation. The definition will be complete when you start again writing at indentation level 0. A quick way to terminate the definition of a function when in indentation sensitive mode is to type - (an empty comment) at the beginning of the line.
We can show some examples. In the first one, a function arrToList is defined using the indentation sensitive mode. Note that == is last symbol at the end of line 8.
... %5 >> import from Integer, Array Integer, List Integer %6 >> -- no `;' needed at the end of the line. %7 >> -- Defining a function using the indentation: %8 >> arrToList(ar: Array Integer): List Integer == -- the definition is not processed yet and the prompt does -- not appear, indicating that you can enter the body of -- the function. local ls : List Integer := empty() -- no `;' for x in ar repeat ls := cons(x,ls) ls -- return value -- This comment at level 0 cause the definition to be processed. Defined: arrToList@ (ar: Array(Integer)) -> List(Integer) %9 >> -- Here the prompt appears again. %10 >> a : Array Integer := [1,2,3] array(1, 2, 3) @ Array(Integer) %11 >> arrToList a list(3, 2, 1) @ List(Integer)
In the second example the same function is defined using braces to get multi-line input:
... %8 >> arrToList(ar: Array Integer): List Integer == { -- Indentation is not necessary, but we suggest using it -- anyway to get a more readable code. Until the definition -- is complete, you need `;' at the end of each line. -- (except when you write comments, of course). local ls : List Integer := empty(); for x in ar repeat ls := cons(x,ls); ls -- only here, `;' is not necessary, following -- the language rules. -- Note that it is essential to match the opening -- brace to terminate the function definition - -- writing an unindented line does not suffice: } Defined arrToList @ (ar: Array(Integer)) -> List(Integer) %9 >> -- the prompt appears again.
Note that, since the definition is processed only when complete, all the errors will be issued at that point. So, for example, if you forget a terminator in the body of the function in the second example, you will get a syntax error only when you type }. This is true when using either braces or indentation.
Note: With interactive input it is often convenient to cut and paste to and from a file (for example under X11 and Emacs). If you are going to compile the file and you want to use fragments of code from the interative mode, you must either insert #pile at the top of your file or use braces when you (interactively) define multi-line functions.
When you are using the indentation sensitive mode, the interpreter will start to process the code when you add a line with indentation level 0, unless this line starts another definition. This makes cutting and pasting of code easier. For example:
... %4 >> arrToList(ar: Array Integer): List Integer == local ls : List Integer := empty() -- no `;' for x in ar repeat ls := cons(x,ls) ls -- return value arrToList(ar: Array SingleInteger): List SingleInteger == local ls : List SingleInteger := empty() -- no `;' for x in ar repeat ls := cons(x,ls) ls -- return value -- () @ with == add () %5 >>
From the previous example we can also see that: (1) you can type <Enter> before defining the function (as in the first line), so that the indentation is much nicer; (2) the interactive mode is currently unable to print a list of multiple definitions, so you get a strange message when you close the double definition.
Note: when the construct with {...} = add {...} is typed on multiple lines, the braces must be placed as in:
} == add {
} == add {
as this will cause a syntax error.
17.3.2 : Initializatino file
As explained above, when Aldor starts in interactive
mode, it looks in the current directory for a file called
aldorinit.as
.
If this file is found, it will be read before the prompt
appears. Note that this only happens when Aldor starts in
interactive mode (-g loop), and not for the other modes,
such as -g run and -g interp.
The most common use
of the initialization file is to define macros in order to
abbreviate the names of commonly used domains;
another use would be to set interactive options (such as
#int history on
) that are off
by default. An example
initialization file was given earlier.
There is also an alternative method to initialize the interactive environment that, under certain circumstances, is more convenient. You may set the shell environment variable INCPATH to point to a directory containing an Aldor initialization file. Suppose that you call this file mylib.as; then, when you start Aldor with -g loop you may type:
%1 >> #include "mylib"
It is usually convenient to add the line:
#include "aldor"
in the file mylib.as, so that you need to include only this file when you start the interactive mode. Therefore you can initialize the interactive environment by using a file aldorinit.as in your current directory (that will be loaded automatically when you start) or by using a file in the include path that must be explicitly included when you start (or both).
Two observations:
Here is another example of an initialization file:
#include "aldor" SI==>SingleInteger; #int verbose off #int history on out(x) ==> print << x;
17.3.3 : Macros
There are no restrictions for macros. They can be defined and used at top level, as in:
%1 >> SI ==> SingleInteger %2 >> import from SI
We recommend defining a set of macros to abbreviate long domain
names. These macros, which can be placed, for example, in the
initialization file (see above), can reduce the number of typing errors.
17.3.4 : Running inside an editor
If you use editors such as Emacs, we suggest running the
interactive mode in an editor inferior shell.
This will allow cutting and pasting of definitions into your text and
maintaining a history of what was typed, so that in the event of a crash
occurring during the interactive mode session you do not lose what you
typed.
17.3.5 : Using the interactive mode as a browser
The interactive mode also may be used for finding the exports from
domains and categories. Suppose that you want to use the Integer
domain. If you want to know its exports, simply type:
%3 >> Integer
You will get:
() @ Join( with integer: Literal -> % coerce: SingleInteger -> % coerce: % -> (BInt$Machine) coerce: (BInt$Machine) -> % == add () , Join(Steppable, IntegerNumberSystem) with == add () )
to get:
() @ Third(OrderedRing with stepsBetween: (%, %, %) -> SingleInteger stepsBetween: (%, %) -> SingleInteger default stepsBetween(x: %, y: %): SingleInteger == stepsBetween(x,y,1) ) == OrderedRing with stepsBetween: (%, %, %) -> SingleInteger stepsBetween: (%, %) -> SingleInteger default stepsBetween(x:%, y:%):SingleInteger == stepsBetween(x,y,1)
and so on.
17.3.6 : Loading an Aldor file
If you have an Aldor file, you can load it into the interactive environment, so that, for example, you can interactively call and test defined programs. There are two ways to do this:
#include "
myfile"
directive.
For example, when you start, instead of typing:
#include "aldor"
you could type:
#include "myfile.as"
(your file should then contain the #include "aldor"
directive).
% Aldorcmd -g loop < myfile.as
(Note that myfile.as
must respect the braces conventions for the
interactive mode, as explained before.)
17.3.7 : The # symbol
In Aldor the # symbol is a legal operator: some domains
(such as Array
) export operations named #.
The problem is that # is also used to identify a preprocessor
directive, such as #include or #int. This can generate
confusion. Suppose, for example, that you type:
1% >> #include "aldor" 2% >> import from Array SingleInteger %3 >> -- create an array of 7 elements initialized to 0 4% >> a := new(7, 0) array(0, 0, 0, 0, 0, 0, 0) @ Array(SingleInteger) 5% >> #a -- print the number of elements of `a'
at this point you will get the message:
[L5 C1] #1 (Warning) Unknown system command.
because the preprocessor is trying to interpret #a as a directive. To ensure the correct behaviour, you can simply add a space before # when it is not intended as a preprocessor directive, since a line containing a preprocessor directive must start with the # (note that the prompt is not considered by the preprocessor). In our case, a space will be the first character of the line. So, if you type:
%6 >> #a -- with ` ' before `#', you get... 7 @ SingleIntegerthat is, the correct answer.
17.3.8 : Labels
Labels cannot be defined at top level. An input of the following kind is not allowed in interactive mode:
%1 >> @lab1 ... %n >> goto @lab1
Note: Actually, the interactive environment does not check if the user is trying to jump to a label defined at the top level, so you generally get a segmentation fault if you try to do this. Labels can be used within function definitions.