Chapter 05 : The Basic Elements of a program & low level examples of branching So far … we have
executed instructions in sequence,
executed a block of instructions if and only if a certain condition was met using an if..elseif..else..endif structure,
repeatedly executed a block of instructions until a condition was met.
labelled a block of instructions with a procedure name, and called for the execution of that block of instructions by using the procedure name as a command to execute that block, at the place where it is called from, in our program.
You may be surprised that all programs are mostly just various combinations of the above.
We have also learned some rudimentary house keeping:
We have told the computer where the program begins and where it ends:
program someProgramName; // The program starts here
begin someProgramName; // program execution starts here, when program is run
end someProgramName; // The program ends here
Notice the semi-colon characters that tell the compiler that we have finished an instruction, (similar to the period at the end of a sentence.)
See:
http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/HelloWorlda2.html#1011925We have also told the computer which (library of) functions it is to recognize.
program testing123;
#include( "stdlib.hhf" ) // include the file stdlib.hhf from the HLA include folder
begin testing123;
stdout.put("Ok. Testing ", 1234567890 ); // just to give some output
end testing123;
Notice the # character. It instructs the compiler here to include the standard library header file. Also notice that a semi-colon, at the end of that instruction to the compiler, is NOT used.
If you wanted to break up a long program file into sections, or store some procedure in a file to be reused later, for example, if you had the declaration/definition of say, procedure myDoIt, saved in a text file in your working directory, or in the HLA include directory, with the name myDoIt.hhf, you could then ask the compiler to include that file like this:
#include ( "myDoIt.hhf" )
You could insert this line in your .hla file in the include section, (like thus):
#include( "stdlib.hhf")
#include ( "myDoIt.hhf" )
Then, at compile time, the HLA compiler/assembler will insert the text of that file into the program(s) then being compiled, just as if you had copied and pasted in that text - at that location, (and then saved your thus modified someName.hla program, before compiling.)
Also, we have told the computer where (and how) to place some data in memory so that it can be accessed where ever appropriate in the program, by name:
program compNamNum;
#include( "stdlib.hhf" )
static
cName: string:= "Dumb Computer"; // the 32 bit address in static
// memory of the 14+ byte constant
// character string in readonly
// memory
cNumb: int32:= 1234567890; // the 32 bit space in static
// memory for an integer
begin compNamNum;
// stdout.put( ... ) is a function in the standard library
// in the ‘stdout’ namespace, ‘nl’ is the HLA for ‘new line’ for all OS’s
stdout.put( "The name of this computer is ", cName, nl );
stdout.put( "The number of this computer is ", cNumb, nl nl );
end compNamNum;
And we have told the computer where (and how) to place some procedures in memory so that they can be accessed by name, where ever appropriate in the program:
program test_showNameNumb;
#include( "stdlib.hhf" )
// Note the syntax for passing a string and number to the following procedure ...
// (A procedure must be declared/defined before it can be called by a program.)
// 1st variable passed is a string; 2nd is an int32; NOTE! ‘;’ separator
procedure printout( cNam: string; cNum: int32 );
begin printout;
stdout.put( "The name.number of this computer is ", cNam, ".", cNum, nl );
end printout;
begin test_showNameNumb;
// Note that 1st passed is a constant string, 2nd passed is a constant int
// Note the ‘,’ separator used between parameters
// when procedures are called ...
printout( "1_Dumb_Computer", 123456789 );
printout( "2_Dumb_Computer", 234567890 );
printout( "3_Dumb_Computer", 345678901 );
end test_showNameNumb;
For an assignment, create a suitable folder like c:\hla\projects\chapt05_myWork … Then, in it:
Using your text editor, create your version, i.e. the file basic_shell2.hla, having just the 3 line (i.e. the bare bones) shell of an HLA program. Then compile it and run it. Is there any output? Why or why not?
(a) Create the file compNamNum2.hla to reflect your version of an HLA program that outputs the Name and the Number of some computer of your imagination. Compile and run it. (b) Now leave off some (for example, the last) closing semi-colon in your program and try compiling it now. Note the error message(s) and see if you can follow them to correct the error(s). (c) Make other errors, preferably, one at a time, and see if you can follow the compiler messages to fix these syntax errors.
Create the file test_showNameNumb2.hla where you will have the program ask for a name to be input and then a number. Then display what was input and ask if they were input correctly. If correct, quit with a message saying that they were ok. If data was not input correctly, then ask for the data to be input again. You may input and test individually … or input both then check if both ok. You may use something like this: static nameStr: = str.strvar(256); // so you have enough space to hold nameStr
Modify your version of the above, to make the file showNameNumb3.hla using another repeat .. until(..) loop to ask 3 times for a name and number, while still, as in the above, checking each time if the data that was input was valid. Hint: static counter: int32:= 0; // 0 initial value before entering loop. Then inside the loop inc(counter); or add( 1, counter); Then at the end of the loop, test if the counter has reached 3 yet. ( Or you can use a register like eax for your counter. By the way, there is an ebx, an ecx, and an edx register also that you can use. These all are 32 bit registers. There are others! ALSO, EAX has an AX part, the lower 16 bits. AX, has an AH and AL part. AH is the top 8 bits of AX. AL is the bottom 8 bits of AX. The same sort of thing happens for EBX, ECX, and EDX. NOTE: When adding or comparing two values, or moving a value to/from a register or to/from a variable( i.e. a memory location), they must each have the same bit size; for example, they must both be 8 bits, <a byte>, 16 bits <a word>, or 32 bits, <a dword>. )
For (easy) bonus, how would you make your repeat .. until structure to loop forever? (Hint: There are several possible ways, that all really boil down to the same thing.) How might one exit from this forever loop? There are simpler ways to code for a forever loop. Try forever ... endfor; NOTE! If you want to find some help on how to code something fast, just Google it. For example when I just now googled HLA forever, this came up at the top:
http://safari.oreilly.com/1593270658/ns1593270658-CHP-15-SECT-3O'Reilly - Safari Books Online - 1593270658 - Write Great Code ...
The following two code fragments demonstrate an HLA forever..endfor loop (along with a breakif) and the corresponding "pure" assembly code: ...
forever
// << Code to execute (at least once)
// prior to the termination test >>
breakif( termination_expression );
// << Code to execute after the loop-termination test >>
endfor;
Converting a forever..endfor loop into pure assembly language is a trivial matter. All you need is a single jmp instruction that can transfer control from the bottom of the loop back to the top of the loop. The implementation of the break statement is just as trivial, it's just a jump (or conditional jump) to the first statement following the loop. The following two code fragments demonstrate an HLA forever..endfor loop (along with a break..if) and the corresponding "pure" assembly code:
// High-level forever statement in HLA:
forever
stdout.put("Enter an unsigned integer less than or equal to five: ");
stdin.get( u );
breakif( u <= 5 );
stdout.put("Error: the value must be in range zero to five." nl);
endfor;
// Low-level coding of the forever loop in HLA:
foreverLabel:
stdout.put("Enter an unsigned integer less than five: ");
stdin.get( u );
cmp( u, 5 ); // i.e. compare the value of u with 5
jbe endForeverLabel; // jump to the bottom label if u <= 5
stdout.put("Error: the value must be in range zero to five" nl);
jmp foreverLabel; // jump to the top label
endForeverLabel:
Of course, you can also rotate this code to create a slightly more efficient version:
// Low-level coding of the forever loop in HLA using code rotation:
jmp foreverEnter;
foreverLabel:
stdout.put("Error: the value must be in range zero to five." nl);
foreverEnter:
stdout.put("Enter an unsigned integer less than five: ");
stdin.get( u );
cmp( u, 5 );
ja foreverLabel; // jump to top label if u > 5
And yes … for more than you may ever need to know about HLA ... try this link:
http://webster.cs.ucr.edu/And in particular, to see MUCH MORE about loops follow these links at:
http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/HelloWorlda3.htmlhttp://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/LowLevelControlStructsa4.htmlA test program, containing the code snippet from the previous page (slightly enhanced) follows:
program lowlevel2; // my test program (of the code snippet-further optimized/commented)
#include( "stdlib.hhf" )
static
u: uns32;
begin lowlevel2;
// Low-level coding of the forever loop in HLA using code rotation:
jmp foreverEnter;
foreverLabel:
stdout.puts("Error: the value must be in the range 0..5" nl);
foreverEnter:
stdout.puts("Enter an unsigned integer less than or equal to five: ");
stdin.getu32(); // returns uns32 number in eax register
// mov( eax, u );
// cmp( u, 5 );
cmp( eax, 5 );
ja foreverLabel; // jump to top label if u > 5
mov( eax, u ); // since good data now ...
stdout.put( nl "Ok ... good data ... you entered: ", u, nl );
end lowlevel2;