home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d7xx
/
d743
/
turbodex.lha
/
TurboDEX
/
Dex.doc
< prev
next >
Wrap
Text File
|
1992-10-11
|
56KB
|
1,416 lines
TurboDEX Compiler v1.2 by $#%!
M A N U A L
Contents:
1. Introduction, The Features
2. Installation And Running
3. The Language In General
4. Step by step Tutorials
5. Alfabetical Overview Of Instructions
6. Function() overview.
7. Advanced Programming And Language Info's
8. Additional Info's
-------------------------------------------------------------------------
CHAPTER 1, INTRODUCTION; THE FEATURES.
-------------------------------------------------------------------------
What is DEX ?
DEX is a Compiler-Language, like C, Modula2, GfaBasic, Pascal etc. it
features a similar programming structure and programming possibilities as
above languages. Yet you'll have to consider that DEX as to offer a lot
more, and, on the other hand, some aspects of the language are less
flexible.
NEW FEATURES ADDED FROM v1.1 TO v1.2
- DataType STRING, together with 14 functions to modify strings,
as StrAdd(), StrCmp(), Instr(), ReadStr(), Val(), StrCopy() etc.
- 16 very handy miscelanious functions to make life easier: a.o.
OpenW(), OpenS(), Gadget(), FileLenght(), MouseX() etc.
- Various small enhancements and bug fixes, like:
flexible comments /* */ and Constants TRUE, FALSE and NIL,
interrupting compilation by pressing both mousebuttons.
- New example sources.
Dex Features:
- Short Executables; small to medium size DEX-sources will compile nearly
always compile to less than 1K, where above languages will need nearly
always more than 5K. (examples: the program given as an example with
the WRITE statement in the reference section would compile into an
executable of ± 300 bytes, the code of a complete vectordemo was done in
± 1300 bytes. All inclusive hunks, reloc-tables, opening of librarys etc.)
- Clear assembly source output: DEX generates fully commented assembly
source, in which you will be able to find all the variables you used,
and compare the code-generation directly to the DEX-source.
- Direct access of all routines of EXEC, DOS, INTUITION, GRAPHICS and MATH,
without ANY includefiles and without opening ANY library. All
customchip registers can adressed by their name, without ANY include.
- Handy features like Global/Local variables, easy calling of
procedures and libraryroutines with return values, inline assembly
code, use of registervariables.
- Faaast executables, extensive use of registers, fast parameter passing,
smart solutions for local variables and structs, quick optimization,
pc relative branching and adressing, special HYPER optimize mode for loops.
- Easy to manage development system: just one compiler will do the job,
no 5 meg of includes, linkfiles, objects, optimizers, profilers etc.
All instructions needed for writing a substancial program integrated
in the compiler.
What is shit about TurboDEX?
- some things haven't been implemented.
- some errors which you might make while programming are not recognised,
and will be compiled, since no things like stack-overflow checking
are implemented.
- Its mosly faster than above languages, but still not optimized enough.
- it doesn't do any type-checking, so things like dividing a CHAR
variable by a LONG, or messing up pointers to wrong memory-area's
are not flagged by the compiler.
- The compiler can be *very* slow sometimes
- The development system is not adequate for big app's.
- kick 2.0 compatible but not 2.0 specific (generates 1.2-and-up code).
- It's not idiot-proof.
Generally, DEX gets you ASSEMBLY quality performance an size executables,
with BASIC effort. But the prize to pay for this that the programmer
needs to know what he's doing.
If you're eager to see what a DEX-source looks like, browse through
the drawer with examples, kick-ass with 'HelloWorld.dex', then check
out the other small sources. For your convenience here's some example:
/* Nominated for most boring example */
PROC main()
WRITE 'Hello, World!\n'
ENDPROC
-------------------------------------------------------------------------
2. INSTALLATION AND RUNNING
-------------------------------------------------------------------------
How to work with TurboDEX.
First of all: all you really need is the compiler 'DEX'. just type
something like:
DEX [-opts] <sourcefile>
example:
DEX:> dex -a helloworld
the compiler will take a pure ascii file with the name 'HELLOWORLD.DEX'
as input in the current directory (this file contains some dex program
you wrote), and will produce a file 'HELLOWORLD.S' as output (this file
contains the assembly language translation from your DEX-source).
The -a flag will cause DEX to invoke A68k and Blink straight away, to
assemble and link the .S file..
Now type:
DEX:> HELLOWORLD
Hello, World!
DEX:>
If you don't use the -a flag, you'll have to assemble by hand. Almost
any assembler will do, supported are A68k and DEVPAC (tm).
Compile with an assembler like A68K and link it with for example Blink:
Dh0:> A68K HELLOWORLD.S
Dh0:> BLINK HELLOWORLD.O
Another example:
Dh0:> dex -flgr
This will enable you to pick your source by means of a file-requester,
dex will generate a list-file, invoke Devpac's GENAM instead of the
A68k/Blink duo, and execute your program afterwards.
Above is all you need.
Additional suggestions:
Best you shove DEX into your C: dir next to A68K and BLINK.
You may want to make Genam or Blink resident to speed up the process,
and if don't own a HD, copy DEX to ram: so you can
Compile-Assemble-Link-Run without disk Access.
NOTE: DEX outputs code suitable for A68K, so if you'd like to use
some other Assembler, you could be forced to make some minor changes.
(see -o option).
CommandLine Options:
Executing DEX with nothing following it will result in DEX opening
a window, where you can enter the commandline at the 'IN>' prompt.
options:
? Display a 'usage:' and some info
-a If compiling succeeded, invoke A68K and BLINK from the compiler.
NOTES: both need to be in the search-path (i.e: mostly C: or the
active directory). this will need c:run (<2.0) and some free-memory.
-c Don't add comments to assembly source (because you're not interested
in the generated code anyway), makes file smaller.
-f Pops up a filerequester to let you choose a source to compile
instead of having to enter it at the commandline.
-g Have GENAM (part of the Devpac (tm) assembler) assemble and
link your program. Includes -o, excludes -a.
-l Produce a list file named <source>.LIST, containing statistical
info's about the program, the compiler-status, and lists of
identifiers, procedures etc.
-o Generate assembly source for any other assembler than A68k.
-r Run the executable after being generated. needs -a or -g
-s Try to generate code that is more reliable, but slower. The compiler
will insert extra intructions to do extending of wrong-size variables,
and make some extra checks. This option must only be used for
test-purposes. Not guaranteed to help.
-t Don't compile file at the command line, but internal test-source
instead (for test-purposes only).
NOTE: options are case-INsensitive, may be put anywhere on the commandline,
and can be but together. so 'DEX -c test -A' has the same effect as
'DEX -ac test'.
NOTE2: Genam may act weird sometimes due to the fact that it probably
expects being run from devpac when it isn't run run from a shell. if
this bothers you, write a small script to run dex and genam, and leave -g.
Ok. Now over to the real stuff:
-------------------------------------------------------------------------
3. THE LANUAGE IN GENERAL
-------------------------------------------------------------------------
Procedures.
All programming instructions are gathered in modules, called PROCs.
The most important of these is the procedure PROC main() which always
has to be part of a program (it doen't have to be the first procedure).
this is the actuall program, where all variables are global. Other
procedures can be added, that can have own (local) variables. These
procedures can be called with or without parameters, like:
'VOID getpicture(rastport,x+4,y/8)'
Procedures cannot be called recursively.
Loops.
Lots of loops are supported, like FOR ... ENDFOR, WHILE ... ENDWHILE and
some others. These can be nested infinetely (well, nearly).
Variables.
At the moment 11 types of variables are supported:
- LONG, a 32 bit wide integer variable, can hold any value from
somewhat less than -2.14 to a little more than 2.14 milliard. this
is the most used variable since all addresses are kept in these,
most system routines expect longints, and nearly all calculations
are done in 32 bit.
- INT, a 16 bit variable, keeps values from -32k to +32k. Used with
multiplies/divides.
- CHAR, an 8 bit variable, most used with texts, and other small data.
range 0 to 255.
- STRING, defines a string that may be modified, and used especially
for complex string manipulations. example:
DEF s=100:STRING
s may now be modified by special string functions. see chapter
on (string-)functions for more info.
- REGLONG, REGINT and REGCHAR. These are the same ase those three described
above, with some small differences: - max. 6 of them can be used per
module, - 680x0 registers are used for their storage.
The advantage of these is mainly their speed, as wel as the smaller and
better code they produce. They are best used with DOWN loops, and
everywhere you need to have a certain part of your program to be as
faaast as possible.
NOTE WELL: these may only be declared with LOCAL
- ARRAY and ARRAYCHIP. These are simple implementations of arrays, and
function as CharArray only. They are defined as variable, and the
variable (compatible with LONG) contains a pointer to the array.
ARRAYCHIP is the version of ARRAY where the array is forced to
chipmem. (for the 'insiders': BSS_c ).
- CUSTOMREGS. all customregs can be used as variable. Just type the
official name in capitals, like DMACON. this enables lines like:
AUD0LEN := samplelen/2 or even COLOR00 := VPOSR*VHPOSR
its up to you to see which registers you can read or write.
- ABSOLUTE, if you would write or read absolute addresses, you can
use a value (specifying the adress) between [], following the variable-
name in the definition, like: sysbase[4]:LONG, would enable you to
use sysbase as an absolute variable. Like this you can specify a
variable as part of a STRUCT, which provides extremely flexibel
programming, like: depth[newscreen.8]:INT
all these variables (except for the CustomRegs) have to be defined before
use. See DEF in the reference section for more info's.
Other parameters.
these can be used as value only.
supported in this version are:
- Values: dependent on the instruction you use, values like 4, 100,
4543836, $ff, $c00000, %101110 etc. can be used.
- Adresses of labels and STRUCTS. you may need to now the address of a
label or stuct in your program. e.g. if somewhere in your program is
something like 'PROC text()', 'STRUCT text' or 'text:' the address could
be obtained with adr := {text} (use {} with the labelname).
- a constant. currently, you can't define them yourself. only these are
available: TRUE (=-1), FALSE (=0), NIL (=0)
- A text string. in the current version, strings that can be altered
are not supported. Though, you may give a string between '' as a
parameter. if the string is one character long, the ascii code will
be passed: c := 'A' equals c := 65 . If the string is longer, however,
the address of the string is passed, thus enabling flexible programming
were routines need the address of a textstring, for example:
VOID Text(rast,'Hello There !',LEN). LEN is a systemvariable, always
containing the lenght of the last string used. In the string you
may use the following codes:
\n a return + linefeed (ascii 10 and 13)
\a an apostophe, the one you need for enclosing the string
\t insert a TAB (9)
\f a linefeed (ascii 10)
\e insert an escape-code (27), '\e[' will work as CSI.
\0 a null byte (not often needed, as all strings in DEX
are terminated with a '0').
\\ a backslash.
example: 'this: \a\\\a is a backslash \n\0'
Additionally, following codes may be used only when using a
string as part of a WRITE-statement:
\d print out a LONG as decimal.
\h print out a LONG as hexadecimal
\c print out a LONG as character
\s print out a 0-terminated string at address.
\w<x> sets minimum width for print, rest will be padded with spaces.
\z pad with zeroes instead of spaces.
\m<x> sets maximum width for strings.
\l put data to the right of the field (default).
\r put data to the left in the field instead of to the right.
example:
WRITE 'some results: \z\w8 $\h \c.',65535,65
will print:
some results: $0000FFFF A.
note: changes to print-formatting made with \w\z\m\l\r are only
valid within one WRITE-statement, they are reset to default
values at the start of the next statement.
- A string as integer value. you may use strings of lenght 1-4 between
double quotes ("") to, for example, quickly compare short strings:
IF {buffer}="FORM" and a := "A"
are equal to
IF {buffer}=$464F524D and a := 65
The first character is stored in the MSB of the LONG. If only
one character is supplied, it is stored in the LSB.
Parameters needed;
mostly a parameter could be one of 2 different types, in the description
of the commands that follows specified as var or exp.
var = parameter that must be a variable. examples;
a, count, COLOR01, etc.
exp = parameter that can be a variable, a value, or an expression (a
combination of more aspects). examples;
1, 200, $ff, a, DMACON, count+3/a-2000
these can be all mentioned above, including combinations.
For example, the parameter of FOR that is the counter would be a var,
and the two parameters specifying the range could be any exp(ression).
Expressions.
as stated above, everywhere an instructions needs a parameter that is
is an exp, you can use any of these operators with variables/values mentioned:
-,+ minus and plus, no restrictions.
examples: 3+a, 60-{text}+$ff
/,* divide and product, these are always done 16bit wide, watch
carefully when using them. examples: a/20, counter*256.
for 32bit operations, see MUL() and DIV().
&,^ AND and OR, used only as mathematical, not logical operators.
=,<,>,? comparisons. in the current version they are only usefull with
IF and WHILE. They need to be the last operator used.
In order: equal, smaller than, bigger than or equal, unequal.
examples: a=3, {data}-1024>$c00000, flag?0, 3*b>a
IMPORTANT: in the current version of the compiler, expressions are compiled
in the same order as written in the sourcecode, and () are not supported.
thus, a+(3*b) shouldn't be written as a+3*b, but 3*b+a, otherwise a+3 would
be calculated first, instead of 3*b. same goes for comparison (!) operators.
Labels and remarks.
labels stand on their own line.
a label is any string followed by a ':' and can be used only to point at
instructions, not structs etc. (see above) example:
startofprogram:
when you program very structured, you won't need labels.
two types of remarks are supported: remarks that start with a ' and
stand on their own line. f.e.:
' Here the screen is setup
/* or remarks that may be anywhere within the source, also on multiple
lines (not nested), as around this sentence */
Syntax.
first of all, the only place where spaces are obigatory, is after an
instruction keyword: WHILE<space>a=3
furthermore, the whole language is case sensitive.
uppercase: keywords, customregisternames
lowercase: variablenames, labelnames, procnames, structnames
both : systemcallnames, Dex additional functions.
every part of the name starts of with an uppercaseletter,
like: VOID WindowToFront(), VOID OpenW()
Startup options.
optional keywords about what sort of startup-code TurboDEX should
generate, may be given between the brackets of PROC main() :
ARG The variables 'argadr' and 'argl' contain the command-line
passed to your program (both LONG).
WB Code will be added to start your program from workbench too.
NOTEZ BIEN: you need to supply a value for stdout
if you write a WB program that uses WRITE.
best is to open a CON:
DETACH makes a program auto-detaching, can be started from shell
without 'C:RUN'
INIT compiles no initcode at all, no opening of librarys etc,
for programs that need to be _VERY_ small (<200 bytes),
rarely usefull.
example: PROC main(ARG)
NOTE: it is not advisable to use more than one option at a time.
Build-In Variables:
Presently, seven of them may be used: stdout, dosbase, graphicsbase,
intuitionbase and mathffpbase (execbase is DEF sysbase[4]:LONG).
When using these variables, code is genereated to provide a correct
contents, and, when using a function from a library, the base is also
defined. stdout contains the output filehandle (mostly the shell window),
when using the WRITE statement: when it's 0, you can open a CON:, and
put it's filehandle into the variable stdout. Furthermore, the variables
argadr and argl (both LONG) may be used if the flag ARG is used
in the header of main().
------------------------------------------------------------------------
4. STEP BY STEP TUTORIALS
------------------------------------------------------------------------
Assuming you copied DEX, A68K and BLINK to your C: directory, made
a directory for storing your sources and the examplesources, and
started up some editor to get things going, i will now give some small
tutorials on DEX-programming.
Best you try to get the HelloWorld.dex program running first. This
will give you a good impression on how the system works. load it in your
editor to see what it looks like:
' The HelloWorld program in DEX !
PROC main()
WRITE 'Hello, World!\n'
ENDPROC
Now, change it to your needs, save it, and compile it with:
DEX HelloWorld -a
After all compiling has been done, check the directory the source is
in. It should now contain two new files: HelloWorld.s and HelloWorld.
I'll get back later on the contents of the .s file, now just execute
the program by typing it's name. Please take note of the small size
of the executable (i guess about 300 bytes).
You now used the basis of any dex program: the PROC main().
this is the minimum of any program: you may add other procedures,
which may have arguments and local variables. The WRITE instruction
can be used for many more purposes than just writing string-contants:
it can print variables in decimal, hexadecimal and ascii format,
and nil-terminated strings. as an example we will now make a program
that prints the starting address of the exec.library to the screen:
PROC main()
DEF sysbase[4]:LONG
WRITE 'execbase = $\h',sysbase
ENDPROC
Here we do something new, we declare a global variable, like 'a'
DEF a:LONG
but now we state we would like to have it at a fixed address, $00000004.
We can print out the contents of the variable sysbase by putting
the formatcode '\h' (hexadecimal) in the outputstring, and the value
following it.
I will now discuss some of the programs to be found in the directory
with example sources to show how small programs could be developped.
First here's the SHELL.DEX program:
/* TurboShell in TurboDEX */
PROC main(DETACH)
DEF window:LONG, buffer=60:ARRAY, a:REGLONG, text:REGLONG
window := Open('con:10/10/400/100/TurboShell v0.0\0',1006)
VOID Write(window,'Shell by $#%! in 1991. \aquit\a to stop.\n',LEN)
WHILE text?"quit"
VOID Execute(buffer,0,window)
VOID Write(window,'Turbo> ',LEN)
a := Read(window,buffer,59)
MCHAR buffer+a,0
text := MLONG(buffer)
ENDWHILE
VOID Close(window)
ENDPROC
It's a very small program that show's clearly enough how to use some of
the language's features. Here's a step-by-step explanation of how
it works:
Because it's a small program, all code is gathered in one procedure,
and we tell the compiler that we want to give the Shell-prompt back
after our program is loaded with the DETACH option. Now we define
a couple of variables for use in the program: in 'window' we will
store the filehandle to our CON:-window, 'a' and 'text' are for use
lateron and buffer is an array of 60 bytes, which we will use to store
the commandline Note that 'buffer' is actually a variabele of the type
LONG which contains a pointer to that array. Now we use Open() from
the dos.library to open our console window, and we do not check if
an error occurred, for the simplicity of the example. Note that you
do not need include-files modules to be linked or whatever to be
able to use functions like Open, they're build in to the language.
Now we use the dos.library Write() (not the DEX WRITE!) to output
a message to it: We could have done this using WRITE, but the example
is about system-functions. Now we come in a loop which we will only
exit if 'text' is unequal to the (LONG-encoded) string "quit".
In this loop, we will Read() something from the console, and then
Exexute() it as a cli-command. Note that we use MCHAR (put a CHAR-sized
value into memory) to terminate the string.
Here's a somewhat longer example to get the feeling of how things
are done in DEX, COLORSCREEN.DEX
/* Open a screen and do something */
PROC main()
DEF rast:LONG,screen:LONG
DEF sx:REGINT, sy:REGINT
screen := OpenS(320,256,5,0,' TurboDEX Screen ')
rast := screen+84
IF screen?FALSE
MOUSE
DOWN sx,320
DOWN sy,256
VOID SetAPen(rast,sx*sy)
VOID WritePixel(rast,sx,sy)
JUMPMOUSE leave
ENDDOWN
ENDDOWN
ENDMOUSE
leave:
VOID CloseS(screen)
ENDIF
ENDPROC
We use the DEX functions new in v1.2 to open and close our screen:
OpenW(), CloseS(). before we start plotting we have to be sure
the screen was actually opened.
In the main program we enter the big MOUSE - ENDMOUSE loop which
is very handy for demo-like programs like this one. it is accompanied
by an extra JUMPMOUSE for faster exit. The inner loop draws the screen
full of colourfull pixels. Note the VOID intruction: we're not interested
in the returnvalues ( 'VOID' is like 'dummy:=' ), when calling the
procedure screen(), we are: ENDPROC gives us the screenptr.
Now we will look at a complete utility in DEX, with errorchecks
To make it usefull for everyday use: a three-column dir-command!
DIRQUICK.DEX displays filelenght too and makes use of extended WRITE
string-formatting.
/* nice directory command in dex ! */
PROC main(ARG)
DEF lock:LONG, info=260:ARRAY, ok:REGLONG, d:REGLONG, c:REGLONG
DEF dir:LONG
MCHAR argadr+argl-1,0
lock := Lock(argadr,-2)
IF lock?FALSE
ok := Examine(lock,info)
IF ok?FALSE
dir := MLONG(info+4)
IF dir>0
WRITE 'Directory of: \s\n',info+8
c := 0
WHILE ok?FALSE
ok := ExNext(lock,info)
INC 1,c
IF ok?FALSE
d := MLONG(info+124)
dir := MLONG(info+4)
IF dir>0
WRITE '\e[1;32m\w25\m25\l\s\e[0;31m',info+8
ELSE
WRITE '\w17\m17\l\s \r\w7\d',info+8,d
ENDIF
IF c=3
WRITE '\n'
c := 0
ELSE
WRITE ' '
ENDIF
ENDIF
ENDWHILE
IF c?1
WRITE '\n'
ENDIF
ELSE
WRITE 'No Dir!\n'
ENDIF
ENDIF
VOID UnLock(lock)
ELSE
WRITE 'What ?!?\n'
ENDIF
ENDPROC
At every step in the program we check if an error may have occurred,
and we put all the nested IF's into one procedure: after making the
neccesary locks and examines, we read each entry, and put it directly
on the screen, directory's and files each their own color for distinction.
Those WRITE statements are good examples of somewhat more complex
string/integer formatting. Note we keep track of the column we're in
with variable 'c'.
Here's short description of all other examples:
DIRSORT.DEX An extented version of DIRQUICK.DEX, does a very
slow bubble sort on the entries before displaying, and
separates the directories from the files. can only read
dir's with less than 400 entries (changeable).
ASLREQ.DEX a demo of how non-DEX-standard-kick-2-libraries may be
used: it puts up the ASL-filerequester, and checks
nicely if you have KICK2, if it could open the library etc.
PLAYSAMPLE.DEX Show's how the buil-in hardware-register variables
can be used to play a beep.
COPPER.DEX Show's the ease of copper-programming from DEX
NEWWINDOW.DEX Opens a intuition-window and output's a text it.
GETARG.DEX Show's how to handle commandline arguments from DEX.
SPEED.DEX Proggie to show off DEX's optimed loops.
RESIDENT.DEX Display's all exec resident modules. Shows how for example
system lists can be dumped.
VECTOR.DEX A vectorDemo in DEX that rotates the word 'TurboDEX' on
the screen in three colours, using the graphics.library,
double-buffering and a precalculated-coordinate list
in the file TDEX.BIN. If you want to compile
this program, make sure the INCLUDE statement in the
source points to where you have the .BIN file.
What's new in v1.2: (except the update of above examples)
MEM.DEX a small utility to let you view any memory area
with hex and asciidump as in a monitor, but now from
a shell. very handy for debugging.
QUICKLAUNCH.DEX a complete application launching utility in DEX.
reads names of app's from a configfile in S:, then
put's them in a window with DEX powerfull new
GadGet() function. nice utility.
Furtermore in the directory PDexamples, you will find sources written
by authors other than me, distributed as PD. currently this is only one.
-------------------------------------------------------------------------
5. ALPHABETICAL DESCRIPTION OF INSTRUCTIONS
-------------------------------------------------------------------------
-----------
AND, OR, NOT
-----------
syntax: AND value,variable
OR value,variable
NOT variable
description: Performs logical and, or and not on a variable.
NOTE: AND and OR are also available as operators in an
expression (&,^).
example: AND $ff,c
NOT x
-----------
ASM, ENDASM
-----------
syntax: ASM
ENDASM
description: all following this statement until ENDASM will not be compiled
by the compiler, and is put unchanged into the output file,
thus enabling inline assembly. if registers D2-D7 are used,
these should be put on the stack first. Make sure you use
distinct labels: best way is to prefix them.
example ASM
moveq #0,d0
ENDASM
-----------
CALL
-----------
syntax: CALL address, paraddress, returnvar
CALL base[offset], paraddress, returnvar
par: address = any memory location that is the start of a routine
base = base address of a library
offset = offset from a librarybase, like -552
paraddress = pointer to memory chunk of 14 longwords,
containing the parameters to a routine, in d0-d7/a0-a5 order.
returnvar = variable to put the returnvalue in
NOTE: both paraddress and returnvar are optional.
description: this instruction enables you to call any assembly language
subroutine, and in particular librarycalls that are not
part of the DEX set.
see the ASLREQ.DEX source for a good example.
example: ' assuming you have an initialized variable called 'aslbase':
CALL aslbase[-30],,reqadr
' this will call AllocFileRequest() from the asl.library
' reqadr may contain 0
-----------
CMOVE, CWAIT, CSKIP, CPART, CSTOP
-----------
syntax: CMOVE value,customreg
CWAIT rastline,rastpos
CSKIP rastline,rastpos
CPART
CSTOP
par: customreg = valid name for a customchip register, like: BLTSIZE
rastline = beam y position (0-255)
rastpos = beam x position (0-$E0)
description: Instructionset to code the copper coprocessor. these
instructions need to be gathered in a CHIPSTRUCT
See your Hardware Reference Manual for more information on
functioning of these instructions. CSTOP designates the
end of a copper-list, CPART needs to precede any intructions
that are to be executed after rasterline 255.
example: ' Split screen in two colors and be very rude to multitasking;
PROC main()
COP2LCH := {coplist}
INTENA := $4000
MOUSE
ENDMOUSE
ENDPROC
CHIPSTRUCT coplist
CMOVE $fff,COLOR00
CWAIT 80,$01
CMOVE $f00,COLOR00
CSTOP
ENDCHIPSTRUCT
-----------
DEC, INC
-----------
syntax: DEC value,variable
INC value,variable
description: Substracts or adds the value (-8 to 8 excluding 0)
to the indicated variable.
example: INC 2,count
-----------
DEF, LOCAL
-----------
syntax: DEF varname:TYPE [, ... ]
LOCAL varname:TYPE [, ... ]
par: type = any of the types of variables discussed in the above
section of variabletypes (like LONG, ARRAY etc.)
varname = any string, signifying the name of the variable. may
be followed by = with a value (LONG, INT, CHAR only) to
initialize it before use (default = 0). Using = with ARRAY
signifies the size of the array (like string=100:ARRAY).
description: declares a variable before use, where DEF defines the
variables that can be used in any module (global), and LOCAL those
which can only be used in one module (local).
example: DEF adr:LONG, sign=25:CHAR, count:REGINT, string=256:ARRAY
LOCAL item[data.6]:INT, picture=10240:ARRAYCHIP
-----------
DIV, MUL
-----------
syntax: var := MUL(exp,exp)
var := DIV(exp,exp)
description: MUL and DIV are 32 bit substitutes for the * and / operators.
The 68000 processor doesn't support 32 bit multiplication and
division, only 16 bit. dex compiles * and / using 16 bit,
for speed reasons, and tries to use 32 bit shifts when
possible. Mostly this isn't a problem, but when it is,
the slower DIV and MUL routines can be called to use
the full 32 bit.
-----------
DOWN, ENDDOWN
-----------
syntax: DOWN counter,loops
ENDDOWN
par: counter = (var) variable decreased by the loop
loops = (exp) number of times loops should be executed
description: this is a simple FOR loop. the counter will be decreased
to zero, f.e. if you specify 100 for loops, the counter will
go from 99 to 0. the must end with an ENDDOWN.
NOTE: Because the only reason to use DOWN over FOR is
speed, it can only be used with REG variables (i.e. REGLONG).
note: do not use DOWN for loops that need to be done only once
or less.
example: DOWN count,1000000
' fast loop here
ENDDOWN
-----------
ENDPROC
-----------
syntax: ENDPROC returnvalue
par: returnvalue = (exp) result of the PROC
description: marks the end of a procedure and returnes a value to the
whatever called it. Default is zero
example see PROC example 2
-----------
EXIT
-----------
syntax: EXIT returnvalue
par: returnvalue (exp) = returncode for dos
description: exits program at any point in the program.
example: EXIT 5
-----------
FOR, ENDFOR
-----------
syntax: FOR counter,start,end [,step]
ENDFOR
par: counter = (var) the variable that counts the loops
start = (exp) begin value of counter
end = (var or value) value for the loop to end with.
step = a value between 8 and -8 (excluding 0), default 1
description: The loop will be executed as many times as specified by
start and end. meanwhile, the counter is being increased
with every loop. as standard, the counter will be increased
by 1, specifying a step changes this.
example: FOR counter,0,319,2
VOID Move(rast,counter,0)
VOID Draw(rast,counter,255)
ENDFOR
-----------
GOTO
-----------
syntax: GOTO labelname
description: continues the execution of the program within one module
at the place of the label.
example: IF a/20=3
GOTO someplace
ENDIF
' rest of the program
someplace:
-----------
IF, ELSEIF ELSE, ENDIF
-----------
syntax: IF equation
...
[ ELSEIF equation ]
...
[ ELSEIF equation ]
...
[ ELSE ]
...
ENDIF
par: equation (exp) = expression to be equated.
description: the programblock between IF and ENDIF will only be executed
if the expression is TRUE. if it is FALSE, however, it will
be skipped, and an ELSEIF block may be executed if that
equation is TRUE. If an ELSE block is present, it will only be
executed if all the other IF's were FALSE.
example: IF a>1000
WRITE 'hey dude, \d is a little too much!!!\n',a
ELSEIF a<0
WRITE 'what about that?\n'
ELSE
WRITE 'that's more like it!\n'
ENDIF
-----------
INCLUDE
-----------
syntax: INCLUDE filename
description: Includes any binary file into the program. Statement
needs to be part of a STRUCT to be accessed properly.
filename doesn't need quotes.
-----------
JUMPMOUSE
-----------
syntax: JUMPMOUSE label
description: If the leftmousebutton is pressed at the moment this
instruction is executed, execution of the program will be
continued at <label> (only within one module).
-----------
LONG, INT, CHAR
-----------
syntax: LONG value1, value2, ...
INT value1, value1, ...
CHAR value1, value2, ...
par: value = any number like 4, 100, $c00000 etc. additionally,
with CHAR you may use strings, like: CHAR 'hello\0', and with
LONG you may use the adresses of programlabels, like:
LONG vectordata .
description: with these statements you can put data of the appropriate
format into your program. they are only usefull within a
struct.
example: anylabel:
structadr := {anystruct}
STRUCT anystruct
INT 0,10240,512
LONG $c00000,anylabel,4
CHAR 0,25,'anystring\n\0',34,227
ENDSTRUCT
-----------
LOOP, ENDLOOP
-----------
syntax: LOOP
ENDLOOP
description: builds an infinite loop. Must end with ENDLOOP. be sure there
is an exit out of the loop.
example: LOOP
WRITE 'An everlasting loop\n'
ENDLOOP
-----------
MLONG,MINT,MCHAR
-----------
syntax: MLONG address,value
or
value := MLONG(address)
par: address (exp) = any valid memory address, with MLONG and
MINT this needs to be at an equal address.
value (exp) = the value to be 'poked' into, or read from
that memorylocation.
description: Commands similar to PEEK and POKE in basic, poke a longword,
word and byte respectively.
example: MCHAR $40000+a,b-1
-----------
MOUSE, ENDMOUSE
-----------
syntax: MOUSE
ENDMOUSE
description: these make a loop that will be repeated as long as the
left mousebutton is not pushed.
example: MOUSE
VOID movesprites(x,y,3)
VOID playtune()
ENDMOUSE
-----------
WRITE
-----------
syntax: WRITE 'string'
par: 'string' = any string of ascii signs, that may contain
codes with an '\' (see above for a discussion on strings
and codes).
description: prints any string and/or integers etc. to standard output
(normally the cli/shell window); can be used to write to
files by saying: stdout:=Open(...) etc.
example: PROC main()
WRITE 'Hello, World!\n'
ENDPROC
-----------
PROC
-----------
syntax: PROC name(par1, par2, ...)
par: name,par = any normal string like 'dosomething', 'rastport'
these must be defined in this PROC as local variables.
description: designates the beginning of a procedure. procedures should
not be nested, and the end of a procedure should always end
with an ENDPROC statement. Zero upto eight parameters can be
passed to localvars. Arguments for a PROC need to declared
as the first local variables in that module. for more info on
return values (as in example 2) see ENDPROC
Info on the main PROC can be found elsewhere
example 1 : PROC screenflash()
VOID DisplayBeep(0)
ENDPROC
example 2 : result=addition(x,y)
...
PROC addition(value1, value2)
LOCAL value1:LONG, value2:LONG
ENDPROC value1+value2
-----------
REPEAT, UNTIL
-----------
syntax: REPEAT
UNTIL equation
description: The block within REPEAT/UNTIL is repeated as long as the
truth for the equation holds. Thus, this loop will always
be executed atleast once: the UNTIL will jump to the
beginning of the loop if the equation is TRUE.
example: REPEAT
Read(fh,buf,10)
UNTIL {buf}="quit"
-----------
SIZEOF
-----------
syntax: size := SIZEOF(label)
description: SIZEOF returns the size of the STRUCT indicated by the label.
example: see STRUCT
-----------
STRUCT, ENDSTRUCT
-----------
syntax: STRUCT structname
ENDSTRUCT
description: this statemenent adds a struct to your program. it can be
anywhere in the program, since it will be compiled to a
place separate from the code. see description of LONG etc.
for more info's. The statements CHIPSTRUCT and ENDCHIPSTRUCT
function exactly the same way, but will be allocated in
chipmem (handy for copperlists, see CMOVE etc.).
example: a := SIZEOF(newscreen)
STRUCT newscreen
INT 0,0,640,256
LONG 0,0, ... etc.
CHAR 'WindowTitle\0'
ENDSTRUCT
-----------
WHILE, ENDWHILE
-----------
syntax: WHILE equation
par: equation = (exp) comparison to be equated.
description: the loop between WHILE and ENDWHILE is repeated as long as
the equation is TRUE. the program will continue after
ENDWHILE as soon as the equation is false. this loop must
end with ENDWHILE.
example: WHILE a/3+1 > 100
a := a-1
ENDWHILE
------------------------------------------------------------------------
6. FUNCTION OVERVIEW
------------------------------------------------------------------------
The 30 all new functions can be divided into 5 intuition, 3 mouse, 8
Dos/miscelanious programming functions and 14 string functions,
which will be discussed at the end.
------------------------------------------
OpenW() OpenS() CloseW() CloseS() Gadget()
------------------------------------------
wptr:=OpenW(x,y,width,height,IDCMP,wflags,title,screen,sflags,gadgets)
creates a window where wflags are flags for window layout
(like BACKDROP, SIMPLEREFRESH e.d, usually $F) and sflags are
for specifying the type of screen to open on (1=wb,15=custom).
screen must only be valid if sflags=15, else NIL will do.
gadgets may point to a glist structure, which you can easily
create with the Gadget() function, else NIL.
VOID CloseW(wptr)
closes that screen again. only difference from CloseWindow()
is that it accepts NIL-pointers.
sptr:=OpenS(width,height,depth,sflags,title)
opens a custom screen for you. sflags is again mostly 15.
VOID CloseS(sptr)
as CloseW(), now for screens.
glistvar:=Gadget(buffer,glist,id,flags,x,y,width,string)
This function to create a list of gadgets, which can then be put in your
window by giving them as an argument to OpenW(), or afterwards with
intuition functions like AddGlist().
buffer is mostly an ARRAY of atleast 120 bytes to hold all the structures
associated with one gadget, id is any number that may help you remember as
to which gadget was pressed when an IntuiMessage arrives.
flags are: 0=normal gadget, 1=boolean gadget, 3=boolean gadget that is
selected. width is width in pixels, that should be large enough to hold
the string, which will be auto-centered. glist should NIL for the first
gadget, and glistvar for all others, so DEX may link all gadgets.
example for three gadgets:
DEF buf=360:ARRAY, mygadget:LONG, wptr:LONG
mygadgets:=Gadget(buf,NIL,... ) /* the 1st gadget */
VOID Gadget(buf+120,mygadgets,... )
VOID Gadget(buf+240,mygadgets,... ) /* any amount linked 2 1st */
wptr:=OpenW( ...,mygadgets)
See QuickLaunch.Dex for an example of these functions.
-------------------------
Mouse() MouseX() MouseY()
-------------------------
code:=Mouse()
gives you the current state of all 2 or 3 mousebuttons; left=1,
right=2 and middle=4. if for example code=3 then left and right were
pressed together.
x:=MouseX() and y:=MouseY()
enables you to read the mouse coordintes. these are always in highest
resolution (640x512, or even more), so you need to scale them if
your app works in a lower resolution.
------------------------------------------------------------------
And() Or() Not() Out() Inp() KickVersion() Filelenght() SetTopaz()
------------------------------------------------------------------
a:=And(b,c) and a:=Or(b,c) and a:=Not(b)
These work with the usual operations, boolean as well as arithmetical.
VOID Out(filehandle,char) and char:=Inp(filehandle)
Either write or read one single byte to some file or stdout
if char=-1 then an EOF was reached, or an error occured.
bool:=KickVersion(vers)
Will give TRUE if the kickstart in the machine your program is running
on is equal or higher than vers, else FALSE
len:=FileLenght(namestring)
let's you determine the lenght of a file you *may* wish to load, and
also, if it exists (returns -1 upon error/file not found).
VOID SetTopaz(rast,size)
let's you set the font of the rastport to topaz, just to be sure that
some custom systemfont of the user won't trash your window layout.
size is ofcourse 8, 9 or (11)
----------------
String Functions
----------------
Starting at v1.15, DEX has a datatype STRING. This is a string, from
now on called 'Dstring', that maybe modified and changed in size,
as opposed to normal strings, usually called 'Cstrings'. Dstrings are
downward compatible with Cstrings, but not the other way around, so if
an argument request a normal string, it can be either of them.
If a dstring is requested, don't use cstrings.
example on the usage:
DEF s=80:STRING, n:LONG /* s is a dstring with a maxlen of 80 */
VOID ReadStr(stdout,s) /* read input from the console */
n:=Val(s) /* get a number out of it */
... etc.
Note that all 14 functions will handle cases where string tends to
get longer than the maximum lenght correctly;
DEF s=5:STRING
VOID StrAdd(s,'this string is longer than 5 characters',TRUE)
s will contain just 'this '.
bool:=StrCmp(string,string,len)
compares two strings. len must be the number of bytes to compare,
or TRUE if the full lenght is to be compared.
VOID StrCopy(Dstring,string,len)
copies the string into the dstring. if len=TRUE, all will be copied.
VOID StrAdd(Dstring,string,len)
same as StrCopy(), only now the string is concatenated to the end.
len:=StrLen(string)
calculates the lenght of a string
len:=DstrLen(dstring)
returns the lenght of a dstring
max:=StrMax(dstring)
returns the maximum lenght of a dstring
VOID RightStr(dstring,string,n)
fills dstring with the n rightmost characters of a string
VOID MidStr(dstring,string,pos,len)
copies any number of characters (including all if len=TRUE) from
position pos in string to dstring
NOTEZ BIEN: in all string related functions where a position in a
string is used, the first character in a string has position 0,
not 1, as used in languages like BASIC.
value:=Val(string)
finds an integer encoded in ascii out of a string. leading spaces will
be skipped, and also hexadecimal numbers (1234567890ABCDEF) may
be read this way if they are preceded by a '$' sign.
Val() returns -1 if the string did not contain an integer, or
the value was too sizy to fit in a LONG.
foundpos:=InStr(string1,string2,startpos)
searches string1 for the occurence of string2, possibly starting from
another position than 0. returned is the position at which the substring
was found, else -1.
newadr:=TrimStr(string)
returns the *address* of the first character in a string, i.e., after
leading spaces, tabs etc.
VOID UpperStr(dstring) and VOID LowerStr(dstring)
changes the case of a string. may also be used on cstrings if
these are part of your program's data, since the string is modified,
but not changed in size.
ok:=ReadStr(filehandle,dstring)
will read a string (ending in ascii 10) from any file or stdout.
ok contains -1 if an error occurred, or an EOF was reached.
------------------------------------------------------------------------
7. ADVANCED PROGRAMMING AND LANGUAGE INFO'S
------------------------------------------------------------------------
This chapter is about:
- DEX <-> Assembly conventions.
- Code generated by DEX / Optimizing.
- Debugging.
- EBNF overview of DEX syntax.
- DEX as a language concept / The future of DEX / All new EEX compiler.
To use the inline assembly feature without trouble, it's best to
know a few things about TurboDEX code-generation:
Register use: normally you may trash ALL (except A7, ofcourse!)
registers, since none are used to point at vital data during the
course of the program. However, REG variables are stored in D2-D7,
(starting with D7) so if you use these in your DEX code, you may not
trash these. Using REG-variables can also be a fine way to allocate
a register for permanent use in a PROC, for example:
PROC bla()
LOCAL a:REGINT, b:REGLONG
...
ASM
... (use D6(=b), D7(=a) here)
ENDASM
... (use a,b here)
ENDPROC
In this module you could store something permanent in D6/D7, without
the danger of getting them trashed: DEX will preserve these registers
if they need to be used for a (system-)functioncall.
This is the sort of PROC-setup you'd be using to obtain very optimized
code.
D0-D1/A0-A1 may ofcourse be trashed by assembly as well as DEX code.
Functions like WRITE are likely to trash more address-registers than
just these.
Sharing local and global variables:
Each variable has a label that can be used to access DEX-variables
from within the inline assembler, they are build as folows:
ModuleName + 'var' + VariableName
PROC bla()
Example: DEF screen:LONG gives EA: mainvarscreen
LOCAL a:INT blavara
ENDPROC
note that global variables always have ModuleName = 'main'
if you want to have an overview of the each effective address
then compile your program with option -l, also have a look at the
source (the .s file) TurboDEX generates to get the idea.
Accessing of labels and arrays is just as easy:
PROC main() will yield: proglabmain
DEF string=80:ARRAY arraylabstring
start: proglabstart
STRUCT newscreen proglabnewscreen
If your program uses functions from a certain library, the base of
that library can be accessed by LibraryName + 'base' (f.e. dosbase).
Debugging hints:
Apart from debuggingmethods that may be used on any language/compiler,
following are specifically handy with DEX:
- expressions: as these are different from other other languages,
it's very likely mistakes are made: check out the order of
operators/comparison's, problems that may occur when using/comparing
variables of different sizes (LONG/CHAR) etc.
- compile with -l to see if you possibly made errors in declaration
of variables etc.
- check variables that contain pointers, as DEX does no type-checking
- throwing the assembly source through a source-level debugger will
mostly indicate the problem :-) .
BNF overview of the language:
The compiler-builders under the readers may find it clarifying
to see some structural elements formalized (not complete):
<program> ::= { <procedure> }
<procedure> ::= PROC <label> ( <definitionlist> )
{ <defstatement> | <localstatement> }
{ <statementblock }
ENDPROC <exp>
<label> ::= <ident>
<variable> ::= <ident>
<ident> ::= <letter> { <character> }
<character> ::= <letter> | <digit>
<definitionlist> ::= <definition> { , <definition> }
<definition> ::= <variable> : <type> |
<variable> = <integer> : <type> |
<variable> [ <absolute> ] : <type>
<type> ::= CHAR | INT | LONG | REGLONG | REGCHAR | REGINT |
ARRAY | ARRAYCHIP
<integer> ::= <digit> { <digit> } |
$ <hexcharacter> { <hexcharacter> }
% 0 | 1 { 0 | 1 }
<absolute> ::= <integer> | <label> . <integer>
<defstatement> ::= DEF <definitionlist>
<localstatement> ::= LOCAL <definitionlist>
<statementblock> ::= { <statement> | <assignment> }
<exp> ::= <empty> | <expitem> { <operator> <expitem> }
<empty> ::=
<expitem> ::= <integer> | <variable> | '{' <label> '}' | " <ascii's> " |
' <ascii and format characters> '
<operator> ::= + | - | * | / | & | ^ | = | > | < | ?
<assignment> ::= <variable> := { <exp> | <procedurecall> |
<function> | <systemcall> }
<procedurecall> ::= <label> <argumentlist>
<function ::= <keyword> <argumentlist>
<systemcall> ::= <amigasystemcall> <argumentlist>
<argumentlist> ::= () | ( <exp> { , <exp> } )
<statement> ::= { <structuralstatement> | <otherstatement> }
<structuralstatement> ::= <conditionalstatement> | <loopstatement>
<loopstatement> ::= <repeatstatement> | <forstatement> | ...
<repeatstatement> ::= REPEAT <statementblock> UNTIL <exp>
<forstatement> ::= FOR <variable> , <exp> , <integer>
<statementblock> ENDFOR
<conditionalstatement> ::= <ifstatement> | ...
<ifstatement> ::= IF <exp> <statementblock> ENDIF |
IF <exp> <statementblock> <elseblock> ENDIF
<elseblock> ::= { ELSEIF <exp> <statementblock> } |
{ ELSEIF <exp> <statementblock> } ELSE <statementblock>
Some definitions are missing, some things are simplified, and
of all instructions only a few are taken as an example. Just
to give the reader a view on the matter.
DEX as a language concept.
As you might have noticed, DEX is not a complicated language when
it comes to structural and typological elements. It belongs to
a family of two languages sofar, and is derived from the language E,
which inturn has mostly been influenced by Modula2 and some C.
In DEX only the fundamentals of E are left, nearly all advanced features
of the language are not contained in DEX, and DEX has few enhancements,
some as replacement of the proffessional features in E, others just
Amiga-specific add-ons.
E
/
/
/
DEX
Very worthwhile noting here is that a Amiga-specific E compiler
is being developped right now, and most important features of
this all new compiler are:
- about 40x (no joke!) the speed of the Dex compiler. (the compiler
is programmed in assembly)
- doesn't generate assembly source, but executables straight away.
No need of seperate assemblers/linkers.
- Nearly full E language standard i.e. much more powerfull than Dex.
- Reliable compiler operation/code generation, adequate for quick
and stable development of big app's
- includes own (inline) assembler that does up to 40000 lines/minute.
- able to generate 1.2 compatible code, as well as 2.x specific
app's: all 2.0 library modules included.
Import characteristics of E (and to some extend, also DEX and EEX)
as opposed to typical influences such as Modula2 (and some C) are:
1. The Principle of True Inline Assembly:
As no higher programming language can be an 'ideal' programming
language, because only Assembly is, E has the feature of true
inline assembly: assembly instructions are part of the language,
and are equal to E instructions when it comes to using identifiers
etc. Note that DEX has this feature only partly
2. The Principle of System-Integration:
the E language has OS-specific features in the core of the language.
Because of 1 and 2 principle 3 automatically holds:
3. The Principle of Non-Portability:
Languages like DEX and E are designed to be nonportable: Programs
should use machine-specific features (in this case AmigaOs 1.2 and
up) for highest quality app's.
4. The Principle of the Typeless Variables:
E is Typeless. Types, as do exist in DEX, are gathered to one,
as for example in EEX, where all types are LONG.
So, Those portability-lovers among you programmers might just as
well copy this distribution to NIL:
------------------------------------------------------------------------
8. ADDITIONAL INFO'S
------------------------------------------------------------------------
TurboDEX Compiler v1.2 released as Public Domain in september 1992,
update from v1.1 on Fish #625
Together with this distribution you will find A68k, Blink and their docs,
see those for distribution contraints. Thanx go to Charlie Gibbs (A68k)
and The Software Distillery (Blink).
NOTE to future DEX coders: people that use DEX more than occasionally
and get stuck may count on full support by me, the compiler author. Send
your unsolvable problems or requests for hints/tips/tricks/enhancements
to me (i prefer electronic above paper mail).
Needless to say, but: TurboDEX may be copied, crunched and used freely as
long as the full distribution is with it, and no modifications are made
to either the executable, the doc or the supportfiles.. Permission granted
for spreading on (pd) disk series other than that of Fred Fish if costs
are limited to a copy fee, otherwise you need my written permission.
I will personally RemHead() and AbortIO() those 'Pd-Distributors' that sell
this program for more than that.
Donations welcome, but certainly not obligatory.
Support quality PD and Shareware! (i don't necessarily mean this program by that).
the address:
Wouter van Oortmerssen ($#%!)
Levendaal 87
2311 JG Leiden
HOLLAND
Or even better Email:
Wouter@alf.let.uva.nl