Developers Heaven Forum

Desktop Programming => HLA => Topic started by: David on May 17, 2013, 10:18:33 AM

Title: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 10:18:33 AM
BEGINNING COMPUTER PROGRAMMING

 
(Using a Try it and See it approach)

                                                                                                                         
(AND ... a Computer Student's/Teacher's DREAM Introductory Computer Language - HLA)


Update: Update: please see this next link:

http://developers-heaven.net/forum/index.php/topic,2636.0.html


FREE homework help NOW available ...

You can contact me via:
http://sites.google.com/site/andeveryeyeshallseehim/home/he-comes
http://developers-heaven.net/forum/index.php/topic,2587.0.html


You may also want to see ...

http://developers-heaven.net/forum/index.php?topic=46.0

BEGINNING COMPUTER PROGRAMMING (using HLA and Python 3.1 and C++) 


http://developers-heaven.net/forum/index.php?topic=2599.0

Six Fast Steps to Programming in High Level Assembly (HLA)

 
 
Introduction:

 

To facilitate the solid insights provided in learning about computing by some exposure to Assembly Language, but also to provide a friendly and facile start for new programmers, HLA provides all the facility and power of Assembly Language, but with a user friendly syntax, yet offers many of the elegant structures of an HLL (High Level Language) like Pascal or C or even the OOP of a language like C++.  And so, going on to C, or C++, or any other modern HLL, will be more readily enabled, and with some real appreciation of what’s going on under the hood and inside the machine.

 

The author has successfully taught Computer Programming at a Canadian grade 7/8 Junior High and 9 to 12 High School level when PCs first became available using varied approaches, including using a personally authored simulated SIMPLE SIMON compiler running on a PC.   But his final approach, after which this course is being patterned, was the most fun, and also the most successful, for both students ... and teacher.

 

Please enjoy and profit from your work. Don't be afraid to make changes and see what happens.  Now dig in ... You may be surprised how much you will learn.

 

Shalom shalom,

David W. Zavitz

Toronto, Ontario, CANADA

dwzavitz@gmail.com

 
For arrangements to use this text beyond individual personal use, please contact the author at the above e-mail.

© (C) 2007-08-17

 

Acknowledgements:

This course and text would not be possible without the very gifted insights, teaching experiences, and programming skills of Randall Hyde,

http://en.wikipedia.org/wiki/Randall_Hyde

the Author, Creator, and so far, the Sustainer of HLA. I also would like to acknowledge the tremendous encouragement given by my youngest son Matthew, who's recent Engineering need to know a little C++, and then Assembly ... provided the incentive for a little more then that, from dad, (which led to HLA and now this attempt to benefit beginning computer students in general.)  Also, I would like to thank my students at Scarborough Christian High School, who besides being very promising young ladies and gentlemen, provided exemplary feedback as we went along into some not yet fully charted territory.

 

 
Table of Contents:

Chapter 01: The Computer prints a message
Chapter 02: The Computer gets some input
Chapter 03: The Computer adds some numbers
Chapter 04: The Computer repeats a procedure
Chapter 05: The Basic Elements of computer programming … and low level example(s)
Chapter 06: The Computer rolls the dice … a first simulation
Chapter 07: First Memory Flow Lab
Chapter 08: Memory Flow Lab2
Chapter 09: Memory Flow Lab3
Chapter 10: HLA Data Types
Chapter 11: The Computer does some Algebra with real numbers ... and Input Data Validation
Chapter 12: Pointers, Strings, your own Types, Records, Arrays, and dynamic things on the fly!
Chapter 13: The Computer files its Records
Chapter 14: The Computer reads its Files
Chapter 15: The Computer updates (edits, deletes, sorts, chops-duplicates-in) its Files
Chapter 16: The Computer … vast OS’s … and the garbage collects?  (Operating Systems ... what is DOS?)
Chapter 17: The Computer delivers daily Manna ... (gui Canadien ... eh?)
Chapter 18: OOP ... goes the computer?
Chapter 19: OOP 2
Chapter 20: Shaping Moving OOP with HLA   ... a CLASS ACT ! (revised 2013-05-24)
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 10:23:36 AM
Chapter 01: The Computer prints a message



Teacher ... set's up each computer, (the presumption here is that you are using a Windows OS, but only minor changes may be needed to adapt this text to Linux, Mac OSX, FreeBSD, or in the future, when HLA is available for them, other OS's also), and ...

 
installs and configures HLA files in the directory c:\hla\

 
For finding everything regarding HLA:

http://216.92.238.133/Webster/

 
If you are a first-time HLA user, the best thing to do is download and run the HLA setup program hlasetup.exe. This version replaces both the HLA and freeHLA (fhla) versions from previous releases.

http://216.92.238.133/Webster/HighLevelAsm/HLADoc/HLARef/HLARef_pdf/03_InstallingHLA.pdf

 
Teacher … also, as needed, to show how to use Windows, some simple OS commands, from the command line like cd to a directory, or md or dir i.e. showing the contents of the current directory.  And also, as needed, to discuss folders, and folders inside folders, and the path to a file in some folder (i.e. the tree structure in organizing files on the disk.)

 
Student ... Create and go to the working directory c:\hla\projects  Note the use of rem indicates a remark or comment. No need for student to enter the rem or what comes after this here:

 
click start  (click on the Circle Shaped Icon in the Lower Left Corner of a Windows 7 OS Screen)
click run  (but skip to next command below here ... if you are using Windows 7 OS ... or later)

enter cmd ( i.e. type in cmd and then press the Enter key)
enter (the following lines on the command line, but not rem or what comes after):

md projects  rem md projects means make a directory called projects
cd projects  rem cd projects means change to the directory projects

md chapt01_print_message
cd chapt01_print_message


Using a text editor program (already installed on your computer) like notepad.exe enter this next line (on the command line):

notepad.exe  print_message.hla

and then select yes when asked Do you want to create a new file?


Now enter these next five lines into the text editor workspace, (i.e. copy and paste the lines into the text editor workspace):

Code: [Select]
program print_message;

#include( "stdlib.hhf" )

begin print_message;

stdout.put( "Hello World!" );

end print_message;

 
Now save this as a file with the name print_message.hla         

(Make sure notepad doesn't save it as print_message.hla.txt)

(Enter dir to see the files in that DIRectory.  If it does have a .txt on the end of it, then rename it by entering the command below … (note: ren means rename)

ren  print_message.hla.txt  print_message.hla

or               

ren  print_message.txt  *.hla

Note: the file needs to end in .hla to let it be compiled by HLA

Now enter this command on the command line to compile/assemble, (the program text file just saved):

hla print_message.hla

Now run the new executable file just produced and see the output by entering this next command:

print_message.exe

See also: http://en.wikipedia.org/wiki/High_Level_Assembly

 
There is absolutely nothing stopping a programmer from writing the "Hello World" program in low-level assembly language, should they really want to do this. However, for the beginner who is experiencing their first hour with assembly language, the former code is far more approachable than this latter code (i.e., explaining the stack and how parameters are passed to a procedure via the stack is a relatively advanced subject).

Code: [Select]
program HelloWorld;

#include( "stdlib.hhf" )

static
// nl is concated to end of string at compile time
hwString : string := "Hello World ... low_level" nl;
prsEnter : string := "Press 'Enter' to continue/exit ... ";

begin HelloWorld;

// Push the address of the "Hello World" string
push( hwString );

// Call an HLA Standard Library function that
// will print the string whose address has
// been pushed on the stack.
call stdout.puts;

push( prsEnter );
call stdout.puts;
call stdin.readLn; // keep window open until the enter key is pressed

end HelloWorld;

 
Addendum:

A user, "Kocmotex" ...

http://developers-heaven.net/forum/index.php/topic,50.msg100.html#new

pointed out a typo error in the "Hello Word", that is now fixed :  "(Was) ... the use of a colon to terminate the third line of chapter 1's program ... employed as a device to demonstrate to the reader the operation of HLA's error reporting system" ?

It may be a good, even at this point, to try out making that "typo error" in your program. See what error message the HLA compiler/assembler presents to you, to help you find errors in your HLA program, so that you might fix them ... and then successfully make ... in this case ... the "print_message.exe" file.
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 11:06:40 AM
Chapter 02: The Computer gets some input

 

Student ... (Go to the working directory)

click start
click run

enter cmd

enter (the following on the command line):

cd c:\hla\projects

md chapt02_get_input

cd chapt02_get_input

 
Using a text editor like notepad.exe enter this next line (on the command line):

notepad.exe  get_input.hla (or just enter ... notepad  get_input.hla)

and then select yes when asked Do you want to create a new file?

 
Now enter these lines into the text editor workspace, (i.e. copy and paste the lines into the text editor workspace):

Code: [Select]
program get_input;

#include( "stdlib.hhf" )

// after two front slash characters, 'comments' may be inserted
// into HLA programs

// declare first_name as a string variable in static memory and
// also reserve (i.e. allocate) space for 64 (byte-size) characters there

static
// declare first_name, last_name as strings in static memory ...
// and reserve (i.e. allocate) space for 64 byte-size characters
first_name: str.strvar(64);
last_name: str.strvar(64);

begin get_input;

stdout.put( "Please enter your first name: " );
stdin.get( first_name );

stdout.put( "Now enter your last name: " );
stdin.get( last_name );

stdout.put( "Are you really ", last_name, ", ", first_name, "?" );

end get_input;


Now save this file with the name get_input.hla

Now enter this following command, on the command line, to compile/assemble  (the program text file just saved) to produce a new executable file with the default name  get_input.exe

hla get_input.hla (or just enter the command line command:  hla get_input)

Now run the file get_input.exe by entering this next command, (on the command line):

get_input.exe (or just enter:  get_input)


An example of using stdin.a_gets() to dynamically allocate space for the input string as needed.

Code: [Select]
program get_input2;

#include( "stdlib.hhf" )

// after two front slash characters, 'comments' may be inserted into HLA programs
// declare firstname; lastname as string variables in var (dynamic) memory ...

var
firstname: string;
lastname: string;

begin get_input2;

stdout.put( "Please enter your first name: " );
stdin.a_gets();
mov( eax, firstname );

stdout.put( "Now enter your last name: " );
stdin.a_gets();
mov( eax, lastname );

stdout.put( "Are you really ", lastname, ", ", firstname, "?" nl );
str.free( lastname );
str.free( firstname );

end get_input2;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 11:15:54 AM
Chapter 03: The Computer adds some numbers

 

Student ... (Go to the working directory)

click start
click run

enter cmd

then enter (on the command line):

cd c:\hla\projects

md chapt03_add_nums

cd chapt03_add_nums

 
Using a text editor like notepad.exe enter this next line (on the command line):

notepad  add_nums.hla

and then select yes when asked Do you want to create a new file?


Now enter these lines into the text editor workspace, (i.e. copy and paste the lines into the text editor workspace):

Code: [Select]
program add_nums;

#include( "stdlib.hhf" )

// declare three 32 bit integer variables in the HLA static memory space

static
num1: int32:= 23; // initialize num1 to 23
num2: int32:= 77; // initialize num2 to 77
sum: int32; // sum is NOT initialized

begin add_nums;

stdout.put( "The sum of ", num1, " and ", num2, " is " );

// eax is a 32 bit register in the microprocessor
mov( num1, eax );// move the (value of the) integer num1 into eax

add( num2, eax );// add the (value of the) integer num2 to (what's in) eax

mov( eax, sum ); // move the 32 bit value now in the eax register into the
// 32 bits of static memory that we reserved and called 'sum'                       

stdout.put( sum )
stdout.newln();  // output an appropriate carriage return/newline character(s)

stdout.put( nl, "Enter an integer " ); // nl will output a newline character(s) as above
stdin.get( num1 );

// Note: ok to leave off comma here, as adjacent strings are all concatenated together
stdout.put( nl "Enter a second integer " );
stdin.get( num2 );

stdout.put( nl "The sum of ", num1, " and ", num2, " is " );
mov( num1, eax );
add( num2, eax );
mov( eax, sum );
stdout.put( sum );
stdout.newln();  // output an appropriate carriage return/newline character(s)

end add_nums;

 
Now save this file with the name add_nums.hla

Now enter this command on the command line to compile/assemble, (the program text file just saved), producing the executable file with the name add_nums.exe

hla add_nums.hla  (or just enter:  hla add_nums)

Now run the file add_nums.exe by entering this next command (on the command line), and observe:

add_nums.exe (or just enter the now executable command:  add_nums)
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 11:27:35 AM
Chapter 04: The Computer repeats a procedure

 

Student ... (Go to the working directory)

click start
click run

enter cmd

then enter (on the command line):

cd c:\hla\projects

md chapt04_repeat_proc

cd chapt04_repeat_proc


Using a text editor like notepad.exe enter this next line (on the command line):

notepad  repeat_proc.hla

and then select yes when asked Do you want to create a new file?


Now enter these lines into the text editor workspace, (i.e. copy and paste the lines into the text editor workspace):
 
Code: [Select]
program repeat_proc;

#include( "stdlib.hhf" )

static
done: boolean:= false; 

// The above reserves a byte of static memory and those 8 bits of
// memory space are now referred to (by the name) 'done' ...
// The value is initialized to 'false' i.e. 0000_0000

// Note: HLA can presently address 2^32 bytes of memory, so it takes a 32 bit
// variable to be able to address each byte of memory available. The highest
// address addressable, 1111_1111_1111_1111_1111_1111_1111_1111, has all 32
// binary bits set.

// Note: the address to get to the memory location 'done' is a 32 bit address, but
// the memory space reserved for the boolean variable 'done' is just one byte


// The following procedure asks for two integers to be entered and then finds
// their sum. It then prints out the two integers just input, and also their sum.

procedure get_nums_find_sum;

// Now declare three 'automatic' variables to hold 32 bit integers
// This is done in this area AFTER the top 'procedure ...' line
// but BEFORE the 'begin ...' line

var
num1: int32; // These 'automatic' variables, inside the procedure's
num2: int32; // declaration section, are created EACH time 'called'.
sum: int32; // And when the procedure is EXITed, they are 'lost'

begin get_nums_find_sum;

stdout.put( "Enter an integer: " );
stdin.flushInput(); // clears the 'stdin' input buffer
stdin.get( num1 );

stdout.put( "Enter a second integer: " );
stdin.get( num2 );

stdout.put( "The sum of ", num1, " and ", num2, " is " );

mov( num1, eax );
add( num2, eax );
mov( eax, sum ); // the int32 (in 'var' memory) with label 'sum'
                    // now holds the 32 bit value of (num1 + num2)
    stdout.put( sum );

end get_nums_find_sum;

 

begin repeat_proc; // Ok now ... start the 'main' section of this program.

// This section is where the 'repeat_proc.exe' program file begins to
// execute, when it first starts to run, after it is loaded into memory.

repeat // This marks the top of the repeat loop structure.

get_nums_find_sum(); // now execute this procedure we defined above

// We could call the 'macro' stdout.put which passes two nl
// OS appropriate codes and the string "Again (y/n) ? " ... each to
// appropriate procedure calls of the stdout library 'put' function ...

// but here, ok to use "stdout.puts( someString );" since the ...

stdout.puts( nl nl "More (y/n) ? " ); // strings here all get concatenated together by the compiler

// flushInput() is a library procedure and is in
// the 'stdin' namespace in HLA
stdin.flushInput(); // this flushes any characters like 'nl' that were
// left in the stdin buffered input stream

stdin.getc(); // puts the first character entered into 'al' (al is an 8 bit register,
// the lowest 8 bit byte of 'eax', eax is a 32 bit register)

if( al = 'n' ) then // if the 8 bits in 'al' match the eight bits in
// the ASCII representation of the character 'n' ... then

mov( true, done );

// move the 8 bit value for 'true' into the 8 bits of memory the computer
// refers to by (the name of) 'done'

elseif( al = 'N' ) then // now check, if need to,
// if a capital 'N' character was entered
mov( true, done );

else // if, and only if, neither of above two checks were true,
// then do this section ...
// output a string (that gets all concatenated together
// before assembled by HLA)
stdout.puts( nl "Ok ... Here we go again." nl );

endif;  // This marks the 'end' of the if..elseif...elseif..else..endif structure.

until( done ); // This marks the bottom of the 'repeat/until' structure.

// This 'repeat..until' structure is always traversed at least once,
// since the 'condition' to exit is NOT tested UNTIL the end.

// If the value of the boolean variable is 'true'
// the loop is exited. Otherwise, it begins again
// right after the top 'repeat' (address in the memory).

end repeat_proc;


Now save this text file with the name repeat_proc.hla

Now enter the following command on the command line to compile/assemble, (the program text file just saved), producing the executable file with the name repeat_proc.exe

hla repeat_proc.hla  (or just enter this command:  hla repeat_proc)

Now run the file repeat_proc.exe by entering this next command (on the command line).  Then supply suitable input and observe:

repeat_proc.exe  (or just enter:  repeat_proc)



Notice the 'done' procedure call used below, an example of an HLA function, (a procedure that returns a value.)

Code: [Select]
program repeat_proc2;

#include( "stdlib.hhf" )

procedure get_nums_find_sum;
begin get_nums_find_sum;
stdout.puts( "Enter an integer: " );
stdin.flushInput();
stdin.geti32();
mov( eax, ebx );

stdout.puts( "Enter a second integer: " );
stdin.flushInput();
stdin.geti32();

stdout.put( "The sum of ", (type int32 ebx), " and ", (type int32 eax), " is " );
add( ebx, eax );
stdout.puti32( eax );
end get_nums_find_sum;

procedure done; @returns( "al" );
begin done;
stdout.puts( nl "Done (y/n) ? " );
stdin.flushInput();
stdin.getc();
if( al == 'y' || al == 'Y' ) then
mov( 1, eax);
else
stdout.puts( "Ok ... Here we go again." nl );
mov( 0, eax );
endif;
end done;


begin repeat_proc2;

repeat
get_nums_find_sum();
until( done() );

end repeat_proc2;



And note the input validation procedure (function) added below ... Now the program won't crash on bad numeric input,

Code: [Select]
program repeat_proc3;

#include( "stdlib.hhf" )

procedure getValidInt( msg:string ); @returns( "eax" );
begin getValidInt;
forever
try
stdout.put( msg );
stdin.flushInput();
stdin.geti32(); // May raise an exception.
unprotected
break;
exception( ex.ValueOutOfRange )
stdout.put( "Value was out of range, re-enter please ..." nl );
exception( ex.ConversionError )
stdout.put( "Value contained illegal char's, re-enter please ..." nl );
endtry;
endfor;
end getValidInt;

procedure get_nums_find_sum;
begin get_nums_find_sum;

mov( getValidInt( "Enter a first integer: " ), ebx );
getValidInt( "Enter a second integer: " );

stdout.put( "The sum of ", (type int32 ebx), " and ", (type int32 eax), " is " );
add( ebx, eax );
stdout.puti32( eax );
end get_nums_find_sum;

procedure done; @returns( "al" );
begin done;
stdout.puts( nl "Done (y/n) ? " );
stdin.flushInput();
stdin.getc();
if( al == 'y' || al == 'Y' ) then
mov( 1, eax);
else
stdout.puts( "Ok ... Here we go again." nl );
mov( 0, eax );
endif;
end done;


begin repeat_proc3;

repeat
get_nums_find_sum();
until( done() );

end repeat_proc3;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 11:28:25 AM
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:

Code: [Select]
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#1011925


We have also told the computer which  (library of) functions it is to recognize.

Code: [Select]
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:

Code: [Select]
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:

Code: [Select]
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-3
O'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: ...
 
Code: [Select]
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:

Code: [Select]
// 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;


Code: [Select]
// 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:

Code: [Select]
// 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.html

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/LowLevelControlStructsa4.html


A test program, containing the code snippet from the previous page (slightly enhanced) follows:

Code: [Select]
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;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 12:09:21 PM
Chapter 06: The Computer rolls the dice … a first simulation

 

Ok … here is an interactive project with a little Google research to find out about the random function in the HLA library.

Create a sub folder in the \hla\projects\ folder with the name chapt06_randomNumber

With your text editor, start a new file called guessIt.hla and cut and paste a shell of an HLA program into it. Save it. Compile it to make sure it is good so far, (or fix it … so that it will compile with no significant error messages.)

Now let’s think about the bare bones of what we want the program to do:

I.     Announce what the program is about.

II.    Ask the user to input a guess in the range 2-12.

III.   Get the computer to select randomly a number in that range.

IV.   See if the number guessed matches the total on the die that the computer rolled

V.    Report the results

VI.   Ask if user wants to try again … or quit

 
Ok … let's get a shell started …

Code: [Select]
program  guessIt;

#include(  "stdlib.hhf"  )

// Note: procedure playgame is the main game ...

procedure playgame;

var
userNum: uns32;
die1: uns32;
die2: uns32;
diceSum: uns32;

begin playgame;

stdout.puts
(
nl
"THE COMPUTER will roll the dice AFTER" nl
"YOU ENTER a number in the RANGE 2..12" nl
"Ok ... what is your guess: "
);
stdin.flushInput();
stdin.get( userNum );

// The following tasks are yet to be coded:
// 1. get two random numbers 1..6 for each die
// 2. see if sum of die matches the number the user guessed
// 3. report success or falure

stdout.put( "You entered ", userNum, nl );

end playgame;

 
 
begin guessIt;

repeat // since we presume that the user wants to play at least
// one time, we can use the repeat..until structure
playgame();       
stdout.puts( nl "Play again (y/n) ? " );
stdin.flushInput();
stdin.getc(); // recall first character returned in lowest 8 bits of eax
// i.e. the al register
until( al = 'n' || al = 'N' ); // i.e. until n or N entered

end guessIt;


Ok … it compiles and runs ok so far, but did you notice that the user can enter numbers that are way out of range?


Let’s fix that this way: (We will pass the value to a function to validate it.)

Code: [Select]
// this 'function' returns true in al if x <= 12, otherwise it returns false

procedure isValid( x:uns32 ); @returns("al");

begin isValid;

    if(x <=12) then
        mov( true, al );
    else
        mov( false, al);
    endif

endisvalid;


Ok … let’s plug that in and check it out so far …

Code: [Select]
program  guessIt2;


#include(  "stdlib.hhf"  )


// this 'function' returns true in al if x <= 12, otherwise it returns false
procedure isValid( x:int32 ); @returns("al");
begin isValid;
if( x <= 12 ) then
mov( true, al );
else
mov( false, al);
endif;
end isValid;


// Note: procedure playgame is the main game …
procedure playgame;

var
userNum: int32;
die1: int32;
die2: int32;
diceSum: int32;

begin playgame;

stdout.puts
(             
nl "THE COMPUTER will roll the dice AFTER" nl
"YOU ENTER a number in the RANGE 2 to 12 ..." nl
);

repeat
stdout.puts( "Your guess 2..12 : " );
stdin.flushInput();
stdin.get( userNum );
until( isValid( userNum ) );

// the following is to do yet ...
// get two random numbers 1..6 for each die
// see if sum matches then ...  report success or falure

stdout.put( "You entered ", userNum, nl );

end playgame;

 

begin guessIt2;

repeat // since we presume that the user wants to play at least
// one time, we can use the repeat..until structure
playgame();       
stdout.puts( nl "Play again (y/n) ? " );
stdin.flushInput();
stdin.getc(); // recall first character returned in lowest 8 bits of eax                                                           
// i.e. the al register
until( al = 'n' || al = 'N' );

end guessIt2;


So far … so good. But let’s do that research on the HLA random function, (if HLA has one?)

Ok … google HLA random and here is what came up on top just now (2007-08-19):

rand.randomize(); // or call rand.randomize; (but this form used  here)

This function "randomizes" the seed used by the random number generators.  If you call rand.randomize, the random number generators should begin generating a sequence starting at a random point in the normal sequence put out by the random number generator.  The randomization function is based on the number of CPU clock cycles that have occurred since the CPU was last powered up.  This function uses the Pentium's RDTSC instruction, hence you should only call this function on machines that have this instruction available (Intel Pentium and later as well as other manufacturer's CPUs that have this instruction).  Because of the nature of the RDTSC instruction, you should not call rand.randomize frequently or you will compromise the quality of the random numbers (indeed, it's generally not a good idea to "randomize" a random number generator more than once per program invocation).

rand.range( startRange:int32; endRange:int32 ); @returns( "eax" );

This function generates a uniformly distributed random number in the range "startRange..endRange" (inclusive). This function generates its random numbers using the rand.random function. This function returns the value in the EAX register.

Or try this link: .... (to find new one)

Random Number Generators (rand.hhf)


Now let’s see if we can plug it in and get it working in our program … (and notice some changes? / deletions? / improvements? … that were made also.)

Code: [Select]
program  guessIt3;

 
#include(  "stdlib.hhf"  )

 
// This 'function' returns true in al if x is in the range 2..12,
// otherwise it returns false. The @display is turned off since it is
// not needed here.  This makes this procedure call more efficient.

procedure isValid( x:int32 ); @nodisplay; @returns("al");

begin isValid;

    if( x >= 2 && x <= 12 ) then  //  i.e. if x in range 2..12
        mov( true, al );
    else
        mov( false, al);
    endif;

end isValid;

 
// Note: procedure playgame is the main game

procedure playgame; @nodisplay;

var

    userNum:    int32;
    die1:       int32;
    die2:       int32;

begin playgame;

    stdout.puts
    (             
        nl
        "THE COMPUTER will roll the dice AFTER" nl
        "YOU ENTER a number in the RANGE 2 to12." nl nl
    );

    repeat

        stdout.puts( "Your guess 2..12 : " );
        stdin.flushInput();
        stdin.get( userNum );

    until( isValid( userNum ) );    // Note: userNum is first passed to isValid
                                    // Then isValid returns true or false               
                                    // get two random numbers 1..6 for each die
    rand.range( 1, 6 );             // returns random num 1..6 in eax
    mov( eax, die1 );               // and move value into die1
    rand.range( 1, 6 );             // returns random num 1..6 in eax
    mov( eax, die2 );               // and move value into die2
    add( die1, eax );               // eax now holds sum

    // see if sum matches
    if( eax = userNum ) then           
        stdout.puts( "MATCH!" nl );     // report success
    else
        stdout.puts( "NO match!" nl );  // report failure
    endif;
                     
    stdout.put
    (
        "You entered ", userNum, nl
        "And the computer rolled ", die1, " & ", die2,
        " or ", (type int32 eax), "." nl
    );

end playgame;


begin guessIt3;

    rand.randomize();   // We just want to call this once in our program,
                        // as per above info.

    repeat  // Since we presume that the user wants to play at least
            // one time, we can use the repeat..until structure.

            playgame(); // We pick two unique random numbers in range 1..6
                        // in each call.

            stdout.puts( nl "Play again (y/n) ? " );
            stdin.flushInput();
            stdin.getc();   // Recall, the first character is returned in
                            // lowest 8 bits of eax
                            // i.e. the al register
                           
    until( al = 'n' || al = 'N' );

end guessIt3;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 02:23:50 PM
Chapter 06: The Computer rolls the dice … a first simulation ... continued ...



Well, these functions are working ok … but let’s make some more enhancements:

Let’s add a counter to keep track of the number of games.  And suppose that you started out with so many cents, say 100, at the beginning and win the number of cents, (the value you guessed), when there is a match … but lose the number (the same number of cents) you guess for the sum of the dice if there is NO match … (Let’s use global variable’s for these to keep the design simple, and also we can use registers, so we won’t have to pass these values back and forth to/from the procedures or to use pass by reference syntax, since this is supposed to be a simple simulation?)

 
The game will be over when all your starting cents are used up, … or … if you choose to quit, (or if by some long shot, the computer loses all its cents!)

Make a final report of the success or failure. (What you started out with. How much you were up/down.  Your new total and the computers new total. The number of games played.)

 
Are you ready to start programming?

Code: [Select]
program  guessIt4;               

#include( "stdlib.hhf" )

static // below are used as global variables
    cCents: int32;
    pCents: int32;
    cWins: int32:= 0;
    pWins: int32:= 0;         
    numGames: int32:= 0;


procedure getValidInt( msg:string; low:int32; high:int32  );@nodisplay;@returns( "eax" );
begin getValidInt;
    push( ebx );
    push( edx );
    forever
        try
            stdout.puts( msg );
            stdin.flushInput();
            stdin.geti32(); // May raise an exception.
        unprotected
            breakif( eax >= low && eax <= high );
            stdout.put( "Value was out of range ", low, "..", high, ", re-enter please ... " nl );
        exception( ex.ValueOutOfRange )
            stdout.put( "Value was out of range, re-enter please ... " nl );
        exception( ex.ConversionError )
            stdout.put( "Value contained illegal char's, re-enter please ..." nl );
        endtry;
    endfor;
    pop( edx );
    pop( ebx );
end getValidInt;
 

procedure playgame; @nodisplay; // Note: procedure playgame is the main game ...
var
    userNum:    int32;
    die1:       int32;
    die2:       int32;
begin playgame;

    stdout.puts
    (             
        nl "THE COMPUTER will roll the dice AFTER "
        "YOU ENTER a number in the RANGE 2 to 12." nl nl
    );

    mov( getValidInt( "Your guess 2..12 : ", 2, 12 ), userNum );

    // get two random numbers 1..6 for each die
    rand.range( 1, 6 ); // returns random num 1..6 in eax
    mov( eax, die1 ); // and move value into die1
    rand.range( 1, 6 ); // returns random num 1..6 in eax
    mov( eax, die2 ); // and move value into die2
    add( die1, eax ); // eax now holds sum

    // see if sum matches ...
    if( eax == userNum ) then       
        // note that edx and ebx were given initial values in the 'main' program section
        stdout.puts( "MATCH!" nl ); // report
        add( userNum, edx ); // player wins
        sub( userNum, ebx ); // computer loses
    else
        stdout.puts( "NO match!" nl ); // report failure
        sub( userNum, edx ); // player loses
        add( userNum, ebx ); // computer wins
    endif;

    stdout.put
    (
        "You entered ", userNum, nl
        "And the computer rolled ", die1, " & ", die2,
        " or ", (type int32 eax), "." nl
    );

end playgame;



begin guessIt4;

    rand.randomize();   // we just want to call this once in our program,
                        // as per above info

    mov( getValidInt( nl "Computer stakes 100..1000 (cents) : ", 100, 1000 ), cCents );
    mov( cCents, ebx ); // working copy in ebx

    mov( getValidInt( nl "Player stakes 100..1000 (cents) : ", 100, 1000 ), pCents );
    mov( pCents, edx ); // working copy in edx

    // since we presume that the user wants to play at least
    // one time, we can use the repeat..until structure
    repeat
    inc( numGames );   // here we go again so increment numGames
    playgame();        // we pick two unique random numbers
                       // in range 1..6 in each call
    stdout.puts( nl "Play again (y/n) ? " );
    stdin.flushInput();
    stdin.getc(); // recall first character returned in the lowest 8 bits of eax (i.e. the al register)
    until
(
        al == 'n' || al == 'N' || // i.e. until n or N selected ... or
        (type int32 ebx) <= 0 ||  // the value, taken as an integer, in ebx <= 0 ... or
        (type int32 edx) <= 0     // the value, taken as an integer, in edx <= 0
);

// don't allow, (i.e. correct for), 'in-hole' stuations ...

    if( (type int32 edx) < 0 ) then     // player in hole
        add( edx, ebx );                // i.e. decrease computer balance
        mov( 0, edx );                  // so now can up balance of player to zero
    elseif( (type int32 ebx) < 0 ) then // computer in hole
        add( ebx, edx );                // decrease player balance
        mov( 0, ebx );                  // so now can up balance of computer to zero
    endif;

stdout.put
(
nl "After ", numGames, " games, the computer has ",
(type int32 ebx), " cents", nl
"and the player has ", (type int32 edx), " cents", nl
);

    // Recall cCents, and pCents hold the starting staked values

    mov( ebx, eax );        // calculate the computer winnings
    sub( cCents, eax );
    mov( eax, cWins );

    mov( edx, eax );        // calculate the player winnings
    sub( pCents, eax );
    mov( eax, pWins );

if( cWins > 0 ) then  // computer wins

neg( pWins );  // take the negative of ( )
stdout.put
(
"The computer wins ", cWins,
" and the player loses ", pWins, nl
);
else // computer loses
neg( cWins );
stdout.put( "The player wins ", pWins, " and the computer loses ", cWins, nl );
endif;

stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.flushInput();
stdin.getc();

end guessIt4;


Here is a fun program using random numbers that I modified a little …

Code: [Select]
program testRandom;

// adapted from ...
// http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/IntegerArithmetic3.html

#include( "stdlib.hhf" )

/*
    Note:
    console.black   := 0;
    console.red     := 1;
    console.green   := 2;
    console.yellow  := 3;
    console.blue    := 4;
    console.magenta := 5;
    console.cyan    := 6;
    console.white   := 7;
*/

begin testRandom;

    console.cls();
    mov( 10_000, ecx );

    call rand.randomize;            // or rand.randomize();

    repeat

        // Generate a random X-coordinate
        // using rand.range.
        rand.range( 1, 78 );
        mov( eax, ebx );            // Save the X-coordinate for now.

        // Generate a random Y-coordinate
        // using rand.urange
        rand.urange( 1, 23 );
        mov( eax, edx );

        // Print an asterisk at
        // the specified coordinate on the screen.
        console.gotoxy( ebx, edx );
        rand.range( 0, 6 );         // no white foreground
        console.setAttrs( eax, 7 ); // all white background
        stdout.puts( "*" );

        // Repeat this 10,000 times to get
        // a good distribution of values.
        dec( ecx );

    until( @z ); // zero flag set when ecx becomes zero

    // Position the cursor at the bottom of the
    // screen so we can observe the results.
    console.gotoxy( 0, 23 );
   
    stdin.readLn();

end testRandom;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 03:21:44 PM
Chapter 07: Memory Flow Lab

 
 
1.  Create (md) a sub-directory in the project folder.  Give it the name memoryFlowLab

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program the name memoryFlowLab.hla

4.  Compile the program and run it. Study the comments and questions that are in the hla program, as well as the questions, (and answers), that appear on the screen when you run (execute) the program.

Code: [Select]
program memoryFlowLab;

/*
 Also see:
 http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/HelloWorlda3.html
*/

#include("stdlib.hhf")

static
    myCharArray:char[255];              // reserve 255 bytes of memory for 255 char's
    myChr:  char;                       // reserve 1 byte of memory for 1 character               
    myInt:  int32:= 12345;              // reserve 4 bytes, i.e. 32 bits, for an int

    // the following shows how to declare a 'pointer' type variable ...
    myP:    pointer to int32:= &myInt;  // now myP holds address of myInt

begin memoryFlowLab;

    // Note below that the ':' character notifies the compiler that
    // 'top' IS to be known, from here on, (in the program), as A LABEL
    // So now the running program HAS a label, (i.e. a name), to
    // refer to, if it needs to go to THAT ADDRESS.

top:
   
    // Note below, the 'no op', i.e. nop() means 'no operation'         

    // 1. How many bytes of program execution
    // memory does this nop(); take?

    // 2. How many bytes of program execution memory
    // do all these comments in the source file take?

    // 3. How many bytes of program execution memory
    // are BETWEEN the addresses given by 'top' and 'bot' ?

top2:
    nop(); 
next:
    add( myInt, eax );
next2:

    mov( & top, eax );       // '&' means 'take the address of'
    stdout.put( nl "The address of label top is ", eax );

    mov( &top2, eax );
    stdout.put( nl "The address of label top2 is ", eax );

    stdout.puts( nl "So how much space do 'comments' take in the '.exe' file?" );

    mov( &next, eax );
    stdout.put( nl nl "The address of label next is ", eax );
    stdout.puts( nl "How many bytes does the instruction nop() take in memory?" );

    mov( &next2, eax );
    stdout.put( nl nl "The address of label next2 is ", eax );
    stdout.puts( nl "How many bytes are used by the instruction 'add( myInt, eax )' ? " );
    sub( &next, eax );
    stdout.put( nl "(The answer, in hexidecimal ... ", eax, ")" );

    mov( &myCharArray, eax );
    stdout.put( nl nl "The address of variable myCharArray is ", eax );

    mov( &myChr, eax );
    stdout.put( nl "The address of variable myChr is ", eax );;

    mov( &myInt, eax );
    stdout.put( nl nl "The address of variable myInt is ", eax );

    mov( myP, eax );
    stdout.put( nl "And ALSO, value of variable myP= ", eax );
                     

    mov( &top, eax );           // eax holds address of 'top' label
    mov( &bot, ebx );           // ebx holds address of 'bot' label
    mov( ebx, ecx );            // now ecx ALSO holds the address of bot2

    sub( eax, ecx );            // i.e. subtract eax from ecx and
                                // store result in ecx

                                // ecx now holds the number of bytes
                                // from top to bot in the programs
                                // memory (while the program is runing
                                // i.e. executing in the computers 'ram')

    stdout.put
    (
        nl nl
        "What to learn:" nl nl    // Note: the compiler concatenates ADJACENT strings ... ok:)

        "The address of label 'top' is ", EAX, nl
        "The address of label 'bot' is ", EBX, nl,                     

        ebx, " - ", eax, " = ", ecx, " = ",
        (type int32 ecx) , nl nl

        "So there are ", ecx, " (in hex) bytes inside the running program,"
        nl "from the label 'top' to the label 'bot'." nl

        nl  "As the program flows, (i.e. executes), as we have written it "
        "from "
        nl "the address labelled 'top' to the address labelled 'bot' ... "             
        nl  "do the values of the addresses in memory decrease or increase? "
        nl nl "Press 'Enter' to continue/exit ... "
    );
   
    stdin.readLn();

bot:
   
end memoryFlowLab;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 03:23:32 PM
Chapter 08: Memory Flow Lab2

 
 
1.  Create (md) a sub-directory in the project folder.  Give it the name memoryFlowLab2

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program the name memoryFlowLab2.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run (execute) the program.

Code: [Select]
program memoryFlowLab2;

#include("stdlib.hhf")

// An example of initializing at the same time as declaring variables.
// We have printed out the value of the memory addresses of some variables, so
// lets ALSO print out the (typed) values in these addresses ...
static
    // reserve 256 bytes of memory for 256 char's. Note: (32*8) = 256
    // Note: '32 dup' means to duplicate [ .. ] 32 times in memory
    myCharArray:char[]:= 32 dup [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' ];

    // reserve 1 byte of memory for 1 character
    myChr:  char:= 'z';   
    // set p, a pointer to 'char', to hold the address of the first element in myCharArray
    p:      pointer to char:= &myCharArray;

begin memoryFlowLab2;

    mov( & myCharArray, eax );
    stdout.put( "The address of variable myCharArray is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray );
    mov( & myCharArray[0], eax );
    stdout.put( nl nl "The address of variable myCharArray[0] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[0] );
    mov( & myCharArray[1], eax );
    stdout.put( nl nl "The address of variable myCharArray[1] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[1] );
    mov( & myCharArray[254], eax );
    stdout.put( nl nl "The address of variable myCharArray[254] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[254] );
    mov( & myCharArray[255], eax );
    stdout.put( nl nl "The address of variable myCharArray[255] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[255] )
    mov( & myCharArray[256], eax );
    stdout.put( nl nl "The address of variable myCharArray[256] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[256] )
    mov( & myChr, eax );
    stdout.put( nl nl "The address of variable myChr is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myChr, nl nl  );

    // ok here is an example using the HLA for..endfor loop structure
    // let's use a register as a counter to give the maximum speed counting ...
    for( mov( 0, ecx); ecx < 39; inc( ecx ) ) do
        stdout.put( myCharArray[ ecx ], " " );
    endfor;

    stdout.puts
    (
        nl "Can you figure out all the above outputs?  Press 'Enter' to continue ... "
    );

    stdin.readLn(); // wait for 'Enter' key to be pressed ...

    // Now ... print out some headers, right-adjusted in 10 character wide fields.
    stdout.put
    (
        nl nl, "address":10, "value":10, nl nl
    );

    for( mov( 0, ecx ); ecx < 20; inc( ecx ) ) do
        lea( eax, myCharArray[ ecx ] ); // take address of each element and put it in eax
        stdout.put( " ", eax, myCharArray[ ecx ]:10,  nl );
    endfor;

    stdout.puts
    (
        nl "Can you figure out all these above outputs?  Press 'Enter' to continue ... "
    );

    stdin.readLn(); // wait for 'Enter' key to be pressed ...

    // Now ... print out some headers, right-adjusted in 10 character wide fields.

    stdout.put
    (
        nl nl, "address":10, "value":10, nl
    );

    mov( p, eax ); // move address of first byte into eax
    for( mov( 0, ecx ); ecx < 20; inc( ecx ) ) do

        // (type char [ eax ]) = go to the address held in eax and ...
        // intrepret the byte, at that address, as a char
        stdout.put( " ", eax, (type char [ eax ]):10,  nl );
        inc( eax ); // go to next byte (address)

    endfor;

    mov( p, eax );
    add( 256, eax );
    stdout.put( nl " ", eax, (type char [ eax ]):10,  nl );
   
    stdout.put( nl nl "Press 'Enter' to continue/exit ... " );
    stdin.readLn();

end memoryFlowLab2;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 03:26:52 PM
Chapter 09: Memory Flow Lab3

 
 
1.  Create (md) a sub-directory in the project folder.  Give it the name memoryFlowLab3

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program the name memoryFlowLab3.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run (execute) the program.

Code: [Select]
program memoryFlowLab3;

#include("stdlib.hhf")

// An example of initializing at the same time as declaring variables.
// We have printed out the value of the memory addresses of some variables, so
// lets ALSO print out the (typed) values in these addresses ...

static

    // reserves 80 bytes of memory for 20 int32's. Note: (2*10*4bytes) = 80bytes
    // Note: '2 dup' means to duplicate [ .. ] 2 times in memory
    myInt32Array:   int32[]:=   2 dup [ 1,2,3,4,5,6,7,8,9,0 ];
    myInt32:        int32:=     987654321;

    // set p, a pointer to 'int32', to hold the address of the first element in myInt32Array
    p:  pointer to int32 :=     &myInt32Array;

begin memoryFlowLab3;

    mov( & myInt32Array, eax );
    stdout.put( "The address of variable myInt32Array is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array );

    mov( & myInt32Array[0], eax );
    stdout.put( nl nl "The address of variable myInt32Array[0] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[0] );

    mov( & myInt32Array[1*4], eax );
    stdout.put( nl nl "The address of variable myInt32Array[1*4] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[1*4] );

    mov( & myInt32Array[18*4], eax );
    stdout.put( nl nl "The address of variable myInt32Array[18*4] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[18*4] );

    mov( & myInt32Array[19*4], eax );
    stdout.put( nl nl "The address of variable myInt32Array[19*4] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[19*4] )

    mov( & myInt32Array[20*4], eax ); // overflow example ...
    stdout.put( nl nl "The address of variable myInt32Array[20*4] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[20*4] )

    mov( & myInt32, eax );
    stdout.put( nl nl "The address of variable myInt32 is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32, nl nl  );

    // ok here is an example using the HLA for..endfor loop structure
    // let's use a register as a counter to give the maximum speed counting ...
    for( mov( 0, ecx); ecx < 20; inc( ecx ) ) do
        stdout.put( myInt32Array[ ecx*4 ], " " );
    endfor;

    stdout.puts
    (
        nl "Can you figure out all the above outputs?  Press 'Enter' to continue ... "
    );

    stdin.readLn(); // wait for 'Enter' key to be pressed ...
   
   

    // Now ... print out some headers, right-adjusted in 10 character wide fields.
    stdout.put
    (
        nl nl, "address":10, "value":10, nl nl
    );

    for( mov( 0, ecx ); ecx < 20*4; add( 4, ecx ) ) do // add 4 since 4 bytes used for each int32
        lea( eax, myInt32Array[ ecx ] ); // take address of each element and put it in eax
        stdout.put( " ", eax, myInt32Array[ ecx ]:10, nl );
    endfor;

    stdout.puts
    (
        nl "Can you figure out all these above outputs?  Press 'Enter' to continue ... "
    );

    stdin.readLn(); // wait for 'Enter' key to be pressed ...
   
   

    // Now ... print out some headers, right-adjusted in 10 character wide fields.
    stdout.put
    (
        nl nl, "address":10, "value":10, nl
    );

    mov( p, eax ); // move address of first int32 into eax
    for( mov( 0, ecx ); ecx < 20; inc( ecx ) ) do
        // (type int32 [ eax ]) ... means to go to the address held in eax ...
        //  and then to intrepret the 4 bytes, at that address, as an int32
        stdout.put( " ", eax, (type int32 [ eax ]):10,  nl );
        add( 4, eax ); // go to next int32 (address)
    endfor;

    mov( p, eax );
    add( 20*4, eax );   // note: compiler/assembler does this calulation of 20*4
                        // when compiling/assembling the 'xxx.hla' file into the 'xxx.exe' file

    stdout.put( nl " ", eax, (type int32 [ eax ]):10,  nl );   

    // recall '[eax]' means to goto the address held in eax
    // (type int32 [ eax ]) means to interpret as an int32 the 4 bytes at the address (pointed to by the value) in eax
    // eax, without square brackets, means take the value in eax
    // (type int32 eax ) would mean to interpret as an int32 the 4 bytes in eax

end memoryFlowLab3;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 03:29:59 PM
Chapter 10: HLA Data Types

 

1.  Create (md) a sub-directory in the project folder.  Give it the name hlaTypes

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program the name hlaTypes.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run (execute) the program.

Code: [Select]
program types; // some HLA data types

#include( "stdlib.hhf" )

static

    b:      byte:=  65;
    u8:     uns8:=  $ff;
    i8:     int8:=  127;
    ca:     char:=  'a';
    cz:     char:=  'z';
    ccA:    char:=  'A';
    ccZ:    char:=  'Z';
    w:      word:=  $ffff;
    u16:    uns16:= $FFFF;
    i16:    int16:= $7fff;
    dw:     dword:= $ffff_ffff;
    u32:    uns32:= $ffffffff;
    i32:    int32:= $7fff_ffff;

    r32:    real32:= 1234567890.123e-47;
    r64:    real64:= 1234567890.123e-316;
    s:      string:= "Pausing now. Press 'Enter' to continue ...";

    len_s:  int32;

begin types;

    str.length( s ); // library function returns string length in eax
    mov( eax, len_s );
   
    stdout.put
    (
        "b=", b, " as byte (i.e. hex)"
        " =", (type uns8 b), " as uns8"           
        " =", (type char b), " as char" nl
        "u8=", u8, nl
        "i8=", i8, nl nl
        "ca=", ca,
        " =", (type byte ca), " as byte"
        " =", (type uns8 ca), " as uns8" nl
        "cz=", cz, nl
        "ccA=", ccA,
        " =", (type byte ccA), " as byte"
        " =", (type uns8 ccA), " as uns8" nl
        "ccZ=", ccZ, nl nl
        "w=", w, nl
        "u16=", u16, " (max uns16)" nl
        "i16=", i16, " (max int16)" nl nl
        "dw=", dw, nl
        "u32=", u32, " (max uns32)" nl
        "i32=", i32, " (max int32)" nl nl
        "r32=", r32,  nl
        "r64=", r64,  nl nl,
        "s='", s, "' (The string length of s =", len_s, ") "
    );
 
    stdin.readLn(); stdout.newln();

    for( mov( '0', cl ); cl <= '9'; inc( cl ) ) do
        stdout.put( (type char cl), "  " );
    endfor;

    stdout.newln();

    for( mov( '0', cl ); cl <= '9'; inc( cl ) ) do
        stdout.put( cl, " " );
    endfor;

    stdout.newln(); stdout.newln();

    for( mov( 'A', cl ); cl <= 'Z'; inc( cl ) ) do
       stdout.put( (type char cl), "  " );
    endfor;

    stdout.newln();

    for( mov( 'A', cl ); cl <= 'Z'; inc( cl ) ) do
        stdout.put( cl, " " );
    endfor;

    stdout.newln();

    for( mov( 'a', cl ); cl <= 'z'; inc( cl ) ) do
        stdout.put( (type char cl), "  " );
    endfor;

    stdout.newln();

    for( mov( 'a', cl ); cl <= 'z'; inc( cl ) ) do
        stdout.put( cl, " " );
    endfor;

    stdout.newln();
    stdin.readLn();

end types;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 03:41:16 PM
Chapter 11: The Computer does some Algebra with real numbers ... and Input Data Validation

 

1.  Create (md) a sub-directory in the project folder.  Give it the name Chapt11_realMath

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program file the name realMath.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run the program.

Code: [Select]
program realMath; // finds the running average of test scores

#include( "stdlib.hhf" )

static
    score:      int32;
    outOf:      int32;
    totScores:  int32:= 0;
    totOutOf:   int32:= 0;
    average:    real64;
    count:      int32:= 0;

begin realMath;

    // The FINIT instruction initializes the FPU for proper operation. Your applications
    // should execute this instruction before executing any other FPU instructions.

    finit();                // initialize floating point (math) unit

    stdout.puts
    (         
        "The following program asks for input of test scores" nl
        "and then finds the average of the scores todate:"
        nl nl
    );

    repeat
   
        inc(count);
        stdout.puts( "Enter score: " );
        stdin.flushInput();
        stdin.get( score );
        mov( score, eax );
        add( eax, totScores );

        stdout.puts( "Enter outOf: " );
        stdin.get( outOf );
        mov( outOf, eax );
        add( eax, totOutOf );

        // The FILD (integer load) instruction converts a 16, 32, or 64 bit two's
        // complement integer to the 80 bit extended precision format and pushes the
        // result onto the stack. This instruction always expects a single operand. This
        // operand must be the address of a word, double word, or quad word integer
        // variable.

        fild( totScores );  // float integer load
        fild( totOutOf );

        // With no operands, the FDIVP instruction pops ST0 and ST1,
        // computes ST1/ST0, and pushes the result back onto the stack.

        fdivp(); // find totScores / totOutOf and leave result on top of FPU stack (in st0)

        // The FSTP instruction POPS and copies the value on the top of the floating
        // point register stack to another floating point register or to a 32, 64, or 80 bit
        // memory variable. When copying data to a 32 or 64 bit memory variable, the
        // 80 bit extended precision value on the top of stack is rounded to the smaller
        // format as specified by the rounding control bits in the FPU control register.

        fstp( average ); // POP and store sto, the top of the FPU stack, into average

        stdout.put
        (
            "The average of ", count, " test(s) with ",
            totScores, " marks out of ", totOutOf,
            " is: ", average:8:3, nl nl
        );

        stdout.puts( "Another (y/n) ? " );
        stdin.flushInput();
       
    until( stdin.getc() == 'n' );

end realMath;



See also:  Floating Point Arithmetic ...


http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/RealArithmetic.html#998833


Let’s add some enhancements to the above program that finds a running average.  Did you notice that if you enter a non-number, when a number is expected for input, the program stops with an error message?  With HLA, we can easily trap those errors.  The following demonstrates how:

 
See also:

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/HelloWorlda3.html#998851

 
The TRY..EXCEPTION..ENDTRY Statement

 
The HLA TRY..EXCEPTION..ENDTRY statement provides very powerful exception handling capabilities. The syntax for this statement is the following: ...


Here is a short example:

Code: [Select]
repeat

            // initialize to false at start of repeat loop, 'goodInteger' is assumed
            // to have been declared previously as a boolean variable

            mov( false, goodInteger );       
            try

                stdout.put( "Enter an integer: " );
                // i is presumed to have been declared previously as an integer
                stdin.get( i );               
                mov( true, goodInteger );

            exception( ex.ConversionError );
                tdout.put( "Illegal numeric value, please re-enter", nl );

            exception( ex.ValueOutOfRange );
                tdout.put( "Value is out of range, please re-enter", nl );
               
        endtry;

until( goodInteger );


Now let’s put this into our program:

Code: [Select]
program realMath2;

// finds the running average of test scores
// this version checks for/and handles non-numeric input

#include( "stdlib.hhf" )

static
    score:      int32;
    outOf:      int32;
    totScores:  int32:= 0;
    totOutOf:   int32:= 0;
    average:    real64;
    count:      int32:= 0;

    good:       boolean;

// In the following macro, 'message' is presumed to be the input message-string
// passed to the macro, and 'num' is some previously declared type of number
// that is passed to the macro, and back again. Note: A macro, is just as if
// that code was inserted into the place from where the macro is called.
// Thus, this macro behaves similar to an 'inline' function call in C++ ...
// NOTE! It is also an 'overloaded' function, in that the type of number
// validated, will be the type of number passed in.

#macro getNumber( message, num );
    repeat
        // initialize to false at start of repeat loop, 'good' is assumed
        // to have been declared previously as a boolean (global) variable
        mov( false, good );         

        try
            stdout.puts( message ); // or more generally, could use stdout.put()
            stdin.flushInput();

            // (the value passed to) num is presumed to have been declared
            // previously with some type
            stdin.get( num );                     
            mov( true, good ); // if no exception jumped to, then accept data
           
        exception( ex.ConversionError );
            stdout.put( "Illegal numeric value, please re-enter", nl );

        exception( ex.ValueOutOfRange );
            stdout.put( "Value is out of range, please re-enter", nl );

        endtry;
       
    until( good );
#endmacro

 

begin realMath2;

    // The FINIT instruction initializes the FPU for proper operation. Your applications
    // should execute this instruction before executing any other FPU instructions.

    finit();        // initialize floating point (math) unit

    stdout.puts
    (         
        "The following program asks for input of test scores" nl
        "and then finds the average of the scores todate:"
        nl nl
    );

    repeat

        inc(count); // increment count by one each time a new score is obtained
           
        getNumber( "Enter score: ", score );
        mov( score, eax );
        add( eax, totScores );

        getNumber( "Enter outOf: ", outOf );
        mov( outOf, eax );
        add( eax, totOutOf );

        // The FILD (integer load) instruction converts a 16, 32, or 64 bit two's
        // complement integer to the 80 bit extended precision format and pushes the
        // result onto the stack. This instruction always expects a single operand. This
        // operand must be the address of a word, double word, or quad word integer
        // variable.

        fild( totScores ); // float integer load
        fild( totOutOf );

        // With no operands, the FDIVP instruction pops ST0 and ST1,
        // computes ST1/ST0, and pushes the result back onto the stack.
       
        fdivp(); // find totScores/totoutOf and leave result on top of FPU stack (in st0)

        // The FSTP instruction POPS and copies the value on the top of the floating
        // point register stack to another floating point register or to a 32, 64, or 80 bit
        // memory variable. When copying data to a 32 or 64 bit memory variable, the
        // 80 bit extended precision value on the top of stack is rounded to the smaller
        // format as specified by the rounding control bits in the FPU control register.
       
        fstp( average ); // POP and store sto, the top of the FPU stack, into average

        stdout.put
        (
            "The average of ", count, " test(s) with ",
            totScores, " marks out of ", totOutOf,
            " is: ", average:8:3, nl nl
        );

        stdout.puts( "Another (y/n) ? " );
        stdin.flushInput();
       
    until( stdin.getc() = 'n' );

end realMath2;

 

The following version also limits the range of user input values and applies some logic, (like the test score input can't be greater than the total score.) It also illustrates some low-level coding for error-checking and looping.

And note how we have been using a macro to make the code more modular.  The macro is called twice in the main program. Note where the macro definition is placed. (The same place as procedures or global variables ... Note also that the macro must be defined before it can be called.)

Code: [Select]
program realMath3;

// finds the running average of test scores
// This version checks for/and handles non-numeric input, and ...
// also limits the range of user input to proscribed values/logic

#include( "stdlib.hhf" )

static
    score:      int32;
    outOf:      int32;
    totScores:  int32:= 0;
    totOutOf:   int32:= 0;
    average:    real64;
    count:      int32:= 0;
    one00:      int32:= 100;

// In the following macro, 'message' is presumed to be the input message-
// string passed to the macro, and 'num' is some previously declared type of
// number that is passed to the macro,and back again. Note: A macro, is just
// as if that code was inserted into the place from where the macro is
// called. Thus, this macro behaves similarly to an 'inline' function call
// in C++ ... NOTE! It is also an 'overloaded' function, in that the type of
// number validated, will be the same type of number as the type of the
// number that was passed in. (Here it is an int32)

#macro getNumber( message, num, low, high );

    forever
        try
            stdout.puts( message ); // or more generally, could use stdout.put( )
            stdin.flushInput();
            stdin.get( num );       // the value passed to num is expected to be
                                    // a type int32 just as num was declared

            // don't accept numbers less than low or more than high
            if( num < low || num > high ) then
                raise( ex.ValueOutOfRange );
            endif;
           
        unprotected;
            break;  // IF we arrive here, NO exception was raised above,
                    // so break out of loop right now ...

        exception( ex.ConversionError );
            stdout.put( "Illegal numeric value, please re-enter", nl );

        exception( ex.ValueOutOfRange );
            stdout.put( "Value is out of range, please re-enter", nl );
           
        endtry;
    endfor;

#endmacro

 

begin realMath3;

    // The FINIT instruction initializes the FPU for proper operation. Your applications
    // should execute this instruction before executing any other FPU instructions

    finit(); // initialize floating point (math) unit

    console.setAttrs( console.blue, console.cyan );
    console.cls();

    stdout.puts
    (             
        "The following program asks for input of test scores" nl
        "and then finds the average of the scores todate ..." nl nl
    );

    repeat

        inc(count); // increment count by one each time a new score is obtained

        // An example of low level coding follows ... in the outer loop
        // ... but for the inner loop, the HLA 'repeat..until' is used

        jmp startGetNumber;   

    errorGetNumber1:
        stdout.put( nl "NOT valid entry ... 'out of' must be at least as big as ",
                    score, nl );
        jmp startGetNumber;

    errorGetNumber2:
        stdout.puts( nl "Entry aborted ... here we go again ..." nl );

    startGetNumber:
        getNumber( "Enter score: ", score, 0, 100 );

        // Don't allow zero entry for 'outOf'. Also, don't allow divide by zero
        repeat // This 'repeat..until' loop is an example of High Level coding

            getNumber( "Enter outOf: ", outOf, 0, 100  );
            if( outOf <= 0 ) then
                stdout.puts
                (
                    "'<=0' not allowed here. Please enter valid data." nl
                );
            endif;

        until( outOf > 0 );

        // Also don't allow a score greater than outOf
        mov( score, eax );
        cmp( eax, outOf );
        ja errorGetNumber1;     // i.e. jump to top label if score > outOf

        // Now one LAST check to confirm the data input was correct ...
        stdout.put
        (
            "You entered a score of ", score, " out of ", outOf,
            "  <===  OK  (y/n)  ? "
        );
        stdin.flushInput();
        stdin.getc();
        chars.toLower( al );    // Converts 'Y'to 'y'
        cmp( al, 'y' );
        jne errorGetNumber2;    // loop back to TOP error handling message block

    // endof low level loop

        mov( score, eax );
        add( eax, totScores );               
        mov( outOf, eax );
        add( eax, totOutOf );

        // The FILD (integer load) instruction converts a 16, 32, or 64 bit two's
        // complement integer to the 80 bit extended precision format and pushes the
        // result onto the stack. This instruction always expects a single operand. This
        // operand must be the address of a word, double word, or quad word integer
        // variable.

        fild( totScores );  // float integer load
        fild( one00 );      // will multiply by 100 to convert to percent

        // With no operands, the FMULP instruction pops ST0 and ST1,
        // computes the product and pushes the result back onto the stack
       
        fmulp();
        fild( totOutOf );   // now in STO ... and totScores*100 now in ST1

        // With no operands, the FDIVP instruction pops ST0 and ST1,
        // computes ST1/ST0, and pushes the result back onto the stack.

        fdivp(); // find totScores*100/totoutOf; (result in stack top i.e. st0)

        // The FST and FSTP instructions copy the value on the top of the floating point
        // register stack to another floating point register or to a 32, 64, or 80 bit
        // memory variable. When copying data to a 32 or 64 bit memory variable, the 80
        // bit extended precision value on the top of stack is rounded to the smaller
        // format as specified by the rounding control bits in the FPU control register.
        // The FSTP instruction POPS the value off the top of stack when moving it to
        // the destination location. It does this by incrementing the top of stack
        // pointer in the status register after accessing the data in ST0. If the
        // destination operand is a floating point register, the FPU stores the
        // value at the specified register number before popping the data off
        // the top of the stack.

        fstp( average ); // POP and store STO, the top of the FPU stack, into average     
        stdout.put
        (
            nl "The average so far in ", count, " test(s) with ",
            totScores, " marks out of ", totOutOf,
            " is ", average:7:1, "%" nl nl
        );

        repeat
       
            stdout.puts( "Another (y/n) ? " );
            stdin.flushInput();
            stdin.getc();           // recall returns char in 'al' register
            chars.toUpper( al );    // Converts 'y', 'n' to 'Y', 'N"

            if( al not in { 'Y', 'N' } ) then
                stdout.puts( "Only 'y' or 'n' accepted here ... " );
            endif;
           
        // NOTE: empty char is in every set ... so IS IN { 'Y', 'N' }
        until( !( al not in { 'Y', 'N' } ) );

    until( al = 'N' );

    stdout.put
    (
        nl "The FINAL AVERAGE IS ", average:7:1, "% in ", count,
        " test(s) with ", totScores, " marks out of ", totOutOf, "." nl
    );
   
end realMath3;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 03:52:43 PM
Chapter 12: Pointers, Strings, my own Types, Records, Arrays, and dynamic things on the fly

 

1.  Create (md) a sub-directory in the project folder.  Give it the name Chapt12_records

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program file the name records.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run the program.

Code: [Select]
program records;

#include( "stdlib.hhf" )

const   
    MaxCount:   int32:= 3; // to keep testing short/simple

type
    MyContact: record
                    theName:string;
                    thePhone:string;
                endrecord;
             
static
    MyBBook: MyContact[ MaxCount ];

 

// tot.num of contacts returned in ecx
procedure getBook; @nodisplay; @returns("ecx");

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    begin takeIn;
        stdout.put( message, ":  " );
        stdin.flushInput();
        stdin.a_gets(); // now eax holds the address of the string just entered
    end takeIn;

begin getBook;

    mov( 0, ecx );
    while( ecx < MaxCount ) do
   
        mov( @size( MyContact ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContact )

        // recall takeIn( .. ) returns a pointer to the string in eax
        mov( takeIn( "Enter name  " ), MyBBook.theName[ebx] );
        mov( takeIn( "Enter phone " ), MyBBook.thePhone[ebx] );
        inc( ecx );

        stdout.puts( "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif ( al == 'n' || al == 'N' );
    endwhile;
   
end getBook;

 

procedure printBook; @nodisplay; // Note: assumes ecx holds size of array

const // text string composed of nl and 2 tabs
    nlTab2: text:="nl stdio.tab stdio.tab";   

begin printBook;

    for( mov( 0, ecx ); ecx < edx ; inc( ecx ) ) do

        mov( @size( MyContact ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContact )
        stdout.puts( nlTab2 ); stdout.puts( MyBBook.theName[ebx] );
        stdout.puts( nlTab2 ); stdout.puts( MyBBook.thePhone[ebx] );
        stdout.newln();

    endfor;

end printBook;

 
begin records;

    getBook();          // returns number of contacts in ecx
    mov( ecx, edx );    // edx now holds the tot.num of contacts,
   
    stdout.puts( nl "Your 'book'  :" );
    printBook();        // value in edx ready for next procedure called
    stdout.put( nl "Note! The size of each MyContact, @size(MyContact) = " );
    stdout.putu32( @size( MyContact ) );
    stdout.put
    (
        ", since each of the" nl
        "2 strings in the record 'MyContact' is really only a 4 byte pointer." nl
    );

    stdin.readLn();

end records;


So … what has been happening above?
 
1.  We defined our own type of variable and gave it the name myContacts.

2.  We further defined myContacts to be a record of two strings.  Now since HLA strings are really pointers to the (address of the) first byte in that string, and as you may recall addresses in HLA are 4 bytes or 32 bits, thus each ‘pointer’ takes 4 bytes … and thus each record of 2 pointers takes 8 bytes.

3.  But there is more … Each string was given enough memory to hold its (allocated memory) by the stdin.a_gets() HLA library function. The ‘a_’ in the function call indicates that … and so sufficient memory was allocated and a pointer (i.e. the address) to that memory was returned in eax, by that HLA stdlib call.

4.  So here we are allocating memory on the fly … cool eh?

5.  Cool as long as we don’t run out. (We can free it when we don’t need it - look this up - and see str.free( ..) used in last example here.)

6.  Note how we access the parts of a record with the dot operator, for example: ‘myBBook.theName[0]’ … (i.e. ebx = 0) …  refers to the base address of the array myBBook and the ‘.theName’ would be with NO-offset from there, whereas the ‘.thePhone’ would have a 4-byte-in offset from that referenced address.

7.  The next record in would be myBBook.theName[8], i.e. 8-bytes-in … and with respect to there, the ‘.theName’ would be the 4 bytes right there, whereas the ‘.thePhone’ would fetch the next 4 bytes in … and so on. This is why we need to step though the array, using the size in bytes of each record. In this case 8 bytes.  See how this was done using these two commands:  mov( szContact, ebx ); intmul( ecx, ebx ); Note that, for example,  intmul( ecx, ebx ) allows one to multiple ebx BY ecx with the answer put into ebx. Thus … myBBook.theName[ebx] gives each base address in as ebx steps through 0, 8, 16, … The ‘.theName’ or the ‘.thePhone’ gives the ‘offset’ from there.


Now ...the above, but without using GLOBAL variables ...

Code: [Select]
program records; // demo using NO global var's //

#include( "stdlib.hhf" )

type
    MyContact:  record
                    theName:string;
                    thePhone:string;
                endrecord;
               
    pMyContact: pointer to MyContact;
   

// tot.num of contacts returned in ecx
procedure getBook( pC: pMyContact in ebx; size: int32 ); @nodisplay; @returns("ecx");

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    begin takeIn;
        stdout.put( message, ":  " );
        stdin.flushInput();
        stdin.a_gets(); // now eax holds the address of the string just entered
    end takeIn;

begin getBook;

    mov( 0, ecx );
    while( ecx < size ) do
   
        mov( @size( MyContact ), edx );
        intmul( ecx, edx ); // edx := ecx*@size( MyContact )

        // recall takeIn( .. ) returns a pointer to the string in eax
        mov( takeIn( "Enter name  " ), ( type string [ebx+edx] ) );
        add( @size(MyContact.theName),  edx );
        mov( takeIn( "Enter phone " ), ( type string [ebx+edx] ) );
        inc( ecx );

        stdout.puts( "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif ( al == 'n' || al == 'N' );
    endwhile;
   
end getBook;

 

procedure printBook( pC: pMyContact in ebx; size: int32  ); @nodisplay;

const // text string composed of nl and 2 tabs
    nlTab2: text:="nl stdio.tab stdio.tab";

begin printBook;

    for( mov( 0, ecx ); ecx < size ; inc( ecx ) ) do

        mov( @size( MyContact ), edx );
        intmul( ecx, edx ); // edx := ecx*@size( MyContact )
        stdout.puts( nlTab2 ); stdout.puts( ( type string [ebx+edx]  ) );
        add( @size(MyContact.theName), edx );
        stdout.puts( nlTab2 ); stdout.puts( ( type string [ebx+edx] ) );
        stdout.newln();

    endfor;

end printBook;


procedure mainProc; @nodisplay;

const   
    MaxCount:   int32:= 3; // to keep testing short/simple

static
    MyBBook: MyContact[ MaxCount ];
    size: int32;
   
begin mainProc;

    getBook( &MyBBook, MaxCount ); // returns number of contacts in ecx
    mov( ecx, size );
   
    stdout.puts( nl "Your 'book'  :" );
    printBook( &MyBBook, size );
    stdout.put( nl "Note! The size of each MyContact, @size(MyContact) = " );
    stdout.putu32( @size( MyContact ) );
    stdout.put
    (
        ", since each of the" nl
        "2 strings in the record 'MyContact' is really only a 4 byte pointer." nl
    );

    stdin.readLn();


end mainProc;


begin records;

    mainProc();

end records;


Or see this ... with some data input validation:

Code: [Select]
program records3;

#include( "stdlib.hhf" )

const 
    MaxCount:   int32 :=    3; // to keep testing short/simple

type
    MyContacts: record
                    theName:    string;
                    thePhone:   string;
                endrecord;

static
    MyBBook:    MyContacts[ MaxCount ];

         
// count of contacts entered returned in ecx ...
procedure getBook( maxSize:int32 ); @nodisplay; @returns("ecx");

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    var
        s:    string;
    begin takeIn;
        forever
            stdout.put( message, ":  " );
            stdin.flushInput();
            stdin.a_gets();
            stdout.put("You input '", (type string eax), "' ... Ok (y/n) ? " );
            mov( eax, s ); // get a copy of pointer into s ...
            stdin.getc();
            if( al == 'y' || al == 'Y' ) then
                mov( s, eax );
                break;
            else str.free( s );
            endif;
        endfor;
    end takeIn;

begin getBook;

    mov( 0, ecx );
    while( ecx < maxSize ) do

        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )

        mov( takeIn( "Enter name   " ), MyBBook.theName[ebx] );
        mov( takeIn( "Enter phone  " ), MyBBook.thePhone[ebx] );
        inc( ecx );

        stdout.puts( "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif ( al == 'n' || al == 'N' );

    endwhile;

end getBook;


procedure printBook( numRecs:int32 ); @nodisplay;

const // text string composed of nl and 2 tabs
    nlTab2: text:="nl stdio.tab stdio.tab";   

begin printBook;

    for( mov( 0, ecx ); ecx < numRecs; inc( ecx ) ) do

        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // now ebx := ecx*@size( MyContacts )
   
        stdout.puts( nlTab2 ); stdout.puts( MyBBook.theName[ebx] );
        stdout.puts( nlTab2 ); stdout.puts( MyBBook.thePhone[ebx] );
        stdout.newln();
    endfor;
           
end printBook;




begin records3;

    getBook( MaxCount );  // recall, returns the record count in ecx

    stdout.puts( nl "Your 'book'  :" );
    printBook( ecx ); // recall, ecx holds number of records ...

    stdout.put
    (
        nl "Note! The size of each MyContacts, @size(MyContacts) = "
    );
    stdout.putu32( @size(MyContacts) );
    stdout.put
    (
        ", since each of the" nl
        "2 strings in the record 'MyContacts' is really only a "
        "4 byte pointer ... " nl nl
        "Press 'Enter' to quit ... "
    );
   
    stdin.readLn();

end records3;


For further reference on HLA strings, see ... HLA strings …

http://216.92.238.133/Webster/www.artofasm.com/AoAExtra/HLAStrs.html


Also ...

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/CharacterStringsa2.html



2.6 The HLA String Module and Other String-Related Routines ...


And a little further on down the first page was ( a link to an other HLA user site that has backed up some AoA info - But .... the link is no longer available ...The info was copied here for easy reference.)



Chapter Five Records, Unions, and Name Spaces

5.1 Chapter Overview

This chapter discusses how to declare and use record (structures), unions, and name spaces in your programs. After strings and arrays, records are among the most commonly used composite data types; indeed, records are the mechanism you use to create user-defined composite data types. Many assembly language programmers never bother to learn how to use records in assembly language, yet would never consider not using them in high level language programs. This is somewhat inconsistent since records (structures) are just as useful in assembly language programs as in high level language programs. Given that you use records in assembly language (and especially HLA) in a manner quite similar to high level languages, there really is no reason for excluding this important tool from your programmer's tool chest. Although you'll use unions and name spaces far less often than records, their presence in the HLA language is crucial for many advanced applications. This brief chapter provides all the information you need to successfully use records, unions, and name spaces within your HLA programs.

5.2 Records

Another major composite data structure is the Pascal  record or C/C++  structure 1  . The Pascal terminology is probably better, since it tends to avoid confusion with the more general term  data structure. Since HLA uses the term "record" we'll adopt that term here.

Whereas an array is homogeneous, whose elements are all the same, the elements in a record can be of any type. Arrays let you select a particular element via an integer index. With records, you must select an element (known as a  field) by name.

The whole purpose of a record is to let you encapsulate different, but logically related, data into a single package. The Pascal record declaration for a student is probably the most typical example:

Code: [Select]
student =

 record

 Name: string [64];

 Major: integer;

 SSN: string[11];

 Midterm1: integer;

 Midterm2: integer;

 Final: integer;

 Homework: integer;

 Projects: integer;

 end;


Most Pascal compilers allocate each field in a record to contiguous memory locations. This means that Pascal will reserve the first 65 bytes for the name 2 , the next two bytes hold the major code, the next 12 the Social Security Number, etc.

In HLA, you can also create structure types using the RECORD/ENDRECORD declaration. You would encode the above record in HLA as follows:

Code: [Select]
type

 student: record

 Name: char[65];

 Major: int16;

 SSN: char[12];

 Midterm1: int16;

 Midterm2: int16;

 Final: int16;

 Homework: int16;

 Projects: int16;

endrecord;


As you can see, the HLA declaration is very similar to the Pascal declaration. Note that, to be true to the Pascal declaration, this example uses character arrays rather than strings for the  Name and  SSN (U.S Social Security Number) fields. In a real HLA record declaration you'd probably use a string type for at least the name (keeping in mind that a string variable is only a four byte pointer).

The field names within the record must be unique. That is, the same name may not appear two or more times in the same record. However, all field names are local to that record. Therefore, you may reuse those field names elsewhere in the program.

The RECORD/ENDRECORD type declaration may appear in a variable declaration section (e.g., STATIC or VAR) or in a TYPE declaration section. In the previous example the  Student declaration appears in the TYPE section, so this does not actually allocate any storage for a  Student variable. Instead, you have to explicitly declare a variable of type  Student. The following example demonstrates how to do this:  (Click on the above link to see graphics and the rest ...)


Also here is a good place to start looking for an answer to any HLA How do I code for ... type question:

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/AoATOC.html


For a little fun assignment, write a short HLA program, using the above student record type ... and output the record size.  ( Hint: use the HLA function @size( student ); )  Does your output agree with the bytes you added up for the record in your head?  (Recall int16 uses 2 bytes.)


Here is a little demo program, but don’t look until you have tried your own.

Code: [Select]
program studentRec;

#include( "stdlib.hhf" )

type
    student:    record

                    // NOTE! 'Name' is a reserved word, so used Fullname

                    Fullname:       char[68];
                    Major:          int16;
                    SSN:            char[12];
                    Midterm1:       int16;
                    Midterm2:       int16;
                    Final:          int16;
                    Homework:       int16;
                    Projects:       int16;

                endrecord;
               
static
    stRecSize:  int32:= @size ( student );  // figured out at compile time
    i32:        int32;

begin studentRec;

            mov( @size( student ), eax );
            mov( eax, i32 );                    // figured out at run time
            stdout.put
            (
                        "The number of bytes in each student record here is : ", i32,
                        nl "stRecSize is : ", i32, nl "Yep! It is : "
            );

            // The HLA compiler/assembler can recognize this value here ...
            // It is inside a procedure/function call & not the stdout.put(..) macro.
            // '@size ( student )' is replaced by 'its value' at compile time
            stdout.puti32( @size ( student ) );
           
end studentRec;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 04:32:14 PM
Chapter 13: The Computer files its Records



1.  Create (md) a sub-directory in the project folder.  Give it the name Chapt13_fileRecords

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program file the name fileRecords.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run the program.


Notice that we are starting out with the same program with which we ended in the previous chapter. For a simple start … we will just add … and then let the program always call a procedure to file the records at the end, before exiting. (Later, we will add another procedure to read these records into an array of records, when we first run our program, if there is an existing file, that is … with records to read.)


Here is a simple ‘pattern’ (to guide us), from AoA, of the HLA functionality we wish to add:

Code: [Select]
program simpleFileOutput;

#include( "stdlib.hhf" )

 
static
    outputHandle:   dword;

           

begin simpleFileOutput;

    fileio.openNew( "myfile.txt" );
    mov( eax, outputHandle );

    for( mov( 0, ebx ); ebx < 10; inc( ebx ) ) do
        fileio.put( outputHandle, ( type uns32 ebx ), nl );
    endfor;

    fileio.close( outputHandle );

end simpleFileOutput;


Ok ... here is out first program to demo how to file our Records ...

Code: [Select]
program fileRecords;
 
#include( "stdlib.hhf" )
 
const 
    MaxCount:   int32 :=    3; // to keep testing short/simple
    FNAME:      text :=     """records.dat""";

type
    MyContacts: record
                    theName:    string;
                    thePhone:   string;
                endrecord;

static
    MyBBook:    MyContacts[ MaxCount ];

         
// count of contacts entered returned in ecx ...
procedure getBook( maxSize:int32 ); @nodisplay; @returns("ecx");

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    var
        s:    string;
    begin takeIn;
        forever
            stdout.put( message, ":  " );
            stdin.flushInput();
            stdin.a_gets();
            stdout.put("You input '", (type string eax), "' ... Ok (y/n) ? " );
            mov( eax, s ); // get a copy of pointer into s ...
            stdin.getc();
            if( al == 'y' || al == 'Y' ) then
                mov( s, eax );
                break;
            else str.free( s );
            endif;
        endfor;
    end takeIn;

begin getBook;

    mov( 0, ecx );
    while( ecx < maxSize ) do

        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )

        mov( takeIn( "Enter name   " ), MyBBook.theName[ebx] );
        mov( takeIn( "Enter phone  " ), MyBBook.thePhone[ebx] );
        inc( ecx );

        stdout.puts( "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif ( al == 'n' || al == 'N' );

    endwhile;

end getBook;

procedure printBook( numRecs:int32 ); @nodisplay;
begin printBook;

    for( mov( 0, ecx ); ecx < numRecs; inc( ecx ) ) do

        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // now ebx := ecx*@size( MyContacts )
        stdout.put( stdio.tab, MyBBook.theName[ebx]:-20, " ", MyBBook.thePhone[ebx], nl )

    endfor;
           
end printBook;
 
procedure fileBook( numRecs:int32 ); @nodisplay;
var
    outFileHandle:  dword;

begin fileBook;
    try
        fileio.openNew( FNAME );
        mov( eax, outFileHandle );
        for( mov( 0, ecx ); ecx < numRecs; inc( ecx ) ) do
            mov( @size( MyContacts ), ebx );
            intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )
            fileio.put( outFileHandle, MyBBook.theName[ebx], nl );
            fileio.put( outFileHandle, MyBBook.thePhone[ebx], nl );
        endfor;
        fileio.close( outFileHandle );
    anyexception
        stdout.put( "There was some problem opening file ", FNAME, " for output." );
    endtry;
end fileBook;
 
 
begin fileRecords;
 
    getBook( MaxCount );    // recall, returns the record count in ecx
    stdout.puts( nl "Your 'book' ..." nl );
    printBook( ecx );
    fileBook( ecx );
    stdout.put( nl, (type int32 ecx),  " records were filed.  Press 'Enter' to exit ... " );
    stdin.readLn();

end fileRecords;


To continue, click on the '2' icon for page '2' ... in the the lower left window.
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 05:13:08 PM
Chapter 14: The Computer reads its Files


 
1.  Create (md) a sub-directory in the project folder.  Give it the name Chapt14_readFile

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program file the name readFile.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run the program.


Notice that we are again starting out with the same program with which we ended in the previous chapter. For a simple start ... we will just add to it.  We will add another procedure, inputBook(), to read these records into an array of records, when we first run our program, (if there is an existing file, that is ... with records to read.)  Then we will just show them, with a little fancier formatting then before. (Check it out.)

BUT … if the records.dat file does NOT exist in the default directory, i.e. our working folder, we will just report that possibility and then ask if the user wishes to start a new one.  If so, we can just call our previously defined procedure getBook() ... Let’s give it a different name of newBook().  However we must not forget to then, right away, write these new records to the disk.  To do so … we just call the procedure we made in the last chapter: fileBook( .. ).  Of course, we must pass to it the number of elements to file.  No problem.  We just pass along the value in the ecx register from the previous function call of getBook(), which returned the number of contacts input from the keyboard in the ecx register.

NOTE:  In our programs we have NOT been specifying any path to the file that we write to or read from the disk. Thus, the .exe file just then reads/writes its data files from/to the default working directory ... which is the same as the folder that we have just made ... the folder where we have been putting each chapter’s files.


Here then, is our next step in this mini data base type program:
 
Code: [Select]
program readFile;

#include( "stdlib.hhf" )

const 
    MaxCount:   int32 := 100; // to allow for a sufficient? number of MyContacts
    FNAME:      text  :=  """contacts.dat"""; // each """ includes one " in output

type
    MyContacts: record
                    theName:    string;
                    thePhone:   string;
                endrecord;

static
    MyBBook:    MyContacts[ MaxCount ]; // get array space for MaxCount MyContacts

 
// tot.num of contacts returned in ecx
procedure newBook( maxSize:int32 ); @nodisplay; @returns("ecx");

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    var
        s:  string;
    begin takeIn;

        forever
            stdout.put( message, ":  " );
            stdin.flushInput();
            stdin.a_gets();
            stdout.put("You input ", (type string eax), " ok (y/n) ? " );
            mov( eax, s );
            stdin.getc();
            if( al == 'y' || al == 'Y' ) then
                mov( s, eax );
                break;
            else str.free( s );
            endif;
        endfor;

    end takeIn;

begin newBook;

    mov( 0, ecx );
    while( ecx < maxSize ) do
   
        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )
        mov( takeIn( "Enter name   " ), MyBBook.theName[ebx] );
        mov( takeIn( "Enter phone  " ), MyBBook.thePhone[ebx] );
        inc( ecx );
       
        stdout.puts( nl "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif( al == 'n' || al == 'N' );
       
    endwhile;

end newBook;


// returns count of records written to file in ecx ...
procedure fileBook( numRecs:int32 ); @nodisplay; @returns( "ecx" );
var
    outFileHandle:  dword;
   
begin fileBook;

    try
        fileio.openNew( FNAME ); // overwrites any existing file
        mov( eax, outFileHandle );
        for( mov( 0, ecx ); ecx < numRecs; inc( ecx ) ) do
            mov( @size( MyContacts ), ebx );
            intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )
            fileio.put( outFileHandle, MyBBook.theName[ebx], nl );
            fileio.put( outFileHandle, MyBBook.thePhone[ebx], nl );
        endfor;
        fileio.close( outFileHandle );
    exception( ex.FileOpenFailure )
        stdout.put( "There was a problem opening file ", FNAME, " for output." nl );
    endtry;

end fileBook;


// returns count of records read from file in ecx ...
procedure inputBook( maxSize:int32 ); @nodisplay; @returns( "ecx" );
var
    inFileHandle:   dword;

begin inputBook;

    try

        fileio.open( FNAME, fileio.r );         // open file for reading
        mov( eax, inFileHandle );

        mov( 0, ecx );                          // initialize counter ...
        while( !fileio.eof( inFileHandle) ) do
       
            mov( @size( MyContacts ), ebx );
            intmul( ecx, ebx );                 // ebx := ecx*@size( MyContacts )

            // allocate space for new strings and
            // move pointers into array (of pointers)
            fileio.a_gets( inFileHandle);       // returns new string in eax
            mov( eax, MyBBook.theName[ebx] );   // store in array of pointers
            fileio.a_gets( inFileHandle);
            mov( eax, MyBBook.thePhone[ebx] );
            inc( ecx );                         // increment contact count
           
        endwhile;
        fileio.close( inFileHandle );

    exception( ex.FileOpenFailure )

        stdout.puts
        (
            nl "There was some problem reading your file. "
            "Perhaps it doesn't exist?"
            nl "Do want to start a new contact book (y/n) ? "
        );

        stdin.getc();
        if( al = 'y' || al = 'Y' ) then
            newBook( maxSize ); // recall ... returns size in ecx
            fileBook( ecx );
        else
            mov( 0, ecx );
        endif;

    endtry;
   
end inputBook;


procedure printBook( numRecs:int32 ); @nodisplay;
begin printBook;

    // a little different formatting ...
    stdout.puts
    (
        nl "Your 'book'  :  __________________________________________________" nl
    );

    for( mov( 0, ecx ); ecx < numRecs; nop() ) do // nop() as inc(ecx) inside loop
        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )\

        inc( ecx );
        stdout.puts( nl stdio.tab stdio.tab );
        stdout.putu32Size( ecx, 3, '0' ); // 3 spaces and front pad with zeros
        stdout.put( ": ", MyBBook.theName[ebx]:-20 );
        stdout.puts( " ---> " );
        stdout.put( MyBBook.thePhone[ebx] );
    endfor;

end printBook;



begin readFile;

    inputBook( MaxCount ); // recall ... returns the record count in ecx
    printBook( ecx );
    stdout.put( nl nl "Total contacts now in memory = ", (type int32 ecx),
                ".  Press 'Enter' to exit ... " );
    stdin.readLn();

end readFile;


Some things to note regarding the above program:

 •  If you were to open up the contacts.dat file with a text editor like MS Notepad.exe, you would notice that each field is on a new line, since that is the way we asked the program to write each string to the file in our procedure fileBook( recCount )  … as per the nl at the end of each fileio.put( outFileHandle, myBBook.thePhone[ebx], nl );

•  So when we read back from the file, we can read each field into a newly allocated string and then store the pointer to that new string, (the new string that on the fly was allocated with sufficient bytes to hold the characters in the field just read from the file), in the appropriate offset in our array of records, (which we, before compiling), set to a maximum of 100 …


Code: [Select]
// store next string from file-with-named-handle in newly allocated memory

fileio.a_gets( inFileHandle);  // and return pointer to that memory in eax

 
// ebx holds previously calculated offset into next record in array myBBook

mov( eax, myBBook.theName[ebx] );  // store new address in array of addresses

•  So with the fileio.a_gets( inFileHandle) call, the strings are individually allocated in memory as input, and the new address to each new chunk of memory that holds the characters in that string, is then stored into the next spot in our array.  Since presently, (in 2007), HLA addresses are 32 bits, (i.e. 4 bytes), all we need to reserve ahead of compile time, is 4 bytes for each string in our array, even though while the program is running, we could conceivable allocate 100’s of bytes further to hold the characters of each string then input.

Thus, not so much computer memory space is wasted, just reserving 4 bytes for each pointer ahead of time, if we don’t actually input all those strings allowed by our maxCount of 100 in our program.

•  We could also mem.alloc( numBytes) space for our array of records, (here, of pointers), on the fly, i.e. dynamically, while the program is executing.

•  Note: the older HLA style of mem.alloc was malloc, ... of str.alloc was stralloc and of mem.free( pointer ) was free( pointer ), ... of str.free( p ) was strfree( p)


Note that the older malloc and stralloc types are used in this link:

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/ConstsVarsAndDataTypes2.html

 

Copied here for reference ...(original link no longer available.)

16 The File I/O Module (fileio.hhf)

--------------------------------------------------------------------------------

The file I/O functions are quite similar to the file class functions except that you explicitly pass a file handle to these routines rather than invoking a method via a file class variable. In fact, the file class methods call the corresponding fileio functions whenever you invoke a file object's methods. Therefore, if you want your programs to be a little smaller, you should use the fileio functions rather than the file class package.

16.1 General File I/O Functions

Here are the file output routines provided by the HLA fileio unit:

fileio.open( FileName: string; Access:dword ); @returns( "eax" );


The fileio.open routine opens the file by the specified name. The Access parameter is one of the following:

•  fileio.r

•  fileio.w

•  fileio.rw

•  fileio.a


The fileio.r constant tells HLA to open the file for read-only access. The fileio.w constant tells HLA to open the file for writing. Using the fileio.rw constant tells fileio.open to open the file for reading and writing. The fileio.a option tells the fileio.open function to open the file for writing and append all written data to the end of the file.

This routine raise an exception if there is a problem opening the file (e.g., the file does not exist). If the file is successfully opened, this function returns the file handle in the EAX register.

fileio.openNew( FileName: string ); @returns( "eax" );


This function opens a new file for writing. The single parameter specifies the file's (path) name. This function raises an exception if there is an error opening the file. If the file is opened successfully, this function returns the file handle in the EAX register. If the file already exists, this function will successfully open the file and delete any existing data in the file.

fileio.close( Handle:dword );


14 Exceptions (excepts.hhf)

--------------------------------------------------------------------------------

The exceptions units contains several things of interest. First, it defines the ExceptionValues enumerated data type that lists out all the standard exceptions in the HLA Standard Library. The second thing provided in the excepts unit is the ex.PrintExceptionError procedure which prints a string associated with the exception number in EAX. Next, the excepts.hhf header file defines the "assert( expr )" macro. Finally,  …

14.1.7 ex.BadFileHandle (6)

The file class and fileio library modules raise this exception if you attempt to read from or write to a file with an illegal file handle (i.e., the file has not been opened or has already been closed).

14.1.8 ex.FileOpenFailure (7)

The HLA file open routines raise this error if there was a catastrophic error opening a file.

14.1.9 ex.FileCloseError ( 8 )

The HLA file close routines raise this error if there was an error closing a file.

14.1.10 ex.FileWriteError (9)

The HLA Standard Library file output routines raise this exception if there is an error while attempting to write data to a file. This is usually a catastrophic error such as file I/O or some hardware error.

14.1.11 ex.FileReadError (10)

The HLA Standard Library file output routines raise this exception if there is an error while attempting to read data from a file. This is usually a catastrophic error such as file I/O or some hardware error.

14.1.12 ex.DiskFullError (11)

The HLA Standard Library raises this exception if you attempt to write data to a disk that is full.

14.1.13 ex.EndOfFile (12)

The HLA Standard Library file I/O routines raise this exception if you attempt to read data from a file after you've reached the end of file. Note that HLA does not raise this exception upon reaching the EOF. You must actually attempt to read beyond the end of the file. …

 
15 File Class (fileclass.hhf)

--------------------------------------------------------------------------------

The HLA Standard Library provides a file class that simplifies file I/O. The name of this class is file and you should declare all objects to be of this type or a pointer to this type, e.g.,

var
        MyOuputFile: file;
        filePtr:     pointer to file;


Once you declare a file variable, you access the remaining methods, procedures, and fields in the file class by specifying the file variable name and a period as a prefix to the field name.

Note: HLA also provides a fileio library module that does file I/O using traditional procedures rather than class objects. If you're more comfortable using such a programming paradigm, or you prefer your code to be a bit more efficient, you should use the fileio module.

Warning: Don't forget that HLA objects modify the values in the ESI and EDI registers whenever you call a class procedure, method, or iterator. Do not leave any important values in either of these register when making calls to the following routines. If the use of ESI and EDI is a problem for you, you might consider using the fileio module that does not suffer from this problem.

Note: Although the file class is convenient to use and provides some nice features to object-oriented programming, the way that the classes work pretty much means that you will be linking in the entire file class if you use only a single method from the class. If you're trying to write a small program, you should use the fileio module rather than the file class.

15.1 General File Operations

filevar.create; @returns( "esi" );

file.create; @returns( "esi" );  [for dynamic objects]


The file class provides a file.create constructor which you should always call before making use of a file variable. For file variables (as opposed to file pointer variables), you should call this routine specifying the name of the file variable. For file pointer variables, you should call this routine using the class name and store the pointer returned in EAX into your file variable. For example, to initialize the two files in the previous example, you would use code like the following:

Code: [Select]
    MyOutputFile.create();

    file.create();

    mov( eax, filePtr );


Note that the file.create constructor simply initializes the virtual method table pointer and does other necessary internal initialization. The constructor does not open a file or perform other file-related activities.


filevar.handle; @returns( "eax" );

This method returns the file handle in the EAX register. The returned value is invalid if you have not opened the file. You can pass this handle value to any of the Standard Library file routines (e.g., fileio.putc) that expect a handle. You may also pass this value to Windows or Linux API functions that expect a file handle.


filevar.open( filename:string; access:dword )

This method opens an existing file. The filename parameter is a string specifying the name of the file you wish to open. The access parameter is one of the following:

•  fileio.r

•  fileio.w

•  fileio.rw

•  fileio.a


The fileio.r constant tells filevar.open to open the file for read-only access. The fileio.w constant tells filevar.open to open the file for writing. Using the fileio.rw constant tells fileio.open to open the file for reading and writing. The fileio.a option tells the filevar.open function to open the file for writing and append all written data to the end of the file.

Before accessing the data in a file, you must open the file (which initializes the file handle). The filevar.open and filevar.openNew methods are excellent tools for this purpose. You may also open the file using direct calls to the Windows or Linux API, but you must initialize the filevar.fileHandle field of the class variable before making any other method calls in the file class.


filevar.openNew( filename:string )


This function opens a new file for writing (if the file already exists, it is first deleted and then a new file is opened for writing). The file is given the "normal" attribute.

Before accessing the data in a file, you must open the file (which initializes the file handle). The filevar.open and filevar.openNew methods are excellent tools for this purpose. You may also open the file using direct calls to the Windows or Linux API, but you must initialize the filevar.fileHandle field of the class variable before making any other method calls in the file class.

filevar.close;

This method closes a file opened via file.Open or file.OpenNew and flushes any buffered data to the disk.

Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 06:16:48 PM
Now for a little educational fun to finish off this chapter ...

Code: [Select]
// checkerBoard.hla //

// Modified from a program found on the web mid 2007

// A good illustration of NESTED LOOPs ...
// Also illustrates HLA MODular division.
// But here, dividing by an even number, we can simply
// and faster CHECK if the last BIT(s) = 0 to see if
// the number itself divides, (with a zero remainder),
// by 2 ... or an other even number.

 // Adapted to HLA and using HLA console COLOURS

program cb;

#include( "stdlib.hhf" )

static
    c:  char := 'x';
    i:  uns32;
    j:  uns32;
    k:  uns32;
     
begin cb;

      stdout.puts( nl stdio.tab "Checkers ?" nl nl  );
     
      for( mov(1, i); i <= 16; inc(i) ) do
            for( mov(0, j); j < 8; inc(j) ) do
                for( mov(0, k); k < 3; inc(k) ) do

                    // Change foreground colour to red,
                    // background to black.

                    if( c = 'x' ) then
                         console.setAttrs( console.red, console.black );
                    else
                         console.setAttrs( console.white, console.black );
                    endif;

                    stdout.put(c);
                   
                endfor;

                if( c = 'x') then
                    mov( 'o', c );
                else
                    mov( 'x', c );
                endif;
            endfor;

            stdout.newln();

            // ----------------------------------
            // an example of HLA MODular DIVision ...
            // ----------------------------------

            mov( 0, edx ); // initialize to zero
            mov( i, eax );
            imod( 2, edx:eax ); // returns "edx"
            if( edx = 0 ) then  // if( (i mod 2) = 0 ) then
           
                if( c = 'x' ) then
                    mov( 'o', c );
                else
                    mov( 'x', c );
                endif;
               
            endif;
        endfor;

    // Change foreground colour to cyan, background to blue

    console.setAttrs( console.cyan, console.blue );
    stdout.puts( "Press 'Enter' to exit ... " );
    stdin.readLn();
    console.cls();

    stdout.puts( nl stdio.tab "Checkers ?" nl nl  );

    for( mov(1, i); i <= 16; inc(i) ) do // start count at one so  2nd / 2 = 0
        for( mov(0, j); j < 8; inc(j) ) do
            for( mov(0, k); k <3; inc(k) ) do
           
                // Change foreground colour to red,
                // background to black.

                if( c = 'x' ) then
                    console.setAttrs( console.red, console.black );
                else
                    console.setAttrs( console.white, console.black );
                endif;

                stdout.put(c);

            endfor;

            if( c = 'x') then mov( 'o', c ); else mov( 'x', c ); endif;
           
        endfor;

        stdout.newln();
       
        // --------------------------------------------------------
        // demo HLA MODular DIVision by an even number USING A MASK
        // --------------------------------------------------------

        mov( i, eax );
        and( 1, eax ); // MASKs out all bits except lowest in eax
        if( eax = 0 ) then  // i.e. if( (i mod 2) = 0 ) then
            if( c = 'x') then mov( 'o', c ); else mov( 'x', c ); endif;
        endif;
    endfor;

    // Change foreground colour to cyan, background to blue
   
    console.setAttrs( console.cyan, console.blue );
    stdout.puts( "Press 'Enter' to exit ... " );
    stdin.readLn();
   
end cb;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 17, 2013, 06:19:54 PM
Chapter 15: The Computer updates (edits, deletes, sorts, chops-duplicates-in) its files

 
 
1.   Create (md) a sub-directory in the project folder.  Give it the name Chapt15_updateFile

2.   Go (cd) to that new directory.

3.   Using your text editor, create the following program file in that folder. 
        Give the first program file here the name addToContacts.hla

4.   Compile the program and run it. Study the comments that are in the HLA program,
        as well as the output that appears on the screen when you run the program.

5.   We will we then add functions and make changes …
   

Notice that we are again starting out with the same program with which we ended in the previous chapter. For a simple start … we will just add to it.  We will add another procedure, showMenu() … and make a few other changes … (see comments in program)
 
Code: [Select]
program addToContacts;
 
// A MENU function 'showMenu' added ... also a name change of the
// 'newBook' function ... changed to 'updateBook' to make it more generic
// Note: If recCount=0 the first time called ... it is a 'new book' ...
// but later it is called with recCount=at_present_num to updateBook by
// adding more contacts
 
// Name of 'inputBook' function changed to 'inputBook_fromFile' to make it
// more descriptive of what it does.  Also fewer passed parameters in
// this ver. (Used global variable 'recCount' instead, for simplicity here.)
                       
 
#include( "stdlib.hhf" )
 
const 
    maxCount:   int32:= 100; // to allow for a sufficient? number of 'myContacts'

    cFileName:  text:=  """contacts.dat"""; // each """ includes one " in output

type
    myContacts: record
                    theName:    string;
                    thePhone:   string;
                endrecord;
static
           
    // special global variables utilized in program

    myBBook:    myContacts[ maxCount ];
    recCount:   int32 := 0; // initalized to 0 before contacts.dat file read
    done:       boolean := false;
 
// tot.num of contacts returned in ecx
procedure updateBook; @nodisplay; @returns("ecx");
var
    more:   boolean;

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    var
        s:          string;
        c:         char;
    begin takeIn;
        repeat
            stdout.put( message, ":  " );
            stdin.flushInput();
            stdin.a_gets();
            stdout.put("You input ", (type string eax), " ok (y/n) ? " );
            mov( eax, s );
            stdin.get( c );
            if( c = 'y' ) then mov( s, eax );
            else str.free( s );
            endif;
        until( c='y' );
    end takeIn;

begin updateBook;
    mov( recCount, ecx );
    mov( true, more );
    while( ( ecx < maxCount ) && more ) do
        mov( @size( myContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )
        mov( takeIn( "Enter name   " ), myBBook.theName[ebx] );
        mov( takeIn( "Enter phone  " ), myBBook.thePhone[ebx] );
        stdout.puts( nl "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        if ( al='n' ) then mov( false, more ); endif;
        inc( ecx );
    endwhile;
end updateBook;
 
 
procedure fileBook; @nodisplay;
var
    outFileHandle:  dword;

begin fileBook;
    fileio.openNew( cFileName ); // overwrites any existing file
    mov( eax, outFileHandle );
    for( mov( 0, ecx ); ecx < recCount; inc( ecx ) ) do
        mov( @size( myContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )
        fileio.put( outFileHandle, myBBook.theName[ebx], nl );
        fileio.put( outFileHandle, myBBook.thePhone[ebx], nl );
    endfor;
    fileio.close( outFileHandle );
end fileBook;
 
   
// returns count of records in file in ecx
procedure inputBook_fromFile; @nodisplay; @returns( "ecx" );
var
    inFileHandle:   dword;

begin inputBook_fromFile;
    try
        fileio.open( cFileName, fileio.r ); // open file for reading
        mov( eax, inFileHandle );

        mov( 0, ecx ); // initialize counter to zero
        while( !fileio.eof( inFileHandle) ) do
            mov( @size( myContacts ), ebx );
            intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )

            // allocate space for new string and
            // mov pointer into array (of pointers)
            fileio.a_gets( inFileHandle);     
            // returns new string in eax

            // mov pointer into array of pointers
            mov( eax, myBBook.theName[ebx] );

            fileio.a_gets( inFileHandle);
            mov( eax, myBBook.thePhone[ebx] );
            inc( ecx );                                // increment count of contacts
        endwhile;
        fileio.close( inFileHandle );

    exception( ex.FileOpenFailure )
        stdout.puts
        (
            nl "There was some problem reading your file. "
            "Perhaps it dosen't exist?"
            nl "Do want to start a new contact book (y/n) ? "
        );
        stdin.getc();

        if( al = 'y' || al = 'Y' ) then
            updateBook();
            mov( ecx, recCount ); // update global variable recCount
            fileBook();
        else
            mov( 0, ecx );
        endif;

    endtry;

end inputBook_fromFile;
 
 
 
procedure showBook; @nodisplay;
           
begin showBook;
    // a little different formatting ...
    console.cls();
    stdout.puts
    (
        nl "Your 'book'  :  __________________________________________________" nl
    );
    for( mov( 0, ecx ); ecx < recCount; inc( ecx ) ) do
        mov( @size( myContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )\

        stdout.puts( nl stdio.tab stdio.tab );
        inc( ecx ); // show 1,2,3... and not 0,1,2 ...
        stdout.putu32Size( ecx, 3, '0' );
        dec (ecx ); // restore to 0,1,2,...
        stdout.put( ": ", myBBook.theName[ebx]:-24 );

        stdout.puts( " ---> " );
        stdout.put( myBBook.thePhone[ebx]:15 );
    endfor;
    end showBook;
 
 
procedure showMenu; @nodisplay;
 
begin showMenu;
 
    showBook();
    stdout.put
    (
        nl nl "Total contacts now in memory = ", recCount, "."
        nl nl "Add new contacts (y/n) ? "
    );
    stdin.flushInput();
    stdin.getc();
    if( al = 'y' ) then
        updateBook();
        mov( ecx, recCount );   // update the global variable recCount
        fileBook();     
    else
        mov( true, done );      // done is also a global variable
    endif;

end showMenu;
 
 
 
begin addToContacts;

    inputBook_fromFile();  // recall ... returns the record count in ecx
    mov( ecx, recCount ); // update global variable recCount                             

    repeat
        showMenu();
    until( done );

end addToContacts;

 
 
Some things to note:

* The menu here is just a start … it will be expanded as we add more functions.

* We need to watch that the values of the registers outside a procedure call don’t get messed up inside a procedure call … (if we need to keep that register value for future use. The last program in this set will show one way to do that so you don’t have to keep a complete mental picture of all the registers you are using for each purpose.)
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 19, 2013, 10:53:51 AM
Here is the next step ...



Code: [Select]
program editContacts;
 
// 'editContact' function added
// The 'nested' function 'takeIn' was made global to allow it to be
// re-used ... NOW it is called from more then just that one procedure.
 
// Recall that procedures, (variables, etc.), must be defined, (in
// appropriate scope), BEFORE they can be used in a program.
 
   
#include( "stdlib.hhf" )
 
const 
    maxCount:   int32 := 100; // to allow for a sufficient? number of 'myContacts'

    cFileName:  text := """contacts.dat"""; // each """ includes one " in output

type
    myContacts: record
                    theName:    string;
                    thePhone:   string;
                endrecord;
static

// special global variables utilized in program (to keep it simple here)

    myBBook:    myContacts[ maxCount ];
    recCount:   int32:= 0; // initalized to zero before contacts.dat file is read
    done:       boolean:= false;

 
procedure takeIn( message:string ); @nodisplay; @returns("eax");
 
var
    s:  string;
    c:  char;
begin takeIn;
    repeat
        stdout.put( message, ":  " );
        stdin.flushInput();
        stdin.a_gets();
        stdout.put("You input ", (type string eax), " ok (y/n) ? " );
        mov( eax, s );
        stdin.get( c );
        if( c = 'y' ) then mov( s, eax );
        else str.free( s );
        endif;
    until( c='y' );
end takeIn;
 
   
// tot.num of contacts returned in ecx
procedure updateBook; @nodisplay; @returns("ecx");
var
            more:   boolean;
 
begin updateBook;
    mov( recCount, ecx );
    mov( true, more );
    while( ( ecx < maxCount ) && more ) do
        mov( @size( myContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )
        mov( takeIn( "Enter name   " ), myBBook.theName[ebx] );
        mov( takeIn( "Enter phone  " ), myBBook.thePhone[ebx] );
        stdout.puts( nl "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        if ( al='n' ) then mov( false, more ); endif;
        inc( ecx );
    endwhile;
end updateBook;
 
 
procedure fileBook; @nodisplay;
var
    outFileHandle:  dword;

begin fileBook;
    fileio.openNew( cFileName ); // overwrites any existing file
    mov( eax, outFileHandle );
    for( mov( 0, ecx ); ecx < recCount; inc( ecx ) ) do
        mov( @size( myContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )
        fileio.put( outFileHandle, myBBook.theName[ebx], nl );
        fileio.put( outFileHandle, myBBook.thePhone[ebx], nl );
    endfor;
    fileio.close( outFileHandle );
end fileBook;
 
 
// returns count of records in file in ecx
procedure inputBook_fromFile; @nodisplay; @returns( "ecx" );
var
            inFileHandle:    dword;
 
begin inputBook_fromFile;
    try
        fileio.open( cFileName, fileio.r ); // open file for reading
        mov( eax, inFileHandle );

        mov( 0, ecx ); // initialize counter to zero
        while( !fileio.eof( inFileHandle) ) do
            mov( @size( myContacts ), ebx );
            intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )

            // allocate space for new string and
            // mov pointer into array (of pointers)
            fileio.a_gets( inFileHandle);     
            // returns new string in eax

            // mov pointer into array of pointers
            mov( eax, myBBook.theName[ebx] );
            fileio.a_gets( inFileHandle);
            mov( eax, myBBook.thePhone[ebx] );
            inc( ecx ); // increment count of contacts
        endwhile;
        fileio.close( inFileHandle );

    exception( ex.FileOpenFailure )
        stdout.puts
        (
            nl "There was some problem reading your file. "
            "Perhaps it dosen't exist?"
            nl "Do want to start a new contact book (y/n) ? "
        );
        stdin.getc();

        if( al = 'y' || al = 'Y' ) then
            updateBook();
            mov( ecx, recCount ); // update global variable recCount
            fileBook();
        else
            mov( 0, ecx );
        endif;

    endtry;

end inputBook_fromFile;
 
 
procedure showBook; @nodisplay;
           
begin showBook;
    // a little different formatting ...
    console.cls();
    stdout.puts
    (
        nl
        "Your 'book'  :  __________________________________________________"
        nl
    );
    for( mov( 0, ecx ); ecx < recCount; inc( ecx ) ) do
        mov( @size( myContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )\

        stdout.puts( nl stdio.tab stdio.tab );

        inc( ecx ); // to show 1,2,3 ... and not 0,1,2 ...
        stdout.putu32Size( ecx, 3, '0' );
        dec (ecx ); // now restore to 0,1,2 ...

        stdout.put( ": ", myBBook.theName[ebx]:-24 );

        stdout.puts( " ---> " );
        stdout.put( myBBook.thePhone[ebx]:15 );
    endfor;
end showBook;
 
 
procedure editContact; @nodisplay;
var
    contactNum: int32;
    goodNum:    boolean;

begin editContact;

    mov( false, goodNum );
    repeat
        try
            stdout.put( nl, "Which contact number (1..", recCount, ") ? " );
            stdin.flushInput();
            stdin.get( contactNum );
            mov( contactNum, eax );
            if( (type int32 eax) < 1  ||  (type int32 eax) > recCount ) then
                raise( ex.ValueOutOfRange );
            else
                mov( true, goodNum );
            endif;

        exception( ex.ValueOutOfRange )
            stdout.puts( nl "Not in valid range.  Please re-enter." );

        exception( ex.ConversionError )
            stdout.puts( nl "Not legal numeric input.  Please re-enter." );

        endtry;

    until( goodNum );
    dec( contactNum ); //

    mov( @size( myContacts ), ebx );
    intmul( contactNum, ebx ); // ebx := contactNumIndex*@size( myContacts )
    mov( takeIn( "Enter name   " ), myBBook.theName[ebx] );
    mov( takeIn( "Enter phone  " ), myBBook.thePhone[ebx] );
                                 
end editContact;
   
 
procedure showMenu; @nodisplay;
 
begin showMenu;

    showBook();
    stdout.put
    (
        nl nl "Total contacts now in memory = ", recCount, "."
        nl nl "Add contacts, Edit contacts, or Quit: (a, e, q) ? "
    );
    stdin.flushInput();
    stdin.getc();
    if( al = 'a' ) then
        updateBook();
        mov( ecx, recCount ); // update the global variable recCount
        fileBook();
    elseif( al = 'e' ) then
        editContact(); 
        fileBook();                 
    elseif( al = 'q' ) then
        mov( true, done );        // done is also a global variable
    endif;

end showMenu;

 
 
begin editContacts;

    inputBook_fromFile();  // recall ... returns the record count in ecx
    mov( ecx, recCount ); // update global variable recCount                             

    repeat
        showMenu();
    until( done );

end editContacts;


We now have a small program working  and debugged and tested with some real data input to check the validity of the design …

Do we get the expected output with some extreme data? 

Then … we can add functions, (i.e. HLA procedures or macros), to that … and test again. 

Add … test.  Add … test …

That way, you can narrow down most of the source of any coding errors to the latest ‘chunk’ of code added.
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 19, 2013, 11:39:07 AM
Here now, are several functions added ...

Each one was added, one at a time … and tested.

Some took a lot more time to get working … than others. 


See the comments and questions in the comments …

What happens when you run the program with various real data of you own?

Code: [Select]
program editContacts2;
 
 
// 'deleteContact' function added ...
// 'sortContacts' function added ...
// 'xDupilcates' function added ... Also, the ability to
// update the file is added directly to the 'menu'.
 
// Note: 'memory leaks' NOT fully handled in this short program ... since here
// the little? amount of allocated memory gets set free when the program quits.
// Note: fixing the ‘memory leaks’ here would make a GOOD project! :)
 
// (Global variables still used here to 'keep it simple'.)
 
// Note (one) way to preserve register values across procedure calls that
// use those registers and so would change the values in the registers.
 
// Do some research on the use of a 'stack' in memory ...
// (Another good project.)
 
 
#include( "stdlib.hhf" )
 
 
const 
    maxCount:   int32 := 100; // to allow for a sufficient? number of 'myContacts'

    cFileName:  text := """contacts.dat"""; // each """ includes one " in output

    type
        myContacts: record
                        theName:    string;
                        thePhone:   string;
                    endrecord;
static

    // global variables utilized in program (to keep it simple here)

    myBBook:    myContacts[ maxCount ];
    recCount:   int32:= 0; // initalized to zero before contacts.dat file is read
    done:       boolean:= false;


    // An example of an HLA library function slightly modified here for this demo ...

    procedure stricmp; @nodisplay; @noframe; @align(4);
    begin stricmp;
        push( ebx );

        // Compare the two strings until we encounter a zero byte
        // or until the corresonding characters are different.

        cmpLoop:

            mov( [esi], al );
            mov( [edi], ah );
            add( 1, esi );
            add( 1, edi );
            cmp( al, 0 );
           
        je notAlpha;
           
            cmp( al, ah );
           
        je cmpLoop;   

        mov( ax, bx );

        // convert to upper case IFF in range 'a..z'

        // if( bl >= 'a' && bl <= 'z' ) then and( $5f, bl ); endif
        cmp( bl, 'a' );
            jb excludeBL;
        cmp( bl, 'z' );
            ja excludeBL;
            and( $5f, bl);   
            excludeBL:

            // IF bl NOT in A..Z THEN 'jmp notAlpha'
            cmp( bl, 'A' );   
            jb notAlpha;
        cmp( bl, 'Z' );
            ja notAlpha;
           
        // if( bh >= 'a' && bh <= 'z' ) then and( $5f, bh ); endif;
        cmp( bh, 'a' );
            jb excludeBH;
        cmp( bh, 'z' );
            ja excludeBH;
            and( $5f, bh );
        excludeBH:  

        // IF bh NOT in A..Z THEN 'jmp notAlpha'
        cmp( bh, 'A' );   
            jb notAlpha;
        cmp( bh, 'Z' );
            ja notAlpha;

        // If we arrive here, bl AND bh are in the range A..Z
        cmp( bl, bh );
            je cmpLoop;

            // so ... NOW exit here!
            // Note: we do NOT want to fall through to the final cmp(al,ah)

            pop( ebx );   
            ret();


        notAlpha:

        // At this point, we've either encountered a zero byte in the source
        // string or we've encountered two bytes that are not the same in
        // the two strings. In either case, return the result of the
        // comparison in the flags.

        cmp( al, ah );
        pop( ebx );
        ret();
   
    end stricmp;

    // An example of an HLA library function slightly modified here for this demo ...

    procedure ilt( src1:string; src2:string ); @nodisplay; @noalignstack; 
    begin ilt;

        push( esi );
        push( edi );

        mov( src1, esi );
        mov( src2, edi );
        stricmp();
        mov( 0, eax );
        setb( al );

        pop( edi );
        pop( esi );

    end ilt;


   
procedure takeIn( message:string ); @nodisplay; @returns("eax");
var
    s:  string;
    c:  char;
begin takeIn;
    repeat
        stdout.put( message, ":  " );
        stdin.flushInput();
        stdin.a_gets();
        stdout.put("You input ", (type string eax), " ok (y/n) ? " );
        mov( eax, s );
        stdin.get( c );
        if( c = 'y' ) then mov( s, eax );
        else str.free( s );
        endif;
    until( c = 'y' );
end takeIn;
 
 
 
// returns valid NUMBER in range (1..recCount) in 'eax'...
procedure takeInValidNum; @nodisplay; @returns( "eax" );
var
    goodNum:    boolean;
 
begin takeInValidNum;

    mov( false, goodNum );
    repeat
        try
            stdout.put( nl, "Which contact number (1..", recCount, ") ? " );
            stdin.flushInput();
            stdin.geti32(); // returns number in eax
            if( (type int32 eax) < 1  ||  (type int32 eax) > recCount ) then
                raise( ex.ValueOutOfRange );
            else
                mov( true, goodNum );
            endif;

        exception( ex.ValueOutOfRange )
            stdout.puts( nl "Not in valid range.  Please re-enter." );
        exception( ex.ConversionError )
            stdout.puts( nl "Not legal numeric input.  Please re-enter." );   
        endtry;
    until( goodNum );

end takeInValidNum;
 
 
 
// tot.num of contacts returned in ecx
procedure updateBook; @nodisplay; @returns("ecx");
var
    more:   boolean;
 
begin updateBook;
    push( ebx );

    mov( recCount, ecx );
    mov( true, more );
    while( ( ecx < maxCount ) && more ) do
        mov( @size( myContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )
        mov( takeIn( "Enter name   " ), myBBook.theName[ebx] );
        mov( takeIn( "Enter phone  " ), myBBook.thePhone[ebx] );

        stdout.puts( nl "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        if ( al='n' ) then mov( false, more ); endif;
        inc( ecx );
        endwhile;

    pop( ebx);
end updateBook;
 
 
 
procedure fileBook; @nodisplay;
var
    outFileHandle:  dword;

begin fileBook;
    push( eax );
    push( ebx );
    push( ecx );

    fileio.openNew( cFileName ); // overwrites any existing file
    mov( eax, outFileHandle );
    for( mov( 0, ecx ); ecx < recCount; inc( ecx ) ) do
        mov( @size( myContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )
        fileio.put( outFileHandle, myBBook.theName[ebx], nl );
        fileio.put( outFileHandle, myBBook.thePhone[ebx], nl );
    endfor;
    fileio.close( outFileHandle );

    pop( ecx );
    pop( ebx );
    pop( eax );
end fileBook;
 
 

// returns count of records in file in ecx
procedure inputBook_fromFile; @nodisplay; @returns( "ecx" );
var
    inFileHandle:   dword;
         
begin inputBook_fromFile;
    push( eax );
    push( ebx );

    try
        fileio.open( cFileName, fileio.r ); // open file for reading
        mov( eax, inFileHandle );

        mov( 0, ecx ); // initialize counter to zero
        while( !fileio.eof( inFileHandle) ) do
            mov( @size( myContacts ), ebx );
            intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )

            // allocate space for new string and
            // mov pointer into array (of pointers)
            fileio.a_gets( inFileHandle);     
            // returns new string in eax

            // mov pointer into array of pointers
            mov( eax, myBBook.theName[ebx] );

            fileio.a_gets( inFileHandle);
            mov( eax, myBBook.thePhone[ebx] );
            inc( ecx );     // increment count of contacts
            endwhile;
        fileio.close( inFileHandle );

    exception( ex.FileOpenFailure )
        stdout.puts
        (
            nl "There was some problem reading your file. "
            "Perhaps it dosen't exist?"
            nl "Do want to start a new contact book (y/n) ? "
        );
        stdin.getc();

        if( al = 'y' || al = 'Y' ) then
            updateBook();
            mov( ecx, recCount ); // update global variable recCount
            fileBook();
        else
            mov( 0, ecx );
        endif;

    endtry;

    pop( ebx );
    pop( eax );     
end inputBook_fromFile;
 
 
 
procedure showBook; @nodisplay;
var
    lineCount:  int32;

begin showBook;
    push( ebx );
    push( ecx );

    // a little different formatting ...
    console.cls();
    stdout.puts
    (
        nl
        "Your 'book'  :  __________________________________________________"
        nl
    );

    mov( 2, lineCount );

    for( mov( 0, ecx ); ecx < recCount; inc( ecx ) ) do

        inc( lineCount );

        mov( @size( myContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( myContacts )\

        stdout.puts( nl stdio.tab stdio.tab );

        inc( ecx ); // to show 1,2,3 ... and not 0,1,2 ...
        stdout.putu32Size( ecx, 3, '0' );
        dec (ecx ); // now restore to 0,1,2 ...

        stdout.put( ": ", myBBook.theName[ebx]:-24 );

        stdout.puts( " ---> " );
        stdout.put( myBBook.thePhone[ebx]:15 );


        // pause after 22 lines printed ... (add if desrired)

        /*
        if( lineCount = 22 && ecx <= recCount) then
         
           stdout.puts( nl nl "Press 'Enter' to continue ... " );
           stdin.readLn();             // wait for 'Enter' key to be pressed
           mov( 0, lineCount );     // set to zero lines re. next screen full
        endif;
        */

    endfor;

    pop( ecx );
    pop( ebx );
end showBook;
 
 
 
procedure editContact; @nodisplay;
var
    contactNum: int32;

begin editContact;
    push( eax );
    push( ebx );     

    takeInValidNum(); // returns num in eax
    mov( eax, contactNum );

    dec( contactNum ); // so = indexes go 0,1,2... (and NOT 1,2,3...)

    mov( @size( myContacts ), ebx );
    intmul( contactNum, ebx ); // ebx := contactNumIndex*@size( myContacts )
    mov( takeIn( "Enter name   " ), myBBook.theName[ebx] );
    mov( takeIn( "Enter phone  " ), myBBook.thePhone[ebx] );

    pop( ebx );
    pop( eax );
end editContact;
 
 
 
procedure deleteContact; @nodisplay;
begin deleteContact;
            push( eax );
            push( ebx );
           
            if( recCount > 0 ) then  // can't delete 0 records
 
                        takeInValidNum();       // returns num in eax
 
                        while( eax < recCount ) do
 
                                   mov( @size( myContacts ), ebx );// equals 8 here ...
                                   intmul( eax, ebx );
                                mov( myBBook.theName[ebx], myBBook.theName[ebx-8] );
                                mov( myBBook.thePhone[ebx], myBBook.thePhone[ebx-8] );
                                   inc( eax );
           
                        endwhile;
                        dec( recCount );
            endif;
 
            pop( ebx );
            pop( eax );
end deleteContact;
 
 
 
// a 'bubblesort' ...
procedure sortBook; @nodisplay;
 
var
    topCount:   int32;
    noSwap:     boolean;

#macro swap( a, b );
    mov( a, edx );
    xchg( edx, b );
    mov( edx, a );
#endmacro

begin sortBook;
    push( eax );
    push( ebx );
    push( edx );
    push( esi );


    if( recCount > 1 ) then     // can't sort 1 record   

        mov( recCount, topCount );
        repeat
       
            mov( true, noSwap );
            for( mov( 1, esi ); esi < topCount; inc( esi ) ) do

                mov( @size( myContacts ), ebx );    // equals 8 here ...
                intmul( esi, ebx ); // ebx := contactNumIndex*@size( myContacts )

                // returns 'true' result in 'al' register if string1 'less than' string2
                // and ... IGNORES CASE i.e. (converts to Caps to compare)

                ilt( myBBook.theName[ebx], myBBook.theName[ebx-8] );

                if( al ) then // swap pointers ...
                    swap( myBBook.theName[ebx], myBBook.theName[ebx-8] );
                    swap( myBBook.thePhone[ebx], myBBook.thePhone[ebx-8] );
                    mov( false, noSwap );
                endif;
            endfor;
            dec( topCount ); // since highest value already in last position
           
        until( noSwap );

    endif;

    pop( esi );
    pop( edx );
    pop( ebx );
    pop( eax );
end sortBook;
 
 
 
/*
int xDuplicates(int a[], int n) // a is an array of int;
{                                             // n is the number of int's
    int i, k = 0;
    for( i = 1; i < n; i++ )
    {
        if( a[k] != a[i] )   // starts with a[0] compared with a[1] ...
        {
            a[k+1] = a[i];  // a lot of copying if few or no duplicates
            k++;
        }
        // if equal goto next 'i' ( but still same old 'k' though )
    }
    return (k+1); // number of unique elements in array
}
*/
 
// Adapted from the above 'C' language algorithm found on the web.
 
procedure xDuplicates; @nodisplay;
var
    k:  int32;

    begin xDuplicates;
    push( eax );
    push( ebx );
    push( ecx );
    push( esi );


    mov( 0, k );
    for( mov( 1, esi ); esi < recCount; inc( esi) ) do

        mov( @size( myContacts ), ebx );
        intmul( esi, ebx );

        mov( @size( myContacts ), ecx );
        intmul( k, ecx );

        //if (a[k] != a[i]) then
        if( str.ine( myBBook.theName[ecx], myBBook.theName[ebx] ) ) then

            //a[k+1] = a[i];
            add( @size( myContacts ), ecx );// now ecx holds (k+1)                   
            mov( myBBook.theName[ebx], myBBook.theName[ecx] );
            mov( myBBook.thePhone[ebx], myBBook.thePhone[ecx] );
            inc( k );
        endif;
    endfor;

    inc(k);
    mov( k, recCount ); // return ( k+1 )

    pop( esi );
    pop( ecx );
    pop( ebx );
    pop( eax );
end xDuplicates;
 
 
   
procedure showMenu; @nodisplay;
begin showMenu;
    push( eax );

    showBook();
    stdout.put
    (
        nl nl "Total contacts now in memory = ", recCount, "."
        nl nl "Add, Delete, Edit, Sort, XDuplicates, File or Quit (a, d, e, s, x, f, q) ? "
    );
    stdin.flushInput();
    stdin.getc();
    if( al = 'a' ) then
        updateBook();
        mov( ecx, recCount ); // update the global variable recCount
        fileBook();
    elseif( al = 'd' ) then
        deleteContact();
        fileBook();
    elseif( al = 'e' ) then
        editContact(); 
        fileBook();
    elseif( al = 's' ) then
        sortBook();
    elseif( al = 'x' ) then
        //sortBook();   // should call sort first (if not already sorted)
        xDuplicates();  // 'chop' duplicates works on a pre-sorted array
    elseif( al = 'f' ) then
        fileBook();
        os.system( "notepad " + cFileName ); // load 'contacts.dat' file into
                                        // text editor to view or edit
    elseif( al = 'q' ) then
    mov( true, done );  // 'done' is also a global variable
    endif;

    pop( eax );
end showMenu;
 
 
 
 
begin editContacts2;
           
    inputBook_fromFile();   // recall ... returns the record count in ecx
    mov( ecx, recCount );   // update global variable recCount 

    repeat
        showMenu();
    until( done );

end editContacts2;


Have you been noticing how you can divide things up into smaller tasks and put them into HLA procedures or macros that you can test out and get working and then use again and again in your program or in other programs?
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 19, 2013, 12:16:39 PM
This versions frees up dynamically allocated memory when it is finished being used.



Code: [Select]
program editContacts2free;

// Note: The 'memory leaks' are handled now ...
// i.e. all deleted/duplicate (allocated) strings are now sent to str.free( stringToDelete )

// Static global variable 'RecCount' is used exclusively to keep 'count'.
// Updating the 'contacts.dat' file is Done automatically if records changed.
// New global boolean variable 'Sorted' added to keep track if Sorted, (or needs to be Sorted).
// Sorting is Done automatically if xDuplicates called, (if not already Sorted)
// or if contacts added or edited.
// Also ... see the example of a type of debugging used here.

#include( "stdlib.hhf" )

// set to 'true' to turn on debugging code/info to be included in the .exe file
? myDebug:= false;

? @nodisplay:= true; // All procedures have @nodisplay 'as default' now.


const   
    MaxSize:    int32 := 100; // to allow for a sufficient? number of 'MyContacts'

    ContactsFNAME: text := """contacts.dat"""; // each """ includes one " in output

type
    MyContacts: record
                    theName:    string;
                    thePhone:   string;
                endrecord;
static
   
    // global variables utilized in program (to keep it simple here)
   
    MyBBook:    MyContacts[ MaxSize ];
    RecCount:   int32:=    0; // initalized to zero before contacts.dat file is read
    Sorted:     boolean:= false;
    Done:       boolean:= false;


    // An example of an HLA library function slightly modified here for this demo ...

    procedure stricmp; @noframe; @align(4);
    begin stricmp;
        push( ebx );
       
        // Compare the two strings until we encounter a zero byte
        // or until the corresonding characters are different.
       
        cmpLoop:
       
            mov( [esi], al );
            mov( [edi], ah );
            add( 1, esi );
            add( 1, edi );
           
        cmp( al, 0 );
            je notAlpha;
       

        cmp( al, ah );
            je cmpLoop;   
               
            mov( ax, bx );

        // convert to upper case IFF in range 'a..z'
        // if( bl >= 'a' && bl <= 'z' ) then and( $5f, bl ); endif;
        cmp( bl, 'a' );
            jb excludeBL;
        cmp( bl, 'z' );
            ja excludeBL;
            and( $5f, bl);   
        excludeBL:
   
        // IF bl NOT in A..Z THEN 'jmp notAlpha'
        cmp( bl, 'A' );   
            jb notAlpha;
        cmp( bl, 'Z' );
            ja notAlpha;
       
        // if( bh >= 'a' && bh <= 'z' ) then and( $5f, bh ); endif;
        cmp( bh, 'a' );
            jb excludeBH;
        cmp( bh, 'z' );
            ja excludeBH;
            and( $5f, bh );
        excludeBH:       

        // IF bh NOT in A..Z THEN 'jmp notAlpha'
        cmp( bh, 'A' );   
            jb notAlpha;
        cmp( bh, 'Z' );
            ja notAlpha;

        // If we arrive here, bl AND bh are in the range A..Z
        cmp( bl, bh );
            je cmpLoop;


        // so ... NOW exit here!
        // Note: we do NOT want to fall through to the final cmp(al, ah)

        pop( ebx );       
        ret();
       

        notAlpha:
       
        // At this point, we've either encountered a zero byte in the source
        // string or we've encountered two bytes that are not the same in
        // the two strings. In either case, return the result of the
        // comparison in the flags.
       
        cmp( al, ah );
        pop( ebx );
        ret();
   
    end stricmp;


    // An example of an HLA library function slightly modified here for this demo ...
    procedure ilt( src1:string; src2:string ); @noalignstack;
    begin ilt;

        push( esi );
        push( edi );
   
        mov( src1, esi );
        mov( src2, edi );
        stricmp();
        mov( 0, eax );
        setb( al );
   
        pop( edi );
        pop( esi );
   
    end ilt;
   
   
     // An example of an HLA library function slightly modified here for this demo ...
    procedure ieq( src1:string; src2:string ); @noalignstack;
    begin ieq;

        push( esi );
        push( edi );
   
        mov( src1, esi );
        mov( src2, edi );
        stricmp();
        mov( 0, eax );
        sete( al );
   
        pop( edi );
        pop( esi );
   
    end ieq;


procedure takeIn( message:string; value:string ); @returns("eax");
var
    s:    string;
begin takeIn;
    forever;
        stdout.puts( message );
        if( str.length( value ) > 0 ) then
            stdout.put( "(", value, "): " );
        else
            stdout.puts( ": " );
        endif;

        stdin.flushInput();
        stdin.a_gets();
        stdout.put("You input ", (type string eax), " ok (y/n) ? " );
        mov( eax, s ); // get a copy of pointer into s ...

        stdin.getc();
        if( al == 'y' || al == 'Y' ) then
            mov( s, eax );
            break;
        else
            str.free( s );
        endif;
    endfor;
end takeIn;


// returns VALID NUMBER in range (1..RecCount) in 'eax'...
procedure takeInValidNum; @returns( "eax" );
begin takeInValidNum;

    forever;
        try
            stdout.put( nl, "Which contact number (1..", RecCount, ") ? " );
            stdin.flushInput();
            stdin.geti32(); // returns number in eax
            if( (type int32 eax) < 1  ||  (type int32 eax) > RecCount ) then
                raise( ex.ValueOutOfRange );
            endif;
           
    unprotected
        break;

        exception( ex.ValueOutOfRange )
            stdout.puts( nl "Not in valid range.  Please re-enter." );
       
        exception( ex.ConversionError )
             stdout.puts( nl "Not legal numeric input.  Please re-enter." );   
        endtry;   
    endfor;

end takeInValidNum;


procedure fileBook;
var
    outFileHandle:    dword;

begin fileBook;
    push( eax );
    push( ebx );
    push( ecx );

    try
   
        fileio.openNew( ContactsFNAME ); // overwrites any existing file
        mov( eax, outFileHandle );
        for( mov( 0, ecx ); ecx < RecCount; inc( ecx ) ) do
            mov( @size( MyContacts ), ebx );
            intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )
            fileio.put( outFileHandle, MyBBook.theName[ebx], nl );
            fileio.put( outFileHandle, MyBBook.thePhone[ebx], nl );
        endfor;
        fileio.close( outFileHandle );
       
    anyexception
        stdout.put( "There was a problem opening file ",  ContactsFNAME,
                    " for output." nl );
    endtry;
    pop( ecx );
    pop( ebx );
    pop( eax );
end fileBook;


// a 'bubblesort' ... by NAMES ...
procedure sortBook;
var
    topCount:   int32;
    noSwap:     boolean;

#macro swap( a, b );
        mov( a, edx );
        xchg( edx, b );
        mov( edx, a );
#endmacro

#macro myCmp;
       
        if( str.eq( MyBBook.thePhone[ebx], MyBBook.thePhone[ebx-8] ) ) then
            ilt( MyBBook.thePhone[ebx], MyBBook.thePhone[ebx-8] );
        else
            ilt( MyBBook.thePhone[ebx], MyBBook.thePhone[ebx-8] );
        endif;
#endmacro


begin sortBook;

    if( RecCount > 1 && !Sorted ) then        // can't sort 1 record   

        push( eax );
        push( ebx );
        push( edx );
        push( esi );

        mov( mov( RecCount, eax ), topCount );   
        repeat
            mov( true, noSwap );
            for( mov( 1, esi ); esi < topCount; inc( esi ) ) do

                mov( @size( MyContacts ), ebx ); // equals 8 here ...
                intmul( esi, ebx );             // ebx := contactNumIndex*@size( MyContacts )


                // returns 'true' result in 'al' register if string1 'less than' string2

                // and ... IGNORES CASE i.e. converts to Caps to compare
               
                myCmp; // cmp value in al

                if( al ) then // swap pointers ...
                    str.eq( MyBBook.thePhone[ebx], MyBBook.thePhone[ebx-8] );
                    if( al) then
                        swap( MyBBook.theName[ebx], MyBBook.theName[ebx-8] );
                        swap( MyBBook.thePhone[ebx], MyBBook.thePhone[ebx-8] );
                        mov( false, noSwap );
                    endif;
                endif;
               
            endfor;
            dec( topCount );    // since highest value already in last position
        until( noSwap );

        mov( true, Sorted );    // update global variable 'Sorted'
        fileBook();             // update contacts.dat file

        pop( esi );
        pop( edx );
        pop( ebx );
        pop( eax );

    endif;

end sortBook;


// Total number of contacts is stored in global variable RecCount
procedure addContacts;
begin addContacts;
    push( eax );
    push( ebx );
    push( ecx );

    mov( RecCount, ecx );
    while( ecx < MaxSize ) do
        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )
        mov( takeIn( "Enter name   ", "" ), MyBBook.theName[ebx] );
        mov( takeIn( "Enter phone  ", "" ), MyBBook.thePhone[ebx] );
        inc( ecx );

        stdout.puts( nl "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif( al == 'n' || al == 'N' );
        if( ecx == MaxSize ) then
            stdout.put( "You have reached the max array size of ", MaxSize, nl );
        endif;
    endwhile;

    if( ecx > RecCount ) then   // Contacts were added ...
        mov( ecx, RecCount );   // So, update the global variable 'RecCount'
        mov( false, Sorted );   // 'authorize' a sort
        sortBook();
    endif;

    pop( ecx );
    pop( ebx);
    pop( eax );
end addContacts;


// returns count of records in file in global variable RecCount
procedure inputBook_fromFile;
var
    inFileHandle:    dword;

begin inputBook_fromFile;
    push( eax );
    push( ebx );

    try
        fileio.open( ContactsFNAME, fileio.r ); // open file for reading
        mov( eax, inFileHandle );

        // RecCount was initialized to zero in static memory

        while( !fileio.eof( inFileHandle) ) do
            mov( @size( MyContacts ), ebx );
            intmul( RecCount, ebx );

            // allocate space for new string and
            // mov pointer into array (of pointers)
            fileio.a_gets( inFileHandle);     // returns new string in eax
            mov( eax, MyBBook.theName[ebx] ); // mov pointer into array of pointers
            fileio.a_gets( inFileHandle);
            mov( eax, MyBBook.thePhone[ebx] );
            inc( RecCount );        // increment count of contacts
           
        endwhile;
        fileio.close( inFileHandle );

    exception( ex.FileOpenFailure )

        stdout.puts
        (
            nl "There was some problem reading your file. " 
            "Perhaps it dosen't exist?"
            nl "Do want to start a new contact book (y/n) ? "
        );
        stdin.getc();
        if( al = 'y' || al = 'Y' ) then
            mov( 0, RecCount );
            addContacts();   
        endif;

    endtry;

    pop( ebx );
    pop( eax );   
end inputBook_fromFile;


procedure editContact;
var
    contactNum: int32;
    s:          string;

begin editContact;

    if( RecCount > 0 ) then // need at least 1 record to edit ...

        push( eax );
        push( ebx );   
   
        mov( takeInValidNum(), contactNum ); // returns num in eax   
        dec( contactNum ); // so = indexes go 0,1,2... (and NOT 1,2,3...)
   
        mov( @size( MyContacts ), ebx );
        intmul( contactNum, ebx ); // ebx := contactNumIndex*@size( MyContacts )


        // free old allocated strings and overwite with new ...

        mov( MyBBook.theName[ebx], eax );
        mov( eax, s ); // get copy of pointer into s ...
        mov( takeIn( "Enter name   ", s ),  MyBBook.theName[ebx] );
        str.free( s );

        mov( MyBBook.thePhone[ebx], eax );
        mov( eax, s ); // get copy into s ...
        mov( takeIn( "Enter phone  ", s ),  MyBBook.thePhone[ebx] );
        str.free( s );


        mov( false, Sorted );            // 'authorize' a sort
        sortBook();

        pop( ebx );
        pop( eax );
    endif;

end editContact;


procedure deleteContact;
begin deleteContact;
   
    if( RecCount > 0 ) then        // can't delete 0 records

        push( eax );
        push( ebx );

        takeInValidNum();
        // returns valid num 1..RecCount in eax
       
        dec( eax ); // to get to proper record index
        str.free( MyBBook.thePhone[eax*8] ); // ok ... free these strings
        str.free( MyBBook.theName[eax*8] );
        inc( eax ); // to get back to record number

        while( eax < RecCount && RecCount > 1 ) do // need at least 2 rec's to do this loop

            mov( @size( MyContacts ), ebx );// equals 8 here ...
            intmul( eax, ebx );         // ebx := contactNumIndex*@size( MyContacts )
            mov( MyBBook.theName[ebx], MyBBook.theName[ebx-8] );
            mov( MyBBook.thePhone[ebx], MyBBook.thePhone[ebx-8] );
            inc( eax );
   
        endwhile;
   
        dec( RecCount );
        fileBook();

        pop( ebx );
        pop( eax );

    endif;

end deleteContact;


/*
int xDuplicates(int a[], int n) // a is an array of int;
{                // n is the number of int's
    int i, k=0;
    for (i = 1; i < n; i++) //
    {
        if (a[k] != a[i])   // starts with a[0] compared with a[1] ...
    {
            // a[k+1] = a[i]; <==> a lot of copying IF NO duplicates
        if( k+1 != i ) a[k+1] = a[i]; // ... but fixed here so it does NOT copy in this case

            k++;
        }
    // if equal goto next 'i' ( but still same old 'k' though )
    }
    return (k+1); // number of unique elements in array
}
*/

// Adapted from the above 'C' language algorithim found on the web.
procedure xDuplicates; 
var
    k:    int32;

begin xDuplicates;

    if( RecCount > 1 ) then // Note: need RecCount > 1 to enter this block ...

        push( eax );
        push( ebx );
        push( ecx );
        push( esi );

        if( !Sorted ) then
            sortBook();   
        endif;

        mov( 0, k );
        for( mov( 1, esi ); esi < RecCount; inc( esi) ) do

            mov( @size( MyContacts ), ecx );
            intmul( k, ecx ); // ecx holds offset into LAST LOWER UNIQUE record compared

            mov( @size( MyContacts ), ebx );
            intmul( esi, ebx ); // ebx now holds offset into this 'i'

            //if (a[k] != a[i])
            if( !( str.ieq( MyBBook.theName[ecx], MyBBook.theName[ebx] ) &&
                str.eq( MyBBook.thePhone[ecx], MyBBook.thePhone[ebx] )) ) then
                   
                inc( k ); // k = k+1; get ready for next pair of '(k, i)' to compare ...
                add( @size( MyContacts ), ecx );   // now ecx holds offset for (k+1)

                if( k <> esi ) then // i.e. if ( (k+1) <> i ) then ...

                    #if(myDebug)       
                        stdout.put( "k=", k, nl nl ); // myDebug <--------------------<<<<
                    #endif   

                    mov( MyBBook.theName[ebx], MyBBook.theName[ecx] ); // copy this new
                    mov( MyBBook.thePhone[ebx], MyBBook.thePhone[ecx] );

                endif;           

            else    // a[k] = a[i], SO THEN goto next 'i', (i.e. esi), but still same old 'k' though.
                // ok to free this 'i' record since = the 'k' record below

                #if(myDebug)       
                    stdout.put( "i=", (type uns32 esi), " " ); // myDebug <----------------<<<<
                #endif

                str.free( MyBBook.thePhone[ebx] ); // ok to free these strings               
                str.free( MyBBook.theName[ebx] );   

            endif;

        endfor;

        inc( k );
        mov( k, ecx );
        if( ecx < RecCount ) then   // i.e. if there were duplicate records then update ...
            mov( ecx, RecCount );   // so ... return ( k+1 ) in RecCount
            fileBook();         // and ... update 'contacts.dat' file   
        endif;

        pop( esi );
        pop( ecx );
        pop( ebx );
        pop( eax );

    endif;

    #if(myDebug)
        stdout.puts( nl "Press 'Enter' to continue ... " ); // myDebug <-------------------<<<<
        stdin.readLn();                   
    #endif

end xDuplicates;


procedure showBook; 
var
    lineCount:    int32;
           
begin showBook;

    push( ebx );
    push( ecx );

    // a little different formatting ...
    console.cls();
    stdout.puts
    (
        nl "Your 'book'  :  __________________________________________________" nl
    );

    mov( 2, lineCount );

    for( mov( 0, ecx ); ecx < RecCount; inc( ecx ) ) do

        inc( lineCount );

        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )

        stdout.puts( nl stdio.tab stdio.tab );
       
        inc( ecx ); // to show 1,2,3 ... and not 0,1,2 ...
        stdout.putu32Size( ecx, 3, '0' );
        dec( ecx ); // now restore to 0,1,2 ...
       
        stdout.put( ": ", MyBBook.theName[ebx]:-24 );

        stdout.puts( " ---> " );
        stdout.put( MyBBook.thePhone[ebx]:15 );

       
        // pause after 22 lines printed ... (add if desrired)

        /*
        if( lineCount = 22 && ecx <= RecCount) then   
           
            stdout.puts( nl nl "Press 'Enter' to continue ... " );
            stdin.readLn();     // wait for 'Enter' key to be pressed
            mov( 0, lineCount );    // set to zero lines re. next screen full
        endif;
        */

    endfor;
   
    pop( ecx );
    pop( ebx );
end showBook;



procedure showMenuDoChoice;
begin showMenuDoChoice;
    push( eax );

    showBook();
    stdout.put
    (
        nl nl "Total contacts now in memory = ", RecCount, "."
        nl nl "Add, Delete, Edit, Sort, XDuplicates or Quit (a, d, e, s, x, q) ? "
    );
    stdin.flushInput();
    stdin.getc();
    if( al = 'a' ) then
        addContacts();
    elseif( al = 'd' ) then
        deleteContact();
    elseif( al = 'e' ) then
        editContact();   
    elseif( al = 's' ) then
        sortBook();
    elseif( al = 'x' ) then
        xDuplicates();        // 'chop' duplicates works on a pre-Sorted array.
    elseif( al = 'q' ) then
        mov( true, Done );     // 'Done' is also a global variable
    endif;
   
    pop( eax );
end showMenuDoChoice;


procedure clearAllContacts;
begin clearAllContacts;
    for( mov( RecCount, ecx ); ecx > 0; nop() ) do
        dec( ecx );
        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx );
        str.free( MyBBook.theName[ebx] );
        str.free( MyBBook.thePhone[ebx] );
    endfor;
    mov( 0, RecCount );
end clearAllContacts;




begin editContacts2free;
 
    inputBook_fromFile();    // returns the record count in global variable RecCount
    repeat
        showMenuDoChoice();
    until( Done );
   
    clearAllContacts();

end editContacts2free;



To be continued ...
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 19, 2013, 03:22:36 PM
Chapter 16: The Computer … vast OS’s … and the garbage collects?
 
 
 
This chapter is ONE BIG RESEARCH PROJECT... firstly on operating systems ...  and on managing memory and other bits inside the ‘box’.
 
From the early day when there were NO OS’s …
 

1.   OS's have been growing bigger and very complex ...
2.   So what did OS's start out as ...
3.   What are some present BIG risks / benefits ... (because of this complexity?)
4.   What is their future ... if any?
5.   What do these mean: 'memory leaks' and 'garbage collection' and is there a need for real time computing still? (Give examples ... Try to google for these.)
6.   What is the relationship between the executable file that an assembler/compiler like HLA produces and an OS like Windows XP or LINUX?
7.   What do these signify:  direct memory access and protected memory? In the old MS DOS days, the OS did not forebide the programmer to poke values directly into memory. What are these dreaded fatal protected memory faults about anyways?
8.   Note that not all computers need to have disks, or screens, or keyboards, or mouses, etc ... Find examples of some very dedicated computing usage, including ones that may not even require an OS.



The following was taken from:

http://www.plantation-productions.com/Webster/Win32Asm/index.html

Win32 programs run in protected mode which is available since 80286. But 80286 is now history. So we only have to concern ourselves with 80386 and its descendants. Windows runs each Win32 program in separated virtual space. That means each Win32 program will have its own 4 GB address space. However, this doesn't mean every win32 program has 4GB of physical memory, only that the program can address any address in that range. Windows will do anything necessary to make the memory the program references valid. Of course, the program must adhere to the rules set by Windows, else it will cause the dreaded General Protection Fault. Each program is alone in its address space. This is in contrast to the situation in Win16. All Win16 programs can *see* each other. Not so under Win32. This feature helps reduce the chance of one program writing over other program's code/data.
Memory model is also drastically different from the old days ofthe 16-bit world. Under Win32, we need not be concerned with memory model or segments anymore! There's only one memory model: Flat memory model. There's no more 64K segments. The memory is a large continuous space of 4 GB. That also means you don't have to play with segment registers. You can use any segment register to address any point in the memory space. That's a GREAT help to programmers. This is what makes Win32 assembly programming as easy as C.
When you program under Win32, you must know some important rules. One such rule is that, Windows uses esi, edi, ebp and ebx internally and it doesn't expect the values in those registers to change. So remember this rule first: if you use any of those four registers in your callback function, don't ever forget to restore them before returning control to Windows. A callback function is your own function which is called by Windows. The obvious example is the windows procedure. This doesn't mean that you cannot use those four registers, you can. Just be sure to restore them back before passing control back to Windows.

Also, take a look at:
If you've ever been confronted by the dreaded Blue Screen Of Death, suffered random reboots or faced the frustration of inexplicable PC crashes, read on for some preventative measures...
http://www.soundonsound.com/sos/jan06/articles/pcmusician.htm?print=yes
http://www.extremetech.com/article2/0,1558,10430,00.asp


Here are some links to help get stated on this VERY BIG project:
 
http://courses.cs.vt.edu/~csonline/OS/Lessons/Introduction/index.html
http://courses.cs.vt.edu/~csonline/OS/Lessons/Resources/index.html
http://courses.cs.vt.edu/~csonline/OS/Lessons/Processes/index.html
http://courses.cs.vt.edu/~csonline/OS/Lessons/Synchronization/index.html
http://courses.cs.vt.edu/~csonline/OS/Lessons/Deadlock/index.html
http://courses.cs.vt.edu/~csonline/OS/Lessons/MemoryAllocation/index.html
http://courses.cs.vt.edu/~csonline/OS/Lessons/VirtualMemory/index.html
http://courses.cs.vt.edu/~csonline/OS/Lessons/FileManagement/index.htm
http://courses.cs.vt.edu/~csonline/OS/Lessons/Summary/index.html
   
Let's take a quick review of all that we have learned about operating systems in these lessons.
 
   1. In the introduction, we saw that software can be roughly divided into two groups: application software and system software. Operating systems are a type of system software that allow applications to interface with computer hardware. Four major categories of operating systems are batch, timesharing, personal computing, and dedicated.
 
   2. Resources are any objects that can be allocated within a system, and the operating system is responsible for managing them. Some resources such as primary memory can be space-multiplexed while other resources such as the CPU must be time-multiplexed.
 
   3. A process is an executing program. Since most computers allow multiple processes to execute simultaneously, the operating system must manage the order in which they execute. Three examples of process scheduling algorithms are First Come First Serve, Round Robin, and Shortest Process Next.
 
   4. Synchronization involves the orderly sharing of system resources by processes. The operating system must ensure that mutually exclusive access is granted to a processes using a critical resource. One way to do this is through the use of semaphores, software flags which indicate whether a critical resource is available.
 
   5. Three conditions are necessary for deadlock to occur in a system: (1) mutual exclusion, (2) hold-and-wait, and (3) no preemption. By attacking one of these three conditions, modern operating systems handle deadlock problems.
 
   6. Three common strategies for primary memory allocation are Best fit, Worst fit, and First fit.
 
   7. Virtual memory allows systems to execute programs which exceed the size of primary memory by dividing programs into sections called pages which can be loaded into sections of memory called page frames. Policies for determining which pages to load and remove from memory include Random Replacement, First In First Out, Second Chance, Least Recently Used, and Least Frequently Used.
 
   8. The file manager is responsible for maintaining secondary storage. Storage blocks in secondary storage can be managed using one of at least three methods: Contiguous Allocation, Linked Allocation, and Indexed Allocation.
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 19, 2013, 03:23:37 PM
Chapter 16: The Computer … vast OS’s … and the garbage collects?  (continued ...)



http://www.mohanraj.info/josh.jsp
 
 
Operating System Design & Implementation Tutorial - JOSH
 
    * Introduction
    * Boot-strap basics
    * Considerations for the boot-strap loader
    * Designing and assembling the boot-loader
    * Rudimentary kernel
    * Interrupt Service
    * Shell - Overview
    * Shell - Implementation
    * Other chapters
 
Introduction
 
I was fascinated by computers right from the moment I got an opportunity to lay my hands on one. I learned BASIC programming in school when I was in grade eight. Those were the days of the 80286 with BASICA on MS-DOS. I went on to complete my degree in Medicine. After completion my interest in computers returned as I got the opportunity of developing a small database system for the hospital I was working. I went on to learn C++, Visual Basic, and ultimately Assembler. I always had a fantasy of developing my own operating system and started reading more and more about that. I ultimately set down to develop a small operating system, which will help me understand the PC better. I then realised the difficulties I underwent to get the needed help and so decided to write the OS as a tutorial as well. I am not sure if the OS will ultimately be completed. But I am sure the reader will be able to complete his/her own version as he/she works with it. Developing the system (which is still under process) was great fun and I am sure the reader will enjoy developing his/her own system.
Pre-requisites
 
A basic/working knowledge of Assembler with an unrelenting desire to explore and know more and to develop something new will be needed to start the project. My own knowledge of the PC is derived from books ('Under the IBM PC' by Peter Norton is an excellent text and I would suggest readers to get a copy of it and read it cover to cover) as a result of which the project will be very much limited in expertise. A copy of the excellent and free NASM (Netwide assembler) is needed for developing the system. You can download your free copy at NASM. All development is done on the Windows operating system. It is also possible to do the same under Unix/Linux system. Differences will be hinted whenever needed.
Design considerations
 
JOSH, as I named it to signify a sense of excitement/satisfaction, will be a real-mode operating system to make learning faster and easier (and my own understanding of the protected mode has only just started). Like MS-DOS it will be interrupt driven. JOSH will be a single tasking operating system. ...
 

 
 
http://64.233.167.104/search?q=cache:Yh9w1R0Q9QEJ:www.cs.vu.nl/~bal/ProposalWritingClass/minix.ps+a+tiny+operating+system&hl=en&ct=clnk&cd=35&gl=ca
   
1. Title: A Small Simple Secure Operating System
 
2. Summary
Current operating systems are very insecure. In theory they all have elaborate security features, but in reality, they are subject to all manner of attacks from hackers, viruses, worms, and so on. The core of the problem is that no current operating system was designed with security in mind. In addi- tion, they are all huge and monolithic, which means that they contain vast numbers of bugs and that each bug is capable of bringing down the entire system. In this research we propose to investigate a new class of operating systems designed from the ground up with security as the primary focus. Our approach is to start with a microkernel, a tiny piece of code that runs in kernel mode and forms the true operating system. This code is small enough that it can probably be made (almost) correct. The rest of the system runs as small protected modules in user mode. In addition, the proposed system is based on the principle of least authority, a well-known technique for containing damage due to software bugs or other causes. Specifically, the use of capabilities will be used to implement this
principle. We believe that by combining the concepts of microkernel and capabilities it should be possible to design an operating system far more secure than any existing one. One OiO is requested and an excellent candidate is available. The research also includes building a prototype to test the results, so a scientific programmer is also requested.
 
3. Description of the Proposed Research
Introduction
Current operating systems have extremely poor security. Practically every week one reads in the newspaper about another security hole in Windows. No sooner has Microsoft posted a patch to its website (which only a tiny fraction of Windows users download and install) than another hole turns up, sometimes in the patch itself. Attacks by viruses and worms are rampant. It is no understatement to say that Windows has very serious security issues.  Variants of UNIX such as Solaris, BSD (including MacOS X and Linux) are not in the press as much. In part it is because they are slightly more secure, but in reality because hackers tend to focus on hitting Windows, where they can get the most publicity for their attacks. If cars, television sets, and other appliances broke down as often as computer software, the public would not stand for it. With computers and especially operating systems, people seem to assume it is only natural that they do not work correctly. Nothing could be further from the truth.  Most of the security problems with current operating systems are due to a fundamental design flaw that they all have inherited from their ancestor operating systems of the 1960s. In the rest of this section we will discuss the nature of the flaw and our proposal for doing research into much more secure operating systems.
 
Why Are Computer Systems Insecure?
Most security problems ultimately come down to the fact that programmers are human beings and as such are not perfect. While no one disputes this statement, no current systems are designed to deal with the consequences of it. Various studies have shown the number of bugs in commercially available software ranges from about 1 bug per 1000 lines of code to 20 bugs per 1000 lines of code, with large and complex software systems having more bugs per 1000 lines of code due to the larger number of modules and their more complex interactions. Windows XP consists of 50 million lines of code. From this it follows that Windows XP has somewhere between 50,000 and 1 million bugs in it. Even if Microsoft’s quality control is the best is the business, there are probably in excess of 50,000 bugs in XP. In this light, it is not surprising that a few of these come to light every week and that Microsoft is constantly sticking its fingers in the software dike. Linux, which consists of a few million lines of code, probably has only a few tens of thousands of bugs. Whether open source software has more bugs than commercial software (due to less stringent quality control) or fewer bugs (due to more eyes looking at the source code) is a highly contentious subject. ...
 
 
 
http://www.personal.kent.edu/~rmuhamma/OpSystems/os.html
 
Operating Systems Lecture Notes
 
   1. Introduction
   2. History of Operating Systems
   3. Operating Systems Structure
          * System Component
          * Operating System Services
          * System Calls and System Programs
          * Layered Approach System Design
          * Mechanism and Policy
   4. Process
          * Definition of Process
          * Process State
          * Process Operations
          * Process Control Block
   5. Threads
   6. Solaris-2 Operating Systems
   7. CPU/Process Scheduling
   8. Schedule Algorithm
          * FCFS Scheduling
          * Round Robin Scheduling
          * SJF Scheduling
          * SRT Scheduling
          * Priority Scheduling
          * Multilevel Queue Scheduling
          * Multilevel Feedback Queue Scheduling
   9. Interprocess Communication
          * Critical Section
          * Mutual Exclusion
          * Achieving Mutual Exclusion
          * Semaphores
  10. Deadlock
          * Necessary and Sufficient Deadlock Conditions
          * Dealing with Deadlock Problem
                o Deadlock Prevention
                o Deadlock Avoidance
                o Deadlock Detection
  11. Absolutely Important UNIX Commands
  12. References
 
 
http://www.howstuffworks.com/operating-system.htm
 
Inside This Article
1. Introduction to How Operating Systems Work
2. The Bare Bones
3. What Does It Do?
4. What Kinds Are There?
5. Wake-Up Call
6. Processor Management
7. Memory Storage and Management
8. Device Management ...
 
If you have a computer, then you have heard about operating systems. Any desktop or laptop PC that you buy normally comes pre-loaded with Windows XP. Macintosh computers come pre-loaded with OS X. Many corporate servers use the Linux or UNIX operating systems. The operating system (OS) is the first thing loaded onto the computer -- without the operating system, a computer is useless.
 
More recently, operating systems have started to pop up in smaller computers as well. If you like to tinker with electronic devices, you are probably pleased that operating systems can now be found on many of the devices we use every day, from cell phones to wireless access points. The computers used in these little devices have gotten so powerful that they can now actually run an operating system and applications. The computer in a typical modern cell phone is now more powerful than a desktop computer from 20 years ago, so this progression makes sense and is a natural development. In any device that has an operating system, there's usually a way to make changes to how the device works. This is far from a happy accident; one of the reasons operating systems are made out of portable code rather than permanent physical circuits is so that they can be changed or modified without having to scrap the whole device.
 
For a desktop computer user, this means you can add a new security update, system patch, new application or often even a new operating system entirely rather than junk your computer and start again with a new one when you need to make a change. As long as you understand how an operating system works and know how to get at it, you can in many cases change some of the ways it behaves. And, it's as true of your cell phone as it is of your computer.
 
The purpose of an operating system is to organize and control hardware and software so that the device it lives in behaves in a flexible but predictable way. In this article, we'll tell you what a piece of software must do to be called an operating system, show you how the operating system in your desktop computer works and give you some examples of how to take control of the other operating systems around you.
 
 
NEXT ... (see above link)
 
 
   
http://en.wikipedia.org/wiki/Disk_Operating_System
 
Disk Operating System (specifically) and disk operating system (generically), most often abbreviated as DOS (not to be confused with the DOS family of disk operating systems for the IBM PC compatible platform), refer to operating system software used in most computers that provides the abstraction and management of secondary storage devices and the information on them (e.g., file systems for organizing files of all sorts). Such software is referred to as a disk operating system when the storage devices it manages are made of rotating platters (such as hard disks or floppy disks).
 
In the early days of microcomputing, memory space was often limited, so the disk operating system was an extension of the operating system. This component was only loaded if needed. Otherwise, disk-access would be limited to low-level operations such as reading and writing disks at the sector-level.
 
In some cases, the disk operating system component (or even the operating system) was known as DOS.
 
Sometimes, a disk operating system can refer to the entire operating system if it is loaded off a disk and supports the abstraction and management of disk devices. Examples include DOS/360 and FreeDOS. On the PC compatible platform, an entire family of operating systems was called DOS.
 
History
 
In the early days of computers, there were no disk drives; delay lines, punched cards, paper tape, magnetic tape, magnetic drums, were used instead. And in the early days of microcomputers, paper tape or audio cassette tape (see Kansas City standard) or nothing were used instead. In the latter case, program and data entry was done at front panel switches directly into memory or through a computer terminal / keyboard, sometimes controlled by a ROM BASIC interpreter; when power was turned off after running the program, the information so entered vanished.
 
Both hard disks and floppy disk drives require software to manage rapid access to block storage of sequential and other data. When microcomputers rarely had expensive disk drives of any kind, the necessity to have software to manage such devices (ie, the 'disk's) carried much status. To have one or the other was a mark of distinction and prestige, and so was having the Disk sort of an Operating System. As prices for both disk hardware and operating system software decreased, there were many such microcomputer systems.
 
 
http://www.ft.com/cms/s/0/9dba9ba2-5a3b-11dc-9bcd-0000779fd2ac.html
 
Chinese military hacked into Pentagon
 
By Demetri Sevastopulo in Washington
 
Published: September 3 2007 19:00 | Last updated: September 3 2007 20:53
 
The Chinese military hacked into a Pentagon computer network in June in the most successful cyber attack on the US defence department, say American ­officials.
 
The Pentagon acknowledged shutting down part of a computer system serving the office of Robert Gates, defence secretary, but declined to say who it believed was behind the attack.
 
Current and former officials have told the Financial Times an internal investigation has revealed that the incursion came from the People’s Liberation Army.
 
One senior US official said the Pentagon had pinpointed the exact origins of the attack. Another person familiar with the event said there was a “very high level of confidence...trending towards total certainty” that the PLA was responsible. The defence ministry in Beijing declined to comment on Monday.
 
Angela Merkel, Germany’s chancellor, raised reports of Chinese infiltration of German government computers with Wen Jiabao, China’s premier, in a visit to Beijing, after which the Chinese foreign ministry said the government opposed and forbade “any criminal acts undermining computer systems, including hacking”. ...
 
 
 
http://www.computerworld.com/governmenttopics/government/story/0,10801,78935,00.html
 
China next to get access to Microsoft source code
Joris Evers, IDG News Service 
 
February 28, 2003 (IDG News Service) -- China has signed up to participate in Microsoft Corp.'s new Government Security Program (GSP), giving the Chinese government access to the source code of Windows operating system software, Microsoft said in a statement today.
The agreement was signed by Microsoft and the China Information Technology Security Certification Center. Chinese President Jiang Zemin was briefed on the GSP today by Microsoft Chairman and Chief Software Architect Bill Gates, who is visiting China, Microsoft said.
The company announced its GSP initiative last month in a bid to allay concerns about the security of its software (see story). The GSP is open to governments and international organizations. GSP participants receive access to the source code and technical information of several versions of Windows software needed to conduct security reviews of the products, the software maker said.
Russia, the U.K. and the North Atlantic Treaty Organization have already signed up to participate in the GSP, and Microsoft is in talks with more than 30 countries, territories and organizations about the program.
Governments signing up for the security program will be able to build systems that offer the high levels of security required for national security, Microsoft has said. However, government users won't be allowed to make modifications to the code or compile the source code into Windows programs themselves, according to Microsoft.
The GSP is also seen as a move in Microsoft's battle against open-source software, primarily the Linux operating system, edging into government administration all around the globe. An open-source license allows users to access and modify the source code. Government users in Finland, Germany, France, Taiwan and the Philippines, among other countries, have already adopted open-source software or are looking into doing so.
Participation in the GSP is free. The program covers current versions, service packs and beta releases of Windows 2000, Windows XP, Windows Server 2003 and Windows CE. In addition, government IT professionals can visit Microsoft headquarters to review Windows development and meet with Microsoft staff. Online access to the source code is secured by smart cards.
Microsoft sees the GSP as an important part of its Trustworthy Computing initiative, an effort announced by Gates last year to improve the security of its software.
Microsoft shares Windows code with governments, companies and educational institutions under various programs that are part of its Shared Source Initiative announced in 2001. The GSP is different in that Microsoft sees it as a partnership with a country or international organization and that it does not require a country or organization to be a Microsoft customer in order to participate. ...
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 19, 2013, 03:46:04 PM
Chapter 17: The Computer delivers daily Manna ...



Here is a fun little project that uses a similar record structure to our previous readFile in Chapter 14.  We will need to find today's date and the dayNumber in the year ... January 1 is day 1.  We can add more records to our file dailyManna.txt if we like. (We will need to keep the same record structure, though.)

We start off by reading the records in dailyManna.txt into an array of records set to a maxDays of 366 ... to allow for leap years.  Recall, this is an array of pointers. (HLA strings are pointers.) So ... it only needs 4 x 2 x 366 bytes of memory at compile time. Later, as we read in the strings from the file dailyManna.txt, we will allocate sufficient memory for each string using fileio.a_gets( inFileHandle );  // which returns the address to each new string in eax

We also will count the records so we will know how may we have ... and also, so we do not exceed the maxDays size of the array.

We will use modular division to find the offset into the array for todays date.

Take a look and see if you can figure out what does what.  You can google on unknown words like this example of key words: HLA day number in year. 

Oh yes, the program uses two data files: dailyManna.txt and PSmessage.hhf.   (Links to these two files follow.)

These need to be in the same folder as the getManna.hla file. 

Link to file to dailyManna.txt to download ...

http://www.4shared.com/office/7hQJKozZ/dailyManna.html

Link to file to PSmessage.hhf to download ...

http://www.4shared.com/file/rSSo6-Z4/PSmessage.html


When you are ready to compile/assemble the getManna.hla file use this command:  hla -w getManna
.

Yes ... this is a Windows example!  Cool French too ... eh!


Now let's get some rich nourishment:

Code: [Select]
program getManna;


#includeonce("w.hhf")
#include( "stdlib.hhf" )

#include("PSmessage.hhf") // PSmessage:    string:=

const 
    maxDays:    int32 := 366;   // to allow for a leap year of days
    cFileName:  text := """dailyManna.txt"""; // each """ includes one " in output

type
    myManna:    record
                    english:    string;
                    french:     string;
                endrecord;
static
    myFood: myManna[ maxDays ];

    dateStr     :str.strvar(16);
    topLine     :str.strvar(128);
    verseStr    :str.strvar(1024*8);    // to be able to hold long strings
    today       :date.daterec;


// returns count of records in file in ecx
procedure inputManna; @nodisplay; @returns( "ecx" );
var
    inFileHandle:   dword;
    dummyStr:       string;

    recCount:       int32;  // to 'backup' ecx in case ecx gets corrupted
                        // if an exception occurs inside try..endtry

begin inputManna;

    str.alloc( 128 );
    mov( eax, dummyStr );
    mov( 0, recCount );
    try
        fileio.open( cFileName, fileio.r ); // open file for reading
        mov( eax, inFileHandle );

        mov( 0, ecx );  // initialize counter to zero
        while( !fileio.eof( inFileHandle) && ecx < maxDays ) do

            mov( @size( myManna ), ebx );
            intmul( ecx, ebx ); // ebx := ecx*@size( myManna )

            // allocate space for new strings and
            // mov pointers into array (of pointers)

            fileio.a_gets( inFileHandle );  // returns new string in eax
            mov(eax,myFood.english[ebx]);   // mov pointer into array of pointers
            fileio.gets(  inFileHandle, dummyStr );
            fileio.a_gets( inFileHandle );
            mov( eax, myFood.french[ebx] );
            fileio.gets(  inFileHandle, dummyStr );
            fileio.gets(  inFileHandle, dummyStr );

            inc( ecx ); // increment count of contacts
            mov( ecx, recCount );

        endwhile;
        fileio.close( inFileHandle );

    anyexception

        str.put
        (
            verseStr,
            nl, "There was some problem reading your file.", nl
            nl, "Perhaps it dosen't exist? ...", nl
            nl, "Or the record structure is corrupted?", nl
            nl nl
        );

    endtry;   

    str.free( dummyStr );
    mov( recCount, ecx );

end inputManna;




begin getManna;
   
    // MAKE TOP LINE MESSAGE STRING WITH TODAY'S DATE ...
    date.today( today );
    date.setFormat( date.yyyymmdd );
    date.setSeparator( '-' );
    date.toString( today, dateStr );

    date.dayNumber( today );  // returns dayNumber in eax 1..366
    str.put
    (
        topLine,
        //"123456789012345678901234567890123456789012345"//
        "Food for your heart, Matthew and Bonnie, for ", dateStr,
        ", day number ", (type int32 eax), " . . . "
    );

    // Get todays MANNA and STORE INTO array of records ...

    inputManna();   // returns the record count in ecx


    if( ecx > 0 ) then

        date.dayNumber( today );
        mov( 0, edx );

        imod( ecx, edx:eax );    // edx = 0,1,2,..recCount-1
        mov( edx, ebx );

        // stdout.put( "ecx=", ecx, "  edx=",edx ); // debugging ..........

        if( ebx = 0 ) then     // i.e. show last record ...
            mov( ecx, ebx );
        endif;
        dec( ebx );      // now at last index ...

        intmul( @size( myManna ), ebx ); // ebx now holds offset

        str.cat( myFood.english[ebx], verseStr );
        str.cat( nl, verseStr );
        str.cat( nl, verseStr );
        str.cat( myFood.french[ebx], verseStr );

    endif;

    w.MessageBox( NULL, verseStr, topLine, w.MB_OK );
    w.MessageBox( NULL, PSmessage, topLine, w.MB_OK );

end getManna;


link to file to dailyManna.txt to download ...

http://www.4shared.com/office/7hQJKozZ/dailyManna.html

link to file to PSmessage.hhf to download ...

http://www.4shared.com/file/rSSo6-Z4/PSmessage.html

Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 19, 2013, 04:18:54 PM
Code: [Select]
// -------- Save this next block as a text file with the name PSmessage.hhf ------- //

const
     n: text :=    "#10";
static
   PSmessage:    string :=

"P.S. ... 'NOTYOU'" n n

"But ye, brethren, are not in darkness, that that day should overtake you as a thief. "
"Ye are all the children of light, and the children of the day: we are not of the night, "
"nor of darkness." n n

"Therefore let us not sleep, as [do] others; but let us watch and be sober. "
"For they that sleep sleep in the night; and they that be drunken are drunken in the night. "
"But let us, who are of the day, be sober, putting on the breastplate of faith and love; "
"and for an helmet, the hope of salvation. For God hath not appointed us to wrath, "
"but to obtain salvation by our Lord Jesus Christ, Who died for us, that, "
"whether we wake or sleep, we should live together with him." n n

"Wherefore comfort yourselves together, and edify one another, even as also ye do. "
"(1 Thessalonians 5:1-11)" n n

"Seeing [it is] a righteous thing with God to recompense tribulation to them that trouble you; "
"And to you who are troubled rest with us, when the Lord Jesus shall be revealed from heaven "
"with his mighty angels, In flaming fire taking vengeance on them that know not God, and that "
"obey not the gospel of our Lord Jesus Christ: Who shall be punished with everlasting destruction "
"from the presence of the Lord, and from the glory of his power; When he shall come to be glorified "
"in his saints, and to be admired in all them that believe (because our testimony among you was "
"believed) in that day. (2 Thessalonians 1:6-10)" n n

"Knowing this first, that there shall come in the last days scoffers, walking after their own lusts, "
"And saying, Where is the promise of his coming? for since the fathers fell asleep, "
"all things continue as [they were] from the beginning of the creation. "

"For this they willingly are ignorant of, that by the word of God the heavens were of old, "
"and the earth standing out of the water and in the water: Whereby the world that then was, "
"being overflowed with water, perished:" n n

"But the heavens and the earth, which are now, by the same word are kept in store, "
"reserved unto fire against the day of judgment and perdition of ungodly men. "

"But, beloved, be not ignorant of this one thing, that one day [is] with the Lord as a thousand years, "
"and a thousand years as one day. "

"The Lord is not slack concerning his promise, as some men count slackness; "
"but is longsuffering to us-ward, "
"not willing that any should perish, but that all should come to repentance." n n

"But the day of the Lord will come as a thief in the night; "
"in the which the heavens shall pass away with a great noise, "
"and the elements shall melt with fervent heat, "
"the earth also and the works that are therein shall be burned up. "

"[Seeing] then [that] all these things shall be dissolved, what manner [of persons] ought ye to be "
"in [all] holy conversation and godliness, Looking for and hasting unto the coming of the day of God, "
"wherein the heavens being on fire shall be dissolved, and the elements shall melt with fervent heat?" n n

"Nevertheless we, according to his promise, look for new heavens and a new earth, "
"wherein dwelleth righteousness." n n

"Wherefore, beloved, seeing that ye look for such things, "
"be diligent that ye may be found of him in peace, without spot, and blameless. "

"And account [that] the longsuffering of our Lord [is] salvation; even as our beloved brother Paul "
"also according to the wisdom given unto him hath written unto you; As also in all [his] epistles, "
"speaking in them of these things; in which are some things hard to be understood, "
"which they that are unlearned and unstable wrest, as [they do] also the other scriptures, "
"unto their own destruction." n n

"Ye therefore, beloved, seeing ye know [these things] before, beware lest ye also, "
"being led away with the error of the wicked, fall from your own stedfastness. "

"But grow in grace, and [in] the knowledge of our Lord and Saviour Jesus Christ. "
"To him [be] glory both now and for ever. Amen. (2 Peter 3:3-18)" n n

"Remember therefore how thou hast received and heard, and hold fast, and repent. "

"If therefore thou shalt not watch, I will come on thee as a thief, and thou shalt not know "
"what hour I will come upon thee. (Revelation 3:3)" n ;


/*

"Behold, I come as a thief. Blessed [is] he that watcheth, and keepeth his garments, "
"lest he walk naked, and they see his shame. (Revelation 16:15)" n ;

*/

// -------------------------------- end of PSmessage.hhf -------------------------- //
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 19, 2013, 05:39:17 PM
Chapter 18: OOP ... goes the computer



1.   Create (md) a sub-directory in the project folder. Give it the name Chapt18_OOP
2.   Go (cd) to that new directory.
3.   Using your text editor, create the following program file in that folder.
      Give the program file the name distanceAndPoints.hla
4.   Compile the program and run it. Study the comments that are in the hla program,
      as well as the output that appears on the screen when you run the program.

You may want to review Chapter 11: The Computer does some Algebra with real numbers ...
that introduces the FPU and real numbers ... up to Chapter 15, and especially Chapter 13:
The Computer files its Records before you dig into the following.

We are about to venture into some very useful stuff that will also help your math insights and skills.

Recall that a straight line is the shortest distance between two points.  If you were to plot, on some graph paper, two points in Euclidean 2 space, calling them A and B with co-ordinates (x1, y1) and (x2, y2) respectively, then the distance between A and B is given by the formula sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ).

This is sometimes abbreviated as sqrt( dX*dX + dY*dY ) …
or spelled out in words …
the square_root_of ( (the difference in the x’s squared) + (the difference in the y’s squared) ).

Our first little program will do just this. We will use real numbers, (HLA type real32’s), for each value of x and y.

You may recall that a real number is just a positive or negative or zero decimal number. 

This includes all fractions, (rational numbers) ...
and all numbers (irrational) like the square root of 2 and PI that never have a repeating pattern to their decimal part …

Thus, we always just approximate reals, (i.e. just the irrational reals), to some number of decimal places.

You may have seen somewhere that 100.001 can be represented by 1.00001e2.

This means the same thing as 1.00001 * 100 which we know is equal to 100.001.

The HLA default output for real numbers is in a format like 1.00001e2.


So let’s dig in.  Don’t be afraid to make changes and see the output.  You can un-comment the line that I commented out … to verify that the output there is what is expected.

Code: [Select]
program distanceAndPoints;

// To find the distance between 2 points, we may
// use the fact that the square on the hypotenuse,
// of any right angled triangle, is equal to the sum
// of the squares on the other two sides ...

// See: The hypotenuse of a right triangle
// http://en.wikipedia.org/wiki/Hypotenuse

#include( "stdlib.hhf" )

// We can store our points (on the 2-D XY plane) like this ...

type
    point:
        record
            x:  real32;
            y:   real32;
        endrecord;

static
    p1: point;
    p2: point;
     
    // to hold the distance between two points
    d:  real32;


// This macro returns the distance between the two
// points a and b ... on the top of the FPU stack.
#macro findDistance( a, b );

    fld( b.x ); // load the x part, of the point b, onto the top of the FPU
    fld( a.x );
    fsubp();    // now have dX in st0, i.e. b.x - a.x in st0

    /* 
    // uncomment these and prove it for your self ...
    fst( d );
    stdout.put( nl nl, "Verify ... Does x2-x1 =  ", d, " ?" nl nl );
    */

    fld( st0 ); // Duplicate dX; i.e. dX now in st0 and in st1
    fmulp();    // Compute dX*dX; pop st0 and st1 and store product in st0

    fld( b.y );
    fld( a.y );
    fsubp();    // now have dY in st0
    fld( st0 ); // Duplicate dY.
    fmulp();    // Compute dY*dY.

    faddp();    // Compute dX*dX + dY*dY
    fsqrt();    // Compute sqrt( dX*dX + dY*dY ).

#endmacro

begin distanceAndPoints;

    finit();    // initialize the FPU

    stdout.puts( "Enter 1st point x,y : " );
    // stdin.get( p1.x, p1.y ); // <== This line is the easy way ...

    // or the following block works too: (Recall 4 bytes for each real32.)
    mov( &p1, ecx );   // put address of p1 into ecx
    stdin.get( (type real32 [ecx]), (type real32 [ecx+4]) ); // ... compare this (1.)

    stdout.puts( "Enter 2nd point x,y : " );
    stdin.get( p2.x, p2.y ); // ... with this (2.)

    findDistance( p1, p2 ); // after execution, the distance is on the top of the FPU
    fstp( d ); // pop off top of stack and store into d, a real32 variable.
    stdout.put( "The distance is: ", d );

end distanceAndPoints;



If you entered 2, 3 and 0, 0  or the other way around ... either way you should have the answer ...

The distance is:  3.605551242e+0

If you entered  0, 0 and  3, -4  or the other way around ... either way you should have the answer ...

The distance is:  5.000000000e+0


So what does this have to do with OOP?  Well, we have just defined an OBJECT, a point ... and described one property of points ... they have a distance between them.  With Objected Oriented Programming, we will keep together, i.e. encapsulate, all the data and all the functions that relate to some object.

Another way that we can think of a point object is ... as a vector.  We can imagine the vector, for now, as having its tail at the origin, i.e. at (0, 0) ... and its head at the point (x, y).  A vector object can also be described by an unique length and an unique direction angle (in the range 0..365.999999999999... degrees) from some line, say the x-axis, (or, -179.9999999999999... to +180 degrees.)

If we have some point or vector then, represented by (x, y) ... we can think of it

●   as the 2 real numbers of the co-ordinates x and y ...

OR ...

●   as a vector with length = sqrt( x*x + y*y ) and direction angle theta = arctan( y/x ).

NOTE!  Either way, TWO unique real numbers are sufficient to describe this OBJECT!  ( i.e a 2-Dimensional vector - has just TWO DIMENSIONS! )

For this example, we will choose the two real numbers that uniquely describe our point, the head of the vector.  And we will also associate functions with this encapsulation of information, concerning this point/vector object ...  i.e.procedures and methods that readily let us calculate / access or get and report this info ... or that set / reset / change / manipulate the numbers that are the data (point) of this object.  To encapsulate all this ... we (will eventually) use a CLASS and give that class a class name.  And all members of that class will use that class name ... similar to what we did with the data inside a record.  Recall that we accessed parts of a record with the dot operator. ... We will likewise use this same dot operator to get to the members of the Class Object ... whether they be data ... or functions that act on that data.

You may not have heard yet ... that the tangent or tan of some angle is just the rise over the run in the right angled triangle described by the points (0, 0), (x, 0),  and ( x, y) ... In this case ... y/x.

And if we know x and y, we can calculate y/x = tan( theta ).  Theta is the angle measured cc (counterclockwise) from the x-axis to the point ( x, y).

Once we know the value of tan( theta ) ... we can look up that value, on a graph or in tables, or use the inverse tan of that value, (same thing as arctan), to find theta.

We will get the FPU unit to do our conversions for us.  If we feed into the FPU function fpatan() ... y and x ... the function will find y/x and then the inverse tan (i.e. the arctan) of the fraction ... i.e. fpatan() outputs theta if we input y and then x ... IT IS IN RADIANS so we will multiply by 360/( 2*pi ) to convert to degrees, where the degrees are counted cc from the positive X-axis. (Recall that in one complete revolution of 360 degrees there are 2pi radians. And ... for a circle with radius1, the circumference is 2*r*pi  = 2*1*pi  = 2*pi ).

See below for the rest of  program vectors2;
Code: [Select]
   fld( y 0; // now have y in st0
   fld( x // now have x in st0, and y in st1
   fpatan(); // take arctan(st1/st0) and store in st1; pop stack
   fmulp( radTodeg ); // convert to degrees ... declared as: radTodeg:    real32:=    360 / ( 2 * 3.14159 );

So here ... where we know y, the rise ... and x, the run ...  then the rise/run = y/x = tan( theta ). Thus we find the direction angle for our vector by plugging this into the formula ...  theta = arctan( y/x )

But if we instead knew the direction angle theta and the length of some vector ... we could then find the unique(x, y) that represents the head of that vector, if we place its tail at the origin.  (We  would use x = lengthOfVector * cos( theta )  and  y = lengthOfVector* sin( theta );  Note that sin(theta)/cos(theta) = tan(theta) = y/x for all theta.)

For further quick reference see:

http://answermath.com/sin.htm

 http://mathworld.wolfram.com/x-Axis.html

http://www.physics.uoguelph.ca/tutorials/vectors/vectors.html
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 19, 2013, 06:28:55 PM
Try these next three programs out for size ...



Don't forget to see the comments in the programs. 

We will encapsulate these into an OOP Vector Class ... right after these.

Code: [Select]
program vectors1;

// Note the changes from the previous program that had
// 2 points ... to this one, with one point w.r.t. to the origin;
// (0, 0) is the reference point for the head of vectors.

#include( "stdlib.hhf" )

type
    vector:
        record
            x:  real32;
            y:  real32;
        endrecord;

static
    v1:     vector;
    v2:     vector;

    // to hold the length of a vector
    len:    real32;   


// Returns the length of a vector
// on the top of the FPU stack.
#macro findLength( a );

    fld( a.x ); // now have a.x in st0
    fld( st0 ); // Duplicate a.x on TOS.
    fmulp();    // Compute a.x*a.x.

    fld( a.y ); // now have a.y in st0
    fld( st0 ); // Duplicate a.y.
    fmulp();    // Compute a.y*a.y.

    faddp();    // Compute a.x*a.x + a.y*a.y
    fsqrt();    // Compute sqrt( a.x*a.x + a.y*a.y ).

#endmacro

begin vectors1;

    finit();    // initialize the FPU

    stdout.puts( "Enter 1st vector x, y : " );
    stdin.get( v1.x, v1.y );

    findLength( v1);
    fstp( len );
    stdout.put( "The length of v1 is: ", len );

    stdout.puts( nl  nl "Enter 2nd vector x, y : " );
    stdin.get( v2.x, v2.y );

    findLength( v2 );
    fstp( len );
    stdout.put( "The length of v2 is: ", len );

end vectors1;



Code: [Select]
program vectors2;

// We will add a function here to find the vector direction angle ...
// and add some logic/validation procedures to assist that function.

#include( "stdlib.hhf" )


type
    vector:
        record
            x:  real32;
            y:  real32;
        endrecord;


const   ZeroVector:dword := 1024;    // 1024..65535 are numbers ok to use for user exceptions


static
    v1:         vector;
    v2:         vector;

    // to hold the length of a vector
    len:        real32;
    angle:      real32;   

    radTodeg:   real32 :=   360 / ( 2 * 3.14159 );


// this function returns 'true' if the 'real'
// value passed to it is zero, otherwise
// ... it returns 'false'
procedure isZero( r:real32 ); @nodisplay; @returns( "al" );
begin isZero;

    fld( r );
    // The  FTST instruction compares the value in ST0 against 0.0
    // Note that this instruction does not differentiate -0.0 from +0.0
    // If the value in ST0 is either of these values, ftst will set C 3
    // to denote equality. Note that this instruction does *NOT POP* st(0)
    // off the stack ...
    ftst();
    fstsw( ax );
    sahf();
    sete( al );     // Set AL to 1 if TOS = 0.0
    fstp( st0 );    // NOW ... pop ST0 off the top of the stack.

end isZero;


// this function returns 'true' if the 'real' passed to it is positive
// ... otherwise, it returns 'false'
procedure isPos( r:real32 ); @nodisplay; @returns( "al" );
begin isPos;

    fld( r );
    // The  FTST instruction compares the value in ST0 against 0.0
    // Note that this instruction does not differentiate -0.0 from +0.0
    // If the value in ST0 is either of these values, ftst will set C 3
    // to denote equality. Note that this instruction does *NOT POP* st(0)
    // off the stack ...
    ftst();
    fstsw( ax );
    sahf();
    seta( al );     // Set AL to 1 if TOS > 0.0
    fstp( st0 );    // NOW ... pop ST0 off the top of the stack.

end isPos;



// Returns the length of a vector
// on the top of the FPU stack.
#macro findLength( a );

    fld( a.x ); // now have a.x in st0
    fld( st0 ); // Duplicate a.x on TOS.
    fmulp();    // Compute a.x*a.x.

    fld( a.y ); // now have a.y in st0
    fld( st0 ); // Duplicate a.y.
    fmulp();    // Compute a.y*a.y.

    faddp();    // Compute a.x*a.x + a.y*a.y
    fsqrt();    // Compute sqrt( a.x*a.x + a.y*a.y ).
   
#endmacro



// Returns the angle of a vector in degrees cc, w.r.t. the x-axis
// being zero degrees ... (returned on the top of the FPU stack)
#macro findAngle( a );

    // The logic here ...  Note: we don't want to
    // divide by 0!  But, if x is 0, then the angle
    // is either 90 deg. if y if positive, or 270 (i.e. -90 )
    // deg. if y if neg.  If both x and y are 0,  then
    // the vector direction angle is NOT defined.
    // See logic below for 0 deg and 180 deg angles

    if( isZero( a.y ) ) then
        if( isZero( a.x ) ) then raise( ZeroVector ); // raise exception
        elseif( isPos( a.x ) ) then  fld( 0.0 );
        else fld( 180.0 );
        endif;
    elseif( isZero( a.x ) ) then
        if( isPos( a.y ) ) then fld( 90.0 );
        else fld( -90.0 );
        endif;
    else
        fld( a.y );     // now have a.y in st0
        fld( a.x );     // now have a.x st0, a.y in st1
        fpatan();       // take arctan(st1/st0) and store in st1; pop stack
       
        fld( radTodeg );
        fmulp();        // convert to degrees
    endif;

#endmacro

procedure more; @nodisplay; @returns( "al" );
begin more;

    stdout.puts( "More (y/n) ? " );
    stdin.getc();
    stdin.flushInput();
    if( al == 'n' || al == 'N' ) then mov( 0, al );
    else mov( 1, al );
    endif;
   
end more;



begin vectors2;

    finit();     // initialize the FPU

    repeat
        try
            stdout.puts( "Enter 1st vector x, y : " );
            stdin.get( v1.x, v1.y );
            findLength( v1);
            fstp( len );
            stdout.put( "The length of v1 is: ", len:8:2 );
            findAngle( v1 );
            fstp( angle );
            stdout.put( nl "The angle of v1 is: ", angle:8:2 );
           
            stdin.flushInput();
           
            stdout.puts( nl  nl "Enter 2nd vector x, y : " );
            stdin.get( v2.x, v2.y );
            findLength( v2 );
            fstp( len );
            stdout.put( "The length of v2 is: ", len:8:2 );
            findAngle( v2 );
            fstp( angle );
            stdout.put( nl "The angle of v2 is: ", angle:8:2, nl nl );

        exception( ZeroVector );
            stdout.puts( nl nl "Zero vector has no defined direction. " nl );

        anyexception
            stdout.puts( nl nl "Some exception occurred ... perhaps invalid data?" nl  );

        endtry;
       
        stdin.flushInput();
       
    until( !more() );

end vectors2;



Code: [Select]
program vectors3;

// Here, we convert our macros to procedures, to get us closer to being ready,
// (to encapsulate all our vector object related stuff in one VECTOR CLASS),
// for our next program ... after this one.

#include( "stdlib.hhf" )


type
    vector:
        record
            x:  real32;
            y:  real32;
        endrecord;


const   ZeroVector:dword := 1024; // 1024..65535 ok num's for user exceptions


static
    v1:         vector;
    v2:         vector;

    // to hold the length of a vector
    len:        real32;
    angle:      real32;   

    radTodeg:   real32 :=   360 / ( 2 * 3.1415926535897932385 );
    // pi = 3.1415926535897932385 // rounded to 20 decimals //
    //      3.14159265358979323846264338327950288419...     //


// this function returns 'true' if the 'real'
// value passed to it is zero, otherwise
// ... it returns 'false'
procedure isZero( r:real32 ); @nodisplay; @returns( "al" );
begin isZero;

    fld( r );
    // The  FTST instruction compares the value in ST0 against 0.0
    // Note that this instruction does not differentiate -0.0 from +0.0
    // If the value in ST0 is either of these values, ftst will set C 3
    // to denote equality. Note that this instruction does *NOT POP* st(0)
    // off the stack ...
    ftst();
    fstsw( ax );
    sahf();
    sete( al );     // Set AL to 1 if TOS = 0.0
    fstp( st0 );    // NOW ... pop ST0 off the top of the stack.

end isZero;


// this function returns 'true' if the 'real' passed to it is positive
// ... otherwise, it returns 'false'
procedure isPos( r:real32 ); @nodisplay; @returns( "al" );
begin isPos;

    fld( r );
    // The  FTST instruction compares the value in ST0 against 0.0
    // Note that this instruction does not differentiate -0.0 from +0.0
    // If the value in ST0 is either of these values, ftst will set C 3
    // to denote equality. Note that this instruction does *NOT POP* st(0)
    // off the stack ...
    ftst();
    fstsw( ax );
    sahf();
    seta( al );     // Set AL to 1 if TOS > 0.0
    fstp( st0 );    // NOW ... pop ST0 off the top of the stack.

end isPos;


// Returns the length of a vector
// on the top of the FPU stack.
procedure findLength( a:vector ); @nodisplay; @returns( "st0" );
begin findLength;

    fld( a.x ); // now have a.x in st0
    fld( st0 ); // Duplicate a.x on TOS.
    fmulp();    // Compute a.x*a.x.
   
    fld( a.y ); // now have a.y in st0
    fld( st0 ); // Duplicate a.y.
    fmulp();    // Compute a.y*a.y.
   
    faddp();    // Compute a.x*a.x + a.y*a.y
    fsqrt();    // Compute sqrt( a.x*a.x + a.y*a.y ).
   
end findLength;


// Returns the angle of a (2D) vector in degrees cc, w.r.t. the x-axis
// being zero degrees ... (returned on the top of the FPU stack)
procedure findAngle( a:vector ); @nodisplay; @returns( "st0" );
begin findAngle;

    // Note logic here: we don't want to divide by 0!
    // But, if x is 0, then the angle is either 90 deg.,
    // if y if positive, or 270 (i.e. -90 ) deg., if y if neg.
    // If both x and y are 0, then the vector direction angle is NOT
    // defined.  See logic below for 0 deg and 180 deg angles

    if( isZero( a.y ) ) then
        if( isZero( a.x ) ) then raise( ZeroVector );
        elseif( isPos( a.x ) ) then fld( 0.0 );
        else fld( 180.0 );
        endif; 
    elseif( isZero( a.x ) ) then
        if( isPos( a.y ) ) then fld( 90.0 );
        else fld( -90.0 );
        endif;
    else
     fld( a.y );      // now have a.y in st0
     fld( a.x );      // now have a.x st0, a.y in st1
     fpatan();        // take arctan(st1/st0) and store in st1 pop stack
       
       fld( radTodeg );
     fmulp();         // convert to degrees
    endif;
   
end findAngle;

procedure more; @nodisplay; @returns( "al" );
begin more;

    stdout.puts( "More (y/n) ? " );
    stdin.getc();
    stdin.flushInput();
    if( al == 'n' || al == 'N' ) then mov( 0, al );
    else mov( 1, al );
    endif;
   
end more;



begin vectors3;

    finit();    // initialize the FPU

    repeat
        try
            stdout.puts( "Enter 1st vector x, y : " );
            stdin.get( v1.x, v1.y );
            findLength( v1);
            fstp( len );
            stdout.put( "The length of v1 is: ", len:8:2 );
            findAngle( v1 );
            fstp( angle );
            stdout.put( nl "The angle of v1 is: ", angle:8:2 );
           
            stdin.flushInput();
           
            stdout.puts( nl  nl "Enter 2nd vector x, y : " );
            stdin.get( v2.x, v2.y );
            findLength( v2 );
            fstp( len );
            stdout.put( "The length of v2 is: ", len:8:2 );
            findAngle( v2 );
            fstp( angle );
            stdout.put( nl "The angle of v2 is: ", angle:8:2, nl nl );

        exception( ZeroVector );
            stdout.puts( nl nl "Zero vector has no defined direction. " nl );

        anyexception
            stdout.puts( nl nl "Some exception occurred ... perhaps invalid data?" nl  );

        endtry;
       
        stdin.flushInput();
       
    until( ! more() );

end vectors3;
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 21, 2013, 11:14:24 AM
Chapter 19: OOP 2



1.   Create (md) a sub-directory in the project folder. Give it the name Chapt19_OOP2
2.   Go (cd) to that new directory.
3.   Using your text editor, create the following program file in that folder. Give the program file the name vectorClass1.hla
4.   Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears
      on the screen when you run the program.

 
Our first CLASS ACT ...

and a lot of behind the scenes work ...

to get the (little) facility (here) we desire ...

but then we have gained considerable power for the next class act to use as a spring board ... and so on ... 

i.e. if we have designed our class a little classy, thinking ahead about future objects that might build on this class?

Code: [Select]
program vectorClass1;

#include( "stdlib.hhf" )

type
    Vector:
        class   
            var
                x:    real32;
                y:    real32;
            procedure create;
            procedure destroy;
            procedure get_x; @returns( "st0" );
            procedure get_y; @returns( "st0" );
            method set_x( r:real32 );
            method set_y( r:real32 );
            method takeIn;  
            procedure display;
            procedure findLength; @returns( "st0" );   
            procedure findAngle; @returns( "st0" );  
        endclass;

const  
    RadToDeg:   real32  :=  360 / ( 2 * 3.1415926535897932384626433833 );

    ZeroVector: dword   :=  1024; // 1024..65535 are ok for user exceptions



static

    VMT( Vector );

    v1:     Vector;
    v2:     Vector;
    pVec:   pointer to Vector;
   
   
   
procedure Vector.create; @nodisplay; @noframe;
begin create;

    push( eax );

    if( esi = 0 ) then  // get new memory IFF NOT already allocated for this obj.
        mem.alloc( @size( Vector ) );
        mov( eax, esi );
    endif;

    mov( &Vector._VMT_, this._pVMT_ );  // update virtual memory table

    pop( eax );
    ret();

end create;


procedure Vector.destroy; @nodisplay;
begin destroy;
    push( eax ); // isInHeap uses this
   
    // Place any other clean up code here.
    // The code to free dynamic objects should always appear last
    // in the destructor.
   
    // The following code assumes that ESI still contains the address
    // of the object.
    if( isInHeap( esi )) then
        free( esi );
    endif;
   
    pop( eax );
end destroy;



procedure Vector.get_x; @nodisplay; @noframe; //@returns( "st0" );
begin get_x;
    fld( this.x );
    ret();
end get_x;

method Vector.set_x( r:real32 ); @nodisplay;
begin set_x;
    fld( r );
    fstp( this.x );
end set_x;


procedure Vector.get_y; @nodisplay; @noframe; //@returns( "st0" );
begin get_y;
    fld( this.y  );
    ret();
end get_y;

method Vector.set_y( r:real32 ); @nodisplay;
begin set_y;
    fld( r );
    fstp( this.y );
end set_y;


method Vector.takeIn; @nodisplay;
begin takeIn;
    stdout.puts( "Enter vector x, y : " );
    stdin.get( this.x, this.y  );
end takeIn;


procedure Vector.display; @nodisplay;
var
    r32:    real32;
begin display;
    stdout.put( "For (", this.x:8:2, ",", this.y:8:2, ")"  );
   
    this.findLength();
    fstp( r32 );
    stdout.put( ", length =", r32:8:2 );
   
    this.findAngle();
    fstp( r32 );
    stdout.put( ", angle =", r32:8:2, nl );
end display;



// Returns the length of a vector
// on the top of the FPU stack.

procedure Vector.findLength; @nodisplay; //@returns( "st0" );
begin findLength;

    fld( this.x );  // now have x in st0
    fld( st0 );     // Duplicate x on TOS.
    fmulp();        // Compute x*x.

    fld( this.y );  // now have y in st0
    fld( st0 );     // Duplicate y.
    fmulp();        // Compute y*y.

    faddp();        // Compute x*x + y*y
    fsqrt();        // Compute sqrt( x*x + y*y ).

end findLength;



// Returns the angle of a vector in degrees cc, w.r.t.
// x --> zero degrees ... on the top of the FPU stack.

procedure Vector.findAngle; @nodisplay; //@returns( "st0" );

    procedure isZero( r:real32 ); @nodisplay; @returns( "al" );
    begin isZero;

        fld( r );
        // The  FTST instruction compares the value in ST0 against 0.0
        // Note that this instruction does not differentiate -0.0 from +0.0
        // If the value in ST0 is either of these values, ftst will set C 3
        // to denote equality. Note that this instruction does *NOT POP* st(0)
        // off the stack ...
        ftst();
        fstsw( ax );
        sahf();
        sete( al );         // Set AL to 1 if TOS = 0.0

        /*
        if( !al ) then      // consider ALSO as zero if (r < 1.0e-10)

            fabs();         // take positive value
            fld( 1.0e-10 );
            fcompp();
            fstsw( ax );
            sahf();
            setb( al );     // AL = true if ST1 < ST0.
        endif;
        */
 
        fstp( st0 );        // NOW ... pop ST0=r off the top of the stack.

    end isZero;

    procedure isPos( r:real32 ); @nodisplay; @returns( "al" );
    begin isPos;

    fld( r );
    // The  FTST instruction compares the value in ST0 against 0.0
    // Note that this instruction does not differentiate -0.0 from +0.0
    // If the value in ST0 is either of these values, ftst will set C 3
    // to denote equality. Note that this instruction does *NOT POP* st(0)
    // off the stack ...
    ftst();
    fstsw( ax );
    sahf();
    seta( al );     // Set AL to 1 if TOS > 0.0
    fstp( st0 );    // NOW ... pop ST0 off the top of the stack.

    end isPos;

begin findAngle;

    // Note logic here: we don't want to divide by 0!
    // But, if x is 0, then the angle is either 90 deg.,
    // if y if positive, or 270 (i.e. -90 ) deg., if y if neg.
    // If both x and y are 0, then the vector direction angle is NOT
    // defined.  See logic below for 0 deg and 180 deg angles

    if( isZero( this.y ) ) then
        if( isZero( this.x ) ) then raise( ZeroVector );
        elseif( isPos( this.x ) ) then fld( 0.0 );
        else fld( 180.0 );
        endif; 
    elseif( isZero( this.x ) ) then
        if( isPos( this.y ) ) then fld( 90.0 );
        else fld( -90.0 );
        endif;
    else
     fld( this.y );   // now have this.y in st0
     fld( this.x );   // now have this.x st0, rhis.y in st1
     fpatan();        // take arctan(st1/st0) and store in st1 pop stack
       
       fld( RadToDeg );
     fmulp();         // convert to degrees
       
    endif;

end findAngle;   
   
   
procedure more; @nodisplay; @returns( "al" );
begin more;

    stdout.puts( "More (y/n) ? " );
    stdin.getc();
    stdin.flushInput();
    if( al == 'n' || al == 'N' ) then mov( 0, al );
    else mov( 1, al );
    endif;
   
end more;
 
 
   
begin vectorClass1;

    finit();    // initialize the FPU
   
    repeat

        try
       
            stdout.newln();
            v1.create(); // get new memory IFF NOT already allocated for this obj.
            v1.takeIn();
            stdin.flushInput();
            v1.display();
            //v1.destroy();
           
            stdout.newln();
            mov( &v2, pVec );
            pVec.create();
            pVec.takeIn();
            pVec.display();
            //pVec.destroy();
   
        exception( ZeroVector );
            stdout.puts( nl nl "Zero vector has no defined direction. " nl );

        anyexception
            stdout.puts( nl nl "Some exception occurred ... perhaps invalid data?" nl  );

        endtry;
       
        stdin.flushInput();
       
        stdout.newln();
       
    until( ! more() );
   
    v1.destroy();
    pVec.destroy();
   
   
end vectorClass1;


We commonly divide the above program up into three parts or modules, each in its own file:

( For simplicity here, we may put all 3 of these new files into our working directory ...
  so the compiler will know where to find them when it is compiling.)

1.   Our main program file, (let's rename it as test_vectorClass.hla). It will also have this line near its top ...
      #include( "vectorClass.hhf" )
2.   The header file itself, that includes any header files, any constants, macros, etc. that the class will use ...
       and declares the class prototypes ... we'll call it vectorClass.hhf
3.   The class definition itself, (let's name this file vectorClass.hla).  This file will ALSO have a line like this near its top:
       #include( "vectorClass.hhf" )

●   And we can THEN compile/assemble these files into one exeucutable file with this command line command:
     HLA   test_vectorClass   vectorClass
●   If all goes well, we will have the desired executable file with the name test_vectorClass.exe in the working folder.
     ( Also ... the files test_vectorClass.obj and vectorClass.obj )
●   If we make any changes to our test file, (or make a new program to use our vectorClass), but ...
     have not made any changes to our vectorClass, we don't need to assemble the vectorClass.hla file again into an obj file.
●   This is how we would make our new executable, if we just changed our test program and so need to re-compile it:
     HLA   test_vectorClass   vectorClass.obj
●   Note the ending of obj on the last file above.  It hasn't changed ... so HLA can just link it in ...
     in the new executable of the new test file.

Well ... there are a few more fine details also needed ... like adding @external; after all the procedure / method prototypes in the header file ...
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 23, 2013, 06:58:08 AM
Chapter 19: OOP 2 ... Continued ...  So here are these 3 FILES:



1. // File name is: test_vectorClass.hla //

Code: [Select]
program test_vectorClass;

#includeonce( "vectorClass.hhf" )

static
    // VMT( Vector );   // moved to near the top of the file vectorClass.hla
                        //    ***  See ALSO the comments there!!!  ***
   
    v1: Vector;         // used here in test program below ...
    v2: Vector;
    pVec:   pointer to Vector;
 

procedure more; @nodisplay; @returns( "al" );
begin more;

    stdout.puts( "More (y/n) ? " );
    stdin.getc();
    stdin.flushInput();
    if( al == 'n' || al == 'N' ) then mov( 0, al );
    else mov( 1, al );
    endif;
   
end more;

 
   
begin test_vectorClass;

    finit();            // initialize the FPU

    repeat
   
        try
       
            v1.create();    // get dynamic memory to hold object v1
                            // (IFF memory NOT exists already)
            stdout.newln();
            v1.takeIn();    // set values in object v1
            stdin.flushInput();
            v1.display();   // show to stdout the stuff ordered up by 'display procedure'

            stdout.newln();

            mov( &v2, pVec );
            pVec.create();
            pVec.takeIn();
            pVec.display();

         
        exception( Vector.ZeroVector );
               stdout.puts( nl nl "Zero vector has no defined direction. " nl );
             
        anyexception
           stdout.puts( nl nl "Some exception occured ... perhaps invalid data?" nl  );
       
        endtry;
       
        stdout.newln();
        stdin.flushInput();
       
    until( ! more() );
   
    v1.destroy();
    pVec.destroy();
   
end test_vectorClass;



2. // File name is: vectorClass.hhf //

Code: [Select]
#include ( "stdlib.hhf" )


type
    Vector:
        class   

            const  
                RadToDeg:   real32 :=   360 / ( 2 * 3.1415926535897932384626433833 );
                ZeroVector: uns32  :=   1024; // 1024..65535 are ok for user exceptions
               
            var
                x:   real32;
                y:   real32;
               
            procedure create; @external;
            procedure destroy; @external;
            procedure get_x; @returns( "st0" ); @external;
            procedure get_y; @returns( "st0" ); @external;
            method set_x( r:real32 ); @external;
            method set_y( r:real32 ); @external;
            method takeIn; @external;    
            procedure display; @external;
            procedure findLength; @returns( "st0" ); @external;   
            procedure findAngle; @returns( "st0" );  @external;
           
        endclass;


3. // file name is: vectorClass.hla //

Code: [Select]
unit vectorClass;

#includeonce( "vectorClass.hhf" )   


static
    VMT( Vector );  // MUST go here, ( and NOT in header file )
                    // so as NOT to be defined twice when the
                    // "vectorClass.hhf" is ALSO included
                    // in the main program.
                   
   
procedure Vector.create; @nodisplay; @noframe;
begin create;

    push( eax );

    if( esi = 0 ) then
        mem.alloc( @size( Vector ) );
        mov( eax, esi );
    endif;

    mov( &Vector._VMT_, this._pVMT_ );

    pop( eax );
    ret();

end create;


procedure Vector.destroy; @nodisplay;
begin destroy;
    push( eax ); // isInHeap uses this
   
    // Place any other clean up code here.
    // The code to free dynamic objects should always appear last
    // in the destructor.
   
    // The following code assumes that ESI still contains the address
    // of the object.
    if( isInHeap( esi )) then
        free( esi );
    endif;
   
    pop( eax );
end destroy;


procedure Vector.get_x; @nodisplay; @noframe; // @returns( "st0" );
begin get_x;
    fld( this.x );
    ret();
end get_x;

method Vector.set_x( r:real32 ); @nodisplay;
begin set_x;
    fld( r );
    fstp( this.x );
end set_x;


procedure Vector.get_y; @nodisplay; @noframe; // @returns( "st0" );
begin get_y;
    fld( this.y  );
    ret();
end get_y;

method Vector.set_y( r:real32 ); @nodisplay;
begin set_y;
    fld( r );
    fstp( this.y );
end set_y;


method Vector.takeIn; @nodisplay;
begin takeIn;
    stdout.puts( "Enter vector x, y : " );
    stdin.get( this.x, this.y  );
end takeIn;


procedure Vector.display; @nodisplay;
var
    r32: real32;
   
begin display;
    stdout.put( "For (", this.x:8:2, ",", this.y:8:2, ")"  );
   
    this.findLength();
    fstp( r32 );
    stdout.put( ", length =", r32:8:2 );
   
    this.findAngle();
    fstp( r32 );
    stdout.put( ", angle =", r32:8:2, nl );
end display;


// Returns the length of a vector
// on the top of the FPU stack.
procedure Vector.findLength; @nodisplay; // @returns( "st0" );
begin findLength;

    fld( this.x );  // now have x in st0
    fld( st0 );     // Duplicate x on TOS.
    fmulp();        // Compute x*x.

    fld( this.y );  // now have y in st0
    fld( st0 );     // Duplicate y.
    fmulp();        // Compute y*y.

    faddp();        // Compute x*x + y*y
    fsqrt();        // Compute sqrt( x*x + y*y ).

end findLength;



// Returns the angle of a vector in degrees cc, w.r.t.
// x --> zero degrees ... on the top of the FPU stack.
procedure Vector.findAngle; @nodisplay; // @returns( "st0" );

    procedure isZero( r:real32 ); @nodisplay; @returns( "al" );
    begin isZero;

        fld( r );
        // The  FTST instruction compares the value in ST0 against 0.0
        // Note that this instruction does not differentiate -0.0 from +0.0
        // If the value in ST0 is either of these values, ftst will set C 3
        // to denote equality. Note that this instruction does *NOT POP* st(0)
        // off the stack ...
        ftst();
        fstsw( ax );
        sahf();
        sete( al );         // Set AL to 1 if TOS = 0.0
        //
        //if( !al ) then    // consider ALSO as zero if (r < 1.0e-10)
        //
        //    fabs();       // take positive value
        //    fld( 1.0e-10 );
        //    fcompp();
        //    fstsw( ax );
        //    sahf();
        //    setb( al );   // AL = true if ST1 < ST0.
        //endif;
        //
        fstp( st0 );        // NOW ... pop ST0=r off the top of the stack.

    end isZero;
   
    procedure isPos( r:real32 ); @nodisplay; @returns( "al" );
    begin isPos;

        fld( r );
        // The  FTST instruction compares the value in ST0 against 0.0
        // Note that this instruction does not differentiate -0.0 from +0.0
        // If the value in ST0 is either of these values, ftst will set C 3
        // to denote equality. Note that this instruction does *NOT POP* st(0)
        // off the stack ...
        ftst();
        fstsw( ax );
        sahf();
        seta( al );     // Set AL to 1 if TOS > 0.0
        fstp( st0 );    // NOW ... pop ST0 off the top of the stack.

    end isPos;

begin findAngle;

    if( isZero( this.y ) ) then

        //assert( !isZero( this.x ) );
        if( isZero( this.x ) ) then raise( Vector.ZeroVector );
            elseif( isPos( this.x ) ) then  fld( 0.0 );
            else fld( 180.0 );
        endif;
       
    elseif( isZero( this.x ) ) then
        if( isPos( this.y ) ) then fld( 90.0 );
        else fld( -90.0 );
        endif;
    else
        fld( this.y );  // now have y in st0
        fld( this.x );  // now have x in st0,  y in st1
        fpatan();       // take arctan(st1/st0) and store in st1; pop stack
       
        fld( Vector.RadToDeg );
        fmulp();        // convert to degrees
   
    endif;
   
end findAngle;

end vectorClass;


Remember to compile/assemble like this (on the command line):

HLA    test_vectorClass   vectorClass

That way, the unit file gets compiled to an obj file and then both of the new .obj files ... test_vectorClass.obj   and   vectorClass.obj ... are liked together into the one executable file test_vectorClass.exe

Now we have three modules ... the main program file, the Class header file, and the Class definition file.  If we were to add another class to our program, we would then probably add two more files ... say ... otherClass.hhf ... otherClass.hla.  Of course, we would then have to #include( "otherClass.hhf" ) in our main program along with any other changes required TO USE this 2nd class. (Remember to also #include( "otherClass.hhf" ) inside and near the top of otherClass.hla.)

If there were no changes to our 1st class definition ... we could use a command line command to compile the project like this: (If there were, we could just add it to the top line,  and remove the -c ... to produce the exe file all in one step. )

HLA   -c   test_vectorClass   otherClass

Followed by this

HLA   test_vectorClass.obj   vectorClass.obj   otherClass.obj

Get the drift ...?


P.S.

You may find a batch file like the following to be useful ...


@echo off
rem to compile one hla file ...
SET fname=
SET /P fname=Enter the name of the file to be compiled/run:
rem hla -w %fname%
hla %fname%
dir %fname%.exe
pause
del %fname%.obj
del %fname%.link
%fname%
pause


or ... to link in an UNIT project FILE with a main FILE ...


@echo off
rem to compile and link a main program with a project unit file (see below)
SET fname=
SET fname2=
SET /P fname=Enter the name of the main file to be compiled/run:
SET /P fname2=Enter the name of the project file to be linked/run:

rem hla -w %fname%

hla %fname% %fname2%
dir %fname%.exe
pause

del %fname%.obj
del %fname2%.obj
del %fname%.link

%fname%
pause
Title: Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
Post by: David on May 24, 2013, 07:38:03 PM
Chapter 20 ... Moving OOP with HLA   ... a CLASS ACT !



Now ... for a little advanced project ...

You may like to convert the HLA code at this next link to an HLA class act :)

http://developers-heaven.net/forum/index.php?topic=2599.msg2966#msg2966


Viva la HLA !


But even more ...


Baruch HaShem !!!


Shalom shalom,


David Wayne Zavitz

2013-05-24   
(My mom was born 105 years ago today.  Dear Father in Heaven, thank YOU SO MUCH for such a wonderful dad and mom and family.)




P.S.


For your ease of ref...


2013-05-24

Hi All,

Just realized (via a few student e-mails) that my old Google Doc's were no longer easily accessible to public ... so updated some and copied everything over to a new hosting site (New site has much better format to show and for students to easily copy/paste example programs)


BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)

http://developers-heaven.net/forum/index.php?topic=2607.0



BEGINNING COMPUTER PROGRAMMING (using HLA and Python 3.1 and C++) 

http://developers-heaven.net/forum/index.php?topic=46.0



Six Fast Steps to Programming in High Level Assembly (HLA)

http://developers-heaven.net/forum/index.php?topic=2599.0


Everything HLA ...

http://www.plantation-productions.com/Webster/


HLA CLASSES ...

http://www.plantation-productions.com/Webster/www.artofasm.com/Windows/HTML/ClassesAndObjects.html#998258

http://www.plantation-productions.com/Webster/www.artofasm.com/index.html


Or see ...

http://www.plantation-productions.com/Webster/