v04i023: Turbo Pascal to C, part 2/4
Alan Strassberg
alan at leadsv.UUCP
Mon Aug 15 08:54:56 AEST 1988
Posting-number: Volume 4, Issue 23
Submitted-by: "Alan Strassberg" <alan at 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
More information about the Comp.sources.misc
mailing list