Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

+size structs...

1 view
Skip to first unread message

Guido Draheim

unread,
Aug 16, 2001, 7:43:54 AM8/16/01
to
oversimplified struct-and-field declaration.
just an idea but what would you think of this?
TIA, Guido
-----------------------------

\ +SIZE STRUCT AND FIELD DEFINITIONS
\ advantages:
\ (1) stepper-words already exist in the language ( CHAR+ CELL+ )
\ (2) adds a plus-enclosed syntax to get the size ( +SIZE CHAR+ )
\ (3) the three words are not used anywhere else ( +SIZE +FIELD +SIZED )
\ (4) obvious format to extend another struct ( +SIZE MYSTRUCT+ )
\ disadvantage:
\ (5) a bit unusual - the size is specified postfix ( overforthish )
\ (6) no chance to add implicit alignments ... or a type-id for the field.
\ but anyway - extremely portable across forth systems.


0 CONSTANT +SIZE

: +FIELD ( offset "name" -- offset )
CREATE DUP ,
DOES> @ +
;

: +SIZED ( offset "name" -- )
CREATE ,
DOES> @ +
;

[VOID] [IF] example:

+SIZE
+FIELD ->A CELL+
+FIELD ->B CHAR+
+SIZED MYSTRUCT+

+SIZE MYSTRUCT+
+FIELD ->C CHAR+
+FIELD ->D CELL+
+SIZED EXT-STRUCT+

+SIZE EXT-STRUCT+ BUFFER: EXT-STRUCT-1

+SIZE
+FIELD ->E CHAR+
ALIGNED
+FIELD ->F CELL+
+SIZED AGN-STRUCT+

[THEN]

Jos .v.d. Ven

unread,
Aug 16, 2001, 2:04:05 PM8/16/01
to

"Guido Draheim" <guidod...@gmx.de> wrote
news:3B7BB1FA...@gmx.de...

> oversimplified struct-and-field declaration.
> just an idea but what would you think of this?
> TIA, Guido
> -----------------------------

Nice but the following allows an easy port from C.

Note I am -- NOT -- a C fan but it is OK when I can use their
structures within Forth.

anew struct.f \ for Win32Forth June 1st, 2001 - 11:54

\ The following memory allocation words allow nesting and cloning
\ of a memory structure. Definitions made in C can be used with
\ small modifications.

0 value _struct 0 value start_struct


vocabulary allocation \ avoids conflicts. eg word

also allocation definitions

code n+adr@ ( n adr - adr@+n )
mov ebx, 0 [ebx] [edi] \ @
pop eax \ +
add ebx, eax
next c;

: _add-struct ( sizeof.struct - )
_struct here ! dup allot +to _struct ;

: add-struct ( sizeof.struct - )
create _add-struct
does> n+adr@ ;

: byte
create 1 _add-struct \ compile-time: ( - )
does> n+adr@ ; \ run-time: ( offset - offset+dword ) immediate

: word
create 2 _add-struct \ compile-time: ( - )
does> n+adr@ ; \ run-time: ( offset - offset+dword ) immediate

\ There is more in struct.f !
\ At the end of struct.f :

only forth definitions forth

: struct{ ( - )
\in-system-ok also allocation
0 dup to start_struct to _struct ;

: }struct ( - size-struct )
\in-system-ok previous _struct
start_struct - constant ;

: mkstruct: ( size-struct - ) create allot ;

\s

\ Example:

struct{ \ language
LANGID language.LanguageID
CHAR language.szDialect[LANG_LEN]
}struct sizeof.language

\ There is nothing allocated yet only the positions in memory are defined
\ Now it is going to be allocated in two different locations.

sizeof.language mkstruct: languageTemp1
sizeof.language mkstruct: languageTemp2

\ Change language.szDialect[LANG_LEN] of languageTemp1 as follows:
1 languageTemp1 language.szDialect[LANG_LEN] c!

\ The names are a bit longer, this is needed to avoid duplicate names.


Using a wheel from C in Forth saves a lot of time.
The rest of struct.f can be downloaded from http://home.planet.nl/~josv
Jos


Guido Draheim

unread,
Aug 16, 2001, 4:44:42 PM8/16/01
to
"Jos .v.d. Ven" wrote:
>
> "Guido Draheim" <guidod...@gmx.de> wrote
> news:3B7BB1FA...@gmx.de...
> > oversimplified struct-and-field declaration.
> > just an idea but what would you think of this?
> > TIA, Guido
> > -----------------------------
>
> Nice but the following allows an easy port from C.
>
> Note I am -- NOT -- a C fan but it is OK when I can use their
> structures within Forth.

Thanks, and yes, I like definitions too that would after all
allow to directly include C header definitions - there is
also a #define syntax that I've taken over from some other
forth (mpe?) along with #ifdef/#endif and others. Your approach
with an extra vocabulary is very very interesting - the only
thing I see as problematic that's the bit about the resulting
struct-type being *not* a self-defining field that can be
used as a field-def in another struct declaration. That's been
part of other struct-definers - and I faintly remember a
scheme that did actually mimic C syntax where I just thought
that "now just let the final word-declarator chop off an
extra ; character from the structname to be declared, and there
you are with a 1:1 mapping".

I had a look into many struct-makers around, the structvariant
thing from mpe is very impressive, and the handling of type-ids
in fsl-structs is sometimes unexpected but useful. After all,
most of them do that typename-which-CREATEs-a-field which needs
a full set of typenames to be declared in advance, and even those
that have sizeof-value-before-FIELD-that-CREATEs will usually
create a full series of size-words for simple types like /CHAR
and /CELL (was that openboot?). Last night I got that lightning
struck about a two-word struct-maker implementation using the
stepper-words CHAR+ CELL+ that already exist.

From here it was not long to see that the human eye could best
follow the text when it looks like each declaration is enclosed
in between plus-characters. The "+field" was born which does
not collide with some "field"-definition in any of the systems
I saw. The rest can be all different, like "+null" to start
an empty declaration, or "+struct:" to end it finally. It just
boils down to that "+field" declarator being the trick that
is *followed* by a stepper allocation of the size for the element.

Having it written down, I saw that this is far away from the
C model that we intuitivly follow so often - and still it looks
very forthish, perhaps a bit overforthish and *very* unusual.
But the longer I look at the more it pleases the eye - I don't
know if others get that same feeling so I wanted to ask. Well,
it is... so.... unusual.... ;-)

cheers,
-- guido

(P.S. it could as well be that the forthers around are enough with
the struct-makers that their system brings about. All systems
ships with a struct-maker - it is *damn* needed and there's no
common spec to follow that would be portable *and* predefined
across systems. But I don't like to heaten up flames about the
best system to use. The best system does of course have all
OO features we know from elsewhere, possibly (*horrors*) C++).

Julian Fondren

unread,
Aug 16, 2001, 8:29:11 PM8/16/01
to
"Jos .v.d. Ven" <jo...@wxs.nl> wrote in message news:<9lh1qf$2tjv1$1...@reader01.wxs.nl>...

> "Guido Draheim" <guidod...@gmx.de> wrote
> news:3B7BB1FA...@gmx.de...
> > oversimplified struct-and-field declaration.
> > just an idea but what would you think of this?
> > TIA, Guido
> > -----------------------------
>
> Nice but the following allows an easy port from C.

(snip code)

> Using a wheel from C in Forth saves a lot of time.
> The rest of struct.f can be downloaded from http://home.planet.nl/~josv
> Jos

Anton's http://mips.complang.tuwien.ac.at/forth/objects/structs.html
seems to be a decent data structure building package.

Tom Zimmer

unread,
Aug 17, 2001, 11:55:22 AM8/17/01
to
Here is an example of a data structure system that already exists in Win32Forth,
this code comes from the file WINSER.F, which is part of Win32Forth, and
implements a simple terminal program.

:Object DCB <Super Object

Record: AddrOf
int DCBlength
int BaudRate
int BinaryBits \ a 32bit cell of bit fields, following
'bits' fields are in this field.
1 bits fBinary \ define the bit fields
1 bits fParity
1 bits fOutxCtsFlow
1 bits fOutxDsrFlow \ SDI changed for Rts to Dsr
2 bits fDtrControl
1 bits fDtrSensitivity
1 bits fTXContinueOnXoff
1 bits fOutX
1 bits fInx
1 bits fErrorChar
1 bits fNull
2 bits fRtsControl
1 bits fAbortOnError
17 bits fDummy
short wReserved
short XonLim
short XoffLim
byte ByteSize
byte Parity
byte StopBits
byte XonChar
byte XoffChar
byte ErrorChar
byte EofChar
byte EvtChar
short wReserved1
;RecordSize: SIZEOFDCB

:M Reset: ( -- )
AddrOf SIZEOFDCB erase
;M

:M ClassInit: ( -- )
ClassInit: super
Reset: self \ create structure as Reset
;M

;Object

Where you would statments like DCB.AddrOf and DCB.SIZEOFDCB to access the entire
structure, and DCB.Parity to access a field of the structure. Notice that bit
fields are supported as well as various sizes of whole byte fields. You can
examine WINSER.F for further details of usage.

For your edification, here is the C source for the same data structure;

typedef struct _DCB { // dcb
DWORD DCBlength; // sizeof(DCB)
DWORD BaudRate; // current baud rate
DWORD fBinary: 1; // binary mode, no EOF check
DWORD fParity: 1; // enable parity checking
DWORD fOutxCtsFlow:1; // CTS output flow control
DWORD fOutxDsrFlow:1; // DSR output flow control
DWORD fDtrControl:2; // DTR flow control type
DWORD fDsrSensitivity:1; // DSR sensitivity
DWORD fTXContinueOnXoff:1; // XOFF continues Tx
DWORD fOutX: 1; // XON/XOFF out flow control
DWORD fInX: 1; // XON/XOFF in flow control
DWORD fErrorChar: 1; // enable error replacement
DWORD fNull: 1; // enable null stripping
DWORD fRtsControl:2; // RTS flow control
DWORD fAbortOnError:1; // abort reads/writes on error
DWORD fDummy2:17; // reserved
WORD wReserved; // not currently used
WORD XonLim; // transmit XON threshold
WORD XoffLim; // transmit XOFF threshold
BYTE ByteSize; // number of bits/byte, 4-8
BYTE Parity; // 0-4=no,odd,even,mark,space
BYTE StopBits; // 0,1,2 = 1, 1.5, 2
char XonChar; // Tx and Rx XON character
char XoffChar; // Tx and Rx XOFF character
char ErrorChar; // error replacement character

char EofChar; // end of input character
char EvtChar; // received event character
WORD wReserved1; // reserved; do not use
} DCB;

I think the Win32Forth implementation compares very well for readability with
the C source version.

Just my thoughts,

Tom Zimmer

Jos .v.d. Ven

unread,
Aug 17, 2001, 1:14:18 PM8/17/01
to

"Guido Draheim" <guidod...@gmx.de> wrote:
news:3B7C30BA...@gmx.de...

> - the only thing I see as problematic that's the bit about the resulting
> struct-type being *not* a self-defining field that can be
> used as a field-def in another struct declaration. That's been
> part of other struct-definers

It is possible to re-use a previous defined structure in an other structure.

Example:
struct{ \ BitmapFileHeader
word bfType
long bfSize
word bfReserved1
word bfReserved2
dword bfOffsetBits
}struct sizeof.BitmapFileHeader

struct{ \ BITMAPINFOHEADER
DWORD biSize
LONG biWidth
LONG biHeight
WORD biPlanes
WORD biBitCount
DWORD biCompression
DWORD biSizeImage
LONG biXPelsPerMeter
LONG biYPelsPerMeter
DWORD biClrUsed
DWORD biClrImportant
}struct sizeof.BITMAPINFOHEADER

struct{ \ BITMAPINFO
sizeof.BitmapFileHeader _add-struct
sizeof.BITMAPINFOHEADER _add-struct
}struct sizeof.Win3DIBFile

: >BitmapInfoHeader ( vadr - adr-BitmapInfoHeader )
sizeof.BitmapFileHeader + ;

Perhaps this is not what you had in mind.
Please post an example to make it clear.

Jos

Jos .v.d. Ven

unread,
Aug 17, 2001, 1:37:57 PM8/17/01
to
"Tom Zimmer" <tzi...@thermofinnigan.com> wrote
news:3B7D3E6A...@thermofinnigan.com...

> Here is an example of a data structure system that already exists in
Win32Forth,

Before I wrote struct.f I looked at your data structure system.

My thoughts were, nice but:
1.I am missing WORD, I do not wan't to translate over and over again WORD
into SHORT.
2.The pack should be extendable without rebuilding Forth.
3.It should be easy to make in other Forth-systems.
4. How can your data structures be nested ?

Jos


Guido Draheim

unread,
Aug 17, 2001, 2:28:40 PM8/17/01
to
"Jos .v.d. Ven" wrote:
> struct{ \ BITMAPINFO
> sizeof.BitmapFileHeader _add-struct
> sizeof.BITMAPINFOHEADER _add-struct
> }struct sizeof.Win3DIBFile
>
> : >BitmapInfoHeader ( vadr - adr-BitmapInfoHeader )
> sizeof.BitmapFileHeader + ;
>
> Perhaps this is not what you had in mind.
> Please post an example to make it clear.
>
IIRC, the fsl-struct have that, to be using your "}struct" it
would be

: }struct create , ( store the offset/size )
does> @ create over , + ( get the offset and create a field with it )
does> @ + ( that is itself that offsetword )
;

so it comes out as

struct{
my.BitmapFileHeader ->fileheader
my.BITMAPINFOHEADER ->infoheader
}struct my.Win3DIBFile

plus a word "sizeof" that fetches the size/offset

: sizeof ' >body @ ;

*aahm* when I first saw an fsl-like implementation ("structure")
it was a bit chilly to read that doubled "does>" - but it works.
(hopefully I recalled the implemenation correctly from longterm memory...)

cheers,
-- guido Edel sei der Mensch, hilfreich und gut
GCS/E/S/P C++$++++ ULHS L++w- N++@ d(+-) s+a- r+@>+++ y++ 5++X- (geekcode)

Tom Zimmer

unread,
Aug 17, 2001, 3:07:57 PM8/17/01
to
"Jos .v.d. Ven" wrote:

> "Tom Zimmer" <tzi...@thermofinnigan.com> wrote
> news:3B7D3E6A...@thermofinnigan.com...
> > Here is an example of a data structure system that already exists in
> Win32Forth,
>
> Before I wrote struct.f I looked at your data structure system.
>
> My thoughts were, nice but:
> 1.I am missing WORD, I do not wan't to translate over and over again WORD
> into SHORT.

I considered this, but my personal choice was not to overload "WORD".


>
> 2.The pack should be extendable without rebuilding Forth.

I didn't need this, and it was not suggested, so it isn't implemented.


>
> 3.It should be easy to make in other Forth-systems.

Since Andrews high level implementation is very portable, I suspect this
extention could be made portable, but I didn't have a need, so it isn't
portable.


>
> 4. How can your data structures be nested ?

I just looked at this, and I believe it could be extended to be nestable, but
again I didn't have a need, so I never made it nestable.


>
>
> Jos

Everyone seems to have different requirements, perhaps that is why we have so
many Forths, and so few libraries.

cLIeNUX user

unread,
Aug 17, 2001, 11:13:40 PM8/17/01
to
humb...@smart.net

>"Jos .v.d. Ven" wrote:
>
>> "Tom Zimmer" <tzi...@thermofinnigan.com> wrote
>
>Everyone seems to have different requirements, perhaps that is why we have so
>many Forths, and so few libraries.

Yeah. Stock Forth does what it does and stops there, I believe, because
from Forth outward the possibilities explode. I think this is in part
because Chuck Moore and others are more cognizant of how variable things
are at a low level than people that are used to some particular approach.
A standard is funny there. A standard implies that X is the way to do it.
Perhaps "standard suggestions" are more appropriate for things with myriad
possible implementations.

Rick Hohensee

Jos .v.d. Ven

unread,
Aug 18, 2001, 12:12:47 PM8/18/01
to
"Guido Draheim" <guidod...@gmx.de> wrote
news:3B7D6258...@gmx.de...

> IIRC, the fsl-struct have that, to be using your "}struct" it
> would be
>
> : }struct create , ( store the offset/size )
> does> @ create over , + ( get the offset and create a field with it )
> does> @ + ( that is itself that offsetword )
> ;
>
> so it comes out as
>
> struct{
> my.BitmapFileHeader ->fileheader
> my.BITMAPINFOHEADER ->infoheader
> }struct my.Win3DIBFile

Thank you for your code. struct.f was changed as follows:

: }struct
\in-system-ok previous
create _struct , ( store the offset/size ) \ unnested
does> @ create _struct , _add-struct ( get the offset and create a field
with it ) \ nested
does> n+adr@ ( that is itself that offsetword )
;

only forth definitions forth

: struct{ ( - )
\in-system-ok also allocation
0 dup to start_struct to _struct ;

: sizeof ' >body @ ;

: mkstruct: ( size-struct - ) create dup , allot does> cell+ ;

\s Changes in the example:

struct{ \ BITMAPINFO
BitmapFileHeader My.BitmapFileHeader
BitmapInfoHeader My.BitmapInfoHeader
}struct Win3DIBFile \ 54

: >BitmapInfoHeader ( vadr - adr-BitmapInfoHeader )

My.BitmapInfoHeader ;


sizeof Win3DIBFile mkstruct: My.Win3DIBFile
cr sizeof My.Win3DIBFile . \ 54
cr My.Win3DIBFile My.BitmapInfoHeader My.Win3DIBFile - . \ 14
cr sizeof BitmapFileHeader . \ 14
cr sizeof BitmapInfoHeader . \ 40
cr ' My.Win3DIBFile >body . My.Win3DIBFile . \ 248780 248784

\s
Jos


David N. Williams

unread,
Aug 18, 2001, 3:24:50 PM8/18/01
to
Tom Zimmer wrote:
>
> Here is an example of a data structure system that already exists in
> Win32Forth,
>
> [...]

Gee, I haven't thought about this for awhile!

Okay, let me shorten your C-example a bit:

typedef struct _DCB { // dcb
DWORD DCBlength; // sizeof(DCB)
DWORD BaudRate; // current baud rate
DWORD fBinary: 1; // binary mode, no EOF check

// ...


DWORD fRtsControl:2; // RTS flow control
DWORD fAbortOnError:1; // abort reads/writes on error
DWORD fDummy2:17; // reserved
WORD wReserved; // not currently used

// ...


BYTE ByteSize; // number of bits/byte, 4-8

// ...


char XonChar; // Tx and Rx XON character

// ...


WORD wReserved1; // reserved; do not use
} DCB;

Our "compatible structures" equivalent, assuming DWORD, WORD,
and BYTE have been defined as "atomic types", would be

struct{ \ dcb
DWORD field DCBlength \ sizeof(DCB)
DWORD field BaudRate \ current baud rate
DWORD 1 bit-field fBinary \ binary mode, no EOF check
\ ...
DWORD 2 bit-field fRtsControl \ RTS flow control
DWORD 1 bit-field fAbortOnError \ abort reads/writes on error
DWORD 17 bit-field fDummy2 \ reserved
WORD field wReserved \ not currently used
\ ...
BYTE field ByteSize \ number of bits/byte, 4-8
\ ...
cchar field XonChar \ Tx and Rx XON character
\ ...
WORD field wReserved1 \ reserved; do not use
}struct _DCB;

_DCB {}structof/ }DCB

Then, for example,

{ }DCB nip

leaves the size of the structure, while

{ XonChar }DCB drop

drops the size of the XonChar field and leaves its address
in }DCB.

Structures are nestable, and arrayable, and field names are
reusable. There is no analog of the DCB typedef.

Or to make it even more C-like, you could make factors like,

: DWORD: DWORD field ;

etc., and

: DWORD-BITS: ( n -- ) >r DWORD r> bit-field ;

with unmentioned stack effects for 'DWORD', 'field', and
'bit-field'. The result is:

struct{ \ dcb
DWORD: DCBlength \ sizeof(DCB)
DWORD: BaudRate \ current baud rate
DWORD-BITS: 1 fBinary \ binary mode, no EOF check
\ ...
DWORD-BITS: 2 fRtsControl \ RTS flow control
DWORD-BITS: 1 fAbortOnError \ abort reads/writes on error
DWORD-BITS: 17 fDummy2 \ reserved
WORD: wReserved \ not currently used
\ ...
BYTE: ByteSize \ number of bits/byte, 4-8
\ ...
char: XonChar \ Tx and Rx XON character
\ ...
WORD: wReserved1 \ reserved; do not use
}struct _DCB;

This is a slight cheat, because I never got around to defining
words to store into and fetch from the bit fields, but that's
straightforward, if otherwise unavoidable...

-David

ftp://feynman.physics.lsa.umich.edu/pub/williams/forth/cstructures/

Michael L. Gassanenko

unread,
Sep 14, 2001, 5:45:46 AM9/14/01
to
Guido, I really like your idea.
I have tried it in a program.
It is able to do everything I want.
But in your original posting the idea is overcomplicated.

* * * * * * * * * * * * * * * * * * * * *

This is what I did:

: ^FIELD CREATE DUP , DOES> @ + ;
: @FIELD CREATE DUP , DOES> @ + @ ;
: !FIELD CREATE DUP , DOES> @ + ! ;

\ history of <...>

0
^FIELD h^nfa @FIELD h.nfa !FIELD h!nfa CELL+
^FIELD h^dp @FIELD h.dp !FIELD h!dp CELL+
^FIELD h^part @FIELD h.part !FIELD h!part CELL+
^FIELD h^val @FIELD h.val !FIELD h!val CELL+
CONSTANT h/item

\ look-up table <...>
0
^FIELD l^nfa @FIELD l.nfa !FIELD l!nfa CELL+
^FIELD l^next @FIELD l.next !FIELD l!next CELL+
^FIELD l^exact @FIELD l.exact !FIELD l!exact CELL+
^FIELD l^longer @FIELD l.longer !FIELD l!longer CELL+
CONSTANT lt/item

<...>

: lookup-nfa ( nfa ^entry0 -- ^entry | 0 )
BEGIN
DUP
WHILE
2DUP l.nfa <>
WHILE
l.next
REPEAT
THEN
NIP
;

\ derived types:
lt/item
^FIELD l^extra CELL+
CONSTANT xlt/item

lt/item
^FIELD l^unnecessary CELL+
CONSTANT ult/item

* * * * * * * * * * * * * * * * * * * * *

Naming convention:

the names of field access operations have the format
<type-id><operation-id><field-id>

All derived types have the same type-id prefix as
their base types. Type-id prefixes replace name spaces,
and we place fields from all "related" classes
into the same "name space".

As to operation-id, I used
^ for obtaining address
. for access to contents (an algolism)
! for storing
but which operations to provide and which symbols to use
is a matter of style/taste.

No comments about field-id.

* * * * * * * * * * * * * * * * * * * * *

I especially like that this approach can provide
any modification of structures I can remember.

1) simple structures

0
^FIELD l^nfa CELL+
^FIELD l^next CELL+
^FIELD l^exact CELL+
^FIELD l^longer CELL+
CONSTANT lt/item

Use:
( addr ) l^next @ ( value ) \ fetch
( value addr ) l^next ! \ store
( addr ) l^next ( field-addr ) \ obtain field address

2) structures with field fetch/store operations:
shown in the beginning of this message

Use:
( addr ) l@next ( value ) \ fetch
( value addr ) l!next \ store
( addr ) l^next ( field-addr ) \ obtain field address

3) structures accessed via a pointer to the current structure

0 VALUE ^curr-l \ the pointer to the current structure
: l^FIELD CREATE DUP , DOES> @ ^curr-l + ;
: l@FIELD CREATE DUP , DOES> @ ^curr-l + @ ;
: l!FIELD CREATE DUP , DOES> @ ^curr-l + ! ;

\ and

0
l^FIELD l^nfa CELL+
l^FIELD l^next CELL+
l^FIELD l^exact CELL+
l^FIELD l^longer CELL+
CONSTANT lt/item

Use:
l^next @ ( value ) \ fetch
( value ) l^next ! \ store
l^next ( field-addr ) \ obtain field address

\ or

0
l^FIELD l^nfa l@FIELD l.nfa l!FIELD l!nfa CELL+
l^FIELD l^next l@FIELD l.next l!FIELD l!next CELL+
l^FIELD l^exact l@FIELD l.exact l!FIELD l!exact CELL+
l^FIELD l^longer l@FIELD l.longer l!FIELD l!longer CELL+
CONSTANT lt/item

Use:
l@next ( value ) \ fetch
( value ) l!next \ store
l^next ( field-addr ) \ obtain field address

* * * * * * * * * * * * * * * * * * * * *

As to bit fields...

Well, it is possible to implement any access you might want.

0
^FIELD s^a CELL+ ( offset )
1 ( offset mask )
bit.field s.x bit!field s!x 2*
bit.field s.y bit!field s!y 2*
bit.field s.z bit!field s!z 2*
1- CONSTANT s&xyz
^FIELD s^xyz CELL+ ( offset )
^FIELD s^b CELL+ ( offset )
CONSTANT s/size

Definitions of words bit.field and bit!field
( offset mask -- offset mask )
are left as an exercise for the readed.

The readed might also prefer to specify the bit masks explicitly
(as I would do):

0
^FIELD s^a CELL+ ( offset )
0001 bit.field s.x bit!field s!x DROP
003E bit.field s.y bit!field s!y DROP
00C0 bit.field s.z bit!field s!z DROP
^FIELD s^xyz CELL+ ( offset )
^FIELD s^b CELL+ ( offset )
CONSTANT s/size

or even

0
^FIELD s^a CELL+ ( offset )
0
0001 bit.field s.x bit!field s!x OR
003E bit.field s.y bit!field s!y OR
00C0 bit.field s.z bit!field s!z OR
CONSTANT s&xyz
^FIELD s^xyz CELL+ ( offset )
^FIELD s^b CELL+ ( offset )
CONSTANT s/size

If you need multi-bit fields, you can develop
such form of access to them that suits your needs best.

* * * * * * * * * * * * * * * * * * * * *

Alignment.

0
^FIELD s.c1 CHAR+
^FIELD s.c2 CHAR+ ALIGN
^FIELD s.x CELL+
CONSTANT s/size

You see that ali8gnment must be specified explicitly.
OTOH, you can create unaligned structures.

* * * * * * * * * * * * * * * * * * * * *

Import from C

I think, that could be done by a program.
Anyway, manual editing of C sources is not the best
thing to do.
(What shall you do when these sources change?)

* * * * * * * * * * * * * * * * * * * * *

Opinions?

* * * * * * * * * * * * * * * * * * * * *

Guido Draheim

unread,
Sep 17, 2001, 2:14:21 PM9/17/01
to
"Michael L. Gassanenko" wrote:
>
> Guido, I really like your idea.
> I have tried it in a program.
> It is able to do everything I want.
> But in your original posting the idea is overcomplicated.
>
> * * * * * * * * * * * * * * * * * * * * *
>
> This is what I did:
>
> : ^FIELD CREATE DUP , DOES> @ + ;
> : @FIELD CREATE DUP , DOES> @ + @ ;
> : !FIELD CREATE DUP , DOES> @ + ! ;
>
> Opinions?

looks great. although I don't like the "style" - it should
really read "+field" for the declaration of an sizeoffset
word which would be along char+/cell+ etc.

Secondly, in quite some programs I saw "->struct.member"
as the general naming scheme for the offsetword - which does
obviously look intuitive atleast to C programmers.

And thirdly, fetch/store should be tacked to the end - it does
make it easier for me to read a line - the final bang on the
line closes the line that consists of a series of @fetches and
scale/offset/arith operations.

And fourthly, you declare @/! but that is without a type, just
the cell-wide one. just as an example you show the bitfield
definers - but what about fields being char or wchar or a
double-wide or just a float? Well I do respect that the actual
bitsize/representation of the underlying struct-member should
be hidden and the user therefore only see fetch/store/adressof
accessors.

However, that could also be achieved on top of the original
offsetword field-declarations like
: ->mystru.a@ ->mystru.a w@ ;
: ->mystru.a! ->mystru.a w! ;

looking over your proposal again, I do see that my posting
of last month was a bit overdone - still. well, here's a
shorter example with a slightly different style:

: +field create dup , does> @ + ;
: struct+: create , does> @ + ;

0 basestru+
+field ->mystru.a char+
+field ->mystru.b char+
struct+: mystru+

0 otherstru+
+field ->newstru.u mystru+
+field ->newstru.v cell+
struct+: newstru+

... and to get the size, it is just a writing style that says
one can use the two-word-sequence `0 newstru+` for it, e.g. in

0 newstru+ buffer: x
0 mystru+ buffer: y

... with traditional accessing like in

x ->newstr.v @ y ->mystru.b c!


hmmm, may be this one should be called "struct-p". It still
has the advantage to *not* use words like "field" or "struct"
that is known to be different for each system predefining it.

Michael L. Gassanenko

unread,
Sep 17, 2001, 4:57:00 PM9/17/01
to
An obvious bug which is easy to repeat:

I have changed the type of two fields.
They were single-cell, now they are double-cell "elements".

First I changed the "dp" field, and then decided
to change the "val" field.
I changed the access operators but forgot to replace
CELL+ by elem-size+ .

The lesson is:
when you change the type of a field,
remember that it is specified in multiple places,
namely:
1) the "size+" operator
2) the fetch/store operator declarations (if any)
3) the places where the values are used

"Michael L. Gassanenko" wrote:
>
> : ^FIELD CREATE DUP , DOES> @ + ;
> : @FIELD CREATE DUP , DOES> @ + @ ;
> : !FIELD CREATE DUP , DOES> @ + ! ;

: ^FIELD CREATE DUP , DOES> @ + ;
: @FIELD CREATE DUP , DOES> @ + @ ;
: !FIELD CREATE DUP , DOES> @ + ! ;

: e@field CREATE DUP , DOES> @ + elem_@ ;
: e!field CREATE DUP , DOES> @ + elem_! ;


>
> 0
> ^FIELD h^nfa @FIELD h.nfa !FIELD h!nfa CELL+
> ^FIELD h^dp @FIELD h.dp !FIELD h!dp CELL+
> ^FIELD h^part @FIELD h.part !FIELD h!part CELL+
> ^FIELD h^val @FIELD h.val !FIELD h!val CELL+
> CONSTANT h/item

0
^FIELD h^id @FIELD h.id !FIELD h!id CELL+
^FIELD h^dp e@field h.dp e!field h!dp elem-size+


^FIELD h^part @FIELD h.part !FIELD h!part CELL+

^FIELD h^val e@field h.val e!field h!val elem-size+
CONSTANT h/item

--------

Maybe, I should have written

: cell-field ^FIELD @FIELD !FIELD CELL+ ;
: elem-field ^FIELD e@FIELD e!FIELD elem-size+ ;

0
cell-field h^id h.id h!id
elem-field h^dp h.dp h!dp
...

But the problem does not disappear, it just gets
hidden in the declaration of elem-field (the type
of data is still mentioned in multiple places there).
Less text to change, but you still have to mind the
possibility of the bug.


--
"filer a l'anglaise" = "to take French leave"
^^^^^^^^ ^^^^^^

Michael L. Gassanenko

unread,
Sep 17, 2001, 6:41:48 PM9/17/01
to
Guido Draheim wrote:
>
> : +field create dup , does> @ + ;
> : struct+: create , does> @ + ;
>
> 0 basestru+
> +field ->mystru.a char+
> +field ->mystru.b char+
> struct+: mystru+
>
> 0 otherstru+
> +field ->newstru.u mystru+
> +field ->newstru.v cell+
> struct+: newstru+
>
> ... and to get the size, it is just a writing style that says
> one can use the two-word-sequence `0 newstru+` for it, e.g. in
>
> 0 newstru+ buffer: x
> 0 mystru+ buffer: y
>
> ... with traditional accessing like in
>
> x ->newstr.v @ y ->mystru.b c!
>
> hmmm, may be this one should be called "struct-p". It still
> has the advantage to *not* use words like "field" or "struct"
> that is known to be different for each system predefining it.

Practice showed one more aspect:

: otherstru[]^ ( index baseaddr -- addr )
SWAP 0 otherstru+ * +
;

I dislike " 0 otherstru+ * ". It should be " /otherstru * "

> Secondly, in quite some programs I saw "->struct.member"
> as the general naming scheme for the offsetword - which does
> obviously look intuitive atleast to C programmers.

1) In C "->" means: fetch, then add offset (pointer -- component).
In Forth [as above], "->" means just
"add offset" (struc -- component), that is, what "." means in C.

2) The -> symbol is long. It looks almost as whitespace
and attracts attention, while the important thing is not ->
but something else. If accessing a structure is not
a remarkable event in itself, it should not
attract so much attention.

The word >R is called >R rather than ->R because -> does
not read well. But it is pronounced as if it was ->R .

BEGIN DUP my.b WHILE DUP my^c dosomething my.next REPEAT
vs
BEGIN DUP ->my.b@ WHILE DUP ->my.c dosomething ->my.next@ REPEAT

A bit resembles the DP+! story, IMO.


--
"We are not poets, our concern is clearness", said Editor
and replaced 'and' with 'as well as'.

Guido Draheim

unread,
Sep 17, 2001, 7:23:03 PM9/17/01
to

the plus-operation is quick on all cpus while mul is not.
OTOH, yes, this is a small advantage for the size-based
structs that have just "/otherstru +" and "/otherstru *".

The main trick of +field structs has been that we already
have the struct-words for the basic types like `char+` and
`cell+` and all the others - and for quite a reason all of
these types are doubled with a scaling operation like is
`chars` and `cells`.

One may adopt the hybrid that was almost visible in your
latest posting - use the offsetwords for the basic types
and let compound structs be just sizewords. A struct
member would therefore look like

0 /otherstru +
+field ->newstru.a char+
+field ->newstru.b /oldstru +
constant /newstru

in a way however it does not have that much a benefit
over openfirmware struct style as it could adopt the
basictypes's offsetwords - it's just the other way round:

0 constant /0

/0 /otherstru +
/0 cell+ field ->newstru.a
/oldstru field ->newstru.b
constant /newstru

>
> > Secondly, in quite some programs I saw "->struct.member"
> > as the general naming scheme for the offsetword - which does
> > obviously look intuitive atleast to C programmers.
>
> 1) In C "->" means: fetch, then add offset (pointer -- component).
> In Forth [as above], "->" means just
> "add offset" (struc -- component), that is, what "." means in C.

ack.

>
> 2) The -> symbol is long. It looks almost as whitespace
> and attracts attention, while the important thing is not ->
> but something else. If accessing a structure is not
> a remarkable event in itself, it should not
> attract so much attention.

may be, but...

>
> The word >R is called >R rather than ->R because -> does
> not read well. But it is pronounced as if it was ->R .
>
> BEGIN DUP my.b WHILE DUP my^c dosomething my.next REPEAT
> vs
> BEGIN DUP ->my.b@ WHILE DUP ->my.c dosomething ->my.next@ REPEAT
>
> A bit resembles the DP+! story, IMO.
>

quite so. Actually, a simple "." in front of a structmember
offsetword would be too easily overlooked, like in

begin dup .my.b @ while dup .my.c dosomething .my.next @ repeat

furthermore the "." words are more used for output of things,
and anyway it should be more obvious to be a binary operation.
The ">" is already taken as "move-over", perhaps ">>" as shift-upto
could be used but it would stand out even more. You could of course
propose to start using "^" ... up front IMHO, like ^my.c to make
it bind closer to the preceding adress, or as the last char to make
it more visible as an operation (but my.c^ looks bad to my eyes).

Anyway, all I can tell you is that I have seen many programs that
use the "->" style - it is almost as traditional as "/" for the
"sizeof" or "#" or "numberof". If I would start to change it, I'd
simply use that "+" tacked to the end of a word containing a dot
in the middle, like in

begin dup my.b+ @ while my.c+ dosomething my.next+ @ repeat

which would also serve well for the interesting case - nested
structures and structs containing pointers to structs. Those
have to be readable if written in a row...

table-base @ ->table.value @ ->pool.handle @ handle.valid? if .....

and with dot-plus style it would become

table-base @ table.value+ @ pool.handle+ @ handle.valid? if

and your style (disregarding fetch/store words)

table-base @ table^value @ pool^handle @ handle.valid? if

and comparing these three, each has its advantages on some
scale, being short or making it intuitivly visible that we
deal with structs and members - your style would have the
least intuition but people could learn about it. It's just
not that far yet, on the contrary people could speak it as
toggle,swap,merge,exchange - a case of being used to, or not.

so much for struct/field styles, even that we still have no
such portable standard yet, and likewise in a word where every
mature system provides a struct/field implementation of its own.
And still I like mpe's one best for a size-based stru-package
that is almost simple and quite powerful with its nested
and union-like declarations.

cheers,

0 new messages