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.
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.
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).
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>
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)
.
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) |
- read and write with first file parameter
- Oregon Pascal extensions
- 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); |
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:
- 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 !
- 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.
- 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:
- 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();
- 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.
- 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).
- 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
.
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.
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 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.
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));
...
}
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.
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;
}
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,
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.
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.
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.
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};
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).
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:
- included file name without extension is the same as name of
converted file without extension
- included file name extension is ".var"
- -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;
- 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 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