Im still playing with it, but as bitRAKE had put it, this is "sweet" :alright:

I have one suggestion that i think you should consider:

By the very nature of the preprocessing, you end up with "true" masm code files that more or less is ment to be compiled, but not viewed and edited explicitly.

You should provide an option (perhaps a command line switch) to make two output files such that objects can be created as, well, objects (obj's). This will make dll libraries, and static libraries easy to build.

This can be easily achieved with a modification to your existing "preprocessor.inc" file:
ifndef PREPROCESSOR_INC


ifdef OOP_MODEL
.386
.model flat,stdcall
option casemap:none
endif
option DOTNAME
.data

PREPROCESSOR_INC = 1
[b]. . .[/b]

Like wise the output normally generated by the preprocessor would also include this at the top (before any other output):
OOP_MODEL   EQU  1

include preprocessor.inc


And at the end of the same file place an END statement.

The second file would have the PROTO and any EQUATES found as a include header (or even better a way of assigning PUBLIC equates and PRIVATE EQUATES). Only the public equates should make it to the header.

I tried something like this with my OOP model, but never got it really off the ground. It was working, but i didnt make much effort to promote it... (at the time i was busy enough just trying to get people's heads willing to even consider OOP ;) ).

However, from what im seeing here with your model, your really close to being able to rapidly build robust and reusable *.OBJ's for linking into other projects. (I can do this now, but it requires the above manual modifications per OOP Class file).

One last comment. I want to be clear here that this idea should be an extra feature option, not to replace the current mode of operation. This will allow it to be flexible for both coding styles that people tend to use.

Anywho, think about it ;) . If you like and need help, i would be happy to assist you.
:alright:
NaN
Posted on 2003-05-05 20:37:22 by NaN
Can your model suport Interfaces?

ie. Inherit a class of virtural members? Im still fiddling, but im not 100% on format of inheritance and, nor virtual members... (forgive me if I seem slow on the learning curve here)..

:NaN:
Posted on 2003-05-05 22:18:26 by NaN
NaN

Glad you like it :alright:

Now it's my turn to be :confused: I'm sorta with you but not quite :grin:

Do you put the class definition and methods in the same file and want them seperated automatically?
I write my objects with an include and source file so compiling OBJs is easy.

Can your model suport Interfaces?



CFOO_1 class

_data1 dd 0

Destructor* proto :DWORD

Method0 proto :DWORD ; static method
Method1* proto :DWORD ; virtual method
Method2 proto :DWORD = 0 ; abstract method

CFOO_1 endc

CFOO_2 class CFOO_1 ; inherit CFOO_1

_data2 dd 0

Destructor* proto :DWORD ; overload CFOO_1 destructor

Method0 proto :DWORD ; overload CFOO_1 static method
Method1* proto :DWORD ; overload CFOO_1 virtual method
Method2* proto :DWORD ; overload CFOO_1 abstract method

CFOO_2 endc


The above demonstrates inheritance as supported by the preprocessor. Defining a method with the same name as a method in the base class will overload that method.
I hope this is what you meant.

Destructors are a special case, the base class ( CFOO_1 ) must have one but derived classes only need overload the destructor if it's needed.
Like the destructor, if you are deriving a new class and the base class has virtual methods you don't need to overload them unless it's needed.

Maelstrom
Posted on 2003-05-06 01:24:33 by Maelstrom
Thanx...

What i was tyring to get at is the ability to use "MO.EXE" as an obj builder as well. I tend to use the tree style including method when i code (i.e. one file includes a bunch of other files. etc.). So all i have to do to recompile is assemble one master file. Because of this structure, i can only have one instance of .386 and model directive (at the top of the master file).

Any OOP classes i build in this structure can not have these directives in them or an assembler error will result. This is fine for such projects, and is often how i develope, cause its fast to do R&D in the design and testing of classes.

However, if i decide through this method i finally have my CFILE.ASM OOP class file perfected, and working properly it would be nice to take the same file (without modifying its source to isolate it as a separate assembly model) pass it to your MO.EXE and have it insert the model info on the generated output. This will keep the source file untouched, but the preprocessed output will have the additional requirements for stand-alone assembly.

If you preprocessor can do this, its trivial to make a batch file to put it all together (ie. MO.EXE Class.asm, then ML.EXE Class_special.asm in the preprocessed output directory, then run LIB to take the OBJ and make a LIB file out of it. If your preprocessor can also splits out the PROTO's and EQU's in a separate "Class_special.inc" as well, i would have everything nicely packaged and ready for future use. All from one batch file, from when my R&D into an OOP class has finished, and eventually is taken from its "test bench coding model" and isolated and processed into a standalown, linkable, library file.

I hope this clears things up a bit...


As for the intefaces, thank i will play around tonight with what you have provided. I guess my bigest problem is I've been in the land of ASM too long. I forget the TRUE purpose for such catch phrases as "virtual" and "abstract".. Im wondering how they are to be used proberly under your model.

If i remeber correctly, Abstract is the Interface command. I.e., no code proc to go along with the class definition. Anything that inherits an Abstract method, but provide code for it, before it can be instanciated.

As for virtual?? Im a bit lost seing the difference between virtual and abstrace at the moment. I always thought virtual is more of a memory organization formatting more than an OOP construct. But i could be wrong here....


Anyways, thanks for your help... im going to play some more with it tonight!

:alright:
NaN
Posted on 2003-05-06 11:52:53 by NaN

As for virtual?? Im a bit lost seing the difference between virtual and abstrace at the moment. I always thought virtual is more of a memory organization formatting more than an OOP construct. But i could be wrong here....

Virtual means it is/can be defined in a child class, and that you can use parent interface to deal with a child object. Without virtual, you have an "invariant over inheritance" - both interface and implementation stays the same.

Or well, that's how it works in C++ - I dunno if it's generic OOP lingo.
Posted on 2003-05-06 12:12:46 by f0dder
NaN

I see where your coming from now. I use a similar style myself but if I know it's going to be reused I compile it to a lib and link to a test proggy to debug it. Your suggestion would make testing and debugging much faster - I'll definitely look into it :alright:

Virtual methods are simply pointers to a specific class method. As f0dder mentioned they allow you to access derived classes by using the base class. Since virtual methods are pointers, the method that's invoked is determined by the object the THIS ptr references.



CFOO_BASE class

Method* proto :DWORD

CFOO_BASE endc

CFOO class CFOO_BASE

Method* proto :DWORD

CFOO endc

SomeFunct proc USES ebx edi esi _object

; lets assume _object is a pointer to a CFOO object

mov esi, _object <CFOO_BASE::foo>

invoke foo.Method ; this invokes CFOO::Method

.superclass foo.Method ; this invokes CFOO_BASE::Method

.ret

SomeFunct endp



Abstract methods are simply virtual methods that have no method associated with them. ie They are null pointers and need to be overloaded by a derived class.

An example could be a CRENDER class that defines its methods as abstract. Now from CRENDER you derive COPENGL & CD3D which overloads the CRENDER methods with code specific for each API.
Now it doesn't matter if you create a COPENGL or CD3D object, if you access the object as a CRENDER object the appropriate method will be called.
This polymorphic behaviour gives you a common interface to a group of classes derived from a common base class.

I'm not sure if my lingo is correct but it sounds good :grin:

Note
The preprocessor will allow you to instance classes with abstract methods.

Maelstrom
Posted on 2003-05-06 18:39:10 by Maelstrom
Thanks for the Primer.. thats the stuff i need (i got all this jazz in my head.. just dont know what to call it ;) ~ like i said, i think I've been doing the ASM route too long ;) )

Thanks again!

I was thinking today about my suggestion (to make obj's). You would probably need to provide the class structure as well in the include header file (which would compliment the obj/lib). Im not sure how your preprocessor works internally, but to be able to reuse these objects in Lib's the preprocessor would need to somehow know just "what" your instanciating, and calling methods on. Or does it even care??? Perhaps it works blindly, and trusts the linker to sort such things out....
Hmmm... I will have to do some tests....

Anywho.. this is slowly growing on me, but its looking very impressive so far. (im going to have to change my bat files ;)

:alright:
:NaN:
Posted on 2003-05-06 19:13:43 by NaN
NaN

You can never do too much ASM ;)

You would probably need to provide the class structure as well in the include header file

No.

Lets assume the preprocessor adds the necessary compiler directives to the output file. If we define our class in a single file, the processed output should contain everything required to compile the object as an OBJ. However, to use the object in a program we must include the original class definition ( CLASS/ENDC ) so the preprocessor knows how to use the object. I could have the preprocessor automatically extract the class definition and create an include file in the include directory specified on the commandline. Obviously, if we use a seperate include file for our class definition then this doesn't matter.

Did that ramble make sense :grin:

Anywho.. this is slowly growing on me

Just wait until I get templates and cloning working.
I'd also like to see if I can get the preprocessor to support COM.

Maelstrom
Posted on 2003-05-06 22:17:57 by Maelstrom
Now your talking ;)


I noticed that there is no error checking for abstract method calls. (I think you eluded to this earlier). You might want to think about that... The preprocessor should have stoped me and said "hey, no fucntion to call pal! ~ Like you, its abstract!"... or something similar ;)

:alright:
:NaN:
Posted on 2003-05-06 22:40:40 by NaN
I managed to package a class into a lib tonight. I dont know what you have been doing, but here is what i did (and my thoughts ;) ):

My OOP Class:
[b]   Math  class

_Result dd 0

Destructor* PROTO lpThis:DWORD
Constructor PROTO lpThis:DWORD
Add_ PROTO lpThis:DWORD, val:DWORD
Sub_ PROTO lpThis:DWORD, val:DWORD
Mul_ PROTO lpThis:DWORD, val:DWORD = 0
Div_ PROTO lpThis:DWORD, val:DWORD = 0

Math endc[/b]

Math SEGMENT
Constructor proc USES ebx edi esi _this:DWORD
mov ebx, _this <@CurClass::Math>
xor eax, eax
mov Math.Result, eax
invoke Beep, 0,0
ret
Constructor endp

Add_ proc USES ebx edi esi _this:DWORD, val:DWORD
mov ebx, _this <@CurClass::Math>
mov eax, Math.Result
add eax, val
mov Math.Result, eax
ret
Add_ ENDP

Sub_ proc USES ebx edi esi _this:DWORD, val:DWORD
mov ebx, _this <@CurClass::Math>
mov eax, Math.Result
sub eax, val
mov Math.Result, eax
ret
Sub_ ENDP

Destructor proc USES ebx edi esi _this:DWORD
ret
Destructor endp

Math ENDS

[b]MoreMath class Math

Destructor* PROTO lpThis:DWORD
Mul_ PROTO lpThis:DWORD, val:DWORD
Div_ PROTO lpThis:DWORD, val:DWORD

MoreMath endc[/b]

MoreMath SEGMENT

Mul_ proc USES ebx edi esi _this:DWORD, val:DWORD
mov ebx, _this <@CurClass::Math>
mov eax, Math.Result
imul eax, val
mov Math.Result, eax
ret
Mul_ ENDP

Div_ proc USES ebx edi esi _this:DWORD, val:DWORD
ret
Div_ ENDP

Destructor proc USES ebx edi esi _this:DWORD
ret
Destructor endp

MoreMath ENDS


I preprocessed this file with a test file (as discussed), and manually added the statements "OOP_MODEL EQU 1; Include Preprocessor.inc", which drived the following additions to preprocessor.inc:
ifndef PREPROCESSOR_INC


ifdef OOP_MODEL
.386
.model flat,stdcall
option casemap:none
endif
option DOTNAME
.data

PREPROCESSOR_INC = 1
. . .


But i discovered some problems when i tried to compile. I used an API "BEEP" from Kerner32. So i had to also include this to get an OBJ from this file. I thought about this and wondered how you can do this with your tool in an automated sorta way. I came to the concusion that you can't, with reliability. People code in different ways, it would be a nightmare to assume all cases and gather all needed include and includelibs from a master template system.

The alternate is to simply modify the above to include ALL typical includes and includelib's you would use. You would simply place them between the ifdef and endif statements. If you dont want people fussing around here you can even put a macro call there, and define the macro elsewhere. This way you can get a 97% assurance it will work reliably for most code. Only the specialty includes will require extra work, but this should be in the source to begin with if its that special ;)


After i compiled it, and got my OBJ, i made a LIB outa it (LIB /OUT:atest.lib math.obj). I then wrote a completely new test scenario with no class includes, but the atest.lib):
.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
includelib atest.lib

[b] Math class[/b]
_Result dd 0

Destructor* PROTO lpThis:DWORD
Constructor PROTO lpThis:DWORD
Add_ PROTO lpThis:DWORD, val:DWORD
Sub_ PROTO lpThis:DWORD, val:DWORD
Mul_ PROTO lpThis:DWORD, val:DWORD = 0
Div_ PROTO lpThis:DWORD, val:DWORD = 0

[b] Math endc[/b]

[b] MoreMath class Math[/b]

Destructor* PROTO lpThis:DWORD
Mul_ PROTO lpThis:DWORD, val:DWORD
Div_ PROTO lpThis:DWORD, val:DWORD

[b] MoreMath endc[/b]

.code
start:
push ebx

.new ebx, MoreMath::Obj
PrintDec Obj.Result
invoke Obj.Add_, 12
PrintDec Obj.Result
invoke Obj.Sub_, 6
PrintDec Obj.Result
invoke Obj.Mul_, 3
PrintDec Obj.Result
.delete Obj

pop ebx
invoke ExitProcess, NULL

end start
end


From trial and error i discovered your MO.EXE *wants* to see only the pre-compiled version of the class definitions to work. Non of the output stuff would work. Which is great actually, since you need to provide less info as an include file! Once i figured this out, preprocessed this, and compiled/assembled it. It worked perfectly.

So to do my sugestion would only take:

    [*]Get the unaltered class definitions (Class/Endc) and dump them to an output include file
    [*]Get all supporting Equates/stuctures and dump them to an output include file (should devise a way of declairing them as public or not ~ but not essential)
    [*]Precompile and insert header lines: "OOP_MODEL EQU 1; Include Preprocessor.inc", and end of file line "END".


    From here ML should be able to compile the ASM output file into an OJB (via batch file) and optionally make it into a LIB as well. The final LIB output will work hand in hand with the include file generated. And viola! all is well!

    This is a small scoped test. I think i would also be wise to place ifdef/endif statements around all class definitions that are copied to the include file. (To get around wierd scenarios where inheritance is happening).


    Anywho, i konw this is getting a bit long, but i wanted to post my findings here. I have to say im growing very impressed with its ease of use. I just have to think up a worthing project to really sink my teeth into it ;)

    Great work!
    :alright:
    NaN
Posted on 2003-05-06 23:46:42 by NaN
NaN

You've been reading my mind haven't you :grin:
I thought about using a macro to add the compiler settings, this way users could customize it to there needs.
It could work like you INCHDR macro, place common includes inside the macro and pass any special includes to the macro.

I noticed that there is no error checking for abstract method calls

I was in two minds about this. I wanted to use abstract methods to create interface classes but I also wanted to be able to use them as user defined methods. For example you could pass a pointer to a function as a param to a class method and have the method set the abstract pointer. You could then call the function as if it was a class method.
Do you think this should be allowed, or should we stick to abstract overloading via inheritance?

I have a question for ya, do you think something like the object generator you wrote for your OOP model would be useful here?
For example, if the preprocessor is run without arguments it opens a dialog something like your object generator and outputs the file skeleton for you to fill out?

I'm also trying to reorganize my includes so that I can post compilable examples.

Maelstrom
Posted on 2003-05-07 01:36:47 by Maelstrom
I would keep your MO.EXE separate from any *tools* you decide to implement. To be honest, im not overly keen even on the GUI dialog box that reports errors. It doesn't lend well to IDE's (or high level text editors).

This is one of the big assets in the MASM package. (all the command line executables). I would aim for a similar approach here.


As for abstract methods... I would still implement error checking... If a person wanted to cast non-method functions to an abstract structure entry, they sould instead have the class itself store the pointer and implement the call for you (internally ~ not externally as you have suggested).

Anywho these are my thoughts... the topic is open to debate ;)

:alright:
NaN
Posted on 2003-05-07 11:55:21 by NaN
If im not assinging EBX to <@CurClass::Whatever> but rather to another object type, how would i do it? Here is my guess (and outline of what im getting at):


FOO Class
_lpObj dd 0 ; Foobar class pointer
funt PROTO lpTHis:DWORD
FOO ENDC

FOO SEGMENT
funt PROC USES EBX lpThis:DWORD
mov ebx, lpThis <@CurrClass::Foo>
mov eax, Foo.lpObj

mov ebx, eax <@Foobar::Foobar>
invoke Foobar.OutaClassMethod
ret
funct ENDP

FOO ENDS


Can i do this? If not, what is the proper way of telling the preprocessor that im actually invoking another object other than the current segment type object.

Thanx!
:alright:
NaN
Posted on 2003-05-07 20:16:54 by NaN
NaN

Simply replace @CurClass with the class name.



; lets assume _lpObj is a pointer to a CFILE object

mov ebx, _this<@CurClass::foo>

mov ebx, foo._lpObj <CFILE::foobar>


Have you tried embedded objects yet?
The preprocessor gives you direct access to embedded objects.
Embedded objects work the same as embedded structures.



CFILE class

__handle dd 0

Open proto :DWORD, :DWORD

CFILE endc

CBLAH class

__file CFILE <> ; embed a CFILE object

CBLAH endc

mov ebx, _this <CBLAH::blah>

invoke [b]blah._file.Open[/b], addr m_fileName

mov edx, [b]blah._file._handle[/b]


Maelstrom
Posted on 2003-05-07 22:49:47 by Maelstrom
No i havent, not in that fashion anyways...

I accidently found some C++ source that would make an excellent starting point to really test your model with. ( http://sequence.rutgers.edu/sequitur/ ) See the C++ example after playing with its neat interface...

The source looks rather simple to translate. Im approximately 70% finished. Perhaps tomorrow i will get a test compile.. This is where and why i posted the above question. It has two main classes, where one is often called from the other.

Thanx!
:alright:
NaN
Posted on 2003-05-07 23:07:29 by NaN
Nan

It will be interesting to see how well the preprocessor can port C++.

Maelstrom
Posted on 2003-05-08 16:27:11 by Maelstrom
Its going a bit slower now.. im getting into thicker C++ stuff...

Its really the **Var stuf that is screwing with my head. (I once knew and understood all this ~ but since threw it all away when i came to ASM since i realized its all B.S. anyways)

I have to "comiple" these symbols into the reality of ASM. :rolleyes:

As well, im getting some wierd calls and stuff that might really challenge your model... i will point them out when im done tho... (im nervous if it will compile/work as it should)..

:alright:
NaN
Posted on 2003-05-08 22:43:08 by NaN
NaN

How's the translation going?
Lost much sanity working with the pointer indirection?

Maelstrom
Posted on 2003-05-10 17:23:20 by Maelstrom
I've stepped back from it to understand it a bit more...

I also dont like some of the translations im doing, cause they are very inefficient. Im not sure of the limits of your preprocessor as well as if im actaully translating correctly. Having two unkowns at once is bothering me a bit....

:NaN:
Posted on 2003-05-10 17:30:40 by NaN
NaN

Fair enough, but we can only find the preprocessors limit if we push it into mental meltdown :grin:

Trying to OOP the preprocessor has been an interesting exercise since I haven't written many OOP programs, but so far so good.

I'll need your help later to see if I can add COM support since I don't know much about it.

P.S - Thanks for the mental picture of Shrek in a thong :eek:

Maelstrom
Posted on 2003-05-10 17:58:12 by Maelstrom