================================= c2nim User's manual ================================= :Author: Andreas Rumpf :Version: 0.8.10 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. ``#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" ``#skip`` directive ------------------- **Note**: There is also ``--skip`` command line option that can be used for the same purpose. 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! EXPORT int f(void); EXPORT int g(void); Instead of to remove ``EXPORT`` from the input source file, one can tell c2nim to skip special identifiers: .. code-block:: C #skip EXPORT // does parse now! EXPORT int f(void); EXPORT int g(void); Limitations =========== * C's ``,`` operator (comma operator) is not supported. * C's ``union`` has no equivalent in Nimrod. * Standalone ``struct x {}`` declarations are not implemented. Put them into a ``typedef``. * The condition in a ``do while(condition)`` statement must be ``0``. * Lots of other small issues...