Author Topic: Six Fast Steps to Programming in High Level Assembly (HLA) ...  (Read 47774 times)

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
  ~~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.)


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 HLA

https://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.
« Last Edit: September 11, 2018, 02:02:49 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #1 on: August 07, 2012, 05:49:33 AM »
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.

Code: [Select]
// 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;
« Last Edit: August 19, 2012, 09:46:39 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #2 on: August 07, 2012, 06:00:21 AM »
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.

Code: [Select]
// 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;
« Last Edit: September 04, 2012, 01:54:14 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #3 on: August 07, 2012, 06:19:48 AM »
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.

Code: [Select]
// 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;
« Last Edit: September 04, 2012, 01:55:29 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #4 on: August 07, 2012, 06:48:14 AM »
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.

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

Code: [Select]
// 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;
« Last Edit: September 04, 2012, 02:35:45 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #5 on: August 07, 2012, 08:23:17 AM »
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.

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

« Last Edit: September 04, 2012, 01:59:12 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #6 on: August 07, 2012, 08:53:43 AM »
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.

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

Code: [Select]
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;
« Last Edit: September 04, 2012, 02:37:44 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #7 on: August 07, 2012, 09:15:15 AM »
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.


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

Code: [Select]
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;
« Last Edit: September 04, 2012, 02:04:39 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #8 on: August 07, 2012, 10:02:07 AM »
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" ...

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

Code: [Select]
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;
« Last Edit: August 29, 2012, 08:32:15 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #9 on: August 07, 2012, 10:17:30 AM »
Now the HLA vector of string example ... (that uses file "readLine.hhf")

7.

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

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

Code: [Select]

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.
« Last Edit: March 07, 2013, 07:57:56 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #10 on: August 07, 2012, 10:45:17 AM »
And  the HLA SLList of string example ...

8.

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

Code: [Select]
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;
« Last Edit: September 04, 2012, 02:42:13 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #11 on: August 07, 2012, 11:04:25 AM »
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)

Code: [Select]
“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.
« Last Edit: August 29, 2012, 08:34:38 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #12 on: August 07, 2012, 11:24:32 AM »
Ok ... the first test program, that considers case ...

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

Code: [Select]
// 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;
« Last Edit: August 27, 2012, 06:11:48 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #13 on: August 07, 2012, 11:34:00 AM »
Now using readWord ... (and vector2.hhf) ...

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

Code: [Select]
// 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;
« Last Edit: August 27, 2012, 06:19:22 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in High Level Assembly (HLA) ...
« Reply #14 on: August 07, 2012, 11:37:12 AM »
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)

Code: [Select]
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
« Last Edit: September 04, 2012, 02:21:08 AM by David »