summary refs log tree commit diff stats
path: root/doc/c2nim.txt
blob: c485a57f1f2a22b51099b1a30985791d0f6e6e0d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
=================================
  c2nim  User's manual
=================================

:Author: Andreas Rumpf
:Version: |nimrodversion|

.. contents::

Introduction
============

c2nim is a tool to translate Ansi C code to Nimrod. The output is 
human-readable Nimrod code that is meant to be tweaked by hand after the 
translation process. c2nim is no real compiler!

c2nim is preliminary meant to translate C header files. Because of this, the 
preprocessor is part of the parser. For example:

.. code-block:: C
  #define abc 123
  #define xyz 789
  
Is translated into:

.. code-block:: Nimrod
  const
    abc* = 123
    xyz* = 789
    

c2nim is meant to translate fragments of C code and thus does not follow 
include files. c2nim cannot parse all of Ansi C and many constructs cannot
be represented in Nimrod: for example `duff's device`:idx: cannot be translated
to Nimrod. 


Preprocessor support
====================

Even though the translation process is not perfect, it is often the case that
the translated Nimrod code does not need any tweaking by hand. In other cases
it may be preferable to modify the input file instead of the generated Nimrod
code so that c2nim can parse it properly. c2nim's preprocessor defines the 
symbol ``C2NIM`` that can be used to mark code sections: 

.. code-block:: C
  #ifndef C2NIM
    // C2NIM should ignore this prototype:
    int fprintf(FILE* f, const char* frmt, ...);
  #endif
  
The ``C2NIM`` symbol is only recognized in ``#ifdef`` and ``#ifndef`` 
constructs! ``#if defined(C2NIM)`` does **not** work. 

c2nim *processes* ``#ifdef C2NIM`` and ``#ifndef C2NIM`` directives, but other
``#if[def]`` directives are *translated* into Nimrod's ``when`` construct: 

.. code-block:: C
  #ifdef DEBUG
  #  define OUT(x) printf("%s\n", x)
  #else
  #  define OUT(x)
  #endif
  
Is translated into:

.. code-block:: Nimrod
  when defined(debug):
    template OUT*(x: expr): expr = 
      printf("%s\x0A", x)
  else:
    template OUT*(x: expr): stmt = 
      nil
  
As can been seen from the example, C's macros with parameters are mapped
to Nimrod's templates. This mapping is the best one can do, but it is of course
not accurate: Nimrod's templates operate on syntax trees whereas C's 
macros work on the token level. c2nim cannot translate any macro that contains
the ``##`` token concatenation operator.

c2nim's preprocessor supports special directives that affect how the output
is generated. They should be put into a ``#ifdef C2NIM`` section so that 
ordinary C compilers ignore them.


``#skipinclude`` directive
--------------------------
**Note**: There is also a ``--skipinclude`` command line option that can be 
used for the same purpose.

By default, c2nim translates an ``#include`` that is not followed by ``<`` 
(like in ``#include <stdlib>``) to a Nimrod ``import`` statement. This 
directive tells c2nim to just skip any ``#include``. 


``#stdcall`` and ``#cdecl`` directives
--------------------------------------
**Note**: There are also ``--stdcall`` and ``--cdecl`` command line options
that can be used for the same purpose.

These directives tell c2nim that it should annotate every proc (or proc type)
with the ``stdcall`` / ``cdecl`` calling convention.


``#dynlib`` directive
---------------------
**Note**: There is also a ``--dynlib`` command line option that can be used for
the same purpose.

This directive tells c2nim that it should annotate every proc that resulted
from a C function prototype with the ``dynlib`` pragma:
 
.. code-block:: C
  
  #ifdef C2NIM
  #  dynlib iupdll
  #  cdecl
  #  if defined(windows)
  #    define iupdll "iup.dll"
  #  elif defined(macosx)
  #    define iupdll "libiup.dynlib"
  #  else
  #    define iupdll "libiup.so"
  #  endif
  #endif
  
  int IupConvertXYToPos(PIhandle ih, int x, int y);

Is translated to:
  
.. code-block:: Nimrod
  when defined(windows):
    const iupdll* = "iup.dll"
  elif defined(macosx):
    const iupdll* = "libiup.dynlib"
  else:
    const iupdll* = "libiup.so"
  
  proc IupConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
    importc: "IupConvertXYToPos", cdecl, dynlib: iupdll.}

Note how the example contains extra C code to declare the ``iupdll`` symbol
in the generated Nimrod code.


``#header`` directive
---------------------
**Note**: There is also a ``--header`` command line option that can be used for
the same purpose.

The ``#header`` directive tells c2nim that it should annotate every proc that
resulted from a C function prototype and every exported variable and type with
the ``header`` pragma:

.. code-block:: C
  
  #ifdef C2NIM
  #  header "iup.h"
  #endif
  
  int IupConvertXYToPos(PIhandle ih, int x, int y);

Is translated to:
  
.. code-block:: Nimrod
  proc IupConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
    importc: "IupConvertXYToPos", header: "iup.h".}

The ``#header`` and the ``#dynlib`` directives are mutually exclusive. 
A binding that uses ``dynlib`` is much more preferable over one that uses
``header``! The Nimrod compiler might drop support for the ``header`` pragma
in the future as it cannot work for backends that do not generate C code.


``#prefix`` and ``#suffix`` directives
--------------------------------------

**Note**: There are also ``--prefix`` and ``--suffix`` command line options
that can be used for the same purpose.

c2nim does not do any name mangling by default. However the 
``#prefix`` and ``#suffix`` directives can be used to strip prefixes and
suffixes from the identifiers in the C code: 
 
.. code-block:: C
  
  #ifdef C2NIM
  #  prefix Iup
  #  dynlib dllname
  #  cdecl
  #endif
  
  int IupConvertXYToPos(PIhandle ih, int x, int y);

Is translated to:
  
.. code-block:: Nimrod

  proc ConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
    importc: "IupConvertXYToPos", cdecl, dynlib: dllname.}


``#mangle`` directive
---------------------

Even more sophisticated name mangling can be achieved by the ``#mangle`` 
directive: It takes a PEG pattern and format string that specify how the
identifier should be converted: 

.. code-block:: C
  #mangle "'GTK_'{.*}" "TGtk$1"

For convenience the PEG pattern and the replacement can be single identifiers
too, there is no need to quote them: 

.. code-block:: C
  #mangle ssize_t  int
  // is short for:
  #mangle "'ssize_t'" "int"


``#private`` directive
----------------------

By default c2nim marks every top level identifier (proc name, variable, etc.)
as exported (the export marker is ``*`` in Nimrod). With the ``#private`` 
directive identifiers can be marked as private so that the resulting Nimrod
module does not export them. The ``#private`` directive takes a PEG pattern:

.. code-block:: C
  #private "@('_'!.)" // all identifiers ending in '_' are private
  
Note: The pattern refers to the original C identifiers, not to the resulting
identifiers after mangling!


``#skipcomments`` directive
---------------------------
**Note**: There is also a ``--skipcomments`` command line option that can be
used for the same purpose.

The ``#skipcomments`` directive can be put into the C code to make c2nim
ignore comments and not copy them into the generated Nimrod file.


``#typeprefixes`` directive
---------------------------
**Note**: There is also a ``--typeprefixes`` command line option that can be
used for the same purpose.

The ``#typeprefixes`` directive can be put into the C code to make c2nim
generate the ``T`` or ``P`` prefix for every defined type.


``#def`` directive
------------------

Often C code contains special macros that affect the declaration of a function
prototype but confuse c2nim's parser:

.. code-block:: C
  // does not parse!
  EXTERN(int) f(void);
  EXTERN(int) g(void);

Instead of removing ``EXTERN()`` from the input source file (which cannot be 
done reliably even with a regular expression!), one can tell c2nim
that ``EXPORT`` is a macro that should be expanded by c2nim too:

.. code-block:: C
  #ifdef C2NIM
  #  def EXTERN(x) static x
  #endif
  // parses now!
  EXTERN(int) f(void);
  EXTERN(int) g(void);
  
``#def`` is very similar to C's ``#define``, so in general the macro definition
can be copied and pasted into a ``#def`` directive.


Limitations
===========

* C's ``,`` operator (comma operator) is not supported.
* C's ``union`` are translated to Nimrod's objects and only the first field
  is included in the object type. This way there is a high chance that it is
  binary compatible to the union.
* The condition in a ``do while(condition)`` statement must be ``0``.
* Lots of other small issues...