home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / compcomp / tpyacc / kwtbl.pas < prev    next >
Pascal/Delphi Source File  |  1991-06-17  |  8KB  |  278 lines

  1.  
  2. (* KWTBL - prepare keyword tables for use in lexical analyzers
  3.  
  4.    USAGE: kwtbl [<input-file] [>output-file]
  5.  
  6.    DESCRIPTION
  7.  
  8.    KWTBL is a tiny utility that helps you prepare keyword tables for use
  9.    in lexical analyzers, such as yylex routines prepared with the TP Lex
  10.    program.
  11.  
  12.    In languages with a large number of keywords it is often more efficient
  13.    to analyze the reserved words using a general pattern, and then use a
  14.    table lookup procedure to determine the actual code for the keyword.
  15.    Also, large keyword tables in a Lex grammar can easily cause TP Lex to
  16.    overflow; in such cases the KWTBL utility is useful.
  17.  
  18.    KWTBL reads in a list of (keyword, code) pairs, sorts keywords alpha-
  19.    betically, and writes out two typed array constants, one containing
  20.    the keyword strings and the other containing the corresponding codes.
  21.    These tables may be accessed through a binary table lookup procedure
  22.    which is appended to the end of the output file. The code for the
  23.    table lookup procedure is assumed to be in the file 'KWTBL.COD' which
  24.    must be present either in the current directory or in the directory
  25.    from which KWTBL was executed; without this file, KWTBL does not
  26.    generate the table lookup procedure.
  27.  
  28.    Consider a typical programming language with identifiers and certain
  29.    reserved words which look like identifiers. The corresponding rules
  30.    of your TP Lex program might look like:
  31.  
  32.    if        return( _IF_ );
  33.    while    return( _WHILE_ );
  34.    ...
  35.    [A-Za-z]+    return( ID );
  36.  
  37.    Alternatively, you can use KWTBL to produce a keyword table lookup
  38.    procedure. The input to KWTBL will be something like:
  39.  
  40.    if        _IF_
  41.    while    _WHILE_
  42.    ...
  43.  
  44.    Each keyword entry is on a separate line, and keyword and corresponding
  45.    code are separated by whitespace (blanks and/or tabs). Empty lines are
  46.    ignored. You do not have to sort the keyword entries; KWTBL will do that
  47.    for you. The code for a keyword can actually be any character sequence
  48.    which denotes a legal constant integer expression.
  49.  
  50.    From the keyword table, KWTBL produces two typed array constants:
  51.  
  52.    const
  53.  
  54.    nkws = ...;   { number of different keywords }
  55.    kwsize = ...; { maximum size of keywords }
  56.  
  57.    kwtbl : array [ 1..nkws ] of String[ kwsize ] = (
  58.      ..., 'if', ..., 'while', ...
  59.    );
  60.  
  61.    kwcod : array [ 1..nkws ] of Integer = (
  62.      ..., _IF_, ..., _WHILE_, ...
  63.    );
  64.  
  65.    These tables may be accessed through the table lookup procedure (named
  66.    kwlookup in the standard version of the KWTBL.COD file). The corresponding
  67.    Lex code will now be:
  68.  
  69.    [A-Za-z]+    if kwlookup( yytext, code ) then
  70.              return( code )
  71.                 else
  72.                   return( ID );
  73. *)
  74.  
  75. uses Dos;
  76.  
  77. (* Quicksort: *)
  78.  
  79. type
  80.  
  81. OrderPredicate = function (i, j : Integer) : Boolean;
  82. SwapProc = procedure (i, j : Integer);
  83.  
  84. procedure quicksort(lo, hi: Integer;
  85.                     less : OrderPredicate;
  86.                     swap : SwapProc);
  87.   (* derived from the quicksort routine in QSORT.PAS in the Turbo Pascal
  88.      distribution *)
  89.   procedure sort(l, r: Integer);
  90.     var i, j, k : Integer;
  91.     begin
  92.       i := l; j := r; k := (l+r) DIV 2;
  93.       repeat
  94.         while less(i, k) do inc(i);
  95.         while less(k, j) do dec(j);
  96.         if i<=j then
  97.           begin
  98.             swap(i, j);
  99.             if k=i then k := j (* pivot element swapped! *)
  100.             else if k=j then k := i;
  101.             inc(i); dec(j);
  102.           end;
  103.       until i>j;
  104.       if l<j then sort(l,j);
  105.       if i<r then sort(i,r);
  106.     end(*sort*);
  107.   begin
  108.     if lo<hi then sort(lo,hi);
  109.   end(*quicksort*);
  110.  
  111. const
  112.  
  113. maxkws = 100;     (* maximum number of keywords *)
  114. maxkwsize = 40;     (* maximum keyword size; longer keywords are truncated *)
  115. maxcodsize = 40; (* maximum code size; longer keyword codes are truncated *)
  116.  
  117. type
  118.  
  119. KwString = String[ maxkwsize ];
  120. CodString = String [ maxcodsize ];
  121.  
  122. var
  123.  
  124. (* the keyword table: *)
  125.  
  126. nkws, kwsize : Integer;
  127.  
  128. kwtbl : array [ 1..maxkws ] of KwString;
  129. kwcod : array [ 1..maxkws ] of CodString;
  130.  
  131. var stderr : Text;
  132.  
  133. procedure error( msg : String );
  134.   (* write out an error message *)
  135.   begin
  136.     writeln( stderr, '*** ', msg );
  137.   end(*error*);
  138.  
  139. procedure fatal( msg : String );
  140.   (* write error message and halt program *)
  141.   begin
  142.     error( 'fatal: '+msg );
  143.     halt ( 1 );
  144.   end(*fatal*);
  145.  
  146. procedure split( line : String; var kw : KwString; var cod : CodString );
  147.   (* split a line in keyword and code part *)
  148.   const tab = ^I;
  149.   var i : Integer;
  150.   begin
  151.     kw := ''; i := 1;
  152.     while (i<=length(line)) and (line[i]<>' ') and (line[i]<>tab) do
  153.       begin
  154.         if length(kw)<maxkwsize then kw := kw+line[i];
  155.         inc(i);
  156.       end;
  157.     while (i<=length(line)) and ((line[i]=' ') or (line[i]=tab)) do inc(i);
  158.     cod := copy( line, i, length(line) );
  159.   end(*split*);
  160.  
  161. function path( filename : String ) : String;
  162.   (* return the drive/directory part of a filename *)
  163.   var d : DirStr; n : NameStr; e : ExtStr;
  164.   begin
  165.     fsplit( filename, d, n, e );
  166.     path := d;
  167.   end(*path*);
  168.  
  169. function intStr( i : Integer ) : String;
  170.   (* convert an integer to a string *)
  171.   var s : String;
  172.   begin
  173.     Str( i, s );
  174.     intStr := s;
  175.   end(*intStr*);
  176.  
  177. (* Routines to sort the keyword table: *)
  178.  
  179. {$F+}
  180. function less( i, j : Integer ) : Boolean;
  181.   begin
  182.     less := kwtbl[i]<kwtbl[j];
  183.   end(*less*);
  184. procedure swap( i, j : Integer );
  185.   var kw : KwString; cod : CodString;
  186.   begin
  187.     kw := kwtbl[i]; cod := kwcod[i];
  188.     kwtbl[i] := kwtbl[j]; kwcod[i] := kwcod[j];
  189.     kwtbl[j] := kw; kwcod[j] := cod;
  190.   end(*swap*);
  191. {$F-}
  192.  
  193. var line : String; i, lineno, actcol : Integer; codfile : Text;
  194.  
  195. begin
  196.   (* open stderr device: *)
  197.   assign( stderr, '' ); rewrite( stderr );
  198.   TextRec(stderr).handle := 2;
  199.   TextRec(stderr).bufSize := 1;
  200.   (* read in the keyword table from standard input: *)
  201.   nkws := 0; kwsize := 0; lineno := 0;
  202.   while not eof do
  203.     begin
  204.       readln( line ); inc( lineno );
  205.       if line<>'' then
  206.         begin
  207.           inc( nkws );
  208.           if nkws>maxkws then fatal( 'too many keywords' );
  209.           split( line, kwtbl[ nkws ], kwcod[ nkws ] );
  210.           if ( kwtbl[ nkws ]='' ) or ( kwcod[ nkws ] = '' ) then
  211.             begin
  212.               error( 'error in line '+intStr( lineno ) );
  213.               dec( nkws );
  214.             end
  215.       else if length(kwtbl[nkws])>kwsize then
  216.         kwsize := length(kwtbl[nkws]);
  217.         end;
  218.     end;
  219.   (* sort the keyword table: *)
  220.   quicksort( 1, nkws, less, swap );
  221.   (* produce output code: *)
  222.   if nkws=0 then fatal( 'nothing to do' );
  223.   writeln;
  224.   writeln( 'const' );
  225.   writeln;
  226.   writeln('nkws = ', nkws, ';' );
  227.   writeln('kwsize = ', kwsize, ';' );
  228.   writeln;
  229.   writeln('kwtbl : array [ 1..nkws ] of String[ kwsize ] = (' );
  230.   write( '  ' ); actcol := 3;
  231.   for i := 1 to nkws do
  232.     begin
  233.       if actcol+length(kwtbl[i])>79 then
  234.         begin
  235.           writeln; write( '  ' ); actcol := 3;
  236.         end;
  237.       write( '''', kwtbl[i], '''' ); inc( actcol, length( kwtbl[i] )+2 );
  238.       if i<nkws then
  239.         begin
  240.           write( ', ' ); inc( actcol, 2 );
  241.         end;
  242.     end;
  243.   writeln;
  244.   writeln( ');' );
  245.   writeln;
  246.   writeln('kwcod : array [ 1..nkws ] of Integer = (' );
  247.   write( '  ' ); actcol := 3;
  248.   for i := 1 to nkws do
  249.     begin
  250.       if actcol+length(kwcod[i])>79 then
  251.         begin
  252.           writeln; write( '  ' ); actcol := 3;
  253.         end;
  254.       write( kwcod[i] ); inc( actcol, length( kwcod[i] ) );
  255.       if i<nkws then
  256.         begin
  257.           write( ', ' ); inc( actcol, 2 );
  258.         end;
  259.     end;
  260.   writeln;
  261.   writeln( ');' );
  262.   writeln;
  263.   (* copy KWTBL.COD file to the output: *)
  264.   {$I-}
  265.   assign( codfile, 'KWTBL.COD' ); reset( codfile );
  266.   if ioresult<>0 then
  267.     begin
  268.       assign( codfile, path( paramStr(0) )+'KWTBL.COD' ); reset( codfile );
  269.       if ioresult<>0 then halt;
  270.     end;
  271.   while not eof( codfile ) do
  272.     begin
  273.       readln( codfile, line );
  274.       writeln( line );
  275.     end;
  276.   close( codfile );
  277. end.
  278.