Jovian satellite motion simulator, Messier object database.
- An Integrated Development Environment (@{"AIDE" alink ace:docs/aide.guide/main} - see separate
archive).
- A program which matches section headings to line and page
numbers to create the document you are now reading from an
unformatted version of it.
@ENDNODE
@NODE 2installation "Installation"
Installation
------------
You will need to open a shell to install ACE. Installation consists of:
- Extracting the four archives found in the single supplied ACE
archive.
- Adding a few commands to your s:user-startup (Wb 2.x/3.0) or
s:startup-sequence (Wb 1.3) file.
The ACE distribution archive contains:
- MAIN.lha (main ACE files with a few examples)
- DOCS.lha (documentation for ACE,A68K and Blink)
- PRGS.lha (more example programs)
- AIDE.lha (a graphical front-end for ACE)
All four will fit onto a single floppy disk in their compressed form.
You must now extract the files from each archive with:
lha x <archive>
If you have a hard disk, just extract all four archives into a directory
created for ACE (eg: sys:ACE). Extract MAIN.lha first. This will set up
the directory structure and main ACE files.
The extraction of MAIN.lha also creates three subdirectories for the last
three archives. So, finally, extract DOCS.lha, PRGS.lha and AIDE.lha into
the docs, prgs and AIDE subdirectories.
If you are using a floppy-only system, extract MAIN.lha onto one disk and
the last three archives onto other disks to suit yourself. The disk on
which the main ACE files reside is the volume to which the shell commands
discussed below refer.
You now have all the files you require to use ACE.
Next, add the following lines to your user-startup or startup-sequence
script:
assign ACE: <volume or directory>
path ACE:bin add
where <volume or directory> is the name of the disk or directory where
the main ACE files now reside (eg: assign ACE: sys:ACE).
In addition, you need to add three more statements to your startup-sequence
or user-startup script:
assign ACElib: ACE:lib ; bas finds scanned libraries here.
assign ACEbmaps: ACE:bmaps ; ace looks here for .bmap files.
assign ACEinclude: ACE:include ; app uses this for include files.
You may also have to set the "s" bit on ACE:bin/bas if it was lost during
the unarchiving process. Do this with the following command:
protect ACE:bin/bas +s add
If you're not sure, do it anyway. This simply lets you run the bas script
without having to use the "execute" command.
Now reboot your Amiga to let the above path and assign commands take
effect.
That's it!
** Note: As an alternative to these startup script modifications, you can
use the "ACEsetup" script to be found in MAIN.lha. Read the comments at
the top of that script for usage details.
@ENDNODE
@NODE 2using "Using the compiler"
Using the compiler
------------------
Starting with ACE v2.0 there are two ways to use the compiler:
- From the shell/CLI.
- Via an Integrated Development Environment: AIDE.
Whichever environment you choose to work with ACE in, read on.
ACE expects all BASIC source files to have a ".b" extension.
If you have a program called foo.b, you would invoke the compiler thus:
ace foo (or ace foo.b)
This would produce foo.s, an A68K-compatible assembly source (text) file.
If you wanted to preprocess, compile, assemble and link foo.b, you'd type:
bas foo
which would yield foo (the executable).
The bas script sets the stack to 40000 bytes. Before running ACE by itself,
you will need to set this. A minimum stack size seems to be around 5000
for many ACE compilations, but I recommend 40000 to be safe.
If your Amiga GURUs or hangs during a compile or produces garbage in the
shell, you can be confident that the stack is too small.
You can either create a BASIC source file using an editor or in the
AmigaBASIC environment. If you want to compile a program developed with
the interpreter, just save the program in ASCII format thus:
save "foo.b",a
ACE will only compile ASCII source files, not AmigaBASIC's compressed
format.
For those who don't have access to the AmigaBASIC interpreter but who
wish to convert old AmigaBASIC programs not saved in ASCII format, see
the ACE:utils directory for a utility called ab2ascii written by Stefan
Reisner.
@ENDNODE
@NODE 2options "Compiler options"
Compiler options
----------------
The full command line syntax for ACE is:
ace [-bcEilOw] <sourcefile>[.b]
which indicates that there are currently seven optional compiler switches.
The switches can appear in any combination (eg: -bO, -clb, -O, -ObE) but
*are* case sensitive (so -b does not equal -B).
The "b" switch tells the compiler to include code to check for ctrl-c
breaks by the user. The inclusion of this code can result in noticeably
larger assembly source files, but execution speed doesn't seem to suffer
appreciably.
When a ctrl-c is detected, the program will clean up and exit but
user-defined windows and screens will remain open. The use of ON BREAK
can get around this by allowing for user-controlled clean up
(see the "@{"Event Trapping" link 3event}" section below).
The "c" switch includes each line of ACE source code as a comment in the
final assembly source file. This was requested as a debugging aid. Warning:
the presence of such comments interferes with peephole optimisation. Also
be aware that ACE sometimes includes extra code apart from that which you
would expect purely on the basis of the source code.
The "E" switch creates a file in the current directory called ace.err which
contains all error messages generated during a compliation. Error messages
are still displayed to the screen during compilation however.
The "i" switch tells ACE to make an icon for the executable resulting from
the compilation. The file "ACE:icons/exe.info" must exist as it is used as
the source file for the icon. This allows you to use an icon of your own if
you so wish.
The "l" switch causes the compiler to display each line of ACE source code
as it is being compiled.
The "O" switch causes the assembly source code produced by ACE to be
optimised. At present, simple peephole optimisation is carried out.
Assembly code size reductions of around 5% to 10% are usual. Speed
improvements vary, depending upon the program, however I recommend the
use of the -O switch for all programs where speed is the least bit
important. As time goes by, ACE's optimiser will be improved.
The "w" switch tells ACE to include checks for window close-gadget clicks.
ACE checks all open windows and upon detecting a close-gadget click, the
clicked window is closed and the program exits. However, any other open
windows or screens will not be closed. The use of ON WINDOW can get around
this by allowing for a user-defined clean-up subroutine
(see the "@{"Event Trapping" link 3event}" section below).
The syntax for the bas script is:
bas [-bcEilOw] <sourcefile> [<objectfile>]
where <sourcefile> is the program to be compiled (without the .b extension)
and <objectfile> is a C or assembly module which has been (compiled and)
assembled to produce an object file.
The <objectfile> is linked with the output of ACE+A68K along with db.lib,
startup.lib and ami.lib. This is necessary when an external function or
variable in <objectfile> is referenced by an ACE program. For more about
external functions, see the section "@{"External references" link 3ref}" below.
@ENDNODE
@NODE 2running "Running ACE programs"
Running ACE programs
--------------------
ACE programs can be run from either a shell/CLI or Workbench. In the latter
case a tool icon must be created for the executable. One has been provided
with the archive in the icons directory (exe.info). Refer to the "i"
switch in "@{"Compiler options" link 2options}" above re: automatic icon creation by the
compiler.
As far as I can tell, ACE programs are pure and so can be made resident
once the pure bit is set with the protect command. I've had no problems
so far.
@ENDNODE
@NODE 2example "About the example programs"
About the example programs
--------------------------
I have written a number of programs which illustrate most of the features
of ACE up to this point and you should find these with the distribution.
Several programs are related to chaos theory and fractals - a pet interest
of mine (and of thousands of other programmers :). The remainder are an
assorted bunch which demonstrate ACE's capabilities.
The information for the chaos/fractal programs came from a wide variety of
sources. The algorithms for @{"henon.b" alink ace:prgs/fractals/henon.b/main} and @{"lorenz.b" alink ace:prgs/fractals/lorenz.b/main} came from "Dynamical
systems and fractals: computer graphics experiments in Pascal"
by Becker & Dorfler, 1990.
Some programs are optimised at the source level and some are not. You'll
find that using integer variables can often result in quite dramatic
improvements in program execution speed (eg: try replacing op% with op and
k% with k in @{"ifs.b" alink ace:prgs/ifs.b/main} and you'll see what I mean).
There are several examples which demonstrate the use of recursive
subprograms in ACE (eg: @{"fact.b" alink ace:prgs/misc/fact.b/main}).
Another area of interest for me is neural networks and you'll find a
program called @{"hopnet.b" alink ace:prgs/misc/hopnet.b/main}, which shows graphically how a simple Hopfield
network changes under various conditions.
Other programs include a talking clock (@{"tclock.b" alink ace:prgs/tclock.b/main}), a sound sample player
(@{"play.b" alink ace:prgs/sound/play.b/main}) and a command-line calculator (@{"bc.b" alink ace:prgs/shellutils/bc.b/main}).
@ENDNODE
@NODE 3comments "General comments"
General comments
----------------
I made a decision very early on in the project to allow standard I/O (for
shell/CLI). All other windows are (as of ACE v2.0) Intuition windows.
The execution speed of most programs (especially with graphics, eg: @{"ifs.b" alink ace:prgs/ifs.b/main})
is, as you might expect, *fast* compared to interpreted AmigaBASIC.
No error messages are given at run-time (but file and serial I/O errors
are reported by the @{"ERR" alink ace:docs/ref.guide/err} function), nor is there any stack overflow or
array bounds checking.
Labels are supported and can be used with @{"GOSUB" alink ace:docs/ref.guide/gosub..return} and @{"GOTO" alink ace:docs/ref.guide/goto}. Line numbers are
supported, but are only necessary for old BASIC programs. Also, ACE's rich
assortment of control constructs makes the use of GOTO largely redundant.
Available control constructs are: @{"WHILE..WEND" alink ace:docs/ref.guide/while..wend}, @{"REPEAT..UNTIL" alink ace:docs/ref.guide/repeat..until},
ACE's boolean values are as follows: 0=false, N=true where N is any
non-zero long integer. Note that relational operations give -1 for true
(since: NOT -1 = 0).
ACE allows you to define named global signed numeric constants with the
@{"CONST" alink ace:docs/ref.guide/const} directive (see command and function reference).
Strings have a default length of 1K instead of the usual 32K, since ACE
programs reserve memory for each string immediately at run-time which could
result in quite memory hungry executables if strings were too large. It is
possible however, to define strings which are longer or shorter than 1K
(see @{"STRING" alink ace:docs/ref.guide/string} command).
ACE strings are NULL terminated, ie: the last character is an ASCII 0, as
in the C programming language.
A string literal without a final '"' will be truncated at the end of the
line.
@ENDNODE
@NODE 3ops "Precedence of operators"
Precedence of operators
-----------------------
ACE follows AmigaBASIC in operator precedence, with the addition of
structure dereferencing and indirection operators.
operators
---------
1. Structure Member Dereferencing, ->
Parentheses and Address Operator () @
2. Indirection Operators *% *& *!
3. Exponentiation ^
4. Unary Negation -
5. Multiplication and Floating-Point Division * /
6. Integer Division \
7. Modulo Arithmetic MOD
8. Addition and Subtraction + -
9. Relational Operators = < > <= >= <>
10. NOT
11. AND
12. OR and XOR
13. EQV
14. IMP
The use of parentheses in an expression forces the enclosed term to be
evaluated before adjacent terms. Expression evaluation always proceeds
from left to right in ACE and AmigaBASIC.
@ENDNODE
@NODE 3id "Identifiers"
Identifiers
-----------
As in AmigaBASIC an identifier can consist of a combination of letters,
numbers and periods (".") up to a maximum length of 40 characters.
In ACE the underline ("_") character is also legal. An ACE identifier must
start with either a letter or an underline character.
An identifier can be used to represent the following:
- labels
- arrays
- variables
- structures
- parameters
- subprograms
- defined functions
- named constants
- shared library functions
- external functions or variables
Labels are global in ACE, so a main program label and a @{"SUB" alink ace:docs/ref.guide/sub..end_sub} label cannot
have the same name.
Identifiers can have a qualifier character (%&$!#) appended in order to
indicate data type, where:
% = short integer
& = long integer
! = single-precision
# = double-precision -> not supported yet
$ = string
Examples of valid identifiers are:
x3
num&
_putchar
play.sound
An identifer with no qualifier has a default type of single-precision. The
@{"DEFxxx" alink ace:docs/ref.guide/defxxx} compiler directives (see command and function reference) have the
same effect as the qualifier characters except they affect all identifiers
starting with a certain letter. Qualifier characters have higher
precedence than DEFxxx directives.
For shared library functions and external references, a qualifier is used
merely to declare data type. So for example, an external function might be
declared thus:
external function RangeRand%
but can later be referred to as RangeRand.
The declaration of external functions/variables and shared library
functions is global no matter where the declaration occurs.
Defined constants are unaffected by qualifier characters.
The _value_ of a defined constant determines its type.
Thus CONST x&=1.2 is a single-precision - NOT a long integer - constant.
Needless to say therefore, it is unwise to use qualifier characters for
named constants.
The declaration of constants (with @{"CONST" alink ace:docs/ref.guide/const}) is always global whether the
declaration takes place in the main program or a subprogram.
Structure variables hold a long integer value (address), so trailing
characters have no effect.
Structure type definitions are global, but structure variable declarations
are local.
ACE allows for *optional* variable declarations with the @{"SHORTINT" alink ace:docs/ref.guide/shortint}, @{"LONGINT" alink ace:docs/ref.guide/longint},
@{"ADDRESS" alink ace:docs/ref.guide/address}, @{"SINGLE" alink ace:docs/ref.guide/single} and @{"STRING" alink ace:docs/ref.guide/string} directives. Such declarations are useful in
that:
(i) They ensure that a variable has a NULL or zero
value.
(ii) They prevent dangerous errors which result from
the misspelling of variable names.
(iii) Most languages have them and they serve to
document variable usage explicitly.
(iv) They provide a "cleaner" way of establishing a
variable which is to be shared by a subprogram.
My feeling on the matter of variable declarations is that in a small
program they probably aren't necessary so long as you are careful, but
in a large program all major variables should be declared for safety.
Variable declarations override the @{"DEFxxx" alink ace:docs/ref.guide/defxxx} compiler directives and qualifier
characters and are local to the current level (main program or subprogram).
Note that for any command which is immediately followed by a # there
should be at least one space between the keyword and the #, even though
I may refer to such commands as <name># in the text of this document and
in @{"Ref.Guide" alink ace:docs/ref.guide/main}.
See the command and function reference for details of each of these.
When WRITE# is used, the result is identical to AmigaBASIC. For example:
X=12 : Y=-3.2 : Z$="fun eh?"
OPEN "O",#1,"stuff"
WRITE #1,X,Y,Z$
CLOSE #1
results in a one-line file of the following format:
12,-3.2,"fun eh?"
On the other hand, if the following is used instead:
PRINT #1,X,Y,Z$
the file format will be:
12 -3.2 fun eh?
while if semicolons are used:
PRINT #1,X;Y;Z$
the file format becomes:
12 -3.2 fun eh?
INPUT# (eg: INPUT #1,X,Y,Z$) can be used to read values from a file in any
of the above formats, but bear in mind that strings that are not delimited
by quotes, but contain spaces or tabs will be seen as more than one string
by INPUT#. So, in the example formats above, while
"fun eh?"
is one string,
fun eh?
is two strings as far as INPUT# is concerned.
The formats of sequential files in ACE and AmigaBASIC are now very nearly
identical, the only differences being in ACE tabs (produced by comma
delimiters in PRINT -- see @{"PRINT" alink ace:docs/ref.guide/print} in Ref.Guide) and the number of decimal
places written for single-precision values (usually more in ACE).
If you find ACE file I/O too slow, you may want to use the dos.library
functions (eg: xRead, xWrite). For this reason, I have included the HANDLE
function which returns the AmigaDOS handle of a file opened with ACE's
OPEN command. You may also wish to use the ami.lib buffered file I/O
functions which also require this handle. If HANDLE returns 0, the file
doesn't exist.
See prgs/IO/@{"print.b" alink ace:prgs/io/print.b/main} for an example of opening a sequential file to a
printer.
Although SER: may be opened as a sequential file, it is not possible to
specify parameters for the serial port (baud rate etc) by this method as
is possible in AmigaBASIC.
Instead, ACE provides a set of special serial I/O commands. See Ref.Guide
for details of @{"SERIAL OPEN" alink ace:docs/ref.guide/serial_open}/@{"CLOSE" alink ace:docs/ref.guide/serial_close} etc, and prgs/IO/@{"aterm.b" alink ace:prgs/io/aterm.b/main} for a simple
terminal program.
@ENDNODE
@NODE 3clwb "Command line and Workbench arguments"
Command line and Workbench arguments
------------------------------------
When called from a Shell or CLI, an ACE program may have arguments, eg:
tree 30
Arguments can be accessed by two ACE functions:
@{"ARGCOUNT" alink ace:docs/ref.guide/argcount} and @{"ARG$" alink ace:docs/ref.guide/arg$}(n)
The former returns a short integer value indicating the number of arguments
for the current program, while the latter returns the nth argument as a
string where n ranges from 0 to argcount. The zeroth argument
(ie: ARG$(0)) is the name of the program.
Workbench arguments are currently supported by ACE in the form of four
functions in the include file WBarg.h: WBargcount, WBarg$(n),
WBargPath$(n) and WBargLock&(n).
The first three are the most useful. The fourth is mainly for use by
WBargPath$.
WBargcount returns the number of arguments passed to a program as icons.
As with ARG$(0), the zeroth Workbench argument is the name of the program.
To pass arguments to a program via Workbench one of the shift keys is held
down while the icons which represent the arguments to be passed are
activated. While still depressing the shift key, the application icon is
double clicked.
An alternative method of passing arguments is to change the default tool
of a project icon (eg: document) with the Info option from Workbench.
When this project icon is double clicked, the default tool will be loaded.
In this case, if the source code of the default tool (the program) had a
line such as:
x$ = WBarg$(1)
x$ would contain the name of the project file.
WBargPath$(n) is used to find the full path of the file name and includes
trailing ":" and "/" characters.
See the include file WBarg.h for further descriptions of each function.
@ENDNODE
@NODE 3subs "Subprograms"
Subprograms
-----------
Subprograms are supported by ACE, but differ from AmigaBASIC subprograms in
a number of ways. Namely, ACE subprograms:
- Are non-static,
- Allow recursion,
- Can be assigned return values.
By way of explanation, being non-static means that once a subprogram has
finished execution, its local variables and parameters cease to exist so
far as the rest of the program is concerned.
Recursive subprograms are an important feature of modern general
programming languages. For several examples of the use of recursion, see
the included programs (eg: @{"fact.b" alink ace:prgs/misc/fact.b/main}, @{"hanoi.b" alink ace:prgs/misc/hanoi.b/main}, @{"tree.b" alink ace:prgs/turtle/tree.b/main}).
A word of warning about recursion: it can be stack hungry, so it's a good
idea to set your stack to 20000 or so, just to be safe, although in most
cases, this will be a lot more than you need. From Workbench, simply
change the tool's stack size with Info, or with the STACK command in a
shell.
As with AmigaBASIC, ACE subprogram declarations cannot be nested.
The syntax of a subprogram call is the same as in AmigaBASIC:
[CALL] sub-name[(parameter-list)]
The only difference is that the parentheses around the parameter list are
not optional when @{"CALL" alink ace:docs/ref.guide/call} is omitted -- unless there are NO parameters.
CALL *must* be used after THEN in a single-line @{"IF..THEN" alink ace:docs/ref.guide/if} statement.
By default, every subprogram has a return type of single-precision (just
like variables). The @{"DEFxxx" alink ace:docs/ref.guide/defxxx} directives can be used to change the default
data type of subprograms, as can the trailing characters !#$&%.
A subprogram name can also be preceded by @{"SHORTINT" alink ace:docs/ref.guide/shortint},@{"LONGINT" alink ace:docs/ref.guide/longint},@{"ADDRESS" alink ace:docs/ref.guide/address},@{"SINGLE" alink ace:docs/ref.guide/single}
or @{"STRING" alink ace:docs/ref.guide/string} as yet another alternative to setting the subprogram's return
type.
The fact that ACE subprograms can be easily used as functions pretty much
obviates the need for @{"DEF FN" alink ace:docs/ref.guide/def_fn}. However for reasons of compatibility with
AmigaBASIC and other BASICs, as well as its utility for simple functions,
ACE supports DEF FN (as of v2.0).
A subprogram is given a value either inside the body of the relevant
subprogram or in the main program (eg: to zero it) - ala Pascal - thus:
sub-name = <expression>
However, subprograms cannot be assigned a value in any other way (eg: with
@{"INPUT" alink ace:docs/ref.guide/input} or @{"READ" alink ace:docs/ref.guide/read}).
A subprogram can be used in an expression, whereupon the subprogram is
called and its value pushed onto the stack for inclusion in the final
result of the expression, eg:
x=n*pow(n)
where "pow" is a subprogram with one parameter.
While subprogram declarations can appear anywhere within the program text,
ACE requires that declarations precede calls. So:
sub test
print "hello"
end sub
test
is legal, but:
test
sub test
print "hello"
end sub
is not, and will yield an "undeclared subprogram" error. To get around
this, a forward declaration can be used:
declare sub test
test
sub test
print "hello"
end sub
Forward declarations can include a parameter list. If you later declare
the actual @{"SUB" alink ace:docs/ref.guide/sub..end_sub} with a different parameter list and you've already called
the subprogram after a forward declaration, the results will be
unpredictable. I may place tighter controls on this at some stage.
Actual parameters are checked for number and type against formals, and
parameter count mismatches result in a compilation error. An actual
parameter is coerced to the formal parameter's type.
ACE's parameter passing mechanism for subprograms is NOT the same as that
used for assembly code routines or external functions. In other words, the
standard C parameter passing mechanism is not used for SUBs. This may be
changed in the future as it makes object modules written in ACE
incompatible with C or assembler object modules in this respect.
Changes made to a formal parameter have no effect upon the actual
parameter in a simple call to an ACE subprogram, but see "@{"Limitations" link 4limit}"
re: overwriting of strings/arrays during recursive calls;
see also "@{"Structures" link 3struct}" below.
The formal parameter list consists of identifiers separated by commas.
Each identifier may also be preceded by: @{"SHORTINT" alink ace:docs/ref.guide/shortint},@{"LONGINT" alink ace:docs/ref.guide/longint},@{"ADDRESS" alink ace:docs/ref.guide/address},@{"SINGLE" alink ace:docs/ref.guide/single}
or @{"STRING" alink ace:docs/ref.guide/string} to avoid the use of a qualifier (%&!$).
Actual parameters can basically be any type of expression. A whole array
cannot be passed as a value parameter in ACE however.
There is an arbitrary upper limit of 40 parameters per subprogram at the
moment, which may be removed at some stage.
Main program variables and arrays can be accessed and modified within
subprograms via the @{"SHARED" alink ace:docs/ref.guide/shared} directive. All shared variables are passed by
reference to a subprogram.
Multiple SHARED statements are allowed within a single subprogram.
DIM SHARED is not allowed. An array is declared to be shared in exactly
the same way as simple variables, for example:
DIM x(10)
sub thing
shared x
.
.
end sub
Note that parentheses are not required after an array in the shared
statement, nor are they legal in ACE.
The differences between variable parameters and shared variables in ACE
are that:
- Shared variables only allow access to main program
variables from a subprogram, and do not provide a
mechanism for changing the value of variables in
one subprogram from another.
- The name of a variable to be shared must correspond
to the name of an existing (ie: already referenced/declared)
main program variable.
Although variable parameters are not explictly provided by ACE there are
two ways to implement them: using indirection operators for simple
variables and the @{"ADDRESS" alink ace:docs/ref.guide/address} option of @{"DIM" alink ace:docs/ref.guide/dim} and @{"STRING" alink ace:docs/ref.guide/string}.
(see also "@{"Structures" link 3struct}" section).
Here's an example of call-by-reference parameters for simple variables
(@{"DEFxxx" alink ace:docs/ref.guide/defxxx} directives are used here for clarity):
deflng x '..x is an address holder
defsng n '..n is a single-precision variable
sub doub(x)
*!x := *!x * 2 '...n=n*2 [note the ":=" symbol!]
end sub
n=22.5
print n
doub(@n) '..pass the address of n
print n
which passes the single-precision variable n by reference to the
subprogram doub, where n is doubled. This will first print 22.5 and
then 45.
For an array, the following could be done:
deflng x '..x is an address holder
sub test(x)
dim a(10) address x '..points to n
a(3)=a(3)+12
end sub
dim n(10)
n(3)=2
print n(3)
test(@n)
print n(3)
which would print first 2 and then 14.
The same mechanism can be used to pass a string variable by reference.
These variable parameter mechanisms are most useful when used to pass data
*between* subprograms, otherwise it is simpler to use @{"SHARED" alink ace:docs/ref.guide/shared} variables.
The following table shows the possibilities regarding parameters and
Note: In the above table, "addr" is a long integer address. @{"VARPTR" alink ace:docs/ref.guide/varptr} or @
can be used to obtain this. The address is passed to the @{"SUB" alink ace:docs/ref.guide/sub..end_sub} by value.
@ENDNODE
@NODE 3struct "Structures"
Structures
----------
Structures have been included in ACE mainly because of their utility in
gaining access to operating system functions.
Legal structure members are of the following type: BYTE (in structures
only), @{"SHORTINT" alink ace:docs/ref.guide/shortint}, @{"LONGINT" alink ace:docs/ref.guide/longint}, @{"ADDRESS" alink ace:docs/ref.guide/address}, @{"SINGLE" alink ace:docs/ref.guide/single}, @{"STRING" alink ace:docs/ref.guide/string}. The latter ca
have an
optional size specification.
If an array or structure is required as a structure member, it is necessary
to use STRING <ident> SIZE <bytes>. The address of the member can then be
found with @ or @{"VARPTR" alink ace:docs/ref.guide/varptr} and assigned to an array or structure variable.
If you want to have an address (ie: pointer to an object) as a structure
member simply declare it as an item of type ADDRESS (or LONGINT).
When declaring a structure, the only difference between the following two
forms:
DECLARE STRUCT mystructtype mystruct
and
DECLARE STRUCT mystructtype *mystruct
is that for the former, an appropriate data object is created (on a long
word boundary), but not for the latter.
In both cases, mystruct contains the start address of a structure of type
mystructtype. In the second case, the address is NULL until assigned a
value (eg: with @{"ALLOC" alink ace:docs/ref.guide/alloc}). In both cases, the address can be reassigned at
will, although this should only really be done for structure pointers
(the second form).
Since both forms of structure declaration result in an address being stored
(in mystruct in the example), the dereferencing operator is always "->".
examples:
--------
PRINT mystruct - prints the start address of the structure.
PRINT mystruct->mins - prints the value of a member called mins.
The @{"SIZEOF" alink ace:docs/ref.guide/sizeof} function can be used to determine the size of a structure type
if allocating memory for a structure (see @{"linkedlist.b" alink ace:prgs/misc/linkedlist.b/main}).
ACE structures are stand-alone data objects, and cannot be elements in an
array (although structure addresses can be).
ACE structures can be @{"SHARED" alink ace:docs/ref.guide/shared} to allow its member's values to be modified,
or a structure's address can be passed to a subprogram, eg:
struct my
longint one
longint two
end struct
sub test(addr&)
declare struct my *second
second=addr&
second->one = second->one * 2
end sub
'..main
declare struct my first
first->one=12
print first->one
test(first)
print first->one
which will print 12 followed by 24.
The following code allocates enough memory to hold a structure of type
"my" gives values to the structure's 2 members, and changes the address
held by the structure variable "third" to the start of the newly allocated
memory area:
const PUBLIC=2
declare struct my *third
sub create(ADDRESS a_struct)
declare struct my *temp
temp = Alloc(sizeof(my),PUBLIC)
temp->one = 16
temp->two = 10
*&a_struct := temp '..change structure variable's value
end sub
'..main
create(@third)
.
.
Finally, it is not currently possible to use @{"INPUT" alink ace:docs/ref.guide/input}, @{"(LINE)" alink ace:docs/ref.guide/line_input} @{"INPUT#" alink ace:docs/ref.guide/input_#} or @{"READ" alink ace:docs/ref.guide/read}
in conjunction with structures.
@ENDNODE
@NODE 3lib "Shared library function calls"
Shared library function calls
-----------------------------
ACE provides access to shared libraries in the same way as AmigaBASIC does
with the exception that you MUST declare a function in order to use it.
Also, the library in question must either be in LIBS: or in ROM.
As of version 2.0, ACE and AmigaBASIC are otherwise pretty much the same.
The ACE commands also retain their earlier syntax for backward
- Transfers control to the function <funcname>, loading the
appropriate registers before doing so, according to the
information about that function in the library's bmap file.
- The return value of a function can be accessed by calling
a function as part of an expression, eg: addr& = AllocMem(100,2).
Function declarations are GLOBAL. They are are NOT optional in ACE.
** PLEASE NOTE ***
No type checking of parameters is performed, so expect weirdness if you
pass values of the wrong type. If the RKM or whatever reference you are
using for library functions says to use a long integer, then do so.
Don't assume that a short integer will be coerced to a long integer. It
won't. ACE cannot get that information from the bmap file in which a
function is found and parameters are not sign-extended by default.
When passing strings as parameters it is not necessary to add a CHR$(0)
to the end of a string since ACE strings are already NULL terminated.
Either @{"VARPTR" alink ace:docs/ref.guide/varptr} or @{"SADD" alink ace:docs/ref.guide/sadd} can safely be used to find the address of a string
variable or constant. Actually, the use of SADD or VARPTR for strings
passed to library functions is optional, but it's probably a good idea to
use one or the other all the time, for consistency's sake. These comments
also apply to calling machine code routines and external functions.
It is up to YOU to open and close libraries correctly. ACE doesn't keep
track of this, and will try to jump to a library function so long as
it finds a reference to it in a bmap file even if the library hasn't
been opened! As mentioned above, it is not necessary to open and close
dos.library because _every_ ACE program does this.
ACE expects the bmap file for a library to be in the directory ACEbmaps:
(see "@{"Installation" link 2installation}"). I have been advised by Commodore Australia that
these files may be distributed with ACE but I will wait until I have this
in writing before providing them with the archive (I've waited several
months already).
As of version 2.0, I have provided a program (FD2BMAP) which is
functionally equivalent to ConvertFD (since this may NOT be freely
redistributed) so that bmap files for new libraries can be created.
The source code for FD2BMAP is to be found in the ACE:utils/fd2bmap
directory and was written in ACE by Harald Schneider, with some
modifications by me.
The 1.3 FD files can be found in the BasicDemos drawer on the Extras disk.
The FD files for Release 2.x/3.0 are available from Commodore for about
$30 (you get six disks of developer goodies: ask for the Native Developers
Kit).
AmigaBASIC cannot handle functions which use address register a5. This is
not true for ACE. Neither ACE nor AmigaBASIC allow the use of functions
which use register a6.
See @{"library.b" alink ace:prgs/library/library.b/main} for an example of how to use shared library functions in ACE.
@ENDNODE
@NODE 3machine "Machine code calls"
Machine code calls
------------------
ACE supports AmigaBASIC's mechanism for calling machine code routines and
the passing of parameters to such routines. AmigaBASIC's stack conventions
are also followed (ie: C style parameter passing).
The syntax for calling such a routine is:
CALL long-integer-variable-name[(parameter-list)]
Note that @{"CALL" alink ace:docs/ref.guide/call} is NOT optional. Also, the variable containing the address
of the routine *must* be a long integer in ACE.
For example,
CALL caps&(length&,addr&)
will set up the stack like this:
8(sp) = addr&
4(sp) = length&
0(sp) = return address
on entry to the machine code subroutine caps&.
On exit from a routine, ACE cleans up the stack by POPping all parameters.
You can use a short integer array, a string or an allocated area of memory
(with ACE's @{"ALLOC" alink ace:docs/ref.guide/alloc} function) to poke the bytes of a machine code routine
into. I prefer the latter method.
Note that because ACE treats ASCII 0 as the end-of-string character, don't
use the string-building method, eg:
z$=""
for i=1 to N
read b
z$=z$+chr$(b)
next
since if b=0, chr$(b) will be the NULL string. If you want to use a string,
do the following:
z$="" '..or STRING z$ SIZE 100 (if there are 100 bytes of MC).
addr&=sadd(z$)
for i&=0 to N-1
read b%
poke addr&+i&,b%
next
call addr&
The latter is okay, so long as you don't allocate other strings with odd
sizes. But if you want to be sure that you have an area of memory which
is long-word aligned, use @{"ALLOC" alink ace:docs/ref.guide/alloc}, eg:
addr&=Alloc(100,2) '..100 bytes of PUBLIC memory
for i&=0 to N-1
read b%
poke addr&+i&,b%
next
CALL addr&
The above examples assume the presence of appropriate @{"DATA" alink ace:docs/ref.guide/data} statements. See
the prgs/MC directory for working examples.
ACE also supports inline assembly code inclusion. See @{"ASSEM..END ASSEM" alink ace:docs/ref.guide/assem} in
Ref.Guide for details.
@ENDNODE
@NODE 3ref "External references"
External references
-------------------
Reference can be made to a variable or function in another file which is
resolved at link time. You may for instance, have written a function in C
or assembler. It is possible to pass parameters to, call and obtain return
values (as with ACE SUBs) from such a function in ACE after declaring an
external reference to the function with the @{"EXTERNAL" alink ace:docs/ref.guide/external} FUNCTION directive
(see command and function reference for syntax).
When passing parameters, standard C parameter passing conventions
are used. Although some C compilers seem to pass all parameters as
4 bytes per parameter on the stack, ACE allows 2 (short words) or 4
byte parameters. Be aware of this! See prgs/ExternFunc for examples.
External variables can be assigned values like normal variables, eg:
external RangeSeed&
RangeSeed=5276&
All external reference identifiers have an underscore prefixed by ACE but
this is optional when declaring or using an external reference. C
compilers prepend an underscore to external symbols, so ACE does too.
Note that the names of external references ARE case sensitive.
Also, the bas script can take as a third argument the name of the object
file produced from the original C or assembly source (ie: .o or .lib file)
which contains the external function or variable to be linked with your
ACE program.
It's not easy to call ACE SUBs from C or assembler for two reasons:
1. ACE SUBs don't currently use C parameter passing conventions.
2. ACE produces whole assembly source programs, not just functions
like a C compiler does.
For now, you'll have to get your hands dirty with the assembly source code
produced by ACE if you want to do this. ACE's -c switch may be of some
help here.
@ENDNODE
@NODE 3windows "Windows"
Windows
-------
You can open up to nine user-defined windows on the Workbench screen.
See the command and function reference for the syntax of the @{"WINDOW" alink ace:docs/ref.guide/window}
statement.
All user-defined windows are now (as of ACE v2.0) Intuition windows with
each characteristic being configurable via the "type" parameter as per
AmigaBASIC (see @{"Ref.Guide" alink ace:docs/ref.guide/window}).
Windows can be opened on the Workbench screen or a user-defined screen.
The zeroth window (the shell/CLI, if the program was CLI launched) is now
the only instance of a DOS console window in ACE.
The WINDOW function takes a single parameter and returns information about
the current output window. See Ref.Guide for details.
Note that for user-defined windows, close-gadget clicks must be handled by
the use of ON WINDOW event trapping or via the "w" compiler option.
@ENDNODE
@NODE 3screens "Screens"
Screens
-------
You can open 9 screens at once (memory permitting!).
By default, when a screen is opened, a BORDERLESS window the same size
as the screen is also opened. Subsequent graphics and text commands send
their output to the newly created screen's window (until the screen is
closed). Note that this facility is not provided by AmigaBASIC.
In addition, you can open user-defined windows onto any screen, in which
case all output is directed to the current output window.
Avoid mixing the use of default and user-defined windows. Except for the
simple case in which you use nothing but screens and their default windows
you should consider windows to be the primary output destination for
graphics and text.
When a screen is closed, ACE makes the screen with the next highest id
the current one, so it is advisable to open and close screens in ascending
and descending order.
A special SCREEN function exists in ACE which returns pointers to various
Intuition structures (window,screen,rastport,viewport). This is detailed
in the command and function reference (Ref.Guide) as are the following
commands: @{"SCREEN" alink ace:docs/ref.guide/screen}, @{"SCREEN CLOSE" alink ace:docs/ref.guide/screen_close}, @{"PALETTE" alink ace:docs/ref.guide/palette} and @{"PRINTS" alink ace:docs/ref.guide/prints}. The latter is now
redundant since all commands and functions can - as of v2.0 - be used
transparently for screens, user-defined windows and the shell/CLI.
@ENDNODE
@NODE 3gadgets "Gadgets"
Gadgets
-------
ACE supports the Amiga's three standard gadget types:
boolean, proportional (vertical and horizontal), and
string (including long integer).
Since one of my aims is to support all Amigas running everything from Wb
1.3 to Wb 3.0, I have chosen to stick with simple Intuition gadgets for
now.
In a future revision, a run-time test may detect machines running Wb
2.x/3.0 and use GadTools gadgets instead. Furthermore, other gadget
types may then be supported (radio buttons, check boxes etc).
Memory permitting, up to 255 gadgets can be created during a single
program run.
The @{"GADGET" alink ace:docs/ref.guide/gadget} command creates a gadget with specific features while
@{"GADGET CLOSE" alink ace:docs/ref.guide/gadget_close} removes the gadget from the window. Once created, a gadget
can be enabled or disabled, indeed it can be disabled upon creation if
so desired.
Having created a gadget or gadgets, you must then decide how to receive and
handle information from them. ACE provides four methods: standard event
trapping (ON GADGET), polling (via the GADGET function), WAITing for a
specific gadget or WAITing for any gadget.
Where it is possible to make your programs modal (ie: focussed upon a
single event or event type) you should do so. The @{"GADGET WAIT" alink ace:docs/ref.guide/gadget_wait} command
allows this.
See "@{"Event Trapping" link 3event}" for more about modality in ACE programs.
The following commands set up a window with two boolean gadgets and a
close gadget. The latter is set up by Intuition with the @{"WINDOW" alink ace:docs/ref.guide/window} command.
The program traps WINDOW and GADGET events. The comments should help you
understand the code.
CONST having_fun = -1&
WINDOW 1,"Gadgets",(0,0)-(640,200),8
GADGET 1,1,"Hit Me",(3,3)-(75,20),1,1
GADGET 2,1,"Quit",(100,150)-(200,175),1,2
ON GADGET GOSUB gadget_handler
GADGET ON
ON WINDOW GOTO quit
WINDOW ON
'..main loop (actually does nothing, but is necessary for event trapping)
WHILE having_fun
'..have a nap while nothing's happening
'..(don't hog the machine by busy waiting)
SLEEP
WEND
gadget_handler:
'..find out which gadget was selected
gad = GADGET(1)
LOCATE 12,40:PRINT "<<";gad;">>"
if gad = 2 then quit
RETURN
quit:
GADGET CLOSE 2
GADGET CLOSE 1
WINDOW CLOSE 1
END
Alternatively, you could poll for a gadget to the exclusion of other
events:
.
.
'..await a gadget selection
REPEAT
WHILE NOT GADGET(0)
SLEEP '..be a little nice to the operating system
WEND
'..which one?
gad = GADGET(1)
LOCATE 12,40
PRINT "<<";gad;">>"
UNTIL gad=2
.
.
Finally, you can wait for a gadget:
.
.
GADGET WAIT 2 '.."GADGET WAIT 0" waits for ANY gadget! BEST method!
.
.
See the program prgs/misc/ACEgadgets.b for an example of gadget programming
in ACE.
For boolean gadgets you can - if you need to - get information about the
width and height of the gadget's text font by calling WINDOW(12) and
WINDOW(13). If you need more precise width information, use the graphics
library TextLength function.
ACE string gadgets currently only allocate enough text buffer space for
the number of characters which can fit into the gadget (as specified by
the bounding box in the GADGET command).
In the next revision, this will be changed to allow a larger buffer such
as InputBox[$] permits (see the "@{"Requesters" link 3requesters}" section) either via an
optional buffer-size parameter or a fixed-size buffer. I have not yet
decided upon the best course to take on this matter.
For more details about the @{"GADGET" alink ace:docs/ref.guide/gadget} commands and function, see Ref.Guide.
@ENDNODE
@NODE 3menus "Menus"
Menus
-----
ACE supports menus ala AmigaBASIC, with two additions: menu item command
keys and a @{"MENU WAIT" alink ace:docs/ref.guide/menu_wait} command. The latter puts the program to sleep until a
menu event occurs. The former is specified by an optional parameter to the
@{"MENU" alink ace:docs/ref.guide/menu} command, for example:
MENU 1,5,1,"Quit","Q"
defines menu item number 5 in menu number 1 to be the 'Quit' option and
sets up a command-key sequence (Amiga-Q) for that item. The third parameter
enables the menu item as per AmigaBASIC.
Note that although ACE adjusts menu text for font size and type as set
via preferences, some fonts may require you to pad your menu title/item
names with blanks when using command keys to avoid overlaps.
For an example of menu programming with ACE see prgs/@{"ifs.b" alink ace:prgs/ifs.b/main}. For a better
example, see the source code for AIDE. Over time I will modify some of
the other example programs in the archive so that they are menu-driven.
See Ref.Guide for more details about the @{"MENU" alink ace:docs/ref.guide/menu} commands and function.
@ENDNODE
@NODE 3requesters "Requesters"
Requesters
----------
As of version 2.0, ACE supports 3 standard requesters:
- System requester
- File requester
- Input requesters x 2
My recent experiences with Visual Basic for Windows have led me to add
these to ACE since I have now come to expect them. You can get the most
commonly needed requesters in a single line of ACE code!
If you are running Wb 2.x and above, ACE generates an ASL file requester.
For Wb 1.3 an ARP file requester is invoked for two simple reasons:
- The arp.library is common on Wb 1.3 systems.
- The ARP file requester is still quite good.
See @{"MSGBOX" alink ace:docs/ref.guide/msgbox}, @{"FILEBOX" alink ace:docs/ref.guide/filebox$}, @{"INPUTBOX" alink ace:docs/ref.guide/inputbox} and @{"INPUTBOX$" alink ace:docs/ref.guide/inputbox$} in Ref.Guide for more.
@ENDNODE
@NODE 3turtle "Turtle Graphics"
Turtle Graphics
---------------
You may be wondering one or more of the following:
- what the heck is Turtle Graphics?
- isn't that for kids?
- why did he include THAT?
To answer the first question: Turtle Graphics (TG) originated as a subset
of the language LOGO invented by Seymour Papert et al at MIT. LOGO was
originally intended as a language for learning. Children are able to write
simple programs to draw shapes on the computer's screen or move a
Turtle - a dome-shaped robot - on a sheet of paper on the floor, learning
about geometry "by doing" and having fun to boot.
LOGO also has many Lisp-like qualities and so can be used as a serious
language for AI work, although to my knowledge, it's not.
But I digress. Apart from the fun kids can have with TG, it's actually
possible to construct quite complex shapes with it. Combined with
recursion, TG is a powerful tool. It is particularly useful in plotting
many fractal shapes (see @{"snowflake.b" alink ace:prgs/turtle/snowflake.b/main}, @{"dragon.b" alink ace:prgs/turtle/dragon.b/main}).
Since the first LOGO, there have been many manifestations of TG. Turbo
Pascal for the PC and the Mac have both had TG.
A couple of years ago, I wrote a pure TG subset of LOGO which used the
same syntax as the original language and allowed recursive procedures. I've
also written TG functions in C. Both of these have been useful to me and
I've often wished that BASIC came with TG built-in. Well, now one dialect
does!
For some examples of the use of Turtle Graphics in ACE, see the following