ABCD
1

BOB'S projects with ESP32forth
2
WORD STACKCOMMENTS
3
4
MINI-OOF by Bernd Paysan 1998 adapted by Bob Edwards 24th July 2021Mini Object Oriented Forth is a powerful tool to help you turn esp32forth into an application specific language, reducing coding time and making for easier maintenance. However, use it only when a more simple and elegant solution eludes you. Always write the simplest code that works for the here and now
5
6
DEFINED? *MINI-OOF* [IF] forget *MINI-OOF* [THEN]
: *MINI-OOF* ;
If MINI-OOF was previously compiled, remove it before recompiling

7
8
\ Words missing from the esp32forth system
9
10
: NOOP ;do nothing - a place holder for the vector table overwritten later by a method xt
11
: /STRING
DUP >R -
SWAP R> +
SWAP
;
( addr1 cnt1 n --
addr2 cnt2 )


remove n chars from the front of a counted string or memory block


12
13
\ The object oriented extensions
14
15
: METHOD
CREATE
OVER , SWAP
CELL+ SWAP
DOES>
@ OVER @ +
@ EXECUTE
;
( m v -- m' v )




( .. o -- ... )




During method declaration, the number of methods and instance variables is on the stack (in address units). method creates one method and increments the method number. To execute a method, it takes the object, fetches the vector table pointer, adds the offset, and executes the execution token stored there. Each method takes the object it is invoked from as top of stack parameter. The method itself should consume that object.


16
: VAR
CREATE
OVER , +
DOES>
@ +
;
( m v size -- )


( o -- addr )


Same as above, a word is created with the current offset. Instance variables can have different sizes (cells, floats, doubles, chars), so all we do is take the size and add it to the offset. If your machine has alignment restrictions, put the proper aligned or faligned before the variable, it will adjust the variable offset. That's why it is on the top of stack.

17
: CLASS
DUP
2@ SWAP ;
( class -- class methods vars )
A CLASS definition (recipe for cloning OBJECTS that can store data and run class specific code) is started with this word
18
: END-CLASS
CREATE
HERE >R
, DUP ,
2 CELLS ?DO
['] NOOP ,
1 CELLS +LOOP
CELL+ DUP CELL+ R>
ROT
@
2 CELLS
/STRING
CMOVE
;
( CLASS totalMETHODspace totalVARspace "name" -- )








Now, for inheritance, the vector table of the parent object has to be copied, when a new, derived class is declared. This gives all the methods of the parent class, which can be overridden (different methods substituted), if required





First we create the vector table, initialized with noops. Then the words starting CELL+ DUP CELL+ ... is the inheritance mechanism, it copies the execution tokens from the parent vector table





19
: DEFINES
' >BODY @ + !
;
( xt class -- )

This allows to define new METHODS - actions that OBJECTS made from the CLASS can do

20
: NEW
HERE OVER @ ALLOT
SWAP OVER !
;
( class -- o )


This word is used to create new OBJECTS ( named clones that can be run ) of the required CLASS


21
: ::
' >BODY @ + @ ,
;
( class "name" -- )

And sometimes derived classes want to access the method of the parent object. There are two ways to achieve this with this OOF: first, you could use named words, and second, you could look up the vtable of the parent object.
22
CREATE OBJECT
1 cells , 2 cells ,
( -- )
We need a starting point (the empty object from which all other classes arise)
23
24
25
\ Example MINI-OOF code
26
27
object class
cell var teeth#
cell var height
method speak
method greet
method walk
method add.
end-class pet
( -- )




CREATE ... DOES> are very useful. They allow us to clone our own arrays, lists, queues, stacks and all manner of simple objects - as many as we want. HOWEVER, each object only does one thing - e.g. when an array word is executed, the start address is returned on the stack.

A CLASS is an extension of a CREATE ... DOES> word. You can see there are two 'var' declared to store data (each var can have more space e.g. 3 cells var myarray). Also declared are a number of METHODS or things that this class can do. What the METHODS actually do is defined next

This is just a recipe for creating one or more OBJECTS of type 'pet'. It isn't directly executed, so don't try doing that!
28
:noname ." pet speaks" drop ; pet defines speak
:noname ." pet greets" drop ; pet defines greet
:noname ." pet walks" drop ; pet defines walk
:noname drop + ." n1 + n2 = " . ; pet defines add.
( n1 n2 -- )OK - these words define what each method actually does.

Notice that method 'add.' takes in two parameters from the stack

Why are we dropping something in each method? Well - when a method executes, a reference to the particular pet we wish to operate on is top of the data stack. By convention we're supposed to remove that from the stack during execution of a method


We've completely defined CLASS pet. Remember we still can't run anything yet
29
pet class
method happy
end-class cat
( -- )

Suppose we have a variation on pet that we wish to make: Class 'cat' does slightly more than a pet can do.

We define the extra method 'happy'
30
:noname ." cat purrs" drop ; cat defines happy( -- )
And here we define what 'happy' will actually do in a cat object

Again, just another recipe - we still can't run anything
31
:noname ." cat says meow" drop ; cat defines speak
:noname ." cat raises tail" drop ; cat defines greet
( -- )

Here we've decided that the default methods supplied by 'pet' don't suit cat, so we've substituted or overrided those methods with these


32
pet class
end-class dog
( -- )Here's another class of type pet called dog
33
:noname ." dog says wuff" drop ; dog defines speak
:noname ." dog wags tail" drop ; dog defines greet
( -- )


And again, dogs do something different than pets for these methods NB you don't have to override all methods - that's up to you to suit the application

34
cat new constant tibby
dog new constant fido
( -- )
OK, at last we've created two actual pets as OBJECTS or INSTANCES of classes cat and dog - we can make these execute their methods, read and write their data and so on
35
20 tibby teeth# !
30 fido teeth# !
50 tibby height !
75 fido height !
( -- )

Here we are setting vars in our two objects Notice the syntax is:

<data> <objectname> <varname> !

varname adds an offset to objectname to form the address to store our data
36
tibby teeth# @ . cr
fido height @ . cr
( -- )
And this is the opposite, we're reading data from the two objects. The syntax is <objectname> <varname> @
37
tibby greet
fido speak
tibby speak
( -- )
Here, we're getting the two pets to do stuff - it'll just display the message defined in each method in our simple demo

Notice how the word 'speak' does different things dependent on which pet is referenced. Reuse of words cuts the number that the programmer has to make up or remember. No more catspeak and dogspeak type of words needed
38
34 56 fido add.( n1 n2 -- )Our pets are pretty smart - here's fido adding two numbers, that we've place on the stack ready for that method. It could also leave stuff on the stack if that were required
39
tibby walk( -- )Notice that cat ( and dog ) have INHERITED all of pet's methods. 'walk' wasn't overidden, so both dog and cat know how to walk
40
41
\ The above packs quite a lot of punch for very little code space
42
\ and may make all the difference to an otherwise awkward-to-code job
43
\ Bernd Paysans Mini-OOF pages
44
\ An extension to Mini-OOF by Gerry Jackson might also be interesting