home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / alde_c / misc / util / ptoc / ptc.doc next >
Encoding:
Text File  |  1988-02-20  |  37.4 KB  |  1,242 lines

  1.  
  2.  
  3.                    PTC implementation note
  4.  
  5.                      by
  6.  
  7.                     Per    Bergsten
  8.  
  9.                    Holistic    Technology AB
  10.                    Grona Gatan 59
  11.                   414 54 Gothenburg
  12.                        Sweden
  13.  
  14.  
  15.       This note describes the implementation of  ptc,  a  Pascal  to  C
  16.       translator.    The program was    developed by Per Bergsten of Holis-
  17.       tic Technology AB, Gothenburg, Sweden.  The paper is intended     to
  18.       provide  a  guide  for  those     who need to transport ptc to a    new
  19.       environment, it describes how    Pascal constructs are mapped onto C
  20.       constructs.
  21.  
  22.  
  23.  
  24.       Holistic Technology AB     PTC        HD870410-1 Rev:    1.6
  25.  
  26.  
  27.       1.  Background
  28.  
  29.       The aim was originally to provide a simple tool for  transporting
  30.       finished  applications  to systems lacking Pascal compilers.    The
  31.       first    versions,  constructed    in  about  1984,  were    capable     of
  32.       translating  simple  Pascal  programs.   It was never    intended to
  33.       become a released product, however, as time went by, programs    and
  34.       ambitions grew to the    point where nearly the full Pascal language
  35.       was supported.  Thus the program as it stands    today  has  a  long
  36.       ancestry  but     it has    never been redesigned (which it    should have
  37.       been).
  38.  
  39.       2.  Pascal vs    C
  40.  
  41.       To anyone familiar with the two languages it is obvious that they
  42.       are very similar in structure.  The major features may be summar-
  43.       ised as follows:
  44.  
  45.              Pascal                   C
  46.  
  47.       Block-structured          Block-structured
  48.       - multiple declaration levels      - single declaration level
  49.       Statically scoped          Statically scoped
  50.       Strongly typed          Weakly typed
  51.                       - allows unbounded pointers
  52.       Call by value              Mostly call by value
  53.       - and    call by    reference
  54.       Highly independent          Highly integrated
  55.       - of host system          - with system
  56.       Self contained          Allows external definitions.
  57.  
  58.  
  59.       On the syntactic level the languages differ only in  minor  ways,
  60.       mostly  in  the  order in which keywords and other symbols occur,
  61.       and of course    in that    the languages uses  different  symbols    for
  62.       the  same  purposes.     The  only complication    is that    C prohibits
  63.       nested subroutine declarations.
  64.  
  65.       On the semantic level    the situation is worse.     C  has     the  pecu-
  66.       liarity  that     array variables are treated differently from other
  67.       variables, this forces us to adopt some  general  way     to  handle
  68.       array    variables.  Furthermore, since Pascal offers nested subrou-
  69.       tine declarations it becomes necessary to simulate  part  of    the
  70.       activation  record  mechanism    in the translated code,    in one case
  71.       it is    extremely difficult to completely  do  this.   It  is  also
  72.       clear     that  the  C  typedef mechanism has some shortcomings that
  73.       preclude an easy translation of Pascal types.
  74.  
  75.       3.  Mapping Pascal to    C
  76.  
  77.       In this part of the paper we briefly illustrate how to  translate
  78.       Pascal code into equivalent C    code.
  79.  
  80.       3.1.    Programs
  81.  
  82.       A minimal Pascal program:
  83.  
  84.           program p;
  85.           begin
  86.           end.
  87.  
  88.       translates to    the C equivalent:
  89.  
  90.           extern void exit();
  91.           main()
  92.           {
  93.               exit(0);
  94.           }
  95.  
  96.  
  97.       It should be noted here that the  translator    does  not  actually
  98.       require  a  complete    Pascal    program, the implementation is such
  99.       that any consistent set of declarations can be translated.
  100.  
  101.       3.2.    Lexical    issues
  102.  
  103.       The C    language uses ASCII as a carrier, almost all of    the availi-
  104.       ble  characters  are    used.  The Pascal definition uses a smaller
  105.       set of characters.  Since few    features of the    languages depend on
  106.       the  underlying character set    this does not introduce    much diffi-
  107.       culties.
  108.  
  109.       One serious problem does occur.  Both    language definitions states
  110.       that    comments have no meaning and no    clear place in the language
  111.       syntax.  Furthermore,    the Pascal definition states that a comment
  112.       is  equivalent  to  a    blank character.  This implies that if com-
  113.       ments    are handled accurately the translator should also  be  able
  114.       to  collect and classify each    blank character    in a Pascal program
  115.       and to generate a C program with the same number of blank charac-
  116.       ters    in the corresponding positions.     This implication conflicts
  117.       with the fact    that the languages have    different syntax rules,     it
  118.       is not obvious what the "corresponding positions" would be.
  119.  
  120.       Since    comments have no defined meaning a user    is free     to  inter-
  121.       pret    them  in any way and, in particular, to    associate them with
  122.       the surrounding code in any way s/he    chooses.   Although  humans
  123.       usually are able to deduce what bearing a comment has    on the sur-
  124.       rounding program code    there are no formal rules  for    how  to     do
  125.       this.      Therefore  there  is no a priori correct way to translate
  126.       comments and the translator described    here ignores comments alto-
  127.       gether.   If/when  a    reasonable  ad    hoc  solution is found that
  128.       feature may be incorporated.
  129.  
  130.       3.3.    Declarations
  131.  
  132.       The program may introduce local declarations which are handled as
  133.       follows.
  134.  
  135.       3.3.1.  Labels
  136.  
  137.  
  138.           program p;
  139.  
  140.           label    9;
  141.  
  142.           begin
  143.           9:
  144.               goto 9
  145.           end.
  146.  
  147.       which    we simply translate into:
  148.  
  149.           extern void exit();
  150.           main()
  151.           {
  152.           L9:
  153.               goto L9;
  154.               exit(0);
  155.           }
  156.  
  157.  
  158.       If the label is reached from an inner    procedure:
  159.  
  160.           program p;
  161.  
  162.           label    100;
  163.  
  164.               procedure q;
  165.  
  166.               begin
  167.                   goto 100
  168.               end;
  169.  
  170.           begin
  171.           100:
  172.           end.
  173.  
  174.       a more complicated translation must be used:
  175.  
  176.           # define Line    __LINE__
  177.           void Caseerror();
  178.           # include <setjmp.h>
  179.           static struct    Jb { jmp_buf jb; } J[1];
  180.  
  181.            void
  182.           q()
  183.           {
  184.               longjmp(J[0].jb, 100);
  185.           }
  186.  
  187.           main()
  188.           {
  189.               if (setjmp(J[0].jb))
  190.                   goto L100;
  191.           L100:
  192.               exit(0);
  193.           }
  194.  
  195.  
  196.       We assume the    existence of the standard  setjmp()  and  longjmp()
  197.       library  functions.    Jumpbuffers  are  statically  allocated     as
  198.       needed depending on the number of declarationlevels in  the  pro-
  199.       gram.
  200.  
  201.       3.3.2.  Constants
  202.  
  203.       Constant declarations    are treated in two different ways.  Numbers
  204.       aliases  etc    are simply # define'd but string constants are con-
  205.       verted to static character arrays in order to     avoid    unnecessary
  206.       duplication of string-constants in the object    code, thus:
  207.  
  208.           const
  209.              p    = 3.14;
  210.              pie   = '3.14';
  211.  
  212.       translates to:
  213.  
  214.           # define pi 3.14
  215.           static char pie[] = "3.14";
  216.  
  217.  
  218.       3.3.3.  Types    and variables
  219.  
  220.       Types    and variables are mostly easy to translate:
  221.  
  222.           program p;
  223.  
  224.           const    length     = 15;
  225.  
  226.           type
  227.              struct     = 0 ..    length;
  228.              vect     =    array [    struct ] of struct;
  229.              color    =    (red, blue, ada, yellow);
  230.              pointer  =    ^ recd;
  231.              recd     =    record
  232.                   r     : pointer;
  233.                   case b : boolean of
  234.                 false: (c : color);
  235.                 true:  (v : vect);
  236.                  end;
  237.  
  238.           var    SP    :    pointer;
  239.  
  240.           begin
  241.              new(SP, true);
  242.           end.
  243.  
  244.       becomes
  245.  
  246.           typedef char      boolean;
  247.           # define false (boolean)0
  248.           # define true    (boolean)1
  249.           extern char *Bools[];
  250.           # define Unionoffs(p,    m) (((long)(&(p)->m))-((long)(p)))
  251.           extern char *malloc();
  252.           # define length 15
  253.           typedef unsigned char    C47_struct;
  254.           typedef struct { C47_struct A[length + 1]; } vect;
  255.           typedef enum { red, blue, ada, yellow    } color;
  256.           typedef struct S57 *pointer;
  257.           typedef struct S57 {
  258.              pointer  r;
  259.              boolean  b;
  260.              union {
  261.             struct {
  262.                color    c;
  263.             } V1;
  264.             struct    {
  265.                vect     v;
  266.             } V2;
  267.              } U;
  268.           }  recd;
  269.           pointer  sp;
  270.  
  271.           main()
  272.           {
  273.              sp    = (struct S57 *)malloc((unsigned)
  274.             (Unionoffs(sp, U.V2.v) + sizeof(sp->U.V2)));
  275.              exit(0);
  276.           }
  277.  
  278.       The rationale    is as follows:
  279.  
  280.       Identifiers in the Pascal program which conflicts  with  reserved
  281.       words     in  C are renamed by adding a unique prefix Cnnn where    nnn
  282.       is a number.
  283.  
  284.       We also note here that uppercase letters in identifiers and  key-
  285.       words      are  translated  to  lowercase.   Pascal  specifies  that
  286.       upper/lower case is insignificant whereas  C    (for  the  present)
  287.       separates  the two.  This fact is used to advantage by the trans-
  288.       lator    as all subroutines and macros  defined    by  the     translator
  289.       have an initial uppercase letter which prevents confusion.
  290.  
  291.       -    The type    boolean    is a predefined    Pascal    type,  when  it     is
  292.            used  the  translator emits code    which defines boolean to be
  293.            the smallest convenient type: char.  The    constants false    and
  294.            true  are  defined  and    the vector Bools will contain text-
  295.            strings for output if needed.
  296.  
  297.       -    The predefined types integer and    real  are  likewise  mapped
  298.            directly     onto the standard C types int and double through a
  299.            typedef declaration.
  300.  
  301.            Integer subranges are  mapped  onto  standard  C     arithmetic
  302.            types  according     to  a    short table in the translator.    The
  303.            table is    scanned    from top to bottom until an enclosing range
  304.            is found    and the    corresponding type-name    is emitted.
  305.  
  306.       -    C-arrays    have peculiar semantix.     To unify the treatment     of
  307.            arrays and other    datatypes we always encapsulate    an array in
  308.            a struct, thus an array always becomes a    struct with a  sin-
  309.            gle member named    A.
  310.  
  311.       -    Records and their variants are translated into C    struct    and
  312.            union  definitions.   Since  C requires all union members to
  313.            have a name we must supply artificial names for    all  record
  314.            variants.  A record with    variants will therefore    always con-
  315.            tain one    field with the name U which have  sub-fields  named
  316.            Vnnn where nnn is a positive number.
  317.  
  318.            When allocating dynamic storage for a record  with  variants
  319.            naming the desired variant
  320.  
  321.                new(sp, true)
  322.  
  323.            we face the problem of  determining  the     amount     of  memory
  324.            needed.
  325.  
  326.            C does not provide a safe way to    compute    the size of  a
  327.            particular struct variant.
  328.  
  329.            The strategy adopted to cope with this problem is to attempt
  330.            to compute the offset of    a fieldmember in the variant match-
  331.            ing the constant    and then to add    the size  of  the  variant.
  332.            The  offset  computation    is expressed as    a macro, Unionoffs,
  333.            which uses rather foul typecasting  to  achive  the  result.
  334.            The only    availible alternative would be to use the same size
  335.            of all variants.     This  method,    while  being  safe,  wastes
  336.            memory  when  many  small  and few large    records    of the same
  337.            type are    created    dynamically.
  338.  
  339.       -    Pascal enumeration types    are converted directly    to  C  enum
  340.            types.
  341.  
  342.       -    Pascal pointer types are    translated into     C  pointer  types.
  343.            Pascal allows the programmer to construct recursive types as
  344.            pointer types need not be fully defined until the end of    the
  345.            declaration-section  where  the    pointer     type  is used.     In
  346.            practice    this is    only used to introduce record  types  which
  347.            contain    pointers  to themselves.  This problem is partially
  348.            solved by introducing a name for    the record type.  Hence
  349.  
  350.                type
  351.               ptr    = ^ node;
  352.               node    = record
  353.                 next  :    ptr;
  354.                 info  :    integer
  355.                    end;
  356.  
  357.            becomes
  358.  
  359.                typedef struct S56 * ptr;
  360.                typedef struct S56 {
  361.               ptr       next;
  362.               integer     info;
  363.                } node;
  364.  
  365.            we note in passing that the  problem  cannot  be     completely
  366.            solved since
  367.  
  368.                type  pureptr  =    ^ pureptr;
  369.  
  370.            which is    valid Pascal, cannot be    expressed in C.
  371.  
  372.       -    A pascal    set-type does not have any direct counterpart in C.
  373.            The C language does however have    a adequate set of operators
  374.            for bit manipulation.  We use these to  implement  a  Pascal
  375.            set as an array of setword.  So:
  376.  
  377.                type
  378.               s  = set of 1    .. 100;
  379.  
  380.                var
  381.               ss : s;
  382.  
  383.            is translated into:
  384.  
  385.                typedef unsigned    short setword;
  386.                typedef struct {    setword    S[8]; }    s;
  387.  
  388.                s  ss;
  389.  
  390.            The situation is    slightly complicated by    the fact that  Pas-
  391.            cal  has    a set constructor which    permits    the construction of
  392.            arbitrary large sets, for example:
  393.  
  394.                s := [ 50 .. maxint ] * [ 1 .. 80 ]
  395.  
  396.            for that    reason the first member    in the array of    words gives
  397.            size  of     the  set  (in words).    In the example above s.S[0]
  398.            would have the value 7, and s.S[1] through s.S[7] would hold
  399.            the  bits.   The    number 7 is computed on    the assumption that
  400.            the type    unsigned short on the target host  is  sufficiently
  401.            large  to  holds     16  bits.  The    set operators of Pascal    are
  402.            implemented as C    functions returning pointers to     arrays     of
  403.            setwords, the intermediary results are held in a    static area
  404.            of fixed    size.
  405.  
  406.       -    Pascal files are    implemented using the standard i/o  package
  407.            availible  in  most C implementations.  Since Pascal has    the
  408.            requirement that    the next element of a file  is    visible     in
  409.            the  filebuffer    before it is read, and the requirement that
  410.            linemarkers in textfiles    are given special treatement we    are
  411.            forced  to  extend  the    FILE  type  provided  in <stdio.h>.
  412.            Hence:
  413.  
  414.                var   f    : text;
  415.  
  416.            becomes
  417.  
  418.                typedef struct {
  419.               FILE    *fp;
  420.               unsigned short
  421.                 eoln:1,
  422.                 eof:1,
  423.                 init:1,
  424.                 out:1,
  425.                 :12;
  426.               char    buf;
  427.                }  text;
  428.                text  f;
  429.  
  430.            where buf is our    filebuffer and eoln, eof and init are flags
  431.            giving the state    of the file.  All Pascal i/o operations    are
  432.            implemented using macros    that maintain  the  flags  and    the
  433.            buffer  variable.  The actual reading and writing of data is
  434.            deferred    to the standard    i/o package.
  435.  
  436.       3.3.4.  Procedures and functions
  437.  
  438.       Pascal  procedures  and  functions  are  somewhat  difficult     to
  439.       translate to C.  The main problems lie in nested declarations    and
  440.       procedural parameters.  Nested declarations are  handled  in    the
  441.       following manner:
  442.  
  443.            -    If procedure B is declared in procedure  A,     then  pro-
  444.             cedure  B is emitted before    A and A    is forward declared
  445.             before B.
  446.  
  447.            -    Any    constants and types declared in    A is moved  to    the
  448.             global scope, this may force renaming of those objects.
  449.  
  450.            -    Any    variable declared in A and used    in B  is  converted
  451.             to    a  pointer  and     moved    to  the     global    scope.    The
  452.             pointer value is saved  and     re-initialized     upon  each
  453.             entry of A and restored upon exit from A.
  454.  
  455.       Hence:
  456.  
  457.           procedure A;
  458.  
  459.           const    limit =    20;
  460.  
  461.           type    loctyp     = 0 ..    limit;
  462.  
  463.           var    i, j  :    loctyp;
  464.  
  465.              procedure B(k : loctyp);
  466.  
  467.              begin
  468.             j := k + 2
  469.              end;
  470.  
  471.           begin
  472.              B(i)
  473.           end;
  474.  
  475.       becomes
  476.  
  477.           typedef unsigned char      loctyp;
  478.           loctyp   *G56_j;
  479.  
  480.           void a();
  481.  
  482.            void
  483.           b(k)
  484.              loctyp  k;
  485.           {
  486.              (*G56_j) =    k + 2;
  487.           }
  488.  
  489.            void
  490.           a()
  491.           {
  492.           # define limit 20
  493.              loctyp  i,    j;
  494.              loctyp  *F57;
  495.  
  496.              F57 = G56_j;
  497.              G56_j = &j;
  498.              b(i);
  499.              G56_j = F57;
  500.           }
  501.  
  502.       we see that references to j inside procedure b  are  replaced     by
  503.       the  pointer    G56_j  which points to the local variable j in pro-
  504.       cedure a.  In    order to preserve the proper semantix in  the  face
  505.       of  recursion     the value of the pointer need also be saved in    the
  506.       local    variable F57 during the    invocation of a.
  507.  
  508.       -    Procedure parameters offer little  problems.   We  translate
  509.            Pascal  value-parameters    into ordinary C    parameters and Pas-
  510.            cal var-parameters are treated as pointers.
  511.  
  512.       -    Procedural parameters appear at first to    be easy    to  handle.
  513.            The ordinary program:
  514.  
  515.                program p;
  516.  
  517.                procedure pp(procedure q(i : integer));
  518.  
  519.                begin
  520.               q(2)
  521.                end;
  522.  
  523.                procedure qq(i :    integer);
  524.                begin
  525.                end;
  526.  
  527.                begin
  528.               pp(qq)
  529.                end.
  530.  
  531.            becomes
  532.  
  533.                extern void exit();
  534.                typedef int integer;
  535.  
  536.             void
  537.                pp(q)
  538.               void    (*q)();
  539.                {
  540.               (*q)(2);
  541.                }
  542.  
  543.             void
  544.                qq(i)
  545.               integer i;
  546.                {
  547.                }
  548.  
  549.                main()
  550.                {
  551.               pp(qq);
  552.               exit(0);
  553.                }
  554.  
  555.            which looks simple enough.
  556.  
  557.            However,    Pascal requires     that  the  scope  of  a  procedure
  558.            remains unchanged throughout its    lifetime.  Consider:
  559.  
  560.                program demo(output);
  561.  
  562.                var   i    : integer;
  563.  
  564.               procedure p(procedure    q);
  565.  
  566.               var    j  : integer;
  567.  
  568.                  procedure qq;
  569.  
  570.                  begin
  571.                 writeln(j)
  572.                  end;
  573.  
  574.               begin
  575.                  j := i;
  576.                  q;
  577.                  if    i < 1 then
  578.                    begin
  579.                 i := i + 1;
  580.                 p(qq)
  581.                    end
  582.               end;
  583.  
  584.               procedure dummy;
  585.               begin
  586.               end;
  587.  
  588.                begin
  589.               i := 0;
  590.               p(dummy)
  591.                end.
  592.  
  593.            When p is first invoked it assigns the local variable j    the
  594.            value  0.   This     variable  is  accessible  from    qq which is
  595.            passed as a parameter in     the  recursive     call  of  p.    The
  596.            second  invocation  of  p then sets its variable    j to 1,    and
  597.            calls q which is    bound to the  first  instance  of  qq,    and
  598.            should  therefore  print    the number 0.  Sadly, the code pro-
  599.            duced by    the translator fails to    do  this.   It    is  obvious
  600.            that  the  program  above calls for a complete simulation of
  601.            the activation record mechanism of Pascal to work correctly.
  602.  
  603.            A workable but unpractical solution would be:
  604.  
  605.            1)   When qq is used as parameter  we  call  a  function     q1
  606.             which saves    the environment    for qq (i.e. the address of
  607.             j) in a well known place and returns a pointer to q2.
  608.  
  609.            2)   When qq is later called (under the name q)    the  actual
  610.             target  will be q2 which sets up the proper    environment
  611.             calls qq.
  612.  
  613.            The problem is that this    requires a save-area for each  pro-
  614.            cedural parameter which can hold    the intresting parts of    its
  615.            environment for each of its  invocations.   In  the  example
  616.            above  we need one are which holds the address of i for each
  617.            instance    of qq (say N instances,     where    N  depends  on    the
  618.            run-time     behaviour  of    p).  It    also requires a    set of dif-
  619.            ferent procedures to perform the    work  of  q2  (N  different
  620.            procedures   which   sets  up  the  environment    for  the  N
  621.            instances).  This requires much to much work to implement so
  622.            the  problem  is     left unsolved,    this is    hardly a problem in
  623.            practice    since humans rarely write such code  but  it  could
  624.            introduce problems in machine generated Pascal code.
  625.  
  626.            It should be noted that the translator accepts  the  keyword
  627.            external     in  place  of    the  Pascal  forward  directive    and
  628.            assumes that the    so declared procedure is defined elsewhere.
  629.  
  630.       3.4.    Statements.
  631.  
  632.       Pascal statements are    comparatively easy to translate    to C.    The
  633.       only parts that require special care are non-local goto, with    and
  634.       for statements.  The code
  635.  
  636.           program p(output);
  637.  
  638.           type
  639.              msgtyp   =    packed array [ 1 .. 12 ] of char;
  640.  
  641.           var
  642.              a    : array    [ 1 .. 10 ] of
  643.                record
  644.                   r     : real
  645.                end;
  646.              i    : integer;
  647.              ok    : boolean;
  648.  
  649.              procedure fatal(m : msgtyp);
  650.  
  651.              begin
  652.             writeln('Fatal error: ', m)
  653.              end;
  654.  
  655.           begin
  656.              while true    do
  657.                repeat
  658.             ok := false;
  659.             i := 1;
  660.             for i := i + 1 to i + 10 do
  661.                if i    > 10 then
  662.                   fatal(' 10 exceeded')
  663.                else
  664.                  with a[i] do
  665.                   if r > 9.99e+38 then
  666.                  ok := true
  667.                   else
  668.                  writeln(r)
  669.                until ok
  670.           end.
  671.  
  672.       becomes
  673.  
  674.           typedef char boolean;
  675.           # define false (boolean)0
  676.           # define true    (boolean)1
  677.           typedef int integer;
  678.           typedef double real;
  679.  
  680.           typedef struct { char    A[12 - 1 + 1]; } msgtyp;
  681.           typedef struct { struct S57 {
  682.              real  r;
  683.           }  A[10 - 1 +    1]; }  T56;
  684.           T56       a;
  685.           integer  i;
  686.           boolean  done;
  687.  
  688.            void
  689.           fatal(m)
  690.              msgtyp   m;
  691.           {
  692.              (void)fprintf(output.fp, "Fatal error: %.12s", m.A),
  693.                  Putchr('\n', output);
  694.           }
  695.  
  696.           main()
  697.           {
  698.              while (true)
  699.                do {
  700.             done = false;
  701.             i = 1;
  702.             {
  703.               integer      B1 = i +    1, B2 =    i + 10;
  704.  
  705.               if (B1 <= B2)
  706.                for (i = B1;    ; i++) {
  707.                   if (i > 10)
  708.                  fatal(*((msgtyp *)" 10    exceeded"));
  709.                   else {
  710.                  register struct   S57 *W3 = &a.A[i - 1];
  711.  
  712.                  if (W3->r > 9.99e+38)
  713.                     done = true;
  714.                  else
  715.                     (void)fprintf(output.fp, "%    20e", W3->r),
  716.                        Putchr('\n', output);
  717.                   }
  718.                   if (i == B2) break;
  719.                }
  720.             }
  721.                } while (!(done));
  722.              exit(0);
  723.           }
  724.  
  725.       for the following reasons:
  726.  
  727.       3.4.1.  Begin
  728.  
  729.       The compound statements are very similar in the two languages    and
  730.       need no further explanation.
  731.  
  732.       3.4.2.  If
  733.  
  734.       Pascal if-statements have the    same structure and  semantix  as  C
  735.       if-statments.
  736.  
  737.       3.4.3.  Case
  738.  
  739.       Pascal case-statements have the same structure and semantix as  C
  740.       switch-statements  provided  that a break is always added to each
  741.       entry.
  742.  
  743.       The translator supports a common  Pascal  extension  in  that     it
  744.       recognizes  the keyword otherwise to signify a default entry in a
  745.       case-statement.
  746.  
  747.       3.4.4.  Labels
  748.  
  749.       Pascal labeled statements and    labels have the    same structure    and
  750.       semantix  as    C  labeled statements except that Pascal labels    are
  751.       numbers where    C labels are identifiers, this difference is solved
  752.       by simply prefixing the labels with the letter L.
  753.  
  754.       3.4.5.  Goto
  755.  
  756.       Pascal goto-statements have the same structure as C  goto  state-
  757.       ments     but  the  semantix  differ in that Pascal allows a goto to
  758.       lead out of the current procedure.  This is implemented using    the
  759.       setjmp/longjmp library functions of C    as described earlier.
  760.  
  761.       3.4.6.  With
  762.  
  763.       The with-statement of    Pascal has no  counterpart  in    C.   It     is
  764.       translated into nested compund statements where pointervariables,
  765.       referencing the corresponding    records, are declared and  initial-
  766.       ized.      Within  the  scope  of the with-statement, the accessible
  767.       record fields    are renamed to include the pointer.  The effect     of
  768.       this    is  that the record address is evaluated once as the Pascal
  769.       standard requires.
  770.  
  771.       3.4.7.  For
  772.  
  773.       The for-statement of Pascal has a structure that  is    similar     to
  774.       the  C  for-statement    but the    semantix differ    completely.  Pascal
  775.       requires that    a loop be exited when  the  upper  bound  has  been
  776.       reached,   Pascal  also  requires  that  the    loop-boundaries     be
  777.       evaluated exactly once.  The standard    C for-loop is  exited  when
  778.       the  loop-condition  becomes    false.    This implies that it is    not
  779.       always true that
  780.  
  781.           for (i = 0; i    <= e; i++) ;
  782.  
  783.       behaves in the same manner as
  784.  
  785.           for i    := 0 to    e do ;
  786.  
  787.       since    (in most implementations) the C    version    becomes    an infinite
  788.       loop    if  e  equals maxint or    if e is    the expression i.  For that
  789.       reason Pascal    for-statments are translated into  compound  state-
  790.       ments     where    the  upper/lower bounds    of the for-loop    are held in
  791.       local    variables.  It is  also     necessary  to    add  a    conditional
  792.       break-statement at the end of    the loop.  It is possible to obtain
  793.       the  more  relaxed  translation  by  configuring  the     translator
  794.       appropriately    (see "Tuning" below).
  795.  
  796.       3.4.8.  While
  797.  
  798.       The while-statement behaves exactly the same in both languages.
  799.  
  800.       3.4.9.  Repeat
  801.  
  802.       The repeat-statement of Pascal matches the do-while statement     of
  803.       C  except  for  the  trivial    difference  that  Pascal  permits a
  804.       statement-list where C permits a single statment in the loop.
  805.  
  806.       3.4.10.  Empty
  807.  
  808.       The empty statement has (of course) the same structure and seman-
  809.       tix in both languages.
  810.  
  811.       3.5.    Expressions and    assignments
  812.  
  813.       In most cases    Pascal expressions can be literally translated into
  814.       equivalent C expressions.
  815.  
  816.       identifiers     Except    where identifiers clash    with reserved words
  817.              or  with  other  identifiers  declared    in the same
  818.              scope,    they may simply    be printed.  In    some  cases
  819.              the  translator is forced to rename identifiers or
  820.              to invent new identifiers.
  821.  
  822.       operators     The operators +, -, * div and mod when    applied     to
  823.              real  or  integer operands have exact counterparts
  824.              in C and are therefore    easy to    handle.     The opera-
  825.              tor  for real division, /, corresponds    to the same
  826.              C  operator  except  that  the     operands  may     be
  827.              integers.  In that case a cast    is necessary.  When
  828.              the operands are sets the expression is  converted
  829.              into a    function call.
  830.  
  831.              The operators <, <=, >, >=,  =     and  <>  all  have
  832.              exact    counterparts  in  C  for  integer  and real
  833.              operands.  Most C implementations  disallows  enum
  834.              operands,  the     translator  therefore    casts  such
  835.              operands to int.  Comparisons on structures  (i.e.
  836.              strings  or  sets)  are  converted  into  function
  837.              calls.
  838.  
  839.       assignments     Assignments are straightforward  to  handle  since
  840.              arrays    are encapsulated in structures.     Therefore:
  841.  
  842.                  a := b
  843.  
  844.              becomes
  845.  
  846.                  a = b
  847.  
  848.              unless    b is a string or a set,    in which  case    the
  849.              assignment is converted into a    function call.
  850.  
  851.       indexing     Given    the  translation  for  array   declarations
  852.              (described above) we are forced to translate
  853.  
  854.                  a[i]
  855.  
  856.              into
  857.  
  858.                  a.A[i - c]
  859.  
  860.              where c is the    lower bound for    the index type.
  861.  
  862.       selection     Given the translation for  records  with  variants
  863.              (described above) the translation of
  864.  
  865.                  a.b
  866.  
  867.              becomes
  868.  
  869.                  a.b
  870.  
  871.              or, if    b is declared in a variant,
  872.  
  873.                  a.Vxxx.b
  874.  
  875.              where Vxxx is a name manufactured by the  transla-
  876.              tor for the particular    variant.
  877.  
  878.       dereferencing     Pointer references and    var-parameters are  handled
  879.              by  prefixing the expression with an asterisk,    but
  880.              the special case dereferencing    followed by  selec-
  881.              tion is also recognized, so:
  882.  
  883.                  p^ := q^.f
  884.  
  885.              becomes
  886.  
  887.                  *p = q->f
  888.  
  889.  
  890.       miscellanea     The boolean operators and, or and not    are  simply
  891.              translated  into  their  C  counterparts.  The    set
  892.              contructors [], and ..     and the  operator  in    are
  893.              converted to function calls.
  894.  
  895.       4.  Implementation
  896.  
  897.       The general strategy is to convert the Pascal    source program into
  898.       a  parsetree.      The tree is then traversed by    a set of procedures
  899.       that perform some necessary transformations.    The tree is finally
  900.       traversed  by     a set of procedures that print    the corresponding C
  901.       constructs.  The translator consists of  three  major     procedures
  902.       that    perform    these actions.    They are augmented by a    set of pro-
  903.       cedures that maintain    a symbol table that holds information about
  904.       identifiers found in the source, and by a procedure that initial-
  905.       izes all internal datastructures.
  906.  
  907.       There    are three major    datastructures that interact in    complicated
  908.       ways:
  909.  
  910.       1)   a store for identifiers and strings
  911.  
  912.       2)   a multilevel symbol table
  913.  
  914.       3)   a parse-tree.
  915.  
  916.       The identifier and string store, strstor is in principle an array
  917.       of  characters  that    grow  in  increments  of  one string block.
  918.       Exactly one copy of each identifier  is  stored  in  that  array.
  919.       Whenever  an identifier is found in the input    stream the array is
  920.       scanned to see if that identifier has    been seen before.  In order
  921.       to  speed  up    the search all identifiers are represented by nodes
  922.       which    are chained together such that all nodes  in  a     particular
  923.       chain    have the same hashvalue    as determined by the function hash.
  924.       Each idnode holds an index to     strstor  where     the  corresponding
  925.       identifier text is stored.  The start    of the hashchains are found
  926.       in the global    variable idtab.
  927.  
  928.       idtab
  929.       ---+
  930.       |  |    chain of idnodes with same hashvalue
  931.       ---+    ------+     ------+
  932.       | --->|    --->|     |idnode representing
  933.       ---+    |     |     |index|identifier "demo"
  934.       |  |    ------+     ------+
  935.  
  936.          strstor
  937.       ----------- ------+
  938.       |  |    |     |     |
  939.       --|-------- ------+
  940.         |
  941.  
  942.       -------------------------
  943.       |  |    |d |e |m |o |/ |
  944.       -------------------------  first idblock
  945.          ^
  946.         index=2
  947.  
  948.  
  949.       So: the global representation    of the identifier "demo" is a  par-
  950.       ticlular idnode; whenever the    lexical    analysis routine recognizes
  951.       the identifier "demo"    it returns a pointer to    that idnode.
  952.  
  953.       In order to represent    different identifiers with the same name we
  954.       need    to  be    able to    distinguish between identifiers    declared in
  955.       different scopes.  This is accomplished  by  the  symnode  struc-
  956.       tures.   When    an identifier is first encountered in a    given scope
  957.       it is    "declared", meaning that a  new     symnode  is  created  that
  958.       references the identifier.  Occurrences of the same identifier in
  959.       that scope are then represented in the  parse-tree  by  treenodes
  960.       referencing the same symnode.
  961.  
  962.       The program:
  963.  
  964.           program p;
  965.  
  966.           var    demo  :    integer;
  967.  
  968.           begin
  969.              demo := 3
  970.           end.
  971.  
  972.       yilds    the following structure:
  973.  
  974.          top
  975.  
  976.          ------------+treenode representing
  977.          |npgm     |the program
  978.          ------------+
  979.         |  | ^|    ^
  980.         |  | ||    ---------------------+
  981.         |  | |---------------------+ |
  982.         |    |               | |
  983.         | -------+treenode represen|i|g
  984.         | |nvar     |the var-declaration|
  985.         | -------+      ------------+treenode    repr.
  986.         |  | ^|          |nassign    |assignment
  987.         |  | |-----> to    ty------------+
  988.       symtab|    |               ^     ^
  989.       ---+    | ----+treenode    re------+ -------+
  990.       |  |<----+ |nid|occurrence |nid  | |ninteg|r
  991.           ----+id. "demo" ------+ -------+
  992.       |  |       | ^             |          |    ^
  993.       ---+       | |---------------+          |    |
  994.       |  |         |                |
  995.       ---+    ---------+symnode represent--------+
  996.       | --->   |lidentif|identifier    "demo"|lintege|
  997.       ---+    ---------+in the current sc|linum=3|
  998.            |               --------+
  999.       idtab       ---------+
  1000.       ---+            |
  1001.       |  |
  1002.       ---+    ------+     ------+
  1003.       | --->|    --->|     |idnode representing
  1004.       ---+    |     |     |index|identifier "demo"
  1005.       |  |    ------+     ------+
  1006.  
  1007.          strstor
  1008.       ----------- ------+
  1009.       |  |    |     |     |
  1010.       ----------- ------+
  1011.         |
  1012.  
  1013.       -------------------------
  1014.       |  |    |d |e |m |o |/ |
  1015.       -------------------------  first idblock
  1016.          ^
  1017.         index=2
  1018.  
  1019.       We see that the two occurrences  of  the  identifier    "demo"    are
  1020.       represented  by  two    treenodes  of  variant    nid  that both have
  1021.       pointers to the same    symnode     representing  the  declaration     of
  1022.       "demo".   All     symnodes  at  a given declarationlevel    are chained
  1023.       together (in the same    manner as the idnodes) and the    chains    are
  1024.       attached  to the global variable symtab.  In order to    find out if
  1025.       an identifer is declared in the current scope    we scan     the  chain
  1026.       of symnodes starting from symtab, and    check if any of    them refer-
  1027.       ences    the idnode we are looking  for.      A  symnode  also  have  a
  1028.       pointer  to  the  treenode which defines the symbol.    The symtabs
  1029.       themselves are also chained, the  chain  implements  a  stack     of
  1030.       declarationlevels.  The symtab which is created when the scope of
  1031.       a procedure is entered is also attached to that procedure.   When
  1032.       a  procedure    is entered we create a new symtab, push    it onto    the
  1033.       stack, parse the procedure and pop the stack.     The  symbols  then
  1034.       visible are those that still can be reached from the stack.
  1035.  
  1036.       The parse-tree consists of treenodes representing  each  declara-
  1037.       tion,     statement,  expression    etc.  Each node    except the nprogram
  1038.       node has a pointer to    its immediate father (giving  the  defining
  1039.       point),  to its children (if it has any) and to its right brother
  1040.       (if it is a member of    a list).  The top of the tree is  found     in
  1041.       the global variable top.
  1042.  
  1043.       In order to find the defining    point for  the    identifier  in    the
  1044.       assignment,  we  follow pointers from    the nassign-treenode to    the
  1045.       nid-treenode,    to the lidentifier-symnode,  and  then    up  to    the
  1046.       nid-treenode    in the declaration.  If    we want    to know    the type of
  1047.       the identifier we proceed up to the nvar-treenode and     then  down
  1048.       to  the  node     giving    the type in the    declaration (in    our example
  1049.       that node would also be a nid-treenode  referencing  a  linteger-
  1050.       symnode  that     represents  the identifier "integer").     There is a
  1051.       function typeof that performs    exactly    this  operation.   It  will
  1052.       return  a  pointer  to  a  npredef-,    nsubrange-, nscalar-, nptr-
  1053.       narray-, nrecord-, nfileof- or nsetof-treenode.  In  those  cases
  1054.       where     the  translator  pays attention to types it uses a pointer
  1055.       (obtained from typeof) as representation of a    type.
  1056.  
  1057.       Given    the parse-tree and the layered symbol table it is not  hard
  1058.       to see how the translations described    earlier    are performed.    The
  1059.       one place where the code becomes more     than  usually    complex     is
  1060.       when    a  write  statement  with  format  specifications  is to be
  1061.       translated into a call to fprintf.
  1062.  
  1063.       5.  Tuning
  1064.  
  1065.       The behaviour    of the translator may be modified  for    some  cases
  1066.       simply by changing constants.     These constants are all located at
  1067.       the top of the program text.
  1068.  
  1069.       output      The translator will copy the source during  input     if
  1070.               the  constant echo is true.  The copy is preceeded by
  1071.               the line
  1072.  
  1073.                   #    ifdef PASCAL
  1074.  
  1075.               and ended    by the line
  1076.  
  1077.                   #    else
  1078.  
  1079.               and then follows the translated code and finally
  1080.  
  1081.                   #    endif
  1082.  
  1083.               This may be used to hold both Pascal and C source     in
  1084.               the  same     file.    If the Pascal part is changed the C
  1085.               part may be updated through:
  1086.  
  1087.                  cpp -P    -DPASCAL < orig    > tmp
  1088.                  ptc < tmp > new
  1089.                  move new orig
  1090.  
  1091.               assuming that echo is true and that cpp is the  stan-
  1092.               dard C preprocessor.
  1093.  
  1094.                   Default value:
  1095.  
  1096.                  echo      = false;
  1097.  
  1098.  
  1099.       comments    The translator recognizes    both (*    and  {    as  comment
  1100.               delimiters.   They are treated as    different, allowing
  1101.               1    level nested comments, if the constant    diffcom     is
  1102.               true.
  1103.  
  1104.                   Default value:
  1105.  
  1106.                  diffcomm = false;
  1107.  
  1108.  
  1109.       symbols     The  translator  accepts    default     entries  in  case-
  1110.               statements  provided that    the keyword defined through
  1111.               othersym is used in place    of the constant    list.
  1112.  
  1113.                   Default value:
  1114.  
  1115.                  othersym = 'otherwise ';
  1116.  
  1117.               substitute for
  1118.  
  1119.                  othersym = 'otherwise%';
  1120.  
  1121.               if that feature is undesired.
  1122.  
  1123.               The translator accepts externally    declared procedures
  1124.               and  functions  provided    that  the directive defined
  1125.               through externsym    is used    in  place  of  the  keyword
  1126.               forward.
  1127.  
  1128.                   Default value:
  1129.  
  1130.                  externsym   = 'external  ';
  1131.  
  1132.  
  1133.       sets          Sets are implemented as arrays of    wordtype.  The type
  1134.               is assumed to hold setbits + 1 bits numbered from    0.
  1135.  
  1136.                   Default value:
  1137.  
  1138.                  wordtype = 'unsigned short';
  1139.                  setbits  = 15;
  1140.  
  1141.  
  1142.       files          The implementation of files uses    a  flag-word  which
  1143.               has  the    type  given as filebits    which is assumed to
  1144.               hold filefill + 4    bits.
  1145.  
  1146.                   Default value:
  1147.  
  1148.                  filebits = 'unsigned short';
  1149.                  filefill = 12;
  1150.  
  1151.  
  1152.       stmts          If the Pascal source is known to be "normal"  in    the
  1153.               sense  that for-loops always have    an upper bound that
  1154.               is less than the maximum value of     the  type  of    the
  1155.               loop-variable,  and in the sense that the    upper bound
  1156.               doesn't change by    computations inside the    loop,  then
  1157.               the  translator  may  generate  a     more natural code.
  1158.               I.e:
  1159.  
  1160.                   for i := 1 to 10 do ;
  1161.  
  1162.               becomes
  1163.  
  1164.                   for (i = 1; i <= 10; i++)    ;
  1165.  
  1166.               Since the    requirements cannot be    determined  by    the
  1167.               translator itself    this kind of code is generated when
  1168.               the constant lazyfor is true.
  1169.  
  1170.                   Default value:
  1171.  
  1172.                  lazyfor  = false;
  1173.  
  1174.  
  1175.       new          The second and following parameters to the  procedure
  1176.               new  will     be  ignored  if  the  constant    unionnew is
  1177.               false.
  1178.  
  1179.                   Default value:
  1180.  
  1181.                  unionnew = true;
  1182.  
  1183.  
  1184.       strings     All identifiers and strings are stored in    the  trans-
  1185.               lator  with  the special character having    the ordinal
  1186.               value null as endmarker.    Hence, that  character    can
  1187.               not occur    in strings in the Pascal source.
  1188.  
  1189.                   Default value:
  1190.  
  1191.                  null      = 0;
  1192.  
  1193.  
  1194.       types          The names    of predefined types are    given by  the  con-
  1195.               stants: inttyp, chartyp, floattyp, and doubletyp.
  1196.  
  1197.                   Default value:
  1198.  
  1199.                  inttyp         = 'int';
  1200.                  chartyp  = 'char';
  1201.                  floattyp = 'float';
  1202.                  doubletyp   = 'double';
  1203.  
  1204.               The typename for real variables and functions defined
  1205.               by the user is given by the constant realtyp.
  1206.  
  1207.                   Default value:
  1208.  
  1209.                  realtyp  = doubletyp;
  1210.  
  1211.               The typename for procedures is given by the  constant
  1212.               voidtyp.
  1213.  
  1214.                   Default value:
  1215.  
  1216.                  voidtyp  = 'void';
  1217.  
  1218.  
  1219.       i/o          The default fieldwidths for integer and  real  values
  1220.               written  on  textfiles  are  given  by  the constants
  1221.               intlen and fixlen.
  1222.  
  1223.                   Default value:
  1224.  
  1225.                  intlen      = 10;
  1226.                  fixlen      = 20;
  1227.  
  1228.  
  1229.       types          A    table in the translator    gives the mapping from Pas-
  1230.               cal  integer  subrange  types  to    C arithmetic types.
  1231.               The table    is initialized by code located at  the    end
  1232.               of  procedure initialize giving the following default
  1233.               configuration:
  1234.  
  1235.               Low bound        High bound     Selected type
  1236.  
  1237.                 0       255     unsigned char
  1238.                  -128       127     char
  1239.                 0     65535     unsigned short
  1240.                -32768     32767     short
  1241.               -2147483647   2147483647     long
  1242.