Tutorial
"Adde parvum parvo magnus
acervus erit."
Ovidius
In this section, we present HILMAS language in a more structured manner, explaining its elements ordered by some important arguments. A more complete but synthetic explanation of every instruction in HILMAS is in "Quick Reference".
Defining Variables.
In HILMAS declaring variables is mandatory: every used variable must be defined after last executable line of code (that may be a ENDPROG or a RETURN if it is a Subroutine), after the pseudo-instruction '/INCLUDE HILMAS VAR' and before the last line of source code, that is END.
Every declared variable is visible (that is, usable) from any point of the source code, even from internal subroutines, if there are. Is not possible to change the 'scope' of a variable: all are in COMMON with every routine of the source file where are defined. If you want 'mask' the name and the usability of variables used by a routine, you must define this routine (and its variables) in a divided source file defined as a 'External Subroutine'.
Variables are basically of two types: numeric and string; numeric variables are compound by some sub-types: integer (short and long, that is, in Assembler terms, Half and Full), float (with floating decimal point), packed and zoned.
Defining variables is the only thing of HILMAS that must be defined in native Assembler: that is every variable must be written as though it were a true Assembler program.
Therefore variables must follow these rules:
- variable-name written from column 1 (mandatory)
- name-length of 8 characters maximum (or more, if use HLASM as Assembler compiler)
- 'DS' or 'DC' after variable name: 'DS' is Define Space (i.e. the variable is not initialized) and 'DC' is Define Constant (the variable is initialized with a value, but can be changed by program)
- type of variable (with length, if variable is a string)
- initializing value between quotes (') if is a 'DC' definition
The general outline is:
<var-name> DS <type>[Lnn]
<var-name> DC <type>[Lnn]'value'
L is followed by a number 'nn' that is the length in bytesTypes of variables are:
F integer (Full, 4 bytes) H integer (Half, 2 bytes) Z zoned, that is a integer number with sign, whose length (mandatory) is equal to number of digits P packed, that is a integer number with sign, whose length (mandatory) is equal to half the number of digits D float, that is a fractional number with sign (8 bytes) C character, that is a string with a mandatory length from 1 to 255 bytes A address, that is a 4 bytes pointer to memory position (to a variable, to a program, etc.) Some examples:
NUM1 DS F an integer not initialized ITERAT DC H'1' a short integer initialized to 1 LINE DS CL80 a string 80 characters long not initialized TITLE DC CL10' Title ' a string initialized ADR1 DS A a pointer variable
Using Variables and Expressions.
To assign a value to a variable you must use MOVE instruction, an instruction similar to MOVE in COBOL:
MOVE A,TO,B
MOVE -34,TO,NUM
MOVE 'STRING',TO,SThe value in the first operand (the value contained in A, in first example) is placed in the third operand (variable B)
The first operator of MOVE must be a variable or a constant; it cannot be an expression.
The third operator must be a variable; the variable types must be the same; 'TO' is an auto explaining fixed word.To reckon a numerical expression use LET instruction:
LET NUM1,NUM1,*,2,-,6
LET FR,(X,+,Y),/,(A,-,B)The First operator is the variable that will contain the result.
In another languages (Basic or C) are equivalent to:NUM1 = NUM1 * 2 - 6
FR = (X + Y) / (A - B)Is nearly the same thing in HILMAS: you must use the commas correctly an don't leave internal blanks.
There is not a true array definition and manipulation in HILMAS, but there is an instruction that permit a 'simulation'. For example to extract a value from a mono-dimensional array::
MOVARRAY TAB,(INDEX),TO,NUM
where TAB is a variable containing a lot of values of the same type of NUM; the value in position INDEX is put in variable NUM; in C language is the same as:
NUM = TAB[INDEX]
The Index is from 0, that is the first element of TAB; TAB is declared, for example, as:
TAB DS 20F
and in this case INDEX is a integer variable (or constant) ranging from 0 to 19 and NUM must be a Fullword integer.To assign a value to an array element use:
MOVARRAY TAB,(INDEX),FROM,NUM
No control is done (in compilation or run time) over the correctness of the range of index.
If you want to use a string array, the string element must be of fixed length and must be specified in the instruction:MOVARRAY TABSTR,(N1),TO,STR,SLEN=8
TABSTR DS 30CL8
If you use a two (or three) dimension array, must specify also the length of the first (and second) dimension of the array.
MOVARRAY TABSTR2,(N1,N2),TO,STR,SLEN=8,D1=4
Input / Output Processing.
The basic and most used instruction to display values is SAY:
SAY 'The value of A is: ',A,' and string S is: ',(S,10)
where the values separated by commas can be string constants or variables of any type.
You can limit the length of a displayed string variable (in this example, only the first 10 characters of the string S are displayed)
The 3270 video terminal display is treated in line mode (even in CICS environment) that is SAY is an I/O instruction that display only a line (and not a screen).
Note: this powerful instruction is truly environment-independent, that is the same SAYs work without modification in TSO or CMS as in CICS environment (and even in batch). Can you do this with a COBOL program?SAY can be used also in batch: output is in a conventional 'standard output' (SYSOUT in MVS and SYSLST in VSE); SAY can be used to compose a string to print in a second time (i.e. the output can be a memory variable of the program) or can be used to write directly on a file.
To accept values from terminal keyboard use, for example
INPUT STRING1,STRING2,STRING3
in which, if user write the words:
MIKY MOUSE
the word MIKY is put in variable STRING1, the word MOUSE is put in variable STRING2 and STRING3 is left empty (that is filled with blanks). Also INPUT instruction is environment independent: you can use it in batch to read from a 'standard input' (SYSIN in MVS).You can use every file in HILMAS, VSAM or sequential. Use FOPEN and FCLOSE instruction to open and close a file and use FREAD and FWRITE to read and write on it.
In a VSAM file you can also browse a bunch of records (with FSTARTBR), or insert, update and delete a single record (with FWRITE, FREWRITE and FDELETE).Controlling the Flow within a Program.
Using Conditional Instructions
There are two types of conditional instructions.
IF / THEN / ELSE can direct the execution to one of two choices.
SELECT / WHEN / OTHERW / ENDSEL can direct the execution to one of many choices.
Using Looping Instructions
There are two types of looping instructions, repetitive loops and conditional loops. Repetitive loops allow you to repeat instructions a certain number of times, and conditional loops use a condition to control repeating.
Repetitive loop is FOR / NEXT instruction, while conditional loop are
WHILE / ENDWHILE instruction and REPEAT / UNTIL instruction.Use of these instructions are similar to corresponding instructions in major structured languages as Pascal, C or REXX; see Quick Reference for details.
And GO TO instruction?
There isn't a GOTO instruction in Hilmas; if your program follows directives of structured programming you don't need any GOTO instruction. But if you want to program "quick and dirty" (and you aren't afraid of "spaghetti programming") you can use native assembler instruction B (Branch) to pass control unconditionally to a specified label; for example:
B MYJUMP . . . . . . . MYJUMP CONTINUEWriting Subroutines.
A subroutine is a series of instructions that an HILMAS program invokes to perform a specific task.
Subroutines may be internal, in the same source file and following the main, or external and therefore in another source file, compiled separately and written in a language that can be different by HILMAS.
The instruction that invokes the internal subroutine is the GOSUB instruction. The GOSUB instruction may be used several times in a program to invoke the same subroutine
Internal subroutines are started by SUBDEF instruction; when the subroutine ends, it can return control to the instruction that directly follows the subroutine call. The instruction that control is the ENDSUB instruction (that terminate the coding of subroutine) or SUBEXIT (that leave the subroutine first its natural end). All variables are visible from an internal subroutine, (there is not variable-scope in HILMAS) and so there isn't a passing parameter problem in this type of subroutine.The instruction that invokes the external subroutine is the CALL instruction.
If you write an external subroutine in HILMAS, it hasn't PROGRAM and ENDPROG instructions, it start with ROUTINE instruction and end with RETURN. The only variables of the calling program that are visible to a routine are the variables passed at calling time: these must be defined in ROUTINE instruction and must correspond in type, order and length to variables in calling program. For any other thing, an external routine is equal to a main program that can have itself any number of internal or external routine.
An external routine written in HILMAS can be called by program written in any language, provided that standard IBM calling convention is used.
Using Functions.
We call Function every HILMAS instruction that is implemented as function in other languages as Pascal, C, or REXX; really there is not any change in HILMAS syntax.
Usually, the first parameter of a so-called HILMAS function is the output variable, and others are input variables.There are numerous functions in HILMAS, that we can divide in:
- string manipulation (LENGTH, SUBSTR, OVERLAY, INSERT, etc.)
- numeric function (INC, DEC, INT, etc.)
- string and number conversion (EDIT2NUM, NUM2EDIT, VAR2HEX, etc.)
- environment function, as RANDOM or SLEEP
PARSE, a powerful instruction.
We have borrowed from REXX language the PARSE instruction whose we have implemented a subset. With this instruction you can easily divide a parameter line in its components or a record in its fields, if parameters or fields are divided by blanks (or commas). In other words, with Parse you can divide an input line in a NOT positional manner, suitable for an input typed by a user on a terminal.
For example, if user type on a terminal, as an answer of a INPUT instruction:
Knowledge is powerand this words are in a variable named STRING, with instruction:
PARSE STRING,WITH,WORD1,WORD2,WORD3variables are assigned in this way:
WORD1 = 'Knowledge'
WORD2 = 'is'
WORD3 = 'power'
indipendently of how many blanks are typed between a word and another.
(INPUT istruction has an embedded Parse instruction to divide words in the specified variables).