Difference between revisions of "Common problems when converting C header files"

From Lazarus wiki
Jump to navigationJump to search
(syntaxhighlight and category)
Line 6: Line 6:
  
 
Some header files contain the C++ namespace block:
 
Some header files contain the C++ namespace block:
  #if defined(__cplusplus)
+
<syntaxhighlight lang="c">
  extern "C" {
+
#if defined(__cplusplus)
  #endif
+
extern "C" {
  ...
+
#endif
  #if defined(__cplusplus)
+
...
  }
+
#if defined(__cplusplus)
  #endif
+
}
 +
#endif
 +
</syntaxhighlight>
  
 
Fix: Add the '''Remove C++ 'extern "C"' lines''' or the '''Pre H2Pas''' tool to the '''before h2pas''' tools.
 
Fix: Add the '''Remove C++ 'extern "C"' lines''' or the '''Pre H2Pas''' tool to the '''before h2pas''' tools.
Line 19: Line 21:
  
 
Some header files contain empty macros used for further extensions:
 
Some header files contain empty macros used for further extensions:
  #define MPI_FILE_DEFINED
+
<syntaxhighlight lang="c">#define MPI_FILE_DEFINED</syntaxhighlight>
  
 
Fix: Add the '''Remove empty C macros''' or the '''Pre H2Pas''' tool to the '''before h2pas''' tools.
 
Fix: Add the '''Remove empty C macros''' or the '''Pre H2Pas''' tool to the '''before h2pas''' tools.
Line 26: Line 28:
  
 
C allows implicit arrays in parameter types. For example:
 
C allows implicit arrays in parameter types. For example:
  int MPI_Group_range_incl(MPI_Group, int, int [][3], MPI_Group *);
+
<syntaxhighlight lang="c">int MPI_Group_range_incl(MPI_Group, int, int [][3], MPI_Group *);</syntaxhighlight>
  
 
The int [][3] is an implicit type, which is not allowed under Pascal. h2pas supports adding pointer types. So, it enough to replace all [] with *.
 
The int [][3] is an implicit type, which is not allowed under Pascal. h2pas supports adding pointer types. So, it enough to replace all [] with *.
Line 35: Line 37:
  
 
Some header files contain typed 0 pointers:
 
Some header files contain typed 0 pointers:
  #define MPI_BOTTOM      (void *)0
+
<syntaxhighlight lang="c">#define MPI_BOTTOM      (void *)0</syntaxhighlight>
  
 
Fix: Add the '''Replace macro values 0 pointer like (char *)0 with NULL''' or the '''Pre H2Pas''' tool to the '''before h2pas''' tools.
 
Fix: Add the '''Replace macro values 0 pointer like (char *)0 with NULL''' or the '''Pre H2Pas''' tool to the '''before h2pas''' tools.
Line 43: Line 45:
 
C allows to define function types, while pascal only allows pointers to functions. For example:
 
C allows to define function types, while pascal only allows pointers to functions. For example:
  
  typedef int (MPI_Comm_copy_attr_function)(MPI_Comm, int, void *, void *,
+
<syntaxhighlight lang="c">typedef int (MPI_Comm_copy_attr_function)(MPI_Comm, int, void *, void *,
                                         void *, int *);
+
                                         void *, int *);</syntaxhighlight>
  
 
The C header never uses this definition directly, instead it always uses pointers to such types '''MPI_Comm_copy_attr_function*''', for instace:
 
The C header never uses this definition directly, instead it always uses pointers to such types '''MPI_Comm_copy_attr_function*''', for instace:
  #define MPI_COMM_NULL_COPY_FN ((MPI_Comm_copy_attr_function*)0)
+
<syntaxhighlight lang="c">#define MPI_COMM_NULL_COPY_FN ((MPI_Comm_copy_attr_function*)0)</syntaxhighlight>
  
  
 
The translation can work this way: Make the function type a pointer. That means add a * in front of the definition and prepend a P and remove the * behind all references. For example:
 
The translation can work this way: Make the function type a pointer. That means add a * in front of the definition and prepend a P and remove the * behind all references. For example:
  
  typedef int (*PMPI_Comm_copy_attr_function)(MPI_Comm, int, void *, void *,
+
<syntaxhighlight lang="c">
 +
typedef int (*PMPI_Comm_copy_attr_function)(MPI_Comm, int, void *, void *,
 
                                         void *, int *);
 
                                         void *, int *);
  #define MPI_COMM_NULL_COPY_FN ((PMPI_Comm_copy_attr_function)0)
+
#define MPI_COMM_NULL_COPY_FN ((PMPI_Comm_copy_attr_function)0)
 
+
</syntaxhighlight>
  
 
Solution: Add the tool '''Convert function types to pointer''' or '''Pre H2Pas''' tool to the before h2pas tools.
 
Solution: Add the tool '''Convert function types to pointer''' or '''Pre H2Pas''' tool to the before h2pas tools.
Line 71: Line 74:
 
Change the code to
 
Change the code to
  
<pre>
+
<syntaxhighlight>
 
program MPIHelloWorld;
 
program MPIHelloWorld;
  
Line 86: Line 89:
 
   MPI_Finalize;
 
   MPI_Finalize;
 
end.
 
end.
</pre>
+
</syntaxhighlight>
  
 
Add the h2p/mpi.pas to the project. Project -> Add editor file to project.
 
Add the h2p/mpi.pas to the project. Project -> Add editor file to project.
Line 108: Line 111:
 
For example: '''mpi.pas(26,16) Error: Forward type not resolved "PMPI_Aint"'''
 
For example: '''mpi.pas(26,16) Error: Forward type not resolved "PMPI_Aint"'''
 
The error line is often a pointer type to a record:
 
The error line is often a pointer type to a record:
  PMPI_Aint = ^MPI_Aint;
+
<syntaxhighlight>PMPI_Aint = ^MPI_Aint;</syntaxhighlight>
 
h2pas adds PMPI_Aint to give nameless C pointers like *MPI_Aint a name. It adds the pointers to the start of the file. But pascal requires, that the forward definition is in the same '''type''' section.
 
h2pas adds PMPI_Aint to give nameless C pointers like *MPI_Aint a name. It adds the pointers to the start of the file. But pascal requires, that the forward definition is in the same '''type''' section.
 
Sometimes h2pas adds a pointer type, although it already exists.
 
Sometimes h2pas adds a pointer type, although it already exists.
Line 137: Line 140:
 
C allows implicits types in parameters. For example: ''int [][3]''. Pascal does not allow this, so you must give it a name and declare a type. But h2pas does not do this automatically and adds instead the implicit type in a quasi pascal syntax. For example:
 
C allows implicits types in parameters. For example: ''int [][3]''. Pascal does not allow this, so you must give it a name and declare a type. But h2pas does not do this automatically and adds instead the implicit type in a quasi pascal syntax. For example:
  
  int some_func(int [][3]);
+
<syntaxhighlight lang="c">int some_func(int [][3]);</syntaxhighlight>
  
 
becomes
 
becomes
  
  function some_func(_para1:array[0..2] of Plongint):longint;cdecl;external;
+
<syntaxhighlight>function some_func(_para1:array[0..2] of Plongint):longint;cdecl;external;</syntaxhighlight>
  
 
Fix: Luckily there is now a tool to remove these implicit types and add explicit types, it's called '''Replace implicit types'''. It is also part of the '''Post H2Pas''' tool. Add it to the ''after'' tool list.
 
Fix: Luckily there is now a tool to remove these implicit types and add explicit types, it's called '''Replace implicit types'''. It is also part of the '''Post H2Pas''' tool. Add it to the ''after'' tool list.
Line 163: Line 166:
  
 
In pascal forward defined types are only allowed in a type section. For example:
 
In pascal forward defined types are only allowed in a type section. For example:
  type
+
<syntaxhighlight>
    TMyRecord = record
+
type
      Next: PMyRecord; // using the forward definition
+
  TMyRecord = record
    end;
+
    Next: PMyRecord; // using the forward definition
    PMyRecord = ^TMyRecord;
+
  end;
 +
  PMyRecord = ^TMyRecord;
 +
</syntaxhighlight>
  
 
The below is not allowed, because the forward definition is in another type section:
 
The below is not allowed, because the forward definition is in another type section:
  type
+
<syntaxhighlight>
    TMyRecord = record
+
type
      Next: PMyRecord; // using the forward definition
+
  TMyRecord = record
    end;
+
    Next: PMyRecord; // using the forward definition
  type
+
  end;
    PMyRecord = ^TMyRecord;
+
type
 +
  PMyRecord = ^TMyRecord;
 +
</syntaxhighlight>
  
 
Solution: The code must be reordered. Add the tool fix forward definitions-
 
Solution: The code must be reordered. Add the tool fix forward definitions-
Line 188: Line 195:
  
 
The h2pas wizard can merge include files into one. For example first.h includes via the c include directive the file second.h. Select the second.h in the wizard and check the 'Merge file' feature. Then the source of second.h' will be appended to first.h before sending the output to h2pas. As always: This does not change the header files.
 
The h2pas wizard can merge include files into one. For example first.h includes via the c include directive the file second.h. Select the second.h in the wizard and check the 'Merge file' feature. Then the source of second.h' will be appended to first.h before sending the output to h2pas. As always: This does not change the header files.
 
  
  
Line 210: Line 216:
  
 
The mpi.h file defines MPI_File as pointer of ADIOI_FileD, but ADIOI_FileD is not defined public:
 
The mpi.h file defines MPI_File as pointer of ADIOI_FileD, but ADIOI_FileD is not defined public:
  typedef struct ADIOI_FileD *MPI_File;
+
<syntaxhighlight lang="c">typedef struct ADIOI_FileD *MPI_File;</syntaxhighlight>
 
The h2pas tool translated this to:
 
The h2pas tool translated this to:
    MPI_File = ^ADIOI_FileD;
+
<syntaxhighlight>MPI_File = ^ADIOI_FileD;</syntaxhighlight>
 
Because ADIOI_FileD is not defined public, it is a private structure, so you can simply replace it with a ''Pointer'':
 
Because ADIOI_FileD is not defined public, it is a private structure, so you can simply replace it with a ''Pointer'':
 
Add to the 'After h2pas' tools a new tool of type 'Search and replace' with the following properties:
 
Add to the 'After h2pas' tools a new tool of type 'Search and replace' with the following properties:
Line 236: Line 242:
  
 
Compiler gives ''Illegal expression'' on the following statement
 
Compiler gives ''Illegal expression'' on the following statement
  const
+
<syntaxhighlight>
    MPI_LONG_LONG = MPI_LONG_LONG_INT;
+
const
 +
  MPI_LONG_LONG = MPI_LONG_LONG_INT;
 +
</syntaxhighlight>
 
The reason is, that h2pas translated the MPI_LONG_LONG_INT constant to a function.
 
The reason is, that h2pas translated the MPI_LONG_LONG_INT constant to a function.
  
Line 243: Line 251:
  
 
Replace the  
 
Replace the  
  #define MPI_LONG_LONG  MPI_LONG_LONG_INT
+
<syntaxhighlight lang="c">#define MPI_LONG_LONG  MPI_LONG_LONG_INT</syntaxhighlight>
 
with
 
with
  #define MPI_LONG_LONG      ((MPI_Datatype)0x4c000809)
+
<syntaxhighlight lang="c">#define MPI_LONG_LONG      ((MPI_Datatype)0x4c000809)</syntaxhighlight>
 
by adding a '''Search and replace''' tool before h2pas.
 
by adding a '''Search and replace''' tool before h2pas.
  
Line 261: Line 269:
  
 
For example: Many C headers are enclosed in  
 
For example: Many C headers are enclosed in  
  {$IFNDEF FOO}
+
<syntaxhighlight>
  {$DEFINE FOO}
+
{$IFNDEF FOO}
  ...
+
{$DEFINE FOO}
  {$ENDIF}
+
...
 +
{$ENDIF}
 +
</syntaxhighlight>
  
 
This trick allows to include a C header file multiple times - like the units under pascal. So, pascal does not need this. Therefore the tool ''Reduce compiler directives in pascal file'' and the '''Post H2Pas''' tool have two properties: ''Defines'' and ''Undefines''. Click on the ''...'' button of the property to edit them. Each line can contain a macroname, that should be (un)defined. Add the line ''FOO'' to the ''Undefines''. This way the '''$IFNDEF FOO''' is always true and the tool will remove it. The '''$DEFINE FOO''' is now unneeded too and will be removed too.
 
This trick allows to include a C header file multiple times - like the units under pascal. So, pascal does not need this. Therefore the tool ''Reduce compiler directives in pascal file'' and the '''Post H2Pas''' tool have two properties: ''Defines'' and ''Undefines''. Click on the ''...'' button of the property to edit them. Each line can contain a macroname, that should be (un)defined. Add the line ''FOO'' to the ''Undefines''. This way the '''$IFNDEF FOO''' is always true and the tool will remove it. The '''$DEFINE FOO''' is now unneeded too and will be removed too.
Line 300: Line 310:
  
 
h2pas converts macros like  
 
h2pas converts macros like  
  #define A B
+
<syntaxhighlight lang="c">#define A B</syntaxhighlight>
 
to
 
to
  const A = B;
+
<syntaxhighlight>const A = B;</syntaxhighlight>
 
which is almost always correct. But some c header contain aliases for types, variables and functions too.
 
which is almost always correct. But some c header contain aliases for types, variables and functions too.
  
Line 308: Line 318:
  
 
The mpi.h contains the macro
 
The mpi.h contains the macro
  #define MPI_LONG_LONG      MPI_LONG_LONG_INT
+
<syntaxhighlight lang="c">#define MPI_LONG_LONG      MPI_LONG_LONG_INT</syntaxhighlight>
 
h2pas converts this simply to
 
h2pas converts this simply to
  const
+
<syntaxhighlight>
    MPI_LONG_LONG = MPI_LONG_LONG_INT;     
+
const
 +
  MPI_LONG_LONG = MPI_LONG_LONG_INT;     
 +
</syntaxhighlight>
 
but MPI_LONG_LONG_INT is a function.
 
but MPI_LONG_LONG_INT is a function.
  
Line 318: Line 330:
  
 
Note: This tool can also fix alias to external functions. For example:
 
Note: This tool can also fix alias to external functions. For example:
  function ExternalFunc1(_para1:longint; _para2:pointer):longint;cdecl;external name 'ExternalFunc1';
+
<syntaxhighlight>
  const
+
function ExternalFunc1(_para1:longint; _para2:pointer):longint;cdecl;external name 'ExternalFunc1';
    ExternalFuncAlias1 = ExternalFunc1;// should be replaced with full declaration
+
const
 +
  ExternalFuncAlias1 = ExternalFunc1;// should be replaced with full declaration
 +
</syntaxhighlight>
  
 
==h2pas creates functions for constants==
 
==h2pas creates functions for constants==
  
 
For example:
 
For example:
  function MPI_2COMPLEX : MPI_Datatype;
+
<syntaxhighlight>
      begin
+
function MPI_2COMPLEX : MPI_Datatype;
        MPI_2COMPLEX:=MPI_Datatype(MPI_DATATYPE_NULL);
+
begin
      end;
+
  MPI_2COMPLEX:=MPI_Datatype(MPI_DATATYPE_NULL);
 +
end;
 +
</syntaxhighlight>
 +
 
 
All used identifiers are types and constants, so this function can be replaced with a simple constant.
 
All used identifiers are types and constants, so this function can be replaced with a simple constant.
 
This is checked and done by the tool '''Replace simple functions with constants''' or the '''Post H2Pas'''.
 
This is checked and done by the tool '''Replace simple functions with constants''' or the '''Post H2Pas'''.
Line 335: Line 352:
  
 
For example:
 
For example:
  function PMPI_Win_f2c(win : longint) : MPI_Win;
+
<syntaxhighlight>
    begin
+
function PMPI_Win_f2c(win : longint) : MPI_Win;
      PMPI_Win_f2c:=MPI_Win(win);
+
begin
    end;
+
  PMPI_Win_f2c:=MPI_Win(win);
 +
end;
 +
</syntaxhighlight>
 
This function can be replaced with a simple type, resulting in a type cast.
 
This function can be replaced with a simple type, resulting in a type cast.
 
This is checked and done by the tool '''Replace simple functions with type casts''' or the '''Post H2Pas''' tool.
 
This is checked and done by the tool '''Replace simple functions with type casts''' or the '''Post H2Pas''' tool.
Line 345: Line 364:
  
 
C allows much more forward definitions than pascal, so the definitions must be topologically sorted. For example:
 
C allows much more forward definitions than pascal, so the definitions must be topologically sorted. For example:
  type
+
<syntaxhighlight>
    PMPI_Datatype  = ^MPI_Datatype;
+
type
    MPI_Datatype = longint;
+
  PMPI_Datatype  = ^MPI_Datatype;
 +
  MPI_Datatype = longint;
 +
</syntaxhighlight>
  
 
The pointer PMPI_Datatype must be moved to the same type section as MPI_Datatype.
 
The pointer PMPI_Datatype must be moved to the same type section as MPI_Datatype.
Line 357: Line 378:
  
 
For example there is an ugly function without parameter names:
 
For example there is an ugly function without parameter names:
  int MPI_Intercomm_create(MPI_Comm, int, MPI_Comm, int, int, MPI_Comm * );
+
<syntaxhighlight lang="c">int MPI_Intercomm_create(MPI_Comm, int, MPI_Comm, int, int, MPI_Comm * );</syntaxhighlight>
 
The parameter names are defined in the corresponding .c file:
 
The parameter names are defined in the corresponding .c file:
  int MPI_Intercomm_create(MPI_Comm local_comm, int local_leader,  
+
<syntaxhighlight lang="c">
                          MPI_Comm peer_comm, int remote_leader, int tag,  
+
int MPI_Intercomm_create(MPI_Comm local_comm, int local_leader,  
                          MPI_Comm *newintercomm)
+
                        MPI_Comm peer_comm, int remote_leader, int tag,  
 +
                        MPI_Comm *newintercomm)
 +
</syntaxhighlight>
  
 
Solution: There is no solution yet. Except manual editing or searching for other .h files. Often such .h files were auto generated and there are some nicer header files somewhere on the internet.
 
Solution: There is no solution yet. Except manual editing or searching for other .h files. Often such .h files were auto generated and there are some nicer header files somewhere on the internet.
Line 371: Line 394:
 
I'm impressed by the power of lua scripting language and how easy it's to do funny things with it.
 
I'm impressed by the power of lua scripting language and how easy it's to do funny things with it.
  
<pre>
+
<syntaxhighlight lang="lua">
 
--
 
--
 
-- Please send any improvement to mingodadATgmailDOTcom.
 
-- Please send any improvement to mingodadATgmailDOTcom.
Line 840: Line 863:
 
-- print the results
 
-- print the results
 
print(pasbody)
 
print(pasbody)
</pre>
+
</syntaxhighlight>
  
 
Here is an example of a c file converted.
 
Here is an example of a c file converted.
  
<pre>
+
<syntaxhighlight>
 
//uses lua, llimits, lmem, lstate, lzio;
 
//uses lua, llimits, lmem, lstate, lzio;
 
(*
 
(*
Line 939: Line 962:
 
   exit(buff.buffer);
 
   exit(buff.buffer);
 
end;
 
end;
</pre>
+
</syntaxhighlight>
 +
 
 +
[[Category:Tutorials]]

Revision as of 14:22, 15 April 2012

h2pas reports an error

Here is a list of common C structures, not recognized by h2pas and how to fix them:

h2pas problem: extern "C"

Some header files contain the C++ namespace block:

#if defined(__cplusplus)
extern "C" {
#endif
...
#if defined(__cplusplus)
}
#endif

Fix: Add the Remove C++ 'extern "C"' lines or the Pre H2Pas tool to the before h2pas tools.

h2pas problem: Empty macro

Some header files contain empty macros used for further extensions:

#define MPI_FILE_DEFINED

Fix: Add the Remove empty C macros or the Pre H2Pas tool to the before h2pas tools.

h2pas problem: Implicit array types

C allows implicit arrays in parameter types. For example:

int MPI_Group_range_incl(MPI_Group, int, int [][3], MPI_Group *);

The int [][3] is an implicit type, which is not allowed under Pascal. h2pas supports adding pointer types. So, it enough to replace all [] with *.

Fix: Add the Replace [] with * or the Pre H2Pas tool to the before h2pas tools.

h2pas problem: Makros for 0 pointers

Some header files contain typed 0 pointers:

#define MPI_BOTTOM      (void *)0

Fix: Add the Replace macro values 0 pointer like (char *)0 with NULL or the Pre H2Pas tool to the before h2pas tools.

h2pas problem: function types are silently skipped

C allows to define function types, while pascal only allows pointers to functions. For example:

typedef int (MPI_Comm_copy_attr_function)(MPI_Comm, int, void *, void *,
                                        void *, int *);

The C header never uses this definition directly, instead it always uses pointers to such types MPI_Comm_copy_attr_function*, for instace:

#define MPI_COMM_NULL_COPY_FN ((MPI_Comm_copy_attr_function*)0)


The translation can work this way: Make the function type a pointer. That means add a * in front of the definition and prepend a P and remove the * behind all references. For example:

typedef int (*PMPI_Comm_copy_attr_function)(MPI_Comm, int, void *, void *,
                                        void *, int *);
#define MPI_COMM_NULL_COPY_FN ((PMPI_Comm_copy_attr_function)0)

Solution: Add the tool Convert function types to pointer or Pre H2Pas tool to the before h2pas tools.

Test compilation and add tools to beautify the output

When h2pas runs without errors it has created a pascal file. The -i switch defines if it is a unit or an include file. The next step is test compilation. Setup up a test project that uses the new pascal source. Then use the 'Run h2pas and compile' button in the h2pas wizard.

Example: MPICH2

Create a new project with Project -> New Project -> Program. Save it a mpihelloworld. Change the code to

program MPIHelloWorld;

{$mode objfpc}{$H+}
{$linklib mpich}
{$linklib rt}

uses
  {$IFDEF UNIX}pthreads{$ENDIF}, MPI;

begin
  MPI_Init(@argc, @argv);
  writeln('Hello, world.');
  MPI_Finalize;
end.

Add the h2p/mpi.pas to the project. Project -> Add editor file to project.

Common compiler errors on h2pas output

Sometimes h2pas does not create valid pascal code. Here are the common problems and how to fix them.

Unit name contains the file path

h2pas sometimes add the whole path to the unitname.

Fix: Add Replace "unit filename;" with "unit name;" or the Post H2Pas tool to the After h2pas tools.

Missing include files

h2pas converts #include directives to pascal {$i } directives. If you create a unit for each header file, then you can remove all include directives with the tool Remove includes or the Post H2Pas.

Forward type not resolved

For example: mpi.pas(26,16) Error: Forward type not resolved "PMPI_Aint" The error line is often a pointer type to a record:

PMPI_Aint = ^MPI_Aint;

h2pas adds PMPI_Aint to give nameless C pointers like *MPI_Aint a name. It adds the pointers to the start of the file. But pascal requires, that the forward definition is in the same type section. Sometimes h2pas adds a pointer type, although it already exists.

Fix: Add the tool Remove redefined pointer types or the Post H2Pas to the After h2pas tools.

Removing system types

h2pas adds some system types, like PLongint, which are nowadays part of the system unit.

Fix: Add Remove type redefinitons like PLongint or the Post H2Pas tool to the After h2pas tools.

Empty type/var/const sections

After the above tools removed some variables, types, constants some setions become empty, which is not allowed in pascal.

Fix: Add Remove empty type/var/const sections or the Post H2Pas tool to the After h2pas tools.

h2pas forgets to add IFDEFs for function bodies

h2pas converts macros to functions. But if the macro was in an IFDEF block, h2pas does not add IFDEFs around the function body.

Fix: Add the tool Add missing h2pas IFDEFs for function bodies or the Post H2Pas. Add this right in front of the tool Reduce compiler directives in pascal file.

Implicit Types

C allows implicits types in parameters. For example: int [][3]. Pascal does not allow this, so you must give it a name and declare a type. But h2pas does not do this automatically and adds instead the implicit type in a quasi pascal syntax. For example:

int some_func(int [][3]);

becomes

function some_func(_para1:array[0..2] of Plongint):longint;cdecl;external;

Fix: Luckily there is now a tool to remove these implicit types and add explicit types, it's called Replace implicit types. It is also part of the Post H2Pas tool. Add it to the after tool list.

Array of nothing

Sometimes h2pas converts the C ellipsis parameter type '...' wrongly to 'array of )'. It should be 'array of const)'.

Fix: Add the tool Fix open arrays or the Post H2Pas to the after tools.

Identifier not found

There are three cases:

The identifier is defined in the unit, but after it is used

In pascal forward defined types are only allowed in a type section. For example:

type
  TMyRecord = record
    Next: PMyRecord; // using the forward definition
  end;
  PMyRecord = ^TMyRecord;

The below is not allowed, because the forward definition is in another type section:

type
  TMyRecord = record
    Next: PMyRecord; // using the forward definition
  end;
type
  PMyRecord = ^TMyRecord;

Solution: The code must be reordered. Add the tool fix forward definitions-

The identifier is defined in another unit (another .h file)

Solution 1: Add the unit to the uses section

If the other unit is already using this unit, then you have a circle. A circle dependency is allowed between .h files, but not between pascal units. In this case you must move code between both units or use IFDEFs like the gtk2 bindings or use the below merge function of the h2pas wizard.

Solution 2: Merge the two include files

The h2pas wizard can merge include files into one. For example first.h includes via the c include directive the file second.h. Select the second.h in the wizard and check the 'Merge file' feature. Then the source of second.h' will be appended to first.h before sending the output to h2pas. As always: This does not change the header files.


Example: MPICH2

The type MPI_Request is defined in mpi.h and used in mpio.h. Both c header files heavily use each other, so you can not put them into two separated units. Select mpio.h and enable the 'Merge file' function.

The identifier is a pointer to an existing type, but h2pas forgot to add it

Solution: Add the tool Add missing pointer types like PPPChar or the Post H2Pas tool to the after H2Pas tools.

The identifier is not defined anywhere

Probably you are missing a header file or you are using one with the wrong version or it is private identifier.

Solution: Search the header file and convert it too. If you can not find it or you don't want to translate this file, you can comment the identifier or replace it.

Example: MPICH2

Note: this is just a demonstration. The real solution for the MPICH2 headers is to setup the Defines correct, so that the below example vanishes automatically.

The mpi.h file defines MPI_File as pointer of ADIOI_FileD, but ADIOI_FileD is not defined public:

typedef struct ADIOI_FileD *MPI_File;

The h2pas tool translated this to:

MPI_File = ^ADIOI_FileD;

Because ADIOI_FileD is not defined public, it is a private structure, so you can simply replace it with a Pointer: Add to the 'After h2pas' tools a new tool of type 'Search and replace' with the following properties:

Property Value
Caption Replace ADIOI_FileD with Pointer
Name ReplaceADIOI_FileDwithPointer
SearchFor ADIOI_FileD
ReplaceWith Pointer
Options [trtMatchCase,trtWholeWord]

Illegal expression

Example: MPICH2

Compiler gives Illegal expression on the following statement

const
   MPI_LONG_LONG = MPI_LONG_LONG_INT;

The reason is, that h2pas translated the MPI_LONG_LONG_INT constant to a function.

Solution: Fix h2pas or use a trick:

Replace the

#define MPI_LONG_LONG   MPI_LONG_LONG_INT

with

#define MPI_LONG_LONG      ((MPI_Datatype)0x4c000809)

by adding a Search and replace tool before h2pas.

Common other issues

The pascal file contains a lot of unneccessary ifdef

h2pas translates even the C #ifdef directives. Many of them are C specific and not needed under FPC and can even make it impossible many tools on this side to explore the code. That's why there is a tool to clean up and disable or remove many unneeded IFDEFs: Reduce compiler directives in pascal file. Do not forget to insert the tool Add missing h2pas IFDEFs for function bodies in front of it.

Hints about unneeded directives ($IFDEFs, $DEFINEs, ...)

You can see the directives in the Code Explorer.

The tool will only remove the $IFDEFs and $DEFINEs, that are unneeded on all platforms. That means for example a {$IFDEF CPU386} will not be removed - even if you are currently working on an intel 32 bit compatible machine it will not be removed. This allows to create platform independent bindings. Of course C headers often contain a lot of IFDEFs not needed under FPC (Delphi, Kylix, gpc, ...).

For example: Many C headers are enclosed in

{$IFNDEF FOO}
{$DEFINE FOO}
...
{$ENDIF}

This trick allows to include a C header file multiple times - like the units under pascal. So, pascal does not need this. Therefore the tool Reduce compiler directives in pascal file and the Post H2Pas tool have two properties: Defines and Undefines. Click on the ... button of the property to edit them. Each line can contain a macroname, that should be (un)defined. Add the line FOO to the Undefines. This way the $IFNDEF FOO is always true and the tool will remove it. The $DEFINE FOO is now unneeded too and will be removed too.

Example: MPICH2

Add the following to the Undefines property:

 MPI_INCLUDED
 MPIO_INCLUDE
 NEEDS_MPI_FINT
 MPI_BUILD_PROFILING
 MPICH_SUPPRESS_PROTOTYPES
 MPI_Wtime
 HAVE_MPICH2G2
 FOO
 HAVE_PRAGMA_HP_SEC_DEF


Add the following to the Defines property:

 MPICH2
 MPICH_NEW_MPIIO

The C header files contain redefinitions

This is ok for C compilers, because a type is the same if its definition is the same. But for Pascal each type is a different type.

Solution: Add the tool Remove redefinitions in pascal unit or the Post H2Pas to the after h2pas tools. As the name implies, it only works on units, not on include files. And it expect at least a valid pascal syntax. That's why it is important to add this tool after the tools that fix the pascal syntax like Replace "unit filename;" with "unit name;", Remove empty type/var/const sections, Remove includes, Replace implicit types and Fix open arrays.

Example: MPICH2

The mpi.h contains several redefinitions like MPIIMPL_HAVE_MPI_TYPE_CREATE_DARRAY. They can all be fixed with this tool.

Alias macros are always translated by h2pas to constants

h2pas converts macros like

#define A B

to

const A = B;

which is almost always correct. But some c header contain aliases for types, variables and functions too.

Example: MPICH2

The mpi.h contains the macro

#define MPI_LONG_LONG      MPI_LONG_LONG_INT

h2pas converts this simply to

const
   MPI_LONG_LONG = MPI_LONG_LONG_INT;

but MPI_LONG_LONG_INT is a function.


Solution: Add the tool Fixes section type of alias definitions in pascal unit or the Pre H2Pas tool to the Before H2Pas tools.

Note: This tool can also fix alias to external functions. For example:

function ExternalFunc1(_para1:longint; _para2:pointer):longint;cdecl;external name 'ExternalFunc1';
const
  ExternalFuncAlias1 = ExternalFunc1;// should be replaced with full declaration

h2pas creates functions for constants

For example:

function MPI_2COMPLEX : MPI_Datatype;
begin
  MPI_2COMPLEX:=MPI_Datatype(MPI_DATATYPE_NULL);
end;

All used identifiers are types and constants, so this function can be replaced with a simple constant. This is checked and done by the tool Replace simple functions with constants or the Post H2Pas.

h2pas creates functions for type casts

For example:

function PMPI_Win_f2c(win : longint) : MPI_Win;
begin
   PMPI_Win_f2c:=MPI_Win(win);
end;

This function can be replaced with a simple type, resulting in a type cast. This is checked and done by the tool Replace simple functions with type casts or the Post H2Pas tool.

Some identifiers are used before they are defined

C allows much more forward definitions than pascal, so the definitions must be topologically sorted. For example:

type
  PMPI_Datatype  = ^MPI_Datatype;
  MPI_Datatype = longint;

The pointer PMPI_Datatype must be moved to the same type section as MPI_Datatype.

Solution: Add the Fix forward definitions by reordering or the Pre H2Pas tool to the Before H2Pas tools. The tool should be put after the tools fixing redefinitions and types. At the moment the tool only moves pointer types. ToDo: reorder some more definitions like constants.


The C header files do not contain parameter names

For example there is an ugly function without parameter names:

int MPI_Intercomm_create(MPI_Comm, int, MPI_Comm, int, int, MPI_Comm * );

The parameter names are defined in the corresponding .c file:

int MPI_Intercomm_create(MPI_Comm local_comm, int local_leader, 
                         MPI_Comm peer_comm, int remote_leader, int tag, 
                         MPI_Comm *newintercomm)

Solution: There is no solution yet. Except manual editing or searching for other .h files. Often such .h files were auto generated and there are some nicer header files somewhere on the internet.

Proposal: Write a clever tool, that searches functions with missing parameter names and the corresponding functions in the .c files with parameter names and improve the .h file.

Another option to convert c to pascal with lua

I'm impressed by the power of lua scripting language and how easy it's to do funny things with it.

--
-- Please send any improvement to mingodadATgmailDOTcom.
--

inFileName = arg[1] or 'g:\\tmp\\plua\\clua\\lvm.c'

fh = assert(io.open(inFileName))
cbody = fh:read('*a')
fh:close()

pasbody = cbody

function split(str, pat)
   local t = {}  -- NOTE: use {n = 0} in Lua-5.0
   local fpat = '(.-)' .. pat
   local last_end = 1
   local s, e, cap = str:find(fpat, 1)
   while s do
      if s ~= 1 or cap ~= '' then
	table.insert(t, cap)
      end
      last_end = e+1
      s, e, cap = str:find(fpat, last_end)
   end
   if last_end <= #str then
      cap = str:sub(last_end)
      table.insert(t, cap)
   end
   return t
end

function trim(s)
  -- from PiL2 20.4
  return (s:gsub('^%s*(.-)%s*$', '%1'))
end

function trimChars(str, c1, c2)
	return str:gsub('^%' .. c1 .. '*(.-)%' .. c2 .. '*$', '%1')
end

function getPascalType(cType)
	if cType == 'void' then
		return 'pointer'
	elseif cType == 'int' then
		return 'integer'
	elseif cType == 'short' then
		return 'Shortint'
	elseif cType == 'define' then
		return 'is_define'
	else
		return cType
	end
end


--check var name and type
--if var starts with a capital letter
-- add 'T' informt of it
--if var is preceded by * then add a 'P' for type

function checkVarType(aType, aVar)
	aType = getPascalType(aType)
	aType = aType:gsub('^(%u)', 'T%1')
	aVar = aVar:gsub('^(%*)', function(m)
			aType = 'P' .. aType
			return ''
		end)
	aVar = aVar:gsub('(%[[^]]+%])', function(m)
			aType = 'array' .. m .. ' of ' .. aType
			return ''
		end)
	return aType, aVar
end

function varDeclaration(aType, aVar)
	aType, aVar = checkVarType(aType, aVar)
	return aVar .. ' : ' .. aType
end

function checkDeclarationOrGoto(m1, m2, m3)
	if m2 ~= 'goto' then
		return '\n' .. m1 .. varDeclaration(m2, m3) .. ';'
	else
		return '\n' .. m1 .. m2 .. ' ' .. m3 .. ';'
	end
end

function addProcFunc(mtype, mname, mparams, mbody)
	local str, isFunc, rType, k, v
	if mtype == 'void' then
		str = '\nprocedure '
		isFunc = false
	else
		str = '\nfunction '
		isFunc = true
	end
	mtype, mname = checkVarType(mtype, mname)
	local vparams = split(trimChars(mparams, '(',')'), ',')
	str = str .. mname .. '('

	local tparams = {}
	for k, v in pairs(vparams) do
		local vparam = split(trim(v), ' ')
		if #vparam > 2 then
			table.insert(tparams, vparam[1] .. ' ' .. varDeclaration(vparam[2], vparam[3]))
		else
			--print(vparam[1], vparam[2])
			table.insert(tparams, varDeclaration(vparam[1], vparam[2] or 'is_define'))
		end
	end

	str = str .. table.concat(tparams, '; ') .. ')'
	if isFunc then
		if mtype == 'int' then
			rType = 'integer'
		else
			rType = mtype
		end
		str = str .. ':' .. rType
	end

	if mbody then
		local tblLabels = {}
		for v in mbody:gmatch('\n[\t ]*([%w_]+)[\t ]*:[^=]') do
			if v ~= 'default' then
				table.insert(tblLabels, v)
			end
		end

		if #tblLabels > 0 then
			str = str .. ';\nlabel\n  '.. table.concat(tblLabels, ',  ')
		end

		local declarations = {}

		mbody = mbody:gsub('(\n[\t ]*)const[\t ]+([%w_]+)[\t ]+(%*?[%w_]+)[\t ]*:%=[\t ]*([^;\n]+;)','%1 %2 %3 := %4')

		mbody = mbody:gsub('(\n[\t ]*)([%w_]+)[\t ]+(%*?[%w_]+)[\t ]*:%=[\t ]*([^;\n]+;)', function(m1, m2, m3, m4)
			table.insert(declarations, varDeclaration(m2, m3) .. ';' )
			return m1 .. m3 .. ' := ' .. m4
		end)

		mbody = mbody:gsub('\n[\t ]*const[\t ]*([%w_]+)[\t ]+(%*?[%w_]+)[\t ]*;', function(m1,m2)
				table.insert(declarations, varDeclaration(m1, m2) .. ';')
				return ''
			end)

		mbody = mbody:gsub('\n([\t ]*)([%w_]+)[\t ]+(%*?[%w_ ,]+);', function(m1,m2,m3)
				if m2 ~= 'goto' then
					table.insert(declarations, varDeclaration(m2, m3) .. ';')
					return ''
				else
					return '\n' .. m1 .. m2 .. ' ' .. m3 .. ';'
				end
			end)


		if #declarations > 0 then
			local unique_decl = {}
			table.sort(declarations)
			local lastV = ''
			local k2, v2
			for k2,v2 in pairs(declarations) do
				if v2 ~= lastV then
					lastV = v2
					table.insert(unique_decl, v2)
				end
			end
			str = str .. ';\nvar\n  '.. table.concat(unique_decl, '\n  ')  .. '\n'
		else
			str = str .. ';\n'
		end

		str = str .. 'begin' .. trimChars(mbody, '{','}') .. 'end'
	end
	return str .. ';'
end

--*************************************
--
-- Order of substitutions are important
--
--*************************************

--=assignements statements
	pasbody = pasbody:gsub("([\t ]*)([%w_]+)[\t ]*=[\t ]*([^=;\n]+);", '%1%2 := %3;')

--return
	pasbody = pasbody:gsub('([\t ]*)return[\t ]+([^;]+);', '%1exit(%2);')

--NULL
	pasbody = pasbody:gsub('([^%w]+)NULL([^%w]+)', '%1nil%2')

--void functions to procedure declaratios
	pasbody = pasbody:gsub('([%w_*]+)[\t ]+([%w_*]+)[\t ]*(%b())[%s]*(%b{})', addProcFunc)
	--pasbody = pasbody:gsub('\n([%w_]+)%s+([^%s]+)%s*(%b());', addProcFunc)

--const/static
	tblLeaveCommented = {
		'const', 'static'
	}
	for k,v in pairs(tblLeaveCommented) do
		pasbody = pasbody:gsub('([\t ]*)(' .. v .. ')([\t ]*)', '%1{%2}%3')
	end

--defines to const
	isConstEmmited = false
	function addConst(m1,m2)
		local sm
		sm = ''
		if not isConstEmmited then
			isConstEmmited = true
			sm = '\nconst'
		end
		return sm .. '\n\t' .. m1 .. ' = ' .. m2 .. ';'
	end

	isConstEmmited = false
	pasbody = pasbody:gsub('\n#define%s+([^%s]+)%s+(%b())', '\nconst %1 = %2;')
	isConstEmmited = false
	pasbody = pasbody:gsub('\n#define%s+([^%s]+)[ \t]+([^%s]+)', '\nconst %1 = %2;')

--includes
	tblUses = {}
	pasbody = pasbody:gsub('\n#[ \t]*(include)%s+([^\n]+)', function(m1,m2)
			for w in m2:gmatch('"([^.]+)%..+"') do
				table.insert(tblUses, w)
			end
			return '\n//#' .. m1 .. ' ' .. m2
		end)
	pasbody = '//uses ' .. table.concat(tblUses, ', ') .. ';\n' .. pasbody

--defines to compiler directives
	pasbody = pasbody:gsub('\n#([^\n]+)', '\n{$%1}')

--comments
	pasbody = pasbody:gsub('\n#', '\n//#')
	pasbody = pasbody:gsub('/%*', '(*')
	pasbody = pasbody:gsub('%*/', '*)')

--declarations
	pasbody = pasbody:gsub('\n([\t ]*)([%w_]+)[\t ]+([%w_ ,]+);', checkDeclarationOrGoto)

--structs
	function parseStruct(m1, m2)
		return '\n' .. m1 .. ' = record\n' .. trimChars(m2, '{', '}') .. '\nend'
	end
	pasbody = pasbody:gsub('\n[\t ]*struct[\t ]+([%w_]+)[\t ]*(%b{})', parseStruct)

--if statements
	parseStatementCalled = false

	function parseStatement(mSpace, mStatement, mCond, mBody)
		parseStatementCalled = true
		local vStatement
		if mStatement == 'if' then
			vStatement = mStatement .. ' ' .. mCond .. ' then'
		elseif mStatement == 'else' then
			return mSpace .. mStatement .. ' begin' .. trimChars(mCond, '{', '}') .. ' end;'
		elseif (mStatement == 'while') then
			vStatement = mStatement .. ' ' .. mCond .. ' do'
		elseif (mStatement == 'for') then
			vStatement = mStatement .. ' ' .. mCond .. ' do'
			--local forArgs = split(trimChars(mCond, '(', ')'), ';')
			--return mSpace .. (forArgs[1] or '') .. ';' .. mSpace ..'while (' ..
			--	(forArgs[2] or 'true') .. ') do' .. mSpace .. 'begin' .. mSpace .. trimChars(mBody, '{', '}') .. '\n' .. mSpace ..
			--	(forArgs[3] or '') .. ';\n' .. mSpace .. 'end;'
		else
			vStatement = mStatement .. ' ' .. mCond .. '\n'
		end
		return mSpace .. vStatement .. ' begin' ..  trimChars(mBody, '{', '}') .. 'end;'
	end

	-- for nested blocks
	parseStatementCalled = true
	while(parseStatementCalled) do
		parseStatementCalled = false
		pasbody = pasbody:gsub('([^%w_])(if)[\t ]*(%b())[\t ]*(%b{})', parseStatement)
	end

	-- else
	pasbody = pasbody:gsub('([\t ]+)(else)[\t ]*(%b{})', parseStatement)

	pasbody = pasbody:gsub("([^%w_])if[\t ]*(%b())[\t ]*([^;\n]+);", '%1if %2 then %3;')

--?: short if
	pasbody = pasbody:gsub("([^?])?([^:;\n]):[\t ]*([^%s;]+);", ' iff(%1, %2, %3) ')

--while loop
	-- for nested blocks
	parseStatementCalled = true
	while(parseStatementCalled) do
		parseStatementCalled = false
		pasbody = pasbody:gsub('([^%w_])(while)[\t ]*(%b())[\t ]*(%b{})', parseStatement)
	end

--for loop
	-- for nested blocks
	parseStatementCalled = true
	while(parseStatementCalled) do
		parseStatementCalled = false
		pasbody = pasbody:gsub('([^%w_])(for)[\t ]*(%b())%s*(%b{})', parseStatement)
	end

--do/while
	-- for nested blocks
	parseStatementCalled = true
	while(parseStatementCalled) do
		parseStatementCalled = false
		pasbody = pasbody:gsub("([^%w_])do[\t ]*(%b{})[\t ]*while([^;\n]+);",
			function(m1, m2, m3)
				parseStatementCalled = true
				return m1 .. 'repeat ' .. trimChars(m2, '{', '}') .. 'until not' .. m3
			end)
	end


--switch/case statements

	--begin/end enclose blocks around
	-- for nested blocks
	parseStatementCalled = true
	while(parseStatementCalled) do
		parseStatementCalled = false
		pasbody = pasbody:gsub("([^%w_]case[\t ]+[^:]+)[\t ]*:[%s]*(%b{})",
			function(m1, m2, m3)
				parseStatementCalled = true
				return m1 .. ': begin' .. trimChars(m2, '{', '}') .. 'end;'
			end)
		pasbody = pasbody:gsub("([^%w_]default[\t ]*):[%s]*(%b{})",
			function(m1, m2, m3)
				parseStatementCalled = true
				return m1 .. ': begin' .. trimChars(m2, '{', '}') .. 'end;'
			end)
	end

	--breaks remove
	pasbody = pasbody:gsub("([^%w_]case[\t ]+[^:]+)[\t ]*:[%s]*(.-)break;", '%1: %2')

	--case
	pasbody = pasbody:gsub("([^%w_])case[\t ]+([^:]+):", '%1%2:')

	-- for nested blocks
	parseStatementCalled = true
	while(parseStatementCalled) do
		parseStatementCalled = false
		pasbody = pasbody:gsub("([^%w_])switch[\t ]*(%b())[\t ]*(%b{})",
			function(m1, m2, m3)
				parseStatementCalled = true
				return m1 .. 'case ' .. m2 .. ' of ' .. trimChars(m3, '{', '}') .. 'end;'
			end)
	end

	--pasbody = pasbody:gsub("([\t ]*)case[\t ]+('.')[\t ]*:\n", '%1%2:\n')
	--pasbody = pasbody:gsub("([\t ]*)case[\t ]+(%d+)[\t ]*:\n", '%1%2:\n')
	--pasbody = pasbody:gsub("([\t ]*)(case)[\t ]+('.')[\t ]*:[\t ]*(%b{})", '%1%2 : %3')

--pre/pos increments
	-- (n)++ -> PosInc(n)
	pasbody = pasbody:gsub("(%([^%s+]+%))%+%+", 'PosInc%1')
	-- n*++ -> PosInc(n*)
	pasbody = pasbody:gsub("([^%s*+]+)%+%+", 'PosInc(%1)')
	-- ++(n) -> PreInc(n)
	pasbody = pasbody:gsub("%+%+(%([^%s;+]+%))", 'PreInc%1')
	-- ++*n -> PreInc(n)
	pasbody = pasbody:gsub("%+%+([^%s*;+]+)", 'PreInc(%1)')

	-- (n)--
	pasbody = pasbody:gsub("(%([^%s-]+%))%-%-", 'PosDec%1')
	-- n*--
	pasbody = pasbody:gsub("([^%s*-]+)%-%-", 'PosDec(%1)')
	-- --(n)
	pasbody = pasbody:gsub("%-%-(%([^%s;-]+%))", 'PreDec%1')
	-- --n
	pasbody = pasbody:gsub("%-%-([^%s;-]+)", 'PreDec(%1)')

--boolean operators
	tblBooleanOperators = {
		{'||', 'or'},
		{'&&', 'and'},
	}
	for k,v in pairs(tblBooleanOperators) do
		pasbody = pasbody:gsub('([\t ]*)' .. v[1] .. '([\t ]*)', '%1) ' .. v[2] .. ' (%2')
	end


--pointers
	pasbody = pasbody:gsub("%->", '.')
	pasbody = pasbody:gsub("%(%*([%w_]+)", '(%1^')
	pasbody = pasbody:gsub("%*%*([%w_]+)", '%1^^')
	pasbody = pasbody:gsub("&([%w_]+)", '@%1')
	pasbody = pasbody:gsub("%*([%w_]+)[\t ]*:[\t ]*([%w_]+);", '%1 : ^%2;')
	pasbody = pasbody:gsub("%^char", 'pchar')
	--pasbody = pasbody:gsub("%*([%w_]+)[\t ]*:=[\t ]*([^;\n]+);", '%1^ := %2;')

--bit operators
	tblBitOperators = {
		{'<<', 'shl'},
		{'>>', 'shr'},
		{'|', 'or'},
		{'&', 'and'},
		{'~', 'not'},
	}

	for k,v in pairs(tblBitOperators) do
		pasbody = pasbody:gsub('([\t ]*)' .. v[1] .. '([\t ]*)', '%1 ' .. v[2] .. ' %2')
	end

--==eq operator
	pasbody = pasbody:gsub("([\t ]*)%=%=([\t ]*)", '%1 = %2')

--!= not eq operator
	pasbody = pasbody:gsub("([\t ]*)!%=([\t ]*)", '%1 <> %2')

--! unary
	pasbody = pasbody:gsub('([\t ]*)!([\t ]*)', '%1 not %2')

--blocks
	--pasbody = pasbody:gsub("(%b{})", function(m1) return 'begin' ..  trimChars(m1, '{', '}') .. 'end;' end)
	--pasbody = pasbody:gsub("(%b{})", function(m1) return 'begin' ..  trimChars(m1, '{', '}') .. 'end;' end)

--strings and escaped characters
	tblEscapedCahrs = {
		{'\\"', '"'},
		{'\\\\', '\\'},
		{'\\t', "'#9"},
		{'\\n', "'#10'"},
		{'\\f', "'#12'"},
	}
	pasbody = pasbody:gsub('%b""', function(m1)
			return "'" .. trimChars(m1:gsub("'", "''") , '"', '"')  .. "'"
		end)
	for k,v in pairs(tblEscapedCahrs) do
		pasbody = pasbody:gsub(v[1], v[2])
	end

--common functions/procedure
	tblOrigFuncNewFunc = {
		{'printf', 'format'},
		{'malloc', 'GetMem'},
		{'free', 'Dispose'},
		{'memcpy', 'Move'},
	}

	for k,v in pairs(tblOrigFuncNewFunc) do
		pasbody = pasbody:gsub('([\t ]+)' .. v[1] .. '%(', '%1' .. v[2] .. '(')
	end

--typedefs
	isTypeEmmited = false
	function addType(m1,m2)
		local sm
		sm = ''
		if not isTypeEmmited then
			isTypeEmmited = true
			sm = '\ntype'
		end
		return sm .. '\n\t' .. m2 .. ' = ' .. m1 .. ';'
	end
	--pasbody = pasbody:gsub('\ntypedef%s+struct%s+([^%s]+)%s+([^;]+)', addType)
	--pasbody = pasbody:gsub('\ntypedef%s+([^%s]+)%s+([^;]-)', addType)
	pasbody = pasbody:gsub('\n[\t ]*typedef[\t ]+struct[\t ]+([%w_]+)[\t ]+([^;]+)', '\n%2 = %1')
	pasbody = pasbody:gsub('\n[\t ]*typedef[\t ]+struct%s+(%b{})%s+([%w_]+);',
		function(m1, m2) return m2 .. ' = record' .. trimChars(m1, '{', '}') .. 'end;' end)


-- print the results
print(pasbody)

Here is an example of a c file converted.

//uses lua, llimits, lmem, lstate, lzio;
(*
** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
** a generic input stream interface
** See Copyright Notice in lua.h
*)


//#include <string.h>

{$define lzio_c}
{$define LUA_CORE}

//#include 'lua.h'

//#include 'llimits.h'
//#include 'lmem.h'
//#include 'lstate.h'
//#include 'lzio.h'



function luaZ_fill(z : PTZIO):integer;
var
  L : Plua_State;
  buff : Pchar;
  size : size_t;
begin
  *L := z.L;
  lua_unlock(L);
  buff := z.reader(L, z.data, @size);
  lua_lock(L);
  if (buff  =  nil ) or ( size  =  0) then exit(EOZ);
  z.n := size - 1;
  z.p := buff;
  exit(char2int(PosInc^((z.p))));
end;



function luaZ_lookahead(z : PTZIO):integer;
begin
  if (z.n  =  0) then begin
    if (luaZ_fill(z)  =  EOZ)
      exit(EOZ);
    else begin
      PosInc(z.n);  (* luaZ_fill removed first byte; put back it *)
      z-PosDec(>p);
     end;
  end;
  exit(char2int(z^.p));
end;



procedure luaZ_init(L : Plua_State; z : PTZIO; reader : lua_Reader; data : Ppointer);
begin
  z.L := L;
  z.reader := reader;
  z.data := data;
  z.n := 0;
  z.p := nil;
end;


(* --------------------------------------------------------------- read --- *)

function luaZ_read(z : PTZIO; b : Ppointer; n : size_t):size_t;
var
  m : size_t;
begin
  while (n) do begin
    if (luaZ_lookahead(z)  =  EOZ)
      exit(n);  (* exit(number of missing bytes *)
    m = (n <= z.n) ? n : z.n);  (* min. between n and z.n *)
    Move(b, z.p, m);
    z.n -= m;
    z.p += m;
    b := (char *)b + m;
    n -= m;
  end;
  exit(0);
end;

(* ------------------------------------------------------------------------ *)

function luaZ_openspace(L : Plua_State; buff : PTMbuffer; n : size_t):Pchar;
begin
  if (n > buff.buffsize) then begin
    if (n < LUA_MINBUFFER) then n := LUA_MINBUFFER;
    luaZ_resizebuffer(L, buff, n);
  end;
  exit(buff.buffer);
end;