Hey guys

Please read the preprocessor section at the bottom if you don't want to lose your code

Well it's finally here, and probably still has bugs in it but give it a go and tell me what you think.

Defining our object

The class definition is fairly straight forward but must be enclosed with CLASS/ENDC keywords.



CLASSNAME class

_blah dd [default value] ; data
_blah CLASSNAME <> ; embedded object

Blah proto :DWORD ; static method
Blah* proto :DWORD ; virtual method
Blah proto :DWORD = 0 ; abstract method

protected

; protected stuff here

private

; private stuff here

CLASSNAME endc


Class data MUST start with an underscore, the underscore is used by the preprocessor and DOESN'T become part of the name. If you want to prefix your data with an underscore you need to use two underscores. You can also give data members a default value which is used to initialize new objects.

Member functions must have at least 1 argument for the THIS ptr and the C calling convention is supported.

Members can have 1 of 3 forms of access control :-
public (default, not a keyword ) - members can be accessed by anyone from anywhere.
protected - members can only be accessed from inside the class that defined them or a class derived from the defining class.
private - members can only be accessed from inside the class that defined them.

Every base class must have a virtual destructor method, but they are optional for derived classes. Constructors are completely optional.

Defining our methods

Defining methods is extremely simple with the only requirement being that the methods be enclosed in a class segment.



CLASSNAME segment

Blah proc USES ebx edi esi _this

ret

Blah endp

CLASSNAME ends


The preprocessor will automatically prefixes the class name to the method name, but YOU must manually define the THIS ptr argument.

It's also YOUR responsibility to call the base class constructor/destructor methods and initialize/destroy embedded objects. ( see below )

Accessing our object

I've tried to make the preprocessor syntax as unobtrusive as possible while extending the existing MASM syntax.



CBLAH segment

Blah proc USES ebx edi esi _this

mov ebx, _this <@CurClass::blah>

mov blah.data, eax ; access data
invoke blah.method, [args] ; access functions

mov blah.embeddedObject.data, eax
inboke blah.embeddedObject.method, [args]

ret

Blah endp

CBLAH ends


As you can see you simply define a symbol telling the preprocessor what type of object the register addresses and the name you wish to use to access the object. The only restriction to defining symbols is the second word in the line MUST be the register ( I'll see if I can improve this later :rolleyes: ). The @CurClass keyword tells the preprocessor to use the name of the class whose segment you are currently in. Obviously if you aren't in a class segment then this won't work and you need to specify the actual class name.

Once you've defined your symbol it's simply a case of using it like a structure.

If you have embedded objects in your class then you can access them directly.

I said earlier that YOU where responsible for initializing the object, here's how



CBLAH segment

Constructor proc USES ebx edi esi _this

mov ebx, _this <@CurClass::blah>

; init base class

.superclass blah.Constructor, [args]

; init embedded objects

invoke blah.embeddedObject.Constructor, [args]

...
...
...

ret

Constructor endp

Destructor proc USES ebx edi esi _this

mov ebx, _this <@CurClass::blah>

...
...
...

; destroy embedded objects

invoke blah.embbededObject.Destructor

; destroy base class

.superclass blah.Destructor

ret

Destructor endp

CBLAH ends


Calling the base is required but you could initialize and destroy embedded objects whenever you like.

Creating an object

The preprocessor currently only supports dynamic creation of objects.



.new reg, class::symbol, [args]

.delete symbol


reg - MUST be a register ( required )
class - class name ( required )
symbol - register alias ( required, I'll look into making this optional later )
args - arguments passed to the constructor

The symbol is simply an alias for the register but allows you to access the object using a name. Symbols are only valid inside the PROC that defined them and if you define a symbol that already exists, the existing symbol is overwritten with the new one.

The .new and .delete keywords are converted into macro calls. The macros are defined in the preprocessor.inc file and can be customized to your hearts content. If modifying the new macro there are 2 things you MUST do :-
1. copy the class template into the newly allocated memory, the class template contains the default data values and virtual method pointers.
2. move the memory pointer into the specified register before returning.

The preprocessor will allow you to create objects with abstract methods, but if you intend to call them you need to either derive a new class or manually overload the virtual method entry. Check the processed output to get the method name.

Preprocessing

You must include preprocessor.inc in your source.

mo -i:\includeDir -o:\outputDir *.asm

The preprocessor requires some strict usage at the moment, but I hope to improve that soon.

You must run the preprocessor from the directory that contains the files you want to process.
You must supply an include directory so it can find include files not in the current directory. Only one include directory supported at the moment.
You must supply an output directory, it MUST be a different directory than the source as the preprocessor uses the original file name when creating the processed file in the output directory.

The preprocessor hasen't been optimized yet at all so there's a lot of room for speed improvement. The preprocessor will search all include files specified in the source and will write ALL of these to the output directory.

A quick note on the error reporting, it's not good :rolleyes:

Also the preprocessor only opens its dialog if an error occurs so if you don't see anything, then everything worked or it hung your system ( something else to improve :rolleyes: ).

Final thoughts

There are a number of things to improve but I'm tossing around a few ideas...

- .clone keyword for cloning objects
- .overload keyword for manual overloading of abstract methods
- do we need inline methods?

Tell me what you think.

Maelstrom
Posted on 2003-05-01 18:15:28 by Maelstrom
Ok here's a quick example



CFILE class

Close proto :DWORD
Create proto :DWORD, :DWORD
Destructor* proto :DWORD
GetSize proto :DWORD
Open proto :DWORD, :DWORD
Read proto :DWORD, :DWORD, :DWORD
Seek proto :DWORD, :DWORD, :DWORD
Write proto :DWORD, :DWORD, :DWORD

private

_handle dd 0

CFILE endc

CFILE segment

Close proc USES ebx edi esi _this

mov ebx, _this <@CurClass::file>
.if file.handle
invoke CloseHandle, file.handle
test eax, eax
jz _1
mov file.handle, 0
.endif
.ret

_1: ; do error stuff

Close endp

Create proc USES ebx edi esi _this, _fileName

mov ebx, _this <@CurClass::file>
invoke CreateFile, _fileName, GENERIC_READ + GENERIC_WRITE,
FILE_SHARE_READ + FILE_SHARE_WRITE, 0, CREATE_ALWAYS,
FILE_ATTRIBUTE_ARCHIVE, 0
cmp eax, INVALID_HANDLE_VALUE
je _1
mov file.handle, eax
.ret

_1: ; do error stuff

Create endp

Destructor proc USES ebx edi esi _this

mov ebx, _this <@CurClass::file>
;--------------------------------------------------------------------------------
.superclass file.Destructor
;--------------------------------------------------------------------------------
.ret

Destructor endp

GetSize proc USES ebx edi esi _this

mov ebx, _this <@CurClass::file>
xor eax, eax
.if file.handle
invoke GetFileSize, file.handle, 0
cmp eax, INVALID_HANDLE_VALUE
je _1
.endif
.ret eax

_1: ; do error stuff

GetSize endp

Open proc USES ebx edi esi _this, _fileName

mov ebx, _this <@CurClass::file>
invoke CreateFile, _fileName, GENERIC_READ + GENERIC_WRITE,
FILE_SHARE_READ + FILE_SHARE_WRITE, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_ARCHIVE, 0
cmp eax, INVALID_HANDLE_VALUE
je _1
mov file.handle, eax
.ret

_1: ; do error stuff

Open endp

Read proc USES ebx edi esi _this, _buf, _size

LOCAL _count:DWORD

mov ebx, _this <@CurClass::file>
xor eax, eax
.if file.handle
invoke ReadFile, file.handle, _buf, _size, addr _count, 0
test eax, eax
jz _1
mov eax, _count
.endif
.ret eax

_1: ; do error stuff

Read endp

Seek proc USES ebx edi esi _this, _distance, _origin

mov ebx, _this <@CurClass::file>
xor eax, eax
.if file.handle
invoke SetFilePointer, file.handle, _distance, 0, _origin
cmp eax, INVALID_SET_FILE_POINTER
je _1
.endif
.ret eax

_1: ; do error stuff

Seek endp

Write proc USES ebx edi esi _this, _buf, _size

LOCAL _count:DWORD

mov ebx, _this <@CurClass::file>
xor eax, eax
.if file.handle
invoke WriteFile, file.handle, _buf, _size, addr _count, 0
test eax, eax
jz _1
mov eax, _count
.endif
.ret eax

_1: ; do error stuff

Write endp

CFILE ends


Maelstrom
Posted on 2003-05-01 18:29:56 by Maelstrom
Glad to see you finished it up! Great work!

I will give it a solid once over tonight and give you any critical feedback i can. But for now take a pat on the back! To do stuff like this takes alot of work!

:alright:
NaN
Posted on 2003-05-01 23:20:40 by NaN
Preprocessor is a good way to achieve the goal. I noticed you used the MACRO in the previous version, if you have lost the confidence of MACRO's power?
Great idea to do this, I will check your design carefully.
Thank you
Posted on 2003-05-02 02:57:55 by taowen2002
NaN

Thanks for the encouragement, feedback would be great :alright:

I'm currently using the preprocessor to improve the preprocessor, primarily the error reporting as it currently sucks :grin:

taowen2002

No I haven't lost confidence in MASM macros, actually until I wrote the macro OOP framework I didn't realize how powerful they can be.
The decision to do a preprocessor was mainly because there's no limit to what I can do with it.

Maelstrom
Posted on 2003-05-02 05:50:25 by Maelstrom
Can you explain the power of your preprocessor for me?
Why I need a preprocessor as we already have so powerful macro?
I am more concern about how simple the usage can be than how powerful the tool can be. It is my principle of designing OOP model
Posted on 2003-05-02 12:13:51 by taowen2002
Pre-processing allows your to make the "simplest" commands. You have the ability to program complex routines to take a simple idea and forge a complex result.

Macro's can do this as well. In essence they *are* a pre-processor. However you are restricted to the limitations of this "macro language" that was conceived from ASM to begin with. To skip over macro's and use ASM purely gives your the largest amount of pre-processor flexibility and options when defining your OOP statements.

:NaN:
Posted on 2003-05-02 17:38:12 by NaN
I am trying a simple example, but have a couple questions:

1) What is the proper way to call a class function from within the class.

2) Am I correct in assuming my 'IF DEBUG's will break the class?

3) Please point out any errors, supply more examples, etc...


The .ret macro from the other thread isn't in the distribution.



; First In First Out Queue

CQUEUE class

Create proto :DWORD, :DWORD
Destructor* proto :DWORD

Count proto :DWORD ; return number of items in queue
Clear proto :DWORD

Enqueue proto :DWORD, :DWORD ; push an item in back of queue
Dequeue proto :DWORD ; pop an item from front of queue

Front proto :DWORD ; return front item
Back proto :DWORD ; return back item

IF DEBUG
Debug_Print proto :DWORD
ENDIF

private

__count DWORD 0
__front DWORD NULL
__back DWORD NULL
_granularity DWORD 0

_handle DWORD NULL
_blocks DWORD 0

CQUEUE endc



CQUEUE segment

Create proc USES ebx esi _this, _granularity
mov ebx, _this <@CurClass::queue>
mov esi, _granularity

cmp queue.count, 0
jne _x

mov queue.granularity, esi

test esi, esi
je _x

invoke GetProcessHeap
invoke HeapAlloc, eax, NULL, esi

test eax, eax
je _x

mov queue.handle, eax
; ### How?
invoke Clear, ebx

mov eax, ebx
.ret
_x:
xor eax, eax
.ret
Create endp


Count PROC _this
mov edx, _this <@CurClass::queue>
.ret queue._count
Count ENDP

Clear PROC _this
mov edx, _this <@CurClass::queue>
xor eax, eax
mov ecx, queue.handle
mov queue._count, eax
mov queue._front, ecx
mov queue._back, ecx
.ret
Clear ENDP


Enqueue PROC item, _this
mov edx, _this <@CurClass::queue>
inc queue._count

.ret
Enqueue ENDP

Dequeue PROC _this
mov edx, _this <@CurClass::queue>
dec queue._count

.ret
Dequeue ENDP


Front PROC _this
mov edx, _this <@CurClass::queue>
mov ecx, queue._front
.ret DWORD PTR [ecx]
Front ENDP

Back PROC _this
mov edx, _this <@CurClass::queue>
mov ecx, queue._back
.ret DWORD PTR [ecx]
Back ENDP


IF DEBUG
Debug_Print PROC uses ebx esi edi, _this
mov edx, _this <@CurClass::queue>
; Output hex DWORDs from front of queue to back

.ret
Debug_Print ENDP
ENDIF

CQUEUE ends
Posted on 2003-05-04 09:57:56 by bitRAKE
Hey bitRAKE

What is the proper way to call a class function from within the class.

All class members are accessed thru the class symbol.
The preprocessor determines the member type and generates the appropriate output.



mov queue.granularity, esi ; access data

invoke queue.Clear ; access method


Am I correct in assuming my 'IF DEBUG's will break the class?

Well yes and no.
The preprocessor will find the debug method inside the ( IF DEBUG ) block and will add it to the class definition.
If you invoke the debug method from inside an ( IF DEBUG ) block, which I assume will be the case, everything works fine since MASM handles these.
If you invoke the debug method outside an ( IF DEBUG ) block then MASM will spit the dummy.
If the debug method is virtual or abstract, the class structure will contain a method pointer regardless of the DEBUG state.



invoke queue.Debug_Print ; MASM won't be able to find the proc

IF DEBUG
invoke queue.Debug_Print ; works fine
ENDIF


Please point out any errors, supply more examples, etc...

No syntax errors, but there's a error in the Create method.
Since you also have a Count method the preprocessor was treating it as a method call, I'll add some code to trap this later.
I'm currently OOPing the preprocessor so I'll post some of the classes I create.



cmp queue.count, 0

; should be

cmp queue._count, 0


The .ret macro from the other thread isn't in the distribution.

The .ret macro isn't a requirement for the preprocessor, but I'll add it to the next release.

Maelstrom
Posted on 2003-05-04 18:08:12 by Maelstrom
Im trying to preprocess you CFILE example as a starting point, but im not getting to far.. i keep getting your dlg box pop-up.

Can you expand on the command line requirements again? Im lost with the include bit...

Do i need to provide the path to the oop files? (current directroy, ie. run mo.exe from the current directroy and also provide the path in the -i:\D:\masm32\acitve\oop as well?

I have made a sub directory "out" for output. I dont think this is the fault..

The architecture looks good, im eager to get going on it.. but for now this is a stumping point.

:NaN:
:stupid:
Posted on 2003-05-04 22:01:09 by NaN
Whoo hooo!

I got an output.. but i have a bunch of .ret that are no good ;)


Now im getting somewhere....
Posted on 2003-05-04 22:08:33 by NaN
I put mo.exe in a directory, then created two directories: one called .\samples and another .\out. With mo.exe is a batch file called samples.bat:
mo -i\samples -o\out *.asm
I've been creating some test and just throw 'em in the samples directory and double click the bat. Might want to do something like this for the distribution? I want to build a little test/debug shell for every class.
Posted on 2003-05-04 22:31:23 by bitRAKE
bitRAKE

Just noticed on the Enqueue method, the THIS ptr must be first, probably just a typo tho ;)

NaN

Sorry about the lack of docs.



mo -i:[include dir] -o:[output dir] filespec


You must run the preprocessor from the directory that contains the source you want to process.

The include directory is the directory where your includes are, the same directory you supply to ML for windows.inc, kernel32.inc, etc
I only have a single include directory but I'll add support for multiple directories later.
The preprocessor checks this directory if it can't locate an included file in the current directory

The output directory will recieve the processed files.

This is the commandline I use with relative paths. I call it using a shortcut to a batch file.



mo -i:\RADASM\MASM\INC -o:\RADASM\OUT *.asm


Just change the .ret to a normal ret, I think all the return values in the file example are already in EAX.

Maelstrom
Posted on 2003-05-04 22:42:01 by Maelstrom
Originally posted by Maelstrom
Just noticed on the Enqueue method, the THIS ptr must be first, probably just a typo tho ;)
Hey, just seeing if you were paying attention - or rather the preprocessor. :)

Thanks, for coming through with a slick tool!
Posted on 2003-05-04 22:51:41 by bitRAKE
I seriously need a working example to see how it is intended to work... I getting pre-processed output, but im haveing a hell of a time using it. Its probably my only style of coding that is to blame, but i dont have much to work on here.

I finally got it to parse and build multiple outputs:
My framework:
	DataClass class


Data1 dd 0 ; Data value 1
Data2 dd 20 ; Data value 2

Destructor* proto lpThis:DWORD
GetData1 PROTO lpThis:DWORD
GetData2 PROTO lpThis:DWORD
SetData1 PROTO lpThis:DWORD, mydata:DWORD
SetData2 PROTO lpThis:DWORD, mydata:DWORD

private

AddData PROTO lpThis:DWORD
Data3 dd 0

DataClass endc

;--------------------------------------------------------------------------------
DataClass segment

GetData1 proc USES ebx edi esi _this:DWORD

mov ebx, _this <@CurClass::Data>

ret
GetData1 endp




GetData2 proc USES ebx edi esi _this:DWORD

mov ebx, _this <@CurClass::Data>

ret
GetData2 endp




SetData1 proc USES ebx edi esi _this:DWORD, mydata:DWORD

mov ebx, _this <@CurClass::Data>

ret
SetData1 endp




SetData2 proc USES ebx edi esi _this:DWORD, mydata:DWORD

mov ebx, _this <@CurClass::Data>

ret
SetData2 endp




AddData proc USES ebx edi esi _this:DWORD

mov ebx, _this <@CurClass::Data>

ret
AddData endp



Destructor proc USES ebx edi esi _this:DWORD

mov ebx, _this <@CurClass::Data>

ret
Destructor endp

DataClass ends


Seing this is only a "class" i still have to use it. I discovered the "include" directive is funny in that it has two roles (for pre-processing its only to include other files to be preprocessed), alternately in MASM its to, well, include ;)

To beat back the error i keep getting from this, i decided to make a oop code file (OCode.asm):
.data

include OOP.inc

.code
.new ebx, DataClass::Obj


.delete Obj


I can cleanly preprocess this file with the command line "mo -i:.\in -o:.\out ocode.asm", which generates an OOP.inc file and a OCode.asm file in my out directory.

Lastly i have a test file to wrap it all into a windows exe:
.386

.model flat,stdcall
option casemap:none

include D:\masm32\include\_Macros_.inc
INCPATH D:\masm32
INCHDR windows, kernel32, user32, masm32, shell32, gdi32, debug
INCLIB kernel32, user32, masm32, shell32, gdi32, debug

include preprocessor.inc

.data


.code
start:
push ebx

include ocode.asm



pop ebx
invoke ExitProcess, NULL

end start
end


Im including my OOP code hopin it will insert the translated code, but its not. Im getting alot of errors from this
Microsoft (R) Macro Assembler Version 6.14.8444

Copyright (C) Microsoft Corp 1981-1997. All rights reserved.

Assembling: D:\masm32\_ACTIVE\oop\Mo100\Test.asm
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(1) : error A2008: syntax error : DataClass
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(6) : error A2008: syntax error : *
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(12) : error A2008: syntax error : private
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(17) : error A2008: syntax error : DataClass
D:\masm32\_ACTIVE\oop\Mo100\ocode.asm(5) : error A2008: syntax error : ebx
D:\masm32\_ACTIVE\oop\Mo100\ocode.asm(8) : error A2008: syntax error : .delete
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(24) : error A2020: identifier not a record : _this
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(34) : error A2020: identifier not a record : _this
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(44) : error A2020: identifier not a record : _this
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(54) : error A2020: identifier not a record : _this
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(64) : error A2020: identifier not a record : _this
D:\masm32\_ACTIVE\oop\Mo100\OOP.inc(73) : error A2020: identifier not a record : _this
_
Assembly Error


If you have a simple, start to finish, example it would be appreciated. Thanx.

PS: Oh by the way i altered your preprocessor.inc slightly to add:
ifndef PREPROCESSOR_INC

Option DOTNAME
.data


At the beginning. As well im not sure your "sizeof Class/4" at the init macro will work in all cases. If for any reason your class is not integer multiples of 4 in length it will not copy the last of the init data. (This can easily be done by adding a word or byte data member).

:NaN:
Posted on 2003-05-04 22:56:51 by NaN
Finally figured it out and got it to compile with masm!

But i discovered a bug along the way.

The "include" directive parsing. What is happening is im including a standard set of macros i use, one of which is the INCHRD macro that takes variable arguments and includes them one at a time. The macro is defined:
INCHDR MACRO arg1:REQ, arg2:=<>, arg3:=<>, arg4:=<>, arg5:=<>, arg6:=<>, arg7:=<>, arg8:=<>, arg9:=<>, arg0:=<>

@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg1>,<.inc> )
ifnb <arg2>
@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg2>,<.inc> )
endif
ifnb <arg3>
@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg3>,<.inc> )
endif
ifnb <arg4>
@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg4>,<.inc> )
endif
ifnb <arg5>
@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg5>,<.inc> )
endif
ifnb <arg6>
@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg6>,<.inc> )
endif
ifnb <arg7>
@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg7>,<.inc> )
endif
ifnb <arg8>
@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg8>,<.inc> )
endif
ifnb <arg9>
@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg9>,<.inc> )
endif
ifnb <arg0>
@CatStr( <include >,%MASM_Inc_Path,<\include\>,<&arg0>,<.inc> )
endif
ENDM


This itself has the key word "include" within it! The pre-processor is getting hung up on this trying to include these and giving me errors. I tried simply commenting it out and uncommenting after pre-processsing. This works, except the preprocessor ignors all comments. So to get around this, I've been placeing an "A" infront of the work "include" to fool the preprocessor.

As well, it would be nice to see the outputs code with comments, as well as their origional line spacing (asthetics i realize ~ but feedback none the less ;) )

PS: I have since realized my mistake with the "-i:" param field, and have totaly abandoned the OCode.asm file and inserted the .new and .destroy directly into the test.asm file (posted previously).

:alright:
NaN
Posted on 2003-05-04 23:18:18 by NaN
NaN

Well it's official, I stink at explaining things :grin:

OK let's take this one step at a time shall we, assume the following

- include directory is \MASM\INC
- output directory is \MASM\OUT
- source directory is \MASM\SRC

Starting in the source directory we call the preprocessor to process our code using the following commandline



mo -i:\MASM\INC -o:\MASM\OUT *.asm


Now, if all goes well our code has been processed and ALL processed files are in the output directory.
Now we compile the code in the output directory and if murphy isn't looking we should have an EXE/DLL/LIB whatever.
The preprocessor will process ALL files defined on the commandline and in the code ( includes ). You don't have to process only the files that contain OOP code, process EVERYTHING.
I hope thats clarified things, but if it doesn't email me and I'll send you a test proggy.

With reference to the new macro, I agree, but you're free to modify this macro and I only wanted to supply something simple to start with. Currently I have mine calling custom AllocateObject/FreeObject functions which tell me if I've forgotten to release any objects. Leaving comments in the output can be done easily, but I'll have to change some code to allow the formatting, I'll see what I can do.

i discovered a bug along the way. The "include" directive parsing

Ah, keywords inside macros, didn't think of that. Should be able to fix that fairly easily if I watch for the MACRO/ENDM keywords.
Do you think this might also be a probem with EQUs?

I also found a bug, the following will not work



CBLAH class

Destructor* proto _this:DWORD

CBLAH endc


The underscore in _this makes the preprocessor spit the dummy on any method proto.

Now I've noticed that both you and bitRAKE are naming the THIS ptr ( _this ), you can name it anything you like.

Maelstrom
Posted on 2003-05-05 00:48:54 by Maelstrom
Thanks, im sorry to be badgering you on this. I did figure that out last night from your previous posts (but is nice to see it clearly now ;) )

My problem is im getting this error:

warning - oop.inc ( line 25 ) member not found

From a command line preprocess:

mo -i:\masm32\include -o:.\out test.asm

Here is the Test.asm
.386

.model flat,stdcall
option casemap:none

ainclude D:\masm32\include\_Macros_.inc
INCPATH D:\masm32
INCHDR windows, kernel32, user32, masm32, shell32, gdi32, debug
INCLIB kernel32, user32, masm32, shell32, gdi32, debug

include preprocessor.inc
include oop.inc

.code
start:
push ebx

.new ebx, DataClass::Obj

.delete Obj

pop ebx
invoke ExitProcess, NULL

end start
end
And here is the OOP.INC
	DataClass class


Data1 dd 0 ; Data value 1
Data2 dd 20 ; Data value 2

Destructor* proto lpThis:DWORD
GetData1 PROTO lpThis:DWORD
GetData2 PROTO lpThis:DWORD
SetData1 PROTO lpThis:DWORD, mydata:DWORD
SetData2 PROTO lpThis:DWORD, mydata:DWORD

private

AddData PROTO lpThis:DWORD
Data3 dd 0

DataClass endc

DataClass segment

GetData1 proc USES ebx edi esi _this:DWORD

mov ebx, _this <@CurClass::Da>
[color=red][size=18][b] mov eax, Da.Data1[/b][/size][/color]

ret
GetData1 endp




GetData2 proc USES ebx edi esi _this:DWORD

mov ebx, _this <@CurClass::Da>
mov eax, Da.Data2
ret
GetData2 endp




SetData1 proc USES ebx edi esi _this:DWORD, mydata:DWORD

mov ebx, _this <@CurClass::Da>
mov eax, mydata
mov Da.Data1, eax
ret
SetData1 endp




SetData2 proc USES ebx edi esi _this:DWORD, mydata:DWORD

mov ebx, _this <@CurClass::Da>
mov eax, mydata
mov Da.Data2, eax
ret
SetData2 endp




AddData proc USES ebx edi esi _this:DWORD

mov ebx, _this <@CurClass::Data>

ret
AddData endp



Destructor proc USES ebx edi esi _this:DWORD

mov ebx, _this <@CurClass::Data>

ret
Destructor endp

DataClass ends
I have BOLDED line 25 for you above. Its not recognizing the label I have assigned. Or im misunderstanding how to use this assignment scheme... can you correct me here??

PS: I think i found another bug. You can not do this:
SetData1 proc USES ebx edi esi _this:DWORD, data:DWORD.
It will replace it with:
SetData1 proc USES ebx edi esi _this:DWORD, ebx:DWORD. This generates a compile error (obviously) ;) .


:alright:
NaN
Posted on 2003-05-05 16:53:19 by NaN
NaN

Badger away, I don't mind at all :)

I should have picked this up earlier but when defining data inside the CLASS/ENDC block you must prefix the data names with an underscore.
The preprocessor uses the underscore to tell the difference between data and methods.
The underscore does not become part of the data name but if you do want to start your data names with an underscore, simply prefix two underscores.



Data1 dd 0 ; Data value 1
Data2 dd 20 ; Data value 2

; should be

_Data1 dd 0
_Data2 dd 20

; use two underscores to add an underscore to the data name

__Data1 dd 0
__Data2 dd 20


PS: I think i found another bug.

Nuts, it's processing the line before I flush the symbols from the previous method, I'll look into it :alright:

Maelstrom
Posted on 2003-05-05 17:56:38 by Maelstrom
Nice! Now im getting somewhere ;)

Thanx! I remember reading about the underscore but i thought it applied for special protected modes... i didnt realize it was for all cases! Thanx!

I look forward to playing around with inheritance now ;)

I wonder if my stupidity will find another bug :tongue: . Now that i its OOP'n i have to say its pretty cool! Will have more to say shortly ;)

Thanx for the assistance..
:alright:
NaN
Posted on 2003-05-05 19:26:57 by NaN