News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Object Oriented Code Attempt

Started by DarkWolf, April 12, 2007, 12:41:48 AM

Previous topic - Next topic

DarkWolf

I started out with the code from the redblack tree example in HIDE.
I was getting lost with the AoA tree edition, it seems a little out of order to me.
I am only getting errors it seems with the name foo for the VMT and procedure.
Is it really that simple ?  :-P

Code is compiled on Linux with v1.89



program ObjCode;



#includeonce ("stdlib.hhf")



type

textclass : class

var

s : string;



procedure create; returns( "esi" );

procedure destroy;

method input( s:string );

method print( s:string );



endclass;



var

foo : textclass;



readonly

VMT( foo );

endreadonly



begin ObjCode;



procedure foo.create; @nodisplay;

begin create;

if( esi = NULL ) then

push( eax );

mem.alloc( @size( foo ));

mov( eax, esi );

pop( eax );

endif;

mov( &foo._VMT_, this._pVMT_ );

end create;



procedure foo.destroy; @nodisplay;

begin destroy;

push( eax );

free( s );

if( isInHeap( esi )) then

free( esi );

endif;

pop( eax );

end destroy;



method foo.input( s ); nodisplay;

begin input

stdin.gets( s );

end input



method foo.print( s ); nodisplay;

begin print

stdout.put( "You entered : ", s );

end print



foo.input;

foo.print;

foo.destroy;



end ObjCode;



Error in file "ObjCode.hla" at line 21 [errid:107447/hlaparse.c]:
syntax error, unexpected LocalVarID.
Near: << ) >>

Error in file "ObjCode.hla" at line 26 [errid:107447/hlaparse.c]:
syntax error, unexpected procedureTkn.
Near: << procedure >>
--
Where's there's smoke, There are mirrors.
Give me Free as in Freedom not Speech or Beer.
Thank You and Welcome to the Internet.

Sevag.K


var

foo : textclass;



readonly

VMT( foo );

endreadonly



VMT has to be a class identifier.  Try:

VMT (textclass);

DarkWolf

I see that I didn't use the classname in the VMT . My labels seem all wrong, it reports errors with ObjCode as the program identifier and if I use either foo or textclass in the procedures and methods. With what I set up what would be the correct identifiers ?
--
Where's there's smoke, There are mirrors.
Give me Free as in Freedom not Speech or Beer.
Thank You and Welcome to the Internet.

Sevag.K

OK.  I pumped your code into HIDE and found loads of errors :)

First one we already covered


readonly

VMT( foo );

endreadonly


should be VMT (textclass);

Right under that you have: 

"begin ObjCode;"

Which belongs down below all the class methods/procedures.



procedure foo.create; @nodisplay;


all your procedures use "foo" as a namespace which should be the class name itself "textclass"



method foo.input( s ); nodisplay;

begin input

stdin.gets( s );

end input



method foo.print( s ); nodisplay;

begin print

stdout.put( "You entered : ", s );

end print


-nodisplay should be @nodisplay;
-missing semicolons.
-you have to declare a type for 's' in the method parameters list as in "s:string"




foo.input;

foo.print;

foo.destroy;


The "begin objCode;" should go above these statements.
-foo.input and foo.print expect a string parameter
-foo.destroy needs an empty parameter: "foo.destroy();"

Thats about all the errors HLA reported.


DarkWolf


program ObjCode;



#includeonce ("stdlib.hhf")



type

textclass: class

var

s: string;



procedure create; returns( "esi" );

procedure destroy;

method input( s:string );

method print( s:string );



endclass;



var

foo: textclass;



readonly

VMT( textclass );

endreadonly



procedure textclass.create; @nodisplay;

begin create;

if( esi = NULL ) then

push( eax );

mem.alloc( @size( textclass ));

mov( eax, esi );

pop( eax );

endif;

mov( &textclass._VMT_, this._pVMT_ );

end create;



procedure textclass.destroy; @nodisplay;

begin destroy;

push( eax );

free( s );

if( isInHeap( esi )) then

free( esi );

endif;

pop( eax );

end destroy;



method textclass.input( s:string ); @nodisplay;

begin input;

stdin.gets( s );

end input;



method textclass.print( s:string ); @nodisplay;

begin print;

stdout.put( "You entered : ", s );

end print;


begin ObjCode;


foo.input( s );

foo.print( s );

foo.destroy();



end ObjCode;


All errors now point out that I don't have s defined and that there is something still wrong with the procedures.
Did I define s correctly or did I put it in the wrong section ?
The AoA text shows that the methods/procedures are declared in the type section and are defined elsewhere before they are implemented later in the code. I am using them at the bottom and declared them in the type section, did I not define them in the right place ?
--
Where's there's smoke, There are mirrors.
Give me Free as in Freedom not Speech or Beer.
Thank You and Welcome to the Internet.

Sevag.K

That's because you don't have 's' defined outside of the class.  If 's' is going to be the one defined in the class, then you need to do some redesigning of the method parameters.

There is also a missing semicolon on endreadonly.  You can just remove this line since it's depricated.
The "free (s);" in the destroy method should be
mem.free (this.s);

But be careful since you don't allocate any actual memory for the string variable in the class!



DarkWolf

I thought that variables used by the class would have to be defined there.
Using the 'this' keyword in the procedures/methods has cleared that up but not for the object foo.

This is where I am in muddy waters, I have a class and an object. I want to define the variables in the class and have the object use them, this is how I thought OO code worked. Where is the allocation done for the class-defined variables ? I would allocate the storage in the input method that gets the user input but that's not right is it, each call to textclass.input would allocate memory and I only free it in the destroy procedure ?

This string variable is where I am having the most trouble getting the OO code setup.
--
Where's there's smoke, There are mirrors.
Give me Free as in Freedom not Speech or Beer.
Thank You and Welcome to the Internet.

Sevag.K

Quote from: DarkWolf on April 15, 2007, 06:33:20 PM
I thought that variables used by the class would have to be defined there.

That is correct.  The problem is that you trying to pass a non-declared variable outside of the class to the class.


Quote
Using the 'this' keyword in the procedures/methods has cleared that up but not for the object foo.

This is where I am in muddy waters, I have a class and an object. I want to define the variables in the class and have the object use them, this is how I thought OO code worked. Where is the allocation done for the class-defined variables ? I would allocate the storage in the input method that gets the user input but that's not right is it, each call to textclass.input would allocate memory and I only free it in the destroy procedure ?

This string variable is where I am having the most trouble getting the OO code setup.

The allocation is done in the declared class object (foo in your case).  However, string types are pointers.  You have to allocate the storage for the strings elsewhere using str.alloc (or using a procedure that automatically allocates memory such as stdin.a_gets ).


program ObjCode;

// a corrected and annotated version

#includeonce ("stdlib.hhf")

type

textclass: class

var
s: string;

procedure create; returns( "esi" );
method destroy; // note this is a method
method input; // note, no parameters needed
method print;

endclass;

readonly

VMT( textclass );


var
foo: textclass; // declare memory for a textclass object



procedure textclass.create; @nodisplay;
begin create;
if( esi = NULL ) then
push( eax );
mem.alloc( @size( textclass ));
mov( eax, esi );
pop( eax );
endif;

mov( &textclass._VMT_, this._pVMT_ );
mov( 0, this.s); // make sure this is cleared

end create;


method  textclass.destroy; @nodisplay; // this is a method now
begin destroy;
push( eax );
if (this.s > 0) then
// free only if s is allocated
// note you can also mem.isInHeap (s), but this is faster
// since we can use s=0 to indicate NULL string.
str.free( this.s ); // use str.free here
endif;

if( mem.isInHeap( esi )) then
mem.free( esi );
endif;

pop( eax );
end destroy;


method textclass.input; @nodisplay;
begin input;

if (this.s > 0) then
// something is already declared here, free it
mem.free (this.s);
endif;
stdout.put ("Enter input :"); // friendly
stdin.a_gets(); // allocate new memory on heap
mov (eax, this.s); // store pointer in s

end input;



method textclass.print; @nodisplay;
begin print;

// something to print only if s is not null
if (this.s > 0) then
stdout.put( "You entered : ", this.s, nl );
endif;

end print;


begin ObjCode;

foo.create(); //important!!
foo.input();
foo.print();
foo.destroy();


end ObjCode;





Evenbit

Another quick example...

program grid;

#include( "stdlib.hhf" )



type

point:

class

var

x :dword;

y :dword;

lbl :string;

endvar;



procedure create( xcor:dword; ycor:dword ); @returns( "esi" );

method setLabel( title:string );

procedure getLabel; @returns( "eax" );

method changeX( xcor:dword );

method showAll;

method destroy;

endclass;

endtype;



procedure point.create( xcor:dword; ycor:dword ); @nodisplay;

begin create;



    push( eax );

    if ( esi = 0 ) then

        mem.alloc( @size( point ) );

        mov( eax, esi );

    endif;

    mov( &point._VMT_, this._pVMT_ );

mov( xcor, eax );

mov( eax, this.x );

mov( ycor, eax );

mov( eax, this.y );

mov( 0, eax );

mov( eax, this.lbl );

pop( eax );



end create;



method point.setLabel( title:string ); @nodisplay;

begin setLabel;



push( eax );

mov( title, eax );

mov( eax, this.lbl );

pop( eax );



end setLabel;



procedure point.getLabel; @nodisplay;

begin getLabel;



mov( this.lbl, eax );



end getLabel;



method point.changeX( xcor:dword ); @nodisplay;

begin changeX;



push( eax );

mov( xcor, eax );

mov( eax, this.x );

pop( eax );



end changeX;



method point.showAll; @nodisplay;

begin showAll;



mov( this.lbl, eax );

if ( eax != 0 ) then

stdout.put( this.lbl, "  " );

else

stdout.put( "<void>  " );

endif;

stdout.putu32( this.x );

stdout.puts( " " );

stdout.putu32( this.y );

stdout.newln();

stdout.put( "----", nl );



end showAll;



method point.destroy; @nodisplay;

begin destroy;



push( eax );

mov( this.lbl, eax );

if ( eax != 0 ) then

str.free( eax );

endif;

pop( eax );

if ( isInHeap( esi ) ) then

        mem.free( esi );

    endif;



end destroy;



readonly

VMT( point );



var

dart :point;

temp :pointer to point;



static

s :string;

c :byte[64];

t :string;



begin grid;



str.init( c[0], 64 );

mov( eax, s );

str.cat( "Hello", s );

str.a_cpy( s );

mov( eax, t );



dart.create( 5, 6 );

dart.setLabel( t );

dart.showAll();

dart.changeX( 8 );

dart.showAll();

dart.destroy();



str.cat( " World", s );

str.a_cpy( s );

mov( eax, t );

point.create( 50, 60 );

mov( esi, temp );

(type point [esi]).setLabel( t );



point.create( 2, 2 );

(type point [esi]).showAll();

(type point [esi]).destroy();



temp.showAll();

temp.destroy();



end grid;



Nathan.

DarkWolf

Attempting to compile either example gives me this error from the linker.
It apparently only compiles a binary file and not an executable.
Command was 'hla ObjCode.hla'. :

ld: warning: cannot find entry symbol _start; not setting start address

But if I use my makefile it works. Is there a difference between my makefile and hla's default operation ?

Makefile:

project: ObjCode.o
hla -x:ObjCode ObjCode.o

ObjCode.o: ObjCode.hla
hla -c ObjCode.hla

clean:
rm *.o
rm *.asm
rm *.inc

nomore: rm *.*


Nevertheless I have to study and make sure I can get right from now on.  ;-)  :U
--
Where's there's smoke, There are mirrors.
Give me Free as in Freedom not Speech or Beer.
Thank You and Welcome to the Internet.

Sevag.K

Don't know, I haven't tested the linux version of HLA in a while.

DarkWolf

Think of me as your guinea pig  :-P
--
Where's there's smoke, There are mirrors.
Give me Free as in Freedom not Speech or Beer.
Thank You and Welcome to the Internet.

DarkWolf

Speaking of testing and guinea pigs.

I split up the file and tried to make a header and unit, to use makefile and maybe expand later.
After fiddling with ar to make the library, my current error is that the textclass isn't defined when compiling the main program.
I can compile the unit and make the .a file (linux version of .lib) but it won't recognize foo as an object of textclass.

I was following the shape example from electronic edition AoA and I don't see a section I may have missed.
The header has the class definition, the unit has the procedure definitions and VMT and the main program has the actual implementation.

( I never had guinea pigs growing up, hamsters and hermit crabs, but not guinea pigs. )



[attachment deleted by admin]
--
Where's there's smoke, There are mirrors.
Give me Free as in Freedom not Speech or Beer.
Thank You and Welcome to the Internet.

Sevag.K

I got ubuntu working so I'm go with linux problems :)

Your biggest problem is that you don't declare your class methods/procedures as external.  You have to do this if you want to work with units!


// 23/06/2007 15:58:07   
// HLA v1.96 Linux

// Sean Shaffer, DarkWolf, KB3IMT

// Experimenting with OO

#if( !@defined( objcode_hhf ))
?objcode_hhf := true;

type
textclass: class
var
s: string;

procedure create; returns( "esi" ); @external;
method destroy; @external; // note this is a method
method input; @external; // note, no parameters needed
method print; @external;

endclass;

#endif;


Also, to get it to compile without complaints, I changed the objcode.hhf include to the current directory;

#includeonce ("objcode.hhf")

And used this makefile


project: objcode.o objcode.a
hla -x:objcode objcode.o objcode.a

objcode.o: objcode.hla
hla -cg objcode.hla

objcode.a: objcode2.o
ar -q objcode.a objcode2.o

objcode2.o: objcode2.hla objcode.hhf
hla -cg objcode2.hla

clean:
rm *.o
rm *.asm
rm *.inc

nomore: rm *.*


You weren't properly linking in objcode.a

If you want to add a lib path on the command line, the proper syntax is:

hla -x:objcode objcode.o objcode.a -lib./

But it's not needed if the library resides in the current directory.

DarkWolf

Duh, I can't believe I forgot to mark them @external.

Well all is good now and I also forgot that the lib and header could be in the same directory. For some reason I was thinking I had to put them relative to the set paths.
Yea, time to screw something else up   :wink
--
Where's there's smoke, There are mirrors.
Give me Free as in Freedom not Speech or Beer.
Thank You and Welcome to the Internet.