Pascal to C/C++ converter

- About PtoC
- PtoC installation
- Pascal runtime library emulation
  1. Arrays
  2. Sets
  3. Mathematical functions
  4. Input/Output
- BGI emulation
- Structure of converter
- Nested functions and call graph analysis
- Resolving name conflicts
- Passing parameters in C
- Passing parameters in C++
- Calling of C functions
- Array assignments
- Conversion of Turbo Pascal strings
- Some porting problems
  1. Representation of integer types
  2. Implementation of Pascal sets
  3. Enumeration types
- Style of converted sources
- Includes in ANSII Pascal
- PtoC options
- Known bugs
- PtoC distribution

## About PtoC

This is yet another Pascal to C/C++ converter. The primary idea of this converter is to produce readable and supportable code which preserves style of original code as far as possible.

Converter recognizes Pascal dialects which are compatible with Turbo Pascal 4.0/5.0 and ISO Pascal standard - IEC 7185:1990(E) (including conformant arrays). At this moment it was tested with Turbo Pascal, Oregon Pascal, Sun Pascal and HP Pascal.

Converter can produce both C++ and C output. Using of C++ language allows to encapsulate some Pascal types and constructions into C++ classes. So mapping between Pascal and C++ becomes more direct then between Pascal and C. I use C++ templates to implement Pascal arrays and files. Special template classes are used for conformant arrays. C++ like streams are used to implement Pascal IO routines. The same runtime library is used both for C and C++.

Now PtoC recognizes Turbo Pascal's extensions, such as units, strings, some special types and operations. Turbo Pascal extensions are supported only for C++ language.

At this moment PtoC successfully converts more than 400,000 lines of Oregon Pascal to C (from RSX to OpenVMS). To test C++ translation and conversion of Turbo Pascal extensions I convert BGIDEMO.PAS and LISTER.PAS files from Turbo Pascal distribution and also convert some numeric programs written on Turbo Pascal by my friends. To check quality of conversion please look in file bgidemo.cxx which was produces from original Borland bgidemo.pas without any manual changes. Moreover it is possible to compile it, link with WinBGI library and run it under Windows or X-Windows.

## PtoC installation

To build PtoC just try `make`. Converter consists of two executable files: `ptoc` - converter itself and `cganal` - analyzer of call graph, runtime library `libptoc.a`, configuration file for converter `ptoc.cfg`, Pascal header for converter `ptoc.pas` (`tptoc.pas` for Turbo Pascal) and include file for all converted sources `ptoc.h`. To run converter you should only specify path to directory with `ptoc` and `cganal`. To compile and link converted files you should specify for compiler and linker path to header file `ptoc.h` and library `libptoc.a`.

I compile PtoC at Unix with GCC or CXX (Digital C++ compiler). I hope that many other C++ compilers also can do it. In MS-Windows I use Microsoft Visual C++ 5.0. You should either explicitly specify name of makefile: `nmake -f makefile.mvc` or use `make.bat` which do exactly the same. Also makefile for Borland C++ `makefile.bcc` is prepared. To invoke Borland linker issue command `make.exe -f makefile.bcc` (`.exe` extension is significant, otherwise `make.bat` will be executed)

I have used converter in following way:

    rm */*.[ch] call.grp
    for name in */*.pas
    do
    $(PTOC_DIR)ptoc -I include -h -in $name -c -analyze -intset -init -unsigned
    done
    $(PTOC_DIR)cganal

In directory `examples` there are several Pascal files and makefile which converts and compiles this files. Examples will be build also by issuing `make` command. You can look in this makefile at the examples of using PTOC and compiling converted code. To compile sources produced from Turbo Pascal files, do not forget to specify `-DTURBO_PASCAL` option.

Directory WinBGI contains source and header file for BGI emulator for MS-Windows as well as makefile for Microsoft Visual C++ (makefile.mvc) and Borland C++ (makefile.bcc) to build this library. Directory Xbgi contains sources of BGI emulator for X-Windows.

Directory "vms" contains VMS specific versions of Pascal runtime library emulation module "io.c".

If you want to make some changes in scanner or parser you need GNU bison and flex. For MS-Windows you can download this tools for example from flexbison.zip. File produced by GNU flex contains reference to `unistd.h`. At Windows you can either remove this reference or create file with this name.

## Pascal runtime library emulation

### Arrays

All Pascal arrays in C are stored as zero based (first element has offset 0). Low value of Pascal array bounds is subtracted from index expression. When array is passed to conformant array parameter or to input/output functions Pascal array bounds are passed before array pointer. Low bound is always passed as it was mentioned in Pascal array definition (symbolic constant or integer literal). High bound is calculated depending on value of low bound (if it is explicit constant) and whether variable is formal parameter. if variable is not formal parameter and low bound is either 0 or 1 macro `items(x)` is used to calculate high array bound:

        #define items(x) (sizeof(x)/sizeof(*(x)))

          procedure foo(a : array [l1..h1,l2..h2:integer] of char); external;
          var a : array [1..10,-10..10] of char;
          begin foo(a); end;

        ==>

          foo(const int l1, const int h2, const int l2, const int h2,
              char* arr);
          char a[10][21];
          { foo(1, items(a), -10, items(*a), *a); }

If left operand is not formal parameter and hence 'sizeof' operation can be used to obtain array size two macros are used to copy and compare array:

          #define arrcmp(a,b) memcmp(a, b, sizeof(a))
          #define arrcpy(a,b) memcpy(a, b, sizeof(a))

If left operand is formal parameter sizeof operator is applied to it's type:

          foo(str5 s) {
             memcpy(s, "12345", sizeof(str5));
          }

When string is passed as actual parameter for conformant array macro `array(s)` is used to calculate bounds of string:

          #define array(s)  1, sizeof(s)-1, (s)

PtoC provides special type `zero_terminated_string` for passing zero terminated strings to C functions. Consider for example the following definition of function:

          function putenv(s : zero_terminated_string); external;

This function can be called in the following way:

        procedure foo(a : array [1..10] of char);
        begin
          putenv('VERSION=1');
          putenv(a);
        end;

    ==>

        void foo(array<1,10,char> a)
        {
          putenv("VERSION=1");
          putenv(lpsz(a));
        }

Function `lpsz(a)` converts array to zero terminated string. This function use static circular buffers for coping array elements to it and appending '\0' symbols at the end.

In C++ arrays are implemented by following template C++ classes:

`array<low_bound, high_bound, type>`
  One dimensional array with fixed bounds.
`conf_array<type>`
  Conformant array. for more details.
`matrix<low_1, high_1, low_2, high_2, type>`
  Two dimensional array with fixed bounds.
`conf_matrix<type>`
  Conformant two dimensional array.

See Passing parameters in C++ for more details about passing of array parameters.

Methods of classes `array, conf_array, matrix, conf_matrix` performs bounds checking by means of `assert()` statement. If, for example, array index is out of bounds, assertion will fail and program will be abnormally terminated. To avoid asserts overhead you should define `NDEBUG` macro (pass `-DNDEBUG` options to the C++ compiler).

### Sets

By default converter use single set type for all Pascal sets. This set type can handle sets with card up to 256 elements (consequently size of set is 256/8 = 32 bytes). Following functions implement Pascal operations with sets:

          boolean subset(set a, set b); /* if a is subset of b */
          boolean inset(SetElemType elem, set s);
          boolean equivalent(set a, set b);
          set     join(set a, set b);
          set     difference(set a, set b);
          set     intersect(set a, set b);

There is a special constructor for set constants: setof(). This function takes varying number of arguments each of them is either set element or range of elements, defined by macro range(a,b). List of elements should be terminated with `eos` (end of set) constant:

          s := [' ', '!', '?', '_', '0'..'9', 'a'..'z'];

        ==>

          s = setof(' ', '!', '?', '_', range('0','9'), range('a','z'), eos);

In C++ work with Pascal sets is encapsulated in `set_template` class. Instantiation of this class with constant `MAX_SET_CARD` as parameter is used as standard Pascal `set`. Sets of enumerations are created by `set_of_enum(e)` macro:

    typedef set_template<MAX_SET_CARD> set;

    #define set_of_enum(e) set_template<last_##e>

### Mathematical functions

This is one to one correspondence between Pascal and C mathematical functions:

Pascal | C
--- | ---
sin | sin
cos | cos
tan | tan
arctan | atan
ln | log
sqrt | sqrt

Functions `trunc(), pred(), succ(), bitsize(), odd(), chr(), ord()` are implemented by macros in the following way:

          #define trunc(x)  ((integer)(x))
          #define pred(type,x) ((type)((x) - 1))
          #define succ(type,x) ((type)((x) + 1))
          #define bitsize(x) (sizeof(x)*8)
          #define odd(x) ((x) & 1)
          #define chr(n) ((char)(n))
          #define ord(c) ((int)(unsigned char)(c))

Round function is implemented as

                            trunc(x+0.5)   x >= 0
                round(x) =
                            trunc(x-0.5)   x < 0

Pascal function `size(x)` is replaced with C operator `sizeof(x)`.

### Input/Output

We use standard C io library to emulate Pascal input/output. Pascal file type is emulated by C macro file(r) which defines structure containing file descriptor and current record. There are following fields in file descriptor: pointer to C FILE structure, file name, last IO-operation error status, open mode, file status (and FAB pointer for OpenVMS system). Special macros are used for all Pascal file accessing procedures which scatter file structure fields and call corresponding functions. Bellow there is a table specifying mapping between Pascal functions, macros and C functions:

Mapping between Pascal and C I/O functions
Pascal | C macro | C function
--- | --- | ---
rewrite | rewrite | pio_rewrite_file
reset | reset | pio_reset_file
get | get | pio_get_record
put | put | pio_put_record
eof | eof | pio_check_end_of_file
read | sread | pio_read_record (1)
write | swrite | pio_write_record (1)
close | close | pio_close
seek | seek | pio_seek_file
rename | rename | pio_rename_file
break | flush | pio_flush_file (2)
delete | delete_file | pio_delete_file (2)
iostatus | iostatus | pio_iostatus (2)
ioerror | ioerror | pio_ioerror (2)
noioerror | noioerror | pio_ignore_error (2)
- | scopy | pio_copy_record (3)
- | access | pio_access_recprd(3)
- | store | pio_store_record (3)

1. read and write with first file parameter
2. Oregon Pascal extensions
3. This macros are used for translation of some Pascal constructions.

Let the following variable are defined:

          type rec = record ... end;
          var f, g : file of rec;
              r : rec;

Then translation translation for the following construction will be:

          r := f^;
          f^ := r;
          f^ := g^;

        ==>

          r = *access(f);
          store(f, r);
          scopy(f, g);

We use lazy evaluation strategy for implementing Pascal file access. Current record is red from disc only when it is accessed. To handle current state of current record two flags are used: `fs_record_defined` and `fs_next_pos`. First flag is used to mark record which is either red from disk or was assigned a value. Flag `fs_next_pos` is set when pointer in file is moved to position after current record. There is the following invariant: flag `fs_next_pos` is set only when flag `fs_record_defined` is set. A table below shows state of this flags after execution of some functions:

Flags settings
function | fs_next_pos | fs_record_defined
--- | --- | ---
pio_rewrite_file | 0 | 0
pio_reset_file | 0 | 0
pio_get_record | 0 | 0
pio_put_record | 0 | 0
pio_read_record | 0 | 0
pio_write_record | 0 | 0
pio_seek_file | 0 | 0
pio_copy_record | 0 | 0
pio_access_record | 1 | 1
pio_store_record | 0 | 1

Pascal write and read procedures working with text files are replaced with `twrite` and `tread` C functions when first parameter is file and `cwrite` and `cread` when console input/output is used. This functions receive printf-like format string and varying number of arguments. Format string can include arbitrary text and format specifiers:

Format specifiers for read and write operations
type | read | write
--- | --- | ---
integer | %i | %i %<width>i
real | %f | %f %<width>f %<width>.<precision>f
char[] (array of char) | %s | %s %<width>s
char* const ok := 'ok' (zero terminated string) | - | %z %<width>z
short unsigned short [-32768..32767] [0..65535] | %W | -
char unsigned char [-128..127] [0..255] | %B | -

where <width> and <precision> is either literal specified in format string either symbol `'*'`. In former case value of this qualifiers is specified AFTER (unlike C) corresponding parameter:

          write(x:5:2);        ==>        cwrite("%5.2f",x);
          write(x:w:p);        ==>        cwrite("%*.*f",x,w,p);

For symbols not preceding with `%` action performed by read and write are:

read | write
--- | ---
if character is `'\n'` then skip all input character until newline character is reached; otherwise character is compared with next input character and if not equal read operation fails | just output character

To output `%` character this symbol should be included in the format string twice.

Procedures `writeln()` and `readln()` are implemented by the same functions but symbol `'\n'` is appended to the formating string.

Array arguments are passed to read and write function with low and high bound specified before array pointer:

          procedure foo(str : packed array [1..100] of char);
          begin
            writeln('str = ',str);
          end;

        ==>

          void foo(char str[100]) {
            writec("str = %s\n", 1, 100, str);
          }

In C++ template class `file<type>` is used as wrapper for these C `pio_` functions. PtoC uses `streamio` like interface for converting Pascal IO operation in C++:

          type
            rec = record
    	  code : integer;
    	  name : array [1..10] of char;
            end;
          const
            pi = 3.14;
          var
            f : file of rec;
    	r : rec;
          begin
            writeln('Hello world');
    	writeln('pi = ', pi:10:5);
    	write(f, r);
    	read(f, r);
    	r := f^;
    	f^ := r;
    	readln;
          end.

      ==>

          struct rec {
              integer code;
              array<1,10,char> name;
          };
          const real pi = 3.14;
          file f;
          rec r;

          main()
          {
            output << "Hello world" << NL;
    	output << "pi = " << format(pi, 10, 5) << NL;
            f << r;
            f >> r;
            r = *f;
            store(f, r);
    	input >> NL;
    	return EXOT_SUCCESS;
         }

The following table summirize rules of translation Pascal IO constructions to C++:

Pascal construction | C++ construction
--- | ---
write(expr1, expr2, ..., exprN) writeln(expr1, ..., exprN) write(f, expr1, ..., exprN) writeln(f, expr1, ..., exprN) | output << expr1 << expr2 << ... << exprN; output << expr1 << ... << exprN << NL; f << expr1 << ... << exprN; f << expr1 << ... << exprN << NL;
read(lvalue1, lvalue2, ..., lvalueN) readln(lvalue1, ..., lvalueN) read(f, lvalue1, ..., lvalueN) readln(f, lvalue1, ..., lvalueN) | input >> lvalue1 >> lvalue2 >> ... >> lvalueN; input >> lvalue1 >> ... >> lvalueN >> NL; f >> lvalue1 >> ... >> lvalueN; f >> lvalue1 >> ... >> lvalueN >> NL;
write(string_expr:width) write(integer_expr:width) write(real_expr:width:precision) | output << format(string_expr, width); output << format(integer_expr, width); output << format(real_expr, width, precision);
file_variable^ | *file_variable
file_variable^ := expr | store(file_variable, expr);

## BGI emulation

PtoC now provides emulation libraries of Borland Graphics Interface (BGI) for X-Windows and Windows-95/NT are included in this distribution (BGI emulators can be also used without converter for C programs using BGI). I found source code of BGI emulator for X-Windows in Internet, so I only have to do some changes and fix few bugs. Unfortunately this emulation library is not fully completed and tested, also not all BGI functionality is supported. And BGI emulator for MS-Windows I created myself (in Internet I found only commercial products). I called this library WinBGI.

WinBGI strictly emulates most of BGI functions (except using of non-standard drivers). Also may be mapping of fonts is not correct. But as far as sources are also available, you can easily customize them for your application. Unfortunately direct work with palette colors (setpalette, setbkcolor, write and putimage modes other than COPYPUT) is supported only for 256-colors Windows mode. Also I have used this library for only few programs (bgidemo is certainly the most complex one) so I can't guaranty that all functions always work properly. I am also sorry for the lack of parameter checking in WinBGI functions. So summarizing all above:

WinBGI advantages:

1. Allows you to run your old Turbo-C DOS applications in 32-bit mode in normal windows. So you can easily overcome all 64Kb limitations and getting 32-bit application by simple recompilation !
2. Graphics is much faster with WinBGI (because native Win32 API is used with minimal emulation overhead) in comparison with original application running in DOS session under Windows (especially at my PPro-200 with NT). Also it seems to me that some things (like switching of graphical pages) are not working properly in DOS mode under Windows-NT.
3. You can use WinBGI for creating non-event driven graphical applications. For example if you want to write a program which only draws graphic of functions, it is not so easy to do with windows. You have to handle REDRAW messages, create timers to output next graphics iteration... It seems to me that BGI is much more comfortable for this purposes: you just draw lines or points and do not worry about window system at all...

WinBGI shortcomings:

1. Handling of Windows events is done in BGI functions `kbhit(). getch() and delay()`. So to make your application work properly You should periodically call one of this functions. For example, the following program will not work with WinBGI:

               initgraph(&hd, &hm, NULL);
               while (1) putpixel(random(640), random(480), random(16));
               closegraph();

   Correct version of this program is:

               initgraph(&hd, &hm, NULL);
               while (!kbhit()) putpixel(random(640), random(480), random(16));
               closegraph();

2. To handle REDRAW message WinBGI has to perform drawing twice: at the screen and in the pixmap which can be used while redrawing. I find that speed of drawing is still very fast but if you want to make it even faster you can assign 0 to global variable `bgiemu_handle_redraw`. In this case drawing is performed only at the screen but correct redrawing is not possible. If your application makes some kind of animation (constantly updates pictures at the screen) then may be storing image in the pixmap is not necessary, because your application will draw new picture instead of old one.
3. Work with palette is possible only in 256-colors Windows mode. I don't know how to solve this problem with Win32 (I am not going to use DirectX).
4. It is still not so good tested and not all BGI functionality is precisely simulated. I am hope that current version of WinBGI can satisfy requirements of most simple Turbo-C graphics applications.

By default WinBGI emulates VGA device with VGAHI (640x480) mode. Default mode parameter can be changed using `bgiemu_default_mode` variable. Special new mode VGAMAX is supported by WinBGI, causing creation of maximized window. To use this mode you should either change value of `bgiemu_default_mode` variable to `VGAMAX` and specify `DETECT` device type, or specify `VGA` device type and `VGAMAX` mode.

I am using Microsoft Visual C++ 5.0 to compile this application. To build library and BGIDEMO example you should only issue command `nmake -f makefile.mvc`. As a result you will have library `winbgi.lib`, header file `graphics.h`.

## Structure of converter

Below there is a short description of converter itself:

- Scanner "lex.l" is written using LEX. It produces list of all tokens including comments and white spaces.
- Parser parser.y is written using YACC. Parser takes from list of tokens created by scanner all tokens except separators and creates object tree (classes are described in trnod.h which nodes contain references to tokens. All names are inserted in global name table nmtbl.h.
- Attributes are assigned to tree nodes by executing virtual method `attrib()` trnod.cxx. At this step symbol table bring.h is created. Classes for type expressions are implemented in tpexpr.cxx.
- Virtual method `translate()` is recursively called for all nodes in tree trnod.cxx. This methods perform conversion of input tokens (modify value, swap tokens, add new tokens) and as a result prepare output list of tokens.
- All tokens from output list of tokens are printed to target file with intelligent preserving position and layout of tokens token.cxx.

## Nested functions and call graph analysis

Converter can perform global call graph analyze in order to recognize non-recursive functions and making static variables of such functions which are accessed by nested functions. If you specify `-analyze` option, converter appends to file "call.grp" information about callers and callees. After conversion of all files special utility `cganal` can be used to produced transitive closure of call graph and output list of recursive procedures in file "recur.prc". When you run converter once again (with `-analyze` option) information from this file is used to mark recursive procedures. This approach greatly increase readability of program as no extra arguments need to be passed to nested functions.

## Resolving name conflicts

Resolving of names conflicts is controlled by file ptoc.cfg which is loaded by converter at startup. This file specifies reserved symbols (C and C++ keywords), names of functions from C standard library, names of macros defined by converter, and mapping of names for some functions from pascal runtime.

## Passing parameters in C

When converter produces C code, it doesn't copy arrays which are passed by value. Instead of this converter declare such arrays as `const`, so any attempt to modify contents of such array cause C compiler warning or error. It seems to me, that there are usually few places in program where procedure modifies array which is passed by value. As a rule absence of VAR qualifier means that procedure only access but not modify contents of the array. So we decide that efficient generation of this most common is more important then some amount of manual job which is necessary to correct places where array has to be copied. You should only rename formal parameter, create local variable with original name and copy value to it:

            foo(str20 const name) {
                ...
            }

    =>

            foo(str20 name_) {
                str20 name;

                memcpy(name, name_, sizeof(name));
                ...
            }

## Passing parameters in C++

As far as Pascal arrays are represented in C++ by special class, there is no problem with array parameter passing as in C. But as far as arrays passed by value are very rarely modified in called procedure, PtoC optimizes passing of arrays by value. If array parameter, passed by value, is not changed in procedure and is not passed by reference to another procedure, then PtoC doesn't create copy of the array. This optimization can be suppressed by `-copy` option. When this option is specified, PtoC strictly emulates Pascal call semantic for arrays passed by value (always create copy of the array). I don't know reasons of using this options.

PtoC implements conformant array by template class `conf_array`. PtoC uses special macro `copy_conformant_array()` to create copy of conformant array passed by value when this array is modified within procedure or option `-copy` is specified. This macro uses `alloca()` function from C library, which allocates space from the system stack.

PtoC uses macro `as(type, string-constant)` for passing string constant to the parameter of `array of char` type. As far as PtoC wants to make it possible to initialize arrays by means of C aggregate construction `{...}`, it is impossible for array class to have constructor. That is why macro `as()`, which calls method `array::make(char const* str)`, is used for passing string constant as parameter. If size of string constant is less than size of target parameter, then string is padded with spaces. If size of string constant is greater than size of target parameter, then string is truncated to the size of parameter.

## Calling of C functions

Sometimes C functions need to be called from Pascal code. Sun Pascal has special "`EXTERNAL C`" qualifier for C procedures called from Pascal. PtoC recognize this qualifier and treat it as C (not C++) function declaration. There are some specific items of conversion of declarations and calls of such functions:

- Zero terminated strings. Many C functions accept zero terminated strings parameters. As far as character arrays in Pascal are not zero terminated, some conversion of string should be done. PtoC provides function `lpsz()`, which copies characters from Pascal array to internal static cyclic buffer and appends them with `'\0'` symbol. Passing of string literal requires no conversion. Turbo Pascal `string` type can be implicitly converted to zero terminated string without calling `lpsz()` method.
- Variables passed by reference. When conversion to C++ is used, formal parameters declared with `VAR` keyword are translated to C++ reference variables. So no explicit operation to take address of actual parameter is required. But as far as there are no references in C, references should be replaced with pointers and explicit operation `"&"` is needed for actual parameters.
- Array passing. Arrays in C are treated as pointers. When C++ is used as target language and function is declared with `"EXTERNAL C"` qualifier, formal parameter of such function belonging to array type are translated to pointer of the array element type. Actual parameters are passed by means of `body()` method, which returns pointer to the array elements.

The following examples illustrate these items:

    type smallstr = array [1..64] of char;

    procedure foo(var x : integer; a : smallstr; b : zero_terminated_string);
    external c;

    var
       i : integer;
       s : smallstr;
    begin
       foo(i, s, s);
       foo(i, 'abc', 'xyz');
    end.

    ----------------------------------------------

    typedef array<1,64,char> smallstr;

    extern "C" void foo(integer* x, char*  a, char*  b);

    int main()
    {
       integer i;
       smallstr s;

       foo(&i, s.body(), lpsz(s));
       foo(&i, "abc", "xyz");
       return EXIT_SUCCESS;
    }

## Array assignments

Some C++ compilers don't allow classes with any assignment operators to be members of unions (for correct implementation it is only necessary that such classes should not redefine DEFAULT assignment operator). As far as arrays can be members of variant components in Pascal, converter can generate code without using of assignment operator for string and character constants. If your specify `-assign` option, converter will use `assign(str)` method of array instead of `operator =` for assignment of string and character constants to array. But PtoC still use default `operator=` generated by compiler for assignment of one array to another. To compile code produced with `-assign` option, pass `-DNO_ARRAY_ASSIGN_OPERATOR` option to C++ compiler.

PtoC translates assignment of string constant to variable of fixed array type by means of `as(type, string-constant)` macro, which performs conversion of string constant to the type of destination variable. If size of string constant is less than the size of the destination variable, then string is padded with spaces. If size of string constant is greater than size of the destination variable, then the string is truncated to the size of destination variable,

## Conversion of Turbo Pascal strings

For conversion of Turbo Pascal classes `string` and `varying_string` were designed to represent correspondent Pascal types. This classes have constructors and assignment operators and so they can not be initialized using C aggregates notation {} and can not be used as components of unions (GCC allows to initialize classes with constructors with {}). To avoid this problem either manually replace such places with C arrays or use option `-cstring` of compiler. When this option is set converter replaces type of string component of records or arrays with C pointer to zero terminated string `const char*`. This approach works well only when this types are used to declare constants.

## Some porting problems

### Representation of integer type

When your are porting application from 16-bit architecture platform you may want to preserve integer size (2 bytes). In this case you can face with two problems: one is that pointers will not more fit into such integers. Converter can't help your in this case. You should change types of some variables and records fields. And second problem is less obvious. In language C `short` and `char` operands are converted to `int` type before operation takes place. So if you you compare for equality variables of signed and unsigned type declared in Pascal as

          type
            word : -32768..32767
            uword : 0..65535
          var
            v1 : word;
            v2 : uword;

containing the same value (for example 40000) then result will be false (unlike original application) ! This is because variable with signed type will be converted to integer with sign extension while variable with unsigned type - without sign extension. To help to deal with this problem converter provides option `-unsigned`, which force converter to insert explicit type conversion in such operations. Lets look at the translation the following Pascal construction with and without `-unsigned` option:

Pascal | C without `-unsigned` | C with `-unsigned`
--- | --- | ---
if v1 = v2 then ... | if (v1 == v2) ... | if ((uword)v1 == v2) ...

It is not recommended to use 2-byte C types for representing INTEGER and WORD Turbo Pascal types, because structures and functions of BGI emulation library deal with original C `int` type. Also I see no much sense in using short types for converted Turbo Pascal applications because in this case you can not receive benefits of 32-bit architecture, it is better to run original application.

### Implementation of Pascal sets

Sometimes it is necessary to preserve original size of data structure. For example if structure is mapped to another structure by means of union (record with variants in Pascal) or is extracted from file. There are two options in converter which can help you in this case. First option is `-intset`, which order converter to generate short sets (2 or 4 bytes) for sets of enumeration types, Operations with short sets are implemented by macros using bit arithmetic. (so they are significantly faster than operations with universal sets). Disadvantage of using short sets is that adding elements to enumeration may cause problems in future.

### Enumeration types

And another option is `-smallenum`. The problem is that `enum` type in C is treated by many compilers as integers and there are no ways to make compiler use less bytes for their representation. When you specify option `-smallenum` converter replaces original enumeration type definition with `unsigned char` or `unsigned short` definitions according to number of elements in enumeration. So construction

            colors = (red, green, blue);

will be translated to

            typedef unsigned char colors;
            enum {red, green, blue};

Size of `colors` type will be 1. And without `-smallenum` size of `colors` type depends on compiler and usually will be equal to the size of integer (4):

            enum colors {red, green, blue};

## Style of converted sources

As was mentioned above converter tries to preserve original indentation of converted sources. But if Pascal sources are not properly aligned you can reformat produced C code using some indentation utility, for example GNU indent, which is freely distributed (GNU indent has one interesting bug: it fails to work with files with empty comments `/**/` which are produced from popular Pascal `{}` comments. To avoid this problem just replace such comments with `/* */` or something else).

## Includes in ANSII Pascal

PtoC supports %include operator (used in Oregon Pascal). This operator works like C #include directive, performing text substitution. This operator can be used in one of the following forms:

    %include file             { "file.pas" will be included }
    %include '../../file.inc' { "../../file.inc" will be included }
    %include file.con ;       { "file.con" will be included }

The statements above will be converted to

    #include "file.h"
    #include "../../file_inc.h"
    #include "file_con.h"

If several files include the file with variables declarations, then this variables will be multiple defined. This problem can be solved either by passing option to linker to merge symbols with the name (most linkers have such option), either by using `-extern` option. Specifying `-extern` option tells the converter to prepend each variable declaration in included file by `EXTERN` qualifier. `EXTERN` is defined as `extern` in ptoc.h and is redefined to `""` (empty string) if:

1. included file name without extension is the same as name of converted file without extension
2. included file name extension is ".var"

## PtoC options

-I [.]
  Include path (colon separated directory list). PtoC will search for included Pascal files in all specified directories.
-in
  Input Pascal file. Exactly one input file should be specified for PtoC. Keyword `-in` can be skipped if name of the file doesn't start with minus sign.
-out
  Name of output C/C++ file. If output file name is not specified, PtoC will creates file with the same name as source Pascal file with extension replaced with ".cxx" (or with one specified by `-suf` option).
-suf [.cxx]
  Output C/C++ file name suffix.
-c
  Translate into ANSI C. By default converter produce C++ output.
-assign
  Do not use assignment operators for array. Use method `array::assign()` instead. See Array assignments
-analyze
  Analyze call graph to find non-recursive functions. Makes `static` all variables from non-recursive functions, which are accessed from nested functions. See Nested functions and call graph analysis
-intset
  Use integer types for short sets of enumerations. See Implementation of Pascal sets
-init
  Call pio_initialize() function from main(). Invocation of this function performs initialization of Pascal runtime library structures. This functions must be called in VMS and for Turbo Pascal if ParamStr or ExitProc variables are used.
-smallenum
  Use for enumerated types as small bytes as possible. See Enumeration types
-unsigned
  Generate correct code for sign/unsigned comparisons when application is ported from 16-bit architecture to 32/64 bit platform with preserving size of integer type (2 bytes). See Representation of integer types
-h
  Output only not existed header files. By default PtoC performs conversion and output of all included files. This option tells PtoC not to output existed files.
-turbo
  Recognize Turbo Pascal extensions.
-cstring
  Use `char*` type for string fields in records and arrays.
-nological
  Use `|` and `&` instead of `||` and `&&` for boolean operations.
-extern
  Declare all variables from included files with `EXTERN` qualifier.
-preserve
  Preserve case of identifiers. By default PtoC translates all names to lowercase. If you prefer to preserve original style of using uppercase and lowercase letters, then use this option.
-nested
  Nested comments. Do not mix `(* *)` and `{ }` comments. By default PtoC consider `(* ... }` as valid comment. Setting this option makes it possible to enclose one type of comments insize another one: `(* outside comment { inside comment } *)`. This rule is the same as in Turbo Pascal, so this option is implicitly set by `-turbo` option.
-copy
  This option is meaningful only for C++ conversion. When this option is set, PtoC strictly emulates Pascal call semantic for arrays passed by value (always create array copy). By default PtoC optimizes passing of array parameter by value. Array parameter is copied only if it is changed within procedure or it is passed by reference to another procedure. See Passing parameters in C++
-pascall []
  Specify modifier (pascal, WINAPI...) for converted functions.
-comment_tags
  Place in comments tags of Pascal variant records. By default PtoC just skip this tags and doesn't output them to C file. in comments tags of Pascal variant records. By default PtoC just skip this tags and doesn't output them to C file.
-namespace
  Place Turbo Pascal units in separate namespaces:

      unit foo;
      interface
      var
          a : integer;
      implementation
      end.
      ---------------------------------------------
      namespace foo {
          integer a;
      }
      unsing namespace foo;

## Known bugs

- Arrays with dimension greater than 2 should be written in form

              array [l1..h1] of array [l2..h2] of array [l3..h3] of something
           instead of
              array [l1..h1,l2..h2,l3..h3] of something

- Converter translates ranges in case statement in the following manner:

           case x of                          switch (x) {
             'a'..'z':           =>             case RANGE_26('a','z'):
             0..9:                              case RANGE_10(0,9):
             -100..100:                         case -100 ... 100;
             low..high:                         case low ... high;
           end;                               }

  Unfortunately '...' C extension is supported only by GCC.
- `CHAR` type in Turbo Pascal is unsigned and in most implementations of C/C++ by default is signed. To avoid the problem with comparison of chars with code greater than 127 use option of C++ compiler forcing `char` type to be unsigned.
- The following Turbo Pascal contructions are not recognized by PtoC: segment prefixes (`$0000:$1000`), explicit address specification for variable (`ABSOLUTE` statement), inline assembler, `INTERRUPT` quilifier in function or procedure definition. Only the following Turbo Pascal compiler directives are recognized by PtoC: `$I, $IFDEF, $ELSE, $ENDIF, $IFNDEF, $DEFINE, $IFOPT`. Other are treated as normal comments.

  ## PtoC distribution

  PtoC is shareware and is distributed in the hope to be useful. Your are free to use this converter, modify the sources and do with this converter everything else you want. Also feel free to ask me any questions about the converter and BGI emulator for Windows. Shareware status doesn't mean lack of support. I will do my best to fix all reported bugs and will help you to tune PtoC to fit your requirements. Also e-mail support is guaranteed.

  Look for new version at my homepage | E-mail me about bugs and problems