[comp.sources.misc] v04i023: Turbo Pascal to C, part 2/4

alan@leadsv.UUCP (Alan Strassberg) (08/15/88)

Posting-number: Volume 4, Issue 23
Submitted-by: "Alan Strassberg" <alan@leadsv.UUCP>
Archive-name: tptc/Part2

[WARNING!!!  This software is shareware and copyrighted.  Those who do not
accept such programs should give this a miss.  ++bsa]

#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# -rw-r--r--   1 allbery  System     17450 Aug 14 16:46 tpcexpr.inc
# -rw-r--r--   1 allbery  System      4274 Aug 14 16:46 tpcmisc.inc
# -rw-r--r--   1 allbery  System     18755 Aug 14 16:46 tpcscan.inc
#
echo 'x - tpcexpr.inc'
if test -f tpcexpr.inc; then echo 'shar: not overwriting tpcexpr.inc'; else
sed 's/^X//' << '________This_Is_The_END________' > tpcexpr.inc
X
X(*
X * TPTC - Turbo Pascal to C translator
X *
X * (C) 1988 Samuel H. Smith (rev. 13-Feb-88)
X *
X *)
X
X
X(*
X * expression parser
X *
X *)
Xfunction pterm: string; forward;
X
Xfunction iscall(var lv: string): boolean;
X   {see if the given lvalue is a function call or not}
Xbegin
X   iscall := lv[length(lv)] = ')';
Xend;
X
X
Xprocedure make_pointer(var expr: string);
X   {convert the expression into a pointer constant, if possible}
Xvar
X   sym:  symptr;
Xbegin
X   
X   case(expr[1]) of
X      '*':
X      begin
X         delete(expr,1,1);
X         exit;
X      end;
X      
X      'a'..'z','A'..'Z','_':
X      begin         {pass pointer to strings/arrays}
X         sym := locatesym(expr);
X         if (sym <> nil) and ((sym^.symtype = s_string) or
X                              (sym^.suptype = ss_array)) then
X         begin
X            {null}
X         end
X         else
X         
X         if expr[length(expr)-1] = '(' then    {remove () from function calls}
X            dec(expr[0],2)
X            
X         else
X            expr := '&' + expr;
X      end;
X      
X   end;
X
Xend;
X
X
Xfunction isnumber(var lv: string): boolean;
X  {see if the given value is a literal number}
Xvar
X   i: integer;
Xbegin
X   for i := 1 to length(lv) do
X      case lv[i] of
X         '0'..'9','.': ;
X         else
X            isnumber := false;
X            exit;
X      end;
X   isnumber := true;
Xend;
X
X
Xprocedure subtract_base(var expr: string; base: integer);
X   {subtract the specified base from the given expression;
X    use constant folding if possible}
Xbegin
X   if base <> 0 then
X      if isnumber(expr) then
X         expr := itoa(atoi(expr) - base)
X      else
X      if base > 0 then
X         expr := expr + '-' + itoa(base)
X      else
X         expr := expr + '+' + itoa(-base);
Xend;
X
X
Xfunction exprtype: char;
X   {determine expression type and return the printf code for the type}
Xvar
X   xt:      char;
X
Xbegin
X   case cexprtype of
X      s_char:    xt := 'c';
X      s_file:    xt := '@';
X      s_double:  xt := 'f';
X      s_string:  xt := 's';
X      s_bool:    xt := 'b';
X      s_int:     xt := 'd';
X      s_long:    xt := 'D'; { calling routine should convert to "ld" }
X      else       xt := '?';
X   end;
X
X   exprtype := xt;
Xend;
X
X
Xfunction strtype(ty: char): boolean;
X   {see if the expression is a string data type or not}
Xbegin
X   case ty of
X      's','c':  strtype := true;
X      else      strtype := false;
X   end;
Xend;
X
X
X
Xfunction psetof:  string;
X   {parse a literal set; returns the set literal translated into
X    the form: setof(.....)}
Xvar
X   ex: string;
X
Xbegin
X   ex := 'setof(';
X   if tok[1] <> ']' then
X      ex := ex + pterm;
X
X   while (tok = '..') or (tok[1] = ',') do
X   begin
X      if tok = '..' then       
X         ex := ex + ',__,'
X      else
X         ex := ex + ',';
X
X      gettok;
X      ex := ex + pterm;
X   end;
X
X   if ex[length(ex)] <> '(' then
X      ex := ex + ',';
X   ex := ex + '_E)';
X   psetof := ex;
Xend;
X
X
Xfunction pterm:   string;
X   {parse an expression term;  returns the translated expression term;
X    detects subexpressions, set literals and lvalues(variable names)}
Xvar
X   ex: string;
X   builtin: boolean;
X
Xbegin
X   if debug_parse then write(' <term>');
X
X   if (toktype = identifier) and (cursym <> nil) then
X      builtin := cursym^.suptype = ss_builtin
X   else
X      builtin := false;
X
X   (* process pos(c,str) and pos(str,str) *)
X   if builtin and (tok = 'POS') then
X   begin
X      if debug_parse then write(' <pos>');
X      gettok;   {consume the keyword}
X      if tok[1] <> '(' then
X         syntax('"(" expected (pterm.pos)');
X      
X      gettok;   {consume the (}
X      ex := pexpr;
X      if exprtype{(ex)} = 'c' then
X         ex := 'cpos(' + ex
X      else
X         ex := 'spos(' + ex;
X
X      gettok;   {consume the ,}
X      ex := ex + ',' + pexpr;
X      gettok;   {consume the )}
X      pterm := ex + ')';
X      cexprtype := s_int;
X   end
X   else
X
X   (* process chr(n) *)
X   if builtin and (tok = 'CHR') then
X   begin
X      if debug_parse then write(' <chr>');
X      gettok;   {consume the keyword}
X      if tok[1] <> '(' then
X         syntax('"(" expected (pterm.chr)');
X      
X      gettok;   {consume the (}
X      ex := pexpr;
X      gettok;   {consume the )}
X
X      if isnumber(ex) then
X         ex := numlit(atoi(ex))
X      else
X         ex := 'chr('+ex+')';
X
X      pterm := ex;
X      cexprtype := s_char;
X   end
X   else
X
X   (* translate NOT term into !term *)
X   if builtin and (tok = 'NOT') then
X   begin
X      if debug_parse then write(' <not>');
X      gettok;
X      pterm := '!' + pterm;
X      cexprtype := s_bool;
X   end
X   else
X
X   (* process port/memory array references *)
X   if builtin and ((tok = 'PORT') or (tok = 'PORTW') or
X                   (tok = 'MEM')  or (tok = 'MEMW')) then
X   begin
X      if debug_parse then write(' <port>');
X      if tok = 'PORT'  then ex := 'inportb('    else
X      if tok = 'PORTW' then ex := 'inport('     else
X      if tok = 'MEM'   then ex := 'peekb('      else
X                            ex := 'peek(';
X
X      gettok;     {consume the keyword}
X      gettok;     {consume the [ }
X
X      repeat
X         ex := ex + pexpr;
X         if tok[1] = ':' then
X         begin
X            gettok;
X            ex := ex + ',';
X         end;
X      until (tok[1] = ']') or recovery;
X
X      gettok;     {consume the ] }
X      pterm := ex + ')';
X      cexprtype := s_int;
X   end
X   else
X
X   (* translate bitwise not (mt+) *)
X   if (tok[1] = '?') or (tok[1] = '~') or (tok[1] = '\') then
X   begin
X      if debug_parse then write(' <bitnot>');
X      gettok;
X      pterm := '!' + pterm;         {what is a bitwise NOT in c?}
X   end
X   else
X
X   (* process unary minus *)
X   if tok = '-' then
X   begin
X      if debug_parse then write(' <unary>');
X      gettok;
X      pterm := '-' + pterm;
X   end
X   else
X
X   (* translate address-of operator *)
X   if tok[1] = '@' then
X   begin
X      if debug_parse then write(' <ref>');
X      gettok;  {consume the '@'}
X      ex := plvalue;
X      make_pointer(ex);
X      pterm := ex;
X   end
X   else
X
X   (* pass numbers *)
X   if toktype = number then
X   begin
X      if debug_parse then write(' <number>');
X      pterm := tok;
X      gettok;
X      cexprtype := s_int;
X   end
X   else
X
X   (* pass strings *)
X   if toktype = strng then
X   begin
X      if debug_parse then write(' <string>');
X      pterm := tok;
X      gettok;
X      cexprtype := s_string;
X   end
X   else
X
X   (* pass characters *)
X   if toktype = chars then
X   begin
X      if debug_parse then write(' <char>');
X      pterm := tok;
X      gettok;
X      cexprtype := s_char;
X   end
X   else
X
X   (* pass sub expressions *)
X   if tok[1] = '(' then
X   begin
X      if debug_parse then write(' <subexp>');
X      gettok;
X      pterm := '(' + pexpr + ')';
X      gettok;
X   end
X   else
X
X   (* translate literal sets *)
X   if tok[1] = '[' then
X   begin
X      if debug_parse then write(' <setlit>');
X      gettok;
X      pterm := psetof;
X      gettok;
X      cexprtype := s_struct;
X   end
X
X   (* otherwise the term will be treated as an lvalue *)
X   else
X      pterm := plvalue;
Xend;
X
X
Xfunction pexpr: string;
X   {top level expression parser; parse and translate an expression and
X    return the translated expr}
Xvar
X   ex:       string;
X   ty:       char;
X   ex2:      string;
X   ty2:      char;
X
X   procedure relop(newop: string40);
X   begin
X      if debug_parse then write(' <relop>');
X      gettok;        {consume the operator token}
X
X      ex2 := pterm;  {get the second term}
X      ty2 := exprtype;
X
X      {use strcmp if either param is a string}
X      if ty = 's' then
X      begin
X         if ty2 = 's' then
X            ex := 'strcmp(' + ex + ',' + ex2 + ') ' + newop + ' 0'
X         else
X         if ex2[1] = '''' then
X            ex := 'strcmp(' + ex + ',"' +
X                     copy(ex2,2,length(ex2)-2) + '") ' + newop + ' 0'
X         else
X            ex := 'strcmp(' + ex + ',ctos(' + ex2 + ')) ' + newop + ' 0'
X      end
X      else
X
X      if ty = 'c' then
X      begin
X         if ty2 = 's' then
X            ex := 'strcmp(ctos(' + ex + '),' + ex2 + ') ' + newop + ' 0'
X         else
X            ex := ex + ' ' + newop + ' ' + ex2
X      end
X
X      else
X         ex := ex + ' ' + newop + ' ' + ex2;
X      cexprtype := s_bool;
X   end;
X
X
X   procedure addop;
X
X      procedure add_scat;
X      var
X         p: integer;
X
X      begin
X         {find end of control string}
X         p := 7;  {position of 'scat("%'}
X         while (ex[p] <> '"') or
X               ((ex[p] = '"') and (ex[p-1] = '\') and (ex[p-2] <> '\')) do
X            p := succ(p);
X         p := succ(p);
X
X         {add literals to the control string if possible}
X         if (ex2[1] = '''') or (ex2[1] = '"') then
X            ex := copy(ex,1,p-2) + 
X                  copy(ex2,2,length(ex2)-2) +
X                  copy(ex,p-1,length(ex)-p+2)
X
X         else {add a parameter to the control string}
X            ex := copy(ex,1,p-2) + '%' + ty2 +
X                  copy(ex,p-1,length(ex)-p+1) + ',' + ex2 + ')';
X      end;
X
X   begin
X      if debug_parse then write(' <addop>');
X      gettok;        {consume the operator token}
X
X      ex2 := pterm;  {get the second term}
X      ty2 := exprtype;
X
X(* writeln('ex{',ex,'}',ty,' ex2{',ex2,'}',ty2); *)
X
X      {continue adding string params to scat control string}
X      if (ex[5] = '(') and (copy(ex,1,4) = 'scat') then
X         add_scat
X      else
X
X      {start new scat call if any par is a string}
X      if strtype(ty) or strtype(ty2) then
X      begin
X         if (ex[1] = '''') or (ex[1] = '"') then
X            ex := 'scat("' + copy(ex,2,length(ex)-2) + '")'
X         else
X            ex := 'scat("%' + ty + '",' + ex + ')';
X         add_scat;
X      end
X      else
X         ex := ex + ' + ' + ex2;
X
X(* writeln('ex=',ex); *)
X   end;
X
X   procedure mulop(newop: string40);
X   begin
X      if debug_parse then write(' <mulop>');
X      gettok;        {consume the operator token}
X
X      ex2 := pterm;  {get the second term}
X      ex := ex + ' ' + newop + ' ' + ex2;
X   end;
X
X   procedure andop(newop: char);
X   begin
X      if debug_parse then write(' <andop>');
X      gettok;        {consume the operator token}
X
X      ex2 := pterm;  {get the second term}
X      ty2 := exprtype;
X
X      {boolean and/or?}
X      if (ty = 'b') or (ty2 = 'b') then
X      begin
X         ex := ex + ' ' + newop + newop + ' ' + ex2;
X         cexprtype := s_bool;
X      end
X      else  {otherwise bitwise}
X         ex := ex + ' ' + newop + ' ' + ex2;
X   end;
X
X
Xbegin
X   if debug_parse then write(' <expr>');
X   ex := pterm;
X   ty := exprtype;
X
X   while true do
X   begin
X      (* process operators *)
X           if tok    = '>='  then relop(tok)
X      else if tok    = '<='  then relop(tok)
X      else if tok    = '<>'  then relop('!=')
X      else if tok[1] = '>'   then relop(tok)
X      else if tok[1] = '<'   then relop(tok)
X      else if tok[1] = '='   then relop('==')
X      else if tok[1] = '+'   then addop
X      else if tok[1] = '-'   then mulop(tok)
X      else if tok[1] = '*'   then mulop(tok)
X      else if tok[1] = '/'   then mulop(tok)
X      else if tok[1] = '&'   then mulop(tok)  {mt+}
X      else if tok[1] = '!'   then mulop('|')  {mt+}
X      else if tok[1] = '|'   then mulop('|')  {mt+}
X      else if tok    = 'DIV' then mulop('/')
X      else if tok    = 'MOD' then mulop('%')
X      else if tok    = 'SHR' then mulop('>>')
X      else if tok    = 'SHL' then mulop('<<')
X      else if tok    = 'XOR' then mulop('^')
X      else if tok    = 'AND' then andop('&')
X      else if tok    = 'OR'  then andop('|')
X      else
X
X      (* translate the expr IN set operator *)
X      if tok = 'IN'  then
X      begin
X         gettok;
X         ex := 'inset('+ex+',' + pterm + ')';
X      end
X      else
X
X      (* ran out of legal expression operators; return what we found *)
X      begin
X         pexpr := ex;
X         exit;
X      end;
X   end;
X
Xend;
X
X
Xfunction plvalue: string;
X   {parse and translate an lvalue specification and return the translated
X    lvalue as a string}
X
Xvar
X   lv:       string;
X   expr:     string;
X   funcid:   string40;
X   pref:     string40;
X   idok:     boolean;
X   sym:      symptr;
X   func:     symptr;
X   btype:    symtypes;
X   cstype:   supertypes;
X   bstype:   supertypes;
X   pvars:    integer;
X   cbase:    integer;
X   bbase:    integer;
X      
Xbegin
X   if debug_parse then write(' <lvalue>');
X   plvalue := 'lvalue';
X
X(* lvalues must begin with an identifier in pascal *)
X   if toktype <> identifier then
X   begin
X      syntax('Identifier expected (plvalue)');
X      exit;
X   end;
X
X(* assign initial part of the lvalue *)
X   idok := false;
X   pref := '';
X   lv := ltok;
X   funcid := tok;
X   bstype := ss_scalar;
X   bbase := 0;
X   cbase := 0;
X
X   sym := cursym;
X   if sym <> nil then
X   begin
X      cstype := sym^.suptype;
X      cbase := sym^.base;
X      cexprtype := sym^.symtype;
X      lv := sym^.repid;          {use replacement identifier}
X
X      {dereference VAR paremter pointers}
X      if sym^.parcount = -2 then
X      begin
X         if debug_parse then write(' <var.deref>');
X         pref := '*';
X      end;
X      
X      {prefix with pointer if this is a member identifier and a with
X       is in effect}
X      if (sym^.parcount < 0) and (sym^.pvar > 0) and (withlevel > 0) then
X      begin
X         if debug_parse then write(' <with.deref>');
X         pref := 'with'+itoa(withlevel)+'->';
X      end;
X      
X   end;
X   
X
X(* process a list of qualifiers and modifiers *)
X   gettok;
X
X   repeat
X      if toktype = identifier then
X      begin
X
X         if cursym <> nil then               {find record member types}
X         begin
X            sym := cursym;
X            cstype := sym^.suptype;
X            cbase := sym^.base;
X            cexprtype := sym^.symtype;
X            ltok := sym^.repid;          {use replacement identifier}
X         end;
X         
X      end;
X      
X      (* process identifiers (variable or field names) *)
X      if idok and (toktype = identifier) then
X      begin
X         if debug_parse then write(' <ident>');
X         lv := lv + ltok;
X         gettok;
X         idok := false;
X      end
X      else
X
X      (* pointers *)
X      if tok = '^' then
X      begin
X         if debug_parse then write(' <deref>');
X         pref := '*' + pref;
X         gettok;
X      end
X      else
X
X      (* pointer subscripts *)
X      if tok = '^[' then
X      begin
X         if debug_parse then write(' <ptr.subs>');
X         lv := lv + '[';
X         gettok;
X
X         while tok <> ']' do
X         begin
X            lv := lv + pexpr;
X            if tok = ',' then
X            begin
X               lv := lv + '][';
X               gettok;
X            end;
X         end;
X
X         lv := lv + ']';
X         gettok;
X      end
X      else
X
X      (* pointer members *)
X      if tok = '^.' then
X      begin
X         if debug_parse then write(' <ptr.deref>');
X         lv := lv + '->';
X         gettok;
X         idok := true;
X      end
X      else
X
X      (* record members *)
X      if tok = '.' then
X      begin
X         if debug_parse then write(' <member>');
X         if pref = '*' then     {translate *id. into id->}
X         begin
X            pref := '';
X            lv := lv + '->';
X         end
X         else
X            lv := lv + '.';
X         idok := true;
X         gettok;
X      end
X      else
X
X      (* subscripts *)
X      if tok[1] = '[' then
X      begin
X         if debug_parse then write(' <subs>');
X         btype := cexprtype;
X         bstype := cstype;
X         bbase := cbase;
X
X         if copy(pref,1,1) = '*' then
X            pref := '';       {replace '*id[' with 'id['}
X
X         lv := lv + '[';
X         gettok;
X
X         repeat
X            expr := pexpr;
X
X            if tok[1] = ',' then
X            begin
X               lv := lv + expr + '][';
X               gettok;
X               bstype := ss_scalar;
X            end;
X         until tok[1] = ']';
X
X         subtract_base(expr,bbase);
X         lv := lv + expr + ']';
X
X         if (btype = s_string) and (bstype <> ss_array) then
X         begin
X            btype := s_char;
X            ltok := lv;
X            if expr = '-1' then
X               warning('Dynamic length reference');
X         end;
X
X         cexprtype := btype;
X         cstype := ss_scalar;
X         cbase := 0;
X         gettok;
X      end
X      else
X
X      (* function calls *)
X      if tok[1] = '(' then
X      begin
X         if debug_parse then write(' <func>');
X         func := locatesym(funcid);
X         pvars := 0;
X         if func <> nil then
X         begin
X            pvars := func^.pvar;          {determine return type}
X            cexprtype := func^.symtype;
X         end;
X            
X         btype := cexprtype;
X         lv := lv + '(';
X         gettok;
X
X         while tok[1] <> ')' do
X         begin
X            expr := pexpr;
X            if (pvars and 1) = 1 then     {prefix VAR paremeters}
X               make_pointer(expr);
X
X            lv := lv + expr;
X            pvars := pvars shr 1;
X
X            if (tok[1] = ',') or (tok = ':') then
X            begin
X               lv := lv + ',';
X               gettok;
X            end;
X         end;
X
X         lv := lv + ')';
X         gettok;
X         cexprtype := btype;
X      end
X      else
X
X(* otherwise just return what was found so far *)
X      begin
X
X         (* add dummy param list to function calls where the proc
X            expects no parameters *)
X         if sym <> nil then
X         begin
X            if (not iscall(lv)) and (sym^.parcount >= 0) then
X               lv := lv + '()';
X         end;
X
X         plvalue := pref + lv;
X         exit;
X      end;
X
X   until recovery;
X
X   plvalue := pref + lv;
Xend;
X
________This_Is_The_END________
if test `wc -c < tpcexpr.inc` -ne 17450; then
	echo 'shar: tpcexpr.inc was damaged during transit (should have been 17450 bytes)'
fi
fi		; : end of overwriting check
echo 'x - tpcmisc.inc'
if test -f tpcmisc.inc; then echo 'shar: not overwriting tpcmisc.inc'; else
sed 's/^X//' << '________This_Is_The_END________' > tpcmisc.inc
X
X(*
X * TPTC - Turbo Pascal to C translator
X *
X * (C) 1988 Samuel H. Smith (rev. 13-Feb-88)
X *
X *)
X
X
X(********************************************************************)
Xprocedure mark_time(var long: longint);
X   {report time in clock ticks since midnight}
Xvar
X   words:   record
X               l,h: word;
X            end   absolute long;
X   reg:     registers;
X   
Xbegin
X   reg.ah := 0;  {get time of day}
X   intr($1a,reg);
X   words.l := reg.dx;
X   words.h := reg.cx;
Xend;
X
X
X(********************************************************************)
Xprocedure abortcheck;
X   {check for the abort(escape) key}
Xvar
X   c:  char;
Xbegin
X   if keypressed then
X   begin
X      c := readkey;
X      if c = #27 then
X         fatal('Aborted by <escape> key');
X   end;
Xend;
X
X
X(********************************************************************)
Xprocedure puttok;
X   {output the current token and a space to the output}
Xbegin
X   write(ofd[unitlevel],ltok,' ');
X   linestart := false;
Xend;
X
X
X(********************************************************************)
Xprocedure putline;
X   {start a new line in the output file}
Xbegin
X   writeln(ofd[unitlevel]);
X   inc(objtotal);
X   linestart := true;
Xend;
X
X
X(********************************************************************)
Xprocedure closing_statistics;
Xvar
X   secs: real;
X   rate: real;
X
Xbegin
X
X   {terminate any active output files}
X   if in_interface then
X      pimplementation;
X   purgetable(locals,nil);
X   while unitlevel > 0 do
X      exit_procdef;
X   putline;
X   putline;
X   purgetable(globals,nil);
X   close(ofd[unitlevel]);
X
X   {determine statistics}
X   mark_time(curtime);
X   secs := int(curtime-starttime) / ticks_per_second;
X
X   {rate := int(srctotal) / secs * 60.0;}
X   rate := int(objtotal) / secs * 60.0;
X   
X   {report statistics}
X   if debug then writeln;
X   writeln(^M,srcfiles[srclevel],'(',srclines[srclevel],')');
X   writeln(srctotal,' source lines, ',
X           objtotal,' object lines, ',
X           secs:0:1,' seconds, ',
X           rate:0:0,' lines/min.');
Xend;
X
X
X(********************************************************************)
Xprocedure error_message (message:       string);
X   {place an error message into the object file and on the screen}
X
X   procedure report(var fd: text);
X   begin
X      writeln(fd,'/* TPTC: ',srcfiles[srclevel],'(',srclines[srclevel],'): ', 
X           message,', tok=', ltok,' */');
X   end;
X
Xbegin
X   if debug then writeln
X   else write(^M);
X   report(output);
X
X   putline;
X   report(ofd[unitlevel]);
X   write(ofd[unitlevel],spaces);
X   inc(objtotal);
Xend;
X
X
X(********************************************************************)
Xprocedure comment_statement;
Xbegin
X   puts(' /* ');
X
X   repeat
X      puttok;
X      gettok;
X   until (tok[1] = ';');
X
X   puts(' */ ');
Xend;
X
X
X(********************************************************************)
Xprocedure warning (message:       string);
X   {report a warning message unless warnings are disabled}
Xbegin
X   if not quietmode then
X      error_message('Warning: '+message);
Xend;
X
X
X(********************************************************************)
Xprocedure syntax (message:       string);
X   {report a syntax error and skip to the next ';'}
Xbegin
X   if (not recovery) or (not quietmode) then
X      error_message('Error: '+message);
X   gettok;
X   recovery := true;
Xend;
X
X
X(********************************************************************)
Xprocedure fatal (message:       string);
X   {abort translation with a fatal error}
Xbegin
X   error_message('Fatal: '+message);
X   closing_statistics;
X   halt(88);
Xend;
X
X
X(********************************************************************)
Xprocedure puts(s: string);
X   {output a string the output file}
Xbegin
X   write(ofd[unitlevel],s);
X   if s[1] = ^J then
X   begin
X      inc(objtotal);
X      linestart := true;
X   end
X   else
X      linestart := false;
Xend;
X
X
X(********************************************************************)
Xprocedure putln(s: string);
X   {output a string the output file and newline}
Xbegin
X   puts(s);
X   putline;
Xend;
X
X
X(********************************************************************)
Xprocedure newline;
X   {start a new line in the output file;  indent to the same level
X    as the current line}
Xbegin
X   putline;
X   write(ofd[unitlevel],spaces);
Xend;
X
X
X
________This_Is_The_END________
if test `wc -c < tpcmisc.inc` -ne 4274; then
	echo 'shar: tpcmisc.inc was damaged during transit (should have been 4274 bytes)'
fi
fi		; : end of overwriting check
echo 'x - tpcscan.inc'
if test -f tpcscan.inc; then echo 'shar: not overwriting tpcscan.inc'; else
sed 's/^X//' << '________This_Is_The_END________' > tpcscan.inc
X 
X(*
X * TPTC - Turbo Pascal to C translator
X *
X * (C) 1988 Samuel H. Smith (rev. 13-Feb-88)
X *
X *)
X
X
X(********************************************************************)
X(*
X * lexical scanner
X *
X *)
X
Xfunction numlit(n: integer): anystring;
Xvar
X   lit: string[6];
X   
X   {convert an integer into a c style numeric character literal}
X   function digit(n: integer): char;
X      (* convert an integer into a hex digit *)
X   begin
X      n := n and 15;
X      if n > 9 then n := n + 7;
X      digit := chr( n + ord('0') );
X   end;
X
Xbegin
X   lit := '''\?''';
X
X   case n of
X     $07:   lit[3] := 'a';
X     $08:   lit[3] := 'b';
X     $09:   lit[3] := 't';
X     $0a:   lit[3] := 'n';
X     $0b:   lit[3] := 'v';
X     $0c:   lit[3] := 'f';
X     $0d:   lit[3] := 'r';
X
X     32..126,128..254:
X            lit := ''''+chr(n)+'''';
X
X     else   begin
X               lit := '''\x??''';
X               lit[4] := digit(n shr 4);
X               lit[5] := digit(n);
X            end;
X   end;
X
X   numlit := lit;
X   toktype := chars;
Xend;
X
X
X(********************************************************************)
Xprocedure getchar;
X   {consume the current char and get the next one}
Xvar
X   stack: char;
Xbegin
X   if ofs(stack) < minstack then
X      fatal('Out of stack space');
X
X   while (srclevel > 0) and eof(srcfd[srclevel]) do
X   begin
X      if not linestart then putline;
X      putln('/* TPTC: end of '+srcfiles[srclevel]+' */');
X      
X      if debug then writeln;
X      writeln(^M,srcfiles[srclevel],'(',srclines[srclevel],')');
X      
X      close(srcfd[srclevel]);
X      freemem(inbuf[srclevel],inbufsiz);
X
X      dec(srclevel);
X      statustime := 0;
X   end;
X    
X   if eof(srcfd[srclevel]) then
X      nextc := '.'
X   else
X      read(srcfd[srclevel], nextc);
X
X   if nextc = ^J then
X   begin
X      inc(srclines[srclevel]);
X      inc(srctotal);
X      
X      mark_time(curtime);
X      if (curtime >= statustime) or debug then
X      begin
X         if debug then writeln;
X         write(^M,srcfiles[srclevel],'(',srclines[srclevel],')');
X         statustime := curtime+statrate;
X         abortcheck;
X      end;
X   end;
Xend;
X
X
X(********************************************************************)
Xfunction usec: char;
X   {use up the current character(return it) and get
X    the next one from the input stream}
Xvar
X   c: char;
Xbegin
X   c := nextc;
X   getchar;
X   usec := c;
Xend;
X
X
X(********************************************************************)
Xfunction newc(n: string40): string40;
X   {replace the current character with a different one and get the next
X    character from the input stream}
Xvar
X   c: char;
Xbegin
X   c := nextc;
X   getchar;
X   newc := n;
Xend;
X
X
X(********************************************************************)
Xprocedure concat_tokens;
X   {concatenate the next token and the current token}
Xvar
X   cur: string;
Xbegin
X   cur := ltok;
X   ltok := nextc;
X   toktype := unknown;
X   scan_tok;
X
X   ltok := copy(cur,1,length(cur)-1) + copy(ltok,2,255);
X   ltok[1] := '"';
X   ltok[length(ltok)] := '"';
X   toktype := strng;
Xend;
X
X
X(********************************************************************)
Xprocedure scan_ident;
X   {scan an identifier; output is ltok; nextc is first character following
X    the identifier; toktype = identifier;  this is the protocol for all of
X    the scan_xxxx procedures in the lexical analyzer}
Xbegin
X
X   toktype := unknown;
X   ltok := '';
X
X   repeat
X      case nextc of
X         'A'..'Z':
X            begin
X               if map_lower then
X                  nextc := chr( ord(nextc)+32 );
X               ltok := ltok + nextc;
X               getchar;
X            end;
X
X         'a'..'z', '0'..'9', '_','@':
X            ltok := ltok + usec;
X
X         else
X            toktype := identifier;
X      end;
X
X   until toktype = identifier;
Xend;
X
X
X
X(********************************************************************)
Xprocedure scan_preproc;
X   {scan a tshell preprocessor directive;  same syntax as C already}
Xbegin
X   puts('#');
X
X   repeat
X      puts(nextc);
X      getchar;
X   until nextc = ^M;
X
X   getchar;
X   putline;
X   toktype := unknown;
Xend;
X
X
X(********************************************************************)
Xprocedure scan_number;
X   {scan a number;  this also processes #nnn character literals, which are
X    converted into octal character literals.  imbedded periods are processed,
X    and a special condition is noted for trailing periods.  this is needed
X    for scanning the ".." keyword when used after numbers.  an ungetchar
X    facility would be more general, but isn't needed anywhere else.
X    in pascal/mt+, #nnn is translated into nnnL }
Xvar
X   hasdot:  boolean;
X   charlit:   boolean;
X   islong:  boolean;
X
Xbegin
X   hasdot := false;
X   islong := false;
X   charlit := false;
X   toktype := number;
X
X(* check for preprocessor directives, character literals or long literals *)
X   if nextc = '#' then
X   begin
X      ltok := '';
X      if mt_plus then
X         islong := true
X      else
X         charlit := true;
X   end;
X
X   getchar;
X
X(* check for preprocessor directives *)
X   if tshell and charlit and (nextc >= 'a') and (nextc <= 'z') then
X      scan_preproc
X   else
X
X   repeat
X      case nextc of
X         '$','0'..'9','a'..'f','A'..'F':
X            ltok := ltok + usec;
X
X         '.':
X            if hasdot then
X            begin
X               if ltok[length(ltok)] = '.' then
X               begin
X                  ltok[0] := pred(ltok[0]);  {remove trailing ., part of ..}
X                  if charlit then
X                     ltok := numlit(atoi(ltok));
X                  extradot := true;
X               end;
X               exit;
X            end
X            else
X
X            begin
X               hasdot := true;
X               ltok := ltok + usec;
X            end;
X
X         else
X            begin
X               if charlit then
X               begin
X                  ltok := numlit(atoi(ltok));
X                  if (nextc = '''') or (nextc = '^') or (nextc = '#') then
X                     concat_tokens;
X                  exit;
X               end;
X               
X               if ltok[1] = '$' then
X                  ltok := '0x' + copy(ltok,2,99);
X               if islong then
X                  ltok := ltok + 'L';
X               exit;
X            end;
X      end;
X
X   until true=false;
Xend;
X
X
X(********************************************************************)
Xprocedure scan_hat;
X   {scan tokens starting with ^ - returns ^X as a character literal 
X    corresponding to the specified control character.  returns ^ident as
X    an identifier with the leading ^ intact.  also scans ^. and ^[.}
Xvar
X   c: char;
X
Xbegin
X   getchar;
X
X   if ((nextc = '.') or (nextc = '[')) and 
X      ((ptoktype = identifier) or (ptok = ']')) then
X   begin
X      ltok := '^' + usec;     {^. or ^[}
X      exit;
X   end;
X
X   case nextc of
X      '@','['..'`':
X         ltok := usec;
X         
X      'A'..'Z','a'..'z':
X         begin
X            ltok := nextc;
X            scan_ident;
X         end;
X       else
X         exit;
X   end;
X
X   if length(ltok) = 1 then      {^c = control char}
X   begin
X      ltok := numlit( ord(upcase(ltok[1])) - ord('@') );
X      if (nextc = '''') or (nextc = '^') or (nextc = '#') then
X         concat_tokens;
X   end
X   else
X      ltok := '^' + ltok;        {^ident = pointer to ident}
X
Xend;
X
X
X(********************************************************************)
Xprocedure scan_dot;
X   {scans tokens starting with "."; knows about the 'extra dot' condition
X    that comes up in number scanning.  returns a token of either '.' or '..'}
Xbegin
X   getchar;
X
X   if (nextc = '.') or extradot then
X   begin
X      ltok := '..';
X      extradot := false;
X   end;
X
X   if nextc = '.' then
X      getchar;
Xend;
X
X
X(********************************************************************)
Xprocedure scan_string;
X   {scans a literal string.  processes imbedded quotes ala pascal.  translates
X    the string into a C string with the proper escapes on imbedded quotes.
X    converts single character strings into character constants.  these are
X    sometimes converted back to strings when the parser needs to}
Xbegin
X   toktype := unknown;
X   ltok := '"';
X   getchar;
X
X   repeat
X      case nextc of
X         ^J,^M:
X            begin
X               error_message('Closing quote expected (scan_string)');
X               toktype := strng;
X            end;
X      
X         '''':
X            begin
X               getchar;     {consume the quote}
X      
X               if nextc = '''' then
X                  ltok := ltok + usec
X                  {double quotes are coded as a single quote}
X               else
X      
X               begin        {end of string}
X                  ltok := ltok + '"';
X                  toktype := strng;
X               end;
X            end;
X      
X         '"':  ltok := ltok + newc('\"');
X         '\':  ltok := ltok + newc('\\');
X
X         else  ltok := ltok + usec;
X      end;
X
X   until toktype = strng;
X
X   if length(ltok) = 3 then
X   begin
X      ltok[1] := '''';
X      ltok[3] := '''';
X      toktype := chars;
X   end;
X
X   if ltok = '"\""' then
X   begin
X      ltok := '''"''';
X      toktype := chars;
X   end
X   else
X
X   if (ltok = '"''"') or (ltok = '''''''') then
X      ltok := '''\'''''
X   else
X
X   if (ltok = '"\\"') then
X   begin
X      ltok := '''\\''';
X      toktype := chars;
X   end;
X
X   if (nextc = '^') or (nextc = '#') then
X      concat_tokens;
Xend;
X
X
X(********************************************************************)
Xprocedure scan_pragma(var isinclude: anystring);
X   {scans a turbo pascal compiler option and translates it into a comment.
X    include directive is translated into the #include.
X    returns with the first non-blank after the pragma}
Xvar
X   code: anystring;
X   prag: anystring;
X   arg:  anystring;
X
X   procedure scanword(var dest: anystring);
X   begin
X      dest := '       ';  {insure dest[2] is initialized}
X      dest := '';
X      while true do
X      case nextc of
X         ' ', '*', '}', ',':
X            exit;
X         else
X         begin
X            dest := dest + upcase(nextc);
X            getchar;
X         end;
X      end;
X   end;
X   
Xbegin
X   isinclude := '';
X   
X   repeat
X      if nextc = ',' then
X         newline;
X
X      getchar;   {consume the $ or ,}
X   
X      {get the progma code}
X      scanword(code);
X      
X      if nextc = ' ' then
X      begin
X         getchar;
X         scanword(arg);
X      end
X      else
X         arg := '';
X      
X      if code[2] = '+' then
X         arg := 'ON'
X      else
X      if code[2] = '-' then
X         arg := 'OFF';
X
X      prag := '/* '+code[1]+'(' + arg + ')' + ' */';
X      
X      case code[1] of
X
X         'D':  if code[2] = 'E' then
X                  prag := '#define '+arg;
X               
X         'E':  if code[2] = 'N' then
X                  prag := '#endif'
X               else
X               if code[2] = 'L' then
X                  prag := '#else';
X               
X         'I':  if code[2] = ' ' then
X               begin
X                  if pos('.',arg) = 0 then
X                     arg := arg + '.PAS';
X                  prag := '#include "' + arg + '"   ';
X                           
X                  if includeinclude then
X                  begin
X                     prag := '';
X                     isinclude := arg;
X                  end;
X               end
X               else
X               
X               if code[2] = 'F' then
X               begin
X                  if code[3] = 'N' then
X                     prag := '#ifndef '+arg
X                  else
X                     prag := '#ifdef '+arg;
X               end;
X
X         'U':  if code[2] = 'N' then
X                  prag := '#undef '+arg;
X               
X      end;
X
X      puts(prag);
X      puts('   ');
X
X      while nextc = ' ' do
X         getchar;
X
X   until nextc <> ',';
X
Xend;
X
X
X(********************************************************************)
Xprocedure open_include(name: anystring);
Xbegin
X   if length(name) = 0 then exit;
X   
X   inc(srctotal);
X   inc(objtotal);
X
X   inc(srclevel);
X   if srclevel > maxincl then
X      fatal('Includes nested too deeply');
X      
X   srcfiles[srclevel] := name;
X   srclines[srclevel] := 1;
X   
X   assign(srcfd[srclevel],name);
X   {$I-} reset(srcfd[srclevel]); {$I+}
X   if ioresult <> 0 then
X   begin
X      dec(srclevel);
X      ltok := name;
X      warning('Missing include file');
X   end
X   else
X
X   begin
X      if not linestart then putline;
X      putln('/* TPTC: include '+name+' */');
X
X      if maxavail-300 <= inbufsiz then
X      begin
X         ltok := name;
X         fatal('Out of memory');
X      end;
X         
X      getmem(inbuf[srclevel],inbufsiz);
X      SetTextBuf(srcfd[srclevel],inbuf[srclevel]^,inbufsiz);
X   end;
X   
X   if {quietmode and} not debug then
X      write(^M,'':40,^M)
X   else
X      writeln;
X   statustime := 0;
Xend;
X
X
X(********************************************************************)
Xprocedure scan_curlycomment;
X   {processes a curly-brace enclosed comment}
Xvar
X   isinclude: anystring;
X   
Xbegin
X   toktype := comment;
X   getchar;   {consume the open comment}
X
X   isinclude := '';
X   if nextc = '$' then
X      scan_pragma(isinclude);
X
X   if nextc = '}' then
X   begin
X      getchar;
X      open_include(isinclude);
X      exit;
X   end;
X
X   if pass_comments then
X      puts('  /* ');
X
X   while nextc <> '}' do
X   begin
X      if pass_comments then
X         puts(nextc);
X      getchar;
X   end;
X
X   if pass_comments then
X   begin
X      puts(' */ ');
X      if nospace then newline;
X   end;
X
X   getchar;   {consume the close comment}
X   open_include(isinclude);
Xend;
X
X
X(********************************************************************)
Xprocedure scan_parencomment;
X   {process a (* enclosed comment}
Xvar
X   isinclude: anystring;
X   
Xbegin
X   toktype := comment;
X   getchar;   {consume the *}
X
X   isinclude := '';
X   if nextc = '$' then
X      scan_pragma(isinclude);
X
X   if pass_comments then
X      puts('/*');
X
X   repeat
X      if pass_comments then
X         puts(nextc);
X
X      if nextc = '*' then
X      begin
X         getchar;
X
X         if nextc = ')' then
X         begin
X            getchar;
X            if pass_comments then
X            begin
X               puts('/ ');
X               if nospace then putline;
X            end;
X            open_include(isinclude);
X            exit;
X         end;
X      end
X      else
X         getchar;
X
X   until true=false;
Xend;
X
X
X(********************************************************************)
Xprocedure scan_blanks;
X   {scan white space.  this procedure sometimes passes whitespace to the
X    output.  it keeps track of the indentation of the current line so it
X    can be used by newline}
Xvar
X   indent:        anystring;
X   valid:         boolean;
X
Xbegin
X   linestart := false;
X   indent := '';
X   valid := false;
X
X   repeat
X
X      case nextc of
X         ^J,^M:  begin
X                    if (nospace = false) and (nextc = ^J) then 
X                       putline;
X                    
X                    indent := '';
X                    linestart := true;
X                    getchar;
X                 end;
X
X         ' ',^I,^@,^L:
X                 indent := indent + usec;
X
X         '#':    if linestart and tshell then
X                 begin
X                    puts(indent);     {pass preprocessor directives}
X                    indent := '';     {without change (single-line only)}
X
X                    repeat
X                       puts(nextc);
X                       getchar;
X                    until nextc = ^M;
X
X                    getchar;
X                    putline;
X                 end
X                 else
X                    valid := true;
X
X         else
X                 valid := true;
X      end;
X
X   until valid;
X
X   if linestart then
X   begin
X      spaces := indent;
X      if nospace=false then
X         puts(spaces);
X
X      linestart := true;
X   end;
Xend;
X
X
X(********************************************************************)
Xprocedure scan_tok;
X   {scans the next lexical token; returns the token in ltok and toktype}
Xbegin
X   scan_blanks;
X
X   toktype := unknown;
X   ltok := nextc;
X
X   case nextc of
X      'a'..'z', 
X      '_', 'A'..'Z': scan_ident;
X
X      '$':           scan_number;
X      '0'..'9':      scan_number;
X
X      '''':          scan_string;
X
X      '^':           scan_hat;
X
X      '#':           begin
X                        scan_number;
X                        if toktype = unknown then
X                           scan_tok;         {in case of #directive}
X                     end;
X
X
X      '<':           begin
X                        getchar;
X                        if (nextc = '>') or (nextc = '=') then
X                           ltok := '<' + usec;
X                     end;
X
X      '>':           begin
X                        getchar;
X                        if nextc = '=' then
X                           ltok := '>' + usec;
X                     end;
X
X      ':':           begin
X                        getchar;
X                        if nextc = '=' then
X                           ltok := ':' + usec;
X                     end;
X
X      '.':           scan_dot;
X
X      '{':           scan_curlycomment;
X
X      '(':           begin
X                        getchar;
X                        if nextc = '*' then
X                           scan_parencomment;
X                     end;
X
X      else           getchar;   {consume the unknown char}
X   end;
Xend;
X
X
X(********************************************************************)
Xprocedure gettok;
X   {get the next input token;  this is the top level of the lexical analyzer.
X    it returns ltok, tok(ltok in upper case), toktype.  it translates BEGIN
X    and END into braces; it checks for statement and section keywords}
Xvar
X   i:             integer;
X
Xbegin
X   ptoktype := toktype;
X   ptok := tok;
X   cursym := nil;
X   
X   repeat
X      scan_tok;
X   until toktype <> comment;
X   tok := ltok;
X
X   if debug then write(' {',ltok,'}');
X
X   if toktype = identifier then
X   begin
X      stoupper(tok);
X
X      if tok = 'BEGIN' then
X      begin
X         tok := '{';
X         ltok := tok;
X         toktype := keyword;
X      end
X      else
X
X      if tok = 'END' then
X      begin
X         tok := '}';
X         ltok := tok;
X         toktype := keyword;
X      end;
X
X      (* check for statement keywords *)
X      i := 0;
X      repeat
X         inc(i);
X         if tok[1] = keywords[i][1] then              {hack for speed}
X         if length(tok) = length(keywords[i]) then
X         if tok = keywords[i] then
X            toktype := keyword;
X      until (i = nkeywords) or (toktype = keyword);
X
X      (* get symbol table information for this item *)
X      cursym := locatesym(tok);
X   end;
Xend;
X
X
X(********************************************************************)
Xfunction usetok: string80;
X   {return (use) and consume current token}
Xvar
X   tv: string80;
Xbegin
X   tv := ltok;
X   gettok;
X   usetok := tv;
Xend;
X
X
________This_Is_The_END________
if test `wc -c < tpcscan.inc` -ne 18755; then
	echo 'shar: tpcscan.inc was damaged during transit (should have been 18755 bytes)'
fi
fi		; : end of overwriting check
exit 0