~~16~
Six Fast Steps to Programming in High Level Assembly (HLA)
This series of programs and comments is a continuation of the series Six Fast Steps to Programming in C ... and ... Six Fast Steps to Programming in C++
Update! Update: please see this next link:
http://developers-heaven.net/forum/index.php/topic,2636.0.html
FREE homework help NOW available via e-mail ... (or in person if in Toronto Ontario Canada region.)
You can contact me via:
http://sites.google.com/site/andeveryeyeshallseehim/home/he-comes
http://developers-heaven.net/forum/index.php/board,9.0.html
The following fast paced tutorial may be of interest to new students of High Level Assembly (HLA) ...
Also now includes examples of using HLA strings with readLine, (available to you now by including my file "readLine.hhf" ... please see link to file "readLine.hhf" below), to read in dynamic HLA strings of
ANY length, (length limited only by available memory). This will add 2 more example programs, example 7. and example 8. to the 1. to 6. example HLA programs that follow.
Link for 7.
A simple example of my HLA type Vec container ... using an HLA Vec of HLA strings ...
http://developers-heaven.net/forum/index.php?topic=2599.msg2961#msg2961
Link for 8.
Using an HLA SLList type container of HLA strings ... (also demo's using 'split' line of text into a SLList of 'words')
http://developers-heaven.net/forum/index.php?topic=2599.msg2962#msg2962
Note: when you have exhausted these following pages, you may like to see vector2.hhf and list2.hhf (and func's .hhf files also) at the following link:
vector 2 link ...
http://developers-heaven.net/forum/index.php?topic=2600.0
list 2 link ...
http://developers-heaven.net/forum/index.php?topic=2600.0
The first part of this tutorial consists of a series of 6 example programs that students may like to have for reference and to use as a working 'shell' from which to start a project.
1. The first program is just a most basic 'shell' that assembles, and when run, asks the user to press 'Enter' to continue/exit ...
2. The next program illustrates how to get valid numeric input in a loop and how to ask for more at the end of a repeat ... until type HLA loop that calls a function 'more()' at the end of the loop
3. The next program demo's a way to get and validate user input using a FUNCTION ... (a type of HLA procedure - one that returns a value in a register - commonly the 32 bit EAX register) ... to get valid input.
4. The next three programs progress from inputting numbers into an ARRAY that has the size fixed at compile time ... to using a vector ... and then a list container ... to hold as many numbers as the user wishes (limited only by available memory). They also illustrate how to SORT, FIND, or ERASE elements from the respective containers.
Note: you will need to have the appropriate pair of the following custom helper files: vector.hhf, vector_func's.hhf ... or ... sllist.hhf and sllist_func's.hhf in the same folder as the programs '5.' and '6.' that use them, to assemble the programs '5'. and '6.' that use vector_func's.hhf and sllist_func's.hhf ... Please note that a link to these 4 helper files is provided below.
Note also, that all the numeric input example programs here, find the (integer) sum and the (floating point) average value ... of the numbers input. Please note also the use of the FPU to handle floating point numbers. Following are links to help with using the FPU and floating point numbers (and all things HLA) ...
http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/AoATOC.html
http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/RealArithmetic.html#998833
Please use this next link to access all things 'HLA" ...
http://216.92.238.133/Webster/
You may also like to see the
SLOWER PACED beginning steps at this next link to ...
BEGINNING COMPUTER PROGRAMMING USING HLAhttps://docs.google.com/document/pub?id=1axLRopTi6Qb7ky_Er-IokvtkuneJMYqZAow8Ldas2t0
Or look here for some other programming links, etc ...
http://secureservices.ca
A student goal (and reward) here may be simply expressed like this ...
After the student has understood these examples, that student may then readily handle ... IN HLA ... many common beginner student type data processing problems ... with much of the same ease of using the C++ STL vector and list containers and the C++ STL support functions.
Ok ... here is that promised 1st step HLA program .. just a 'shell' program that you may find helpful, to save some time typing in a basic HLA shell, from which you may add your code for your particular program ...
(You can now always begin with a working HLA shell program that you can assemble and run ... and so can then start with some working executable code that gives the output expected ... so that you can verify that, so far, everything works as expected.)
Note: to assemble these example programs in HLA, you must first have the HLA assembler installed on your computer. Here is a link to the recently updated HLA home site, where you can find out about all things HLA, including downloading the latest version of HLA.
http://216.92.238.133/Webster/
Or go directly to the download page ...
http://216.92.238.133/Webster/HighLevelAsm/index.html
Once you have downloaded and installed HLA on your PC, then you can simply copy/paste these next example HLA programs into some 'working directory/folder', that you keep for HLA code on your PC. (Note that your HLA program file names must end with .hla to assemble with the HLA assembler.)
Then go to a 'command line' inside that directory/folder .. and then issue the command:
HLA yourProgramName.hla
to invoke the HLA assembler to run ... and to produce your executable program code file ... for that program ... provided that your program had no HLA syntax errors ...
(Or you could use this following batch file ... copy paste this file into a file with name ending with .bat in your working folder)
rem ~~~ batch file begins here ~~~
@echo off
SET fname=
SET /P fname=Enter the name of the file to be assembled/run:
hla %fname%
dir %fname%.exe
pause
del %fname%.obj
del %fname%.link
%fname%
pause
rem ~~~ batch file ends here ~~~
1.
// shell.hla // // 2012-07-31 //
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program shell;
#include( "stdlib.hhf" )
begin shell;
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end shell;
Now ... here is the 2nd in this 6 fast step series ... a loop example that uses an HLA function I named 'more' ... (Note: an HLA 'function' is just a kind of HLA procedure that returns a value). Please see the code and comments below ... and don't forget to assemble and run this working example.
Again, you may find this 'more' example quite useful, as a working 'shell', from which to start your beginner code projects, that loop and ask if you wish to loop again at the end of the loop.
2.
// more.hla // // 2012-09-03 //
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program more_demo;
#include( "stdlib.hhf" )
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.getc();
stdin.flushInput();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
static
count: int32 := 0;
sum: int32 := 0;
avg: real32;
tmpStr: str.strvar( 32 );
begin more_demo;
repeat
try
stdout.puts( "Enter next integer to sum: " );
stdin.geti32();
stdin.flushInput();
add( eax, sum );
inc( count );
exception( ex.ConversionError )
stdout.puts( "Invalid input! Integers only please ..." nl );
exception( ex.ValueOutOfRange )
stdout.puts( "Invalid input! Value out of range ... " nl );
endtry;
until( !more() );
// 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
// 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( sum ); // float integer load
fild( count );
// 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( avg ); // POP and store sto, the top of the FPU stack, into average
stdout.put
(
"The average of ", count, " numbers with sum ", sum, " is "
);
str.put( tmpStr, avg:20:2 );
str.delLeadingSpaces( tmpStr ); // to trim off any leading spaces ...
stdout.puts( tmpStr );
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end more_demo;
This 3rd example illustrates a way to get valid input in a function that prompts for the specific input, using a passed in string parameter, and then returns the validated input. (It also demos the use of HLA's powerful and very user friendly exception handling.)
3.
// getValidInt.hla // // 2012-09-03 //
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program getValidInt_demo;
#include( "stdlib.hhf" )
procedure getValidInt( prompt: string ); @nodisplay; @returns( "eax" );
begin getValidInt;
forever
try
stdout.puts( prompt );
stdin.geti32(); // returns 32 bit integer in eax
stdin.flushInput();
unprotected
break;
exception( ex.ConversionError )
stdout.puts( "Invalid input! Integers only please ..." nl );
stdin.flushInput();
exception( ex.ValueOutOfRange )
stdout.puts( "Invalid input! Value out of range ... " nl );
stdin.flushInput();
endtry;
endfor;
end getValidInt;
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.getc();
stdin.flushInput();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
static
count: int32 := 0;
sum: int32 := 0;
avg: real32;
tmpStr: str.strvar( 32 );
begin getValidInt_demo;
repeat
// note: need to preserve/restore any reg's used when using
// try..endtry as in getValidInt below ...
getValidInt( "Enter next value to sum: " ); // returns int32 in eax
add( eax, sum );
inc( count );
until( !more() );
finit(); // initialize floating point (math) unit
fild( sum ); // float integer load
fild( count );
// With no operands, the FDIVP instruction pops ST0 and ST1,
// computes ST1/ST0, and pushes the result back onto the stack.
fdivp(); // find sum / count and ...
// leave result on top of FPU stack (in st0)
fstp( avg ); // POP and store sto, the top of the FPU stack, into avg
stdout.put
(
"The average of ", count, " numbers with sum ", sum, " is "
);
conv.r32ToStr( avg, 20, 2, ' ', tmpStr );
str.delLeadingSpaces( tmpStr );
stdout.puts( tmpStr );
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end getValidInt_demo;
Now ... an array, with the size prefixed at assemble time ... followed by a dynamic array example, that uses dynamic memory, to allocate sufficient memory to hold an array of integers, with the max input size, specified by the user ... WHILE the program is running...
Note, the first program below, uses a constant to specify, at assemble time, the max array capacity. This constant value can be then easily changed to a larger value, (then reassemble your program with this new value), to accommodate a larger anticipated number of integers.
4.
// arrayInt.hla // // 2011-09-03 //
// enters integer data, finds sum, average, sorts, finds value, erase, shows
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program aryInt_demo;
#include( "stdlib.hhf" )
const
MAX_SIZE: uns32 := 4; // use small size here for simple testing purposes
type
//Aryi32: int32[MAX_SIZE];
pInt32: pointer to int32;
static
last: int32;
myAry: int32[MAX_SIZE]; // Aryi32;
pMyAry: pInt32 := &myAry;
count: uns32;
sum: int32 := 0;
avg: real32;
tmpStr: str.strvar( 32 );
procedure getValidInt( prompt: string ); @nodisplay; @returns( "eax" );
begin getValidInt;
forever
try
stdout.puts( prompt );
stdin.geti32(); // returns 32 bit integer in eax
stdin.flushInput();
unprotected
break;
exception( ex.ConversionError )
stdout.puts( "Invalid input! Integers only please ..." nl );
stdin.flushInput();
exception( ex.ValueOutOfRange )
stdout.puts( "Invalid input! Value out of range ... " nl );
stdin.flushInput();
endtry;
endfor;
end getValidInt;
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.getc();
stdin.flushInput();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
procedure sumAry( pAry: pInt32; size:uns32 ); @nodisplay; @returns( "eax" );
begin sumAry;
push( ebx ); push( ecx );
mov( 0, eax );
mov( pMyAry, ebx );
mov( size, ecx );
for( dec(ecx) ; (type int32 ecx) >= 0; dec( ecx ) ) do
add( (type int32 [ebx + ecx*4]), eax );
endfor;
pop( ecx ); pop( ebx );
end sumAry;
procedure showAry( pAry: pInt32; size:uns32 ); @nodisplay;
begin showAry;
push( ebx ); push( ecx );
mov( pAry, ebx );
for( mov( 0, ecx ); ecx < size; inc( ecx ) ) do
stdout.put( (type int32 [ebx + ecx*4]), " " );
endfor;
pop( ecx ); pop( ebx );
end showAry;
procedure isortAry( pAry: pInt32; size:uns32 ); @nodisplay;
begin isortAry;
push( eax ); push( ebx ); push( ecx ); push( edx ); push( esi );
// int i, j, cmp;
mov( pAry, ebx );
// start with an array of just the first 2 elements (if exists)
for( mov( 1, ecx ); ecx < size; inc( ecx ) ) do
// get copy of this new cmp element on each outer loop
mov( [ebx+ecx*4], edx );
// get index of element just to the left of the above 'cmp'
// to start comparisons
mov( ecx, esi );
dec( esi );
while( (type int32 esi) >= 0 && (type int32 edx) < [ebx + esi*4] ) do
//ary[j+1] = ary[j]; // copy element 'up'
//--j; // decrement j in preparation for next inner loop
mov( [ebx + esi*4], eax );
inc( esi );
mov( eax, [ebx + esi*4] );
sub( 2, esi );
endwhile;
//insert element at index j+1 (since j was decremented above)
//ary[j+1] = cmp;
inc( esi );
mov( edx, [ebx+esi*4] );
endfor;
pop( esi ); pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end isortAry;
procedure findAry( pAry: pInt32; size:uns32; value: int32 );
@nodisplay; @returns( "eax" );
begin findAry;
push( ebx ); push( edx );
mov( value, edx );
mov( pAry, ebx );
for( mov( 0, eax ); eax < size; inc( eax ) ) do
if( (type int32 [ebx+eax*4]) == edx ) then break; endif;
endfor;
// check end condition ...
if( eax == size ) then mov( -1, eax ); endif;
pop( edx ); pop( ebx );
end findAry;
// if valid index erase element, return new size in eax ...
procedure eraseAry( pAry: pInt32; size:uns32; index: uns32 );
@nodisplay; @returns( "eax" );
begin eraseAry;
push( ebx ); push( edx );
mov( pAry, ebx );
mov( index, edx );
if( (type int32 edx) >= 0 && edx < size ) then
dec( size );
for( mov( index, eax ); eax < size; inc( eax ) ) do
// copy each element above, down one index, so erased
//ary[i] = ary[i+1];
inc( eax );
mov( (type int32 [ebx+eax*4]), edx );
dec( eax );
mov( edx, (type int32 [ebx+eax*4]) );
endfor;
else
dec( size );
stdout.put( nl "ERROR! Index ", index, " out of range 0..",
size, nl );
inc( size );
endif;
mov( size, eax ); // now update size and return (new - if updated) size...
pop( edx ); pop( ebx );
end eraseAry;
begin aryInt_demo;
mov( 0, ecx ); // using ecx as counter ...
repeat
// note: need to preserve/restore any reg's used when using
// try..endtry as in getValidInt below ...
push( ecx ); // preserve ecx
getValidInt( "Enter next value to sum: " ); // returns int32 in eax
pop( ecx ); // restore ecx
mov( eax, myAry[ecx*4] );
inc( ecx );
if( ecx == MAX_SIZE ) then
stdout.put( "You have reached ", MAX_SIZE, ", the max size.", nl );
break;
endif;
until( !more() );
mov( ecx, count ); // count now holds size of entered array ...
sumAry( pMyAry, count );
mov( eax, sum );
finit(); // initialize floating point (math) unit
fild( sum ); // float integer load
fild( count );
// 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)
fstp( avg ); // POP and store sto, the top of the FPU stack, into avg
stdout.put
(
"The average of ", count, " numbers with sum ", sum, " is "
);
conv.r32ToStr( avg, 20, 2, ' ', tmpStr );
str.delLeadingSpaces( tmpStr ); // to trim off any leading spaces ...
stdout.puts( tmpStr );
stdout.puts( nl "showAry: " );
showAry( pMyAry, count );
//last = my_ary[ i-1 ];
dec( ecx );
mov( mov( myAry[ecx*4], eax ), last );
stdout.puts( nl "After isort..." nl );
isortAry( pMyAry, count );
stdout.puts( "showAry: " );
showAry( pMyAry, count );
findAry( pMyAry, count, last ); // index returned in eax ...
if( (type int32 eax) != -1 ) then // i.e. if found ...
eraseAry( pMyAry, count, eax ); // count holds size, eax holds index
mov( eax, count ); // update count ...
stdout.put( nl "After erasing ", last, "..." nl );
stdout.put( "showAry: " );
showAry( pMyAry, count );
else stdout.put( nl, last, " NOT found in myAry." nl );
endif;
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end aryInt_demo;
This next example program, uses a dynamic array, with max capacity specified by the user of the running program, when it first begins to run.
// dynamicAryInt.hla // // 2011-08-11 //
// enters integer data, finds sum, average, sorts, finds value, erase, shows
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program dynamicAryInt;
#include( "stdlib.hhf" )
type
pInt32: pointer to int32;
static
last: int32;
pMyAry: pInt32;
maxSize:uns32;
count: uns32;
sum: int32 := 0;
avg: real32;
tmpStr: str.strvar( 32 );
procedure getValidInt( prompt: string ); @nodisplay; @returns( "eax" );
begin getValidInt;
forever
try
stdout.puts( prompt );
stdin.geti32(); // returns 32 bit integer in eax
stdin.flushInput();
unprotected
break;
exception( ex.ConversionError )
stdout.puts( "Invalid input! Integers only please ..." nl );
stdin.flushInput();
exception( ex.ValueOutOfRange )
stdout.puts( "Invalid input! Value out of range ... " nl );
stdin.flushInput();
endtry;
endfor;
end getValidInt;
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.getc();
stdin.flushInput();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
procedure sumAry( pAry: pInt32; size:uns32 ); @nodisplay; @returns( "eax" );
begin sumAry;
push( ebx ); push( ecx );
mov( 0, eax );
mov( pMyAry, ebx );
mov( size, ecx );
for( dec(ecx) ; (type int32 ecx) >= 0; dec( ecx ) ) do
add( (type int32 [ebx + ecx*4]), eax );
endfor;
pop( ecx ); pop( ebx );
end sumAry;
procedure showAry( pAry: pInt32; size:uns32 ); @nodisplay;
begin showAry;
push( ebx ); push( ecx );
mov( pAry, ebx );
for( mov( 0, ecx ); ecx < size; inc( ecx ) ) do
stdout.put( (type int32 [ebx + ecx*4]), " " );
endfor;
pop( ecx ); pop( ebx );
end showAry;
procedure isortAry( pAry: pInt32; size:uns32 ); @nodisplay;
begin isortAry;
push( eax ); push( ebx ); push( ecx ); push( edx ); push( esi );
// int i, j, cmp;
mov( pAry, ebx );
// start with an array of just the first 2 elements (if exists)
for( mov( 1, ecx ); ecx < size; inc( ecx ) ) do
// get copy of this new cmp element on each outer loop
mov( [ebx+ecx*4], edx );
// get index of element just to the left of the above 'cmp'
// to start comparisons
mov( ecx, esi );
dec( esi );
while( (type int32 esi) >= 0 && (type int32 edx) < [ebx + esi*4] ) do
//ary[j+1] = ary[j]; // copy element 'up'
//--j; // decrement j in preparation for next inner loop
mov( [ebx + esi*4], eax );
inc( esi );
mov( eax, [ebx + esi*4] );
sub( 2, esi );
endwhile;
//insert element at index j+1 (since j was decremented above)
//ary[j+1] = cmp;
inc( esi );
mov( edx, [ebx+esi*4] );
endfor;
pop( esi ); pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end isortAry;
procedure findAry( pAry: pInt32; size:uns32; value: int32 );
@nodisplay; @returns( "eax" );
begin findAry;
push( ebx ); push( edx );
mov( value, edx );
mov( pAry, ebx );
for( mov( 0, eax ); eax < size; inc( eax ) ) do
if( (type int32 [ebx+eax*4]) == edx ) then break; endif;
endfor;
// check end condition ...
if( eax == size ) then mov( -1, eax ); endif;
pop( edx ); pop( ebx );
end findAry;
// if valid index erase element, return new size in eax ...
procedure eraseAry( pAry: pInt32; size:uns32; index: uns32 );
@nodisplay; @returns( "eax" );
begin eraseAry;
push( ebx ); push( edx );
mov( pAry, ebx );
mov( index, edx );
if( (type int32 edx) >= 0 && edx < size ) then
dec( size );
for( mov( index, eax ); eax < size; inc( eax ) ) do
// copy each element above, down one index, so erased
//ary[i] = ary[i+1];
inc( eax );
mov( (type int32 [ebx+eax*4]), edx );
dec( eax );
mov( edx, (type int32 [ebx+eax*4]) );
endfor;
else
dec( size );
stdout.put( nl "ERROR! Index ", index, " out of range 0..",
size, nl );
inc( size );
endif;
mov( size, eax ); // now update size and return (new - if updated) size...
pop( edx ); pop( ebx );
end eraseAry;
begin dynamicAryInt;
getValidInt( "Max number of int's to input: " );
mov( eax, maxSize );
intmul( @size(int32), eax );
mem.alloc( eax );
mov( eax, pMyAry );
mov( pMyAry, ebx );
mov( 0, ecx ); // using ecx as counter ...
repeat
// note: need to preserve/restore any reg's used when using
// try..endtry as in getValidInt below ...
push( ecx );
getValidInt( "Enter next value to sum: " ); // returns int32 in eax
pop( ecx );
mov( pMyAry, ebx ); // restores ebx
mov( eax, [ebx+ecx*4] );
inc( ecx );
if( ecx == maxSize ) then
stdout.put( "You have reached ", maxSize, ", the max size.", nl );
break;
endif;
until( !more() );
mov( ecx, count ); // count now holds size of entered array ...
sumAry( pMyAry, count );
mov( eax, sum );
finit(); // initialize floating point (math) unit
fild( sum ); // float integer load
fild( count );
// 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)
fstp( avg ); // POP and store sto, the top of the FPU stack, into avg
stdout.put
(
"The average of ", count, " numbers with sum ", sum, " is "
);
conv.r32ToStr( avg, 20, 2, ' ', tmpStr );
str.delLeadingSpaces( tmpStr ); // to trim off any leading spaces ...
stdout.puts( tmpStr );
stdout.puts( nl "showAry: " );
showAry( pMyAry, count );
//last = my_ary[ i-1 ];
dec( ecx );
mov( pMyAry, ebx );
mov( mov( (type int32 [ebx+ecx*4]), eax ), last );
stdout.puts( nl "After isort..." nl );
isortAry( pMyAry, count );
stdout.puts( "showAry: " );
showAry( pMyAry, count );
findAry( pMyAry, count, last ); // index returned in eax ...
if( (type int32 eax) >= 0 ) then // i.e. if found ...
eraseAry( pMyAry, count, eax ); // count holds size, eax holds index
mov( eax, count ); // update count ...
stdout.put( nl "After erasing ", last, "..." nl );
stdout.put( "showAry: " );
showAry( pMyAry, count );
else stdout.put( nl, last, " NOT found in myAry." nl );
endif;
free( pMyAry );
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end dynamicAryInt;
The following program ALSO uses TWO separate files that ALSO need to be 'included' to use this program. These files, "vector.hhf" and "vector_func's.hhf" can be found in a 'mini-library' of Vec/SLList files linked here ...
http://developers-heaven.net/forum/index.php?topic=2600.0
You may also like to note/compare ... that these files ... "vector.hhf" / "vector_func's.hhf ... are just an HLA implementation of my C files "Cvec.h" / "Cvec_func's.h" ... Note: the 2 above mentioned C files (for using my Cvec type) are available at this next link ...
http://developers-heaven.net/forum/index.php?topic=2580.0
Ok, first the test program, for a simple HLA vector container example. (Note: a vector container is just an easily re-expandable dynamic array.)
Please note that this following example uses procedure pointers, so that one can easily redefine the 'sort' and 'find' ... compare function code ... just by passing the address of the particular compare function desired, to the HLA procedure pointer, for the compare function used in the HLA sorting code. (This is similar to using function pointers in C and/or C++).
Please also note that if you include the file "vector_func's.hhf", that file will first include the file "vector.hhf" ... (and note that the file "vector.hhf" also, first includes, the general HLA library access file called "stdlib.hhf"
Please also see the comments embedded in the program code itself.
5.
program VecInt; // 2012-09-03 //
const
FNAME: text := """testInt.dat""";
InitCap: uns32 := 2; // keeping it small here to test out Vec realloc
type
Rec: record
rval: int32;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @nodisplay; @noframe;
begin freeRec;
// no dynamic memory to free here in each Rec
ret();
end freeRec;
// NOTE! The two types above and the procedure freeRec
// MUST be defined before this next include...
#includeOnce( "vector_func's.hhf" ) // includes vector.hhf that includes stdlib.hhf
// Note that vector.hhf also has: ? @nodisplay:= true;
// So ... all procedures have @nodisplay 'as default' from here on ...
// for isort descending ...
procedure myCmpInt( a: pRec in esi; b: pRec in edi ); @returns("eax");
begin myCmpInt;
mov( (type Rec [esi]).rval, eax );
if( eax > (type Rec [edi]).rval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure myCmpIntEQ( a: pRec in esi; b: pRec in edi ); @returns("eax");
begin myCmpIntEQ;
mov( (type Rec [esi]).rval, eax );
if( eax == (type Rec [edi]).rval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpIntEQ;
// for msort ascending ...
procedure myCmp( a: pRec in esi; b: pRec in edi ); @returns("eax");
begin myCmp;
mov( (type Rec [esi]).rval, eax );
if( eax <= (type Rec [edi]).rval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
procedure showRec( pr: pRec in eax ); @noframe;
begin showRec;
stdout.put( (type Rec [eax]).rval );
ret();
end showRec;
procedure showVec( var v: Vec );
begin showVec;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec[ebx]).size; inc( ecx ) ) do
intmul( @size(Rec), ecx, eax );
add( (type Vec[ebx]).ary, eax );
showRec( eax );
stdout.putc( ' ' );
endfor;
stdout.newln();
pop( ecx ); pop( ebx ); pop( eax );
end showVec;
procedure sumVec( var v: Vec ); @returns( "eax" );
begin sumVec;
push( ebx ); push( ecx ); push( edx );
mov( 0, eax );
mov( v, ebx );
mov( (type Vec [ebx]).size, ecx );
for( dec(ecx) ; (type int32 ecx) >= 0; dec( ecx ) ) do
intmul( @size(Rec), ecx, edx );
add( (type Vec[ebx]).ary, edx );
add( (type Rec [edx]).rval, eax );
endfor;
pop( edx ); pop( ecx ); pop( ebx );
end sumVec;
static
fin: dword;
myRec: Rec;
myVec: Vec;
sum: int32;
avg: real32;
tmpStr: str.strvar( 32 );
begin VecInt;
fileio.open( FNAME, fileio.r );
mov( eax, fin );
initVec( myVec );
while( !fileio.eof( fin ) ) do
fileio.getu32( fin );
mov( eax, myRec.rval );
push_backVec( myVec, myRec );
endwhile;
fileio.close( fin );
stdout.puts( "showVec: " );
showVec( myVec );
sumVec( myVec );
mov( eax, sum );
finit(); // initialize floating point (math) unit
fild( sum ); // float integer load
fild( myVec.size );
// 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)
fstp( avg ); // POP and store sto, the top of the FPU stack, into avg
stdout.put
(
nl "The average of ", myVec.size, " numbers with sum ", sum, " is "
);
conv.r32ToStr( avg, 20, 2, ' ', tmpStr );
str.delLeadingSpaces( tmpStr ); // to trim off any leading spaces ...
stdout.puts( tmpStr );
mov( myVec.size, ecx );
//last = my_ary[ i-1 ];
dec( ecx );
mov( &myVec, ebx );
intmul( @size(Rec), ecx, eax );
add( (type Vec [ebx]).ary, eax );
mov( mov( (type Rec [eax]).rval, eax ), myRec.rval );
stdout.puts( nl nl "After isort...(descending)" nl );
mov( &myCmpInt, pMyCmp );
isortVec( myVec );
stdout.puts( "showVec: " );
showVec( myVec );
mov( &myCmpIntEQ, pMyCmp );
findVec( myVec, myRec ); // index returned in eax ...
if( (type int32 eax) >= 0 ) then // i.e. if found ...
eraseVec( myVec, eax ); // count eax holds index
stdout.put( nl "After erasing ", myRec.rval, "..." nl );
stdout.put( "showVec: " );
showVec( myVec );
else stdout.put( nl, myRec.rval, " NOT found in myVec." nl );
endif;
stdout.puts( nl "After msort... (ascending)" nl );
mov( &myCmp, pMyCmp );
msortVec( myVec );
stdout.puts( "showVec: " );
showVec( myVec );
clearVec( myVec );
stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end VecInt;
You will find the 2 files you need to have available to include ...
"vector_func's.hhf"
"vector.hhf"
at this next link:
http://developers-heaven.net/forum/index.php?topic=2600.0
NOTE: In the above program that reads numbers from file, there can NOT be a 'nl' at the end of the file
A short example file, with the name "testInt.dat", to satisfy the above programs code, might look like this next ONE LINE:
1 2 3 4 5 6 7 8 9 0
JUST ONE LINE, ending right after the 0 above with NO newline char's following.
Note that the next example program also has the above file structure constraint ... NO NEW LINE CHAR(S) at the END!
Now here are the List version test example programs ... (You may like to note that 'SLL' in SLList stands for single-linked-list.)
Note that these 'test files' need to access both of the files that I named "sllist.hhf" and "sllist_func's.hhf" (which are available below.)
Please also note that if you include the file "sllist_func's.hhf", that file will first include the file "sllist.hhf" ... (and note that the file "sllist.hhf" also first includes the HLA general library access file called "stdlib.hhf).
First a test program for a simple list of integers ...
6.
program SLListInt; // 2012-09-03 //
const
FNAME: text := """testInt.dat""";
type
NNode: record
nval: int32;
next: pointer to NNode;
endrecord;
pNNode: pointer to NNode;
procedure freeNNode( pn: pNNode in eax ); @nodisplay; @noframe;
begin freeNNode;
// no dynamic memory to free here in each NNode
ret();
end freeNNode;
// NOTE! The two types above and the procedure freeNNode
// MUST be defined before this next include...
#includeOnce( "sllist_func's.hhf" ) // includes sllist.hhf that includes stdlib.hhf
// Note that sllist.hhf also has: ? @nodisplay:= true;
// So ... all procedures have @nodisplay 'as default' from here on ...
// for isort descending ...
procedure myCmpInt( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpInt;
mov( (type NNode [esi]).nval, eax );
if( eax >= (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure myCmpIntEQ( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpIntEQ;
mov( (type NNode [esi]).nval, eax );
if( eax == (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpIntEQ;
// for msort ascending ...
procedure myCmp( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmp;
mov( (type NNode [esi]).nval, eax );
if( eax <= (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
procedure showNNode( pn: pNNode in eax ); @noframe;
begin showNNode;
stdout.put( (type NNode [eax]).nval );
ret();
end showNNode;
procedure showSLList( var v: SLList );
begin showSLList;
push( eax );
mov( v, eax );
mov( (type SLList[eax]).head, eax );
while( eax ) do
showNNode( eax );
stdout.putc( ' ' );
mov( (type NNode[eax]).next, eax );
endwhile;
stdout.newln();
pop( eax );
end showSLList;
procedure sumSLList( var v: SLList ); @returns( "eax" );
begin sumSLList;
push( ecx );
mov( 0, eax );
mov( v, ecx );
mov( (type SLList[ecx]).head, ecx );
while( ecx ) do
add( (type NNode [ecx]).nval, eax );
mov( (type NNode[ecx]).next, ecx );
endwhile;
pop( ecx );
end sumSLList;
static
fin: dword;
myNNode: NNode;
mySLList: SLList;
sum: int32;
avg: real32;
tmpStr: str.strvar( 32 );
begin SLListInt;
fileio.open( FNAME, fileio.r );
mov( eax, fin );
initSLList( mySLList );
while( !fileio.eof( fin ) ) do
fileio.getu32( fin );
mov( eax, myNNode.nval );
push_backSLList( mySLList, myNNode );
endwhile;
fileio.close( fin );
stdout.puts( "showSLList: " );
showSLList( mySLList );
sumSLList( mySLList );
mov( eax, sum );
finit(); // initialize floating point (math) unit
fild( sum ); // float integer load
fild( mySLList.size );
// 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)
fstp( avg ); // POP and store sto, the top of the FPU stack, into avg
stdout.put
(
nl "The average of ", mySLList.size, " numbers with sum ", sum, " is "
);
conv.r32ToStr( avg, 20, 2, ' ', tmpStr );
str.delLeadingSpaces( tmpStr ); // to trim off any leading spaces ...
stdout.puts( tmpStr );
mov( mySLList.tail, eax );
mov( mov( (type NNode [eax]).nval, eax ), myNNode.nval );
stdout.puts( nl nl "After isort...(descending)" nl );
mov( &myCmpInt, pMyCmp );
isortSLList( mySLList );
stdout.puts( "showSLList: " );
showSLList( mySLList );
mov( &myCmpIntEQ, pMyCmp );
findSLList( mySLList, myNNode ); // index returned in eax ...
if( eax ) then // i.e. if found ...
eraseSLList( mySLList, eax ); // count eax holds index
stdout.put( nl "After erasing ", myNNode.nval, "..." nl );
stdout.put( "showSLList: " );
showSLList( mySLList );
else stdout.put( nl, myNNode.nval, " NOT found in mySLList." nl );
endif;
stdout.puts( nl "After msort... (ascending)" nl );
mov( &myCmp, pMyCmp );
msortSLList( mySLList );
stdout.puts( "showSLList: " );
showSLList( mySLList );
stdout.put( "mySLList.size = ", mySLList.size, nl );
clearSLList( mySLList );
stdout.puts( nl "After clear..." nl );
stdout.puts( "showSLList: " );
showSLList( mySLList );
stdout.put( "mySLList.size = ", mySLList.size, nl );
stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end SLListInt;
You will find the 2 files you need to have available to include ...
"sllist_func's.hhf"
"sllist.hhf"
at this next link:
http://developers-heaven.net/forum/index.php?topic=2600.0
A short example file, with the name "testInt.dat", to satisfy the above programs code, might look like this next ONE LINE:
1 2 3 4 5 6 7 8 9 0
JUST ONE LINE, ending right after the 0 above with NO newline char's following.
And using SLList2...
program SLList2Int; // 2012-09-03 //
#includeOnce( "readWord.hhf" )
#includeOnce( "sllist2_func's.hhf" ) // includes sllist2.hhf that includes stdlib.hhf
// Note that sllist2.hhf also has: ? @nodisplay:= true;
// So ... all procedures have @nodisplay 'as default' from here on ...
const
FNAME: text := """testInt.dat""";
/*
type
NNode: record
nval: int32;
next: pointer to NNode;
endrecord;
pNNode: pointer to NNode;
*/
procedure myFreeNNode( pn: pNNode in eax ); @noframe;
begin myFreeNNode;
// no dynamic memory to free here in each NNode
ret();
end myFreeNNode;
// for isort/msort descending ...
procedure myCmpInt( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpInt;
mov( (type NNode [esi]).nval, eax );
if( (type int32 eax) >= (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure myCmpIntEQ( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpIntEQ;
mov( (type NNode [esi]).nval, eax );
if( eax == (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpIntEQ;
// for isort/msort ascending ...
procedure myCmp( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmp;
mov( (type NNode [esi]).nval, eax );
if( (type int32 eax) <= (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
procedure showNNode( pn: pNNode in eax ); @noframe;
begin showNNode;
stdout.put( (type int32 (type NNode [eax]).nval) );
ret();
end showNNode;
procedure showSLList( var v: SLList );
begin showSLList;
push( eax );
mov( v, eax );
mov( (type SLList[eax]).head, eax );
while( eax ) do
showNNode( eax );
stdout.putc( ' ' );
mov( (type NNode[eax]).next, eax );
endwhile;
stdout.newln();
pop( eax );
end showSLList;
procedure sumSLList( var v: SLList ); @returns( "eax" );
begin sumSLList;
push( ecx );
mov( 0, eax );
mov( v, ecx );
mov( (type SLList[ecx]).head, ecx );
while( ecx ) do
add( (type NNode [ecx]).nval, eax );
mov( (type NNode[ecx]).next, ecx );
endwhile;
pop( ecx );
end sumSLList;
static
fin: dword;
myNNode: NNode;
mySLList: SLList;
sum: int32;
avg: real32;
tmpStr: str.strvar( 32 );
tmpStr2: string;
begin SLList2Int;
fileio.open( FNAME, fileio.r );
mov( eax, fin );
initSLList( mySLList );
while( readWord( fin, tmpStr2, " " nl stdio.tab ) ) do
conv.strToi32( tmpStr2, 0 ); // begin at index 0 ..
mov( eax, myNNode.nval );
push_backSLList( mySLList, myNNode );
str.free( tmpStr2 );
endwhile;
fileio.close( fin );
stdout.puts( "showSLList: " );
showSLList( mySLList );
sumSLList( mySLList );
mov( eax, sum );
finit(); // initialize floating point (math) unit
fild( sum ); // float integer load
fild( mySLList.size );
// 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)
fstp( avg ); // POP and store sto, the top of the FPU stack, into avg
stdout.put
(
nl "The average of ", mySLList.size, " numbers with sum ", sum, " is "
);
conv.r32ToStr( avg, 20, 2, ' ', tmpStr );
str.delLeadingSpaces( tmpStr ); // to trim off any leading spaces ...
stdout.puts( tmpStr );
mov( mySLList.tail, eax );
mov( mov( (type NNode [eax]).nval, eax ), myNNode.nval );
stdout.puts( nl nl "After isort...(descending)" nl );
mov( &myCmpInt, pMyCmp );
isortSLList( mySLList );
stdout.puts( "showSLList: " );
showSLList( mySLList );
mov( &myCmpIntEQ, pMyCmp );
findSLList( mySLList, myNNode ); // index returned in eax ...
if( eax ) then // i.e. if found ...
mov( &myFreeNNode, pFreeNNode );
eraseSLList( mySLList, eax ); // eax holds pointer
stdout.put( nl "After erasing ", (type int32 myNNode.nval), "..." nl );
stdout.put( "showSLList: " );
showSLList( mySLList );
else stdout.put( nl, myNNode.nval, " NOT found in mySLList." nl );
endif;
stdout.puts( nl "After msort... (ascending)" nl );
mov( &myCmp, pMyCmp );
msortSLList( mySLList );
stdout.puts( "showSLList: " );
showSLList( mySLList );
stdout.put( "mySLList.size = ", mySLList.size, nl );
mov( &myFreeNNode, pFreeNNode );
clearSLList( mySLList );
stdout.puts( nl "After clear..." nl );
stdout.puts( "showSLList: " );
showSLList( mySLList );
stdout.put( "mySLList.size = ", mySLList.size, nl );
stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end SLList2Int;
Oh ... I forgot to mention above, that the include file ...
"sllist_func's.hhf"
also includes a 'split' function, similar to that split function available in Python ...
or also available in my own C and C++ freely accessible student library of code, available at this site.
This HLA split function readily allows the programmer to parse a line of text and return a SLList of HLA dynamic strings of any length ... The SLList returned holds all the parsed 'words' in that line of text. The programmer can also very easily specifying the particular delimit characters to use to delimit the words to be parsed out from a line of text.
Here is a simple example HLA program that demos this, but using a line of text, entered from the keyboard, by the user, while the program is running/looping ... asking for 'more' ...
Please note also in this simple example, that I just 'lifted the code' from the file "sllist_func's.hhf" for the split function and copy/pasted that code in the program, rather than include the file "sllist_func's.hhf" ... I only include the file "sllist.hhf" so that I can return a SLList of parsed 'words' ... from each keyboard entered ... test line of text.
// test_split.hla // // 2012-08-16 //
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program test_split;
#includeOnce( "memory.hhf" ) // so can use str.free in freeNNode below
type
NNode: record
nval: string;
next: pointer to NNode;
endrecord;
pNNode: pointer to NNode;
? @nodisplay:= true; // All procedures have @nodisplay 'as default' now.
procedure freeNNode( pn: pNNode in eax ); @noframe;
begin freeNNode;
str.free( (type NNode [eax]).nval );
ret();
end freeNNode;
// NOTE! The two types above and the procedure freeNNode
// MUST be defined before this next include...
#includeOnce( "sllist.hhf" ) // also has #include( "stdlib.hhf" )
procedure showNNode( pn: pNNode in eax ); @noframe;
begin showNNode;
stdout.put( (type NNode [eax]).nval );
ret();
end showNNode;
procedure showSLList( var sll: SLList );
begin showSLList;
push( eax );
mov( sll, eax );
mov( (type SLList [eax]).head, eax );
while( eax != 0 ) do
stdout.putc( ''' );
showNNode( eax );
stdout.putc( ''' );
mov( (type NNode [eax]).next, eax );
stdout.newln();
endwhile;
pop( eax );
end showSLList;
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.flushInput();
stdin.getc();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
procedure chrIsInStr( c: char in al; s: string ); @returns( "eax" );
begin chrIsInStr;
str.chpos( s, al );
inc( eax );
end chrIsInStr;
procedure splitSLList( var sll: SLList; s: string; delims: string );
var
myNNode: NNode;
reg32: dword;
i: uns32;
begin splitSLList;
push( eax ); push( ebx ); push( ecx ); push( edx );
mov( sll, ebx );
mov( s, ecx ); // ecx holds start address ...
forever
while( chrIsInStr( (type char [ecx]), delims ) ) do
inc( ecx );
endwhile;
breakif( (type char [ecx]) == 0 ); // since 'empty' string
mov( ecx, edx );
inc( edx ); // edx holds address one past end of 'word' ...
mov( (type char [edx]), al );
while( al && !chrIsInStr( al, delims ) ) do
inc( edx );
mov( (type char [edx]), al );
endwhile;
mov( edx, reg32 ); // save a copy of 'end' in reg32 ...
sub( ecx, edx ); // edx holds 'len of next word'
mov( ecx, i );
mov( s, eax );
sub( eax, i ); // i is index to start
str.a_substr( s, i, edx ); // start, len
mov( eax, myNNode.nval );
push_backSLList( (type SLList [ebx]), myNNode );
mov( reg32, ecx ); // update (next) start pointer ecx ...
endfor;
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end splitSLList;
static
s: string;
c: char;
myLst: SLList;
begin test_split;
initSLList( myLst );
repeat
stdout.puts( "Enter next string to split: " );
stdin.a_gets();
mov( eax, s );
stdout.put( "You entered: ", s, nl );
splitSLList( myLst, s, " " stdio.tab ); // compiler concates
// space&tab into one string
str.free( s );
stdout.put( "Before clear... myLst.size = ", myLst.size, nl );
showSLList( myLst );
clearSLList( myLst );
stdout.put( "After clear... myLst.size = ", myLst.size, nl );
until( !more() );
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end test_split;
And a simple example of inserting in sorted order ...
program SLListIntInsert; // 2012-09-03 //
// using NNode to avoid conflict with Node
// using SLList to avoid conflict with List
#includeOnce( "readWord.hhf" ) // to read in file of int's as 'word-strings'
const
FNAME: text := """testInt.dat""";
type
NNode: record
nval: int32;
next: pointer to NNode;
endrecord;
pNNode: pointer to NNode;
procedure freeNNode( pn: pNNode in eax ); @nodisplay; @noframe;
begin freeNNode;
// no dynamic memory to free here in each Rec
ret();
end freeNNode;
// NOTE! The two types above and the procedure freeRec
// MUST be defined before this next include...
#includeOnce( "sllist_func's.hhf" ) // includes sllist.hhf that includes stdlib.hhf
// Note that sllist.hhf has ? @nodisplay:= true;
// So ... all procedures have @nodisplay 'as default' from here on ...
// for msort/isort ascending ...
procedure myCmp( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmp;
mov( (type NNode [esi]).nval, eax );
if( eax <= (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
// for find...
procedure myCmpEQ( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpEQ;
mov( (type NNode [esi]).nval, eax );
if( eax == (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpEQ;
procedure showNNode( pn: pNNode in eax ); @noframe;
begin showNNode;
stdout.put( (type NNode [eax]).nval );
ret();
end showNNode;
procedure showSLList( var sll: SLList );
begin showSLList;
push( eax ); push( ebx );
mov( sll, ebx );
mov( (type SLList [ebx]).head, eax );
while( eax != 0 ) do
showNNode( eax );
stdout.putc( ' ' );
mov( (type NNode [eax]).next, eax );
endwhile;
pop( ebx ); pop( eax );
end showSLList;
procedure sumSLList( var sll: SLList ); @returns( "eax" );
begin sumSLList;
push( ebx ); push( ecx );
mov( sll, ebx );
mov( (type SLList [ebx]).head, ecx );
mov( 0, eax );
while( ecx != 0 ) do
add( (type NNode [ecx]).nval, eax );
mov( (type NNode [ecx]).next, ecx );
endwhile;
pop( ecx ); pop( ebx );
end sumSLList;
procedure getValidInt( prompt: string ); @nodisplay; @returns( "eax" );
begin getValidInt;
forever
try
stdout.puts( prompt );
stdin.geti32(); // returns 32 bit integer in eax
stdin.flushInput();
unprotected
break;
exception( ex.ConversionError )
stdout.puts( "Invalid input! Integers only please ..." nl );
stdin.flushInput();
exception( ex.ValueOutOfRange )
stdout.puts( "Invalid input! Value out of range ... " nl );
stdin.flushInput();
endtry;
endfor;
end getValidInt;
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.getc();
stdin.flushInput();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
static
fin: dword;
myNNode: NNode;
mySLList: SLList;
sum: int32;
avg: real32;
tmpStr: str.strvar( 32 );
tmp2Str: string;
Sorted: boolean := false;
begin SLListIntInsert;
fileio.open( FNAME, fileio.r );
mov( eax, fin );
initSLList( mySLList );
// NOTE: " " nl stdio.tab all get concatenated below at assemble time
while( readWord( fin, tmp2Str, " " nl stdio.tab ) ) do
conv.strToi32( tmp2Str, 0 ); // begin at index 0 ...
mov( eax, myNNode.nval );
push_frontSLList( mySLList, myNNode );
str.free( tmp2Str );
endwhile;
fileio.close( fin );
stdout.puts( "After push_front... from file, SLList of int is ... " nl );
showSLList( mySLList );
stdout.newln();
sumSLList( mySLList );
mov( eax, sum );
finit(); // initialize floating point (math) unit
fild( sum ); // float integer load
fild( mySLList.size );
// 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)
fstp( avg ); // POP and store sto, the top of the FPU stack, into avg
stdout.put
(
"The average of ", mySLList.size, " numbers with sum ", sum, " is "
);
str.put( tmpStr, avg:20:2 );
str.delLeadingSpaces( tmpStr ); // to trim off any/all leading spaces
stdout.puts( tmpStr );
mov( &myCmp, pMyCmp );
msortSLList( mySLList );
mov( true, Sorted );
stdout.puts( nl "After msortSLList( mySLList ); "
"mySLList of int is ... " nl );
showSLList( mySLList );
stdout.newln();
repeat
getValidInt( "Enter an integer to push_back... " );
mov( eax, myNNode.nval );
push_backSLList( mySLList, myNNode );
until( !more() );
stdout.puts( nl "After push_backSLList( mySLList, myNNode ); "
"SLList of int is ... " nl );
mov( false, Sorted );
showSLList( mySLList );
stdout.newln();
mov( mySLList.tail, ecx );
// get a copy of terminal nval into myNNode.nval
mov( (type NNode [ecx]).nval, myNNode.nval );
if( !Sorted ) then
isortSLList( mySLList );
stdout.puts( nl "After isortSLList( mySLList ); "
"SLList of int is ... " nl );
showSLList( mySLList );
stdout.newln();
endif;
mov( &myCmpEQ, pMyCmp );
// returns pointer (or 0 if not found) in eax ...
findSLList( mySLList, myNNode ); // eax now holds pointer to myNNode, or 0
if( eax ) then
eraseSLList( mySLList, eax );
stdout.puts( nl "After eraseSLList( mySLList, eax ); "
"SLList of int is ... " nl );
showSLList( mySLList );
stdout.newln();
else
stdout.put( myNNode.nval, " was not found in the SLList ..." nl );
endif;
mov( &myCmp, pMyCmp ); // remember to first set proper 'cmp' function
repeat
getValidInt( nl "Enter an integer to insert_sorted... " );
mov( eax, ebx ); // save copy in ebx ...
mem.alloc( @size(NNode) );
mov( ebx, (type NNode [eax]).nval );
insert_sortedSLList( mySLList, eax );
until( !more() );
stdout.puts( nl "After insert_sortedSLList( mySLList, eax ); "
"SLList of int is ... " nl );
showSLList( mySLList );
stdout.put( nl "Before clearSLList( mySLList ); mySLList.size = ",
mySLList.size, nl );
clearSLList( mySLList );
stdout.put( "After clearSLList( mySLList ); mySLList.size = ",
mySLList.size, nl );
stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end SLListIntInsert;
Now ... here is the above mentioned addition to replace (when needed) the HLA standard library str.a_gets() function, when reading from file ...
This function is called like this:
readLine( fin, hlaString ); // returns a dynamic HLA string (pointer) in the 32 bit register EAX of the file line read in
// or returns 0 in EAX at end of file
// so can NOW code (as in C++) like this ...
while( readLine( fin, hlaStringVar ) do
// do something with this new HLA string holding ALL the file line (minus the 'eaten' nl at the end)
endwhile;
similar to the C++ function call:
getline( fin, cppString );
This NEW HLA call NOW allows one to read into an HLA string, a dynamic HLA string of any file line length, limited only by the remaining available memory at the time of the call to readLine( fin, hlaString );
(unlike using the HLA call:
fileio.a_gets( fin );
which has a max input line length of perhaps only 1024 char's in length.)
Please also note that the next example programs of using a HLA SLList and a HLA vector use HLA strings of any length read from file ...
THUS ... they use my new HLA readLine( fin, hlaString) function call ...
available by including this next include file ... "readLine.hhf"
(so that is why it is made available here.)
You will also find these files you need to have available to include for the following 7. and 8. vector and list of string demo programs
at this next link (also "readLineConsole.hhf" and "readWordConsole.hhf"):
http://developers-heaven.net/forum/index.php?topic=2600.0
Now here are some simple demo programs using "readLineConsole.hhf" and "readWordConsole.hhf" ...
program test_readLineConsole; // 2012-08-23 //
#includeOnce( "readLineConsole.hhf" )
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.flushInput();
stdin.getc();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
static
s: string;
len: uns32;
maxlen: uns32;
begin test_readLineConsole;
repeat
stdout.put( "Enter a short line of text: " );
stdin.flushInput();
readLineConsole();
mov( eax, s );
mov( (type str.strRec [eax]).length, len );
mov( (type str.strRec [eax]).maxlen, maxlen );
stdout.put( "You entered: '", s, "'" nl );
stdout.put( "length = ", len, ", maxlen = ", maxlen, nl );
str.free( s );
until( !more() );
end test_readLineConsole;
And "readWordConsole.hhf" ...
program test_readWordConsole; // 2012-08-24 //
#includeOnce( "readWordConsole.hhf" )
static
s: string;
begin test_readWordConsole;
forever
stdout.puts( "Enter a line of 'words' (q to quit): " );
readWordConsole( s, " " stdio.tab );
if( (type char [eax]) == 'q' ) then
str.free( eax );
break;
endif;
stdout.put( "You entered: '", s, "'" nl );
stdout.put( "length = ", (type str.strRec [eax]).length,
", maxlen = ", (type str.strRec [eax]).maxlen, nl );
str.free( s );
endfor;
stdout.puts( nl "Press 'Enter' to exit/continue ... " );
stdin.flushInput();
stdin.readLn();
end test_readWordConsole;
Now the HLA vector of string example ... (that uses file "readLine.hhf")
7.
program VecString; // 2012-09-03 //
#includeOnce( "readLine.hhf" );
const
FNAME: text := """testStr.dat""";
InitCap: uns32 := 2; // keeping it small here to test out Vec realloc
type
Rec: record
rval: string;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @nodisplay; @noframe;
begin freeRec;
str.free( (type Rec [eax]).rval );
ret();
end freeRec;
// NOTE! The two types above and the procedure freeRec
// MUST be defined before this next include...
#includeOnce( "vector_func's.hhf" ) // includes vector.hhf that includes stdlib.hhf
// Note that vector.hhf also has: ? @nodisplay:= true;
// So ... all procedures have @nodisplay 'as default' from here on ...
// for isort descending ...
procedure myCmpInt( a: pRec in esi; b: pRec in edi ); @returns("eax");
begin myCmpInt;
if( str.gt( (type Rec [esi]).rval, (type Rec [edi]).rval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure myCmpIntEQ( a: pRec in esi; b: pRec in edi ); @returns("eax");
begin myCmpIntEQ;
if( str.eq( (type Rec [esi]).rval, (type Rec [edi]).rval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpIntEQ;
// for msort ascending ...
procedure myCmp( a: pRec in esi; b: pRec in edi ); @returns("eax");
begin myCmp;
if( str.le( (type Rec [esi]).rval, (type Rec [edi]).rval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
procedure showRec( pr: pRec in eax ); @noframe;
begin showRec;
stdout.put( (type Rec [eax]).rval );
ret();
end showRec;
procedure showVec( var v: Vec );
begin showVec;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec[ebx]).size; inc( ecx ) ) do
intmul( @size(Rec), ecx, eax );
add( (type Vec[ebx]).ary, eax );
showRec( eax );
stdout.putc( ' ' );
endfor;
stdout.newln();
pop( ecx ); pop( ebx ); pop( eax );
end showVec;
static
fin: dword;
myRec: Rec;
myVec: Vec;
tmpStr: str.strvar( 32 );
begin VecString;
fileio.open( FNAME, fileio.r );
mov( eax, fin );
initVec( myVec );
while( readLine( fin, myRec.rval ) ) do
push_backVec( myVec, myRec );
endwhile;
fileio.close( fin );
stdout.puts( "showVec: " );
showVec( myVec );
mov( myVec.size, ecx );
//last = my_ary[ i-1 ];
dec( ecx );
mov( &myVec, ebx );
intmul( @size(Rec), ecx, eax );
add( (type Vec [ebx]).ary, eax );
mov( mov( (type Rec [eax]).rval, eax ), myRec.rval );
stdout.puts( nl "After isort... (descending)" nl );
mov( &myCmpInt, pMyCmp );
isortVec( myVec );
stdout.puts( "showVec: " );
showVec( myVec );
mov( &myCmpIntEQ, pMyCmp );
findVec( myVec, myRec ); // index returned in eax ...
if( (type int32 eax) >= 0 ) then // i.e. if found ...
eraseVec( myVec, eax ); // count eax holds index
stdout.put( nl "After erasing ", myRec.rval, "..." nl );
stdout.put( "showVec: " );
showVec( myVec );
else stdout.put( nl, myRec.rval, " NOT found in myVec." nl );
endif;
stdout.puts( nl "After msort... (ascending)" nl );
mov( &myCmp, pMyCmp );
msortVec( myVec );
stdout.puts( "showVec: " );
showVec( myVec );
stdout.put( nl "Before clear, size = ", myVec.size,
", capacity = ", myVec.capacity, nl );
clearVec( myVec );
stdout.put( "After clear, size = ", myVec.size,
", capacity = ", myVec.capacity, nl );
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end VecString;
A short example file, with the name "testStr.dat", to satisfy the above programs code, might look like this next short file:
Sam
Ann
Fran
Bamby
Candy
Lynne
Tim
Joe
Bill
Tom
Dick
Jane
Note: we are using readLine to read each file line into one string, so you will need to have file "readLine.hhf" accessible to be included.
And here is a very simple test program, that just demo's filling up an HLA vector of strings, FROM FILE, here using readLine ... and then displaying that HLA vector of strings to the screen ...
(Please also see the data file used ... I named it "test.dat" ... included below.)
program test_vecStr; // 2012-07-19 //
#include( "stdlib.hhf" )
#includeOnce( "readLine.hhf" )
const
FNAME: text := """test.dat""" ;
InitCap: uns32 := 2;
type
Rec: record
str: string;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @nodisplay;
begin freeRec;
free( (type Rec [eax]).str );
end freeRec;
// NOTE! The two types above and the procedure freeRec
// MUST be defined before this next include...
#includeOnce( "vector.hhf" );
#includeOnce( "vector_func's.hhf" );
procedure showRec( pr: pRec in eax ); @nodisplay; @noframe;
begin showRec;
stdout.put( "'", (type Rec [eax]).str, "'" );
str.length( (type Rec [eax]).str );
stdout.put( ", len = ", (type uns32 eax) );
ret();
end showRec;
procedure showVec( var v: Vec ); @nodisplay;
begin showVec;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec[ebx]).size; inc( ecx ) ) do
intmul( @size(Rec), ecx, eax );
add( (type Vec[ebx]).ary, eax );
showRec( eax );
stdout.newln();
endfor;
pop( ecx ); pop( ebx ); pop( eax );
end showVec;
static
fin: dword;
myRec: Rec;
myVec: Vec;
begin test_vecStr;
fileio.open( FNAME, fileio.r );
mov( eax, fin );
initVec( myVec );
while( readLine( fin, myRec.str ) ) do
push_backVec( myVec, myRec );
endwhile;
fileio.close( fin );
stdout.puts( "Showing vec of str ... " nl );
showVec( myVec );
stdout.put( "size = ", myVec.size, ", capacity = ", myVec.capacity, nl );
stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end test_vecStr;
Now the test data file I used and named it "test.dat"
z 3456789 123456789 123456789
2z
32z
444z
5555z
66666z
777z
88z
9z
z
Note that in my file, the first line is SUPPOSED to be empty ...
and the last line does NOT have a new line char at the end - but it doesn't matter/make_any_difference here, if it does.
And the HLA SLList of string example ...
8.
program SLListString; // 2012-09-03 //
#includeOnce( "readLine.hhf" )
const
FNAME: text := """testStr.dat""";
type
NNode: record
nval: string;
next: pointer to NNode;
endrecord;
pNNode: pointer to NNode;
procedure freeNNode( pn: pNNode in eax ); @nodisplay; @noframe;
begin freeNNode;
str.free( (type NNode [eax]).nval );
ret();
end freeNNode;
// NOTE! The two types above and the procedure freeNNode
// MUST be defined before this next include...
#includeOnce( "sllist_func's.hhf" ) // includes sllist.hhf that includes stdlib.hhf
// Note that sllist.hhf also has: ? @nodisplay:= true;
// So ... all procedures have @nodisplay 'as default' from here on ...
// for isort descending ...
procedure myCmpInt( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpInt;
if( str.ge( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure myCmpIntEQ( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpIntEQ;
if( str.eq( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpIntEQ;
// for msort ascending ...
procedure myCmp( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmp;
if( str.le( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
procedure showNNode( pn: pNNode in eax ); @noframe;
begin showNNode;
stdout.put( (type NNode [eax]).nval );
ret();
end showNNode;
procedure showSLList( var v: SLList );
begin showSLList;
push( eax );
mov( v, eax );
mov( (type SLList[eax]).head, eax );
while( eax ) do
showNNode( eax );
stdout.putc( ' ' );
mov( (type NNode[eax]).next, eax );
endwhile;
stdout.newln();
pop( eax );
end showSLList;
static
fin: dword;
myNNode: NNode;
mySLList: SLList;
begin SLListString;
fileio.open( FNAME, fileio.r );
mov( eax, fin );
initSLList( mySLList );
while( readLine( fin, myNNode.nval ) ) do
push_backSLList( mySLList, myNNode );
endwhile;
fileio.close( fin );
stdout.puts( "showSLList: " );
showSLList( mySLList );
mov( mySLList.tail, eax );
mov( mov( (type NNode [eax]).nval, eax ), myNNode.nval );
stdout.puts( nl "After isort... (descending)" nl );
mov( &myCmpInt, pMyCmp );
isortSLList( mySLList );
stdout.puts( "showSLList: " );
showSLList( mySLList );
mov( &myCmpIntEQ, pMyCmp );
findSLList( mySLList, myNNode ); // index returned in eax ...
if( eax ) then // i.e. if found ...
eraseSLList( mySLList, eax ); // count eax holds index
stdout.put( nl "After erasing ", myNNode.nval, "..." nl );
stdout.put( "showSLList: " );
showSLList( mySLList );
else stdout.put( nl, myNNode.nval, " NOT found in mySLList." nl );
endif;
stdout.puts( nl "After msort... (ascending)" nl );
mov( &myCmp, pMyCmp );
msortSLList( mySLList );
stdout.puts( "showSLList: " );
showSLList( mySLList );
stdout.put( nl "Before clear, mySLList.size = ", mySLList.size, nl );
clearSLList( mySLList );
stdout.put( "After clear, mySLList.size = ", mySLList.size, nl );
stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end SLListString;
A short example file, with the name "testStr.dat", to satisfy the above programs code, might look like this next short file:
Sam
Ann
Fran
Bamby
Candy
Lynne
Tim
Joe
Bill
Tom
Dick
Jane
Note: we are using readLine to read each file line into one string, so you will need to have file "readLine.hhf" accessible to be included.
And using SLList2...
program SLList2Str; // 2012-09-03 //
#includeOnce( "readLine.hhf" )
#includeOnce( "sllist2_func's.hhf" ) // includes sllist2.hhf that includes stdlib.hhf
// Note that sllist2.hhf also has: ? @nodisplay:= true;
// So ... all procedures have @nodisplay 'as default' from here on ...
const
FNAME: text := """testStr.dat""";
/*
type
NNode: record
nval: int32;
next: pointer to NNode;
endrecord;
pNNode: pointer to NNode;
*/
procedure myFreeNNode( pn: pNNode in eax ); @noframe;
begin myFreeNNode;
str.free( (type NNode [eax]).nval );
ret();
end myFreeNNode;
// for isort descending ...
procedure myCmpInt( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpInt;
if( str.ge( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure myCmpIntEQ( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpIntEQ;
if( str.eq( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpIntEQ;
// for msort ascending ...
procedure myCmp( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmp;
if( str.le( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
procedure showNNode( pn: pNNode in eax ); @noframe;
begin showNNode;
stdout.put( (type string (type NNode [eax]).nval) );
ret();
end showNNode;
procedure showSLList( var v: SLList );
begin showSLList;
push( eax );
mov( v, eax );
mov( (type SLList[eax]).head, eax );
while( eax ) do
showNNode( eax );
stdout.putc( ' ' );
mov( (type NNode[eax]).next, eax );
endwhile;
stdout.newln();
pop( eax );
end showSLList;
static
fin: dword;
myNNode: NNode;
mySLList: SLList;
begin SLList2Str;
fileio.open( FNAME, fileio.r );
mov( eax, fin );
initSLList( mySLList );
while( readLine( fin, myNNode.nval ) ) do
push_backSLList( mySLList, myNNode );
endwhile;
fileio.close( fin );
stdout.puts( "showSLList: " );
showSLList( mySLList );
mov( mySLList.tail, eax );
mov( mov( (type NNode [eax]).nval, eax ), myNNode.nval );
stdout.puts( nl nl "After isort...(descending)" nl );
mov( &myCmpInt, pMyCmp );
isortSLList( mySLList );
stdout.puts( "showSLList: " );
showSLList( mySLList );
mov( &myCmpIntEQ, pMyCmp );
findSLList( mySLList, myNNode ); // index returned in eax ...
if( eax ) then // i.e. if found ...
mov( &myFreeNNode, pFreeNNode );
eraseSLList( mySLList, eax ); // eax holds pointer
stdout.put( nl "After erasing ", (type string myNNode.nval), "..." nl );
stdout.put( "showSLList: " );
showSLList( mySLList );
else stdout.put( nl, myNNode.nval, " NOT found in mySLList." nl );
endif;
stdout.puts( nl "After msort... (ascending)" nl );
mov( &myCmp, pMyCmp );
msortSLList( mySLList );
stdout.puts( "showSLList: " );
showSLList( mySLList );
stdout.put( "mySLList.size = ", mySLList.size, nl );
mov( &myFreeNNode, pFreeNNode );
clearSLList( mySLList );
stdout.puts( nl "After clear..." nl );
stdout.puts( "showSLList: " );
showSLList( mySLList );
stdout.put( "mySLList.size = ", mySLList.size, nl );
stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end SLList2Str;
These next four example programs parse a file of text and find the unique words and the count of each unique word used in that text.
The first two programs demo the use of my HLA defined types ... CLList and Vec ... in the same program.
It makes good use of msort and split functions also, that need the programmer to define appropriate compare functions ... so the programmer can then pass in the appropriate address of those functions, via using HLA procedure function pointers.
In the first example, I consider case.
In the second example, I demo the HLA i (ignore) case compare string functions.
So, firstly, with case significant ...
(But first, here is my test file, I called "Genesis1.txt", taken from Genesis chapter 1 in the Holy Bible)
"In the beginning God created the heaven and the earth. And the earth was without form, and void; and darkness [was] upon the face of the deep. And the Spirit of God moved upon the face of the waters. And God said, Let there be light: and there was light. And God saw the light, that [it was] good: and God divided the light from the darkness. And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day. And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters. And God made the firmament, and divided the waters which [were] under the firmament from the waters which [were] above the firmament: and it was so. And God called the firmament Heaven. And the evening and the morning were the second day. And God said, Let the waters under the heaven be gathered together unto one place, and let the dry [land] appear: and it was so. And God called the dry [land] Earth; and the gathering together of the waters called he Seas: and God saw that [it was] good. And God said, Let the earth bring forth grass, the herb yielding seed, [and] the fruit tree yielding fruit after his kind, whose seed [is] in itself, upon the earth: and it was so. And the earth brought forth grass, [and] herb yielding seed after his kind, and the tree yielding fruit, whose seed [was] in itself, after his kind: and God saw that [it was] good. And the evening and the morning were the third day. And God said, Let there be lights in the firmament of the heaven to divide the day from the night; and let them be for signs, and for seasons, and for days, and years: And let them be for lights in the firmament of the heaven to give light upon the earth: and it was so. And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: [he made] the stars also. And God set them in the firmament of the heaven to give light upon the earth, And to rule over the day and over the night, and to divide the light from the darkness: and God saw that [it was] good. And the evening and the morning were the fourth day. And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl [that] may fly above the earth in the open firmament of heaven. And God created great whales, and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that [it was] good. And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth. And the evening and the morning were the fifth day. And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so. And God made the beast of the earth after his kind, and cattle after their kind, and every thing that creepeth upon the earth after his kind: and God saw that [it was] good. And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth. So God created man in his [own] image, in the image of God created he him; male and female created he them. And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth. And God said, Behold, I have given you every herb bearing seed, which [is] upon the face of all the earth, and every tree, in the which [is] the fruit of a tree yielding seed; to you it shall be for meat. And to every beast of the earth, and to every fowl of the air, and to every thing that creepeth upon the earth, wherein [there is] life, [I have given] every green herb for meat: and it was so. And God saw every thing that he had made, and, behold, [it was] very good. And the evening and the morning were the sixth day." (Ge 1:1-31 AV)
Note that this file ALSO demo's the need for my HLA readLine function, because it contains a VERY LONG line of text, that the built in HLA standard library fileio.a_gets( fin ) does NOT handle appropriately, by using just one LONG string, as readLine does correctly here.
Ok ... the first test program, that considers case ...
// uniqueCount.hla // // 2012-08-16 //
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program uniqueCount;
#include( "readLine.hhf" ) // also includes stdlib.hhf ...
//#includeOnce( "memory.hhf" ) // so can use str.free in freeNNode below
//#includeOnce( "stdio.hhf" ) // so can use stdio.tab below
const
FNAME: text := """genesis1.txt""";
MyDelimits: string := " .,;:?!()[]""" stdio.tab;
type
NNode: record
nval: string;
next: pointer to NNode;
endrecord;
pNNode: pointer to NNode;
? @nodisplay:= true; // All procedures have @nodisplay 'as default' now.
procedure freeNNode( pn: pNNode in eax ); @noframe;
begin freeNNode;
str.free( (type NNode [eax]).nval );
ret();
end freeNNode;
// NOTE! The two types above and the procedure freeNNode
// MUST be defined before this next include...
#includeOnce( "sllist_func's.hhf" ) // also includes sllist.hhf/stdlib.hhf
// for msort/isort ascending ...
procedure myCmp( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmp;
if( str.le( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
/*
// for find...
procedure myCmpEQ( a: pNNode in esi; b: pNNode in edi ); @returns("eax");
begin myCmpEQ;
if( str.eq( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpEQ;
*/
procedure showNNode( pn: pNNode in eax ); @noframe;
begin showNNode;
stdout.put( (type NNode [eax]).nval );
ret();
end showNNode;
procedure showSLList( var sll: SLList );
begin showSLList;
push( eax );
mov( sll, eax );
mov( (type SLList [eax]).head, eax );
while( eax != 0 ) do
stdout.putc( ''' );
showNNode( eax );
stdout.puts( "'" nl );
mov( (type NNode [eax]).next, eax );
//stdin.readLn();
endwhile;
pop( eax );
end showSLList;
type
Rec: record
rval: string;
num: uns32;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @noframe;
begin freeRec;
str.free( (type Rec [eax]).rval );
ret();
end freeRec;
// OK ... can now ...
#include( "vector_func's.hhf" )
// for msort in descending frequency ...
procedure myCmpRec( a: pRec in esi; b: pRec in edi ); @returns("eax");
begin myCmpRec;
mov( (type Rec [esi]).num, eax );
if( eax > (type Rec [edi]).num ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpRec;
// and then ... define these next two ...
procedure showRec( pr: pRec in eax ); @nodisplay; @noframe;
begin showRec;
stdout.put( "'", (type Rec [eax]).rval, "', ", (type Rec [eax]).num );
ret();
end showRec;
procedure showVec( var v: Vec ); @nodisplay;
var
count: uns32;
begin showVec;
push( eax ); push( ebx ); push( ecx ); push( edx );
mov( 0, edx ); // sum set to zero ...
mov( edx, count ); // also zero initial count
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec[ebx]).size; inc( ecx ) ) do
intmul( @size(Rec), ecx, eax );
add( (type Vec[ebx]).ary, eax );
inc( count );
stdout.put( "<", count:3, "> : " );
showRec( eax );
add( (type Rec [eax]).num, edx );
stdout.newln();
endfor;
stdout.put( "The total number of original words was ",
(type uns32 edx), nl );
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end showVec;
/*
procedure isortVec( var v: Vec ); // uses/needs pMyCmp(..)
static
rcmp: Rec;
tmpReg: dword;
begin isortVec;
push( eax ); push( ebx ); push( ecx ); push( edx ); push( esi ); push( edi );
//int i, j; // i in eax, j in edx
// start with an array of just the first 2 elements (if exists) ...
// for( i = 1; i < cv->size; ++i )
cld();
mov( v, ebx );
for( mov( 1, eax ); eax < (type Vec [ebx]).size; inc( eax ) ) do
// update this cmp Rec on each outer loop
//memcpy( &cmp, &cv->ary[i], sizeof(Rec) );
mov( &rcmp, edi );
intmul( @size(Rec), eax, esi );
add( (type Vec [ebx]).ary, esi );
mov( @size(Rec), ecx ); // get # bytes to copy in a Rec ... into ecx
rep.movsb(); // ok ... got copy into rcmp ...
// get index of element just to the left of the above 'cmp' to start comparisons
mov( eax, edx ); // j = i
dec( edx ); // --j // i.e. j = i-1; //
while( (type int32 edx) >= 0 ) do // while( j >= 0 && myCmp(&cmp, &cv->ary[j]) < 0 )
intmul( @size(Rec), edx, edi ); // get offset into edi ..
add( (type Vec [ebx]).ary, edi );
mov( &rcmp, esi );
//breakif( !pMyCmp(esi, edi) ); // 'copy up' // but first ...
mov( eax, tmpReg ); // get copy of loop counter in eax
pMyCmp( esi, edi );
if( eax ) then
mov( tmpReg, eax );
else
mov( tmpReg, eax );
break;
endif;
// Now ... 'copy up' ...
//memcpy( &cv->ary[j+1], &cv->ary[j], sizeof(Rec) );
intmul( @size(Rec), edx, esi );
add( (type Vec [ebx]).ary, esi );
mov( esi, edi );
add( @size(Rec), edi ); // to inc( j ) add size //
mov( @size(Rec), ecx ); // get # bytes to copy in a Rec into ecx
rep.movsb();
dec( edx ); //--j; // --j to prepare for next inner loop
endwhile;
// insert pointer at index j+1 (since j was decremented above ...
//memcpy( &cv->ary[j+1], &cmp, sizeof(Rec) );
inc( edx ); // ++j
mov( &rcmp, esi );
intmul( @size(Rec), edx, edi );
add( (type Vec [ebx]).ary, edi );
mov( @size(Rec), ecx ); // get # bytes to copy in a Rec into ecx
rep.movsb();
endfor;
pop( edi ); pop( esi ); pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end isortVec; // size hasn't changed ...
*/
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.getc();
stdin.flushInput();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
static
fin: dword;
s: string;
mySLList: SLList;
t: timer_t;
myVec: Vec;
myRec: Rec;
begin uniqueCount;
initSLList( mySLList );
fileio.open( FNAME, fileio.r );
mov( eax, fin );
t.create();
t.start();
while( readLine( fin, s ) ) do
// passing in (by ref) the SLList to hold a list of words
splitSLList( mySLList, s, MyDelimits );
// free the original string since done with it here
str.free( s );
endwhile;
fileio.close( fin );
t.stop();
stdout.put( "Showing the list of words, "
"each word below inside single quotes ..." nl );
showSLList( mySLList );
stdout.put( "mySLList.size = ", mySLList.size, nl );
stdout.put( "Time to read into list was ", (type uns64 t.Accumulated ),
" millisecs" )
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
t.start(); // start timer ...
mov( &myCmp, pMyCmp );
msortSLList( mySLList );
initVec( myVec );
//mov( &myCmpEQ, pMyCmp );
//uniqueSLList( mySLList );
mov( mySLList.head, ecx );
while( ecx != 0 ) do // get vector of (Records of) unique words (with count) ...
mov( (type NNode [ecx]).nval, myRec.rval ); // get copy of pointer to string
mov( 1, myRec.num ); // set initial count ...
mov( (type NNode [ecx]).next, ecx );
while( ecx && str.eq( myRec.rval, (type NNode [ecx]).nval ) ) do
inc( myRec.num ); // while repeats inc count
mov( (type NNode [ecx]).next, ecx ); // 'inc' ecx pointer ...
endwhile;
push( ecx );
//push( ebx ); push( ecx ); push( esi ); push( edi ); // caller must preserve
push_backVec( myVec, myRec ); // ok done here ... push_back
pop( ecx );
endwhile;
t.stop(); // stop timer ...
stdout.put( nl "Showing list of UNIQUE words, word COUNT "
"(each word inside single quotes) ..." nl );
showVec( myVec );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
stdout.put( "Time to msort and get unique list was ", (type uns64 t.Accumulated ),
" millisecs" nl );
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
mov( &myCmpRec, pMyCmp );
isortVec( myVec );
stdout.put( nl "Showing list of UNIQUE words, word COUNT "
"(in descending COUNT frequency) ..." nl );
showVec( myVec );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
stdout.put( "Before clear... mySLList.size = ", mySLList.size, nl );
clearSLList( mySLList );
stdout.put( "After clear... mySLList.size = ", mySLList.size, nl );
mem.free( myVec.ary ); // ok ... JUST free ary mem as strings all freeded above
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end uniqueCount;
And a test program that demo's ignoring case in the string comparisons. Note the VERY EASY and VERY FEW changes to the code needed to facilitate this change here ...
// uniqueCountIgnoreCase.hla // // 2012-08-16 //
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program uniqueCountIgnoreCase;
#include( "readLine.hhf" ) // also includes stdlib.hhf ...
//#includeOnce( "memory.hhf" ) // so can use str.free in freeNNode below
//#includeOnce( "stdio.hhf" ) // so can use stdio.tab below
const
FNAME: text := """genesis1.txt""";
MyDelimits: string := " .,;:?!()[]""" stdio.tab;
type
NNode: record
nval: string;
next: pointer to NNode;
endrecord;
pNNode: pointer to NNode;
? @nodisplay:= true; // All procedures have @nodisplay 'as default' now.
procedure freeNNode( pn: pNNode in eax ); @noframe;
begin freeNNode;
str.free( (type NNode [eax]).nval );
ret();
end freeNNode;
// NOTE! The two types above and the procedure freeNNode
// MUST be defined before this next include...
#includeOnce( "sllist_func's.hhf" ) // also includes sllist.hhf/stdlib.hhf
// for msort/isort ascending ...
procedure myCmp( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmp;
if( str.ile( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
/*
// for find...
procedure myCmpEQ( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpEQ;
if( str.eq( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpEQ;
*/
procedure showNNode( pn: pNNode in eax ); @noframe;
begin showNNode;
stdout.put( (type NNode [eax]).nval );
ret();
end showNNode;
procedure showSLList( var sll: SLList );
begin showSLList;
push( eax );
mov( sll, eax );
mov( (type SLList [eax]).head, eax );
while( eax != 0 ) do
stdout.putc( ''' );
showNNode( eax );
stdout.puts( "'" nl );
mov( (type NNode [eax]).next, eax );
//stdin.readLn();
endwhile;
pop( eax );
end showSLList;
type
Rec: record
rval: string;
num: uns32;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @noframe;
begin freeRec;
str.free( (type Rec [eax]).rval );
ret();
end freeRec;
// OK ... can now ...
#include( "vector_func's.hhf" )
// for msort in descending frequency ...
procedure myCmpRec( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpRec;
mov( (type Rec [esi]).num, eax );
if( eax > (type Rec [edi]).num ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpRec;
// and then ... define these next two ...
procedure showRec( pr: pRec in eax ); @nodisplay; @noframe;
begin showRec;
stdout.put( "'", (type Rec [eax]).rval, "', ", (type Rec [eax]).num );
ret();
end showRec;
procedure showVec( var v: Vec ); @nodisplay;
var
count: uns32;
begin showVec;
push( eax ); push( ebx ); push( ecx ); push( edx );
mov( 0, edx ); // sum set to zero ...
mov( edx, count ); // also zero initial count
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec[ebx]).size; inc( ecx ) ) do
intmul( @size(Rec), ecx, eax );
add( (type Vec[ebx]).ary, eax );
inc( count );
stdout.put( "<", count:3, "> : " );
showRec( eax );
add( (type Rec [eax]).num, edx );
stdout.newln();
endfor;
stdout.put( "The total number of original words was ",
(type uns32 edx), nl );
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end showVec;
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.getc();
stdin.flushInput();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
static
fin: dword;
s: string;
mySLList: SLList;
t: timer_t;
myVec: Vec;
myRec: Rec;
begin uniqueCountIgnoreCase;
initSLList( mySLList );
fileio.open( FNAME, fileio.r );
mov( eax, fin );
t.create();
t.start();
while( readLine( fin, s ) ) do
// passing in (by ref) the SLList to hold a list of words
splitSLList( mySLList, s, MyDelimits );
// free the original string since done with it here
str.free( s );
endwhile;
fileio.close( fin );
t.stop();
stdout.put( "Showing the list of words, "
"each word below inside single quotes ..." nl );
showSLList( mySLList );
stdout.put( "mySLList.size = ", mySLList.size, nl );
stdout.put( "Time to read into list was ", (type uns64 t.Accumulated ),
" millisecs" )
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
t.start(); // start timer ...
mov( &myCmp, pMyCmp );
msortSLList( mySLList );
initVec( myVec );
//mov( &myCmpEQ, pMyCmp );
//uniqueSLList( mySLList );
mov( mySLList.head, ecx );
while( ecx != 0 ) do // get vector of (Records of) unique words (with count) ...
mov( (type NNode [ecx]).nval, myRec.rval ); // get copy of pointer to string
mov( 1, myRec.num ); // set initial count ...
mov( (type NNode [ecx]).next, ecx );
while( ecx && str.ieq( myRec.rval, (type NNode [ecx]).nval ) ) do // ignore case
inc( myRec.num ); // while repeats inc count
mov( (type NNode [ecx]).next, ecx ); // 'inc' ecx pointer ...
endwhile;
push( ecx );
//push( ebx ); push( ecx ); push( esi ); push( edi ); // caller must preserve if needed
push_backVec( myVec, myRec ); // ok done here ... push_back
pop( ecx );
endwhile;
t.stop(); // stop timer ...
stdout.put( nl "Showing list of UNIQUE words, word COUNT "
"(each word inside single quotes) ..." nl );
showVec( myVec );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
stdout.put( "Time to msort and get unique list was ", (type uns64 t.Accumulated ),
" millisecs" nl );
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
mov( &myCmpRec, pMyCmp );
isortVec( myVec );
stdout.put( nl "Showing list of UNIQUE words, word COUNT "
"(in descending COUNT frequency) ..." nl );
showVec( myVec );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
stdout.put( "Before clear... mySLList.size = ", mySLList.size, nl );
clearSLList( mySLList );
stdout.put( "After clear... mySLList.size = ", mySLList.size, nl );
mem.free( myVec.ary ); // ok ... JUST free ary mem as strings all freeded above
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end uniqueCountIgnoreCase;
Now using readWord ... (and vector2.hhf) ...
// uniqueCount_readWord.hla // // 2012-08-22 //
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program uniqueCount_readWord;
#includeOnce( "readWord.hhf" ) // also includes stdlib.hhf ...
#includeOnce( "vector2_func's.hhf" ) // includes vector2.hhf & stdlib.hhf
//? @nodisplay:= true; //
//All procedures have @nodisplay 'as default' now ... included above //
//#includeOnce( "memory.hhf" ) // so can use str.free in freeNNode below
//#includeOnce( "stdio.hhf" ) // so can use stdio.tab below
const
FNAME: text := """genesis1.txt""";
MyDelimits: string := " .,;:?!()[]""" nl stdio.tab;
type
Rec: record
rval: string;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @noframe;
begin freeRec;
str.free( (type Rec [eax]).rval );
ret();
end freeRec;
// for msort/isort ascending ...
procedure myCmp( a: pRec in esi; b: pRec in edi ); @returns("eax");
begin myCmp;
if( str.le( (type Rec [esi]).rval, (type Rec [edi]).rval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
procedure showRec( pr: pRec in eax ); @noframe;
begin showRec;
stdout.put( (type Rec [eax]).rval );
ret();
end showRec;
procedure showVec( var vc: Vec );
begin showVec;
push( eax ); push( ebx ); push( ecx );
mov( vc, ebx );
for( mov( 0, ecx ); ecx < (type Vec [ebx]).size; inc( ecx ) ) do
stdout.putc( ''' );
intmul( @size( Rec ), ecx, eax );
add( (type Vec [ebx]).ary, eax );
showRec( eax );
stdout.puts( "'" nl );
endfor;
pop( ecx ); pop( ebx ); pop( eax );
end showVec;
type
Rec2: record
rval: string;
num: uns32;
endrecord;
pRec2: pointer to Rec2;
/*
procedure freeRec2( pr: pRec in eax ); @noframe;
begin freeRec2;
str.free( (type Rec2 [eax]).rval );
ret();
end freeRec2;
*/
// for msort in descending frequency ...
procedure myCmpRec2( a: pRec2 in esi; b: pRec2 in edi ); @returns("eax");
begin myCmpRec2;
mov( (type Rec2 [esi]).num, eax );
if( eax >= (type Rec2 [edi]).num ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpRec2;
// and then ... define these next two ...
procedure showRec2( pr: pRec2 in eax ); @nodisplay; @noframe;
begin showRec2;
stdout.put( "'", (type Rec2 [eax]).rval, "', ", (type Rec2 [eax]).num );
ret();
end showRec2;
procedure showVec2( var v: Vec ); @nodisplay;
var
count: uns32;
begin showVec2;
push( eax ); push( ebx ); push( ecx ); push( edx );
mov( 0, edx ); // sum set to zero ...
mov( edx, count ); // also zero initial count
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec[ebx]).size; inc( ecx ) ) do
intmul( @size(Rec2), ecx, eax );
add( (type Vec[ebx]).ary, eax );
inc( count );
stdout.put( "<", count:3, "> : " );
showRec2( eax );
add( (type Rec2 [eax]).num, edx );
stdout.newln();
endfor;
stdout.put( "The total number of original words was ",
(type uns32 edx), nl );
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end showVec2;
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.getc();
stdin.flushInput();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
static
fin: dword;
reg32: dword;
s: string;
myVec: Vec;
myRec: Rec;
t: timer_t;
myVec2: Vec;
myRec2: Rec2;
begin uniqueCount_readWord;
initVec( myVec, @size( Rec ) );
fileio.open( FNAME, fileio.r );
mov( eax, fin );
t.create();
t.start();
while( readWord( fin, s, MyDelimits ) ) do
mov( eax, myRec.rval );
push_backVec( myVec, &myRec );
endwhile;
fileio.close( fin );
t.stop();
stdout.put( "Showing the Vec of words, "
"each word below inside single quotes ..." nl );
showVec( myVec );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
stdout.put( "Time to read into Vec was ", (type uns64 t.Accumulated ),
" millisecs" )
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
t.start(); // start timer ...
mov( &myCmp, pMyCmp );
msortVec( myVec );
initVec( myVec2, @size( Rec2 ) );
// get vector of (Records of) unique words (with count) ...
for( mov( 0, ecx ); ecx < myVec.size; nop() ) do // ecx is ++ in loop ...
intmul( @size( Rec ), ecx, eax );
add( myVec.ary, eax );
mov( (type Rec [eax]).rval, myRec2.rval ); // get copy of pointer to string
mov( 1, myRec2.num ); // set initial count ...
add( @size( Rec ), eax );
inc( ecx ); // ++ ecx in body of loop
mov( eax, reg32 ); // preserve eax ...
while( ecx < myVec.size && str.eq( myRec2.rval, (type Rec [eax]).rval ) ) do
inc( myRec2.num ); // while repeats inc count
inc( ecx ); // 'inc' ecx pointer ...
//mov( reg32, eax );
//add( @size( Rec ), eax );
//mov( eax, reg32 );
add( @size( Rec ), reg32 );
mov( reg32, eax );
endwhile;
push( ecx ); // preserve ecx
push_backVec( myVec2, &myRec2 ); // ok done here ... push_back
pop( ecx );
endfor;
t.stop(); // stop timer ...
stdout.put( nl "Showing Vec2 of UNIQUE words, word COUNT "
"(each word inside single quotes) ..." nl );
showVec2( myVec2 );
stdout.put( "myVec2.size = ", myVec2.size,
", myVec2.capacity = ", myVec2.capacity, nl );
stdout.put( "Time to msort and get unique Vec2 was ", (type uns64 t.Accumulated ),
" millisecs" nl );
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
mov( &myCmpRec2, pMyCmp );
msortVec( myVec2 );
stdout.put( nl "Showing list of UNIQUE words, word COUNT "
"(in descending COUNT frequency) ..." nl );
showVec2( myVec2 );
stdout.put( "myVec2.size = ", myVec2.size,
", myVec2.capacity = ", myVec2.capacity, nl );
stdout.put( "Before clear... myVec.size = ", myVec.size, nl );
mov( &freeRec, pFreeRec );
clearVec( myVec );
stdout.put( "After clear... myVec.size = ", myVec.size, nl );
mem.free( myVec2.ary ); // ok ... JUST free ary mem as strings all freeded above
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end uniqueCount_readWord;
And using readWord but with ignore case comparisons ... (and vector2.hhf) ...
// uniqueCountIC_readWord.hla // // 2012-08-22 //
// http://developers-heaven.net/forum/index.php/topic,46.0.html
program uniqueCountIC_readWord;
#includeOnce( "readWord.hhf" ) // also includes stdlib.hhf ...
#includeOnce( "vector2_func's.hhf" ) // includes vector2.hhf & stdlib.hhf
//? @nodisplay:= true; //
//All procedures have @nodisplay 'as default' now ... included above //
//#includeOnce( "memory.hhf" ) // so can use str.free in freeNNode below
//#includeOnce( "stdio.hhf" ) // so can use stdio.tab below
const
FNAME: text := """genesis1.txt""";
MyDelimits: string := " .,;:?!()[]""" nl stdio.tab;
type
Rec: record
rval: string;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @noframe;
begin freeRec;
str.free( (type Rec [eax]).rval );
ret();
end freeRec;
// for msort/isort ascending ...
procedure myCmp( a: pRec in esi; b: pRec in edi ); @returns("eax");
begin myCmp;
if( str.ile( (type Rec [esi]).rval, (type Rec [edi]).rval ) ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
procedure showRec( pr: pRec in eax ); @noframe;
begin showRec;
stdout.put( (type Rec [eax]).rval );
ret();
end showRec;
procedure showVec( var vc: Vec );
begin showVec;
push( eax ); push( ebx ); push( ecx );
mov( vc, ebx );
for( mov( 0, ecx ); ecx < (type Vec [ebx]).size; inc( ecx ) ) do
stdout.putc( ''' );
intmul( @size( Rec ), ecx, eax );
add( (type Vec [ebx]).ary, eax );
showRec( eax );
stdout.puts( "'" nl );
endfor;
pop( ecx ); pop( ebx ); pop( eax );
end showVec;
type
Rec2: record
rval: string;
num: uns32;
endrecord;
pRec2: pointer to Rec2;
/*
procedure freeRec2( pr: pRec in eax ); @noframe;
begin freeRec2;
str.free( (type Rec2 [eax]).rval );
ret();
end freeRec2;
*/
// for msort in descending frequency ...
procedure myCmpRec2( a: pRec2 in esi; b: pRec2 in edi ); @returns("eax");
begin myCmpRec2;
mov( (type Rec2 [esi]).num, eax );
if( eax >= (type Rec2 [edi]).num ) then
mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpRec2;
// and then ... define these next two ...
procedure showRec2( pr: pRec2 in eax ); @nodisplay; @noframe;
begin showRec2;
stdout.put( "'", (type Rec2 [eax]).rval, "', ", (type Rec2 [eax]).num );
ret();
end showRec2;
procedure showVec2( var v: Vec ); @nodisplay;
var
count: uns32;
begin showVec2;
push( eax ); push( ebx ); push( ecx ); push( edx );
mov( 0, edx ); // sum set to zero ...
mov( edx, count ); // also zero initial count
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec[ebx]).size; inc( ecx ) ) do
intmul( @size(Rec2), ecx, eax );
add( (type Vec[ebx]).ary, eax );
inc( count );
stdout.put( "<", count:3, "> : " );
showRec2( eax );
add( (type Rec2 [eax]).num, edx );
stdout.newln();
endfor;
stdout.put( "The total number of original words was ",
(type uns32 edx), nl );
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end showVec2;
// defaults to 'true' ... unless 'n' or 'N' entered
procedure more; @nodisplay; @returns( "al" );
begin more;
stdout.puts( "More (y/n) ? " );
stdin.getc();
stdin.flushInput();
chars.toLower( al );
if( al == 'n' ) then mov( false, al );
else mov( true, al );
endif;
end more;
static
fin: dword;
reg32: dword;
s: string;
myVec: Vec;
myRec: Rec;
t: timer_t;
myVec2: Vec;
myRec2: Rec2;
begin uniqueCountIC_readWord;
initVec( myVec, @size( Rec ) );
fileio.open( FNAME, fileio.r );
mov( eax, fin );
t.create();
t.start();
while( readWord( fin, s, MyDelimits ) ) do
mov( eax, myRec.rval );
push_backVec( myVec, &myRec );
endwhile;
fileio.close( fin );
t.stop();
stdout.put( "Showing the Vec of words, "
"each word below inside single quotes ..." nl );
showVec( myVec );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
stdout.put( "Time to read into Vec was ", (type uns64 t.Accumulated ),
" millisecs" )
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
t.start(); // start timer ...
mov( &myCmp, pMyCmp );
msortVec( myVec );
initVec( myVec2, @size( Rec2 ) );
// get vector of (Records of) unique words (with count) ...
for( mov( 0, ecx ); ecx < myVec.size; nop() ) do // ecx is ++ in loop ...
intmul( @size( Rec ), ecx, eax );
add( myVec.ary, eax );
mov( (type Rec [eax]).rval, myRec2.rval ); // get copy of pointer to string
mov( 1, myRec2.num ); // set initial count ...
add( @size( Rec ), eax );
inc( ecx ); // ++ ecx is done inside loop
mov( eax, reg32 ); // preserve eax ...
while( ecx < myVec.size && str.ieq( myRec2.rval, (type Rec [eax]).rval ) ) do
inc( myRec2.num ); // while repeats inc count
inc( ecx ); // 'inc' ecx pointer ...
//mov( reg32, eax );
//add( @size( Rec ), eax );
//mov( eax, reg32 );
add( @size( Rec ), reg32 );
mov( reg32, eax );
endwhile;
push( ecx ); // preserve ecx
push_backVec( myVec2, &myRec2 ); // ok done here ... push_back
pop( ecx );
endfor;
t.stop(); // stop timer ...
stdout.put( nl "Showing Vec2 of UNIQUE words, word COUNT "
"(each word inside single quotes) ..." nl );
showVec2( myVec2 );
stdout.put( "myVec2.size = ", myVec2.size,
", myVec2.capacity = ", myVec2.capacity, nl );
stdout.put( "Time to msort and get unique Vec2 was ", (type uns64 t.Accumulated ),
" millisecs" nl );
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
mov( &myCmpRec2, pMyCmp );
msortVec( myVec2 );
stdout.put( nl "Showing list of UNIQUE words, word COUNT "
"(in descending COUNT frequency) ..." nl );
showVec2( myVec2 );
stdout.put( "myVec2.size = ", myVec2.size,
", myVec2.capacity = ", myVec2.capacity, nl );
stdout.put( "Before clear... myVec.size = ", myVec.size, nl );
mov( &freeRec, pFreeRec );
clearVec( myVec );
stdout.put( "After clear... myVec.size = ", myVec.size, nl );
mem.free( myVec2.ary ); // ok ... JUST free ary mem as strings all freeded above
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn(); // keep 'Window' open until 'Enter' key is pressed
end uniqueCountIC_readWord;
This simple example is a POPULAR STUDENT type problem ...
programming a contact list with edit/delete/sort/add/file/unique functions ...
(here using an HLA Vec container type) to hold each record/Contact
Note also that the included file, "vector2_func's.hhf", also calls for the inclusion of the file "vector2.hhf"
These two above mention enhanced files, "vector2_func's.hhf" and "vector2.hhf", (that use dword - like C 'void' pointers) ... allow the user to have as many different kinds of programmer defined records as needed in the same program, using the Vec (2) type container .hhf files ...(More about this to follow, if time ... but see my Cvec2 and Clist2 types at the above link to get a C reference/starting-point ... to see how this was done in C)
program ContactsVector2; // 2012-09-03 // testing vector2.hhf & vector2_func's.hhf
#includeOnce( "readLine.hhf" )
#includeOnce( "vector2_func's.hhf" ) // also has includes vector2.hhf
// NOTE that ALSO set by above include vector2.hhf ... ? @nodisplay:= true;
// So ... all procedures have @nodisplay 'as default' from here on ...
const
FNAME: text := """contacts.dat"""; // each """ includes one " in output
static
// global variables utilized in program (to keep it simple here)
Sorted: boolean := false;
Done: boolean := false;
Update: boolean := false;
type
MyContact: record
theName: string;
thePhone: string;
endrecord;
static
myBook: Vec; // Vec type was defined above in included file "vector2.hhf"
myC: MyContact;
procedure destroyRec( p: dword in eax ); @noframe;
begin destroyRec;
str.free( (type MyContact [eax]).theName );
str.free( (type MyContact [eax]).thePhone );
ret();
end destroyRec;
// for msort... by names ...
procedure myCmp( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmp;
if( str.le( (type MyContact [esi]).theName,
(type MyContact [edi]).theName ) ) then
mov( 1, eax );
else
mov( 0, eax );
endif;
end myCmp;
// for isort... by names ...
procedure myCmp2( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmp2;
if( str.lt( (type MyContact [esi]).theName,
(type MyContact [edi]).theName ) ) then
mov( 1, eax );
else
mov( 0, eax );
endif;
end myCmp2;
// for find by name ...
procedure myCmpEQ( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpEQ;
if( str.eq( (type MyContact [esi]).theName,
(type MyContact [edi]).theName ) ) then
mov( 1, eax );
else
mov( 0, eax );
endif;
end myCmpEQ;
procedure takeIn( message:string; value:string ); @returns("eax");
begin takeIn;
push( edi );
forever;
stdout.puts( message );
if( str.length( value ) > 0 ) then
stdout.put( "(", value, "): " );
else
stdout.puts( ": " );
endif;
stdin.flushInput();
stdin.a_gets();
mov( eax, edi );
// ensure first letter is Upper Case ...
mov( chars.toUpper( [edi] ), (type char [edi]) );
stdout.put("You input '", (type string edi), "' Ok (y/n) ? " );
stdin.getc();
chars.toLower( al );
if( al == 'y' ) then
mov( edi, eax );
break;
else
str.free( edi );
endif;
endfor;
pop( edi );
end takeIn;
procedure fileBook( var v: Vec );
var
fout: dword;
rsize: uns32;
begin fileBook;
push( eax ); push( ebx ); push( ecx ); push( edx );
try
fileio.openNew( FNAME ); // overwrites any existing file
mov( eax, fout );
mov( v, ebx );
mov( (type Vec [ebx]).elen, rsize );
for( mov( 0, ecx ); ecx < (type Vec [ebx]).size; inc( ecx ) ) do
mov( rsize, edx );
intmul( ecx, edx );
add( (type Vec [ebx]).ary, edx );
fileio.put( fout, (type MyContact[edx]).theName, nl );
fileio.put( fout, (type MyContact[edx]).thePhone, nl );
endfor;
fileio.close( fout );
exception( ex.FileOpenFailure )
stdout.put( "There was a problem opening file ", FNAME,
" for output." nl );
endtry;
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end fileBook;
// Total number of contacts is stored in global variable RecCount
procedure addContacts( var v: Vec );
var
oldSize:uns32;
rsize: uns32;
static
newC: MyContact;
begin addContacts;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
mov( (type Vec [ebx]).size, oldSize );
mov( (type Vec [ebx]).elen, rsize );
stdout.puts( "To abort/exit, just enter/accept an empty line "
"for 'name' or 'phone' ... " nl );
forever
mov( takeIn( "Enter name ", "" ), newC.theName );
mov( takeIn( "Enter phone ", "" ), newC.thePhone );
if( str.length(newC.theName) && str.length(newC.thePhone) ) then
push_backVec( (type Vec [ebx]), &newC );
else
str.free( newC.thePhone );
str.free( newC.theName );
stdout.puts( "Ok ... aborted ... " );
endif;
stdout.puts( nl "More y/n ? " );
stdin.flushInput();
stdin.getc();
chars.toLower( al );
breakif( al == 'n' );
endfor;
mov( (type Vec [ebx]).size, ecx );
if( ecx > oldSize ) then // Contacts were added ...
mov( &myCmp2, pMyCmp ); // so can isort... ok, when called ...
isortVec( (type Vec [ebx]) ); // also updates Update
mov( true, Sorted );
mov( true, Update );
endif;
pop( ecx ); pop( ebx); pop( eax );
end addContacts;
// returns count of records in file in Vec size parameter
procedure inputBook_fromFile( var v: Vec );
var
fin: dword;
static
myC: MyContact;
begin inputBook_fromFile;
push( eax ); push( ebx );
try
fileio.open( FNAME, fileio.r ); // open file for reading
mov( eax, fin );
mov( v, ebx );
while( !fileio.eof( fin) ) do
// allocate space for new string and
// mov pointer into array (of pointers)
fileio.a_gets( fin ); // returns new string in eax
mov( eax, myC.theName ); // get Contact
fileio.a_gets( fin);
mov( eax, myC.thePhone );
push_backVec( (type Vec [ebx]), &myC );
endwhile;
fileio.close( fin );
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();
chars.toLower( al );
if( al == 'y' ) then
mov( v, ebx );
addContacts( (type Vec [ebx]) );
endif;
endtry;
pop( ebx ); pop( eax );
end inputBook_fromFile;
procedure editContact( var v: Vec; i: int32 in eax );
var
s: string;
begin editContact;
push( ebx );
mov( v, ebx );
if( (type Vec [ebx]).size > 0 ) then // need at least 1 record to edit
push( eax ); push( ecx ); push( edx );
mov( (type Vec [ebx]).elen, edx );
intmul( eax, edx );
add( (type Vec [ebx]).ary, edx );
// free old allocated strings and overwite with new ... (if updated )
mov( (type MyContact [edx]).theName, eax );
mov( eax, s ); // get copy of pointer into s ...
stdout.puts( "To abort/exit, just enter/accept an empty "
"line for a name ... " nl );
mov( takeIn( "Enter name ", s ), (type MyContact [edx]).theName );
if( str.length( (type MyContact [edx]).theName ) ) then // if NOT empty ...
str.free( s );
mov( (type MyContact [edx]).thePhone, eax );
mov( eax, s ); // get copy into s ...
mov( takeIn( "Enter phone ", s ), (type MyContact [edx]).thePhone );
str.free( s );
mov( &myCmp, pMyCmp ); // so can msort ok, when called ...
msortVec( (type Vec [ebx]) ); // also updates Update ...
mov( true, Sorted );
mov( true, Update );
else
str.free( (type MyContact [edx]).theName ); // free rejected entry ...
mov( mov( s, eax ), (type MyContact [edx]).theName ); // restore original
stdout.puts( "Ok ... edit aborted ... " nl );
endif;
pop( edx ); pop( ecx ); pop( eax );
endif;
pop( ebx );
end editContact;
/*
procedure deleteContact( var v: Vec );
var
index: uns32;
begin deleteContact;
push( ebx );
mov( v, ebx );
if( (type Vec [ebx]).size > 0 ) then // can't delete 0 records
push( eax ); push (ecx ); push( esi ); push( edi );
takeInValidNum( (type Vec [ebx]).size );
// returns valid num 1..RecCount in eax
dec( eax ); // to get to proper record index to delete
mov( eax, index );
mov( (type Vec [ebx]).elen, eax );
intmul( index, eax );
add( (type Vec [ebx]).ary, eax );
pFreeRec( eax );
// need at least 2 rec's to be able to move some down over one ...
mov( (type Vec [ebx]).size, ecx );
if( ecx > 1 ) then
cld();
mov( ecx, esi ); // if ecx-1 - eax > 1
dec( esi );
sub( index, esi );
if( esi > 0 ) then // copy last chunk down one record size
//inc( esi );
mov( esi, ecx );
intmul( (type Vec [ebx]).elen, ecx ); // bytes to mov in ecx
mov( (type Vec [ebx]).elen, edi );
intmul( index, edi );
add( (type Vec [ebx]).ary, edi );
mov( edi, esi );
add( (type Vec [ebx]).elen, esi );
rep.movsb();
endif;
endif;
dec( (type Vec [ebx]).size );
pop( edi ); pop( esi ); pop( ecx ); pop( eax );
endif;
pop( ebx );
end deleteContact;
*/
procedure showBook( var v: Vec );
var
lineCount: int32;
begin showBook;
push( eax ); push( ebx ); push( ecx );
// a little different formatting ...
console.cls();
stdout.puts
(
nl "Your 'book' : __________________________________________________" nl
);
mov( 2, lineCount );
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec [ebx]).size; inc( ecx ) ) do
inc( lineCount );
mov( (type Vec [ebx]).elen, eax );
intmul( ecx, eax );
add( (type Vec [ebx]).ary, eax );
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( ": ", (type MyContact [eax]).theName : -24 );
stdout.puts( " ---> " );
stdout.put( (type MyContact [eax]).thePhone : 15 )
endfor;
pop( ecx ); pop( ebx ); pop( eax );
end showBook;
procedure showMenu( var v: Vec );
var
s: string;
oldSize: uns32;
begin showMenu;
push( eax ); push( ebx );
mov( v, ebx );
showBook( (type Vec [ebx]) );
stdout.put
(
nl nl "Total contacts now in memory = ", (type Vec [ebx]).size,
", capacity = ", (type Vec [ebx]).capacity, "."
nl nl "Add, Delete, Edit, Sort, XDuplicates or Quit (a, d, e, s, x, q) ? "
);
stdin.flushInput();
stdin.getc();
chars.toLower( al );
if( al == 'a' ) then
addContacts( (type Vec [ebx]) );
elseif( al == 'd' ) then
//mov( &destroyRec, pFreeRec );
//deleteContact( (type Vec [ebx]) );
stdout.puts( "To abort/exit, just enter/accept an empty "
"line for a name ... " nl );
mov( takeIn( "Enter name to find", "" ),
myC.theName ); // returns in eax then copies pointer to myC.string
if( str.length( myC.theName ) ) then
mov( &myCmpEQ, pMyCmp ); // so can use findVec (EQ)
findVec( (type Vec [ebx]), &myC ); // returns index in eax (-1 if not found)
if( eax != -1 ) then
inc( eax ); // convert index to position ...
stdout.put( "Found at position ", (type uns32 eax), " so erasing ... " nl );
dec( eax ); // now restore as index ...
mov( &destroyRec, pFreeRec );
eraseVec( (type Vec [ebx]), eax ); // a library proc
else
stdout.put( myC.theName, " was NOT found ... " nl );
str.free( myC.theName );
endif;
else
str.free( myC.theName );
stdout.puts( "Ok ... aborting delete ... " nl );
endif;
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
elseif( al == 'e' ) then
stdout.puts( "To abort/exit, just enter/accept an empty "
"line for a name ... " nl );
mov( takeIn( "Enter name to find", "" ),
myC.theName ); // returns in eax then copies pointer to myC.string
if( str.length( myC.theName ) ) then
mov( &myCmpEQ, pMyCmp ); // so can use findVec (EQ)
findVec( (type Vec [ebx]), &myC ); // returns indwx in eax (-1 if not found)
if( eax != -1 ) then
stdout.put( "Found at index ", (type uns32 eax), nl );
editContact( (type Vec [ebx]), eax );
else
stdout.put( myC.theName, " was NOT found ... " nl );
str.free( myC.theName );
endif;
else
str.free( myC.theName );
stdout.puts( "Ok ... aborting edit ... " nl );
endif;
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
elseif( al == 's' ) then
mov( &myCmp, pMyCmp ); // so can msort... ok, when called
msortVec( (type Vec [ebx]) );
mov( true, Sorted );
mov( true, Update );
elseif( al == 'x' ) then
if( !Sorted ) then
mov( &myCmp, pMyCmp ); // so can msort... ok, when called
msortVec( (type Vec [ebx]) );
mov( true, Sorted );
mov( true, Update );
endif;
mov( &myCmpEQ, pMyCmp ); // so can cmp (EQ)... ok, when called
mov( &destroyRec, pFreeRec );
mov( v, ebx );
mov( (type Vec [ebx]).size, oldSize );
xDuplicates( (type Vec [ebx]) ); // pre-sort array to 'chop' duplicates
mov( (type Vec [ebx]).size, eax );
if( eax < oldSize ) then
mov( true, Update ); // and ... will update 'contacts.dat' file
endif;
elseif( al == 'q' ) then
mov( true, Done ); // 'Done' is also a global variable
endif;
pop( ebx ); pop( eax );
end showMenu;
begin ContactsVector2;
initVec( myBook, @size(MyContact) );
reserveVec( myBook, 3 );
mov( &destroyRec, pFreeRec );
inputBook_fromFile( myBook ); // returns the record count in size parameter
repeat
showMenu( myBook );
until( Done );
if( Update ) then
fileBook( myBook );
stdout.put( nl "Ok ... your BOOK should NOW be filed in file '",
FNAME, "' ... " nl );
endif; // update file with changes ...
stdout.put( nl "Before clear... myBook.size = ", myBook.size,
", myBook.capacity = ", myBook.capacity, nl );
clearVec( myBook );
stdout.put( "After clear... myBook.size = ", myBook.size,
", myBook.capacity = ", myBook.capacity, nl );
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end ContactsVector2;
You will find the 3 files you need to have available to include ...
"readLine.hhf'
"vector2_func's.hhf"
"vector2.hhf"
at this next link:
http://developers-heaven.net/forum/index.php?topic=2600.0
Now here is the above Contact program, but using a SLList ...
program ContactsSLList2; // 2012-09-03 // testing sllist2.hhf & sllist2_func's.hhf
#includeOnce( "readLine.hhf" )
#includeOnce( "sllist2_func's.hhf" ) // also has includes sllist2.hhf
// NOTE that ALSO set by above include sslist2.hhf ... ? @nodisplay:= true;
// So ... all procedures have @nodisplay 'as default' from here on ...
const
FNAME: text := """contacts.dat"""; // each """ includes one " in output
static
// global variables utilized in program (to keep it simple here)
Sorted: boolean := false;
Done: boolean := false;
Update: boolean := false;
type
MyContact: record
theName: string;
thePhone: string;
endrecord;
static
myBook: SLList; // SLList type was defined above in included file "sllist2.hhf"
procedure destroyMyC( p: dword in eax ); @noframe;
begin destroyMyC;
push( ebx );
mov( [eax], ebx );
str.free( (type MyContact [ebx]).theName );
str.free( (type MyContact [ebx]).thePhone );
mem.free( ebx );
pop( ebx );
ret();
end destroyMyC;
// for isort/msort... by names ...
procedure myCmp( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmp;
push( ebx );
mov( [esi], eax );
mov( [edi], ebx );
if( str.le( (type MyContact [eax]).theName,
(type MyContact [ebx]).theName ) ) then
mov( 1, eax );
else
mov( 0, eax );
endif;
pop( ebx );
end myCmp;
// for find by name ...
procedure myCmpEQ( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpEQ;
push( ebx );
mov( [esi], eax );
mov( [edi], ebx );
if( str.eq( (type MyContact [eax]).theName,
(type MyContact [ebx]).theName ) ) then
mov( 1, eax );
else
mov( 0, eax );
endif;
pop( ebx );
end myCmpEQ;
// returns string 'taken in' in eax ...
procedure takeIn( message:string; value:string ); @returns("eax");
begin takeIn;
push( edi );
forever;
stdout.puts( message );
if( str.length( value ) > 0 ) then
stdout.put( "(", value, "): " );
else
stdout.puts( ": " );
endif;
stdin.flushInput();
stdin.a_gets();
mov( eax, edi );
// ensure first letter is Upper Case ...
mov( mov( chars.toUpper( [edi] ), al), (type char [edi]) );
stdout.put("You input '", (type string edi), "' Ok (y/n) ? " );
stdin.getc();
chars.toLower( al );
if( al == 'y' ) then
mov( edi, eax );
break;
else
str.free( edi );
endif;
endfor;
pop( edi );
end takeIn;
procedure fileBook( var sll: SLList );
var
fout: dword;
begin fileBook;
push( eax ); push( ebx );
try
fileio.openNew( FNAME ); // overwrites any existing file
mov( eax, fout );
mov( sll, eax );
mov( (type SLList [eax]).head, eax );
while( eax ) do
mov( [eax], ebx );
fileio.put( fout, (type MyContact [ebx]).theName, nl );
fileio.put( fout, (type MyContact [ebx]).thePhone, nl );
mov( (type NNode[eax]).next, eax );
endwhile;
fileio.close( fout );
exception( ex.FileOpenFailure )
stdout.put( "There was a problem opening file ", FNAME,
" for output." nl );
endtry;
pop( ebx ); pop( eax );
end fileBook;
// Total number of contacts is stored in global variable RecCount
procedure addContacts( var sll: SLList );
var
newNNode: NNode;
oldSize: uns32;
begin addContacts;
push( eax ); push( ebx ); push( ecx );
mov( sll, ebx );
mov( (type SLList [ebx]).size, eax );
mov( eax, oldSize );
mov( (type SLList [ebx]).head, eax );
stdout.puts( "To abort/exit, just enter/accept an empty line "
"for 'name' or 'phone' ... " nl );
forever
mem.alloc( @size( MyContact ) );
mov( eax, ecx );
mov( takeIn( "Enter name ", "" ), (type MyContact [ecx]).theName );
mov( takeIn( "Enter phone ", "" ), (type MyContact [ecx]).thePhone );
if( str.length( (type MyContact [ecx]).theName ) &&
str.length( (type MyContact [ecx]).thePhone ) ) then
mov( ecx, newNNode.nval );
push_backSLList( (type SLList [ebx]), newNNode );
else
str.free( (type MyContact [ecx]).thePhone );
str.free( (type MyContact [ecx]).theName );
stdout.puts( "Ok ... aborted ... " );
endif;
stdout.puts( nl "More y/n ? " );
stdin.flushInput();
stdin.getc();
chars.toLower( al );
breakif( al == 'n' );
endfor;
mov( (type SLList [ebx]).size, ecx );
if( ecx > oldSize ) then // Contacts were added ...
mov( &myCmp, pMyCmp ); // so can msort... ok, when called ...
msortSLList( (type SLList [ebx]) ); // also updates Update
mov( true, Sorted );
mov( true, Update );
endif;
pop( ecx ); pop( ebx); pop( eax );
end addContacts;
// returns count of records in file in SLList size parameter
procedure inputBook_fromFile( var sll: SLList );
var
fin: dword;
newNNode: NNode;
begin inputBook_fromFile;
push( eax ); push( ebx ); push( ecx );
try
fileio.open( FNAME, fileio.r ); // open file for reading
mov( eax, fin );
mov( sll, ebx );
while( !fileio.eof( fin) ) do
mem.alloc( @size( MyContact ) );
mov( eax, ecx );
// allocate space for new string and
// mov pointer into array (of pointers)
fileio.a_gets( fin ); // returns new string in eax
mov( eax, (type MyContact [ecx]).theName ); // get Contact
fileio.a_gets( fin);
mov( eax, (type MyContact [ecx]).thePhone );
mov( ecx, newNNode.nval );
push_backSLList( (type SLList [ebx]), newNNode );
endwhile;
fileio.close( fin );
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();
chars.toLower( al );
if( al == 'y' ) then
mov( sll, ebx );
addContacts( (type SLList [ebx]) );
endif;
endtry;
pop( ecx ); pop( ebx ); pop( eax );
end inputBook_fromFile;
procedure editContact( var sll: SLList; pn: dword in eax );
var
s: string;
begin editContact;
push( ebx ); push( ecx ); push( edx );
mov( sll, ebx );
if( (type SLList [ebx]).size > 0 ) then // need at least 1 record to edit
// free old allocated strings and overwite with new ... (if updated )
mov( [eax], ecx ); // derefence pointer
mov( (type MyContact [ecx]).theName, edx );
mov( edx, s ); // get copy of pointer into s ...
stdout.puts( "To abort/exit, just enter/accept an empty "
"line for a name ... " nl );
mov( takeIn( "Enter name ", s ), (type MyContact [ecx]).theName );
if( str.length( (type MyContact [ecx]).theName ) ) then // if NOT empty ...
str.free( s );
mov( (type MyContact [ecx]).thePhone, edx );
mov( edx, s ); // get copy into s ...
mov( takeIn( "Enter phone ", s ), (type MyContact [ecx]).thePhone );
str.free( s );
mov( &myCmp, pMyCmp ); // so can msort ok, when called ...
msortSLList( (type SLList [ebx]) ); // also updates Update ...
mov( true, Sorted );
mov( true, Update );
else
str.free( (type MyContact [ecx]).theName ); // free rejected entry ...
mov( mov( s, edx ), (type MyContact [ecx]).theName ); // restore original
stdout.puts( "Ok ... edit aborted ... " nl );
endif;
endif;
pop( edx ); pop( ecx ); pop( ebx );
end editContact;
procedure showBook( var sll: SLList );
var
lineCount: int32;
begin showBook;
push( eax ); push( ebx ); push( ecx ); push( edx );
// a little different formatting ...
console.cls();
stdout.puts
(
nl "Your 'book' : __________________________________________________" nl
);
mov( 2, lineCount );
mov( sll, ebx );
mov( (type SLList [ebx]).head, eax );
mov( 0, ecx );
while( eax ) do
inc( lineCount );
stdout.puts( nl stdio.tab stdio.tab );
inc( ecx ); // to show 1,2,3 ... and not 0,1,2 ...
stdout.putu32Size( ecx, 3, '0' );
mov( [eax], edx );
stdout.put( ": ", (type MyContact [edx]).theName : -24 );
stdout.puts( " ---> " );
stdout.put( (type MyContact [edx]).thePhone : 15 );
mov( (type NNode [eax]).next, eax );
endwhile;
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end showBook;
procedure showMenu( var sll: SLList );
var
s: string;
oldSize: uns32;
myC: MyContact;
myNNode: NNode;
begin showMenu;
push( eax ); push( ebx );
mov( sll, ebx );
showBook( (type SLList [ebx]) );
stdout.put
(
nl nl "Total contacts now in memory = ", (type SLList [ebx]).size,
nl nl "Add, Delete, Edit, Sort, XDuplicates or Quit (a, d, e, s, x, q) ? "
);
stdin.flushInput();
stdin.getc();
chars.toLower( al );
if( al == 'a' ) then
addContacts( (type SLList [ebx]) );
elseif( al == 'd' ) then
stdout.puts( "To abort/exit, just enter/accept an empty "
"line for a name ... " nl );
mov( takeIn( "Enter name to find", "" ),
myC.theName ); // returns in eax then copies pointer to myC.string
if( str.length( myC.theName ) ) then
mov( &myCmpEQ, pMyCmp ); // so can use findVec (EQ)
findSLList( (type SLList [ebx]), myC ); // returns pointer or 0
if( eax ) then
stdout.put( "Found ... so erasing ... " nl );
mov( &destroyMyC, pFreeNNode );
eraseSLList( (type SLList [ebx]), eax ); // a library proc
else
stdout.put( myC.theName, " was NOT found ... " nl );
str.free( myC.theName );
endif;
else
str.free( myC.theName );
stdout.puts( "Ok ... aborting delete ... " nl );
endif;
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
elseif( al == 'e' ) then
mem.alloc( @size( MyContact ) );
mov( eax, ecx );
stdout.puts( "To abort/exit, just enter/accept an empty "
"line for a name ... " nl );
mov( takeIn( "Enter name to find", "" ), // returns in eax then copies pointer ...
(type MyContact [ecx]).theName );
if( str.length( (type MyContact [ecx]).theName ) ) then
mov( &myCmpEQ, pMyCmp ); // so can use findSLList (EQ)
mov( ecx, myNNode.nval );
findSLList( (type SLList [ebx]), myNNode ); // returns pointer or 0
if( eax ) then
stdout.put( "Found ... ", nl );
editContact( (type SLList [ebx]), eax );
else
stdout.put( myC.theName, " was NOT found ... " nl );
str.free( myC.theName );
endif;
else
str.free( myC.theName );
stdout.puts( "Ok ... aborting edit ... " nl );
endif;
mem.free( ecx );
stdout.put( nl "Press 'Enter' to continue ... " );
stdin.readLn();
elseif( al == 's' ) then
mov( &myCmp, pMyCmp ); // so can msort... ok, when called
msortSLList( (type SLList [ebx]) );
mov( true, Sorted );
mov( true, Update );
elseif( al == 'x' ) then
if( !Sorted ) then
mov( &myCmp, pMyCmp ); // so can msort... ok, when called
msortSLList( (type SLList [ebx]) );
mov( true, Sorted );
mov( true, Update );
endif;
mov( &myCmpEQ, pMyCmp ); // so can cmp (EQ)... ok, when called
mov( &destroyMyC, pFreeNNode );
mov( sll, ebx );
mov( (type SLList [ebx]).size, oldSize );
uniqueSLList( (type SLList [ebx]) ); // pre-sort array to 'chop' duplicates
mov( (type SLList [ebx]).size, eax );
if( eax < oldSize ) then
mov( true, Update ); // and ... will update 'contacts.dat' file
endif;
elseif( al == 'q' ) then
mov( true, Done ); // 'Done' is also a global variable
endif;
pop( ebx ); pop( eax );
end showMenu;
begin ContactsSLList2;
initSLList( myBook );
mov( &destroyMyC, pFreeNNode );
inputBook_fromFile( myBook ); // returns the record count in size parameter
repeat
showMenu( myBook );
until( Done );
if( Update ) then
fileBook( myBook );
stdout.put( nl "Ok ... your BOOK should NOW be filed in file '",
FNAME, "' ... " nl );
endif; // update file if changes ...
stdout.put( nl "Before clear... myBook.size = ", myBook.size, nl );
clearSLList( myBook );
stdout.put( "After clear... myBook.size = ", myBook.size, nl );
stdout.put( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end ContactsSLList2;
You will find the 3 files you need to have available to include ...
"readLine.hhf"
"sllist2_func's.hhf"
"sllist2.hhf"
at this next link:
http://developers-heaven.net/forum/index.php?topic=2600.0
Oops ... just remember this little demo of using vector2.hhf ... that demo's using two different kinds of programmer defined records in the same program ... using my HLA user defined type Vec (2) container ...
First the two little test data files that I used:
// "testInt.dat"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// "testStr.dat"
z 3456789 123456789 123456789
2z
32z
444z
5555z
66666z
777z
88z
9z
z
And here is the demo/test file ...
program testVec2StrInt; // 2012-09-03 //
#includeOnce( "readWord.hhf" )
const
Fname: text := """testStr.dat""" ;
Fname2: text := """testInt.dat""" ;
InitCap: uns32 := 2; // Note: if NOT defined here defaults to 8
// kept small for testing of Vec memory reallocates
#includeOnce( "vector2_func's.hhf" ); // Note: has #includeOnce("vector2.hhf");
// and "vector2.hhf" has ? @nodisplay:= true;
// so all procedures have @nodisplay 'as default'
// Ok ... now we need to define our records ...
// and free rec procedures (to handle potential case of dynamic memory)
type
Rec: record
str: string;
endrecord;
procedure freeRec( pr: dword in eax ); @noframe;
begin freeRec;
str.free( (type Rec [eax]).str );
ret();
end freeRec;
type
Rec2: record
i32: int32;
endrecord;
procedure freeRec2( pr: dword in eax ); @noframe;
begin freeRec2;
// no dynamic memory to free here ...
ret();
end freeRec2;
// Now ... we can define our compare functions to be used by find and sort ...
// re. isort...
procedure myCmp( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmp;
if( str.lt( (type Rec [esi]).str, (type Rec [edi]).str ) ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmp;
// re. msort...
procedure myCmpLE( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpLE;
if( str.le( (type Rec [esi]).str, (type Rec [edi]).str ) ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpLE;
// re. isort...
procedure myCmpRev( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpRev;
if( str.gt( (type Rec [esi]).str, (type Rec [edi]).str ) ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpRev;
// re. find...
procedure myCmpEQ( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpEQ;
if( str.eq( (type Rec [esi]).str, (type Rec [edi]).str ) ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpEQ;
// re. comparing int32 ... for msort reverse order... recall >= is used
procedure myCmpIntRev( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpIntRev;
mov( (type Rec2 [esi]).i32, esi );
mov( (type Rec2 [edi]).i32, eax );
if( (type int32 esi) >= eax ) then mov( 1, eax ); // i.e. descending sort
else mov( 0, eax );
endif;
end myCmpIntRev;
// re. find int32...
procedure myCmpEQRec2( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpEQRec2;
mov( (type Rec2 [esi]).i32, esi );
mov( (type Rec2 [edi]).i32, eax );
if( (type int32 esi) == eax ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpEQRec2;
// so can reuse showVec with different showRec's ...
static
pShowRec: procedure( pr: dword in eax ); // get a proc pointer
// Now .. define show record ... for each different record ...
procedure showRec( pr: dword in eax ); @noframe;
begin showRec;
stdout.puts( (type Rec [eax]).str );
ret();
end showRec;
procedure showRec2( pr: dword in eax ); @noframe;
begin showRec2;
stdout.puti32( [eax] );
ret();
end showRec2;
// using above procedure pointer pShowRec ... can define showVec
procedure showVec( var v: Vec );
begin showVec;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec[ebx]).size; inc( ecx ) ) do
mov( ecx, eax );
intmul( (type Vec [ebx]).elen, eax );
add( (type Vec[ebx]).ary, eax );
pShowRec( eax );
stdout.putc( ' ' );
endfor;
pop( ecx ); pop( ebx ); pop( eax );
end showVec;
static
fin: dword; // file handle
myRec: Rec; // get some objects with memory ...
myRec2: Rec2;
myVec: Vec;
myVec2: Vec;
tmpStr: string;
begin testVec2StrInt;
// get some strings from file into a Vec using push_backVec...
fileio.open( Fname, fileio.r );
mov( eax, fin );
initVec( myVec, @size(Rec) ); // Note: must initial for Vec to work
while( readWord( fin, myRec.str, " " nl stdio.tab ) ) do
push_backVec( myVec, &myRec ); // Note here, passing Vec by ref and Rec by pointer
endwhile;
fileio.close( fin );
stdout.puts( "Showing vec of str ... " nl );
mov( &showRec, pShowRec );
showVec( myVec );
stdout.put( "size = ", myVec.size, ", capacity = ", myVec.capacity, nl );
mov( &myCmp, pMyCmp );
isortVec( myVec );
stdout.puts( nl "Showing insert sorted vec of str ... " nl );
showVec( myVec );
stdout.put( "size = ", myVec.size, ", capacity = ", myVec.capacity, nl )
mov( &myCmpRev, pMyCmp );
isortVec( myVec );
stdout.puts( nl "Showing insert sorted REVERSE vec of str ... " nl );
showVec( myVec );
stdout.put( "size = ", myVec.size, ", capacity = ", myVec.capacity, nl );
mov( &myCmpLE, pMyCmp );
msortVec( myVec );
stdout.puts( nl "Showing merge sorted vec of str ... " nl );
showVec( myVec );
stdout.put( "size = ", myVec.size, ", capacity = ", myVec.capacity, nl nl );
str.a_cpy( "777z" );
mov( eax, myRec.str );
mov( &myCmpEQ, pMyCmp );
findVec( myVec, &myRec );
mov( &freeRec, pFreeRec );
if( (type int32 eax) != -1 ) then
stdout.put( "'", myRec.str, "' WAS FOUND at index ", (type int32 eax), nl );
stdout.puts( "So after erasing ... vec is ... " nl );
eraseVec( myVec, eax );
showVec( myVec );
else
stdout.put( "'", myRec.str, "' was NOT found in the vector ... ", nl );
endif;
// ok ... clean up all dynamic memory when 'done'
str.free( myRec.str );
//mov( &freeRec, pFreeRec ); // done above before erase ...
clearVec( myVec );
stdout.puts( nl "Press 'Enter' to continue to Vec of integers from file ... " );
stdin.readLn();
// get some int's from an int file into a different Vec (using push_backVec...)
fileio.open( Fname2, fileio.r );
mov( eax, fin );
initVec( myVec2, @size(Rec2) );
while( readWord( fin, tmpStr, " " nl stdio.tab ) ) do
conv.strToi32( tmpStr, 0 ); // begin at index 0 ...
mov( eax, myRec2.i32 );
push_backVec( myVec2, &myRec2 );
endwhile;
fileio.close( fin );
stdout.puts( "Showing vec of int32 ... " nl );
mov( &showRec2, pShowRec );
showVec( myVec2 );
stdout.put( "size = ", myVec2.size, ", capacity = ", myVec2.capacity, nl );
mov( &myCmpIntRev, pMyCmp );
msortVec( myVec2 );
stdout.puts( nl "Showing merge sorted (reverse) vec of int32 ... " nl );
showVec( myVec2 );
stdout.put( "size = ", myVec2.size, ", capacity = ", myVec2.capacity, nl );
mov( 11, myRec2.i32 );
mov( &myCmpEQRec2, pMyCmp );
findVec( myVec2, &myRec2 );
mov( &freeRec2, pFreeRec );
if( (type int32 eax) != -1 ) then
stdout.put( nl "'", myRec2.i32, "' WAS FOUND at index ", (type int32 eax), nl );
stdout.puts( nl "So after erasing ... vec is ... " nl );
eraseVec( myVec2, eax );
showVec( myVec2 );
else
stdout.put( "'", myRec2.i32, "' was NOT found in the vector ... ", nl );
endif;
stdout.put( "size = ", myVec2.size, ", capacity = ", myVec2.capacity, nl nl );
// mov( &freeRec2, pFreeRec ); // done above before erase ...
clearVec( myVec2 );
stdout.put( "After clear... size = ", myVec2.size, ", capacity = ",
myVec2.capacity, nl nl );
stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end testVec2StrInt;
You will find the 3 files you need to have available to include ...
"readWord.hhf"
"vector2_func's.hhf"
"vector2.hhf"
at this next link:
http://developers-heaven.net/forum/index.php?topic=2600.0
Now ... like the above, but using a SLList ...
program testSLList2StrInt; // 2012-09-03 //
#includeOnce( "readWord.hhf" ) // Note: has ? @nodisplay:= true; ... so all
// procedures have @nodisplay 'as default'
#includeOnce( "sllist2_func's.hhf" ); // Note: has #includeOnce("sllist2.hhf");
const
Fname: text := """testStr.dat""" ;
Fname2: text := """testInt.dat""" ;
// Ok ... now we need to define our records ...
// and free NNode procedures (to handle potential case of dynamic memory)
procedure freeStrNNode( pr: dword in eax ); @noframe;
begin freeStrNNode;
str.free( (type NNode [eax]).nval );
ret();
end freeStrNNode;
procedure freeIntNNode( pr: dword in eax ); @noframe;
begin freeIntNNode;
// no dynamic memory to free here ...
ret();
end freeIntNNode;
// Now ... we can define our compare functions to be used by find and sort ...
// re. msort/isort...
procedure myCmpLE( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpLE;
if( str.le( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpLE;
// re. msort/isort...
procedure myCmpRev( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpRev;
if( str.ge( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpRev;
// re. find...
procedure myCmpEQ( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpEQ;
if( str.eq( (type NNode [esi]).nval, (type NNode [edi]).nval ) ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpEQ;
// re. comparing int32 ... for isort/msort reverse order... recall >= used
procedure myCmpIntRev( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpIntRev;
mov( (type NNode [esi]).nval, eax );
if( (type int32 eax) >= (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpIntRev;
// for isort/msort ascending ...
procedure myCmpInt( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpInt;
mov( (type NNode [esi]).nval, eax );
if( (type int32 eax) <= (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
// re. find int32...
procedure myCmpEQInt( a: dword in esi; b: dword in edi ); @returns("eax");
begin myCmpEQInt;
mov( (type NNode [esi]).nval, eax );
if( eax == (type NNode [edi]).nval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpEQInt;
// so can reuse showSLList with different showRec's ...
static
pShowNNode: procedure( pr: dword in eax ); // get a proc pointer
// Now .. define show record ... for each different record ...
procedure showNNodeStr( pr: dword in eax ); @noframe;
begin showNNodeStr;
stdout.puts( (type NNode [eax]).nval );
ret();
end showNNodeStr;
procedure showNNodeInt( pr: dword in eax ); @noframe;
begin showNNodeInt;
stdout.puti32( (type NNode [eax]).nval );
ret();
end showNNodeInt;
// using above procedure pointer pShowNNode ... can define showSLList
procedure showSLList( var v: SLList );
begin showSLList;
push( eax );
mov( v, eax );
mov( (type SLList[eax]).head, eax );
while( eax ) do
pShowNNode( eax );
mov( (type NNode[eax]).next, eax );
stdout.putc( ' ' );
endwhile;
pop( eax );
end showSLList;
static
fin: dword; // file handle
myNNode: NNode;
mySLList: SLList;
mySLList2: SLList;
tmpStr: string;
begin testSLList2StrInt;
// get some strings from file into a SLList using push_backSLList...
fileio.open( Fname, fileio.r );
mov( eax, fin );
initSLList( mySLList ); // Note: must initial for SLList to work
while( readWord( fin, myNNode.nval, " " nl stdio.tab ) ) do
push_backSLList( mySLList, myNNode ); // Note here, passing SLList and myNNode by ref
endwhile;
fileio.close( fin );
stdout.puts( "Showing SLList of string ... " nl );
mov( &showNNodeStr, pShowNNode );
showSLList( mySLList );
stdout.put( "size = ", mySLList.size, nl );
mov( &myCmpLE, pMyCmp );
isortSLList( mySLList );
stdout.puts( nl "Showing insert sorted SLList of str ... " nl );
showSLList( mySLList );
stdout.put( "size = ", mySLList.size, nl )
mov( &myCmpRev, pMyCmp );
isortSLList( mySLList );
stdout.puts( nl "Showing insert sorted REVERSE SLList of str ... " nl );
showSLList( mySLList );
stdout.put( "size = ", mySLList.size, nl );
mov( &myCmpLE, pMyCmp );
msortSLList( mySLList );
stdout.puts( nl "Showing merge sorted SLList of str ... " nl );
showSLList( mySLList );
stdout.put( "size = ", mySLList.size, nl nl );
str.a_cpy( "777z" );
mov( eax, myNNode.nval );
mov( &myCmpEQ, pMyCmp );
findSLList( mySLList, myNNode );
mov( &freeStrNNode, pFreeNNode );
if( eax ) then
stdout.puts( "Found ... So erasing ... and SLList now is ... " nl );
eraseSLList( mySLList, eax );
showSLList( mySLList );
else
stdout.put( "'", (type string myNNode.nval), "' was NOT found in the SLList ... ", nl );
endif;
// ok ... clean up all dynamic memory when 'done'
str.free( myNNode.nval );
//mov( &freeStrNNode, pFreeNNode ); // done above ...(before erase)
clearSLList( mySLList );
stdout.puts( nl "Press 'Enter' to continue to SLList of integers from file ... " );
stdin.readLn();
// get some int's from an int file into a different SLList (using push_backSLList...)
fileio.open( Fname2, fileio.r );
mov( eax, fin );
initSLList( mySLList2 );
while( readWord( fin, tmpStr, " " nl stdio.tab ) ) do
conv.strToi32( tmpStr, 0 ); // begin at index 0 ...
mov( eax, myNNode.nval );
push_backSLList( mySLList2, myNNode );
str.free( tmpStr );
endwhile;
fileio.close( fin );
stdout.puts( "Showing SLList of int32 ... " nl );
mov( &showNNodeInt, pShowNNode );
showSLList( mySLList2 );
stdout.put( "size = ", mySLList2.size, nl );
mov( &myCmpIntRev, pMyCmp );
msortSLList( mySLList2 );
stdout.puts( nl "Showing merge sorted (reverse) SLList of int32 ... " nl );
showSLList( mySLList2 );
stdout.put( "size = ", mySLList2.size, nl );
mov( 11, myNNode.nval );
mov( &myCmpEQInt, pMyCmp );
findSLList( mySLList2, myNNode );
mov( &freeIntNNode, pFreeNNode );
if( eax ) then
stdout.put( nl "Found ", (type int32 myNNode.nval),
" so after erasing SLList is ... " nl );
eraseSLList( mySLList2, eax );
showSLList( mySLList2 );
else
stdout.put( "'", (type int32 myNNode.nval), "' was NOT found in the SLList ... ", nl );
endif;
stdout.puts( nl "Showing insert sorted SLList of int32 ... " nl );
mov( &myCmpInt, pMyCmp );
isortSLList( mySLList2 );
showSLList( mySLList2 );
stdout.put( "size = ", mySLList2.size, nl );;
// mov( &freeIntNNode, pFreeNNode ); // done above before erase ...
clearSLList( mySLList2 );
stdout.put( "After clear... size = ", mySLList2.size, nl nl );
stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.readLn();
end testSLList2StrInt;
Now here is a timed very SLOW read from file ... HLA example ... from a LARGE file of 3,000,000 random integers ...
(See example of the C code version at the bottom of the msortVecInt.hla program file).
Note: USING "vector.hhf" and "vector_func's.hhf' here ... You will first need to create a file of 3,000,000 random integers ... AND MAKE SURE there is NO WHITE SPACE/New line char's at the end of the file after the ending 3,000,000th integer ... (OR the program will CRASH - but not with C coded Cvec version ... and file read in C version was 50 to 90 times faster.)
/* msortVecInt.hla */ /* this version 2012-08-22 */
/*
NOTE!
FILE READ ERROR if NL char at end of file of integers ...
SO ... first MUST ensure all non-numeric char's, are trimmed from
the end of the file of integers ... can use a text editor !
*/
/*
http://developers-heaven.net/forum/index.php/topic,46.0.html
*/
program msortVecIntLarge;
const
InitCap: uns32 := 3000000; // to hold 3 Million random int's
HEADER: string := "HLA program to sort 3 Million random int's from file"
#13 #10 "stored in an HLA user defined type Vec...";
//#includeOnce( "readWord.hhf" )
type
Rec: record
rval: int32;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @noframe;
begin freeRec;
// NO dynamic memory here to free ...
ret();
end freeRec;
// ok ... after above two types defined ... now can ...
#includeOnce( "vector_func's.hhf" )
procedure myCmpInt( a: pRec in esi; b: pRec in edi ); @returns( "eax" );
begin myCmpInt;
mov( (type Rec [esi]).rval, eax );
if( eax <= (type Rec [edi]).rval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure isSorted( var v: Vec ); @returns( "eax" );
begin isSorted;
mov( v, ebx );
mov( (type Vec [ebx]).size, ecx );
dec( ecx );
intmul( @size( Rec ), ecx, eax );
add( (type Vec [ebx]).ary, eax );
mov( (type Rec [eax]).rval, edi );
while( (type int32 ecx) > 0 ) do
dec( ecx );
sub( @size( Rec ), eax );
mov( (type Rec [eax]).rval, esi );
if( (type int32 esi) > edi ) then
mov( 0, eax );
break;
endif;
mov( esi, edi );
endwhile;
mov( 1, eax );
end isSorted;
static
myVec: Vec;
myRec: Rec;
fin: dword;
tmpStr: string;
clock: timer_t;
begin msortVecIntLarge;
stdout.put( HEADER, nl nl );
initVec( myVec );
clock.create();
clock.start();
fileio.open( "randInt3M.txt", fileio.r );
mov( eax, fin );
while( !fileio.eof( fin ) ) do
fileio.geti32( fin );
mov( eax, myRec.rval );
// push( ebx ); push( ecx ); push( esi ); push( edi ); // if needed //
push_backVec( myVec, myRec );
endwhile;
clock.stop();
stdout.put( nl "To fill Vec from file ... ms = ", (type uns64 clock.Accumulated), nl );
clock.start();
mov( &myCmpInt, pMyCmp );
msortVec( myVec );
clock.stop();
stdout.put( nl "To msort ... ms = ", (type uns64 clock.Accumulated), nl );
isSorted( myVec );
stdout.put( "isSorted( myVec ) = ", (type boolean al) );
stdout.puts( nl nl "Press 'Enter' to exit/continue ... " );
stdin.readLn();
end msortVecIntLarge;
#if( false )
int main( void ) /* ***************************************************** */
{
FILE* fp;
double ti, tp;
int i, valToFind;
Rec r;
Cvec cv;
initCvec( &cv ); /* Note: MUST initial Cvec v ... for Cvec to work */
puts( HEADER );
ti = clock();
fp = fopen( "randInt3M.txt", "r" );
while( 1 == fscanf( fp, "%d", &r.val ) )
{
push_backCvec( &cv, &r ); /* since good Rec was obtained */
/*if( cv.size == 32768*3 ) break; // 32768*11 */
}
tp = clock() - ti;
printf( "%d int's were read from file in %.2f sec's ... ",
cv.size, tp/CLOCKS_PER_SEC );
ti = clock();
msort( &cv );
tp = clock() - ti;
printf( "merge sorted in %.2f sec's", tp/CLOCKS_PER_SEC );
printf( "\nand isSorted( &v ) = %d\n", isSorted( &cv ) );
ti = clock();
uniqueCvec( &cv );
tp = clock() - ti;
printf( "\nuniqueCvec in %.2f sec's", tp/CLOCKS_PER_SEC );
printf( " ... and isSorted( &cv ) = %d ", isSorted( &cv ) );
printf( "\n... and isUniqueCvec( &cv ) = %d\n",
isUniqueCvec( &cv ) & cv.isSorted );
printf( "\nAfter uniqueCvec: cv.size = %d, cv.cap = %d\n\n", cv.size, cv.cap );
valToFind = cv.ary[cv.size-1].val;
ti = clock();
i = findCvec( &cv, valToFind );
if( i != -1 )
{
eraseCvec( &cv, i );
tp = clock() - ti;
printf( "%d was erased ...", valToFind);
printf( "%d is new end val...\n", cv.ary[cv.size-1].val);
printf( "find/ereaseCvec in %.2f sec's\n\n", tp/CLOCKS_PER_SEC );
}
else printf( "%d was NOT-found/NOT-erased ...\n\n", valToFind );
myShowAll( &cv );
printf( "Before clearCvec: cv.size = %d, cv.cap = %d\n", cv.size, cv.cap );
clearCvec( &cv );
printf( "After clearCvec: cv.size = %d, cv.cap = %d\n", cv.size, cv.cap );
fclose( fp );
fputs( "\nPress 'Enter' to continue ... ", stdout );
getchar();
return 0;
} /* ******************************************************************** */
#endif
You will find the 2 files you need to have available to include ...
"vector_func's.hhf"
"vector.hhf"
at this next link:
http://developers-heaven.net/forum/index.php?topic=2600.0
Here is a speeded up version that reads a line at a time ... (also handles spaces at end of lines)
/* msortVecInt2.hla */ /* this version 2012-08-22 */
/*
http://developers-heaven.net/forum/index.php/topic,46.0.html
*/
program msortVecIntLarge;
const
InitCap: uns32 := 3_000_000; // to hold 3 Million random int's
HEADER: string := "HLA program to sort 3 Million random int's from file"
#13 #10 "stored in an HLA user defined type Vec...";
type
Rec: record
rval: int32;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @noframe;
begin freeRec;
// NO dynamic memory here to free ...
ret();
end freeRec;
// ok ... after above two types defined ... now can ...
#includeOnce( "vector_func's.hhf" )
procedure myCmpInt( a: pRec in esi; b: pRec in edi ); @returns( "eax" );
begin myCmpInt;
mov( (type Rec [esi]).rval, eax );
if( eax <= (type Rec [edi]).rval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure isSorted( var v: Vec ); @returns( "eax" );
begin isSorted;
mov( v, ebx );
mov( (type Vec [ebx]).size, ecx );
dec( ecx );
intmul( @size( Rec ), ecx, eax );
add( (type Vec [ebx]).ary, eax );
mov( (type Rec [eax]).rval, edi );
while( (type int32 ecx) > 0 ) do
dec( ecx );
sub( @size( Rec ), eax );
mov( (type Rec [eax]).rval, esi );
if( (type int32 esi) > edi ) then
mov( 0, eax );
break;
endif;
mov( esi, edi );
endwhile;
mov( 1, eax );
end isSorted;
static
myVec: Vec;
myRec: Rec;
fin: dword;
tmpStr: string;
clock: timer_t;
line: str.strvar( 256 ); // lines here are less than 100 char's
begin msortVecIntLarge;
stdout.put( HEADER, nl nl );
initVec( myVec );
clock.create();
clock.start();
fileio.open( "randInt3M.txt", fileio.r );
mov( eax, fin );
while( !fileio.eof( fin ) ) do
fileio.gets( fin, line ); // max size fixed above to 256 char's
mov( line, esi );
mov( (type str.strRec [esi]).length, edx );
if( edx ) then // i.e. if line NOT empty ... trim any spaces from end
dec( edx );
while( (type char [esi+edx]) == ' ' ) do dec( edx ); endwhile;
inc( edx );
mov( 0, (type char [esi+edx]) ); // ensure 0 terminated
//mov( edx, (type str.strRec [esi]).length ); // update with new length
while( (type char [esi]) != 0 ) do
conv.atoi32( [esi] );
mov( eax, myRec.rval );
// push( ebx ); push( ecx ); push( esi ); push( edi ); // if needed //
push( esi );
push_backVec( myVec, myRec );
pop( esi );
endwhile;
endif;
endwhile;
clock.stop();
stdout.put( nl "To fill Vec from file ... ms = ", (type uns64 clock.Accumulated), nl );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
clock.start();
mov( &myCmpInt, pMyCmp );
msortVec( myVec );
clock.stop();
stdout.put( nl "To msort ... ms = ", (type uns64 clock.Accumulated), nl );
isSorted( myVec );
stdout.put( "isSorted( myVec ) = ", (type boolean al), nl );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
clearVec( myVec );
stdout.puts( nl "Press 'Enter' to exit/continue ... " );
stdin.readLn();
end msortVecIntLarge;
Now ... a super fast load from file, reading the whole file into one large dynamic buffer in ONE big gulp ... (also handles NON numeric/whitespace at end of file, if any to handle) ...
/* msortVecInt3.hla */ /* this version 2012-08-22 */
/*
http://developers-heaven.net/forum/index.php/topic,46.0.html
*/
program msortVecIntLarge;
const
InitCap: uns32 := 3_000_000; // to hold 3 Million random int's
FNAME: string := "randInt3M.txt";
HEADER: string := "HLA program to sort 3 Million random int's from file"
#13 #10 "stored in an HLA user defined type Vec...";
type
Rec: record
rval: int32;
endrecord;
pRec: pointer to Rec;
procedure freeRec( pr: pRec in eax ); @noframe;
begin freeRec;
// NO dynamic memory here to free ...
ret();
end freeRec;
// ok ... after above two types defined ... now can ...
#includeOnce( "vector_func's.hhf" )
procedure myCmpInt( a: pRec in esi; b: pRec in edi ); @returns( "eax" );
begin myCmpInt;
mov( (type Rec [esi]).rval, eax );
if( eax <= (type Rec [edi]).rval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure isSorted( var v: Vec ); @returns( "eax" );
begin isSorted;
mov( v, ebx );
mov( (type Vec [ebx]).size, ecx );
dec( ecx );
intmul( @size( Rec ), ecx, eax );
add( (type Vec [ebx]).ary, eax );
mov( (type Rec [eax]).rval, edi );
while( (type int32 ecx) > 0 ) do
dec( ecx );
sub( @size( Rec ), eax );
mov( (type Rec [eax]).rval, esi );
if( (type int32 esi) > edi ) then
mov( 0, eax );
break;
endif;
mov( esi, edi );
endwhile;
mov( 1, eax );
end isSorted;
static
myVec: Vec;
myRec: Rec;
fin: dword;
tmpStr: string;
clock: timer_t;
buf: pointer to char;
begin msortVecIntLarge;
stdout.put( HEADER, nl nl );
initVec( myVec );
clock.create();
clock.start();
fileio.open( FNAME, fileio.r );
mov( eax, fin );
filesys.size( fin );
mov( eax, ecx );
inc( eax ); // leave room for terminal 0
mem.alloc( eax );
mov( eax, buf );
fileio.read( fin, [eax], ecx );
if( eax != -1 ) then
if( ecx ) then
dec( ecx );
mov( buf, esi );
while( (type int32 ecx) >= 0 && (type char [esi+ecx]) < '0' ||
(type char [esi+ecx]) > '9' ) do dec( ecx );
endwhile;
inc( ecx );
mov( 0, (type char [esi+ecx]) ); // ensure 0 terminated
while( (type char [esi]) != 0 ) do
conv.atoi32( [esi] );
mov( eax, myRec.rval );
// push( ebx ); push( ecx ); push( esi ); push( edi ); // if needed //
push( esi );
push_backVec( myVec, myRec );
pop( esi );
endwhile;
endif;
else
stdout.put( "There was a problem reading file ", FNAME, nl );
endif;
mem.free( buf );
clock.stop();
stdout.put( nl "To fill Vec from file ... ms = ", (type uns64 clock.Accumulated), nl );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
clock.start();
mov( &myCmpInt, pMyCmp );
msortVec( myVec );
clock.stop();
stdout.put( nl "To msort ... ms = ", (type uns64 clock.Accumulated), nl );
isSorted( myVec );
stdout.put( "isSorted( myVec ) = ", (type boolean al), nl );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
clearVec( myVec );
stdout.puts( nl "Press 'Enter' to exit/continue ... " );
stdin.readLn();
end msortVecIntLarge;
Now, using the same file of 3,000,000 random integers as above, try this super fast file read ... (and sort) ... and you don't need to be concerned if there is, or is not, a new-line/white-space sequence at file end :)
Note: using "vector2.hhf", "vector2_func's.hhf" here ...
program fileSizeReadDemo_atoi32; // 2012-08-16 //
const
InitCap: uns32 := 3_000_000;
#includeOnce( "vector2_func's.hhf" )
type
Rec: record
rval: int32;
endrecord;
pRec: pointer to Rec;
procedure myFreeRec( pr: pRec in eax ); @noframe;
begin myFreeRec;
// no dynamic memory to free ...
ret();
end myFreeRec;
// re. msort...
procedure myCmpInt( a: pRec in esi; b: pRec in edi ); @returns( "eax" );
begin myCmpInt;
mov( (type Rec [esi]).rval, eax );
if( eax <= (type Rec [edi]).rval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure isSorted( var v: Vec ); @returns( "eax" );
begin isSorted;
mov( v, ebx );
mov( (type Vec [ebx]).size, ecx );
if( ecx > 2 ) then
dec( ecx );
intmul( @size( Rec ), ecx, eax );
add( (type Vec [ebx]).ary, eax );
mov( (type Rec [eax]).rval, edi );
while( (type int32 ecx) > 0 ) do
dec( ecx );
sub( @size( Rec ), eax );
mov( (type Rec [eax]).rval, esi );
if( (type int32 esi) > edi ) then
mov( 0, eax );
break;
endif;
mov( esi, edi );
endwhile;
endif;
mov( 1, eax );
end isSorted;
static
fin: dword;
line: string;
myVec: Vec;
myRec: Rec;
clock: timer_t;
begin fileSizeReadDemo_atoi32;
clock.create();
clock.start();
fileio.open( "randInt3M.txt", fileio.r );
mov( eax, fin );
filesys.size( fin );
mov( eax, ecx );
if( ecx != -1 ) then
stdout.put( nl "Size of file = ", (type uns32 ecx), " bytes", nl );
str.alloc( ecx );
mov( eax, line );
fileio.read( fin, [eax], ecx ); // get whole file into string
mov( line, eax ); // now ensure 'end' is 'trimmed'
dec( ecx );
while( (type char [eax+ecx]) < '0' || (type char [eax+ecx]) > '9' ) do
dec( ecx );
endwhile;
inc( ecx );
mov( ecx, (type str.strRec [eax]).length );
mov( 0, (type char [eax+ecx]) ); // ensure 0 terminated ...
initVec( myVec, @size(Rec) ); // now get 'words' into a Vec of int32
mov( &myFreeRec, pFreeRec ); // so can clearVec ... ok
mov( line, esi );
while( (type char [esi]) != 0 ) do
conv.atoi32( [esi] );
mov( eax, myRec.rval );
push( esi );
//push( ebx ); push( ecx ); push( esi ); push( edi );
push_backVec( myVec, &myRec );
pop( esi );
endwhile;
str.free( line );
clock.stop();
stdout.put( nl "To fill Vec with int32 from file ... ms = ",
(type uns64 clock.Accumulated), nl
"myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
clock.start();
mov( &myCmpInt, pMyCmp );
msortVec( myVec );
clock.stop();
stdout.put( nl "To msort Vec ... ms = ",
(type uns64 clock.Accumulated) );
isSorted( myVec );
stdout.put( ", isSorted( myVec ) = ", (type boolean al), nl );
mov( myVec.size, ecx );
dec( ecx );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
intmul( @size( Rec ), ecx, ecx );
add( myVec.ary, ecx );
stdout.put( "last 'sorted' value = '",
(type Rec [ecx]).rval, "'" nl );
clearVec( myVec );
else
stdout.put( "Error calculating file size" nl );
endif;
fileio.close( fin );
stdout.puts( nl "Press 'Enter' to exit/continue ... " );
stdin.readLn();
end fileSizeReadDemo_atoi32;
You will find the 2 files you need to have available to include ...
"vector2_func's.hhf"
"vector2.hhf"
at this next link:
http://developers-heaven.net/forum/index.php?topic=2600.0
This next example program, demo's using HLA blobs, for super-fast loading of a (very large) file into a 'file-like-memory-buffer' ... all in one BIG GULP ... then processing from that LARGE HLA BLOB/BUFFER ... (here - a dynamic memory buffer with file like behaviour) ...
Note: it uses the same file of 3,000,000 random integers as the two programs above. It also demo's a way to handle the problem of whitespace/new-line char's ... (or here, any NON integer char's) ... that might exist at the end of the file of integers. I found on my 64 bit Windows 7 system, that the load times for method2/method1 were consistently at the ratio 1.4
Ok ... here is the HLA BLOB example ...
program blobDemo; // 2012-08-21 //
const
InitCap: uns32 := 3_000_000;
FNAME: string := "randInt3M.txt";
#includeOnce( "vector2_func's.hhf" )
type
Rec: record
rval: int32;
endrecord;
pRec: pointer to Rec;
procedure myFreeRec( pr: pRec in eax ); @noframe;
begin myFreeRec;
// no dynamic memory to free ...
ret();
end myFreeRec;
// re. msort...
procedure myCmpInt( a: pRec in esi; b: pRec in edi ); @returns( "eax" );
begin myCmpInt;
mov( (type Rec [esi]).rval, eax );
if( eax <= (type Rec [edi]).rval ) then mov( 1, eax );
else mov( 0, eax );
endif;
end myCmpInt;
procedure isSorted( var v: Vec ); @returns( "eax" );
begin isSorted;
mov( v, ebx );
mov( (type Vec [ebx]).size, ecx );
if( ecx > 2 ) then
dec( ecx );
intmul( @size( Rec ), ecx, eax );
add( (type Vec [ebx]).ary, eax );
mov( (type Rec [eax]).rval, edi );
while( (type int32 ecx) > 0 ) do
dec( ecx );
sub( @size( Rec ), eax );
mov( (type Rec [eax]).rval, esi );
if( (type int32 esi) > edi ) then
mov( 0, eax );
break;
endif;
mov( esi, edi );
endwhile;
endif;
mov( 1, eax );
end isSorted;
static
fin: dword;
tmpReg: dword;
line: string;
myVec: Vec;
myRec: Rec;
clock: timer_t;
blb: blob.blob;
c: char[4];
loops: uns32 := 5; // so can check load/sort run times ... x5
sum1: uns32[2] := [ 0, 0 ];
sum2: uns32[2] := [ 0, 0 ];
ratio: real32;
begin blobDemo;
clock.create();
beginLoops:
clock.start();
fileio.open( FNAME, fileio.r );
mov( eax, fin );
filesys.size( fin );
mov( eax, ecx );
if( ecx != -1 ) then
stdout.put( nl "Size of file = ", (type uns32 ecx), " bytes", nl );
str.alloc( ecx );
mov( eax, line );
fileio.read( fin, [eax], ecx ); // get whole file into string
mov( line, eax ); // now ensure 'end' is 'trimmed'
dec( ecx );
while( (type char [eax+ecx]) < '0' || (type char [eax+ecx]) > '9' ) do
dec( ecx );
endwhile;
inc( ecx );
mov( ecx, (type str.strRec [eax]).length );
mov( 0, (type char [eax+ecx]) ); // ensure 0 terminated ...
initVec( myVec, @size(Rec) ); // now get 'words' into a Vec of int32
mov( &myFreeRec, pFreeRec ); // so can clearVec ... ok
mov( line, esi );
while( (type char [esi]) != 0 ) do
conv.atoi32( [esi] );
mov( eax, myRec.rval );
mov( esi, tmpReg ); // preserve esi ...
//push( ebx ); push( ecx ); push( esi ); push( edi );
push_backVec( myVec, &myRec );
mov( tmpReg, esi ); // retore esi ...
endwhile;
str.free( line );
clock.stop();
add( eax, sum1 );
stdout.put( nl "To fill Vec with int32 from file/string_buf ... ms = ",
(type uns64 clock.Accumulated), nl
"myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
clock.start();
mov( &myCmpInt, pMyCmp );
msortVec( myVec );
clock.stop();
add( eax, sum1[4] );
stdout.put( nl "To msort Vec ... ms = ",
(type uns64 clock.Accumulated) );
isSorted( myVec );
stdout.put( ", isSorted( myVec ) = ", (type boolean al), nl );
mov( myVec.size, ecx );
dec( ecx );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
intmul( @size( Rec ), ecx, ecx );
add( myVec.ary, ecx );
stdout.put( "last 'sorted' value = '",
(type Rec [ecx]).rval, "'" nl );
clearVec( myVec );
else
stdout.put( "Error calculating file size" nl );
endif;
fileio.close( fin );
stdout.puts( nl nl "Ok ... now demo of almost as super fast "
"fileio ... using an HLA blob ..." nl nl );
initVec( myVec, @size( Rec ) ); // DON'T FORGET to init... @size( Rec )
clock.start();
blob.a_load( FNAME );
mov( eax, blb );
// now trim off any/all NON 0..9 char's from end of blob ...
// and reset length ...
//blob.maxlen( blb );
//stdout.put( "blob.maxlen = ", (type uns32 eax), nl );
blob.length( blb );
//stdout.put( "blob.length = ", (type uns32 eax), nl );
mov( eax, ecx ); // mov (present) blob length into ecx ...
dec( ecx ); // so can 'test' content of last char's in blob
while( (type int32 ecx) >= 0 ) do
//get at last char per either of the 2 lines below ...
//blob.readAt( blobPointer, buffer, index, count );
//blob.readAt( blobPointer, [eax], 2999999, 1 );
blob.readAt( blb, &c, ecx, 1 );
mov( c, al );
if( al < '0' || al > '9' ) then
dec( ecx );
else
break;
endif;
endwhile;
inc( ecx ); // get 'new' length
blob.setLength( blb, ecx ); // Ok ... update with 'new' blob length
// Now can get each int32 from blob without worrying about 'crash' ...
// if there were any non 0..9 char's, after n'th 0..9 char, before eof
while( !blob.eof( blb ) ) do
blob.geti32( blb );
mov( eax, myRec.rval );
push_backVec( myVec, &myRec );
endwhile;
blob.free( blb ); // free (not destroy) since used alloc via blob.a_load
clock.stop();
add( eax, sum2 );
stdout.put( nl "To fill Vec with int32 from file/blob ... ms = ",
(type uns64 clock.Accumulated), nl
"myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
clock.start();
mov( &myCmpInt, pMyCmp ); // done above alraedy
msortVec( myVec );
clock.stop();
add( eax, sum2[4] );
stdout.put( nl "To msort Vec ... ms = ",
(type uns64 clock.Accumulated) );
isSorted( myVec );
stdout.put( ", isSorted( myVec ) = ", (type boolean al), nl );
mov( myVec.size, ecx );
dec( ecx );
stdout.put( "myVec.size = ", myVec.size,
", myVec.capacity = ", myVec.capacity, nl );
intmul( @size( Rec ), ecx, ecx );
add( myVec.ary, ecx );
stdout.put( "last 'sorted' value = '",
(type Rec [ecx]).rval, "'" nl );
clearVec( myVec );
dec( loops );
jnz( beginLoops );
stdout.put( nl nl
"Summery of times ..." nl nl
"Load 1st method sum:", sum1:6, nl
"Sort sum:", sum1[4]:6, nl
"Load 2nd method sum:", sum2:6, nl
"Sort sum:", sum2[4]:6, nl nl );
finit();
fild( sum2[0] );
fild( sum1[0] );
fdivp();
fstp( ratio ); // POP and store sto int ...
stdout.put( "Ratio of load times method2/method1 =", ratio:5:2, nl );
stdout.puts( nl "Press 'Enter' to exit/continue ... " );
stdin.readLn();
end blobDemo;
You will find the 2 files you need to have available to include ...
"vector2_func's.hhf"
"vector2.hhf"
at this next link:
http://developers-heaven.net/forum/index.php?topic=2600.0