Control Structures
IF {condition}
{program code}
[ELSE IF {condition}]
[ELSE]
{program code}
END [IF]
WHILE {condition}
[BREAK]
[LOOP]
{program code}
END [WHILE]
FOR {long variable}={expression} to {expression} [step {expression}]
[BREAK]
[LOOP]
{program code}
NEXT
SWITCH {expression}
CASE {constant}
[BREAK]
[DEFAULT]
END [SWITCH]
BLOCK {variable} [WITH {variable}]
[BREAK]
[LOOP]
{program code}
END [BLOCK]
TEXT {variable}
{text}
[<<variable>>]
END [TEXT]
ON ERROR [RETURN | DO {procedure name}]
DO {procedure name}
PROC {procedure name}
[EXIT]
END [PROC]
MACRO method() | method('some character constant')
RETURN [{expression}]
Note: [] means optional
{condition}- calculates to either _TRUE or _FALSE. It can be composed of any combination
of the following.
| Type |
Example |
| Logical constant |
_TRUE, _FALSE |
| Comparison |
a>c |
| Logical operation |
a>c and not c<=d |
| Expression |
a-b*myapp.total > 500 |
| Conditions |
<, <=, >, >=, <>, = |
| Logicals |
and, or, not |
{expression}- any combination of variables, constants and operators. Precedence
is from left to right unless a set of "( )" is used. Anything in the round brackets
is executed first.
| Type |
Operators |
Examples |
| Numerical |
+, -, *, / |
a+(b*c)+10 |
| Character |
+ |
myapp.hello + "This is the last day" |
| Logical |
and, or, not |
is_true or _TRUE |
| Date |
+, - |
mdate + 20 |
| Class, Object, Index and Table variables cannot use operators.
Only the assignment (=) can be used and no conversions are done. (Object=Object,
Class=Class, and Index=Index only Note: The right side of the expression
can be a function that returns a Class, Index etc) |
{constant}- Any numeric, or character constant e.g. 5, 10.87, 'A', 'string'
{long variable}- In the case of the FOR command above, {variable} is always
a Long (4 byte) integer.
{variable}- Any of the variable types including any type of Object.
{vector variable}- Any variable type that has multiple members like a[5], b[2,3]
Note: 1 to 2 dimensions only.
{program code}- Any combination of "Program Structures" and the assignment command
("="). e.g. data=15 + i*b
{text}- Any text data but the end is defined as [{white space}] END (case doesn't
matter) on a new line.
{method}- A program associated with an Object, defined in a Class. e.g. myclass.mymethod()
: the round brackets are required to specify a method.
{<< variable >>}- Text or numbers (converted to char automatically) can be inserted
into the text by using a << variable >> in the text structure.
4.1 IF ELSE END ELSE IF
- The condition in the "If" statement is always parsed from left
to right except where round brackets force a change. Anything enclosed in
round brackets is executed first.
- The condition can be made up of any arbitrary group of expressions joined
(optionally) by "and", "or" and "not".
- If all conditions are joined by "and" then the first executed
false expression will jump to "else" if it exists or "end if"
at execution time.
- If all conditions are joined by "or" then the first executed true
expression will fall through to the first statement after the "If"
statement.
- If "and" and "or" are both used in a "condition"
then all the "expressions" would have to be executed before determining
whether the "condition" was "true" or "false".
- The optimization sounds complicated but in practise the "If" condition
will be handled correctly in all cases and some code will run much faster
because of it. (C compilers do this optimization.)
- The "Else If" clause can be used to specify a more general purpose
"Switch" structure. The "Else If" structure will check
all conditions from the top down until it matches _TRUE in an expression.
It will then execute the following code and jump to the "End If"
line when finished.
4.2 WHILE BREAK LOOP END
- The optional LOOP command of the WHILE command is used to go directly to
the test condition (on the first line of the "while") from anywhere
in the WHILE.
- There can be any number of LOOP commands in a single WHILE structure.
- The optional BREAK command is used to go directly to the first statement
after the END command.
- There can be any number of BREAK commands inside a single WHILE structure.
- The condition is optimized for "and" and "or" connections
of expressions. (see IF statement above)
4.3 FOR BREAK LOOP NEXT
- The optional BREAK and LOOP commands act in exactly the same way as they
do with the WHILE structure above.
- The looping variable is always a 4 byte long variable. If it exists, then
it is changed to a "long" otherwise it is created.
// Example
long a[100] // create 100 elements and initialize to 0
b=0
for i=1 to a.length()
b=b+a[i] // add all 100 numbers of "a" vector
next
4.4 SWITCH, CASE, BREAK, DEFAULT
END
- This structure is the same as used in C except for the following differences.
- There is no flow through for consecutive CASE statements unless no code
is included in the CASE statement.
- The {constant} for each CASE statement can also be a string constant.
Valid constants are LONG, VARCHAR or CHAR.
- The "Switch" expression is executed and the result is tested against
each "Case" constant until a match is made or no "Case"
statements remain. If a match occurs then that code is executed and then execution
proceeds after the "End Switch" statement.
- The "Default" code is executed if no other "Case" constant
has been matched unless that section doesn't exist.
- This command is opminized for speed, so large "Switch" commands
will be more efficient than the equivalent "Else If" structure.
In an IF/ELSE IF structure you can use any valid expression for each "CASE"
unlike the constants used by the SWITCH command.
4.5 BLOCK BREAK LOOP END
- This structure is used to loop through a vector variable, variable length
text by line, char by char for CHAR data, a fixed number of loops or multi-row
objects automatically.
- The code is loaded internally and the vector variable or table objects
are changed automatically for each record or element.
- This structure is used to speed up some repetitive tasks.
- When a table is traversed, it automatically buffers the table listed using
it's defined cluster sizes. This makes looking through even VERY large tables
very fast.
- Looping is performed inside a single C function so operations like transforming
a matrix of pixel data to some other matrix is very fast.
- The block structure always loops to the length of the table or variable
listed unless the "Loop" or "Break" commands are used.
These can be used to skip or prematurely exit the looping structure.
// Examples
class myclass {
char name(30)
char custn(6)
number balance(10,2)
}xcust(this, 100), cust(myclass, 1000) // define a class and create 2 tables
// this and myclass are the same class in the above line
=cust.import('test.txt','text') // import test data : cust is buffered in 1000's of records but can be any size
block cust // buffer and loop through cust
if cust.state='ND' // each time through the block structure the default object is filled with each record of cust
xcust.append(cust) // append all matching fields from default object of cust to xcust if state='ND' for current record
endif
endb
total=0.00 // create a double float variable : double constant is created if a decimal is used otherwise a 4 byte integer would be created
block xcust // buffer and loop through xcust
? xcust.name // display name field
total=total+xcust.balance // sum total of balance field for all records from state='ND'
endb
long a[2,5]
block a with g
? g // this would display 10 numbers in row wise order : left to right
endb
long a[2,3],b
b=0
block a with g
b=b+g // this puts the sum of all elements of a in b
endb
4.6 TEXT <<variable>>
END
- This command can be used to enter multi-line text into a variable.
- It can be used to initialize a Vector, Object or multi-row Object like a
Table, List, Stack etc
- I can be used to send multi-line text to a method to generate an inline
Macro. (This is any function that can return 1 or more lines of source code
that would be compiled at this point in the program as if it had been typed
there.)
- Variables can be specified within the body of the text so that their values
are inserted at those points in the text.
- This variable insertion could be used to create program Macro, SQL multi-line
statements, HTML code etc.
- The kind of operation this command does would depend on the kind of variable
after the Text command and whether the Macro keyword was used.
- Other keywords might be added to this command.
4.7 ON ERROR DO
- This command is used catch runtime errors.
- When a runtime error occurs, the program execution halts and an "On
Error" routine is sought on the current program stack level.
- If a routine is not found, then the program stack is popped until an "On
Error" routine is found or no more levels are left.
- Note: The program stack is used to "Return" from Method calls.
If a Method A calls B and B calls C, then the program stack would be on level
3 with 2 entries on the stack.
- If no routine is found, then an error message is put on the console and
that program is terminated.
- Note: Many programs can run at the same time and errors from one program
don't affect other running programs.
- If a "On Error" routine is found, then execution is continued
at the start of that routine.
- Information on the error number and error message can be had by looking
in the object this.event, to decide what to do with the error.
- The error can be generated in the software for testing or other purposes
by changing this property.
- The "On Error" routine would normally end with a "Return"
command which would terminate the method that encountered the error (not necessarily
the whole running event).
- It could also be terminated by an "Exit" command (the same command
used to exit a procedure) which would continue executing on the command directly
after the command that caused the error.
- All "On Error Do <<proc name>>" code is stored in
a procedure defined like any other procedure.
- More than one "On Error" rountine can be used in a single Method.
- As the execution passes an "On Error" routine, when no error
has occured, that routine is set to the current "On Error" routine
on that program stack level.
4.8 DO
- This command is used to execute method procedures.
- A procedure can be thought of as a kind of function/method and the Do command
is used to execute it.
- The following are the differences between a function/method and a procedure.
- A procedure is defined and called only from the current method. A procedure
canot be directly called from other methods.
- No parameter can be passed to a procedure.
- All the execution environment is available to code put in the procedure
which is not the case with a method. A method can only access data passed
through it's calling parameters.
- A method can have it's own local variables that the calling program doesn't
have access to. A procedure can define new variables but they are added to
the methods variable table just as if the code was in the calling method (which
in fact it is).
- Calling a function requires overhead for mapping the passed parameters and
pushing some parameters on the stack to give the called method it's own variables
and space.
- The overhead of calling a procedure is just that of a simple goto.
- A procedure can be used to just organize chucks of a method or it can be
used so that the same code doesn't have to be typed in multiple times. A procedure
can also be used when execution time is paramount. It is almost like having
code inserted inline at compile time.
4.9 PROC EXIT END
- The PROC/END pair are used to define a procedure in a method.
- The name of the procedure is defined just after the PROC command.
- These structures are normally defined at the end of the method and they
can be called with the DO command from the main method code or in any other
procedure defined in the method.
- A procedure can be called by the ON ERROR DO {proc name} command to alter
the execution of the code if a runtime error occurs.
- The EXIT command returns to the line after the line that called the procedure
or after the command that caused the runtime error if it was called by the
ON ERROR DO command.
- A RETURN | {expression} can also be executed from within a procedure which
would return from the whole method. An optional return value could be included.
4.10 MACRO
- The MACRO command allows any user created HAL method to be executed optionally
passing a character constant, that would return program source code.
- This source code would be compiled as if it had been typed at this location
in the program.
- Any number of MACRO commands can be used in a method and the MACRO method
called can have any number of MACROs in it's code.
- This command can be used to create code at compile time by using the power
of HAL's programming language.
- Any features of the language could be used to create this text.
- This facility would occur at compile time and no run time performance penalty
would occur from it's use.
4.11 RETURN
- The "Expression" after the "Return" command would be
executed and returned to the calling method. This can be an atomic variable
(Int, Long, Char etc) or it can be an Object or multi-row Object (Table, List,
Stack etc).
4.12 SQL
- SQL is implimented in HAL as if was a Macro (in the HAL or Lisp sense of
a Macro).
- The SQL statement can be multi-line starting with the SQL command and ending
with the END command.
- The SQL statement is translated into standard HAL code which is then compiled
at the location in the program where the SQL command was placed.
- This method of implimenting SQL is not only very fast but the underlying
HAL language can be used interchangeably with SQL statements.
- Triggers can easily be added to any Table by Inheriting the Table Class
and putting in your own Insert, Delete and Update code.
- Unlike most implimentations of SQL, compiling of SQL statements is done
at compile time with essentially no Select overhead.
- A program that makes 10,000 Select command calls will not be very fast in
most SQL implimentations but it just becomes 10,000 finds in HAL which takes
only a fraction of a second.
- Looking through large sets of rows is equally fast because the Block command
is used for looking through tables and large buffers of records are automatically
used.
- This is not a full implimentation of SQL (for now) but HAL code can be used
directly on the tables to impliment anything that is not already there.
4.13 CLASS APP INHERIT
- This structure is used to create a Class and optionally an App or Objects
based on this class.
- By putting the APP keyword after the class name, an application is created
that consists of a Class and Object with the same Class name and a Registry
file is also created for the application.
- The INHERIT keyword is used to inherit Properties and Methods from previously
defined Classes.
- A class can only inherit from one parent class but that class can also inherit
from it's parent class etc.
- This structure is used to define the data objects that this class contains.
A Class can be defined without any Properties however.
- A list of methods can be included in this structure (optionally with each's
source code) or the methods can be added to this Class later.
- Changes to the Properties of a Class automatically propigate to all Classes
that inherit this Class. Any Objects that are created using this Class or
any that were created with Classes that inherit this Class are also changed.
- All Properties that are inherited automatically get a "_" prepended
to their name. These Properties can be refured to directly by using the "_"
in front of the Property name or they can be accessed with just their name
if no other Property was defined with the same name in the current Class.
- The last line of this structure can optionally create objects that use this
Class. These can include Tables, Lists, Stacks, Objects etc.
4.14 REGISTER END
- The register structure was designed so that applications could be moved
around to different places on different machines without changing the source
code.
- It was also designed to insulate Object and Class names in one application
from other applications while still giving the ability to comunicate on an
intimate level.
- Each application has a file that "registers" the names of Objects
and Classes.
- This means that an object that might exist in the Object hierarchy at hal:my_obj:xyz:hello
could be registered as just "mine". In any method executed by an
object belonging to the application HAL (in this example) this object could
be refered to as simply "mine". The register line would look like
mine=hal:my_obj:xyz:hello or mine=hal:my_obj:xyz:hello object
- You could automatically register this object with the name "hello"
by using the keyword "REGISTER" when creating the object. ??????
- Classes can also be added to the registery of an application by using the
REGISTER keyword on the CLASS definition line.
- Objects and Classes are both put in the same registry but are separate so
there is no confussion with a Class and Object having the same register name.
- Any Class or Object that is defined with the same register name as one that
already exists replaces the existing entry with it's information.
- Any access to Classes or Objects outside the current application must be
defined in the registry of the current application. e.g. if HAL and HAL2 are
apps
- and object a:b:c of HAL is to be accessed by HAL2 then a command like REGISTER
hal_c=hal:a:b:c END must be executed in a HAL2 method.
- Once an Object or Class has been defined in the registry, any Objects or
Classes can be refered to relatively by using the registry name and the additional
child name from there.
- In the above example, if another Object exists under hal:a:b:c like hal:a:b:c:d
then just hal_c:d would access this object from the HAL2 application.
4.15 ? ?? CURSOR CLEAR SCREEN
- This set of 5 commands are used to display data on the programmers console.
The programmers console is not the normal location for output from HAL programs
but it can be handy for debugging at times.
- The ?? {expression} displays the result of the expression followed by a
single space. No CRLF is issued. The data is displayed at the current cursor
location on the current programmer screen.
- The ? {expression} displays the expression as the ?? does except the it
adds a CRLF after displaying the expression.
- The CURSOR y,x sets the cursor at a specific spot on the screen but only
if the screen is fixed and not relative. (Multiple screens can be defined
and they can be relative or fixed)
- The CLEAR command clears the screen regardless if it is relative or fixed.
- The SCREEN command is used to change the current screen to display the data
on. This command can also redirect output from the ? and ?? commands into
a VARCHAR string.
- Only the ? and ?? commands can display data on the programmer screens.
- The normal interface for data in HAL is through a web server using HTML.