CIAO is an OOP package modelled on C++ for VFX Forth. CIAO is designed to provide easy interfacing to host operating system structures that are built around a C++ model.
The source code for CIAO is in the Lib\oop\Ciao directory, as are several example class files. To rebuild CIAO, compile the file ciao.bld.
Various utilities and factors useful for parsing text.
buffer: token-buffer
A Memory buffer used to hold the result of the last token parse.
The size of this buffer comes from the environement variable
MAX-CHAR and is MAX-CHAR + 1 characters in length since the string
is stored as a counted string.
: new-word \ char -- $
This is a replacement for WORD which places the output in the
token buffer.
: peek-token \ -- c-addr u
Copy the next token into the TOKEN-BUFFER without permanent change
to the input specification (uses SAVE-INPUT and RESTORE-INPUT).
Returns TOKEN-BUFFER as a c-addr u pair.
: drop-token \ --
Throw away the next token *without* corrupting TOKEN-BUFFER.
: ciao-token \ -- c-addr u
Grab the next space delimited token and return c-addr u. Fills
TOKEN-BUFFER.
: bracketed? \ c-addr u -- flag
Is the string C-ADDR U bracketed?
The heart of this OOP implementation is the concept of "THIS". Just like C++ "THIS" returns the currently active object instance pointer. Instance data is accessed via this pointer as are the "virtual" methods.
THIS is kept in a form of stack.
: >this \ val --
Set THIS to VAL. (Preservation is taken care of in the compiler.)
: this \ -- instance-pointer
Return the current instance pointer. Only valid within a method
declaration.
SCOPE_PUBLIC Value CurrentScope \ -- n
When defining a derived class this holds the scoping type employed.
0 Value CurrentClass \ -- n
When defining a class this points to its CLASS structure.
0 Value DefFlags \ -- n
The declaration flags to be employed by the next method or data
member defined in the current class. Records information from
control definitions such as VIRTUAL and STATIC.
0 Value CurrentDefClass \ -- class
During compilation of a code method, this value holds a pointer
to the associated CLASS structure.
0 Value CurrentDefXT \ -- xt
During compilation of a code method, this value holds a pointer to
the XT of the definition. See the CIAO-COLON hook for details.
0 Value CurrentDefList \ -- list
During compilation of a code method, this value holds a pointer to
the internal method list to be used. The list will either be the
classes public, protected or private chain depending on the scope
at the time of the method declaration prototype.
variable class-base-mem \ -- addr
This variable holds the value of HERE after the building of CIAO.
It is used to sanity check the values passed to the instance
destruction definition DELETE. Any passed value between this
variables value and the current HERE is in dictionary space and
must be a static instance which cannot be DELETEd.
: NSEARCH-WORDLIST \ WIDN .. WID1 N C-ADDR U -- XT FLAG | 0
A most useful definition. FIND takes a counted string but searches
the whole search-order. SEARCH-WORDLIST takes a C-ADDR U pair but
only searches one wordlist. This definition combines the two, and
looks through a number of wordlists for a name described by a
C-ADDR U pair. Usually used in association with GET-ORDER to
provide a more useful version of FIND.
: (FindClass) \ c-addr u -- ptr | THROW
Run through the current search-order lookin for the name supplied.
If the name is found then a >BODY @ is employed on the XT to look
for the MAGIC_CLASS identifier. Never called directly, this
definition is run from FINDCLASS via CATCH to protect against the
times when the token is found but is not a class. Due to the
exception handling abilities of CATCH under VFX, this operation
should be safe no matter what XT it is employed against.
: FindClass \ c-addr u -- ptr | ABORTs
Invoke (FINDCLASS) via CATCH. Will look for the token supplied and
if found will ensure it really is a class definition. ABORTs with
text if anything goes wrong.
The Method Lists hold all the required compiler information for each method within a class. In CIAO, methods don't ever actually exist as regular Forth words. Instead the act of defining a class builds the method lists. Each class has three of these, one for each valid scope (public/protected and private).
| Link | Type | Param1 | Param2 | Name Len | Name Text |
| CELL | CELL | CELL | CELL | CHAR | n chars |
Link |
Pointer to start of previous list entry (or 0 for top) |
Type |
The type of the method (see types below) |
Param1 |
Parameter 1, varies depending on TYPE. |
Param2 |
Parameter 2, varies depending on TYPE. |
NameLen |
Length of method name. |
NameText |
The text for the method name. |
Describes an instance data buffer, PARAM1 is the base offset from THIS.
Describes a static data buffer. A static data buffer is placed within the global dictionary rather than being offset from THIS. The net result is that all instances of the owning class and any derived classes share the same location for this data element. PARAM1 is the address in global space of the buffer start.
The default code method type. PARAM1 points to a CELL in global dataspace which will contain the XT of the method body as soon as it becomes available. A CODE method cannot be re-defined or rewritten and it's behaviour is inherited by any derived class.
The second type of code method. It behaves in a similar fashion to TYPE_CODE except the instance pointer THIS is not valid within the method body. These means that a static member has no access to any other member of the class which is non-static. A static member can also be invoked from a colon definition or the interpreter by using the "named scope override" syntax, which does not require an instance pointer. Primarily used to store "normal" functions in a restricted namespace. Ie "do <something> in the name of <some class>"
One of the most useful syntactic additions to C++ was the virtual method. A virtual method can best be described as a method in a base class which you expect to have to modify or replace in a derived class. PARAM1 holds a 0 based index into a table of XTs called a "vtable". Each class has a vtable which in the case of a derived class is initially inherited from the superclass. A derived class can either omit its function body (and thus inherit the behaviour of the superclass) or it can define its own body which can also optionally elect to invoke the superclass's body by using the named scope override syntax. Therefore a virtual method can be either modified or replaced within the context of a derived class. A particularly useful feature of the usefulness of virtual methods can be seen later.
This type of method specifies a static instance of another class as being a part of the current. PARAM1 specifies the class type whilst PARAM2 specifies the offset from THIS for the instance pointer of the contained class.
A special form of data store which holds a pointer to a class instance. PARAM1 specifies the class type and PARAM2 the offset from THIS to a single cell. This cell will hold an instance pointer which can be dynamically assigned.
: list_link \ *entry -- *link
Modify a pointer to a list head to point to the link field.
: list_type \ *entry -- *type
Modify a pointer to a list head to point to the type field.
: list_param1 \ *entry -- *param1
Modify a pointer to a list head to point to the param1 field.
: list_param2 \ *entry -- *param2
Modify a pointer to a list head to point to the param2 field.
: list_namelen \ *entry -- *namelen
Modify a pointer to a list head to point to the namelen field.
: list_name \ *entry -- *name
Modify a pointer to a list head to point to the name field.
: .list-type \ n --
Given contents of a list entry's type field print it's name as an
ascii text string.
: .list-entry \ *entry --
Supplied with a pointer to a list entry this definition will print
its contents in human readable form.
: .list \ *head --
Supplied with the address of a variable which points to a list
entry this definition will walk backwards through the linked list
performing .LIST-ENTRY on each in turn.
: +LIST \ Type Param1 Param2 c-addr u *list-head --
Using the first 5 parameters lay a list-entry structure in the
dictionary and add it to the end of the list whose anchor address
is at the address pointed to by *LIST-HEAD.
Each class has a linked list called the Operator Chain. This list contains the mapping of operator-id number against class method list entry (from above).
An operator structure entry consists of three fields, the link, the operator id number and a method-list pointer.
: oplist_link ;
Given a pointer to an operator structure return pointer to link
: oplist_op# 1 cells + ;
Given a pointer to an operator structure return pointer to op#
: oplist_list 2 cells + ;
Given a pointer to an operator structure return pointer to *list
: .op# \ n --
Where possible print human readable description for operator id N
: .oplist-entry \ *entry
Display an operator structure in human readable form.
: .oplist \ *head --
Given a pointer to the head of an operator chain from a class,
call .OPLIST-ENTRY for each member.
: +OPLIST \ op# *list-entry *head --
Add record to the operator chain anchored at *HEAD
All classes defined have the same structure:
Size Navigation Word Useage
------------------------------------------------------------------
CELL class_magic A magic 32 bit number used
to signify a CLASS structure.
CELL class_super Pointer to parent class for
a derived class object.
CELL class_private Method list anchor for PRIVATE
definitions.
CELL class_protected Method list anchor for PROTECTED
definitions.
CELL class_public Method list anchor for PUBLIC
definitions.
CELL class_opchain Anchor for the operator chain
for this class.
CELL class_sizeidata Size of Instance data required.
CELL class_#vtable Number of entries in the
virtual method table.
CELL class_pvtable Pointer to the virtual method
table.
: .class \ "name" --
Display as much information about the class "name" as possible
in a human readable form.
Definitions used to find a given method within a class.
: FindMethodInClass \ c-addr u *class -- ptr SCOPE | -1
Given a string containing the method name and a pointer to a class
structure, this definition attempts to get the method list entry
for that method. On success a pointer to the method list structure
is returned as well as the SCOPE indicator, if the method does
not exist in the specified class a -1 is returned.
Any code method has a default action assigned when it is prototyped as a debugging aid. Invoking a method for which you have defined no code will give a polite message via ABORT"
: vcrash \ ?? --
Default action for prototyped virtual methods.
: scrash \ ?? --
Default action for prototyped static methods.
: icrash \ ?? --
Default action for prototyped instance methods.
During class definition the scope can be altered. These definitions are used to control/handle scoping.
: public: \ --
During CLASS definition set the current scope to public.
: protected: \ --
During CLASS definition set the current scope to protected.
: private: \ --
During CLASS definition set the current scope to private.
: GetCurrentList \ -- *list-head
Return the method list pointer for the current scope.
In order to reserve characters to provide the syntax for typecasts, scope overrides and method definition certain characters are illegal for method and class names.
Brackets are illegal, since they are used to perform typecasts.
Colon is an illegal character since it is used for scope overrides.
Period (dot) is illegal since it is used for compound invokations.
Star (*) is illegal since it declares an instance pointer.
: ?validname \ c-addr u --
Check the name string supplied is valid for either a class or
name. Causes an ABORT" on failiure.
Methods and instance variables defined in a class can have various attributes, these are controlled by simple indicator words.
: static \ --
Modify the global DEFFLAGS to include the static type.
: virtual \ --
Modify the global DEFFLAGS to include the virtual type.
: post-def \ --
Clear the global DEFFLAGS, called after a member definition to
reset ready for the next member.
These routines are used within a CLASS or STRUCT{ definition to define data members.
: buff: \ size "name" --
Define a data member called "name" of SIZE bytes. By default
instance specific data is created, if the member was modified by
the STATIC keyword, then global space is allocated. STATIC data
members share the same memory location for all instances of the
class and any derived classes.
: cell: \ "name" --
A shortcut for a BUFF: of one cell.
: char: \ "name" --
A shortcut for a BUFF: of one char.
These routines are used within a CLASS or STRUCT{ definition to define methods.
: static-meth: \ "name" --
The action invoked by METH: when the STATIC modifier was present.
Static members have no access to THIS or instance data and like
static data members are shared between all instances of the owning
class and any derived classes.
: virtual-meth: \ "name" --
The action invoked by METH: when the VIRTUAL modifier is in force.
Virtual methods can be given a code definition for a class and
later modified in a derived class.
: instance-meth: \ "name" --
The default action of METH: creates a method associated with that
class.
: meth: \ "name" --
Create a code member (method). Dispatches to one of the above
definitions depending on any applied modifiers.
These routines are used within a CLASS or STRUCT{ definition to define members which are in turn classes.
: inst: \ *class "name" --
Embed an instance of the supplied class under the given "name".
: iptr: \ *class "name" --
Create a typed pointer for the given class inside the current one.
NOT IMPLEMENTED YET!
This code is used to associate an operator with a given method in a class or structure.
: FindClassOperator \ op# *class -- *list-entry true | false
Given an operator ID and a class pointer attempt to locate the
method list entry associated with that id.
: AddOperatorToClass \ op# *list-entry *class --
Routine used to bind a method-list entry to an operator id for
the given class.
: oper: \ "name" --
Attempt to assign the method "name" as the action of the currently
active operator in the current class.
Code to create CLASS definitions.
: derived? \ "text" -- true | "" -- false
A look-ahead parsing definition used as a factor in CLASS to see
if the class name is followed by a " : [<scope>] <name> " string
for defining derived classes.
: derived-scope \ c-addr u -- scope flag
Another parsing definition used by CLASS, after passing the
DERIVED? test the next token is checked for a scope setting. If
the next token is one of "public, protected or private" then the
scope id is returned and a true flag indicating the next token
has been used, otherwise SCOPE_PUBLIC is assumed and a false return
flag tells CLASS that this token is the actual base class name.
: class \ "name [ : [ <scope> ] <super> ]" -- ; Exec: -- ptr
Begin a new class definition called NAME. If the new class is
derived from a base class, the method lists are copied depending
on C++ scoping rules, as is the Instance data size, operator chain
and vtable size.
When a CLASS definition is invoked it can do one of two things:
If invoked within another CLASS definition it will invoke the class
member instance creation (See previous section "Class Method
Prototyping"), at any other time a pointer to the class structure
is returned.
: end-class \ --
Finish the definition of the current CLASS. If this is a derived
class, the vtable from the parent is copied. After that any new
vtable entries have the default crash vector attached.
Under CIAO (like C++) a structure is a class. The only technical difference is that by default, members of a STRUCT{ are public.
STRUCT{ is provided for more syntactic reasons than technical. It is expected that STRUCT{ is used to declare structures consisting entirely of public data mapped in a contiguous manner so it can be be used with operating system supplied structure pointers.
: struct{ \ "name [ : <scope> <super>" -- ; Exec: -- ptr
Begin a new STRUCTure definition. Used in the same fashion as
CLASS.
: } \ --
Terminate a STRUCTure definition. See also END-CLASS.
CIAO overrides the standard Forth : and ; definitions to allow for method definitions. After a class has been defined it is necessary to write the actual code for any methods prototyped within it. CIAO like C++ takes a method name as being in the form
<class>::<method>
: ciao-colon \ "name" -- | "name" -- "name"
The new action of : when CIAO is installed. Pre-parses the name
to see if it contains a double colon. If not then the original
Forth : is called. If a double colon is found the assumption is
that this definition is a method. The first portion (before the ::)
is taken to be a class name and the second portion the member name.
The class is looked up and its *class pointer stored in a global,
then the method name is looked up within that class and it's
method list entry is also stored. Compilation is then triggered by
:NONAME and the XT of this definition kept for use in ;
: ciao-semicolon \ --
The CIAO over-riding action of ; to handle the closing of method
definitions. If the current definition was not a method-def then
only the original ; is invoked. Otherwise ; is invoked and the
XT of the method is patched into the class structure depending
on the method type.
: : \ "name" --
The actual overload of Forth's :
: ; \ --
The actual overload of the base Forth ;
This code is used by the method compiler extension in the Forth interpreter loop. It is a number of definitions used to create strings to pass to EVALUATE.
1024 buffer: CompileBuffer
The buffer used to build strings for EVALUATE.
: ResetCompileBuffer \ --
Resets the COMPILEBUFFER for a new string.
: ciao-evaluate \ c-addr u --
All EVALUATEs for CIAO come through here.
: EvaluateCompileBuffer \ --
Pass the COMPILEBUFFER string to CIAO-EVALUATE.
: $+RCB \ c-addr u --
Append the string in C-ADDR U to the COMPILEBUFFER.
: n+RCB \ n --
Append the ascii representation of the number N to the
COMPILEBUFFER. The string added is in the form "$<hex> "
These definitions handle the compilation of method-list entries depending on type.
: CompileMethod_DATA \ *list-entry --
Compiles code for an Instance Data member. Generates a pointer by
laying code for "THIS <offset> +".
: CompileMethod_STATICDATA \ *list-entry --
Compiles code for a static data member. This is simply a literal
address of the global space.
: CompileMethod_CODE \ *list-entry --
Compiles code for an instance code member. If the member has
already been bound to a definition then the definition XT is compiled
along with execute (i.e. " $<XT> execute " is compiled) otherwise a
pointer to where the XT will be stored is compiled with a @ execute.
: CompileMethod_STATICCODE \ *list-entry --
Compiles code for a static code member. This is a literal address of
where the XT will be and a fetch-execute.
: CompileMethod_VIRTUALCODE \ *list-entry --
Compiles code for a virtual method. It compiles the following code.
$<virtual-method-index> \ the index into the vtable
cells \ convert to vtable offset
this \ Get current instance pointer
cell- @ \ Fetch objects vtable pointer
+ @ \ extract XT from vtable
execute \ and run it
: CompileMethod_CLASS \ *list-entry --
Compile code for a class instance member. This is almost identical
to instance data.
: OperatorProcess \ *class --
Compile code for any current operatortype.
: MethodTokenCompileFromList \ *entry --
The global factor for this section. Given a method-list-entry it
will dispatch to one of the COMPILEMETHOD_xxx definitions depending
on type.
The single-token check is used at the beginning of the Forths token interpret before the normal FIND. This is used to provide some special overrides to single Forth tokens. Namely:
1. If defining a code method, other members of the current class can be invoked simply by name. Therefore when defining a method any single token needs to be looked up in the method table before checking the normal Forth dictionary.
2. A token can be preceeded by :: which enforces that the name is searched for in global name space (the Forth dictionary) regardless. This is usually used to get you out of rule #1. If for instance you are defining a method for a class which has a member called DUMP, simply entering "DUMP" will compile a reference to that member, if you actually want to use the Forth DUMP you would type "::DUMP"
3. A token can consist of a class-name and method name separated by a double-colon. NOT IMPLEMENTED YET!. This should compile a reference to a STATIC member of a class.
: single-token \ c-addr u -- flag
Does the single-token-check operation and returns TRUE if the
token has been processed. If the token should be passed on to
the normal Forth lookup FALSE is returned.
: Process1stToken \ c-addr u -- ap 0 | code-to-throw
Used to handle the first part of a dot-notation compound. The
first 'token' needs to ultimately lay the code generate THIS and
needs to locate the correct class structure pointer that begins
this invocation (called the address-provider).
How the first token is actually translated depends on a number
of rules:
1. If defining a method, the first token may be a class or class pointer member of the current class.
2. If the first token is surrounded by brackets it's a typecast. the name in brackets identifies the address provider whilst the instance pointer is assumed to already be top of the data stack.
3. Next it could be that the first token is a named scope override. (as in rule 3 for single-token) This behaviour is NOT IMPLEMENTED YET! This is generally used for a virtual method in a derived class to invoke the action of the virtual method associated with it's parent.
4. Finally the token can either be a name in global space or a name defined as a LOCAL.
: ciao-hook \ c-addr u -- flag
This code receives a token that has fallen through the Forth
FIND and NUMBER? cycle. If the string does not contain a dot
separator it is not a compound statement and false is returned.
Otherwise the string is split into a heap allocated token buffer
using dot as the delimiter and the following steps taken:
1. If in compile state code is laid to preserve the current THIS.
2. The first token is passed to PROCESS1STTOKEN above to obtain the instance pointer and address provider.
3. NOT IMPLEMENTED YET. The middle tokens should be processed. any of these tokens MUST represent a Class instance or class instance pointer as a member of the current address-provider. Each middle token should compile/execute code to modify THIS and the address provider each time.
4. The Final token is processed according to special rules. It must exist in the name space of the current address provider. If we are defining a method for the current address provider all three scope lists are valid, otherwise the method must be in PUBLIC name space. If successfully located according to scope rules the method entry is passed to METHODTOKENCOMPILEFROMLIST (see earlier) to compile the invokation code for that method and any applicable operator.
5. The code to restore the saved value of THIS is compiled.
CIO can be installed into VFX v4 or v5 onwards.
: ciao-classhook \ caddr len -- flag
The action of CLASSHOOK
when CIAO is installed.
: ciao-undefined \ caddr len --
The action of UNDEFINED
when CIAO is installed.
: +ciao \ --
Install CIAO's system hooks.
: -ciao \ --
Uninstall CIAO's system hooks.
' noop ' noop ' postCiaoText RecType: r:CiaoHook \ -- struct
Contains the three actions for dot parsers.
: rec-CiaoHook \ caddr u -- r:CiaoHook | r:fail
The parser part of the floating point recogniser.
' noop ' noop ' postCiaoText RecType: r:CiaoUndef \ -- struct
Contains the three actions for dot parsers.
: rec-CiaoUndef \ caddr u -- r:CiaoUndef | r:fail
The parser part of the floating point recogniser.
: +ciao \ --
Switch on the CIAO parser.
: -ciao \ --
Switch off the CIAO parser.
: dynamicnew \ *class -- this
The runtime code called for instances created via DNEW. Allocate
a block of heap memory large enough for the 2 control cells
(*class pointer and vtable pointer) followed by the instance data.
The THIS pointer returned is the beginning of the instance data.
: staticnew \ *class "name" -- ; Exec-child: -- this
Create a new instance of class called "name" in the dictionary.
The instance is a child of CREATE which has a body containing
the *CLASS value, a pointer to the instance vtable then the
instance data. At runtime a THIS instance pointer is returned, this
is 2 cells on from the PFA (IE past the vtable.)
Forms the action of NEW when invoked outside of a : definition.
: localnew2 \ *class frame-add --
I apologise unreservedly for this trick. This definition performs
the compile-time tail of local-new. Since LOCALNEW performs a
create..does> I cannot add any compile time tail so I tick this
definition and push it on the return stack! Sorry ;-)
: localnew \ *class "name" --
This definition forms the action of NEW when making a local method.
It hacks into VFX locals to create a new entry on the local frame
and lays the code necessary (in LOCALNEW2) to setup the two
control cells AT RUNTIME. The net result is a very fast and useable
named local instance. Implementors beware, this is the most system
specified piece of code imaginable.
: dnew \ *class -- this
State smart definition to create a new class instance on the heap.
returns a pointer to the instance which can be stored.
A heap allocated instance pointer can be held for as long as
required and does not go "out of scope" until explicitly removed
with DELETE. Use this type to create a dynamic instance which you
can safely return from a method/colon definition. Note that unlike
in C++ you must use DNEW in CIAO for heap allocation.
: new \ *class "name" --
A state smart definition to create a named instance of a class.
When used within a : definition the object is created in a locals
frame (one is created if required). When invoked outside of a
definition the instance space is ALLOTed from the dictionary.
The instance goes out of scope (and is implicitly DELETEd when
local) at the same time as the name goes out of scope. For a static
instance, i.e. one in the dictionary, it remains in scope for the
lifetime of the application (until BYE) whereas for a local
instance it is DELETEd and goes out of scope at the end of the
definition. Therefore please note that returning a pointer to a
local instance *will* break your code - you must DNEW instead. You cannot
ever explicitly DELETE a named instance. In future you will be
allowed to attempt it and the effect will be to call the destructor
method, as will happen when scope is lost anyway.
: delete \ this --
DELETE is used to release the memory of a dynamic instance created
via DNEW. Memory release for static and local instances is
automagic. Any valid destructor is called prior to releasing the
memory back to the free-heap. In future performing DELETE on a
static or local will simply invoke the destructor.
This example shows how to create and use a class called AUTOVAR. This class contains one private data member and two public methods. one method initialises the data store, the other will return the contents of that store and post-increment it.
class AutoVar \ begin a new class definition
private:
cell: m_data \ Where the count will be stored
public:
meth: read++ \ The method to read and increment
meth: set \ The method to initialise the count
end-class \ end definition
: AutoVar::read++ \ -- n ; Method
1 m_data dup @ -rot +! \ read and increment data store
;
: AutoVar::set \ n -- ; Method
m_data ! \ write to data store
;
Here are three test routines which each take an initial value for an AutoVar type and then run the read++ method 10 times writing the result. The first case uses a static instance of AutoVar, the second case uses a local instance, and finally the third case shows how to use a heap allocated instance and how to typecast an object pointer. Note that in CIAO there are separate words for static/local instances with NEW and heap allocation with DNEW.
AutoVar new Foo \ create a static instance of Autovar
: test1 \ n -- ; Test static instance FOO
foo.set \ init with supplied index
10 0 do
cr foo.read++ . \ read and increment 10 times!
loop
;
: test2 \ n -- ; Same thing, local class tho'
AutoVar new Foobar \ create local instance of AUTOVAR
foobar.set
10 0 do
cr foobar.read++ .
loop
;
: test3 \ n -- ; Third time, heap allocated instance
AutoVar dnew \ create instance and store pointer
tuck (AutoVar).set \ use type cast on heap pointer )
10 0 do
cr dup (AutoVar).read++ . )
loop
delete \ destroy heap instance
;
AUTOVAR2 is a class derived from AUTOVAR to extend its functionality. AutoVar2 has no publically accessable methods but uses operators to perform the read and initialise.
Class AutoVar2 : private Autovar \ Create new class, inherit from
\ Autovar with all methods in
\ private scope.
oper: read++ \ Default operator performs
\ read++ method
to oper: set \ TO operator performs set method
end-class
The test procedures could now look like:
AutoVar2 new Foo \ create a static instance
: test1 \ n -- ; Test static instance FOO
to Foo \ init with supplied index
10 0 do
cr foo . \ read and increment 10 times!
loop
;
: test2 \ n -- ; Same thing, local class tho'
AutoVar2 new Foobar \ create local instance
to Foobar
10 0 do
cr foobar .
loop
;
The following code documents the beginning of an MFC style class library for CIAO.
The following operators have been defined and are used through out the base classes whenever applicable. Each class will document its use of these operators.
operator: ++ \ --
Increment by 1
operator: -- \ --
Decrement by 1
operator: cout<< \ --
Display applicable output
operator: cout<<hex \ --
Display applicable output in hex
operator: xywh-> \ x y width height --
Store X Y WIDTH HEIGHT parameters.
operator: lprect-> \ *Rect --
Store X Y WIDTH HEIGHT obtained from a RECT structure.
operator: [] \ index -- char
Get array element at index.
operator: []to \ index val --
Set element at index: <idx> <val> []to <class>
operator: (LPCTSTR) \ -- z$
Get contents as a zero-termintated string.
operator: (LPCTSTR)to \ z$ --
Set contents from a 0 terminated string pointer.
operator: += \ instance-pointer --
Concatenate/Add from a class of same type.
operator: (LPCTSTR)+= \ z$ --
Concatenate from a 0 terminated string.
This collection of classes represents the primitive data types found in C++. They can be though of as extended Forth VALUEs.
This data type represents a simple number which is basically equivalent to a CELL. It has no methods publically callable but simply uses operators to access.
The following operators have been assigned to methods for this class.
<default> |
No operator, returns contents. |
to |
Set content from stack item. |
addr |
Get the address rather than contents. |
++ |
Increment by 1. |
-- |
Decrement by 1. |
cout<< |
Write contents to console. |
cout<<hex |
Write contents as hex to console. |
Defines some simple classes for Windows data-types. Most simple types under Windows are just 32 bit numbers. Therefore the following types are all simply private scope derived from the INT type documented before.
LPVOID HANDLE HWND HMENU
HINSTANCE LPCTSTR LONG DWORD
The following structures are defined using standard Windows names. all data members are one of the previously defined Windows types.
RECT CREATESTRUCT POINT
This is simply a class version of the POINT structure. The reason for the separation is that the STRUCT{ version can be typecast from an OS supplied point-struct into a CIAO POINT struct or CPOINT class
The CPOINT class is publicly derived from POINT with a method and operator for TO supplied which takes another point as the source.
This is a class version of the RECT structure. The CRECT class is publicly derived from RECT with methods and operators.
class CRect : public Rect
public:
meth: Width
meth: Height
meth: SetXYWH
meth: SetLPRECT
meth: dump
-> oper: SetLPRect
xywh-> oper: SetXYWH
lprect-> oper: SetLPRECT
cout<< oper: dump
A CString object contains a variable-length sequence of characters. It also provides functions and operators which allow for easy to Concatenation and comparison operators, together with automatic memory management. CString objects are far easier to use than ordinary character arrays.
CString is based on the FORTH char data type.
CString Objects have the following useful characteristics:
Some of the members of this class can take either a character or a zero-terminated string as a parameter. This is autodetected by the simple assumption that any value greater than the maximum value storable in a char is an array pointer. For 8 bit character systems this means a pointer cannot be in the range 0..255.
: CString::ResizeBuffer \ rsize --
Resize the current string buffer memory to RSIZE chars.
: CString::Empty \ --
Release all string memory and return to init state.
: CString::GetAt \ idx -- char
Return the ascii character at IDX position in the string.
: CString::GetLength \ -- n
Return the length of the current string.
: CString::GetLPCTSTR \ -- z$
Return a pointer to the string as a zero-terminated. After
obtaining this pointer, any operation which modifies the string may
destroy this pointer.
: CString::IsEmpty \ -- BOOL
Return TRUE if there is no string information.
: CString::SetAt \ idx char --
Place character CHAR at the IDX position in the string.
: CString::Add \ *CString --
Add the contents of the CString class pointed to onto the end of
the current string.
: CString::AddLPCTSTR \ z$ --
Add the supplied zero terminated string to the end of the current.
: CString::SetLPCTSTR \ z$ --
Replace the current string with the supplied zero terminated one.
: CString::to \ *CString --
Replace the current string with the contents of the CString class
whose pointer is supplied.
: CString::Compare \ z$ -- flag
Compare the current string with the zero-terminated string supplied.
: CString::CompareNoCase \ z$ -- flag
As CString::Compare except character case is ignored.
: CString::Mid \ first count -- *CString(dynamic)
Return a new dynamic instance pointer for a CString which contains
a substring of the current. COUNT characters from index FIRST are
copied.
: CString::Left \ count -- *CString(dynamic)
Return a new dynamic instance pointer for a CString which contains
a substring of the current. COUNT characters are copied from the
start (left) of the string.
: CString::Right \ count -- *CString(dynamic)
Return a new dynamic instance pointer for a CString which contains
a substring of the current. COUNT characters are copied from the
end (right) of the string.
: CString::Delete \ index count -- newlen
Remove COUNT characters from the string starting at the INDEX
position. If count+index exceeds the string length it is trucated.
Also returns the new length of the string after the delete.
: CString::Insert \ index z$ -- int | index char -- int
Passed either an index and a z$ or an index and a character this
will perform an insert operation. The string or character supplied
is inserted starting at the original offset INDEX. Returns the
new length of the string.
: CString::MakeUpper \ --
Convert the classes string data to upper case where possible.
: CString::MakeLower \ --
Convert the classes string data to lower case where possible.
The following operators have been assigned to methods for this class.
[] |
GetAt -- Get character at specified index. |
[]to |
SetAt -- Set chatacter at specified index. |
(LPCTSTR) |
GetLPCTSTR -- Return 0terminated string pointer. ) |
to |
to -- Assign from another CString. |
(LPCTSTR)to |
SetLPCTSTR -- Assign from a 0 terminated string. ) |
+= |
Add -- Append from another CString. |
(LPCTSTR)+= |
AddLPCTSTR -- Append from a 0 terminated string. ) |