Discussion:
gm2, DEFINITION MODULE FOR "C"
(too old to reply)
cvs
2011-07-03 11:09:05 UTC
Permalink
Hi group!

I am having problems writing working definition modules for a C
library (for use with gm2). Could someone share some experiences?

My questions are:

1. What to do with all the preprocessor definitions? I know some can
just be translated to constants but how do you translate something
like (0x20?):
#define GDBM_SYNC 0x20

2. What is the correct way to translate types like this one:
typedef struct {
char *dptr;
int dsize;
} datum;

3. Lines like this one:
extern GDBM_FILE gdbm_open __P((char *, int, int, int, void (*)()));
are really confusing. What does the __P do in C? How can this be
written in a definition module?

Thanks in advance

Christoph
Marco van de Voort
2011-07-03 12:53:01 UTC
Permalink
Post by cvs
Hi group!
I am having problems writing working definition modules for a C
library (for use with gm2). Could someone share some experiences?
1. What to do with all the preprocessor definitions? I know some can
just be translated to constants but how do you translate something
#define GDBM_SYNC 0x20
20H
Post by cvs
typedef struct {
char *dptr;
int dsize;
} datum;
datum= RECORD
dptr : POINTER TO CHAR;
dsize : INTEGER;
END;
Post by cvs
extern GDBM_FILE gdbm_open __P((char *, int, int, int, void (*)()));
are really confusing. What does the __P do in C? How can this be
written in a definition module?
Nothing. Afaik the _P is something to workaround limitations in older (K&R)
compilers, and can it safely be omitted.
cvs
2011-07-03 14:37:41 UTC
Permalink
Post by cvs
Hi group!
I am having problems writing working definition modules for a C
library (for use with gm2). Could someone share some experiences?
1. What to do with all the preprocessor definitions? I know some can
just be translated to constants but how do you translate something
#define  GDBM_SYNC    0x20
20H
Post by cvs
typedef struct {
   char *dptr;
   int   dsize;
      } datum;
datum=  RECORD
    dptr : POINTER TO CHAR;
    dsize : INTEGER;
    END;
Post by cvs
extern GDBM_FILE gdbm_open __P((char *, int, int, int, void (*)()));
are really confusing. What does the __P do in C? How can this be
written in a definition module?
Nothing. Afaik the _P is something to workaround limitations in older (K&R)
compilers, and can it safely be omitted.
Thanks a lot for the quick answers!

To clarify my second question: I wrote the record like you did but I
have seen example code which uses different types from SYSTEM to
interface with int, like SYSTEM.CARDINAL32 or SYSTEM.INTEGER16; Can I
- knowing about the values of a specific var - just select a fitting
type? Does it make a difference in memory usage (as I thought it's
just a call)? Will gm2 know how to deal with a var of some CARDINAL
type even if the underlying C procedure/function expects an int? Or is
it just the value that has to be in the boundaries of C-integer? For
now I'll stick to INTEGER -

C.
Marco van de Voort
2011-07-03 15:10:25 UTC
Permalink
Post by cvs
To clarify my second question: I wrote the record like you did but I
have seen example code which uses different types from SYSTEM to
interface with int, like SYSTEM.CARDINAL32 or SYSTEM.INTEGER16; Can I
- knowing about the values of a specific var - just select a fitting
type?
More or less yes. But you can't read intention of the C sources. E.g. did
the author of the C source really meant int (as in, on the rare machines
where int is 64-bits (older Cray's mainly afaik), the value would be
64-bit?). Or did he simply mean int32?
Post by cvs
Does it make a difference in memory usage (as I thought it's just a call)?
The objective is to match the C headers exactly. There is no room for
optimization, since the definition header is probably codeless. It merely
describes the C code in M2 terms.
Post by cvs
Will gm2 know how to deal with a var of some CARDINAL type even if the
underlying C procedure/function expects an int?
As long as you use the subset of both of them (0.. 2^31-1), it doesn't
matter. But better make a policy of following the C header to the letter,
unless you are very, very sure of it.
jan272
2011-07-04 11:18:57 UTC
Permalink
Post by cvs
Hi group!
I am having problems writing working definition modules for a C
library (for use with gm2). Could someone share some experiences?
that'll teach you
Post by cvs
1. What to do with all the preprocessor definitions? I know some can
just be translated to constants but how do you translate something
#define GDBM_SYNC 0x20
CONST GDBMSYNC 20H

or

CONST GDBMSYNC 36C

depending on the purpose of the constant. if it's a character
definition you need the latter. modula-2 normally does not accept
underscores, as you surely will know.
Post by cvs
typedef struct {
char *dptr;
int dsize;
} datum;
This will not work..... modula-2 does not allow pointers to anonymous
types. when dptr is a string, you COULD try 'dptr : ARRAY OF CHAR' but
I would not bet a nickle on it.

marco gave the best possible translation...
Post by cvs
extern GDBM_FILE gdbm_open __P((char *, int, int, int, void (*)()));
are really confusing. What does the __P do in C? How can this be
written in a definition module?
forget it. this is not even like cursing in a church. it's like a
priest with Tourette syndrome in St Peter's cathedral in Rome.

IF you were to do it in modula-2, it would be something along the
lines of

FROM Gdbm IMPORT open;

everything from the '__' is superfluous in modula-2 because it was
dealt with in the definition module of 'Gdbm'.

It seems like you are making the basic mistake of a translator: 1 on 1
translations work in 90% of the time. The other 10% take up a lot of
time. More than the initial 90%.....

dutch: Laat je niet de kaas van het brood eten

1 on 1 english: Don't let them eat the cheese off your bread.

whereas the meaning is: 'act quickly; do not hesitate; be very
cautious'

when translating (or porting) you have to

- thoroughly understand the program
- thoroughly understand the source of the program
- thoroughly understand the source language
- thoroughly understand the target language

only THEN can you make a new version in the target language. you must
make new ALGORITHMS, not new STATEMENTS. a line by line translation
will never work. not even if the source is modula-2 and the target
oberon.... not even if the source is mocka and gm2 as target.
have you read at least one of the 'data structures + algorithms =
programs' books by our Grand Master? they're cheap on amazon. also
take the time to read at least one of the 'compiler construction'
books by wirth.
Gaius Mulley
2011-07-05 10:27:52 UTC
Permalink
Post by cvs
Hi group!
I am having problems writing working definition modules for a C
library (for use with gm2). Could someone share some experiences?
1. What to do with all the preprocessor definitions? I know some can
just be translated to constants but how do you translate something
#define  GDBM_SYNC    0x20
typedef struct {
        char *dptr;
        int   dsize;
      } datum;
extern GDBM_FILE gdbm_open __P((char *, int, int, int, void (*)()));
are really confusing. What does the __P do in C? How can this be
written in a definition module?
Thanks in advance
Christoph
Hi Christoph,

DEFINITION MODULE FOR "C" foo ;

CONST
GDBM_SYNC = 20H ; (* for an integer/cardinal derived type *)
GDBM_SYNC_C = CHAR(20H) ; (* for a char type *)

TYPE
datum = RECORD
dptr : POINTER TO CHAR ;
dsize: INTEGER ;
END ;

proc = PROCEDURE ;
charStar = POINTER TO CHAR ;

(* extern GDBM_FILE gdbm_open __P((char *, int, int, int, void (*)
())); *)

PROCEDURE gdbm_open (a: charStar; b, c, d: INTEGER; e: proc) ;

END foo.


when you link remember to include -lgdbm and all should be well!

regards,
Gaius
tbreeden
2011-07-06 13:01:53 UTC
Permalink
TYPE
   proc     = PROCEDURE ;
(* extern GDBM_FILE gdbm_open __P((char *, int, int, int, void (*)
())); *)
PROCEDURE gdbm_open (a: charStar; b, c, d: INTEGER; e: proc) ;
Even a little bit simpler, the type definition here for "proc" is
unnecessary, as "PROC" is an M2 pervasive type of the same definition.

Tom
Marco van de Voort
2011-07-06 13:13:09 UTC
Permalink
Post by tbreeden
TYPE
? ?proc ? ? = PROCEDURE ;
(* extern GDBM_FILE gdbm_open __P((char *, int, int, int, void (*)
())); *)
PROCEDURE gdbm_open (a: charStar; b, c, d: INTEGER; e: proc) ;
Even a little bit simpler, the type definition here for "proc" is
unnecessary, as "PROC" is an M2 pervasive type of the same definition.
Not necessarily. gdbm.proc has a calling convention of gdbm (cdecl), while
system.PROC has whatever the M2 language system internal calling convention is.

In some compilers (specially non x86) this might be the same, but it is not
an absolute rule, and defining a separate time for it is smart.
Marco van de Voort
2011-07-06 19:02:35 UTC
Permalink
Post by Marco van de Voort
In some compilers (specially non x86) this might be the same, but it is not
an absolute rule, and defining a separate time for it is smart.
.. a separate type obviously.
tbreeden
2011-07-09 20:34:39 UTC
Permalink
Post by Marco van de Voort
Post by tbreeden
TYPE
? ?proc ? ? = PROCEDURE ;
PROCEDURE gdbm_open (a: charStar; b, c, d: INTEGER; e: proc) ;
Even a little bit simpler, the type definition here for "proc" is
unnecessary, as "PROC" is an M2 pervasive type of the same definition.
Not necessarily. gdbm.proc has a calling convention of gdbm (cdecl), while
system.PROC has whatever the M2 language system internal calling convention is.
In some compilers (specially non x86) this might be the same, but it is not
an absolute rule, and defining a separate time for it is smart.
That makes sense, especially if the procedure being passed has
parameters itself.
In this case, the .h file gives no information about whether it does
or no, but
seems to imply that it does not. In which case, is putting the TYPE
proc = PROCEDURE;
within the 'DEFINITION MODULE FOR "C"' enough to ensure that the M2
compiler
will type check enforce that the passed procedure is also defined
within a
'DEFINITION MODULE FOR "C"' definition block ?

Consulting the gdbm docs, it looks like that proc is called from
gdbm_open on
a Fatal Error and actually does have a parameter, and actually does
have a parameter,
a string (message?). So will the type definition be better as
"TYPE proc = PROCEDURE(ARRAY OF CHAR)" ?

Or, it looks from the gdbm docs that you can pass null for the last
parameter here
and get a default handling of fatal errors, but exactly how to do that
is not entirely
clear to me.

Maybe not so simple as first thought?

Tom
Marco van de Voort
2011-07-09 21:38:46 UTC
Permalink
Post by Marco van de Voort
Post by tbreeden
TYPE
? ?proc ? ? = PROCEDURE ;
PROCEDURE gdbm_open (a: charStar; b, c, d: INTEGER; e: proc) ;
Even a little bit simpler, the type definition here for "proc" is
unnecessary, as "PROC" is an M2 pervasive type of the same definition.
Not necessarily. gdbm.proc has a calling convention of gdbm (cdecl), while
system.PROC has whatever the M2 language system internal calling convention is.
In some compilers (specially non x86) this might be the same, but it is not
an absolute rule, and defining a separate time for it is smart.
That makes sense, especially if the procedure being passed has parameters
itself. In this case, the .h file gives no information about whether it
does or no, but seems to imply that it does not. In which case, is
putting the TYPE proc = PROCEDURE; within the 'DEFINITION MODULE FOR "C"'
enough to ensure that the M2 compiler will type check enforce that the
passed procedure is also defined within a 'DEFINITION MODULE FOR "C"'
definition block ?
No idea. Maybe not even defined if the "FOR C" bit is a GM2 extension, since
GM2 probably has cdecl everywhere, so it will be hard to say what is
implementatation defined or language.
Consulting the gdbm docs, it looks like that proc is called from gdbm_open
on a Fatal Error and actually does have a parameter, and actually does
have a parameter, a string (message?). So will the type definition be
better as "TYPE proc = PROCEDURE(ARRAY OF CHAR)" ?
The fact that it works if parameters are omitted points to cdecl as assumed
calling convention. That is not a property of all calling conventions.
Or, it looks from the gdbm docs that you can pass null for the last
parameter here and get a default handling of fatal errors, but exactly how
to do that is not entirely clear to me.
Ah well, I peeked at the FPC implementation and saw the callback type def
had no cdecl. At least something good came out of this discussion.
Maybe not so simple as first thought?
In addition to the above, calling convention/ABI might not be just about
parameter passing, but can also be about e.g. alignment or other processor
features. (coprocessor mask also comes to mind).

A more wellknown one is safecall, which transforms SEH exceptions into
return values.

Loading...