DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦aced30ac9⟧ TextFile

    Length: 367028 (0x599b4)
    Types: TextFile
    Notes: R1k Text-file segment

Derivation

└─⟦8527c1e9b⟧ Bits:30000544 8mm tape, Rational 1000, Arrival backup of disks in PAM's R1000
    └─ ⟦5a81ac88f⟧ »Space Info Vol 1« 
        └─⟦8e47d4d95⟧ 
            └─⟦this⟧ 

TextFile


-- TITLE aflex - main program
--
-- AUTHOR: John Self (UCI)
-- DESCRIPTION main subprogram of aflex, calls the major routines in order
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/aflex.a,v 1.11 90/10/15 20:00:40 self Exp Locker: self $ 
--*************************************************************************** 
--                              aflex
--                          version 1.1c
--***************************************************************************
--
--                            Arcadia Project
--               Department of Information and Computer Science
--                        University of California
--                        Irvine, California 92717
--
--    Send requests for aflex information to alex-info@ics.uci.edu
--
--    Send bug reports for aflex to alex-bugs@ics.uci.edu
--
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
--
--    This program is based on the flex program written by Vern Paxson.
--
--    The following is the copyright notice from flex, from which aflex is
--    derived.
--	Copyright (c) 1989 The Regents of the University of California.
--	All rights reserved.
--
--	This code is derived from software contributed to Berkeley by
--	Vern Paxson.
--
--      The United States Government has rights in this work pursuant to
--	contract no. DE-AC03-76SF00098 between the United States Department of
--	Energy and the University of California.
--
--	Redistribution and use in source and binary forms are permitted
--	provided that the above copyright notice and this paragraph are
--	duplicated in all such forms and that any documentation,
--	advertising materials, and other materials related to such
--	distribution and use acknowledge that the software was developed
--	by the University of California, Berkeley.  The name of the
--	University may not be used to endorse or promote products derived
--	from this software without specific prior written permission.
--	THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
--	IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
--	WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
--
--***************************************************************************

with MAIN_BODY, DFA, GEN, MISC_DEFS, TEXT_IO, MISC; 
with TSTRING, TEMPLATE_MANAGER, EXTERNAL_FILE_MANAGER; use MISC_DEFS, TEXT_IO, 
  TSTRING, EXTERNAL_FILE_MANAGER; 
function AFLEX return INTEGER is 
	copyright : constant string :=
    "@(#) Copyright (c) 1990 Regents of the University of California.";
    	copyright2 : constant string :=
    "All rights reserved.";
begin
  MAIN_BODY.AFLEXINIT; 

  MAIN_BODY.READIN; 

  if (SYNTAXERROR) then 
    MAIN_BODY.AFLEXEND(1); 
  end if; 

  if (PERFORMANCE_REPORT) then 
    if (INTERACTIVE) then 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, 
        "-I (interactive) entails a minor performance penalty"); 
    end if; 


  end if; 

  if (VARIABLE_TRAILING_CONTEXT_RULES) then 
    MISC.AFLEXERROR("can't handle variable trailing context rules"); 
  end if; 

  -- convert the ndfa to a dfa
  DFA.NTOD; 

  -- generate the Ada state transition tables from the DFA
  GEN.MAKE_TABLES; 

  TEMPLATE_MANAGER.GENERATE_IO_FILE; 
  TEMPLATE_MANAGER.GENERATE_DFA_FILE; 
  MAIN_BODY.AFLEXEND(0); 
  return 0; 
exception
  when MAIN_BODY.AFLEX_TERMINATE => 
    return MAIN_BODY.TERMINATION_STATUS; 
end AFLEX; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE  scanner parser interface
-- AUTHOR: John Self (UCI)
-- DESCRIPTION causes parser to call augmented version of YYLex.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/aflex_scanner.a,v 1.3 90/01/12 15:19:33 self Exp Locker: self $ 

with PARSE_TOKENS, SCANNER; use PARSE_TOKENS, SCANNER; 

package AFLEX_SCANNER is 
  function YYLEX return TOKEN; 
end AFLEX_SCANNER; 

with PARSE_TOKENS, SCANNER; use PARSE_TOKENS, SCANNER; 

package body AFLEX_SCANNER is 
  function YYLEX return TOKEN is 
  begin
    return SCANNER.GET_TOKEN; 
  end YYLEX; 

end AFLEX_SCANNER; 
-- A lexical scanner generated by aflex
with text_io; use text_io;
with ascan_dfa; use ascan_dfa; 
with ascan_io; use ascan_io; 
--# line 1 "ascan.l"
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-- TITLE scanner specification file
-- AUTHOR: John Self (UCI)
-- DESCRIPTION regular expressions and actions matching tokens
--             that aflex expects to find in its input.
-- NOTES input to aflex (NOT alex.)  It uses exclusive start conditions
--       and case insensitive scanner generation available only in aflex
--       (or flex if you use C.)
--       generate scanner using the command 'aflex -is ascan.l'
-- $Header: /dc/uc/self/arcadia/aflex/ada/src/RCS/ascan.l,v 1.19 1991/12/03 23:08:24 self Exp self $ 
--# line 44 "ascan.l"


with misc_defs, misc, sym, parse_tokens, int_io;
with tstring, ascan_dfa, ascan_io, external_file_manager;
use misc_defs, parse_tokens, tstring;
use ascan_dfa, ascan_io, external_file_manager;

package scanner is
    call_yylex : boolean := false;
    function get_token return Token;
end scanner;

package body scanner is

beglin : boolean := false;
i, bracelevel: integer;

function get_token return Token is
    toktype : Token;
    didadef, indented_code : boolean;
    cclval : integer;
    nmdefptr : vstring;
    nmdef, tmpbuf : vstring;

procedure ACTION_ECHO is
begin
    text_io.put( temp_action_file, yytext(1..YYLength) );
end ACTION_ECHO;

procedure MARK_END_OF_PROLOG is
begin
     text_io.put( temp_action_file, "%%%% end of prolog" );
     text_io.new_line( temp_action_file );
end MARK_END_OF_PROLOG;

procedure PUT_BACK_STRING(str : vstring; start : integer) is
begin
	for i in reverse start+1..tstring.len(str) loop
	    unput( CHAR(str,i) );
	end loop;
end PUT_BACK_STRING;

function check_yylex_here return boolean is
begin
	return ( (yytext'length >= 2) and then
			((yytext(1) = '#') and (yytext(2) = '#')));
end check_yylex_here;

function YYLex return Token is
subtype short is integer range -32768..32767;
    yy_act : integer;
    yy_c : short;

-- returned upon end-of-file
YY_END_TOK : constant integer := 0;
YY_END_OF_BUFFER : constant := 82;
subtype yy_state_type is integer;
yy_current_state : yy_state_type;
INITIAL : constant := 0;
SECT2 : constant := 1;
SECT2PROLOG : constant := 2;
SECT3 : constant := 3;
PICKUPDEF : constant := 4;
SC : constant := 5;
CARETISBOL : constant := 6;
NUM : constant := 7;
QUOTE : constant := 8;
FIRSTCCL : constant := 9;
CCL : constant := 10;
ACTION : constant := 11;
RECOVER : constant := 12;
BRACEERROR : constant := 13;
ACTION_STRING : constant := 14;
yy_accept : constant array(0..206) of short :=
    (   0,
        0,    0,    0,    0,    0,    0,   80,   80,    0,    0,
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
       82,   13,    6,   12,   10,    1,   11,   13,   13,   13,
        9,   39,   31,   32,   25,   39,   38,   23,   39,   39,
       39,   31,   21,   39,   39,   24,   81,   19,   80,   80,
       15,   14,   16,   45,   81,   41,   42,   44,   46,   60,
       61,   58,   57,   59,   47,   49,   48,   47,   53,   52,
       53,   53,   55,   55,   55,   56,   66,   71,   70,   72,
       66,   72,   67,   64,   65,   81,   17,   63,   62,   73,

       75,   76,   77,    6,   12,   10,    1,   11,    0,    0,
        2,    0,    7,    4,    5,    0,    9,   31,   32,    0,
       28,    0,    0,    0,   78,   78,   27,   26,   27,    0,
       31,   21,    0,    0,   35,    0,    0,   19,   18,   80,
       80,   15,   14,   43,   44,   57,   79,   79,   50,   51,
       54,   66,    0,   69,    0,   66,   67,    0,   17,   73,
       74,    0,    7,    0,    0,    3,    0,   29,    0,   36,
        0,   78,   27,   27,   37,    0,    0,    0,   35,    0,
       30,   79,   66,   68,    0,    0,    8,    0,    0,    0,
        0,    0,    0,    0,    0,    0,    0,   22,    0,   22,

        0,   22,    4,    0,   34,    0
    ) ;

yy_ec : constant array(CHARACTER'FIRST..CHARACTER'LAST) of short :=
    (   0,
        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
        1,    4,    1,    1,    1,    1,    1,    1,    1,    1,
        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
        1,    5,    1,    6,    7,    8,    9,    1,   10,   11,
       11,   11,   11,   12,   13,   11,   14,   15,   15,   15,
       15,   15,   15,   15,   15,   15,   15,    1,    1,   16,
        1,   17,   11,    1,   23,   22,   22,   22,   24,   25,
       22,   22,   22,   22,   22,   22,   22,   22,   26,   22,
       22,   27,   28,   29,   22,   22,   22,   30,   22,   22,
       18,   19,   20,   21,   22,    1,   23,   22,   22,   22,

       24,   25,   22,   22,   22,   22,   22,   22,   22,   22,
       26,   22,   22,   27,   28,   29,   22,   22,   22,   30,
       22,   22,   31,   32,   33,    1,    1
    ) ;

yy_meta : constant array(0..33) of short :=
    (   0,
        1,    2,    3,    2,    2,    4,    1,    1,    1,    5,
        1,    1,    6,    5,    7,    1,    1,    1,    8,    9,
        1,   10,   10,   10,   10,   10,   10,   10,   10,   10,
        5,   11,   12
    ) ;

yy_base : constant array(0..254) of short :=
    (   0,
        0,   29,   58,   89,  503,  499,  498,  305,    4,    8,
      119,  147,  286,  285,   32,   34,   65,   67,   93,   96,
      110,  113,  177,    0,  302,  301,   12,   15,   82,  121,
      303,  880,   76,  880,    0,   37,  880,  299,   11,  288,
        0,  880,   11,  880,  880,   14,  880,  284,  280,  283,
      196,  225,  880,  288,  283,  880,  292,    0,  291,  880,
        0,  133,  880,  880,  880,  880,  272,    0,  880,  880,
      880,  880,  277,  880,  880,  880,  880,  276,  880,  880,
      274,  275,  880,    0,  272,  880,    0,  880,  880,  109,
      273,  880,    0,  880,  880,  282,  880,  880,  880,    0,

      880,  880,    0,  149,  880,    0,  152,  880,  271,  280,
      880,  272,    0,  247,  880,  263,    0,   72,  880,  262,
      880,  240,   63,  119,  880,  248,    0,  880,  245,  249,
      277,  880,  248,  153,    0,  256,  253,    0,  880,  252,
      880,    0,  156,  880,    0,  239,  880,  238,  880,  880,
      880,    0,  221,  880,    0,  309,    0,  249,  880,    0,
      880,  248,    0,  227,  246,  880,  245,  880,  221,  880,
      148,  231,    0,    0,  880,  232,  229,  230,    0,  241,
      880,  226,    0,  880,  236,  234,  880,  209,  210,  197,
      231,  212,  159,  128,  108,  194,  115,  880,  108,  880,

       84,  880,  880,    4,  880,  880,  342,  354,  366,  378,
      390,  402,  414,  426,  438,  450,  462,  474,  486,  493,
      502,  508,  520,  527,  536,  547,  559,  571,  583,  595,
      607,  619,  631,  638,  648,  660,  672,  684,  695,  702,
      712,  724,  736,  748,  760,  772,  784,  795,  807,  819,
      831,  843,  855,  867
    ) ;

yy_def : constant array(0..254) of short :=
    (   0,
      207,  207,  208,  208,  209,  209,  210,  210,  211,  211,
      212,  212,  213,  213,  214,  214,  215,  215,  216,  216,
      217,  217,  206,   23,  218,  218,  213,  213,  219,  219,
      206,  206,  206,  206,  220,  221,  206,  222,  223,  206,
      224,  206,  225,  206,  206,  206,  206,  206,  226,  227,
      228,  229,  206,  206,  206,  206,  230,  231,  232,  206,
      233,  206,  206,  206,  206,  206,  206,  234,  206,  206,
      206,  206,  206,  206,  206,  206,  206,  227,  206,  206,
      235,  236,  206,  237,  227,  206,  238,  206,  206,  239,
      238,  206,  240,  206,  206,  241,  206,  206,  206,  242,

      206,  206,  243,  206,  206,  220,  221,  206,  206,  222,
      206,  206,  244,  206,  206,  245,  224,  225,  206,  246,
      206,  206,  226,  226,  206,  206,  247,  206,  247,  206,
      229,  206,  206,  246,  248,  249,  230,  231,  206,  232,
      206,  233,  206,  206,  234,  206,  206,  206,  206,  206,
      206,  238,  239,  206,  239,  206,  240,  241,  206,  242,
      206,  250,  244,  206,  245,  206,  246,  206,  206,  206,
      226,  206,  247,  129,  206,  206,  249,  246,  248,  249,
      206,  206,  156,  206,  251,  250,  206,  206,  206,  226,
      252,  253,  254,  206,  206,  226,  252,  206,  253,  206,

      254,  206,  206,  206,  206,    0,  206,  206,  206,  206,
      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,
      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,
      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,
      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,
      206,  206,  206,  206
    ) ;

yy_nxt : constant array(0..913) of short :=
    (   0,
      206,   33,   34,   33,   33,   62,   63,   62,   62,   62,
       63,   62,   62,  119,   98,  121,  121,   98,  121,  113,
      205,   35,   35,   35,   35,   35,   35,   35,   35,   35,
       36,   37,   36,   36,   71,   38,   71,   39,  114,  108,
      115,   40,  120,   72,   99,   72,   73,   99,   73,  109,
       41,   41,   41,   41,   41,   41,   41,   41,   41,   43,
       44,   43,   43,   45,   74,   46,   74,   76,   47,   76,
       77,   47,   77,   48,  119,   49,   50,  104,  105,  104,
      104,  124,  170,   78,  101,   78,  202,  102,   51,   47,
       52,   53,   52,   52,   45,   65,   46,   54,   65,   47,

      103,   55,   47,  120,   48,   80,   49,   50,   80,   56,
      200,   81,   65,   82,   81,   65,   82,  198,  154,   51,
       47,   65,   84,  101,  204,   84,  102,  155,   85,   86,
       66,   85,   86,  171,  143,   67,  143,  143,  123,  103,
       68,   68,   68,   68,   68,   68,   68,   68,   68,   65,
      104,  105,  104,  104,  108,  168,  203,  143,   66,  143,
      143,  202,  190,   67,  109,  178,  124,  170,   68,   68,
       68,   68,   68,   68,   68,   68,   68,   87,   87,   88,
       87,   87,   89,   87,   87,   87,   90,   87,   87,   91,
       92,   87,   87,   87,   87,   87,   87,   87,   93,   93,

       93,   93,   93,   93,   93,   93,   93,   94,   87,   95,
      128,  196,  124,  170,  200,  124,  170,  129,  129,  129,
      129,  129,  129,  129,  129,  129,  131,  132,  131,  131,
      154,  181,  168,  198,  195,  194,  187,  133,  184,  155,
      147,  192,  193,  181,  191,  125,  189,  168,  166,  188,
      187,  159,  182,  146,  141,  138,  134,  174,  181,  174,
      177,  176,  172,  169,  168,  166,  174,  174,  174,  174,
      174,  174,  174,  174,  174,  164,  162,  175,  131,  132,
      131,  131,  111,  116,  159,  156,  126,  150,  148,  133,
      126,  146,  144,  141,  138,  136,  135,  126,  124,  122,

      116,  111,  206,   97,   97,   69,   69,   60,  134,  183,
      183,  184,  183,  183,  185,  183,  183,  183,  185,  183,
      183,  183,  185,  183,  183,  183,  183,  183,  183,  183,
      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
      183,  185,   32,   32,   32,   32,   32,   32,   32,   32,
       32,   32,   32,   32,   42,   42,   42,   42,   42,   42,
       42,   42,   42,   42,   42,   42,   57,   57,   57,   57,
       57,   57,   57,   57,   57,   57,   57,   57,   59,   59,
       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,

       61,   61,   64,   64,   64,   64,   64,   64,   64,   64,
       64,   64,   64,   64,   65,   65,   65,   65,   65,   65,
       65,   65,   65,   65,   65,   65,   70,   70,   70,   70,
       70,   70,   70,   70,   70,   70,   70,   70,   75,   75,
       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
       79,   79,   83,   83,   83,   83,   83,   83,   83,   83,
       83,   83,   83,   83,   96,   96,   96,   96,   96,   96,
       96,   96,   96,   96,   96,   96,  100,  100,  100,  100,
      100,  100,  100,  100,  100,  100,  100,  100,  106,  106,

       60,   58,  106,  107,  107,   58,  206,  107,  110,  110,
      110,  110,  110,  110,  110,  110,  110,  110,  110,  110,
      112,  112,  112,  112,  112,  112,  112,  112,  112,  112,
      112,  112,  117,  117,  206,  206,  117,  118,  118,  206,
      206,  206,  206,  206,  206,  206,  118,  123,  123,  206,
      123,  123,  123,  123,  123,  206,  123,  123,  123,  125,
      125,  206,  125,  125,  125,  125,  125,  125,  125,  125,
      125,  127,  127,  206,  127,  127,  127,  127,  127,  127,
      127,  127,  127,  130,  130,  130,  130,  130,  130,  130,
      130,  130,  130,  130,  130,  137,  137,  137,  137,  137,

      137,  137,  137,  137,  137,  137,  137,  139,  206,  206,
      139,  139,  139,  139,  139,  139,  139,  139,  139,  140,
      140,  140,  140,  140,  140,  140,  140,  140,  140,  140,
      140,  142,  142,  206,  142,  142,  142,  142,  142,  142,
      142,  142,  142,  145,  145,  206,  206,  145,  147,  147,
      206,  147,  147,  147,  147,  147,  147,  147,  147,  147,
      149,  149,  206,  149,  149,  149,  149,  149,  149,  149,
      149,  149,  151,  151,  206,  151,  151,  151,  151,  151,
      206,  151,  151,  151,  152,  152,  206,  206,  206,  152,
      152,  152,  152,  206,  152,  153,  153,  206,  153,  153,

      153,  153,  153,  153,  153,  153,  153,  157,  157,  206,
      206,  157,  158,  158,  158,  158,  158,  158,  158,  158,
      158,  158,  158,  158,  160,  160,  206,  206,  160,  160,
      160,  206,  160,  160,  160,  160,  161,  161,  206,  161,
      161,  161,  161,  161,  161,  161,  161,  161,  163,  163,
      206,  163,  163,  163,  163,  163,  163,  163,  163,  163,
      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
      165,  165,  167,  167,  167,  167,  167,  167,  167,  167,
      167,  167,  167,  167,  173,  173,  206,  173,  173,  173,
      173,  173,  173,  173,  173,  179,  179,  206,  179,  179,

      179,  179,  179,  179,  179,  179,  179,  180,  180,  180,
      180,  180,  180,  180,  180,  180,  180,  180,  180,  186,
      186,  186,  186,  186,  186,  186,  186,  186,  186,  186,
      186,  185,  185,  185,  185,  185,  185,  185,  185,  185,
      185,  185,  185,  197,  197,  197,  197,  197,  197,  197,
      197,  197,  197,  197,  197,  199,  199,  199,  199,  199,
      199,  199,  199,  199,  199,  199,  199,  201,  201,  201,
      201,  201,  201,  201,  201,  201,  201,  201,  201,   31,
      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,
      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,

      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,
      206,  206,  206
    ) ;

yy_chk : constant array(0..913) of short :=
    (   0,
        0,    1,    1,    1,    1,    9,    9,    9,    9,   10,
       10,   10,   10,   43,   27,   46,   46,   28,   46,   39,
      204,    1,    1,    1,    1,    1,    1,    1,    1,    1,
        2,    2,    2,    2,   15,    2,   16,    2,   39,   36,
       39,    2,   43,   15,   27,   16,   15,   28,   16,   36,
        2,    2,    2,    2,    2,    2,    2,    2,    2,    3,
        3,    3,    3,    3,   15,    3,   16,   17,    3,   18,
       17,    3,   18,    3,  118,    3,    3,   33,   33,   33,
       33,  123,  123,   17,   29,   18,  201,   29,    3,    3,
        4,    4,    4,    4,    4,   19,    4,    4,   20,    4,

       29,    4,    4,  118,    4,   19,    4,    4,   20,    4,
      199,   19,   21,   19,   20,   22,   20,  197,   90,    4,
        4,   11,   21,   30,  195,   22,   30,   90,   21,   21,
       11,   22,   22,  124,   62,   11,   62,   62,  124,   30,
       11,   11,   11,   11,   11,   11,   11,   11,   11,   12,
      104,  104,  104,  104,  107,  134,  194,  143,   12,  143,
      143,  193,  171,   12,  107,  134,  171,  171,   12,   12,
       12,   12,   12,   12,   12,   12,   12,   23,   23,   23,
       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,

       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
       51,  190,  196,  196,  192,  190,  190,   51,   51,   51,
       51,   51,   51,   51,   51,   51,   52,   52,   52,   52,
      153,  177,  178,  191,  189,  188,  186,   52,  185,  153,
      182,  177,  178,  180,  176,  172,  169,  167,  165,  164,
      162,  158,  148,  146,  140,  137,   52,  129,  136,  129,
      133,  130,  126,  122,  120,  116,  129,  129,  129,  129,
      129,  129,  129,  129,  129,  114,  112,  129,  131,  131,
      131,  131,  110,  109,   96,   91,   85,   82,   81,  131,
       78,   73,   67,   59,   57,   55,   54,   50,   49,   48,

       40,   38,   31,   26,   25,   14,   13,    8,  131,  156,
      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
      156,  156,  207,  207,  207,  207,  207,  207,  207,  207,
      207,  207,  207,  207,  208,  208,  208,  208,  208,  208,
      208,  208,  208,  208,  208,  208,  209,  209,  209,  209,
      209,  209,  209,  209,  209,  209,  209,  209,  210,  210,
      210,  210,  210,  210,  210,  210,  210,  210,  210,  210,
      211,  211,  211,  211,  211,  211,  211,  211,  211,  211,

      211,  211,  212,  212,  212,  212,  212,  212,  212,  212,
      212,  212,  212,  212,  213,  213,  213,  213,  213,  213,
      213,  213,  213,  213,  213,  213,  214,  214,  214,  214,
      214,  214,  214,  214,  214,  214,  214,  214,  215,  215,
      215,  215,  215,  215,  215,  215,  215,  215,  215,  215,
      216,  216,  216,  216,  216,  216,  216,  216,  216,  216,
      216,  216,  217,  217,  217,  217,  217,  217,  217,  217,
      217,  217,  217,  217,  218,  218,  218,  218,  218,  218,
      218,  218,  218,  218,  218,  218,  219,  219,  219,  219,
      219,  219,  219,  219,  219,  219,  219,  219,  220,  220,

        7,    6,  220,  221,  221,    5,    0,  221,  222,  222,
      222,  222,  222,  222,  222,  222,  222,  222,  222,  222,
      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
      223,  223,  224,  224,    0,    0,  224,  225,  225,    0,
        0,    0,    0,    0,    0,    0,  225,  226,  226,    0,
      226,  226,  226,  226,  226,    0,  226,  226,  226,  227,
      227,    0,  227,  227,  227,  227,  227,  227,  227,  227,
      227,  228,  228,    0,  228,  228,  228,  228,  228,  228,
      228,  228,  228,  229,  229,  229,  229,  229,  229,  229,
      229,  229,  229,  229,  229,  230,  230,  230,  230,  230,

      230,  230,  230,  230,  230,  230,  230,  231,    0,    0,
      231,  231,  231,  231,  231,  231,  231,  231,  231,  232,
      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
      232,  233,  233,    0,  233,  233,  233,  233,  233,  233,
      233,  233,  233,  234,  234,    0,    0,  234,  235,  235,
        0,  235,  235,  235,  235,  235,  235,  235,  235,  235,
      236,  236,    0,  236,  236,  236,  236,  236,  236,  236,
      236,  236,  237,  237,    0,  237,  237,  237,  237,  237,
        0,  237,  237,  237,  238,  238,    0,    0,    0,  238,
      238,  238,  238,    0,  238,  239,  239,    0,  239,  239,

      239,  239,  239,  239,  239,  239,  239,  240,  240,    0,
        0,  240,  241,  241,  241,  241,  241,  241,  241,  241,
      241,  241,  241,  241,  242,  242,    0,    0,  242,  242,
      242,    0,  242,  242,  242,  242,  243,  243,    0,  243,
      243,  243,  243,  243,  243,  243,  243,  243,  244,  244,
        0,  244,  244,  244,  244,  244,  244,  244,  244,  244,
      245,  245,  245,  245,  245,  245,  245,  245,  245,  245,
      245,  245,  246,  246,  246,  246,  246,  246,  246,  246,
      246,  246,  246,  246,  247,  247,    0,  247,  247,  247,
      247,  247,  247,  247,  247,  248,  248,    0,  248,  248,

      248,  248,  248,  248,  248,  248,  248,  249,  249,  249,
      249,  249,  249,  249,  249,  249,  249,  249,  249,  250,
      250,  250,  250,  250,  250,  250,  250,  250,  250,  250,
      250,  251,  251,  251,  251,  251,  251,  251,  251,  251,
      251,  251,  251,  252,  252,  252,  252,  252,  252,  252,
      252,  252,  252,  252,  252,  253,  253,  253,  253,  253,
      253,  253,  253,  253,  253,  253,  253,  254,  254,  254,
      254,  254,  254,  254,  254,  254,  254,  254,  254,  206,
      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,
      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,

      206,  206,  206,  206,  206,  206,  206,  206,  206,  206,
      206,  206,  206
    ) ;


-- copy whatever the last rule matched to the standard output

procedure ECHO is
begin
    text_io.put( yytext );
end ECHO;

-- enter a start condition.
-- Using procedure requires a () after the ENTER, but makes everything
-- much neater.

procedure ENTER( state : integer ) is
begin
     yy_start := 1 + 2 * state;
end ENTER;

-- action number for EOF rule of a given start state
function YY_STATE_EOF(state : integer) return integer is
begin
     return YY_END_OF_BUFFER + state + 1;
end YY_STATE_EOF;

-- return all but the first 'n' matched characters back to the input stream
procedure yyless(n : integer) is
begin
        yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext
        yy_cp := yy_bp + n;
        yy_c_buf_p := yy_cp;
        YY_DO_BEFORE_ACTION; -- set up yytext again
end yyless;

-- redefine this if you have something you want each time.
procedure YY_USER_ACTION is
begin
        null;
end;

-- yy_get_previous_state - get the state just before the EOB char was reached

function yy_get_previous_state return yy_state_type is
    yy_current_state : yy_state_type;
    yy_c : short;
    yy_bp : integer := yytext_ptr;
begin
    yy_current_state := yy_start;
    if ( yy_ch_buf(yy_bp-1) = ASCII.LF ) then
	yy_current_state := yy_current_state + 1;
    end if;

    for yy_cp in yytext_ptr..yy_c_buf_p - 1 loop
	yy_c := yy_ec(yy_ch_buf(yy_cp));
	if ( yy_accept(yy_current_state) /= 0 ) then
	    yy_last_accepting_state := yy_current_state;
	    yy_last_accepting_cpos := yy_cp;
	end if;
	while ( yy_chk(yy_base(yy_current_state) + yy_c) /= yy_current_state ) loop
	    yy_current_state := yy_def(yy_current_state);
	    if ( yy_current_state >= 207 ) then
		yy_c := yy_meta(yy_c);
	    end if;
	end loop;
	yy_current_state := yy_nxt(yy_base(yy_current_state) + yy_c);
    end loop;

    return yy_current_state;
end yy_get_previous_state;

procedure yyrestart( input_file : file_type ) is
begin
   set_input(input_file);
   yy_init := true;
end yyrestart;

begin -- of YYLex
<<new_file>>
        -- this is where we enter upon encountering an end-of-file and
        -- yywrap() indicating that we should continue processing

    if ( yy_init ) then
        if ( yy_start = 0 ) then
            yy_start := 1;      -- first start state
        end if;

        -- we put in the '\n' and start reading from [1] so that an
        -- initial match-at-newline will be true.

        yy_ch_buf(0) := ASCII.LF;
        yy_n_chars := 1;

        -- we always need two end-of-buffer characters.  The first causes
        -- a transition to the end-of-buffer state.  The second causes
        -- a jam in that state.

        yy_ch_buf(yy_n_chars) := YY_END_OF_BUFFER_CHAR;
        yy_ch_buf(yy_n_chars + 1) := YY_END_OF_BUFFER_CHAR;

        yy_eof_has_been_seen := false;

        yytext_ptr := 1;
        yy_c_buf_p := yytext_ptr;
        yy_hold_char := yy_ch_buf(yy_c_buf_p);
        yy_init := false;
    end if; -- yy_init

    loop                -- loops until end-of-file is reached
        yy_cp := yy_c_buf_p;

        -- support of yytext
        yy_ch_buf(yy_cp) := yy_hold_char;

        -- yy_bp points to the position in yy_ch_buf of the start of the
        -- current run.
	yy_bp := yy_cp;
	yy_current_state := yy_start;
	if ( yy_ch_buf(yy_bp-1) = ASCII.LF ) then
	    yy_current_state := yy_current_state + 1;
	end if;
	loop
		yy_c := yy_ec(yy_ch_buf(yy_cp));
		if ( yy_accept(yy_current_state) /= 0 ) then
		    yy_last_accepting_state := yy_current_state;
		    yy_last_accepting_cpos := yy_cp;
		end if;
		while ( yy_chk(yy_base(yy_current_state) + yy_c) /= yy_current_state ) loop
		    yy_current_state := yy_def(yy_current_state);
		    if ( yy_current_state >= 207 ) then
			yy_c := yy_meta(yy_c);
		    end if;
		end loop;
		yy_current_state := yy_nxt(yy_base(yy_current_state) + yy_c);
	    yy_cp := yy_cp + 1;
if ( yy_current_state = 206 ) then
    exit;
end if;
	end loop;
	yy_cp := yy_last_accepting_cpos;
	yy_current_state := yy_last_accepting_state;

<<next_action>>
	    yy_act := yy_accept(yy_current_state);
            YY_DO_BEFORE_ACTION;
            YY_USER_ACTION;

        if aflex_debug then  -- output acceptance info. for (-d) debug mode
            text_io.put( Standard_Error, "--accepting rule #" );
            text_io.put( Standard_Error, INTEGER'IMAGE(yy_act) );
            text_io.put_line( Standard_Error, "(""" & yytext & """)");
        end if;

<<do_action>>   -- this label is used only to access EOF actions
            case yy_act is
		when 0 => -- must backtrack
		-- undo the effects of YY_DO_BEFORE_ACTION
		yy_ch_buf(yy_cp) := yy_hold_char;
		yy_cp := yy_last_accepting_cpos;
		yy_current_state := yy_last_accepting_state;
		goto next_action;



when 1 => 
--# line 46 "ascan.l"
 indented_code := true; 

when 2 => 
--# line 47 "ascan.l"
 linenum := linenum + 1; ECHO;
				-- treat as a comment;
			

when 3 => 
--# line 50 "ascan.l"
 linenum := linenum + 1; ECHO; 

when 4 => 
--# line 51 "ascan.l"
 return ( SCDECL ); 

when 5 => 
--# line 52 "ascan.l"
 return ( XSCDECL ); 

when 6 => 
--# line 54 "ascan.l"
 return ( WHITESPACE ); 

when 7 => 
--# line 56 "ascan.l"

			sectnum := 2;
			misc.line_directive_out;
			ENTER(SECT2PROLOG);
			return ( SECTEND );
			

when 8 => 
--# line 63 "ascan.l"

			text_io.put( Standard_Error, "old-style lex command at line " );
			int_io.put( Standard_Error, linenum );
			text_io.put( Standard_Error, "ignored:" );
			text_io.new_line( Standard_Error );
			text_io.put( Standard_Error, ASCII.HT );
			text_io.put( Standard_Error, yytext(1..YYLength) );
			linenum := linenum + 1;
			

when 9 => 
--# line 73 "ascan.l"

			nmstr := vstr(yytext(1..YYLength));
			didadef := false;
			ENTER(PICKUPDEF);
			

when 10 => 
--# line 79 "ascan.l"
 nmstr := vstr(yytext(1..YYLength));
			  return NAME;
			

when 11 => 
--# line 82 "ascan.l"
 linenum := linenum + 1;
			  -- allows blank lines in section 1;
			

when 12 => 
--# line 85 "ascan.l"
 linenum := linenum + 1; return Newline; 

when 13 => 
--# line 86 "ascan.l"
 misc.synerr( "illegal character" );ENTER(RECOVER);

when 14 => 
--# line 88 "ascan.l"
 null;
			  -- separates name and definition;
			

when 15 => 
--# line 92 "ascan.l"

			nmdef := vstr(yytext(1..YYLength));

			i := tstring.len( nmdef );
			while ( i >= tstring.first ) loop
			    if ( (CHAR(nmdef,i) /= ' ') and
				 (CHAR(nmdef,i) /= ASCII.HT) ) then
				exit;
			    end if;
			    i := i - 1;
			end loop;

                        sym.ndinstal( nmstr,
				tstring.slice(nmdef, tstring.first, i) );
			didadef := true;
			

when 16 => 
--# line 109 "ascan.l"

			if ( not didadef ) then
			    misc.synerr( "incomplete name definition" );
			end if;
			ENTER(0);
			linenum := linenum + 1;
			

when 17 => 
--# line 117 "ascan.l"
 linenum := linenum + 1;
			  ENTER(0);
			  nmstr := vstr(yytext(1..YYLength));
			  return NAME;
			

when 18 => 
yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext
yy_cp := yy_cp - 1;
yy_c_buf_p := yy_cp;
YY_DO_BEFORE_ACTION; -- set up yytext again
--# line 123 "ascan.l"

			linenum := linenum + 1;
			ACTION_ECHO;
			MARK_END_OF_PROLOG;
			ENTER(SECT2);
			

when 19 => 
--# line 130 "ascan.l"
 linenum := linenum + 1; ACTION_ECHO; 

when YY_END_OF_BUFFER +SECT2PROLOG + 1 
 =>
--# line 132 "ascan.l"
 MARK_END_OF_PROLOG;
			  return End_Of_Input;
			

when 21 => 
--# line 136 "ascan.l"
 linenum := linenum + 1;
			  -- allow blank lines in sect2;

			-- this rule matches indented lines which
			-- are not comments.
when 22 => 
--# line 141 "ascan.l"

			misc.synerr("indented code found outside of action");
			linenum := linenum + 1;
			

when 23 => 
--# line 146 "ascan.l"
 ENTER(SC); return ( '<' ); 

when 24 => 
--# line 147 "ascan.l"
 return ( '^' );  

when 25 => 
--# line 148 "ascan.l"
 ENTER(QUOTE); return ( '"' ); 

when 26 => 
yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext
 yy_cp := yy_bp + 1;
yy_c_buf_p := yy_cp;
YY_DO_BEFORE_ACTION; -- set up yytext again
--# line 149 "ascan.l"
 ENTER(NUM); return ( '{' ); 

when 27 => 
--# line 150 "ascan.l"
 ENTER(BRACEERROR); 

when 28 => 
yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext
 yy_cp := yy_bp + 1;
yy_c_buf_p := yy_cp;
YY_DO_BEFORE_ACTION; -- set up yytext again
--# line 151 "ascan.l"
 return ( '$' ); 

when 29 => 
--# line 153 "ascan.l"
 continued_action := true;
			  linenum := linenum + 1;
			  return Newline;
			

when 30 => 
--# line 158 "ascan.l"
 linenum := linenum + 1; ACTION_ECHO; 

when 31 => 
--# line 160 "ascan.l"

			-- this rule is separate from the one below because
			-- otherwise we get variable trailing context, so
			-- we can't build the scanner using -f,F

			bracelevel := 0;
			continued_action := false;
			ENTER(ACTION);
			return Newline;
			

when 32 => 
yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext
yy_cp := yy_cp - 1;
yy_c_buf_p := yy_cp;
YY_DO_BEFORE_ACTION; -- set up yytext again
--# line 171 "ascan.l"

			bracelevel := 0;
			continued_action := false;
			ENTER(ACTION);
			return Newline;
			

when 33 => 
--# line 178 "ascan.l"
 linenum := linenum + 1; return Newline; 

when 34 => 
--# line 180 "ascan.l"
 return ( EOF_OP ); 

when 35 => 
--# line 182 "ascan.l"

			sectnum := 3;
			ENTER(SECT3);
			return ( End_Of_Input );
			-- to stop the parser
			

when 36 => 
--# line 189 "ascan.l"


			nmstr := vstr(yytext(1..YYLength));

			-- check to see if we've already encountered this ccl
                        cclval := sym.ccllookup( nmstr );
			if ( cclval /= 0 ) then
			    yylval := cclval;
			    cclreuse := cclreuse + 1;
			    return ( PREVCCL );
			else
			    -- we fudge a bit.  We know that this ccl will
			    -- soon be numbered as lastccl + 1 by cclinit
			    sym.cclinstal( nmstr, lastccl + 1 );

			    -- push back everything but the leading bracket
			    -- so the ccl can be rescanned

			    PUT_BACK_STRING(nmstr, 1);

			    ENTER(FIRSTCCL);
			    return ( '[' );
			end if;
			

when 37 => 
--# line 214 "ascan.l"

			nmstr := vstr(yytext(1..YYLength));
			-- chop leading and trailing brace
			tmpbuf := slice(vstr(yytext(1..YYLength)),
								2, YYLength-1);

			nmdefptr := sym.ndlookup( tmpbuf );
			if ( nmdefptr = NUL ) then
			    misc.synerr( "undefined {name}" );
			else
			    -- push back name surrounded by ()'s
			    unput(')');
			    PUT_BACK_STRING(nmdefptr, 0);
			    unput('(');
			end if;
			

when 38 => 
--# line 231 "ascan.l"
 tmpbuf := vstr(yytext(1..YYLength));
			  case tstring.CHAR(tmpbuf,1) is
				when '/' => return '/';
				when '|' => return '|';
				when '*' => return '*';
				when '+' => return '+';
				when '?' => return '?';
				when '.' => return '.';
				when '(' => return '(';
				when ')' => return ')';
				when others =>
					misc.aflexerror("error in aflex case");
			  end case;
			

when 39 => 
--# line 245 "ascan.l"
 tmpbuf := vstr(yytext(1..YYLength));
			  yylval := CHARACTER'POS(CHAR(tmpbuf,1));
			  return CHAR;
			

when 40 => 
--# line 249 "ascan.l"
 linenum := linenum + 1; return Newline; 

when 41 => 
--# line 252 "ascan.l"
 return ( ',' ); 

when 42 => 
--# line 253 "ascan.l"
 ENTER(SECT2); return ( '>' ); 

when 43 => 
yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext
 yy_cp := yy_bp + 1;
yy_c_buf_p := yy_cp;
YY_DO_BEFORE_ACTION; -- set up yytext again
--# line 254 "ascan.l"
 ENTER(CARETISBOL); return ( '>' ); 

when 44 => 
--# line 255 "ascan.l"
 nmstr := vstr(yytext(1..YYLength));
			  return NAME;
			

when 45 => 
--# line 258 "ascan.l"
 misc.synerr( "bad start condition name" ); 

when 46 => 
--# line 260 "ascan.l"
 ENTER(SECT2); return ( '^' ); 

when 47 => 
--# line 263 "ascan.l"
 tmpbuf := vstr(yytext(1..YYLength));
			  yylval := CHARACTER'POS(CHAR(tmpbuf,1));
			  return CHAR;
			

when 48 => 
--# line 267 "ascan.l"
 ENTER(SECT2); return ( '"' ); 

when 49 => 
--# line 269 "ascan.l"

			misc.synerr( "missing quote" );
			ENTER(SECT2);
			linenum := linenum + 1;
			return ( '"' );
			

when 50 => 
yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext
 yy_cp := yy_bp + 1;
yy_c_buf_p := yy_cp;
YY_DO_BEFORE_ACTION; -- set up yytext again
--# line 277 "ascan.l"
 ENTER(CCL); return ( '^' ); 

when 51 => 
yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext
 yy_cp := yy_bp + 1;
yy_c_buf_p := yy_cp;
YY_DO_BEFORE_ACTION; -- set up yytext again
--# line 278 "ascan.l"
 return ( '^' ); 

when 52 => 
--# line 279 "ascan.l"
 ENTER(CCL); yylval := CHARACTER'POS('-'); return ( CHAR ); 

when 53 => 
--# line 280 "ascan.l"
 ENTER(CCL);
			  tmpbuf := vstr(yytext(1..YYLength));
			  yylval := CHARACTER'POS(CHAR(tmpbuf,1));
			  return CHAR;
			

when 54 => 
yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext
 yy_cp := yy_bp + 1;
yy_c_buf_p := yy_cp;
YY_DO_BEFORE_ACTION; -- set up yytext again
--# line 286 "ascan.l"
 return ( '-' ); 

when 55 => 
--# line 287 "ascan.l"
 tmpbuf := vstr(yytext(1..YYLength));
			  yylval := CHARACTER'POS(CHAR(tmpbuf,1));
			  return CHAR;
			

when 56 => 
--# line 291 "ascan.l"
 ENTER(SECT2); return ( ']' ); 

when 57 => 
--# line 294 "ascan.l"

			yylval := misc.myctoi( vstr(yytext(1..YYLength)) );
			return ( NUMBER );
			

when 58 => 
--# line 299 "ascan.l"
 return ( ',' ); 

when 59 => 
--# line 300 "ascan.l"
 ENTER(SECT2); return ( '}' ); 

when 60 => 
--# line 302 "ascan.l"

			misc.synerr( "bad character inside {}'s" );
			ENTER(SECT2);
			return ( '}' );
			

when 61 => 
--# line 308 "ascan.l"

			misc.synerr( "missing }" );
			ENTER(SECT2);
			linenum := linenum + 1;
			return ( '}' );
			

when 62 => 
--# line 316 "ascan.l"
 misc.synerr( "bad name in {}'s" ); ENTER(SECT2); 

when 63 => 
--# line 317 "ascan.l"
 misc.synerr( "missing }" );
			  linenum := linenum + 1;
			  ENTER(SECT2);
			

when 64 => 
--# line 322 "ascan.l"
 bracelevel := bracelevel + 1; 

when 65 => 
--# line 323 "ascan.l"
 bracelevel := bracelevel - 1; 

when 66 => 
--# line 324 "ascan.l"
 ACTION_ECHO; 

when 67 => 
--# line 325 "ascan.l"
 ACTION_ECHO; 

when 68 => 
--# line 326 "ascan.l"
 linenum := linenum + 1; ACTION_ECHO; 

when 69 => 
--# line 327 "ascan.l"
 ACTION_ECHO;
				  -- character constant;
			

when 70 => 
--# line 331 "ascan.l"
 ACTION_ECHO; ENTER(ACTION_STRING); 

when 71 => 
--# line 333 "ascan.l"

			linenum := linenum + 1;
			ACTION_ECHO;
			if ( bracelevel = 0 ) then
			    text_io.new_line ( temp_action_file );
			    ENTER(SECT2);
	                end if;
			

when 72 => 
--# line 341 "ascan.l"
 ACTION_ECHO; 

when 73 => 
--# line 343 "ascan.l"
 ACTION_ECHO; 

when 74 => 
--# line 344 "ascan.l"
 ACTION_ECHO; 

when 75 => 
--# line 345 "ascan.l"
 linenum := linenum + 1; ACTION_ECHO; 

when 76 => 
--# line 346 "ascan.l"
 ACTION_ECHO; ENTER(ACTION); 

when 77 => 
--# line 347 "ascan.l"
 ACTION_ECHO; 

when 78 => 
--# line 350 "ascan.l"

			yylval := CHARACTER'POS(misc.myesc( vstr(yytext(1..YYLength)) ));
			return ( CHAR );
			

when 79 => 
--# line 355 "ascan.l"

			yylval := CHARACTER'POS(misc.myesc( vstr(yytext(1..YYLength)) ));
			ENTER(CCL);
			return ( CHAR );
			

when 80 => 
--# line 362 "ascan.l"
 if ( check_yylex_here ) then
				return End_Of_Input;
			  else
				ECHO;
			  end if;
			

when 81 => 
--# line 368 "ascan.l"
raise AFLEX_SCANNER_JAMMED;
when YY_END_OF_BUFFER + INITIAL + 1 |
YY_END_OF_BUFFER + SECT2 + 1 |
YY_END_OF_BUFFER + SECT3 + 1 |
YY_END_OF_BUFFER + PICKUPDEF + 1 |
YY_END_OF_BUFFER + SC + 1 |
YY_END_OF_BUFFER + CARETISBOL + 1 |
YY_END_OF_BUFFER + NUM + 1 |
YY_END_OF_BUFFER + QUOTE + 1 |
YY_END_OF_BUFFER + FIRSTCCL + 1 |
YY_END_OF_BUFFER + CCL + 1 |
YY_END_OF_BUFFER + ACTION + 1 |
YY_END_OF_BUFFER + RECOVER + 1 |
YY_END_OF_BUFFER + BRACEERROR + 1 |
YY_END_OF_BUFFER + ACTION_STRING + 1 => 
    return End_Of_Input;
                when YY_END_OF_BUFFER =>
                    -- undo the effects of YY_DO_BEFORE_ACTION
                    yy_ch_buf(yy_cp) := yy_hold_char;

                    yytext_ptr := yy_bp;

                    case yy_get_next_buffer is
                        when EOB_ACT_END_OF_FILE =>
                            begin
                            if ( yywrap ) then
                                -- note: because we've taken care in
                                -- yy_get_next_buffer() to have set up yytext,
                                -- we can now set up yy_c_buf_p so that if some
                                -- total hoser (like aflex itself) wants
                                -- to call the scanner after we return the
                                -- End_Of_Input, it'll still work - another
                                -- End_Of_Input will get returned.

                                yy_c_buf_p := yytext_ptr;

                                yy_act := YY_STATE_EOF((yy_start - 1) / 2);

                                goto do_action;
                            else
                                --  start processing a new file
                                yy_init := true;
                                goto new_file;
                            end if;
                            end;
                        when EOB_ACT_RESTART_SCAN =>
                            yy_c_buf_p := yytext_ptr;
                            yy_hold_char := yy_ch_buf(yy_c_buf_p);
                        when EOB_ACT_LAST_MATCH =>
                            yy_c_buf_p := yy_n_chars;
                            yy_current_state := yy_get_previous_state;

                            yy_cp := yy_c_buf_p;
                            yy_bp := yytext_ptr;
                            goto next_action;
                        when others => null;
                        end case; -- case yy_get_next_buffer()
                when others =>
                    text_io.put( "action # " );
                    text_io.put( INTEGER'IMAGE(yy_act) );
                    text_io.new_line;
                    raise AFLEX_INTERNAL_ERROR;
            end case; -- case (yy_act)
        end loop; -- end of loop waiting for end of file
end YYLex;
--# line 368 "ascan.l"
begin
    if (call_yylex) then
    	toktype := YYLex;
    	call_yylex := false;
    	return toktype;
    end if;

    if ( eofseen ) then
	toktype := End_Of_Input;
    else
	toktype := YYLex;
    end if;
-- this tracing code allows easy tracing of aflex runs
if (trace) then
text_io.new_line(Standard_Error);
text_io.put(Standard_Error, "toktype = :" );
text_io.put(Standard_Error, Token'image(toktype));
text_io.put_line(Standard_Error, ":" );
end if;

    if ( toktype = End_Of_Input ) then
	eofseen := true;

	if ( sectnum = 1 ) then
	    misc.synerr(  "unexpected EOF" );
	    sectnum := 2;
	    toktype := SECTEND;
	else
	    if ( sectnum = 2 ) then
	    	sectnum := 3;
	    	toktype := SECTEND;
	    end if;
    	end if;
    end if;
    
    if ( trace ) then
	if ( beglin ) then
	    int_io.put( Standard_Error, num_rules + 1 );
	    text_io.put( Standard_Error, ASCII.HT );
	    beglin := false;
    	end if;

	case toktype is
	    when '<' | '>'|'^'|'$'|'"'|'['|']'|'{'|'}'|'|'|'('|
    	    	 ')'|'-'|'/'|'?'|'.'|'*'|'+'|',' =>
		text_io.put( Standard_Error, Token'image(toktype) );

	    when NEWLINE =>
		text_io.new_line(Standard_Error);
		if ( sectnum = 2 ) then
		    beglin := true;
    	    	end if;

	    when SCDECL =>
		text_io.put( Standard_Error, "%s" );

	    when XSCDECL =>
   		text_io.put( Standard_Error, "%x" );

	    when WHITESPACE =>
       		text_io.put( Standard_Error, " " );

	    when SECTEND =>
       		text_io.put_line( Standard_Error, "%%" );	   

		-- we set beglin to be true so we'll start
		-- writing out numbers as we echo rules.  aflexscan() has
		-- already assigned sectnum

		if ( sectnum = 2 ) then
		    beglin := true;
    	    	end if;

	    when NAME =>
		text_io.put( Standard_Error, ''' );
		text_io.put( Standard_Error, YYText);
		text_io.put( Standard_Error, ''' );

	    when CHAR =>
	    	if ( (yylval < CHARACTER'POS(' ')) or
		     (yylval = CHARACTER'POS(ASCII.DEL)) ) then
		    text_io.put( Standard_Error, '\' );
		    int_io.put( Standard_Error, yylval );
    		    text_io.put( Standard_Error, '\' );
		else
		    text_io.put( Standard_Error, Token'image(toktype) );
    	    	end if;

	    when NUMBER =>
    	    	int_io.put( Standard_Error, yylval );

	    when PREVCCL =>
		text_io.put( Standard_Error, '[' );
   	    	int_io.put( Standard_Error, yylval );
		text_io.put( Standard_Error, ']' );		

    	    when End_Of_Input =>
    	    	text_io.put( Standard_Error, "End Marker" );

	    when others =>
	    	text_io.put( Standard_Error, "Something weird:" );
		text_io.put_line( Standard_Error, Token'image(toktype));
    	end case;
    end if;
	    
    return toktype;

end get_token;
end scanner;
package ascan_dfa is
aflex_debug : boolean := false;
yytext_ptr : integer; -- points to start of yytext in buffer

-- yy_ch_buf has to be 2 characters longer than YY_BUF_SIZE because we need
-- to put in 2 end-of-buffer characters (this is explained where it is
-- done) at the end of yy_ch_buf
YY_READ_BUF_SIZE : constant integer :=  8192;
YY_BUF_SIZE : constant integer := YY_READ_BUF_SIZE * 2; -- size of input buffer
type unbounded_character_array is array(integer range <>) of character;
subtype ch_buf_type is unbounded_character_array(0..YY_BUF_SIZE + 1);
yy_ch_buf : ch_buf_type;
yy_cp, yy_bp : integer;

-- yy_hold_char holds the character lost when yytext is formed
yy_hold_char : character;
yy_c_buf_p : integer;   -- points to current character in buffer

function YYText return string;
function YYLength return integer;
procedure YY_DO_BEFORE_ACTION;
--These variables are needed between calls to YYLex.
yy_init : boolean := true; -- do we need to initialize YYLex?
yy_start : integer := 0; -- current start state number
subtype yy_state_type is integer;
yy_last_accepting_state : yy_state_type;
yy_last_accepting_cpos : integer;
end ascan_dfa;

with ascan_dfa; use ascan_dfa; 
package body ascan_dfa is
function YYText return string is
    i : integer;
    str_loc : integer := 1;
    buffer : string(1..1024);
    EMPTY_STRING : constant string := "";
begin
    -- find end of buffer
    i := yytext_ptr;
    while ( yy_ch_buf(i) /= ASCII.NUL ) loop
    buffer(str_loc ) := yy_ch_buf(i);
        i := i + 1;
    str_loc := str_loc + 1;
    end loop;
--    return yy_ch_buf(yytext_ptr.. i - 1);

    if (str_loc < 2) then
        return EMPTY_STRING;
    else
      return buffer(1..str_loc-1);
    end if;

end;

-- returns the length of the matched text
function YYLength return integer is
begin
    return yy_cp - yy_bp;
end YYLength;

-- done after the current pattern has been matched and before the
-- corresponding action - sets up yytext

procedure YY_DO_BEFORE_ACTION is
begin
    yytext_ptr := yy_bp;
    yy_hold_char := yy_ch_buf(yy_cp);
    yy_ch_buf(yy_cp) := ASCII.NUL;
    yy_c_buf_p := yy_cp;
end YY_DO_BEFORE_ACTION;

end ascan_dfa;
with ascan_dfa; use ascan_dfa; 
with text_io; use text_io;

package ascan_io is
NULL_IN_INPUT : exception;
AFLEX_INTERNAL_ERROR : exception;
UNEXPECTED_LAST_MATCH : exception;
PUSHBACK_OVERFLOW : exception;
AFLEX_SCANNER_JAMMED : exception;
type eob_action_type is ( EOB_ACT_RESTART_SCAN,
                          EOB_ACT_END_OF_FILE,
                          EOB_ACT_LAST_MATCH );
YY_END_OF_BUFFER_CHAR :  constant character:=  ASCII.NUL;
yy_n_chars : integer;       -- number of characters read into yy_ch_buf

-- true when we've seen an EOF for the current input file
yy_eof_has_been_seen : boolean;

procedure YY_INPUT(buf: out unbounded_character_array; result: out integer; max_size: in integer);
function yy_get_next_buffer return eob_action_type;
procedure yyunput( c : character; yy_bp: in out integer );
procedure unput(c : character);
function input return character;
procedure output(c : character);
function yywrap return boolean;
procedure Open_Input(fname : in String);
procedure Close_Input;
procedure Create_Output(fname : in String := "");
procedure Close_Output;
end ascan_io;

package body ascan_io is
-- gets input and stuffs it into 'buf'.  number of characters read, or YY_NULL,
-- is returned in 'result'.

procedure YY_INPUT(buf: out unbounded_character_array; result: out integer; max_size: in integer) is
    c : character;
    i : integer := 1;
    loc : integer := buf'first;
begin
    while ( i <= max_size ) loop
    if (end_of_line) then -- Ada ate our newline, put it back on the end.
            buf(loc) := ASCII.LF;
            skip_line(1);
        else
            get(buf(loc));
    end if; 
    
        loc := loc + 1;
    i := i + 1;
    end loop;
    
    result := i - 1; 
    exception
        when END_ERROR => result := i - 1;
    -- when we hit EOF we need to set yy_eof_has_been_seen
    yy_eof_has_been_seen := true;
end YY_INPUT;

-- yy_get_next_buffer - try to read in new buffer
--
-- returns a code representing an action
--     EOB_ACT_LAST_MATCH - 
--     EOB_ACT_RESTART_SCAN - restart the scanner
--     EOB_ACT_END_OF_FILE - end of file

function yy_get_next_buffer return eob_action_type is
    dest : integer := 0;
    source : integer := yytext_ptr - 1; -- copy prev. char, too
    number_to_move : integer;
    ret_val : eob_action_type;
    num_to_read : integer;
begin    
    if ( yy_c_buf_p > yy_n_chars + 1 ) then
        raise NULL_IN_INPUT;
    end if;

    -- try to read more data

    -- first move last chars to start of buffer
    number_to_move := yy_c_buf_p - yytext_ptr;

    for i in 0..number_to_move - 1 loop
        yy_ch_buf(dest) := yy_ch_buf(source);
    dest := dest + 1;
    source := source + 1;
    end loop;
        
    if ( yy_eof_has_been_seen ) then
    -- don't do the read, it's not guaranteed to return an EOF,
    -- just force an EOF

    yy_n_chars := 0;
    else
    num_to_read := YY_BUF_SIZE - number_to_move - 1;

    if ( num_to_read > YY_READ_BUF_SIZE ) then
        num_to_read := YY_READ_BUF_SIZE;
        end if;

    -- read in more data
    YY_INPUT( yy_ch_buf(number_to_move..yy_ch_buf'last), yy_n_chars, num_to_read );
    end if;
    if ( yy_n_chars = 0 ) then
    if ( number_to_move = 1 ) then
        ret_val := EOB_ACT_END_OF_FILE;
    else
        ret_val := EOB_ACT_LAST_MATCH;
        end if;

    yy_eof_has_been_seen := true;
    else
    ret_val := EOB_ACT_RESTART_SCAN;
    end if;
    
    yy_n_chars := yy_n_chars + number_to_move;
    yy_ch_buf(yy_n_chars) := YY_END_OF_BUFFER_CHAR;
    yy_ch_buf(yy_n_chars + 1) := YY_END_OF_BUFFER_CHAR;

    -- yytext begins at the second character in
    -- yy_ch_buf; the first character is the one which
    -- preceded it before reading in the latest buffer;
    -- it needs to be kept around in case it's a
    -- newline, so yy_get_previous_state() will have
    -- with '^' rules active

    yytext_ptr := 1;

    return ret_val;
end yy_get_next_buffer;

procedure yyunput( c : character; yy_bp: in out integer ) is
    number_to_move : integer;
    dest : integer;
    source : integer;
    tmp_yy_cp : integer;
begin
    tmp_yy_cp := yy_c_buf_p;
    yy_ch_buf(tmp_yy_cp) := yy_hold_char; -- undo effects of setting up yytext

    if ( tmp_yy_cp < 2 ) then
    -- need to shift things up to make room
    number_to_move := yy_n_chars + 2; -- +2 for EOB chars
    dest := YY_BUF_SIZE + 2;
    source := number_to_move;

    while ( source > 0 ) loop
        dest := dest - 1;
        source := source - 1;
            yy_ch_buf(dest) := yy_ch_buf(source);
    end loop;

    tmp_yy_cp := tmp_yy_cp + dest - source;
    yy_bp := yy_bp + dest - source;
    yy_n_chars := YY_BUF_SIZE;

    if ( tmp_yy_cp < 2 ) then
        raise PUSHBACK_OVERFLOW;
    end if;
    end if;

    if ( tmp_yy_cp > yy_bp and then yy_ch_buf(tmp_yy_cp-1) = ASCII.LF ) then
    yy_ch_buf(tmp_yy_cp-2) := ASCII.LF;
    end if;

    tmp_yy_cp := tmp_yy_cp - 1;
    yy_ch_buf(tmp_yy_cp) := c;

--  Note:  this code is the text of YY_DO_BEFORE_ACTION, only
--         here we get different yy_cp and yy_bp's
    yytext_ptr := yy_bp;
    yy_hold_char := yy_ch_buf(tmp_yy_cp);
    yy_ch_buf(tmp_yy_cp) := ASCII.NUL;
    yy_c_buf_p := tmp_yy_cp;
end yyunput;

procedure unput(c : character) is
begin
     yyunput( c, yy_bp );
end unput;

function input return character is
    c : character;
    yy_cp : integer := yy_c_buf_p;
begin
    yy_ch_buf(yy_cp) := yy_hold_char;

    if ( yy_ch_buf(yy_c_buf_p) = YY_END_OF_BUFFER_CHAR ) then
    -- need more input
    yytext_ptr := yy_c_buf_p;
    yy_c_buf_p := yy_c_buf_p + 1;

    case yy_get_next_buffer is
        -- this code, unfortunately, is somewhat redundant with
        -- that above

        when EOB_ACT_END_OF_FILE =>
        if ( yywrap ) then
            yy_c_buf_p := yytext_ptr;
            return ASCII.NUL;
        end if;

        yy_ch_buf(0) := ASCII.LF;
        yy_n_chars := 1;
        yy_ch_buf(yy_n_chars) := YY_END_OF_BUFFER_CHAR;
        yy_ch_buf(yy_n_chars + 1) := YY_END_OF_BUFFER_CHAR;
        yy_eof_has_been_seen := false;
        yy_c_buf_p := 1;
        yytext_ptr := yy_c_buf_p;
        yy_hold_char := yy_ch_buf(yy_c_buf_p);

        return ( input );
        when EOB_ACT_RESTART_SCAN =>
        yy_c_buf_p := yytext_ptr;

        when EOB_ACT_LAST_MATCH =>
        raise UNEXPECTED_LAST_MATCH;
        when others => null;
        end case;
    end if;

    c := yy_ch_buf(yy_c_buf_p);
    yy_c_buf_p := yy_c_buf_p + 1;
    yy_hold_char := yy_ch_buf(yy_c_buf_p);

    return c;
end input;

procedure output(c : character) is
begin
    text_io.put(c);
end output;

-- default yywrap function - always treat EOF as an EOF
function yywrap return boolean is
begin
    return true;
end yywrap;

procedure Open_Input(fname : in String) is
    f : file_type;
begin
    yy_init := true;
    open(f, in_file, fname);
    set_input(f);
end Open_Input;

procedure Create_Output(fname : in String := "") is
    f : file_type;
begin
    if (fname /= "") then
        create(f, out_file, fname);
        set_output(f);
    end if;
end Create_Output;

procedure Close_Input is
begin
    null;
end Close_Input;

procedure Close_Output is
begin
    null;
end Close_Output;

end ascan_io;
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE character classes routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION routines for character classes like [abc]
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/cclB.a,v 1.5 90/01/12 15:19:40 self Exp Locker: self $ 

with MISC_DEFS, TEXT_IO, MISC, TSTRING; use MISC_DEFS, TEXT_IO; 
package body CCL is 

-- ccladd - add a single character to a ccl
  procedure CCLADD(CCLP : in INTEGER; 
                   CH   : in CHARACTER) is 
    IND, LEN, NEWPOS : INTEGER; 
  begin
    LEN := CCLLEN(CCLP); 
    IND := CCLMAP(CCLP); 

    -- check to see if the character is already in the ccl
    for I in 0 .. LEN - 1 loop
      if (CCLTBL(IND + I) = CH) then 
        return; 
      end if; 
    end loop; 

    NEWPOS := IND + LEN; 

    if (NEWPOS >= CURRENT_MAX_CCL_TBL_SIZE) then 
      CURRENT_MAX_CCL_TBL_SIZE := CURRENT_MAX_CCL_TBL_SIZE + 
        MAX_CCL_TBL_SIZE_INCREMENT; 

      NUM_REALLOCS := NUM_REALLOCS + 1; 

      REALLOCATE_CHARACTER_ARRAY(CCLTBL, CURRENT_MAX_CCL_TBL_SIZE); 
    end if; 

    CCLLEN(CCLP) := LEN + 1; 
    CCLTBL(NEWPOS) := CH; 

  end CCLADD; 

  -- cclinit - make an empty ccl

  function CCLINIT return INTEGER is 
  begin
    LASTCCL := LASTCCL + 1; 
    if (LASTCCL >= CURRENT_MAXCCLS) then 
      CURRENT_MAXCCLS := CURRENT_MAXCCLS + MAX_CCLS_INCREMENT; 

      NUM_REALLOCS := NUM_REALLOCS + 1; 

      REALLOCATE_INTEGER_ARRAY(CCLMAP, CURRENT_MAXCCLS); 
      REALLOCATE_INTEGER_ARRAY(CCLLEN, CURRENT_MAXCCLS); 
      REALLOCATE_INTEGER_ARRAY(CCLNG, CURRENT_MAXCCLS); 
    end if; 

    if (LASTCCL = 1) then 

      -- we're making the first ccl
      CCLMAP(LASTCCL) := 0; 

    else 

      -- the new pointer is just past the end of the last ccl.  Since
      -- the cclmap points to the \first/ character of a ccl, adding the
      -- length of the ccl to the cclmap pointer will produce a cursor
      -- to the first free space
      CCLMAP(LASTCCL) := CCLMAP(LASTCCL - 1) + CCLLEN(LASTCCL - 1); 
    end if; 

    CCLLEN(LASTCCL) := 0; 
    CCLNG(LASTCCL) := 0; 

    -- ccl's start out life un-negated
    return LASTCCL; 
  end CCLINIT; 

  -- cclnegate - negate a ccl

  procedure CCLNEGATE(CCLP : in INTEGER) is 
  begin
    CCLNG(CCLP) := 1; 
  end CCLNEGATE; 

  -- list_character_set - list the members of a set of characters in CCL form
  --
  -- writes to the given file a character-class representation of those
  -- characters present in the given set.  A character is present if it
  -- has a non-zero value in the set array.

  procedure LIST_CHARACTER_SET(F    : in FILE_TYPE; 
                               CSET : in C_SIZE_BOOL_ARRAY) is 
    I, START_CHAR : INTEGER; 
  begin
    TEXT_IO.PUT(F, '['); 

    I := 1; 
    while (I <= CSIZE) loop
      if (CSET(I)) then 
        START_CHAR := I; 

        TEXT_IO.PUT(F, ' '); 

        TSTRING.PUT(F, MISC.READABLE_FORM(CHARACTER'VAL(I))); 

        I := I + 1; 
        while ((I <= CSIZE) and then (CSET(I))) loop
          I := I + 1; 
        end loop; 

        if (I - 1 > START_CHAR) then 

          -- this was a run
          TEXT_IO.PUT(F, "-"); 
          TSTRING.PUT(MISC.READABLE_FORM(CHARACTER'VAL(I - 1))); 
        end if; 

        TEXT_IO.PUT(F, ' '); 
      end if; 
      I := I + 1; 
    end loop; 

    TEXT_IO.PUT(F, ']'); 
  end LIST_CHARACTER_SET; 
end CCL; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE character classes routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION routines for character classes like [abc]
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/cclS.a,v 1.3 90/01/12 15:19:43 self Exp Locker: self $ 

with MISC_DEFS, TEXT_IO; use MISC_DEFS, TEXT_IO; 
package CCL is 
  procedure CCLADD(CCLP : in INTEGER; 
                   CH   : in CHARACTER); 
  function CCLINIT return INTEGER; 
  procedure CCLNEGATE(CCLP : in INTEGER); 
  procedure LIST_CHARACTER_SET(F    : in FILE_TYPE; 
                               CSET : in C_SIZE_BOOL_ARRAY); 
end CCL; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE command line interface
-- AUTHOR: John Self (UCI)
-- DESCRIPTION command line interface body for use with the VERDIX VADS system.
-- NOTES this file is system dependent
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/command_lineB.a,v 1.3 90/01/12 15:19:44 self Exp Locker: self $ 

with TSTRING; use TSTRING; 
with A_STRINGS; use A_STRINGS; 
with COMMAND_LINE; 
package body COMMAND_LINE_INTERFACE is 
  procedure INITIALIZE_COMMAND_LINE is 
  begin
    for I in 0 .. COMMAND_LINE.ARGC - 1 loop
      ARGV(I) := VSTR(COMMAND_LINE.ARGV(I).S); 
    end loop; 
    ARGC := COMMAND_LINE.ARGC; 
  end INITIALIZE_COMMAND_LINE; 
end COMMAND_LINE_INTERFACE; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE command line interface
-- AUTHOR: John Self (UCI)
-- DESCRIPTION command line interface body for use with the VERDIX VADS system.
-- NOTES this file is system dependent
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/command_lineS.a,v 1.3 90/01/12 15:19:46 self Exp Locker: self $ 

with TSTRING; use TSTRING; 
package COMMAND_LINE_INTERFACE is 
  MAX_NUMBER_ARGS : INTEGER := 32; 
  type COMMAND_VECTOR is array(0 .. MAX_NUMBER_ARGS) of VSTRING; 
  procedure INITIALIZE_COMMAND_LINE; 
  ARGV : COMMAND_VECTOR; 
  ARGC : INTEGER; 
end COMMAND_LINE_INTERFACE; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE DFA construction routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION converts non-deterministic finite automatons to finite ones.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/dfaB.a,v 1.18 90/01/12 15:19:48 self Exp Locker: self $ 

with DFA, INT_IO, MISC_DEFS, TEXT_IO, MISC, TBLCMP, CCL, EXTERNAL_FILE_MANAGER; 
with ECS, NFA, TSTRING, GEN, SKELETON_MANAGER; use MISC_DEFS, 
  EXTERNAL_FILE_MANAGER; 

package body DFA is 
  use TSTRING; 
  -- check_for_backtracking - check a DFA state for backtracking
  --
  -- ds is the number of the state to check and state[) is its out-transitions,
  -- indexed by equivalence class, and state_rules[) is the set of rules
  -- associated with this state

  DID_STK_INIT : BOOLEAN := FALSE; 
  STK          : INT_PTR; 

  procedure CHECK_FOR_BACKTRACKING(DS    : in INTEGER; 
                                   STATE : in UNBOUNDED_INT_ARRAY) is 
    use MISC_DEFS; 
  begin
    if (DFAACC(DS).DFAACC_STATE = 0) then 

      -- state is non-accepting
      NUM_BACKTRACKING := NUM_BACKTRACKING + 1; 

      if (BACKTRACK_REPORT) then 
        TEXT_IO.PUT(BACKTRACK_FILE, "State #"); 
        INT_IO.PUT(BACKTRACK_FILE, DS, 1); 
        TEXT_IO.PUT(BACKTRACK_FILE, "is non-accepting -"); 
        TEXT_IO.NEW_LINE(BACKTRACK_FILE); 

        -- identify the state
        DUMP_ASSOCIATED_RULES(BACKTRACK_FILE, DS); 

        -- now identify it further using the out- and jam-transitions
        DUMP_TRANSITIONS(BACKTRACK_FILE, STATE); 
        TEXT_IO.NEW_LINE(BACKTRACK_FILE); 
      end if; 
    end if; 
  end CHECK_FOR_BACKTRACKING; 


  -- check_trailing_context - check to see if NFA state set constitutes
  --                          "dangerous" trailing context
  --
  -- NOTES
  --    Trailing context is "dangerous" if both the head and the trailing
  --  part are of variable size \and/ there's a DFA state which contains
  --  both an accepting state for the head part of the rule and NFA states
  --  which occur after the beginning of the trailing context.
  --  When such a rule is matched, it's impossible to tell if having been
  --  in the DFA state indicates the beginning of the trailing context
  --  or further-along scanning of the pattern.  In these cases, a warning
  --  message is issued.
  --
  --    nfa_states[1 .. num_states) is the list of NFA states in the DFA.
  --    accset[1 .. nacc) is the list of accepting numbers for the DFA state.

  procedure CHECK_TRAILING_CONTEXT(NFA_STATES : in INT_PTR; 
                                   NUM_STATES : in INTEGER; 
                                   ACCSET     : in INT_PTR; 
                                   NACC       : in INTEGER) is 
    NS, AR              : INTEGER; 
    STATE_VAR, TYPE_VAR : STATE_ENUM; 

    use MISC_DEFS, MISC, TEXT_IO; 
  begin
    for I in 1 .. NUM_STATES loop
      NS := NFA_STATES(I); 
      TYPE_VAR := STATE_TYPE(NS); 
      AR := ASSOC_RULE(NS); 

      if ((TYPE_VAR = STATE_NORMAL) or (RULE_TYPE(AR) /= RULE_VARIABLE)) then 
        null; 

      -- do nothing
      else 
        if (TYPE_VAR = STATE_TRAILING_CONTEXT) then 

          -- potential trouble.  Scan set of accepting numbers for
          -- the one marking the end of the "head".  We assume that
          -- this looping will be fairly cheap since it's rare that
          -- an accepting number set is large.
          for J in 1 .. NACC loop
            if (CHECK_YY_TRAILING_HEAD_MASK(ACCSET(J)) /= 0) then 
              TEXT_IO.PUT(STANDARD_ERROR, 
                "aflex: Dangerous trailing context in rule at line "); 
              INT_IO.PUT(STANDARD_ERROR, RULE_LINENUM(AR), 1); 
              TEXT_IO.NEW_LINE(STANDARD_ERROR); 
              return; 
            end if; 
          end loop; 
        end if; 
      end if; 
    end loop; 
  end CHECK_TRAILING_CONTEXT; 


  -- dump_associated_rules - list the rules associated with a DFA state
  --
  -- goes through the set of NFA states associated with the DFA and
  -- extracts the first MAX_ASSOC_RULES unique rules, sorts them,
  -- and writes a report to the given file

  procedure DUMP_ASSOCIATED_RULES(F  : in FILE_TYPE; 
                                  DS : in INTEGER) is 
    J                    : INTEGER; 
    NUM_ASSOCIATED_RULES : INTEGER := 0; 
    RULE_SET             : INT_PTR; 
    SIZE, RULE_NUM       : INTEGER; 
  begin
    RULE_SET := new UNBOUNDED_INT_ARRAY(0 .. MAX_ASSOC_RULES + 1); 
    SIZE := DFASIZ(DS); 

    for I in 1 .. SIZE loop
      RULE_NUM := RULE_LINENUM(ASSOC_RULE(DSS(DS)(I))); 

      J := 1; 
      while (J <= NUM_ASSOCIATED_RULES) loop
        if (RULE_NUM = RULE_SET(J)) then 
          exit; 
        end if; 
        J := J + 1; 
      end loop; 
      if (J > NUM_ASSOCIATED_RULES) then 

        --new rule
        if (NUM_ASSOCIATED_RULES < MAX_ASSOC_RULES) then 
          NUM_ASSOCIATED_RULES := NUM_ASSOCIATED_RULES + 1; 
          RULE_SET(NUM_ASSOCIATED_RULES) := RULE_NUM; 
        end if; 
      end if; 
    end loop; 

    MISC.BUBBLE(RULE_SET, NUM_ASSOCIATED_RULES); 

    TEXT_IO.PUT(F, " associated rules:"); 

    for I in 1 .. NUM_ASSOCIATED_RULES loop
      if (I mod 8 = 1) then 
        TEXT_IO.NEW_LINE(F); 
      end if; 

      TEXT_IO.PUT(F, ASCII.HT); 
      INT_IO.PUT(F, RULE_SET(I), 1); 
    end loop; 

    TEXT_IO.NEW_LINE(F); 
  exception
    when STORAGE_ERROR => 
      MISC.AFLEXFATAL("dynamic memory failure in dump_associated_rules()"); 
  end DUMP_ASSOCIATED_RULES; 


  -- dump_transitions - list the transitions associated with a DFA state
  --
  -- goes through the set of out-transitions and lists them in human-readable
  -- form (i.e., not as equivalence classes); also lists jam transitions
  -- (i.e., all those which are not out-transitions, plus EOF).  The dump
  -- is done to the given file.

  procedure DUMP_TRANSITIONS(F     : in FILE_TYPE; 
                             STATE : in UNBOUNDED_INT_ARRAY) is 
    EC           : INTEGER; 
    OUT_CHAR_SET : C_SIZE_BOOL_ARRAY; 
  begin
    for I in 1 .. CSIZE loop
      EC := ECGROUP(I); 

      if (EC < 0) then 
        EC :=  -EC; 
      end if; 

      OUT_CHAR_SET(I) := (STATE(EC) /= 0); 
    end loop; 

    TEXT_IO.PUT(F, " out-transitions: "); 

    CCL.LIST_CHARACTER_SET(F, OUT_CHAR_SET); 

    -- now invert the members of the set to get the jam transitions
    for I in 1 .. CSIZE loop
      OUT_CHAR_SET(I) := not OUT_CHAR_SET(I); 
    end loop; 

    TEXT_IO.NEW_LINE(F); 
    TEXT_IO.PUT(F, "jam-transitions: EOF "); 

    CCL.LIST_CHARACTER_SET(F, OUT_CHAR_SET); 

    TEXT_IO.NEW_LINE(F); 
  end DUMP_TRANSITIONS; 


  -- epsclosure - construct the epsilon closure of a set of ndfa states
  --
  -- NOTES
  --    the epsilon closure is the set of all states reachable by an arbitrary
  --  number of epsilon transitions which themselves do not have epsilon
  --  transitions going out, unioned with the set of states which have non-null
  --  accepting numbers.  t is an array of size numstates of nfa state numbers.
--  Upon return, t holds the epsilon closure and numstates is updated.  accset
  --  holds a list of the accepting numbers, and the size of accset is given
  --  by nacc.  t may be subjected to reallocation if it is not large enough
  --  to hold the epsilon closure.
  --
  --    hashval is the hash value for the dfa corresponding to the state set

  procedure EPSCLOSURE(T                  : in out INT_PTR; 
                       NS_ADDR            : in out INTEGER; 
                       ACCSET             : in out INT_PTR; 
                       NACC_ADDR, HV_ADDR : out INTEGER; 
                       RESULT             : out INT_PTR) is 
    NS, TSP                                      : INTEGER; 
    NUMSTATES, NACC, HASHVAL, TRANSSYM, NFACCNUM : INTEGER; 
    STKEND                                       : INTEGER; 
    STKPOS                                       : INTEGER; 
    procedure MARK_STATE(STATE : in INTEGER) is 
    begin
      TRANS1(STATE) := TRANS1(STATE) - MARKER_DIFFERENCE; 
    end MARK_STATE; 
    pragma INLINE(MARK_STATE); 

    function IS_MARKED(STATE : in INTEGER) return BOOLEAN is 
    begin
      return TRANS1(STATE) < 0; 
    end IS_MARKED; 
    pragma INLINE(IS_MARKED); 

    procedure UNMARK_STATE(STATE : in INTEGER) is 
    begin
      TRANS1(STATE) := TRANS1(STATE) + MARKER_DIFFERENCE; 
    end UNMARK_STATE; 
    pragma INLINE(UNMARK_STATE); 


    procedure CHECK_ACCEPT(STATE : in INTEGER) is 
    begin
      NFACCNUM := ACCPTNUM(STATE); 
      if (NFACCNUM /= NIL) then 
        NACC := NACC + 1; 
        ACCSET(NACC) := NFACCNUM; 
      end if; 
    end CHECK_ACCEPT; 
    pragma INLINE(CHECK_ACCEPT); 

    procedure DO_REALLOCATION is 
    begin
      CURRENT_MAX_DFA_SIZE := CURRENT_MAX_DFA_SIZE + MAX_DFA_SIZE_INCREMENT; 
      NUM_REALLOCS := NUM_REALLOCS + 1; 
      REALLOCATE_INTEGER_ARRAY(T, CURRENT_MAX_DFA_SIZE); 
      REALLOCATE_INTEGER_ARRAY(STK, CURRENT_MAX_DFA_SIZE); 
    end DO_REALLOCATION; 
    pragma INLINE(DO_REALLOCATION); 


    procedure PUT_ON_STACK(STATE : in INTEGER) is 
    begin
      STKEND := STKEND + 1; 
      if (STKEND >= CURRENT_MAX_DFA_SIZE) then 
        DO_REALLOCATION; 
      end if; 
      STK(STKEND) := STATE; 
      MARK_STATE(STATE); 
    end PUT_ON_STACK; 
    pragma INLINE(PUT_ON_STACK); 

    procedure ADD_STATE(STATE : in INTEGER) is 
    begin
      NUMSTATES := NUMSTATES + 1; 
      if (NUMSTATES >= CURRENT_MAX_DFA_SIZE) then 
        DO_REALLOCATION; 
      end if; 
      T(NUMSTATES) := STATE; 
      HASHVAL := HASHVAL + STATE; 
    end ADD_STATE; 
    pragma INLINE(ADD_STATE); 

    procedure STACK_STATE(STATE : in INTEGER) is 
    begin
      PUT_ON_STACK(STATE); 
      CHECK_ACCEPT(STATE); 
      if ((NFACCNUM /= NIL) or (TRANSCHAR(STATE) /= SYM_EPSILON)) then 
        ADD_STATE(STATE); 
      end if; 
    end STACK_STATE; 
    pragma INLINE(STACK_STATE); 

  begin
    NUMSTATES := NS_ADDR; 
    if (not DID_STK_INIT) then 
      STK := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFA_SIZE); 
      DID_STK_INIT := TRUE; 
    end if; 

    NACC := 0; 
    STKEND := 0; 
    HASHVAL := 0; 

    for NSTATE in 1 .. NUMSTATES loop
      NS := T(NSTATE); 

      -- the state could be marked if we've already pushed it onto
      -- the stack
      if (not IS_MARKED(NS)) then 
        PUT_ON_STACK(NS); 
        null; 
      end if; 

      CHECK_ACCEPT(NS); 
      HASHVAL := HASHVAL + NS; 
    end loop; 


    STKPOS := 1; 
    while (STKPOS <= STKEND) loop
      NS := STK(STKPOS); 
      TRANSSYM := TRANSCHAR(NS); 

      if (TRANSSYM = SYM_EPSILON) then 
        TSP := TRANS1(NS) + MARKER_DIFFERENCE; 

        if (TSP /= NO_TRANSITION) then 
          if (not IS_MARKED(TSP)) then 
            STACK_STATE(TSP); 
          end if; 

          TSP := TRANS2(NS); 

          if (TSP /= NO_TRANSITION) then 
            if (not IS_MARKED(TSP)) then 
              STACK_STATE(TSP); 
            end if; 
          end if; 
        end if; 
      end if; 
      STKPOS := STKPOS + 1; 
    end loop; 

    -- clear out "visit" markers
    for CHK_STKPOS in 1 .. STKEND loop
      if (IS_MARKED(STK(CHK_STKPOS))) then 
        UNMARK_STATE(STK(CHK_STKPOS)); 
      else 
        MISC.AFLEXFATAL("consistency check failed in epsclosure()"); 
      end if; 
    end loop; 

    NS_ADDR := NUMSTATES; 
    HV_ADDR := HASHVAL; 
    NACC_ADDR := NACC; 

    RESULT := T; 
  end EPSCLOSURE; 


  -- increase_max_dfas - increase the maximum number of DFAs

  procedure INCREASE_MAX_DFAS is 
  begin
    CURRENT_MAX_DFAS := CURRENT_MAX_DFAS + MAX_DFAS_INCREMENT; 

    NUM_REALLOCS := NUM_REALLOCS + 1; 

    REALLOCATE_INTEGER_ARRAY(BASE, CURRENT_MAX_DFAS); 
    REALLOCATE_INTEGER_ARRAY(DEF, CURRENT_MAX_DFAS); 
    REALLOCATE_INTEGER_ARRAY(DFASIZ, CURRENT_MAX_DFAS); 
    REALLOCATE_INTEGER_ARRAY(ACCSIZ, CURRENT_MAX_DFAS); 
    REALLOCATE_INTEGER_ARRAY(DHASH, CURRENT_MAX_DFAS); 
    REALLOCATE_INT_PTR_ARRAY(DSS, CURRENT_MAX_DFAS); 
    REALLOCATE_DFAACC_UNION(DFAACC, CURRENT_MAX_DFAS); 
  end INCREASE_MAX_DFAS; 


  -- ntod - convert an ndfa to a dfa
  --
  --  creates the dfa corresponding to the ndfa we've constructed.  the
  --  dfa starts out in state #1.

  procedure NTOD is 

    ACCSET                                             : INT_PTR; 
    DS, NACC, NEWDS                                    : INTEGER; 
    DUPLIST, TARGFREQ, TARGSTATE, STATE                : C_SIZE_ARRAY; 
    SYMLIST                                            : C_SIZE_BOOL_ARRAY; 
    HASHVAL, NUMSTATES, DSIZE                          : INTEGER; 
    NSET, DSET                                         : INT_PTR; 
    TARGPTR, TOTALTRANS, I, J, COMSTATE, COMFREQ, TARG : INTEGER; 
    NUM_START_STATES, TODO_HEAD, TODO_NEXT             : INTEGER; 
    SNSRESULT                                          : BOOLEAN; 
    FULL_TABLE_TEMP_FILE                               : FILE_TYPE; 
    BUF                                                : VSTRING; 
    NUM_NXT_STATES                                     : INTEGER; 
    use TEXT_IO; 

    -- this is so find_table_space(...) will know where to start looking in
    -- chk/nxt for unused records for space to put in the state
  begin
    ACCSET := ALLOCATE_INTEGER_ARRAY(NUM_RULES + 1); 
    NSET := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFA_SIZE); 

    -- the "todo" queue is represented by the head, which is the DFA
    -- state currently being processed, and the "next", which is the
    -- next DFA state number available (not in use).  We depend on the
    -- fact that snstods() returns DFA's \in increasing order/, and thus
    -- need only know the bounds of the dfas to be processed.
    TODO_HEAD := 0; 
    TODO_NEXT := 0; 

    for CNT in 0 .. CSIZE loop
      DUPLIST(CNT) := NIL; 
      SYMLIST(CNT) := FALSE; 
    end loop; 

    for CNT in 0 .. NUM_RULES loop
      ACCSET(CNT) := NIL; 
    end loop; 

    if (TRACE) then 
      NFA.DUMPNFA(SCSET(1)); 
      TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      TEXT_IO.PUT(STANDARD_ERROR, "DFA Dump:"); 
      TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      TEXT_IO.NEW_LINE(STANDARD_ERROR); 
    end if; 

    TBLCMP.INITTBL; 

    if (FULLTBL) then 
      GEN.DO_SECT3_OUT; 

      -- output user code up to ##
      SKELETON_MANAGER.SKELOUT; 

      -- declare it "short" because it's a real long-shot that that
      -- won't be large enough
      begin -- make a temporary file to write yy_nxt array into
        CREATE(FULL_TABLE_TEMP_FILE, OUT_FILE); 
      exception
        when USE_ERROR | NAME_ERROR => 
          MISC.AFLEXFATAL("can't create temporary file"); 
      end; 

      NUM_NXT_STATES := 1; 
      TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, "( "); 
      -- generate 0 entries for state #0
      for CNT in 0 .. NUMECS loop
        MISC.MK2DATA(FULL_TABLE_TEMP_FILE, 0); 
      end loop; 

      TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, " )"); 
      -- force extra blank line next dataflush()
      DATALINE := NUMDATALINES; 
    end if; 

    -- create the first states

    NUM_START_STATES := LASTSC*2; 

    for CNT in 1 .. NUM_START_STATES loop
      NUMSTATES := 1; 

      -- for each start condition, make one state for the case when
      -- we're at the beginning of the line (the '%' operator) and
      -- one for the case when we're not

      if (CNT mod 2 = 1) then 
        NSET(NUMSTATES) := SCSET((CNT/2) + 1); 
      else 
        NSET(NUMSTATES) := NFA.MKBRANCH(SCBOL(CNT/2), SCSET(CNT/2)); 
      end if; 

      DFA.EPSCLOSURE(NSET, NUMSTATES, ACCSET, NACC, HASHVAL, NSET); 

      SNSTODS(NSET, NUMSTATES, ACCSET, NACC, HASHVAL, DS, SNSRESULT); 
      if (SNSRESULT) then 
        NUMAS := NUMAS + NACC; 
        TOTNST := TOTNST + NUMSTATES; 
        TODO_NEXT := TODO_NEXT + 1; 

        if (VARIABLE_TRAILING_CONTEXT_RULES and (NACC > 0)) then 
          CHECK_TRAILING_CONTEXT(NSET, NUMSTATES, ACCSET, NACC); 
        end if; 
      end if; 
    end loop; 

    SNSTODS(NSET, 0, ACCSET, 0, 0, END_OF_BUFFER_STATE, SNSRESULT); 
    if (not SNSRESULT) then 
      MISC.AFLEXFATAL("could not create unique end-of-buffer state"); 
    end if; 
    NUMAS := NUMAS + 1; 
    NUM_START_STATES := NUM_START_STATES + 1; 
    TODO_NEXT := TODO_NEXT + 1; 

    while (TODO_HEAD < TODO_NEXT) loop
      NUM_NXT_STATES := NUM_NXT_STATES + 1; 
      TARGPTR := 0; 
      TOTALTRANS := 0; 

      for STATE_CNT in 1 .. NUMECS loop
        STATE(STATE_CNT) := 0; 
      end loop; 

      TODO_HEAD := TODO_HEAD + 1; 
      DS := TODO_HEAD; 

      DSET := DSS(DS); 
      DSIZE := DFASIZ(DS); 

      if (TRACE) then 
        TEXT_IO.PUT(STANDARD_ERROR, "state # "); 
        INT_IO.PUT(STANDARD_ERROR, DS, 1); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, ":"); 
      end if; 

      SYMPARTITION(DSET, DSIZE, SYMLIST, DUPLIST); 

      for SYM in 1 .. NUMECS loop
        if (SYMLIST(SYM)) then 
          SYMLIST(SYM) := FALSE; 

          if (DUPLIST(SYM) = NIL) then 
          -- symbol has unique out-transitions
            NUMSTATES := SYMFOLLOWSET(DSET, DSIZE, SYM, NSET); 
            DFA.EPSCLOSURE(NSET, NUMSTATES, ACCSET, NACC, HASHVAL, NSET); 

            SNSTODS(NSET, NUMSTATES, ACCSET, NACC, HASHVAL, NEWDS, SNSRESULT); 
            if (SNSRESULT) then 
              TOTNST := TOTNST + NUMSTATES; 
              TODO_NEXT := TODO_NEXT + 1; 
              NUMAS := NUMAS + NACC; 

              if (VARIABLE_TRAILING_CONTEXT_RULES and (NACC > 0)) then 
                CHECK_TRAILING_CONTEXT(NSET, NUMSTATES, ACCSET, NACC); 
              end if; 
            end if; 

            STATE(SYM) := NEWDS; 

            if (TRACE) then 
              TEXT_IO.PUT(STANDARD_ERROR, ASCII.HT); 
              INT_IO.PUT(STANDARD_ERROR, SYM, 1); 
              TEXT_IO.PUT(STANDARD_ERROR, ASCII.HT); 
              INT_IO.PUT(STANDARD_ERROR, NEWDS, 1); 
              TEXT_IO.NEW_LINE(STANDARD_ERROR); 
            end if; 

            TARGPTR := TARGPTR + 1; 
            TARGFREQ(TARGPTR) := 1; 
            TARGSTATE(TARGPTR) := NEWDS; 
            NUMUNIQ := NUMUNIQ + 1; 
          else 
          -- sym's equivalence class has the same transitions
          -- as duplist(sym)'s equivalence class

            TARG := STATE(DUPLIST(SYM)); 
            STATE(SYM) := TARG; 
            if (TRACE) then 
              TEXT_IO.PUT(STANDARD_ERROR, ASCII.HT); 
              INT_IO.PUT(STANDARD_ERROR, SYM, 1); 
              TEXT_IO.PUT(STANDARD_ERROR, ASCII.HT); 
              INT_IO.PUT(STANDARD_ERROR, TARG, 1); 
              TEXT_IO.NEW_LINE(STANDARD_ERROR); 
            end if; 

            -- update frequency count for destination state

            I := 1; 

            while (TARGSTATE(I) /= TARG) loop
              I := I + 1; 
            end loop; 

            TARGFREQ(I) := TARGFREQ(I) + 1; 
            NUMDUP := NUMDUP + 1; 
          end if; 

          TOTALTRANS := TOTALTRANS + 1; 
          DUPLIST(SYM) := NIL; 
        end if; 
      end loop; 

      NUMSNPAIRS := NUMSNPAIRS + TOTALTRANS; 

      if (CASEINS and not USEECS) then 
        I := CHARACTER'POS('A'); 
        J := CHARACTER'POS('a'); 
        while (I < CHARACTER'POS('Z')) loop
          STATE(I) := STATE(J); 
          I := I + 1; 
          J := J + 1; 
        end loop; 
      end if; 

      if (DS > NUM_START_STATES) then 
        CHECK_FOR_BACKTRACKING(DS, STATE); 
      end if; 

      if (FULLTBL) then 
      -- supply array's 0-element
        TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, ","); 
        MISC.DATAFLUSH(FULL_TABLE_TEMP_FILE); 
        TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, "( "); 
        if (DS = END_OF_BUFFER_STATE) then 
          MISC.MK2DATA(FULL_TABLE_TEMP_FILE,  -END_OF_BUFFER_STATE); 
        else 
          MISC.MK2DATA(FULL_TABLE_TEMP_FILE, END_OF_BUFFER_STATE); 
        end if; 

        for CNT in 1 .. NUMECS loop
        -- jams are marked by negative of state number
          if ((STATE(CNT) /= 0)) then 
            MISC.MK2DATA(FULL_TABLE_TEMP_FILE, STATE(CNT)); 
          else 
            MISC.MK2DATA(FULL_TABLE_TEMP_FILE,  -DS); 
          end if; 
        end loop; 

        TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, " )"); 
        -- force extra blank line next dataflush()
        DATALINE := NUMDATALINES; 
      else 
        if (DS = END_OF_BUFFER_STATE) then 
        -- special case this state to make sure it does what it's
        -- supposed to, i.e., jam on end-of-buffer
          TBLCMP.STACK1(DS, 0, 0, JAMSTATE_CONST); 
        else  -- normal, compressed state
        -- determine which destination state is the most common, and
        -- how many transitions to it there are
          COMFREQ := 0; 
          COMSTATE := 0; 

          for CNT in 1 .. TARGPTR loop
            if (TARGFREQ(CNT) > COMFREQ) then 
              COMFREQ := TARGFREQ(CNT); 
              COMSTATE := TARGSTATE(CNT); 
            end if; 
          end loop; 

          TBLCMP.BLDTBL(STATE, DS, TOTALTRANS, COMSTATE, COMFREQ); 
        end if; 
      end if; 
    end loop; 

    if (FULLTBL) then 
      TEXT_IO.PUT("yy_nxt : constant array(0.."); 
      INT_IO.PUT(NUM_NXT_STATES - 1, 1); 
      TEXT_IO.PUT_LINE(" , character'first..character'last) of short :="); 
      TEXT_IO.PUT_LINE("   ("); 

      RESET(FULL_TABLE_TEMP_FILE, IN_FILE); 
      while (not END_OF_FILE(FULL_TABLE_TEMP_FILE)) loop
        TSTRING.GET_LINE(FULL_TABLE_TEMP_FILE, BUF); 
        TSTRING.PUT_LINE(BUF); 
      end loop; 
      DELETE(FULL_TABLE_TEMP_FILE); 

      MISC.DATAEND; 
    else 
      TBLCMP.CMPTMPS;  -- create compressed template entries

      -- create tables for all the states with only one out-transition
      while (ONESP > 0) loop
        TBLCMP.MK1TBL(ONESTATE(ONESP), ONESYM(ONESP), ONENEXT(ONESP), ONEDEF(
          ONESP)); 
        ONESP := ONESP - 1; 
      end loop; 

      TBLCMP.MKDEFTBL; 
    end if; 
  end NTOD; 

  -- snstods - converts a set of ndfa states into a dfa state
  --
  -- on return, the dfa state number is in newds.
  procedure SNSTODS(SNS           : in INT_PTR; 
                    NUMSTATES     : in INTEGER; 
                    ACCSET        : in INT_PTR; 
                    NACC, HASHVAL : in INTEGER; 
                    NEWDS_ADDR    : out INTEGER; 
                    RESULT        : out BOOLEAN) is 
    DIDSORT : BOOLEAN := FALSE; 
    J       : INTEGER; 
    NEWDS   : INTEGER; 
    OLDSNS  : INT_PTR; 
  begin
    for I in 1 .. LASTDFA loop
      if (HASHVAL = DHASH(I)) then 
        if (NUMSTATES = DFASIZ(I)) then 
          OLDSNS := DSS(I); 

          if (not DIDSORT) then 
          -- we sort the states in sns so we can compare it to
          -- oldsns quickly.  we use bubble because there probably
          -- aren't very many states

            MISC.BUBBLE(SNS, NUMSTATES); 
            DIDSORT := TRUE; 
          end if; 

          J := 1; 
          while (J <= NUMSTATES) loop
            if (SNS(J) /= OLDSNS(J)) then 
              exit; 
            end if; 
            J := J + 1; 
          end loop; 

          if (J > NUMSTATES) then 
            DFAEQL := DFAEQL + 1; 
            NEWDS_ADDR := I; 
            RESULT := FALSE; 
            return; 
          end if; 

          HSHCOL := HSHCOL + 1; 
        else 
          HSHSAVE := HSHSAVE + 1; 
        end if; 
      end if; 
    end loop; 
    -- make a new dfa

    LASTDFA := LASTDFA + 1; 
    if (LASTDFA >= CURRENT_MAX_DFAS) then 
      INCREASE_MAX_DFAS; 
    end if; 

    NEWDS := LASTDFA; 

    DSS(NEWDS) := new UNBOUNDED_INT_ARRAY(0 .. NUMSTATES + 1); 

    -- if we haven't already sorted the states in sns, we do so now, so that
    -- future comparisons with it can be made quickly

    if (not DIDSORT) then 
      MISC.BUBBLE(SNS, NUMSTATES); 
    end if; 

    for I in 1 .. NUMSTATES loop
      DSS(NEWDS)(I) := SNS(I); 
    end loop; 

    DFASIZ(NEWDS) := NUMSTATES; 
    DHASH(NEWDS) := HASHVAL; 

    if (NACC = 0) then 
      DFAACC(NEWDS).DFAACC_STATE := 0; 
      ACCSIZ(NEWDS) := 0; 
    else 
    -- find lowest numbered rule so the disambiguating rule will work
      J := NUM_RULES + 1; 

      for I in 1 .. NACC loop
        if (ACCSET(I) < J) then 
          J := ACCSET(I); 
        end if; 
      end loop; 

      DFAACC(NEWDS).DFAACC_STATE := J; 
    end if; 

    NEWDS_ADDR := NEWDS; 
    RESULT := TRUE; 
    return; 

  exception
    when STORAGE_ERROR => 
      MISC.AFLEXFATAL("dynamic memory failure in snstods()"); 
  end SNSTODS; 

  -- symfollowset - follow the symbol transitions one step
  function SYMFOLLOWSET(DS              : in INT_PTR; 
                        DSIZE, TRANSSYM : in INTEGER; 
                        NSET            : in INT_PTR) return INTEGER is 
    NS, TSP, SYM, LENCCL, CH, NUMSTATES, CCLLIST : INTEGER; 
  begin
    NUMSTATES := 0; 

    for I in 1 .. DSIZE loop
    -- for each nfa state ns in the state set of ds
      NS := DS(I); 
      SYM := TRANSCHAR(NS); 
      TSP := TRANS1(NS); 

      if (SYM < 0) then 
      -- it's a character class
        SYM :=  -SYM; 
        CCLLIST := CCLMAP(SYM); 
        LENCCL := CCLLEN(SYM); 

        if (CCLNG(SYM) /= 0) then 
          for J in 0 .. LENCCL - 1 loop
          -- loop through negated character class
            CH := CHARACTER'POS(CCLTBL(CCLLIST + J)); 

            if (CH > TRANSSYM) then 
              exit;  -- transsym isn't in negated ccl
            else 
              if (CH = TRANSSYM) then 
                goto BOTTOM;  -- next 2
              end if; 
            end if; 
          end loop; 

          -- didn't find transsym in ccl
          NUMSTATES := NUMSTATES + 1; 
          NSET(NUMSTATES) := TSP; 
        else 
          for J in 0 .. LENCCL - 1 loop
            CH := CHARACTER'POS(CCLTBL(CCLLIST + J)); 

            if (CH > TRANSSYM) then 
              exit; 
            else 
              if (CH = TRANSSYM) then 
                NUMSTATES := NUMSTATES + 1; 
                NSET(NUMSTATES) := TSP; 
                exit; 
              end if; 
            end if; 
          end loop; 
        end if; 
      else 
        if ((SYM >= CHARACTER'POS('A')) and (SYM <= CHARACTER'POS('Z')) and 
          CASEINS) then 
          MISC.AFLEXFATAL("consistency check failed in symfollowset"); 
        else 
          if (SYM = SYM_EPSILON) then 
            null;  -- do nothing
          else 
            if (ECGROUP(SYM) = TRANSSYM) then 
              NUMSTATES := NUMSTATES + 1; 
              NSET(NUMSTATES) := TSP; 
            end if; 
          end if; 
        end if; 
      end if; 

      <<BOTTOM>> null; 
    end loop; 
    return NUMSTATES; 
  end SYMFOLLOWSET; 

  -- sympartition - partition characters with same out-transitions
  procedure SYMPARTITION(DS        : in INT_PTR; 
                         NUMSTATES : in INTEGER; 
                         SYMLIST   : in out C_SIZE_BOOL_ARRAY; 
                         DUPLIST   : in out C_SIZE_ARRAY) is 
    TCH, J, NS, LENCCL, CCLP, ICH : INTEGER; 
    DUPFWD                        : C_SIZE_ARRAY; 

  -- partitioning is done by creating equivalence classes for those
  -- characters which have out-transitions from the given state.  Thus
  -- we are really creating equivalence classes of equivalence classes.
  begin
    for I in 1 .. NUMECS loop
    -- initialize equivalence class list
      DUPLIST(I) := I - 1; 
      DUPFWD(I) := I + 1; 
    end loop; 

    DUPLIST(1) := NIL; 
    DUPFWD(NUMECS) := NIL; 
    DUPFWD(0) := 0; 

    for I in 1 .. NUMSTATES loop
      NS := DS(I); 
      TCH := TRANSCHAR(NS); 

      if (TCH /= SYM_EPSILON) then 
        if ((TCH <  -LASTCCL) or (TCH > CSIZE)) then 
          MISC.AFLEXFATAL("bad transition character detected in sympartition()")
            ; 
        end if; 

        if (TCH > 0) then 
        -- character transition
          ECS.MKECHAR(ECGROUP(TCH), DUPFWD, DUPLIST); 
          SYMLIST(ECGROUP(TCH)) := TRUE; 
        else 
        -- character class
          TCH :=  -TCH; 

          LENCCL := CCLLEN(TCH); 
          CCLP := CCLMAP(TCH); 
          ECS.MKECCL(CCLTBL(CCLP .. CCLP + LENCCL), LENCCL, DUPFWD, DUPLIST, 
            NUMECS); 

          if (CCLNG(TCH) /= 0) then 
            J := 0; 

            for K in 0 .. LENCCL - 1 loop
              ICH := CHARACTER'POS(CCLTBL(CCLP + K)); 

              J := J + 1; 
              while (J < ICH) loop
                SYMLIST(J) := TRUE; 
                J := J + 1; 
              end loop; 
            end loop; 

            J := J + 1; 
            while (J <= NUMECS) loop
              SYMLIST(J) := TRUE; 
              J := J + 1; 
            end loop; 
          else 
            for K in 0 .. LENCCL - 1 loop
              ICH := CHARACTER'POS(CCLTBL(CCLP + K)); 
              SYMLIST(ICH) := TRUE; 
            end loop; 
          end if; 
        end if; 
      end if; 
    end loop; 
  end SYMPARTITION; 
end DFA; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE DFA construction routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION converts non-deterministic finite automatons to finite ones.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/dfaS.a,v 1.4 90/01/12 15:19:52 self Exp Locker: self $ 

with MISC_DEFS; 
with TEXT_IO; 
package DFA is 
  use MISC_DEFS, TEXT_IO; 
  procedure CHECK_FOR_BACKTRACKING(DS    : in INTEGER; 
                                   STATE : in UNBOUNDED_INT_ARRAY); 
  procedure CHECK_TRAILING_CONTEXT(NFA_STATES : in INT_PTR; 
                                   NUM_STATES : in INTEGER; 
                                   ACCSET     : in INT_PTR; 
                                   NACC       : in INTEGER); 

  procedure DUMP_ASSOCIATED_RULES(F  : in FILE_TYPE; 
                                  DS : in INTEGER); 

  procedure DUMP_TRANSITIONS(F     : in FILE_TYPE; 
                             STATE : in UNBOUNDED_INT_ARRAY); 

  procedure EPSCLOSURE(T                  : in out INT_PTR; 
                       NS_ADDR            : in out INTEGER; 
                       ACCSET             : in out INT_PTR; 
                       NACC_ADDR, HV_ADDR : out INTEGER; 
                       RESULT             : out INT_PTR); 

  procedure INCREASE_MAX_DFAS; 

  procedure NTOD; 

  procedure SNSTODS(SNS           : in INT_PTR; 
                    NUMSTATES     : in INTEGER; 
                    ACCSET        : in INT_PTR; 
                    NACC, HASHVAL : in INTEGER; 
                    NEWDS_ADDR    : out INTEGER; 
                    RESULT        : out BOOLEAN); 

  function SYMFOLLOWSET(DS              : in INT_PTR; 
                        DSIZE, TRANSSYM : in INTEGER; 
                        NSET            : in INT_PTR) return INTEGER; 

  procedure SYMPARTITION(DS        : in INT_PTR; 
                         NUMSTATES : in INTEGER; 
                         SYMLIST   : in out C_SIZE_BOOL_ARRAY; 
                         DUPLIST   : in out C_SIZE_ARRAY); 
end DFA; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE equivalence class
-- AUTHOR: John Self (UCI)
-- DESCRIPTION finds equivalence classes so DFA will be smaller
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/ecsB.a,v 1.7 90/01/12 15:19:54 self Exp Locker: self $ 

with MISC_DEFS; 
with MISC; use MISC_DEFS; 
package body ECS is 

-- ccl2ecl - convert character classes to set of equivalence classes

  procedure CCL2ECL is 
    use MISC_DEFS; 
    ICH, NEWLEN, CCLP, CCLMEC : INTEGER; 
  begin
    for I in 1 .. LASTCCL loop

      -- we loop through each character class, and for each character
      -- in the class, add the character's equivalence class to the
      -- new "character" class we are creating.  Thus when we are all
      -- done, character classes will really consist of collections
      -- of equivalence classes
      NEWLEN := 0; 
      CCLP := CCLMAP(I); 

      for CCLS in 0 .. CCLLEN(I) - 1 loop
        ICH := CHARACTER'POS(CCLTBL(CCLP + CCLS)); 
        CCLMEC := ECGROUP(ICH); 
        if (CCLMEC > 0) then 
          CCLTBL(CCLP + NEWLEN) := CHARACTER'VAL(CCLMEC); 
          NEWLEN := NEWLEN + 1; 
        end if; 
      end loop; 

      CCLLEN(I) := NEWLEN; 
    end loop; 
  end CCL2ECL; 


  -- cre8ecs - associate equivalence class numbers with class members
  --  fwd is the forward linked-list of equivalence class members.  bck
  --  is the backward linked-list, and num is the number of class members.
  --  Returned is the number of classes.

  procedure CRE8ECS(FWD, BCK : in out C_SIZE_ARRAY; 
                    NUM      : in INTEGER; 
                    RESULT   : out INTEGER) is 
    J, NUMCL : INTEGER; 
  begin
    NUMCL := 0; 

    -- create equivalence class numbers.  From now on, abs( bck(x) )
    -- is the equivalence class number for object x.  If bck(x)
    -- is positive, then x is the representative of its equivalence
    -- class.
    for I in 1 .. NUM loop
      if (BCK(I) = NIL) then 
        NUMCL := NUMCL + 1; 
        BCK(I) := NUMCL; 
        J := FWD(I); 
        while (J /= NIL) loop
          BCK(J) :=  -NUMCL; 
          J := FWD(J); 
        end loop; 
      end if; 
    end loop; 
    RESULT := NUMCL; 
    return; 
  end CRE8ECS; 


  -- mkeccl - update equivalence classes based on character class xtions
  -- where ccls contains the elements of the character class, lenccl is the
  -- number of elements in the ccl, fwd is the forward link-list of equivalent
  -- characters, bck is the backward link-list, and llsiz size of the link-list

  procedure MKECCL(CCLS     : in out CHAR_ARRAY; 
                   LENCCL   : in INTEGER; 
                   FWD, BCK : in out UNBOUNDED_INT_ARRAY; 
                   LLSIZ    : in INTEGER) is 
    use MISC_DEFS, MISC; 
    CCLP, OLDEC, NEWEC, CCLM, I, J : INTEGER; 
    PROC_ARRAY                     : BOOLEAN_PTR; 
  begin

    -- note that it doesn't matter whether or not the character class is
    -- negated.  The same results will be obtained in either case.
    CCLP := CCLS'FIRST; 

    -- this array tells whether or not a character class has been processed.
    PROC_ARRAY := new BOOLEAN_ARRAY(CCLS'FIRST .. CCLS'LAST); 
    for CCL_INDEX in CCLS'FIRST .. CCLS'LAST loop
      PROC_ARRAY(CCL_INDEX) := FALSE; 
    end loop; 

    while (CCLP < LENCCL + CCLS'FIRST) loop
      CCLM := CHARACTER'POS(CCLS(CCLP)); 
      OLDEC := BCK(CCLM); 
      NEWEC := CCLM; 

      J := CCLP + 1; 

      I := FWD(CCLM); 
      while ((I /= NIL) and (I <= LLSIZ)) loop

        -- look for the symbol in the character class
        while ((J < LENCCL + CCLS'FIRST) and ((CCLS(J) <= CHARACTER'VAL(I)) or 
          PROC_ARRAY(J))) loop
          if (CCLS(J) = CHARACTER'VAL(I)) then 

            -- we found an old companion of cclm in the ccl.
            -- link it into the new equivalence class and flag it as
            -- having been processed
            BCK(I) := NEWEC; 
            FWD(NEWEC) := I; 
            NEWEC := I; 
            PROC_ARRAY(J) := TRUE; 

            -- set flag so we don't reprocess

            -- get next equivalence class member
            -- continue 2
            goto NEXT_PT; 
          end if; 
          J := J + 1; 
        end loop; 

        -- symbol isn't in character class.  Put it in the old equivalence
        -- class
        BCK(I) := OLDEC; 

        if (OLDEC /= NIL) then 
          FWD(OLDEC) := I; 
        end if; 

        OLDEC := I; 
        <<NEXT_PT>> I := FWD(I); 
      end loop; 

      if ((BCK(CCLM) /= NIL) or (OLDEC /= BCK(CCLM))) then 
        BCK(CCLM) := NIL; 
        FWD(OLDEC) := NIL; 
      end if; 

      FWD(NEWEC) := NIL; 

      -- find next ccl member to process
      CCLP := CCLP + 1; 

      while ((CCLP < LENCCL + CCLS'FIRST) and PROC_ARRAY(CCLP)) loop

        -- reset "doesn't need processing" flag
        PROC_ARRAY(CCLP) := FALSE; 
        CCLP := CCLP + 1; 
      end loop; 
    end loop; 
  exception
    when STORAGE_ERROR => 
      MISC.AFLEXFATAL("dynamic memory failure in mkeccl()"); 
  end MKECCL; 


  -- mkechar - create equivalence class for single character

  procedure MKECHAR(TCH      : in INTEGER; 
                    FWD, BCK : in out C_SIZE_ARRAY) is 
  begin

    -- if until now the character has been a proper subset of
    -- an equivalence class, break it away to create a new ec
    if (FWD(TCH) /= NIL) then 
      BCK(FWD(TCH)) := BCK(TCH); 
    end if; 

    if (BCK(TCH) /= NIL) then 
      FWD(BCK(TCH)) := FWD(TCH); 
    end if; 

    FWD(TCH) := NIL; 
    BCK(TCH) := NIL; 
  end MKECHAR; 

end ECS; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE equivalence class
-- AUTHOR: John Self (UCI)
-- DESCRIPTION finds equivalence classes so DFA will be smaller
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/ecsS.a,v 1.4 90/01/12 15:19:57 self Exp Locker: self $ 

with MISC_DEFS; use MISC_DEFS; 
package ECS is 
  procedure CCL2ECL; 
  procedure CRE8ECS(FWD, BCK : in out C_SIZE_ARRAY; 
                    NUM      : in INTEGER; 
                    RESULT   : out INTEGER); 
  procedure MKECCL(CCLS     : in out CHAR_ARRAY; 
                   LENCCL   : in INTEGER; 
                   FWD, BCK : in out UNBOUNDED_INT_ARRAY; 
                   LLSIZ    : in INTEGER); 
  procedure MKECHAR(TCH      : in INTEGER; 
                    FWD, BCK : in out C_SIZE_ARRAY); 
end ECS; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE external_file_manager
-- AUTHOR: John Self (UCI)
-- DESCRIPTION opens external files for other functions
-- NOTES This package opens external files, and thus may be system dependent
--       because of limitations on file names.
--       This version is for the VADS 5.5 Ada development system.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/file_managerB.a,v 1.5 90/01/12 15:19:58 self Exp Locker: self $ 

with MISC_DEFS, TSTRING, TEXT_IO, MISC; use MISC_DEFS, TSTRING, TEXT_IO, MISC; 

package body EXTERNAL_FILE_MANAGER is 

-- FIX comment about compiler dependent

  subtype SUFFIX_TYPE is STRING(1 .. 1); 

  function ADA_SUFFIX return SUFFIX_TYPE is 
  begin
    return "a"; 
  end ADA_SUFFIX; 

  procedure GET_IO_FILE(F : in out FILE_TYPE) is 
  begin
    if (LEN(INFILENAME) /= 0) then 
      CREATE(F, OUT_FILE, STR(MISC.BASENAME) & "_io." & ADA_SUFFIX); 
    else 
      CREATE(F, OUT_FILE, "aflex_yy_io." & ADA_SUFFIX); 
    end if; 
  exception
    when USE_ERROR | NAME_ERROR => 
      MISC.AFLEXFATAL("could not create IO package file"); 
  end GET_IO_FILE; 

  procedure GET_DFA_FILE(F : in out FILE_TYPE) is 
  begin
    if (LEN(INFILENAME) /= 0) then 
      CREATE(F, OUT_FILE, STR(MISC.BASENAME) & "_dfa." & ADA_SUFFIX); 
    else 
      CREATE(F, OUT_FILE, "aflex_yy_dfa." & ADA_SUFFIX); 
    end if; 
  exception
    when USE_ERROR | NAME_ERROR => 
      MISC.AFLEXFATAL("could not create DFA package file"); 
  end GET_DFA_FILE; 

  procedure GET_SCANNER_FILE(F : in out FILE_TYPE) is 
    OUTFILE_NAME : VSTRING; 
  begin
    if (LEN(INFILENAME) /= 0) then 

      -- give out infile + ada_suffix
      OUTFILE_NAME := MISC.BASENAME & "." & ADA_SUFFIX; 
    else 
      OUTFILE_NAME := VSTR("aflex_yy." & ADA_SUFFIX); 
    end if; 

    CREATE(F, OUT_FILE, STR(OUTFILE_NAME)); 
    SET_OUTPUT(F); 
  exception
    when NAME_ERROR | USE_ERROR => 
      MISC.AFLEXFATAL("can't create scanner file " & OUTFILE_NAME); 
  end GET_SCANNER_FILE; 

  procedure GET_BACKTRACK_FILE(F : in out FILE_TYPE) is 
  begin
    CREATE(F, OUT_FILE, "aflex.backtrack"); 
  exception
    when USE_ERROR | NAME_ERROR => 
      MISC.AFLEXFATAL("could not create backtrack file"); 
  end GET_BACKTRACK_FILE; 

  procedure INITIALIZE_FILES is 
  begin
    null; 

  -- doesn't need to do anything on Verdix
  end INITIALIZE_FILES; 

end EXTERNAL_FILE_MANAGER; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE external_file_manager
-- AUTHOR: John Self (UCI)
-- DESCRIPTION opens external files for other functions
-- NOTES This package opens external files, and thus may be system dependent
--       because of limitations on file names.
--       This version is for the VADS 5.5 Ada development system.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/file_managerS.a,v 1.4 90/01/12 15:20:00 self Exp Locker: self $ 

with TEXT_IO; use TEXT_IO; 
package EXTERNAL_FILE_MANAGER is 
  procedure GET_IO_FILE(F : in out FILE_TYPE); 
  procedure GET_DFA_FILE(F : in out FILE_TYPE); 
  procedure GET_SCANNER_FILE(F : in out FILE_TYPE); 
  procedure GET_BACKTRACK_FILE(F : in out FILE_TYPE); 
  procedure INITIALIZE_FILES; 
end EXTERNAL_FILE_MANAGER; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE file strings
-- AUTHOR: John Self (UCI)
-- DESCRIPTION used to store lines in the template files
-- NOTES if lines in a template exceed 128 characters we are in trouble
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/file_strings.a,v 1.3 90/01/12 15:20:02 self Exp Locker: self $ 

with VSTRINGS; 
package FILE_STRING is 
  new VSTRINGS(128); 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE scanner generation
-- AUTHOR: John Self (UCI)
-- DESCRIPTION
-- NOTES does actual generation (writing) of output aflex scanners
-- $Header: /dc/uc/self/arcadia/aflex/ada/src/RCS/genB.a,v 1.25 1992/10/02 23:08:41 self Exp self $ 

with MISC_DEFS, TEXT_IO, MISC, INT_IO, TSTRING, PARSE_TOKENS; 
with SCANNER, SKELETON_MANAGER, EXTERNAL_FILE_MANAGER; use MISC_DEFS, TEXT_IO, 
  TSTRING, PARSE_TOKENS, EXTERNAL_FILE_MANAGER; 

package body GEN is 
  INDENT_LEVEL : INTEGER := 0;  -- each level is 4 spaces

  MAX_SHORT    : constant INTEGER := 32767; 
  procedure INDENT_UP is 
  begin
    INDENT_LEVEL := INDENT_LEVEL + 1; 
  end INDENT_UP; 
  pragma INLINE(INDENT_UP); 
  procedure INDENT_DOWN is 
  begin
    INDENT_LEVEL := INDENT_LEVEL - 1; 
  end INDENT_DOWN; 
  pragma INLINE(INDENT_DOWN); 

  procedure SET_INDENT(INDENT_VAL : in INTEGER) is 
  begin
    INDENT_LEVEL := INDENT_VAL; 
  end SET_INDENT; 


  -- indent to the current level

  procedure DO_INDENT is 
    I : INTEGER := INDENT_LEVEL*4; 
  begin
    while (I >= 8) loop
      TEXT_IO.PUT(ASCII.HT); 
      I := I - 8; 
    end loop; 

    while (I > 0) loop
      TEXT_IO.PUT(' '); 
      I := I - 1; 
    end loop; 
  end DO_INDENT; 

  -- generate the code to keep backtracking information

  procedure GEN_BACKTRACKING is 
  begin
    if (NUM_BACKTRACKING = 0) then 
      return; 
    end if; 

    INDENT_PUTS("if ( yy_accept(yy_current_state) /= 0 ) then"); 

    INDENT_UP; 
    INDENT_PUTS("yy_last_accepting_state := yy_current_state;"); 
    INDENT_PUTS("yy_last_accepting_cpos := yy_cp;"); 
    INDENT_DOWN; 
    INDENT_PUTS("end if;"); 
  end GEN_BACKTRACKING; 

  -- generate the code to perform the backtrack

  procedure GEN_BT_ACTION is 
  begin
    if (NUM_BACKTRACKING = 0) then 
      return; 
    end if; 

    SET_INDENT(4); 

    INDENT_PUTS("when 0 => -- must backtrack"); 
    INDENT_PUTS("-- undo the effects of YY_DO_BEFORE_ACTION"); 
    INDENT_PUTS("yy_ch_buf(yy_cp) := yy_hold_char;"); 

    if (FULLTBL) then 
      INDENT_PUTS("yy_cp := yy_last_accepting_cpos + 1;"); 
    else 

      -- backtracking info for compressed tables is taken \after/
      -- yy_cp has been incremented for the next state
      INDENT_PUTS("yy_cp := yy_last_accepting_cpos;"); 
    end if; 

    INDENT_PUTS("yy_current_state := yy_last_accepting_state;"); 
    INDENT_PUTS("goto next_action;"); 
    TEXT_IO.NEW_LINE; 

    SET_INDENT(0); 
  end GEN_BT_ACTION; 

  -- generate equivalence-class table

  procedure GENECS is 
    I       : INTEGER; 
    NUMROWS : INTEGER; 
    use TEXT_IO; 
  begin
    TEXT_IO.PUT("yy_ec : constant array(CHARACTER'FIRST.."); 
    TEXT_IO.PUT_LINE("CHARACTER'LAST) of short :="); 
    TEXT_IO.PUT_LINE("    (   0,"); 

    for CHAR_COUNT in 1 .. CSIZE loop
      if (CASEINS and ((CHAR_COUNT >= CHARACTER'POS('A')) and (CHAR_COUNT <= 
        CHARACTER'POS('Z')))) then 
        ECGROUP(CHAR_COUNT) := ECGROUP(MISC.CLOWER(CHAR_COUNT)); 
      end if; 

      ECGROUP(CHAR_COUNT) := abs(ECGROUP(CHAR_COUNT)); 
      MISC.MKDATA(ECGROUP(CHAR_COUNT)); 
    end loop; 

    MISC.DATAEND; 

    if (TRACE) then 
      TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      TEXT_IO.PUT(STANDARD_ERROR, "Equivalence Classes:"); 
      TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      NUMROWS := (CSIZE + 1)/8; 

      for J in 1 .. NUMROWS loop
        I := J; 
        while (I <= CSIZE) loop
          TSTRING.PUT(STANDARD_ERROR, MISC.READABLE_FORM(CHARACTER'VAL(I))); 
          TEXT_IO.PUT(STANDARD_ERROR, " = "); 
          INT_IO.PUT(STANDARD_ERROR, ECGROUP(I), 1); 
          TEXT_IO.PUT(STANDARD_ERROR, "   "); 
          I := I + NUMROWS; 
        end loop; 
        TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      end loop; 
    end if; 
  end GENECS; 

  -- generate the code to find the action number

  procedure GEN_FIND_ACTION is 
  begin
    INDENT_PUTS("yy_act := yy_accept(yy_current_state);"); 
  end GEN_FIND_ACTION; 

  -- genftbl - generates full transition table

  procedure GENFTBL is 
    END_OF_BUFFER_ACTION : INTEGER := NUM_RULES + 1; 
    -- *everything* is done in terms of arrays starting at 1, so provide
    -- a null entry for the zero element of all C arrays
    use TEXT_IO; 
  begin
    TEXT_IO.PUT("yy_accept : constant array(0.."); 
    INT_IO.PUT(LASTDFA, 1); 
    TEXT_IO.PUT_LINE(") of short :="); 
    TEXT_IO.PUT_LINE("    (   0,"); 

    DFAACC(END_OF_BUFFER_STATE).DFAACC_STATE := END_OF_BUFFER_ACTION; 

    for I in 1 .. LASTDFA loop
      declare
        ANUM : INTEGER := DFAACC(I).DFAACC_STATE; 
      begin
        MISC.MKDATA(ANUM); 

        if (TRACE and (ANUM /= 0)) then 
          TEXT_IO.PUT(STANDARD_ERROR, "state # "); 
          INT_IO.PUT(STANDARD_ERROR, I, 1); 
          TEXT_IO.PUT(STANDARD_ERROR, " accepts: ["); 
          INT_IO.PUT(STANDARD_ERROR, ANUM, 1); 
          TEXT_IO.PUT(STANDARD_ERROR, "]"); 
          TEXT_IO.NEW_LINE(STANDARD_ERROR); 
        end if; 
      end; 
    end loop; 

    MISC.DATAEND; 

    if (USEECS) then 
      GENECS; 
    end if; 

  -- don't have to dump the actual full table entries - they were created
  -- on-the-fly
  end GENFTBL; 

  -- generate the code to find the next compressed-table state

  procedure GEN_NEXT_COMPRESSED_STATE is 
  begin
    if (USEECS) then 
      INDENT_PUTS("yy_c := yy_ec(yy_ch_buf(yy_cp));"); 
    else 
      INDENT_PUTS("yy_c := yy_ch_buf(yy_cp);"); 
    end if; 

    -- save the backtracking info \before/ computing the next state
    -- because we always compute one more state than needed - we
    -- always proceed until we reach a jam state
    GEN_BACKTRACKING; 

    INDENT_PUTS(
      "while ( yy_chk(yy_base(yy_current_state) + yy_c) /= yy_current_state ) loop"
      ); 
    INDENT_UP; 
    INDENT_PUTS("yy_current_state := yy_def(yy_current_state);"); 

    if (USEMECS) then 

      -- we've arrange it so that templates are never chained
      -- to one another.  This means we can afford make a
      -- very simple test to see if we need to convert to
      -- yy_c's meta-equivalence class without worrying
      -- about erroneously looking up the meta-equivalence
      -- class twice
      DO_INDENT; 

      -- lastdfa + 2 is the beginning of the templates
      TEXT_IO.PUT("if ( yy_current_state >= "); 
      INT_IO.PUT(LASTDFA + 2, 1); 
      TEXT_IO.PUT_LINE(" ) then"); 

      INDENT_UP; 
      INDENT_PUTS("yy_c := yy_meta(yy_c);"); 
      INDENT_DOWN; 
      INDENT_PUTS("end if;"); 
    end if; 

    INDENT_DOWN; 
    INDENT_PUTS("end loop;"); 

    INDENT_PUTS("yy_current_state := yy_nxt(yy_base(yy_current_state) + yy_c);")
      ; 
    INDENT_DOWN; 
  end GEN_NEXT_COMPRESSED_STATE; 

  -- generate the code to find the next match

  procedure GEN_NEXT_MATCH is 
  -- note - changes in here should be reflected in get_next_state
  begin
    if (FULLTBL) then 
      INDENT_PUTS(
        "yy_current_state := yy_nxt(yy_current_state, yy_ch_buf(yy_cp));"); 
      INDENT_PUTS("while ( yy_current_state > 0 ) loop"); 
      INDENT_UP; 
      INDENT_PUTS("yy_cp := yy_cp + 1;"); 
      INDENT_PUTS(
        "yy_current_state := yy_nxt(yy_current_state, yy_ch_buf(yy_cp));"); 
      INDENT_DOWN; 
      INDENT_PUTS("end loop;"); 

      if (NUM_BACKTRACKING > 0) then 
        GEN_BACKTRACKING; 
        TEXT_IO.NEW_LINE; 
      end if; 

      TEXT_IO.NEW_LINE; 
      INDENT_PUTS("yy_current_state := -yy_current_state;"); 
    else 

      -- compressed
      INDENT_PUTS("loop"); 

      INDENT_UP; 

      GEN_NEXT_STATE; 

      INDENT_PUTS("yy_cp := yy_cp + 1;"); 

      if (INTERACTIVE) then
        TEXT_IO.PUT("if ( yy_base(yy_current_state) = ");
        INT_IO.PUT(JAMBASE, 1);
      else
        TEXT_IO.PUT("if ( yy_current_state = "); 
        INT_IO.PUT(JAMSTATE, 1); 
      end if;
      
      TEXT_IO.PUT_LINE(" ) then"); 
      TEXT_IO.PUT_LINE("    exit;"); 
      TEXT_IO.PUT_LINE("end if;"); 

      INDENT_DOWN; 

      DO_INDENT; 

      TEXT_IO.PUT_LINE("end loop;"); 

      if (not INTERACTIVE) then
        INDENT_PUTS("yy_cp := yy_last_accepting_cpos;"); 
        INDENT_PUTS("yy_current_state := yy_last_accepting_state;"); 
      end if;
    end if; 
  end GEN_NEXT_MATCH; 

  -- generate the code to find the next state

  procedure GEN_NEXT_STATE is 
  -- note - changes in here should be reflected in get_next_match
  begin
    INDENT_UP; 
    if (FULLTBL) then 
      INDENT_PUTS("yy_current_state := yy_nxt(yy_current_state,"); 
      INDENT_PUTS("                    yy_ch_buf(yy_cp));"); 
      GEN_BACKTRACKING; 
    else 
      GEN_NEXT_COMPRESSED_STATE; 
    end if; 
  end GEN_NEXT_STATE; 

  -- generate the code to find the start state

  procedure GEN_START_STATE is 
  begin
    INDENT_PUTS("yy_current_state := yy_start;"); 

    if (BOL_NEEDED) then 
      INDENT_PUTS("if ( yy_ch_buf(yy_bp-1) = ASCII.LF ) then"); 
      INDENT_UP; 
      INDENT_PUTS("yy_current_state := yy_current_state + 1;"); 
      INDENT_DOWN; 
      INDENT_PUTS("end if;"); 
    end if; 

  end GEN_START_STATE; 

  -- gentabs - generate data statements for the transition tables

  procedure GENTABS is 
    I, J, K, NACC, TOTAL_STATES : INTEGER; 
    ACCSET, ACC_ARRAY           : INT_PTR; 
    ACCNUM                      : INTEGER; 
    END_OF_BUFFER_ACTION        : INTEGER := NUM_RULES + 1; 
    -- *everything* is done in terms of arrays starting at 1, so provide
    -- a null entry for the zero element of all C arrays

    C_LONG_DECL                 : STRING(1 .. 44) := 
      "static const long int %s[%d] =\n    {   0,\n"; 
    C_SHORT_DECL                : STRING(1 .. 45) := 
      "static const short int %s[%d] =\n    {   0,\n"; 
    C_CHAR_DECL                 : STRING(1 .. 40) := 
      "static const char %s[%d] =\n    {   0,\n"; 
  begin
    ACC_ARRAY := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFAS); 
    NUMMT := 0; 

    -- the compressed table format jams by entering the "jam state",
    -- losing information about the previous state in the process.
    -- In order to recover the previous state, we effectively need
    -- to keep backtracking information.
    NUM_BACKTRACKING := NUM_BACKTRACKING + 1; 

    DFAACC(END_OF_BUFFER_STATE).DFAACC_STATE := END_OF_BUFFER_ACTION; 

    for CNT in 1 .. LASTDFA loop
      ACC_ARRAY(CNT) := DFAACC(CNT).DFAACC_STATE; 
    end loop; 


    ACC_ARRAY(LASTDFA + 1) := 0; 

    -- add accepting number for the jam state

    -- spit out ALIST array, dumping the accepting numbers.

    -- "lastdfa + 2" is the size of ALIST; includes room for arrays
    -- beginning at 0 and for "jam" state
    K := LASTDFA + 2; 

    TEXT_IO.PUT("yy_accept : constant array(0.."); 
    INT_IO.PUT(K - 1, 1); 
    TEXT_IO.PUT_LINE(") of short :="); 
    TEXT_IO.PUT_LINE("    (   0,"); 
    for CNT in 1 .. LASTDFA loop
      MISC.MKDATA(ACC_ARRAY(CNT)); 

      if (TRACE and (ACC_ARRAY(CNT) /= 0)) then 
        TEXT_IO.PUT(STANDARD_ERROR, "state # "); 
        INT_IO.PUT(STANDARD_ERROR, CNT, 1); 
        TEXT_IO.PUT(STANDARD_ERROR, " accepts: ["); 
        INT_IO.PUT(STANDARD_ERROR, ACC_ARRAY(CNT), 1); 
        TEXT_IO.PUT(STANDARD_ERROR, ']'); 
        TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      end if; 
    end loop; 

    -- add entry for "jam" state
    MISC.MKDATA(ACC_ARRAY(LASTDFA + 1)); 

    MISC.DATAEND; 

    if (USEECS) then 
      GENECS; 
    end if; 

    if (USEMECS) then 

      -- write out meta-equivalence classes (used to index templates with)
      if (TRACE) then 
        TEXT_IO.NEW_LINE(STANDARD_ERROR); 
        TEXT_IO.NEW_LINE(STANDARD_ERROR); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, "Meta-Equivalence Classes:"); 
      end if; 

      TEXT_IO.PUT("yy_meta : constant array(0.."); 
      INT_IO.PUT(NUMECS, 1); 
      TEXT_IO.PUT_LINE(") of short :="); 
      TEXT_IO.PUT_LINE("    (   0,"); 
      for CNT in 1 .. NUMECS loop
        if (TRACE) then 
          INT_IO.PUT(STANDARD_ERROR, CNT, 1); 
          TEXT_IO.PUT(STANDARD_ERROR, " = "); 
          INT_IO.PUT(STANDARD_ERROR, abs(TECBCK(CNT)), 1); 
          TEXT_IO.NEW_LINE(STANDARD_ERROR); 
        end if; 
        MISC.MKDATA(abs(TECBCK(CNT))); 
      end loop; 

      MISC.DATAEND; 
    end if; 

    TOTAL_STATES := LASTDFA + NUMTEMPS; 

    TEXT_IO.PUT("yy_base : constant array(0.."); 
    INT_IO.PUT(TOTAL_STATES, 1); 
    if (TBLEND > MAX_SHORT) then 
      TEXT_IO.PUT_LINE(") of integer :="); 
    else 
      TEXT_IO.PUT_LINE(") of short :="); 
    end if; 
    TEXT_IO.PUT_LINE("    (   0,"); 

    for CNT in 1 .. LASTDFA loop
      declare
        D : INTEGER := DEF(CNT); 
      begin
        if (BASE(CNT) = JAMSTATE_CONST) then 
          BASE(CNT) := JAMBASE; 
        end if; 

        if (D = JAMSTATE_CONST) then 
          DEF(CNT) := JAMSTATE; 
        else 
          if (D < 0) then 

            -- template reference
            TMPUSES := TMPUSES + 1; 
            DEF(CNT) := LASTDFA - D + 1; 
          end if; 
        end if; 
        MISC.MKDATA(BASE(CNT)); 
      end; 
    end loop; 

    -- generate jam state's base index
    I := LASTDFA + 1; 
    MISC.MKDATA(BASE(I)); 

    -- skip jam state
    I := I + 1; 

    for CNT in I .. TOTAL_STATES loop
      MISC.MKDATA(BASE(CNT)); 
      DEF(CNT) := JAMSTATE; 
    end loop; 

    MISC.DATAEND; 

    TEXT_IO.PUT("yy_def : constant array(0.."); 
    INT_IO.PUT(TOTAL_STATES, 1); 
    if (TBLEND > MAX_SHORT) then 
      TEXT_IO.PUT_LINE(") of integer :="); 
    else 
      TEXT_IO.PUT_LINE(") of short :="); 
    end if; 
    TEXT_IO.PUT_LINE("    (   0,"); 

    for CNT in 1 .. TOTAL_STATES loop
      MISC.MKDATA(DEF(CNT)); 
    end loop; 

    MISC.DATAEND; 
    TEXT_IO.PUT("yy_nxt : constant array(0.."); 
    INT_IO.PUT(TBLEND, 1); 
    if (LASTDFA > MAX_SHORT) then 
      TEXT_IO.PUT_LINE(") of integer :="); 
    else 
      TEXT_IO.PUT_LINE(") of short :="); 
    end if; 
    TEXT_IO.PUT_LINE("    (   0,"); 

    for CNT in 1 .. TBLEND loop
      if ((NXT(CNT) = 0) or (CHK(CNT) = 0)) then 
        NXT(CNT) := JAMSTATE; 

      -- new state is the JAM state
      end if; 
      MISC.MKDATA(NXT(CNT)); 
    end loop; 

    MISC.DATAEND; 

    TEXT_IO.PUT("yy_chk : constant array(0.."); 
    INT_IO.PUT(TBLEND, 1); 
    if (LASTDFA > MAX_SHORT) then 
      TEXT_IO.PUT_LINE(") of integer :="); 
    else 
      TEXT_IO.PUT_LINE(") of short :="); 
    end if; 
    TEXT_IO.PUT_LINE("    (   0,"); 

    for CNT in 1 .. TBLEND loop
      if (CHK(CNT) = 0) then 
        NUMMT := NUMMT + 1; 
      end if; 

      MISC.MKDATA(CHK(CNT)); 
    end loop; 

    MISC.DATAEND; 
  exception
    when STORAGE_ERROR => 
      MISC.AFLEXFATAL("dynamic memory failure in gentabs()"); 
  end GENTABS; 

  -- write out a string at the current indentation level, adding a final
  -- newline

  procedure INDENT_PUTS(STR : in STRING) is 
  begin
    DO_INDENT; 
    TEXT_IO.PUT_LINE(STR); 
  end INDENT_PUTS; 

  -- do_sect3_out - dumps section 3.

  procedure DO_SECT3_OUT is 
    GARBAGE : TOKEN; 
  begin
    SCANNER.CALL_YYLEX := TRUE; 
    GARBAGE := SCANNER.GET_TOKEN; 
  end DO_SECT3_OUT; 

  -- make_tables - generate transition tables
  --
  --
  -- Generates transition tables and finishes generating output file

  procedure MAKE_TABLES is 
    DID_EOF_RULE      : BOOLEAN := FALSE; 
    TRANS_OFFSET_TYPE : STRING(1 .. 7); 
    TOTAL_TABLE_SIZE  : INTEGER := TBLEND + NUMECS + 1; 
    BUF               : VSTRING; 
  begin
    if (not FULLTBL) then 

      -- if we used full tables this is already output
      DO_SECT3_OUT; 

      -- intent of this call is to get everything up to ##
      SKELETON_MANAGER.SKELOUT; 

    -- output YYLex code up to part about tables.
    end if; 

    TEXT_IO.PUT("YY_END_OF_BUFFER : constant := "); 
    INT_IO.PUT(NUM_RULES + 1, 1); 
    TEXT_IO.PUT_LINE(";"); 

    INDENT_PUTS("subtype yy_state_type is integer;"); 
    INDENT_PUTS("yy_current_state : yy_state_type;"); 

    -- now output the constants for the various start conditions
    RESET(DEF_FILE, IN_FILE); 

    while (not TEXT_IO.END_OF_FILE(DEF_FILE)) loop
      TSTRING.GET_LINE(DEF_FILE, BUF); 
      TSTRING.PUT_LINE(BUF); 
    end loop; 

    if (FULLTBL) then 
      GENFTBL; 
    else 
      GENTABS; 
    end if; 

    RESET(TEMP_ACTION_FILE, IN_FILE); 

    -- generate code for yy_get_previous_state
    SET_INDENT(1); 
    SKELETON_MANAGER.SKELOUT; 

    if (BOL_NEEDED) then 
      INDENT_PUTS("yy_bp : integer := yytext_ptr;"); 
    end if; 
    SKELETON_MANAGER.SKELOUT; 

    GEN_START_STATE; 
    SKELETON_MANAGER.SKELOUT; 
    GEN_NEXT_STATE; 
    SKELETON_MANAGER.SKELOUT; 

    SET_INDENT(2); 

    INDENT_PUTS("yy_bp := yy_cp;"); 

    GEN_START_STATE; 
    GEN_NEXT_MATCH; 

    SKELETON_MANAGER.SKELOUT; 

    SET_INDENT(3); 
    GEN_FIND_ACTION; 

    SET_INDENT(1); 
    SKELETON_MANAGER.SKELOUT; 

    INDENT_UP; 
    GEN_BT_ACTION; 

    MISC.ACTION_OUT; 
    MISC.ACTION_OUT; 

    -- generate cases for any missing EOF rules
    for I in 1 .. LASTSC loop
      if (not SCEOF(I)) then 
        DO_INDENT; 
        if (not DID_EOF_RULE) then 
          TEXT_IO.PUT("when "); 
        else 
          TEXT_IO.PUT_LINE("|"); 
        end if; 
        TEXT_IO.PUT("YY_END_OF_BUFFER + "); 
        TSTRING.PUT(SCNAME(I)); 
        TEXT_IO.PUT(" + 1 "); 
        DID_EOF_RULE := TRUE; 
      end if; 
    end loop; 
    if (DID_EOF_RULE) then 
      TEXT_IO.PUT_LINE("=> "); 
    end if; 

    if (DID_EOF_RULE) then 
      INDENT_UP; 
      INDENT_PUTS("return End_Of_Input;"); 
      INDENT_DOWN; 
    end if; 

    SKELETON_MANAGER.SKELOUT; 

    -- copy remainder of input to output
    MISC.LINE_DIRECTIVE_OUT; 
    DO_SECT3_OUT; 

  -- copy remainder of input, after ##, to the scanner file.
  end MAKE_TABLES; 

end GEN; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE scanner generation
-- AUTHOR: John Self (UCI)
-- DESCRIPTION
-- NOTES does actual generation (writing) of output aflex scanners
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/genS.a,v 1.4 90/01/12 15:20:07 self Exp Locker: self $ 

with MISC_DEFS; use MISC_DEFS; 
package GEN is 
  procedure DO_INDENT; 
  procedure GEN_BACKTRACKING; 
  procedure GEN_BT_ACTION; 
  procedure GEN_FIND_ACTION; 
  procedure GEN_NEXT_COMPRESSED_STATE; 
  procedure GEN_NEXT_MATCH; 
  procedure GEN_NEXT_STATE; 
  procedure GEN_START_STATE; 
  procedure GENECS; 
  procedure GENFTBL; 
  procedure INDENT_PUTS(STR : in STRING); 
  procedure GENTABS; 
  procedure INDENT_DOWN; 
  procedure INDENT_UP; 
  procedure SET_INDENT(INDENT_VAL : in INTEGER); 
  procedure MAKE_TABLES; 
  procedure DO_SECT3_OUT; 
end GEN; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE integer IO
-- AUTHOR: John Self (UCI)
-- DESCRIPTION instantiation of integer IO generic for integers
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/int_io.a,v 1.3 90/01/12 15:20:09 self Exp Locker: self $ 

with TEXT_IO; 
package INT_IO is 
  new TEXT_IO.INTEGER_IO(INTEGER); 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE main body
-- AUTHOR: John Self (UCI)
-- DESCRIPTION driver routines for aflex.  Calls drivers for all
-- high level routines from other packages.
-- $Header: /dc/uc/self/arcadia/aflex/ada/src/RCS/mainB.a,v 1.24 1991/07/22 18:06:53 self Exp self $ 

with MISC_DEFS, MISC, COMMAND_LINE_INTERFACE, DFA, ECS, GEN, TEXT_IO, PARSER; 
with MAIN_BODY, TSTRING, PARSE_TOKENS, SKELETON_MANAGER, EXTERNAL_FILE_MANAGER; 
with EXTERNAL_FILE_MANAGER, INT_IO; use MISC_DEFS, COMMAND_LINE_INTERFACE, 
  TSTRING, EXTERNAL_FILE_MANAGER; 

package body MAIN_BODY is 
  OUTFILE_CREATED    : BOOLEAN := FALSE; 
  AFLEX_VERSION      : CONSTANT STRING := "1.1d"; 
  STARTTIME, ENDTIME : VSTRING; 

  -- aflexend - terminate aflex
  --
  -- note
  --    This routine does not return.

  procedure AFLEXEND(STATUS : in INTEGER) is 
    use TEXT_IO; 
    TBLSIZ : INTEGER; 
  begin
    TERMINATION_STATUS := STATUS; 

    -- we'll return this value of the OS.
    if (IS_OPEN(SKELFILE)) then 
      CLOSE(SKELFILE); 
    end if; 

    if (IS_OPEN(TEMP_ACTION_FILE)) then 
      DELETE(TEMP_ACTION_FILE); 
    end if; 

    if (IS_OPEN(DEF_FILE)) then 
      DELETE(DEF_FILE); 
    end if; 

    if (BACKTRACK_REPORT) then 
      if (NUM_BACKTRACKING = 0) then 
        TEXT_IO.PUT_LINE(BACKTRACK_FILE, "No backtracking."); 
      else 
        if (FULLTBL) then 
          INT_IO.PUT(BACKTRACK_FILE, NUM_BACKTRACKING, 0); 
          TEXT_IO.PUT_LINE(BACKTRACK_FILE, 
            " backtracking (non-accepting) states."); 
        else 
          TEXT_IO.PUT_LINE(BACKTRACK_FILE, "Compressed tables always backtrack."
            ); 
        end if; 
      end if; 

      CLOSE(BACKTRACK_FILE); 
    end if; 

    if (PRINTSTATS) then 
      ENDTIME := MISC.AFLEX_GETTIME; 

      TEXT_IO.PUT_LINE(STANDARD_ERROR, "aflex version " & AFLEX_VERSION & 
        " usage statistics:"); 

      TSTRING.PUT_LINE(STANDARD_ERROR, "  started at " & STARTTIME & 
        ", finished at " & ENDTIME); 
      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, LASTNFA, 0); 
      TEXT_IO.PUT(STANDARD_ERROR, '/'); 
      INT_IO.PUT(STANDARD_ERROR, CURRENT_MNS, 0); 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, "  NFA states"); 

      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, LASTDFA, 0); 
      TEXT_IO.PUT(STANDARD_ERROR, '/'); 
      INT_IO.PUT(STANDARD_ERROR, CURRENT_MAX_DFAS, 0); 
      TEXT_IO.PUT(STANDARD_ERROR, " DFA states ("); 
      INT_IO.PUT(STANDARD_ERROR, TOTNST, 0); 
      TEXT_IO.PUT(STANDARD_ERROR, "  words)"); 

      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, NUM_RULES - 1, 0); 

      -- - 1 for def. rule
      TEXT_IO.PUT_LINE(STANDARD_ERROR, "  rules"); 

      if (NUM_BACKTRACKING = 0) then 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, "  No backtracking"); 
      else 
        if (FULLTBL) then 
          TEXT_IO.PUT(STANDARD_ERROR, "  "); 
          INT_IO.PUT(STANDARD_ERROR, NUM_BACKTRACKING, 0); 
          TEXT_IO.PUT_LINE(STANDARD_ERROR, 
            "  backtracking (non-accepting) states"); 
        else 
          TEXT_IO.PUT_LINE(STANDARD_ERROR, " compressed tables always backtrack"
            ); 
        end if; 
      end if; 

      if (BOL_NEEDED) then 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, "  Beginning-of-line patterns used"); 
      end if; 

      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, LASTSC, 0); 
      TEXT_IO.PUT(STANDARD_ERROR, '/'); 
      INT_IO.PUT(STANDARD_ERROR, CURRENT_MAX_SCS, 0); 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, " start conditions"); 

      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, NUMEPS, 0); 
      TEXT_IO.PUT(STANDARD_ERROR, " epsilon states, "); 
      INT_IO.PUT(STANDARD_ERROR, EPS2, 0); 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, "  double epsilon states"); 

      if (LASTCCL = 0) then 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, "  no character classes"); 
      else 
        TEXT_IO.PUT(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, LASTCCL, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, '/'); 
        INT_IO.PUT(STANDARD_ERROR, CURRENT_MAXCCLS, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, " character classes needed "); 
        INT_IO.PUT(STANDARD_ERROR, CCLMAP(LASTCCL) + CCLLEN(LASTCCL), 0); 
        TEXT_IO.PUT(STANDARD_ERROR, '/'); 
        INT_IO.PUT(STANDARD_ERROR, CURRENT_MAX_CCL_TBL_SIZE, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, " words of storage, "); 
        INT_IO.PUT(STANDARD_ERROR, CCLREUSE, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, "reused"); 
      end if; 

      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, NUMSNPAIRS, 0); 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, " state/nextstate pairs created"); 

      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, NUMUNIQ, 0); 
      TEXT_IO.PUT(STANDARD_ERROR, '/'); 
      INT_IO.PUT(STANDARD_ERROR, NUMDUP, 0); 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, " unique/duplicate transitions"); 

      if (FULLTBL) then 
        TBLSIZ := LASTDFA*NUMECS; 
        TEXT_IO.PUT(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, TBLSIZ, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, " table entries"); 
      else 
        TBLSIZ := 2*(LASTDFA + NUMTEMPS) + 2*TBLEND; 

        TEXT_IO.PUT(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, LASTDFA + NUMTEMPS, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, '/'); 
        INT_IO.PUT(STANDARD_ERROR, CURRENT_MAX_DFAS, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, " base-def entries created"); 

        TEXT_IO.PUT(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, TBLEND, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, '/'); 
        INT_IO.PUT(STANDARD_ERROR, CURRENT_MAX_XPAIRS, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, " (peak "); 
        INT_IO.PUT(STANDARD_ERROR, PEAKPAIRS, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, ") nxt-chk entries created"); 

        TEXT_IO.PUT(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, NUMTEMPS*NUMMECS, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, '/'); 
        INT_IO.PUT(STANDARD_ERROR, CURRENT_MAX_TEMPLATE_XPAIRS, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, " (peak "); 
        INT_IO.PUT(STANDARD_ERROR, NUMTEMPS*NUMECS, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, ") template nxt-chk entries created"); 

        TEXT_IO.PUT(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, NUMMT, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, " empty table entries"); 
        TEXT_IO.PUT(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, NUMPROTS, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, " protos created"); 
        TEXT_IO.PUT(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, NUMTEMPS, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, " templates created, "); 
        INT_IO.PUT(STANDARD_ERROR, TMPUSES, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, "uses"); 
      end if; 

      if (USEECS) then 
        TBLSIZ := TBLSIZ + CSIZE; 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, NUMECS, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, '/'); 
        INT_IO.PUT(STANDARD_ERROR, CSIZE, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, " equivalence classes created"); 
      end if; 

      if (USEMECS) then 
        TBLSIZ := TBLSIZ + NUMECS; 
        TEXT_IO.PUT(STANDARD_ERROR, "  "); 
        INT_IO.PUT(STANDARD_ERROR, NUMMECS, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, '/'); 
        INT_IO.PUT(STANDARD_ERROR, CSIZE, 0); 
        TEXT_IO.PUT_LINE(STANDARD_ERROR, " meta-equivalence classes created"); 
      end if; 

      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, HSHCOL, 0); 
      TEXT_IO.PUT(STANDARD_ERROR, " ("); 
      INT_IO.PUT(STANDARD_ERROR, HSHSAVE, 0); 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, " saved) hash collisions, "); 
      INT_IO.PUT(STANDARD_ERROR, DFAEQL, 0); 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, " DFAs equal"); 

      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, NUM_REALLOCS, 0); 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, " sets of reallocations needed"); 
      TEXT_IO.PUT(STANDARD_ERROR, "  "); 
      INT_IO.PUT(STANDARD_ERROR, TBLSIZ, 0); 
      TEXT_IO.PUT_LINE(STANDARD_ERROR, " total table entries needed"); 
    end if; 

    if (STATUS /= 0) then 
      raise AFLEX_TERMINATE; 
    end if; 
  end AFLEXEND; 

  -- aflexinit - initialize aflex

  procedure AFLEXINIT is 
    use TEXT_IO, TSTRING; 
    SAWCMPFLAG, USE_STDOUT : BOOLEAN; 
    OUTPUT_FILE            : FILE_TYPE; 
    INPUT_FILE             : FILE_TYPE; 
    I                      : INTEGER; 
    ARG_CNT                : INTEGER; 
    FLAG_POS               : INTEGER; 
    ARG                    : VSTRING; 
    SKELNAME               : VSTRING; 
    SKELNAME_USED          : BOOLEAN := FALSE; 
  begin
    PRINTSTATS := FALSE; 
    SYNTAXERROR := FALSE; 
    TRACE := FALSE; 
    SPPRDFLT := FALSE; 
    INTERACTIVE := FALSE; 
    CASEINS := FALSE; 
    BACKTRACK_REPORT := FALSE; 
    PERFORMANCE_REPORT := FALSE; 
    DDEBUG := FALSE; 
    FULLTBL := FALSE; 
    CONTINUED_ACTION := FALSE; 
    GEN_LINE_DIRS := TRUE; 
    USEMECS := TRUE; 
    USEECS := TRUE; 

    SAWCMPFLAG := FALSE; 
    USE_STDOUT := FALSE; 

    -- read flags
    COMMAND_LINE_INTERFACE.INITIALIZE_COMMAND_LINE; 

    -- load up argv
    EXTERNAL_FILE_MANAGER.INITIALIZE_FILES; 

    -- do external files setup

    -- loop through the list of arguments
    ARG_CNT := 1; 
    while (ARG_CNT <= ARGC - 1) loop
      if ((CHAR(ARGV(ARG_CNT), 1) /= '-') or (LEN(ARGV(ARG_CNT)) < 2)) then 
        exit; 
      end if; 

      -- loop through the flags in this argument.
      ARG := ARGV(ARG_CNT); 
      FLAG_POS := 2; 
      while (FLAG_POS <= LEN(ARG)) loop
        case CHAR(ARG, FLAG_POS) is 
          when 'b' => 
            BACKTRACK_REPORT := TRUE; 
          when 'd' => 
            DDEBUG := TRUE; 
          when 'f' => 
            USEECS := FALSE; 
            USEMECS := FALSE; 
            FULLTBL := TRUE; 
          when 'I' => 
            INTERACTIVE := TRUE; 
          when 'i' => 
            CASEINS := TRUE; 
          when 'L' => 
            GEN_LINE_DIRS := FALSE; 
          when 'p' => 
            PERFORMANCE_REPORT := TRUE; 
          when 'S' => 
            if (FLAG_POS /= 2) then 
              MISC.AFLEXERROR("-S flag must be given separately"); 
            end if; 
            SKELNAME := SLICE(ARG, FLAG_POS + 1, LEN(ARG)); 
            SKELNAME_USED := TRUE; 
            goto GET_NEXT_ARG; 
          when 's' => 
            SPPRDFLT := TRUE; 
          when 't' => 
            USE_STDOUT := TRUE; 
          when 'T' => 
            TRACE := TRUE; 
          when 'v' => 
            PRINTSTATS := TRUE; 
          when others => 
            MISC.AFLEXERROR("unknown flag " & CHAR(ARG, FLAG_POS)); 
        end case; 
        FLAG_POS := FLAG_POS + 1; 
      end loop; 
      <<GET_NEXT_ARG>> ARG_CNT := ARG_CNT + 1; 

    -- go on to next argument from list.
    end loop; 

    if (FULLTBL and USEMECS) then 
      MISC.AFLEXERROR("full table and -cm don't make sense together"); 
    end if; 

    if (FULLTBL and INTERACTIVE) then 
      MISC.AFLEXERROR("full table and -I are (currently) incompatible"); 
    end if; 

    if (ARG_CNT < ARGC) then 
      begin
        if (ARG_CNT - ARGC > 1) then 
          MISC.AFLEXERROR("extraneous argument(s) given"); 
        end if; 

        -- Tell aflex where to read input from.
        INFILENAME := ARGV(ARG_CNT); 
        OPEN(INPUT_FILE, IN_FILE, STR(ARGV(ARG_CNT))); 
        SET_INPUT(INPUT_FILE); 
      exception
        when NAME_ERROR => 
          MISC.AFLEXFATAL("can't open " & INFILENAME); 
      end; 
    end if; 

    if (not USE_STDOUT) then 
      EXTERNAL_FILE_MANAGER.GET_SCANNER_FILE(OUTPUT_FILE); 
      OUTFILE_CREATED := TRUE; 
    end if; 

    if (BACKTRACK_REPORT) then 
      EXTERNAL_FILE_MANAGER.GET_BACKTRACK_FILE(BACKTRACK_FILE); 
    end if; 

    LASTCCL := 0; 
    LASTSC := 0; 


    --initialize the statistics
    STARTTIME := MISC.AFLEX_GETTIME; 

    begin

      -- open the skeleton file
      if (SKELNAME_USED) then 
        OPEN(SKELFILE, IN_FILE, STR(SKELNAME)); 
        SKELETON_MANAGER.SET_EXTERNAL_SKELETON; 
      end if; 
    exception
      when USE_ERROR | NAME_ERROR => 
        MISC.AFLEXFATAL("couldn't open skeleton file " & SKELNAME); 
    end; 

    -- without a third argument create make an anonymous temp file.
    begin
      CREATE(TEMP_ACTION_FILE, OUT_FILE); 
      CREATE(DEF_FILE, OUT_FILE); 
    exception
      when USE_ERROR | NAME_ERROR => 
        MISC.AFLEXFATAL("can't create temporary file"); 
    end; 

    LASTDFA := 0; 
    LASTNFA := 0; 
    NUM_RULES := 0; 
    NUMAS := 0; 
    NUMSNPAIRS := 0; 
    TMPUSES := 0; 
    NUMECS := 0; 
    NUMEPS := 0; 
    EPS2 := 0; 
    NUM_REALLOCS := 0; 
    HSHCOL := 0; 
    DFAEQL := 0; 
    TOTNST := 0; 
    NUMUNIQ := 0; 
    NUMDUP := 0; 
    HSHSAVE := 0; 
    EOFSEEN := FALSE; 
    DATAPOS := 0; 
    DATALINE := 0; 
    NUM_BACKTRACKING := 0; 
    ONESP := 0; 
    NUMPROTS := 0; 
    VARIABLE_TRAILING_CONTEXT_RULES := FALSE; 
    BOL_NEEDED := FALSE; 

    LINENUM := 1; 
    SECTNUM := 1; 
    FIRSTPROT := NIL; 

    -- used in mkprot() so that the first proto goes in slot 1
    -- of the proto queue

    LASTPROT := 1; 

    if (USEECS) then 
    -- set up doubly-linked equivalence classes
      ECGROUP(1) := NIL; 

      for CNT in 2 .. CSIZE loop
        ECGROUP(CNT) := CNT - 1; 
        NEXTECM(CNT - 1) := CNT; 
      end loop; 

      NEXTECM(CSIZE) := NIL; 
    else 
    -- put everything in its own equivalence class
      for CNT in 1 .. CSIZE loop
        ECGROUP(CNT) := CNT; 
        NEXTECM(CNT) := BAD_SUBSCRIPT;  -- to catch errors
      end loop; 
    end if; 

    SET_UP_INITIAL_ALLOCATIONS; 


  end AFLEXINIT; 

  -- readin - read in the rules section of the input file(s)
  procedure READIN is 
  begin
    SKELETON_MANAGER.SKELOUT; 
    TEXT_IO.PUT("with " & TSTRING.STR(MISC.BASENAME) & "_dfa" & "; "); 
    TEXT_IO.PUT_LINE("use " & TSTRING.STR(MISC.BASENAME) & "_dfa" & "; "); 
    TEXT_IO.PUT("with " & TSTRING.STR(MISC.BASENAME) & "_io" & "; "); 
    TEXT_IO.PUT_LINE("use " & TSTRING.STR(MISC.BASENAME) & "_io" & "; "); 
    MISC.LINE_DIRECTIVE_OUT; 

    PARSER.YYPARSE; 

    if (USEECS) then 
      ECS.CRE8ECS(NEXTECM, ECGROUP, CSIZE, NUMECS); 
      ECS.CCL2ECL; 
    else 
      NUMECS := CSIZE; 
    end if; 
  exception
    when PARSE_TOKENS.SYNTAX_ERROR => 
      MISC.AFLEXERROR("fatal parse error at line " & INTEGER'IMAGE(LINENUM)); 
      MAIN_BODY.AFLEXEND(1); 
  end READIN; 

  -- set_up_initial_allocations - allocate memory for internal tables
  procedure SET_UP_INITIAL_ALLOCATIONS is 
  begin
    CURRENT_MNS := INITIAL_MNS; 
    FIRSTST := ALLOCATE_INTEGER_ARRAY(CURRENT_MNS); 
    LASTST := ALLOCATE_INTEGER_ARRAY(CURRENT_MNS); 
    FINALST := ALLOCATE_INTEGER_ARRAY(CURRENT_MNS); 
    TRANSCHAR := ALLOCATE_INTEGER_ARRAY(CURRENT_MNS); 
    TRANS1 := ALLOCATE_INTEGER_ARRAY(CURRENT_MNS); 
    TRANS2 := ALLOCATE_INTEGER_ARRAY(CURRENT_MNS); 
    ACCPTNUM := ALLOCATE_INTEGER_ARRAY(CURRENT_MNS); 
    ASSOC_RULE := ALLOCATE_INTEGER_ARRAY(CURRENT_MNS); 
    STATE_TYPE := ALLOCATE_STATE_ENUM_ARRAY(CURRENT_MNS); 

    CURRENT_MAX_RULES := INITIAL_MAX_RULES; 
    RULE_TYPE := ALLOCATE_RULE_ENUM_ARRAY(CURRENT_MAX_RULES); 
    RULE_LINENUM := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_RULES); 

    CURRENT_MAX_SCS := INITIAL_MAX_SCS; 
    SCSET := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_SCS); 
    SCBOL := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_SCS); 
    SCXCLU := ALLOCATE_BOOLEAN_ARRAY(CURRENT_MAX_SCS); 
    SCEOF := ALLOCATE_BOOLEAN_ARRAY(CURRENT_MAX_SCS); 
    SCNAME := ALLOCATE_VSTRING_ARRAY(CURRENT_MAX_SCS); 
    ACTVSC := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_SCS); 

    CURRENT_MAXCCLS := INITIAL_MAX_CCLS; 
    CCLMAP := ALLOCATE_INTEGER_ARRAY(CURRENT_MAXCCLS); 
    CCLLEN := ALLOCATE_INTEGER_ARRAY(CURRENT_MAXCCLS); 
    CCLNG := ALLOCATE_INTEGER_ARRAY(CURRENT_MAXCCLS); 

    CURRENT_MAX_CCL_TBL_SIZE := INITIAL_MAX_CCL_TBL_SIZE; 
    CCLTBL := ALLOCATE_CHARACTER_ARRAY(CURRENT_MAX_CCL_TBL_SIZE); 

    CURRENT_MAX_DFA_SIZE := INITIAL_MAX_DFA_SIZE; 

    CURRENT_MAX_XPAIRS := INITIAL_MAX_XPAIRS; 
    NXT := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_XPAIRS); 
    CHK := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_XPAIRS); 

    CURRENT_MAX_TEMPLATE_XPAIRS := INITIAL_MAX_TEMPLATE_XPAIRS; 
    TNXT := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_TEMPLATE_XPAIRS); 

    CURRENT_MAX_DFAS := INITIAL_MAX_DFAS; 
    BASE := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFAS); 
    DEF := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFAS); 
    DFASIZ := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFAS); 
    ACCSIZ := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFAS); 
    DHASH := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFAS); 
    DSS := ALLOCATE_INT_PTR_ARRAY(CURRENT_MAX_DFAS); 
    DFAACC := ALLOCATE_DFAACC_UNION(CURRENT_MAX_DFAS); 
  end SET_UP_INITIAL_ALLOCATIONS; 
end MAIN_BODY; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE main body
-- AUTHOR: John Self (UCI)
-- DESCRIPTION driver routines for aflex.  Calls drivers for all
-- high level routines from other packages.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/mainS.a,v 1.5 90/01/12 15:20:14 self Exp Locker: self $ 

-- aflex - tool to generate fast lexical analyzers
package MAIN_BODY is 
  procedure AFLEXEND(STATUS : in INTEGER); 
  procedure AFLEXINIT; 
  procedure READIN; 
  procedure SET_UP_INITIAL_ALLOCATIONS; 
  AFLEX_TERMINATE    : exception; 
  TERMINATION_STATUS : INTEGER; 
end MAIN_BODY; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE  miscellaneous aflex routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION
-- NOTES contains functions used in various places throughout aflex.
-- $Header: /dc/uc/self/arcadia/aflex/ada/src/RCS/miscB.a,v 1.22 1991/07/01 21:30:37 self Exp self $ 

with MISC_DEFS, TSTRING, TEXT_IO, MISC, MAIN_BODY; 
with INT_IO, CALENDAR, EXTERNAL_FILE_MANAGER; use MISC, MISC_DEFS, TEXT_IO, 
  EXTERNAL_FILE_MANAGER; 

package body MISC is 
  use TSTRING; 
  -- action_out - write the actions from the temporary file to lex.yy.c

  procedure ACTION_OUT is 
    BUF : VSTRING; 
  begin
    while (not TEXT_IO.END_OF_FILE(TEMP_ACTION_FILE)) loop
      TSTRING.GET_LINE(TEMP_ACTION_FILE, BUF); 
      if ((TSTRING.LEN(BUF) >= 2) and then ((CHAR(BUF, 1) = '%') and (CHAR(BUF, 
        2) = '%'))) then 
        exit; 
      else 
        TSTRING.PUT_LINE(BUF); 
      end if; 
    end loop; 
  end ACTION_OUT; 

  -- bubble - bubble sort an integer array in increasing order
  --
  -- description
  --   sorts the first n elements of array v and replaces them in
  --   increasing order.
  --
  -- passed
  --   v - the array to be sorted
  --   n - the number of elements of 'v' to be sorted

  procedure BUBBLE(V : in INT_PTR; 
                   N : in INTEGER) is 
    K : INTEGER; 
  begin
    for I in reverse 2 .. N loop
      for J in 1 .. I - 1 loop
        if (V(J) > V(J + 1)) then 

          -- compare
          K := V(J); 

          -- exchange
          V(J) := V(J + 1); 
          V(J + 1) := K; 
        end if; 
      end loop; 
    end loop; 
  end BUBBLE; 


  -- clower - replace upper-case letter to lower-case

  function CLOWER(C : in INTEGER) return INTEGER is 
  begin
    if (ISUPPER(CHARACTER'VAL(C))) then 
      return TOLOWER(C); 
    else 
      return C; 
    end if; 
  end CLOWER; 


  -- cshell - shell sort a character array in increasing order
  --
  -- description
  --   does a shell sort of the first n elements of array v.
  --
  -- passed
  --   v - array to be sorted
  --   n - number of elements of v to be sorted

  procedure CSHELL(V : in out CHAR_ARRAY; 
                   N : in INTEGER) is 
    GAP, J, JG  : INTEGER; 
    K           : CHARACTER; 
    LOWER_BOUND : INTEGER := V'FIRST; 
  begin
    GAP := N/2; 
    while GAP > 0 loop
      for I in GAP .. N - 1 loop
        J := I - GAP; 
        while (J >= 0) loop
          JG := J + GAP; 

          if (V(J + LOWER_BOUND) <= V(JG + LOWER_BOUND)) then 
            exit; 
          end if; 

          K := V(J + LOWER_BOUND); 
          V(J + LOWER_BOUND) := V(JG + LOWER_BOUND); 
          V(JG + LOWER_BOUND) := K; 
          J := J - GAP; 
        end loop; 
      end loop; 
      GAP := GAP/2; 
    end loop; 
  end CSHELL; 


  -- dataend - finish up a block of data declarations

  procedure DATAEND is 
  begin
    if (DATAPOS > 0) then 
      DATAFLUSH; 

      -- add terminator for initialization
      TEXT_IO.PUT_LINE("    ) ;"); 
      TEXT_IO.NEW_LINE; 

      DATALINE := 0; 
    end if; 
  end DATAEND; 


  -- dataflush - flush generated data statements

  procedure DATAFLUSH(FILE : in FILE_TYPE) is 
  begin
    TEXT_IO.NEW_LINE(FILE); 
    DATALINE := DATALINE + 1; 
    if (DATALINE >= NUMDATALINES) then 

      -- put out a blank line so that the table is grouped into
      -- large blocks that enable the user to find elements easily
      TEXT_IO.NEW_LINE(FILE); 
      DATALINE := 0; 
    end if; 

    -- reset the number of characters written on the current line
    DATAPOS := 0; 
  end DATAFLUSH; 

  procedure DATAFLUSH is 
  begin
    DATAFLUSH(CURRENT_OUTPUT); 
  end DATAFLUSH; 
  -- aflex_gettime - return current time

  function AFLEX_GETTIME return VSTRING is 
    use TSTRING, CALENDAR; 
    CURRENT_TIME                                            : TIME; 
    CURRENT_YEAR                                            : YEAR_NUMBER; 
    CURRENT_MONTH                                           : MONTH_NUMBER; 
    CURRENT_DAY                                             : DAY_NUMBER; 
    CURRENT_SECONDS                                         : DAY_DURATION; 
    MONTH_STRING, HOUR_STRING, MINUTE_STRING, SECOND_STRING : VSTRING; 
    HOUR, MINUTE, SECOND                                    : INTEGER; 
    SECONDS_PER_HOUR                                        : constant 
      DAY_DURATION := 3600.0; 
  begin
    CURRENT_TIME := CLOCK; 
    SPLIT(CURRENT_TIME, CURRENT_YEAR, CURRENT_MONTH, CURRENT_DAY, 
      CURRENT_SECONDS); 
    case CURRENT_MONTH is 
      when 1 => 
        MONTH_STRING := VSTR("Jan"); 
      when 2 => 
        MONTH_STRING := VSTR("Feb"); 
      when 3 => 
        MONTH_STRING := VSTR("Mar"); 
      when 4 => 
        MONTH_STRING := VSTR("Apr"); 
      when 5 => 
        MONTH_STRING := VSTR("May"); 
      when 6 => 
        MONTH_STRING := VSTR("Jun"); 
      when 7 => 
        MONTH_STRING := VSTR("Jul"); 
      when 8 => 
        MONTH_STRING := VSTR("Aug"); 
      when 9 => 
        MONTH_STRING := VSTR("Sep"); 
      when 10 => 
        MONTH_STRING := VSTR("Oct"); 
      when 11 => 
        MONTH_STRING := VSTR("Nov"); 
      when 12 => 
        MONTH_STRING := VSTR("Dec"); 
    end case; 

    HOUR := INTEGER(CURRENT_SECONDS)/INTEGER(SECONDS_PER_HOUR);
    MINUTE := INTEGER((CURRENT_SECONDS - (HOUR*SECONDS_PER_HOUR))/60); 
    SECOND := INTEGER(CURRENT_SECONDS - HOUR*SECONDS_PER_HOUR - MINUTE*60.0); 

    if (HOUR >= 10) then 
      HOUR_STRING := VSTR(INTEGER'IMAGE(HOUR)); 
    else 
      HOUR_STRING := VSTR("0" & INTEGER'IMAGE(HOUR)); 
    end if; 

    if (MINUTE >= 10) then 
      MINUTE_STRING := VSTR(INTEGER'IMAGE(MINUTE)(2 .. INTEGER'IMAGE(MINUTE)'
        LENGTH)); 
    else 
      MINUTE_STRING := VSTR("0" & INTEGER'IMAGE(MINUTE)(2 .. INTEGER'IMAGE(
        MINUTE)'LENGTH)); 
    end if; 

    if (SECOND >= 10) then 
      SECOND_STRING := VSTR(INTEGER'IMAGE(SECOND)(2 .. INTEGER'IMAGE(SECOND)'
        LENGTH)); 
    else 
      SECOND_STRING := VSTR("0" & INTEGER'IMAGE(SECOND)(2 .. INTEGER'IMAGE(
        SECOND)'LENGTH)); 
    end if; 

    return MONTH_STRING & VSTR(INTEGER'IMAGE(CURRENT_DAY)) & HOUR_STRING & ":"
      & MINUTE_STRING & ":" & SECOND_STRING & INTEGER'IMAGE(CURRENT_YEAR); 
  end AFLEX_GETTIME; 

  -- aflexerror - report an error message and terminate
  -- overloaded function, one for vstring, one for string.
  procedure AFLEXERROR(MSG : in VSTRING) is 
    use TEXT_IO; 
  begin
    TSTRING.PUT(STANDARD_ERROR, "aflex: " & MSG); 
    TEXT_IO.NEW_LINE(STANDARD_ERROR); 
    MAIN_BODY.AFLEXEND(1); 
  end AFLEXERROR; 

  procedure AFLEXERROR(MSG : in STRING) is 
    use TEXT_IO; 
  begin
    TEXT_IO.PUT(STANDARD_ERROR, "aflex: " & MSG); 
    TEXT_IO.NEW_LINE(STANDARD_ERROR); 
    MAIN_BODY.AFLEXEND(1); 
  end AFLEXERROR; 

  -- aflexfatal - report a fatal error message and terminate
  -- overloaded function, one for vstring, one for string.
  procedure AFLEXFATAL(MSG : in VSTRING) is 
    use TEXT_IO; 
  begin
    TSTRING.PUT(STANDARD_ERROR, "aflex: fatal internal error " & MSG); 
    TEXT_IO.NEW_LINE(STANDARD_ERROR); 
    MAIN_BODY.AFLEXEND(1); 
  end AFLEXFATAL; 

  procedure AFLEXFATAL(MSG : in STRING) is 
    use TEXT_IO; 
  begin
    TEXT_IO.PUT(STANDARD_ERROR, "aflex: fatal internal error " & MSG); 
    TEXT_IO.NEW_LINE(STANDARD_ERROR); 
    MAIN_BODY.AFLEXEND(1); 
  end AFLEXFATAL; 

  -- basename - find the basename of a file
  function BASENAME return VSTRING is 
    END_CHAR_POS : INTEGER := LEN(INFILENAME);
    START_CHAR_POS : INTEGER;
  begin
    if (END_CHAR_POS = 0) then 
      -- if reading standard input give everything this name
      return VSTR("aflex_yy"); 
    end if; 
    
    -- find out where the end of the basename is    
    while ((END_CHAR_POS >= 1) and then
           (CHAR(INFILENAME, END_CHAR_POS) /= '.')) loop
      END_CHAR_POS := END_CHAR_POS - 1; 
    end loop; 

    -- find out where the beginning of the basename is    
    START_CHAR_POS := END_CHAR_POS; -- start at the end of the basename
    while ((START_CHAR_POS > 1) and then
           (CHAR(INFILENAME, START_CHAR_POS) /= '/')) loop
    	START_CHAR_POS := START_CHAR_POS - 1; 
    end loop; 

    if (CHAR(INFILENAME, START_CHAR_POS) = '/') then
    	START_CHAR_POS := START_CHAR_POS + 1;
    end if;
    
    if (END_CHAR_POS >= 1) then 
      return SLICE(INFILENAME, START_CHAR_POS,  END_CHAR_POS - 1); 
    else 
      return INFILENAME; 
    end if; 
  end BASENAME; 

  -- line_directive_out - spit out a "# line" statement

  procedure LINE_DIRECTIVE_OUT(OUTPUT_FILE_NAME : in FILE_TYPE) is 
  begin
    if (GEN_LINE_DIRS) then 
      TEXT_IO.PUT(OUTPUT_FILE_NAME, "--# line "); 
      INT_IO.PUT(OUTPUT_FILE_NAME, LINENUM, 1); 
      TEXT_IO.PUT(OUTPUT_FILE_NAME, " """); 
      TSTRING.PUT(OUTPUT_FILE_NAME, INFILENAME); 
      TEXT_IO.PUT_LINE(OUTPUT_FILE_NAME, """"); 
    end if; 
  end LINE_DIRECTIVE_OUT; 


  procedure LINE_DIRECTIVE_OUT is 
  begin
    if (GEN_LINE_DIRS) then 
      TEXT_IO.PUT("--# line "); 
      INT_IO.PUT(LINENUM, 1); 
      TEXT_IO.PUT(" """); 
      TSTRING.PUT(INFILENAME); 
      TEXT_IO.PUT_LINE(""""); 
    end if; 
  end LINE_DIRECTIVE_OUT; 

  -- all_upper - returns true if a string is all upper-case
  function ALL_UPPER(STR : in VSTRING) return BOOLEAN is 
  begin
    for I in 1 .. LEN(STR) loop
      if (not ((CHAR(STR, I) >= 'A') and (CHAR(STR, I) <= 'Z'))) then 
        return FALSE; 
      end if; 
    end loop; 
    return TRUE; 
  end ALL_UPPER; 

  -- all_lower - returns true if a string is all lower-case
  function ALL_LOWER(STR : in VSTRING) return BOOLEAN is 
  begin
    for I in 1 .. LEN(STR) loop
      if (not ((CHAR(STR, I) >= 'a') and (CHAR(STR, I) <= 'z'))) then 
        return FALSE; 
      end if; 
    end loop; 
    return TRUE; 
  end ALL_LOWER; 

  -- mk2data - generate a data statement for a two-dimensional array
  --
  --  generates a data statement initializing the current 2-D array to "value"

  procedure MK2DATA(FILE  : in FILE_TYPE; 
                    VALUE : in INTEGER) is 
  begin

    if (DATAPOS >= NUMDATAITEMS) then 
      TEXT_IO.PUT(FILE, ','); 
      DATAFLUSH(FILE); 
    end if; 

    if (DATAPOS = 0) then 

      -- indent
      TEXT_IO.PUT(FILE, "    "); 
    else 
      TEXT_IO.PUT(FILE, ','); 
    end if; 

    DATAPOS := DATAPOS + 1; 

    INT_IO.PUT(FILE, VALUE, 5); 
  end MK2DATA; 

  procedure MK2DATA(VALUE : in INTEGER) is 
  begin
    MK2DATA(CURRENT_OUTPUT, VALUE); 
  end MK2DATA; 

  --
  --  generates a data statement initializing the current array element to
  --  "value"

  procedure MKDATA(VALUE : in INTEGER) is 
  begin
    if (DATAPOS >= NUMDATAITEMS) then 
      TEXT_IO.PUT(','); 
      DATAFLUSH; 
    end if; 

    if (DATAPOS = 0) then 

      -- indent
      TEXT_IO.PUT("    "); 
    else 
      TEXT_IO.PUT(','); 
    end if; 

    DATAPOS := DATAPOS + 1; 

    INT_IO.PUT(VALUE, 5); 
  end MKDATA; 


  -- myctoi - return the integer represented by a string of digits

  function MYCTOI(NUM_ARRAY : in VSTRING) return INTEGER is 
    TOTAL : INTEGER := 0; 
    CNT   : INTEGER := TSTRING.FIRST; 
  begin
    while (CNT <= TSTRING.LEN(NUM_ARRAY)) loop
      TOTAL := TOTAL*10; 
      TOTAL := TOTAL + CHARACTER'POS(CHAR(NUM_ARRAY, CNT)) - CHARACTER'POS('0')
        ; 
      CNT := CNT + 1; 
    end loop; 
    return TOTAL; 
  end MYCTOI; 


  -- myesc - return character corresponding to escape sequence

  function MYESC(ARR : in VSTRING) return CHARACTER is 
    use TEXT_IO; 
  begin
    case (CHAR(ARR, TSTRING.FIRST + 1)) is 
      when 'a' => 
        return ASCII.BEL; 
      when 'b' => 
        return ASCII.BS; 
      when 'f' => 
        return ASCII.FF; 
      when 'n' => 
        return ASCII.LF; 
      when 'r' => 
        return ASCII.CR; 
      when 't' => 
        return ASCII.HT; 
      when 'v' => 
        return ASCII.VT; 

      when '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => 

        -- \<octal>
        declare
          C, ESC_CHAR : CHARACTER; 
          SPTR        : INTEGER := TSTRING.FIRST + 1; 
        begin
          ESC_CHAR := OTOI(TSTRING.SLICE(ARR, TSTRING.FIRST + 1, TSTRING.LEN(ARR
            ))); 
          if (ESC_CHAR = ASCII.NUL) then 
            MISC.SYNERR("escape sequence for null not allowed"); 
            return ASCII.SOH; 
          end if; 

          return ESC_CHAR; 
        end; 
      when others => 
        return CHAR(ARR, TSTRING.FIRST + 1); 
    end case; 
  end MYESC; 


  -- otoi - convert an octal digit string to an integer value

  function OTOI(STR : in VSTRING) return CHARACTER is 
    TOTAL : INTEGER := 0; 
    CNT   : INTEGER := TSTRING.FIRST; 
  begin
    while (CNT <= TSTRING.LEN(STR)) loop
      TOTAL := TOTAL*8; 
      TOTAL := TOTAL + CHARACTER'POS(CHAR(STR, CNT)) - CHARACTER'POS('0'); 
      CNT := CNT + 1; 
    end loop; 
    return CHARACTER'VAL(TOTAL); 
  end OTOI; 


  -- readable_form - return the the human-readable form of a character
  --
  -- The returned string is in static storage.

  function READABLE_FORM(C : in CHARACTER) return VSTRING is 
  begin
    if ((CHARACTER'POS(C) >= 0 and CHARACTER'POS(C) < 32) or (C = ASCII.DEL))
      then 
      case C is 
        when ASCII.LF => 
          return (VSTR("\n")); 

        -- Newline
        when ASCII.HT => 
          return (VSTR("\t")); 

        -- Horizontal Tab
        when ASCII.FF => 
          return (VSTR("\f")); 

        -- Form Feed
        when ASCII.CR => 
          return (VSTR("\r")); 

        -- Carriage Return
        when ASCII.BS => 
          return (VSTR("\b")); 

        -- Backspace
        when others => 
          return VSTR("\" & INTEGER'IMAGE(CHARACTER'POS(C))); 
      end case; 
    elsif (C = ' ') then 
      return VSTR("' '"); 
    else 
      return VSTR(C); 
    end if; 
  end READABLE_FORM; 

  -- transition_struct_out - output a yy_trans_info structure
  --
  -- outputs the yy_trans_info structure with the two elements, element_v and
  -- element_n.  Formats the output with spaces and carriage returns.

  procedure TRANSITION_STRUCT_OUT(ELEMENT_V, ELEMENT_N : in INTEGER) is 
  begin
    INT_IO.PUT(ELEMENT_V, 7); 
    TEXT_IO.PUT(", "); 
    INT_IO.PUT(ELEMENT_N, 5); 
    TEXT_IO.PUT(","); 
    DATAPOS := DATAPOS + TRANS_STRUCT_PRINT_LENGTH; 

    if (DATAPOS >= 75) then 
      TEXT_IO.NEW_LINE; 

      DATALINE := DATALINE + 1; 
      if (DATALINE mod 10 = 0) then 
        TEXT_IO.NEW_LINE; 
      end if; 

      DATAPOS := 0; 
    end if; 
  end TRANSITION_STRUCT_OUT; 

  function SET_YY_TRAILING_HEAD_MASK(SRC : in INTEGER) return INTEGER is 
  begin
    if (CHECK_YY_TRAILING_HEAD_MASK(SRC) = 0) then 
      return SRC + YY_TRAILING_HEAD_MASK; 
    else 
      return SRC; 
    end if; 
  end SET_YY_TRAILING_HEAD_MASK; 

  function CHECK_YY_TRAILING_HEAD_MASK(SRC : in INTEGER) return INTEGER is 
  begin
    if (SRC >= YY_TRAILING_HEAD_MASK) then 
      return YY_TRAILING_HEAD_MASK; 
    else 
      return 0; 
    end if; 
  end CHECK_YY_TRAILING_HEAD_MASK; 

  function SET_YY_TRAILING_MASK(SRC : in INTEGER) return INTEGER is 
  begin
    if (CHECK_YY_TRAILING_MASK(SRC) = 0) then 
      return SRC + YY_TRAILING_MASK; 
    else 
      return SRC; 
    end if; 
  end SET_YY_TRAILING_MASK; 

  function CHECK_YY_TRAILING_MASK(SRC : in INTEGER) return INTEGER is 
  begin

-- this test is whether both bits are on, or whether onlyy TRAIL_MASK is set
    if ((SRC >= YY_TRAILING_HEAD_MASK + YY_TRAILING_MASK) or ((
      CHECK_YY_TRAILING_HEAD_MASK(SRC) = 0) and (SRC >= YY_TRAILING_MASK)))
      then 
      return YY_TRAILING_MASK; 
    else 
      return 0; 
    end if; 
  end CHECK_YY_TRAILING_MASK; 

  function ISLOWER(C : in CHARACTER) return BOOLEAN is 
  begin
    return (C in 'a' .. 'z'); 
  end ISLOWER; 


  function ISUPPER(C : in CHARACTER) return BOOLEAN is 
  begin
    return (C in 'A' .. 'Z'); 
  end ISUPPER; 

  function ISDIGIT(C : in CHARACTER) return BOOLEAN is 
  begin
    return (C in '0' .. '9'); 
  end ISDIGIT; 

  function TOLOWER(C : in INTEGER) return INTEGER is 
  begin
    return C - CHARACTER'POS('A') + CHARACTER'POS('a'); 
  end TOLOWER; 

  procedure SYNERR(STR : in STRING) is 
    use TEXT_IO; 
  begin
    SYNTAXERROR := TRUE; 
    TEXT_IO.PUT(STANDARD_ERROR, "Syntax error at line "); 
    INT_IO.PUT(STANDARD_ERROR, LINENUM); 
    TEXT_IO.PUT(STANDARD_ERROR, STR); 
    TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  end SYNERR; 

end MISC; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE  miscellaneous aflex routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION
-- NOTES contains functions used in various places throughout aflex.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/miscS.a,v 1.9 90/01/12 15:20:19 self Exp Locker: self $ 

with MISC_DEFS, TSTRING, TEXT_IO; 
package MISC is 
  use MISC_DEFS; 
  use TSTRING; 
  use TEXT_IO; 
  procedure ACTION_OUT; 
  procedure BUBBLE(V : in INT_PTR; 
                   N : in INTEGER); 
  function CLOWER(C : in INTEGER) return INTEGER; 
  procedure CSHELL(V : in out CHAR_ARRAY; 
                   N : in INTEGER); 
  procedure DATAEND; 
  procedure DATAFLUSH; 
  procedure DATAFLUSH(FILE : in FILE_TYPE); 
  function AFLEX_GETTIME return VSTRING; 
  procedure AFLEXERROR(MSG : in VSTRING); 
  procedure AFLEXERROR(MSG : in STRING); 
  function ALL_UPPER(STR : in VSTRING) return BOOLEAN; 
  function ALL_LOWER(STR : in VSTRING) return BOOLEAN; 
  procedure AFLEXFATAL(MSG : in VSTRING); 
  procedure AFLEXFATAL(MSG : in STRING); 
  procedure LINE_DIRECTIVE_OUT; 
  procedure LINE_DIRECTIVE_OUT(OUTPUT_FILE_NAME : in FILE_TYPE); 
  procedure MK2DATA(VALUE : in INTEGER); 
  procedure MK2DATA(FILE  : in FILE_TYPE; 
                    VALUE : in INTEGER); 
  procedure MKDATA(VALUE : in INTEGER); 
  function MYCTOI(NUM_ARRAY : in VSTRING) return INTEGER; 
  function MYESC(ARR : in VSTRING) return CHARACTER; 
  function OTOI(STR : in VSTRING) return CHARACTER; 
  function READABLE_FORM(C : in CHARACTER) return VSTRING; 
  procedure SYNERR(STR : in STRING); 
  procedure TRANSITION_STRUCT_OUT(ELEMENT_V, ELEMENT_N : in INTEGER); 
  function SET_YY_TRAILING_HEAD_MASK(SRC : in INTEGER) return INTEGER; 
  function CHECK_YY_TRAILING_HEAD_MASK(SRC : in INTEGER) return INTEGER; 
  function SET_YY_TRAILING_MASK(SRC : in INTEGER) return INTEGER; 
  function CHECK_YY_TRAILING_MASK(SRC : in INTEGER) return INTEGER; 
  function ISLOWER(C : in CHARACTER) return BOOLEAN; 
  function ISUPPER(C : in CHARACTER) return BOOLEAN; 
  function ISDIGIT(C : in CHARACTER) return BOOLEAN; 
  function TOLOWER(C : in INTEGER) return INTEGER; 
  function BASENAME return VSTRING; 
end MISC; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE miscellaneous definitions
-- AUTHOR: John Self (UCI)
-- DESCRIPTION contains all global variables used in aflex.
--             also some subprograms which are commonly used.
-- NOTES The real purpose of this file is to contain all miscellaneous
--       items (functions, MACROS, variables definitions) which were at the
--       top level of flex.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/misc_defsB.a,v 1.5 90/01/12 15:20:21 self Exp Locker: self $ 

package body MISC_DEFS is 

-- returns true if an nfa state has an epsilon out-transition slot
-- that can be used.  This definition is currently not used.

  function FREE_EPSILON(STATE : in INTEGER) return BOOLEAN is 
  begin
    return ((TRANSCHAR(STATE) = SYM_EPSILON) and (TRANS2(STATE) = NO_TRANSITION)
      and (FINALST(STATE) /= STATE)); 
  end FREE_EPSILON; 

  -- returns true if an nfa state has an epsilon out-transition character
  -- and both slots are free

  function SUPER_FREE_EPSILON(STATE : in INTEGER) return BOOLEAN is 
  begin
    return ((TRANSCHAR(STATE) = SYM_EPSILON) and (TRANS1(STATE) = NO_TRANSITION)
      ); 
  end SUPER_FREE_EPSILON; 

  function ALLOCATE_INTEGER_ARRAY(SIZE : in INTEGER) return INT_PTR is 
  begin
    return new UNBOUNDED_INT_ARRAY(0 .. SIZE); 
  end ALLOCATE_INTEGER_ARRAY; 

  procedure REALLOCATE_INTEGER_ARRAY(ARR  : in out INT_PTR; 
                                     SIZE : in INTEGER) is 
    NEW_ARR : INT_PTR; 
  begin
    NEW_ARR := ALLOCATE_INTEGER_ARRAY(SIZE); 
    NEW_ARR(0 .. ARR'LAST) := ARR(0 .. ARR'LAST); 
    ARR := NEW_ARR; 
  end REALLOCATE_INTEGER_ARRAY; 

  procedure REALLOCATE_STATE_ENUM_ARRAY(ARR  : in out STATE_ENUM_PTR; 
                                        SIZE : in INTEGER) is 
    NEW_ARR : STATE_ENUM_PTR; 
  begin
    NEW_ARR := ALLOCATE_STATE_ENUM_ARRAY(SIZE); 
    NEW_ARR(0 .. ARR'LAST) := ARR(0 .. ARR'LAST); 
    ARR := NEW_ARR; 
  end REALLOCATE_STATE_ENUM_ARRAY; 

  procedure REALLOCATE_RULE_ENUM_ARRAY(ARR  : in out RULE_ENUM_PTR; 
                                       SIZE : in INTEGER) is 
    NEW_ARR : RULE_ENUM_PTR; 
  begin
    NEW_ARR := ALLOCATE_RULE_ENUM_ARRAY(SIZE); 
    NEW_ARR(0 .. ARR'LAST) := ARR(0 .. ARR'LAST); 
    ARR := NEW_ARR; 
  end REALLOCATE_RULE_ENUM_ARRAY; 

  function ALLOCATE_INT_PTR_ARRAY(SIZE : in INTEGER) return INT_STAR_PTR is 
  begin
    return new UNBOUNDED_INT_STAR_ARRAY(0 .. SIZE); 
  end ALLOCATE_INT_PTR_ARRAY; 

  function ALLOCATE_RULE_ENUM_ARRAY(SIZE : in INTEGER) return RULE_ENUM_PTR is 
  begin
    return new UNBOUNDED_RULE_ENUM_ARRAY(0 .. SIZE); 
  end ALLOCATE_RULE_ENUM_ARRAY; 

  function ALLOCATE_STATE_ENUM_ARRAY(SIZE : in INTEGER) return STATE_ENUM_PTR
    is 
  begin
    return new UNBOUNDED_STATE_ENUM_ARRAY(0 .. SIZE); 
  end ALLOCATE_STATE_ENUM_ARRAY; 

  function ALLOCATE_BOOLEAN_ARRAY(SIZE : in INTEGER) return BOOLEAN_PTR is 
  begin
    return new BOOLEAN_ARRAY(0 .. SIZE); 
  end ALLOCATE_BOOLEAN_ARRAY; 

  function ALLOCATE_VSTRING_ARRAY(SIZE : in INTEGER) return VSTRING_PTR is 
  begin
    return new UNBOUNDED_VSTRING_ARRAY(0 .. SIZE); 
  end ALLOCATE_VSTRING_ARRAY; 

  function ALLOCATE_DFAACC_UNION(SIZE : in INTEGER) return DFAACC_PTR is 
  begin
    return new UNBOUNDED_DFAACC_ARRAY(0 .. SIZE); 
  end ALLOCATE_DFAACC_UNION; 

  procedure REALLOCATE_INT_PTR_ARRAY(ARR  : in out INT_STAR_PTR; 
                                     SIZE : in INTEGER) is 
    NEW_ARR : INT_STAR_PTR; 
  begin
    NEW_ARR := ALLOCATE_INT_PTR_ARRAY(SIZE); 
    NEW_ARR(0 .. ARR'LAST) := ARR(0 .. ARR'LAST); 
    ARR := NEW_ARR; 
  end REALLOCATE_INT_PTR_ARRAY; 

  procedure REALLOCATE_CHARACTER_ARRAY(ARR  : in out CHAR_PTR; 
                                       SIZE : in INTEGER) is 
    NEW_ARR : CHAR_PTR; 
  begin
    NEW_ARR := ALLOCATE_CHARACTER_ARRAY(SIZE); 
    NEW_ARR(0 .. ARR'LAST) := ARR(0 .. ARR'LAST); 
    ARR := NEW_ARR; 
  end REALLOCATE_CHARACTER_ARRAY; 

  procedure REALLOCATE_VSTRING_ARRAY(ARR  : in out VSTRING_PTR; 
                                     SIZE : in INTEGER) is 
    NEW_ARR : VSTRING_PTR; 
  begin
    NEW_ARR := ALLOCATE_VSTRING_ARRAY(SIZE); 
    NEW_ARR(0 .. ARR'LAST) := ARR(0 .. ARR'LAST); 
    ARR := NEW_ARR; 
  end REALLOCATE_VSTRING_ARRAY; 

  function ALLOCATE_CHARACTER_ARRAY(SIZE : in INTEGER) return CHAR_PTR is 
  begin
    return new CHAR_ARRAY(0 .. SIZE); 
  end ALLOCATE_CHARACTER_ARRAY; 

  procedure REALLOCATE_DFAACC_UNION(ARR  : in out DFAACC_PTR; 
                                    SIZE : in INTEGER) is 
    NEW_ARR : DFAACC_PTR; 
  begin
    NEW_ARR := ALLOCATE_DFAACC_UNION(SIZE); 
    NEW_ARR(0 .. ARR'LAST) := ARR(0 .. ARR'LAST); 
    ARR := NEW_ARR; 
  end REALLOCATE_DFAACC_UNION; 

  procedure REALLOCATE_BOOLEAN_ARRAY(ARR  : in out BOOLEAN_PTR; 
                                     SIZE : in INTEGER) is 
    NEW_ARR : BOOLEAN_PTR; 
  begin
    NEW_ARR := ALLOCATE_BOOLEAN_ARRAY(SIZE); 
    NEW_ARR(0 .. ARR'LAST) := ARR(0 .. ARR'LAST); 
    ARR := NEW_ARR; 
  end REALLOCATE_BOOLEAN_ARRAY; 

  function MAX(X, Y : in INTEGER) return INTEGER is 
  begin
    if (X > Y) then 
      return X; 
    else 
      return Y; 
    end if; 
  end MAX; 

  function MIN(X, Y : in INTEGER) return INTEGER is 
  begin
    if (X < Y) then 
      return X; 
    else 
      return Y; 
    end if; 
  end MIN; 

end MISC_DEFS; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE miscellaneous definitions
-- AUTHOR: John Self (UCI)
-- DESCRIPTION contains all global variables used in aflex.
--             also some subprograms which are commonly used.
-- NOTES The real purpose of this file is to contain all miscellaneous
--       items (functions, MACROS, variables definitions) which were at the
--       top level of flex.
-- $Header: /co/ua/self/arcadia/alex/ada/RCS/misc_defsS.a,v 1.8 90/01/04 13:39:
-- 33 self Exp Locker: self $ 

with TEXT_IO, TSTRING;
use TEXT_IO, TSTRING;

package MISC_DEFS is

  -- various definitions that were in parse.y
  PAT, SCNUM, EPS, HEADCNT, TRAILCNT, ANYCCL, LASTCHAR, ACTVP, RULELEN : INTEGER
    ;
  TRLCONTXT, XCLUFLG, CCLSORTED, VARLENGTH, VARIABLE_TRAIL_RULE : BOOLEAN;

  MADEANY : BOOLEAN := FALSE;  -- whether we've made the '.' character class 
  PREVIOUS_CONTINUED_ACTION : BOOLEAN; -- whether the previous rule's action wa
                                       -- s '|'

  -- maximum line length we'll have to deal with 
  MAXLINE : constant INTEGER := 1024;

  -- These typees are needed for the various allocators.
  type UNBOUNDED_INT_ARRAY is array ( INTEGER range <> ) of INTEGER;
  type INT_PTR is access UNBOUNDED_INT_ARRAY;
  type INT_STAR is access INTEGER;
  type UNBOUNDED_INT_STAR_ARRAY is array ( INTEGER range <> ) of INT_PTR;
  type INT_STAR_PTR is access UNBOUNDED_INT_STAR_ARRAY;
  type UNBOUNDED_VSTRING_ARRAY is array ( INTEGER range <> ) of VSTRING;
  type VSTRING_PTR is access UNBOUNDED_VSTRING_ARRAY;
  type BOOLEAN_ARRAY is array ( INTEGER range <> ) of BOOLEAN;
  type BOOLEAN_PTR is access BOOLEAN_ARRAY;
  type CHAR_ARRAY is array ( INTEGER range <> ) of CHARACTER;
  type CHAR_PTR is access CHAR_ARRAY;

  -- different types of states; values are useful as masks, as well, for
  -- routines like check_trailing_context()

  type STATE_ENUM is (STATE_NORMAL, STATE_TRAILING_CONTEXT);

  type UNBOUNDED_STATE_ENUM_ARRAY is array ( INTEGER range <> ) of STATE_ENUM;
  type STATE_ENUM_PTR is access UNBOUNDED_STATE_ENUM_ARRAY;

  -- different types of rules
  type RULE_ENUM is (RULE_NORMAL, RULE_VARIABLE);

  type UNBOUNDED_RULE_ENUM_ARRAY is array ( INTEGER range <> ) of RULE_ENUM;
  type RULE_ENUM_PTR is access UNBOUNDED_RULE_ENUM_ARRAY;

  type DFAACC_TYPE is
    record
      DFAACC_SET : INT_PTR;
      DFAACC_STATE : INTEGER;
    end record;

  type UNBOUNDED_DFAACC_ARRAY is array ( INTEGER range <> ) of DFAACC_TYPE;
  type DFAACC_PTR is access UNBOUNDED_DFAACC_ARRAY;

  -- maximum size of file name 

  FILENAMESIZE : constant INTEGER := 1024;

  function MIN (X, Y : in INTEGER) return INTEGER;
  function MAX (X, Y : in INTEGER) return INTEGER;

  -- special chk[] values marking the slots taking by end-of-buffer and action
  -- numbers

  EOB_POSITION : constant INTEGER := - 1;
  ACTION_POSITION : constant INTEGER := - 2;

  -- number of data items per line for -f output
  NUMDATAITEMS : constant INTEGER := 10;

  -- number of lines of data in -f output before inserting a blank line for
  -- readability.

  NUMDATALINES : constant INTEGER := 10;

  -- transition_struct_out() definitions
  TRANS_STRUCT_PRINT_LENGTH : constant INTEGER := 15;

  -- returns true if an nfa state has an epsilon out-transition slot
  -- that can be used.  This definition is currently not used.

  function FREE_EPSILON ( STATE : in INTEGER) return BOOLEAN;

  -- returns true if an nfa state has an epsilon out-transition character
  -- and both slots are free

  function SUPER_FREE_EPSILON (STATE : in INTEGER) return BOOLEAN;

  -- maximum number of NFA states that can comprise a DFA state.  It's real
  -- big because if there's a lot of rules, the initial state will have a
  -- huge epsilon closure.

  INITIAL_MAX_DFA_SIZE : constant INTEGER := 750;
  MAX_DFA_SIZE_INCREMENT : constant INTEGER := 750;

  -- a note on the following masks.  They are used to mark accepting numbers
  -- as being special.  As such, they implicitly limit the number of accepting
  -- numbers (i.e., rules) because if there are too many rules the rule numbers
  -- will overload the mask bits.  Fortunately, this limit is \large/ (0x2000 ==
  -- 8192) so unlikely to actually cause any problems.  A check is made in
  -- new_rule() to ensure that this limit is not reached.

  -- mask to mark a trailing context accepting number
  -- #define YY_TRAILING_MASK 0x2000
  YY_TRAILING_MASK : constant INTEGER := 16#2000#;


  -- mask to mark the accepting number of the "head" of a trailing context rule
  -- #define YY_TRAILING_HEAD_MASK 0x4000
  YY_TRAILING_HEAD_MASK : constant INTEGER := 16#4000#;

  -- maximum number of rules, as outlined in the above note
  MAX_RULE : constant INTEGER := YY_TRAILING_MASK - 1;


  -- NIL must be 0.  If not, its special meaning when making equivalence classes
  -- (it marks the representative of a given e.c.) will be unidentifiable

  NIL : constant INTEGER := 0;

  JAM : constant INTEGER := - 1; -- to mark a missing DFA transition 
  NO_TRANSITION : constant INTEGER := NIL;
  UNIQUE : constant INTEGER := - 1; -- marks a symbol as an e.c. representative
  INFINITY : constant INTEGER := - 1; -- for x{5,} constructions

  -- size of input alphabet - should be size of ASCII set
  CSIZE : constant INTEGER := 127;

  INITIAL_MAX_CCLS : constant INTEGER := 100; -- max number of unique character
                                              --  classes
  MAX_CCLS_INCREMENT : constant INTEGER := 100;

  -- size of table holding members of character classes
  INITIAL_MAX_CCL_TBL_SIZE : constant INTEGER := 500;
  MAX_CCL_TBL_SIZE_INCREMENT : constant INTEGER := 250;
  INITIAL_MAX_RULES : constant INTEGER := 100;
  -- default maximum number of rules
  MAX_RULES_INCREMENT : constant INTEGER := 100;

  INITIAL_MNS : constant INTEGER := 2000; -- default maximum number of nfa stat
                                          -- es
  MNS_INCREMENT : constant INTEGER := 1000; -- amount to bump above by if it's 
                                            -- not enough

  INITIAL_MAX_DFAS : constant INTEGER := 1000; -- default maximum number of dfa
                                               --  states
  MAX_DFAS_INCREMENT : constant INTEGER := 1000;

  JAMSTATE_CONST : constant INTEGER := - 32766; -- marks a reference to the sta
                                                -- te that always jams

  -- enough so that if it's subtracted from an NFA state number, the result
  -- is guaranteed to be negative

  MARKER_DIFFERENCE : constant INTEGER := 32000;
  MAXIMUM_MNS : constant INTEGER := 31999;

  -- maximum number of nxt/chk pairs for non-templates
  INITIAL_MAX_XPAIRS : constant INTEGER := 2000;
  MAX_XPAIRS_INCREMENT : constant INTEGER := 2000;

  -- maximum number of nxt/chk pairs needed for templates
  INITIAL_MAX_TEMPLATE_XPAIRS : constant INTEGER := 2500;
  MAX_TEMPLATE_XPAIRS_INCREMENT : constant INTEGER := 2500;

  SYM_EPSILON : constant INTEGER := 0; -- to mark transitions on the symbol eps
                                       -- ilon

  INITIAL_MAX_SCS : constant INTEGER := 40; -- maximum number of start conditio
                                            -- ns
  MAX_SCS_INCREMENT : constant INTEGER := 40; -- amount to bump by if it's not 
                                              -- enough

  ONE_STACK_SIZE : constant INTEGER := 500; -- stack of states with only one ou
                                            -- t-transition
  SAME_TRANS : constant INTEGER := - 1; -- transition is the same as "default" 
                                        -- entry for state

  -- the following percentages are used to tune table compression:
  --
  -- the percentage the number of out-transitions a state must be of the
  -- number of equivalence classes in order to be considered for table
  -- compaction by using protos

  PROTO_SIZE_PERCENTAGE : constant INTEGER := 15;

  -- the percentage the number of homogeneous out-transitions of a state
  -- must be of the number of total out-transitions of the state in order
  -- that the state's transition table is first compared with a potential 
  -- template of the most common out-transition instead of with the first
  --proto in the proto queue

  CHECK_COM_PERCENTAGE : constant INTEGER := 50;

  -- the percentage the number of differences between a state's transition
  -- table and the proto it was first compared with must be of the total
  -- number of out-transitions of the state in order to keep the first
  -- proto as a good match and not search any further

  FIRST_MATCH_DIFF_PERCENTAGE : constant INTEGER := 10;

  -- the percentage the number of differences between a state's transition
  -- table and the most similar proto must be of the state's total number
  -- of out-transitions to use the proto as an acceptable close match

  ACCEPTABLE_DIFF_PERCENTAGE : constant INTEGER := 50;

  -- the percentage the number of homogeneous out-transitions of a state
  -- must be of the number of total out-transitions of the state in order
  -- to consider making a template from the state

  TEMPLATE_SAME_PERCENTAGE : constant INTEGER := 60;

  -- the percentage the number of differences between a state's transition
  -- table and the most similar proto must be of the state's total number
  -- of out-transitions to create a new proto from the state

  NEW_PROTO_DIFF_PERCENTAGE : constant INTEGER := 20;

  -- the percentage the total number of out-transitions of a state must be
  -- of the number of equivalence classes in order to consider trying to
  -- fit the transition table into "holes" inside the nxt/chk table.

  INTERIOR_FIT_PERCENTAGE : constant INTEGER := 15;

  -- size of region set aside to cache the complete transition table of
  -- protos on the proto queue to enable quick comparisons

  PROT_SAVE_SIZE : constant INTEGER := 2000;

  MSP : constant INTEGER := 50; -- maximum number of saved protos (protos on th
                                -- e proto queue)

  -- maximum number of out-transitions a state can have that we'll rummage
  -- around through the interior of the internal fast table looking for a
  -- spot for it

  MAX_XTIONS_FULL_INTERIOR_FIT : constant INTEGER := 4;

  -- maximum number of rules which will be reported as being associated
  -- with a DFA state

  MAX_ASSOC_RULES : constant INTEGER := 100;

  -- number that, if used to subscript an array, has a good chance of producing
  -- an error; should be small enough to fit into a short

  BAD_SUBSCRIPT : constant INTEGER := - 32767;

  -- Declarations for global variables.

  -- variables for symbol tables:
  -- sctbl - start-condition symbol table
  -- ndtbl - name-definition symbol table
  -- ccltab - character class text symbol table

  type HASH_ENTRY;
  type HASH_LINK is access HASH_ENTRY;
  type HASH_ENTRY is
    record
      PREV, NEXT : HASH_LINK;
      NAME, STR_VAL : VSTRING;
      INT_VAL : INTEGER;
    end record;

  type HASH_TABLE is array ( INTEGER range <> ) of HASH_LINK;

  NAME_TABLE_HASH_SIZE : constant INTEGER := 101;
  START_COND_HASH_SIZE : constant INTEGER := 101;
  CCL_HASH_SIZE : constant INTEGER := 101;

  subtype NDTBL_TYPE is HASH_TABLE (0 .. NAME_TABLE_HASH_SIZE - 1);
  NDTBL : NDTBL_TYPE;
  subtype SCTBL_TYPE is HASH_TABLE (0 .. START_COND_HASH_SIZE - 1);
  SCTBL : SCTBL_TYPE;
  subtype CCLTAB_TYPE is HASH_TABLE (0 .. CCL_HASH_SIZE);
  CCLTAB : CCLTAB_TYPE;

  -- variables for flags:
  -- printstats - if true (-v), dump statistics
  -- syntaxerror - true if a syntax error has been found
  -- eofseen - true if we've seen an eof in the input file
  -- ddebug - if true (-d), make a "debug" scanner
  -- trace - if true (-T), trace processing
  -- spprdflt - if true (-s), suppress the default rule
  -- interactive - if true (-I), generate an interactive scanner
  -- caseins - if true (-i), generate a case-insensitive scanner
  -- useecs - if true (-ce flag), use equivalence classes
  -- fulltbl - if true (-cf flag), don't compress the DFA state table
  -- usemecs - if true (-cm flag), use meta-equivalence classes
  -- gen_line_dirs - if true (i.e., no -L flag), generate #line directives
  -- performance_report - if true (i.e., -p flag), generate a report relating
  --   to scanner performance
  -- backtrack_report - if true (i.e., -b flag), generate "lex.backtrack" file
  --   listing backtracking states
  -- continued_action - true if this rule's action is to "fall through" to
  --                    the next rule's action (i.e., the '|' action)

  PRINTSTATS, DDEBUG, SPPRDFLT,
  INTERACTIVE, CASEINS, USEECS, FULLTBL, USEMECS,
  GEN_LINE_DIRS, PERFORMANCE_REPORT, BACKTRACK_REPORT,
  TRACE, EOFSEEN, CONTINUED_ACTION : BOOLEAN;

  SYNTAXERROR : BOOLEAN;

  -- variables used in the aflex input routines:
  -- datapos - characters on current output line
  -- dataline - number of contiguous lines of data in current data
  --    statement.  Used to generate readable -f output
  -- skelfile - the skeleton file
  -- yyin - input file
  -- temp_action_file - temporary file to hold actions
  -- backtrack_file - file to summarize backtracking states to
  -- infilename - name of input file
  -- linenum - current input line number

  DATAPOS, DATALINE, LINENUM : INTEGER;

  SKELFILE, YYIN, TEMP_ACTION_FILE, BACKTRACK_FILE, DEF_FILE : FILE_TYPE;
  INFILENAME : VSTRING;

  -- variables for stack of states having only one out-transition:
  -- onestate - state number
  -- onesym - transition symbol
  -- onenext - target state
  -- onedef - default base entry
  -- onesp - stack pointer

  ONESTATE, ONESYM, ONENEXT, ONEDEF : array (0 .. ONE_STACK_SIZE - 1) of INTEGER
    ;
  ONESP : INTEGER;


  -- variables for nfa machine data:
  -- current_mns - current maximum on number of NFA states
  -- num_rules - number of the last accepting state; also is number of
  --             rules created so far
  -- current_max_rules - current maximum number of rules
  -- lastnfa - last nfa state number created
  -- firstst - physically the first state of a fragment
  -- lastst - last physical state of fragment
  -- finalst - last logical state of fragment
  -- transchar - transition character
  -- trans1 - transition state
  -- trans2 - 2nd transition state for epsilons
  -- accptnum - accepting number
  -- assoc_rule - rule associated with this NFA state (or 0 if none)
  -- state_type - a STATE_xxx type identifying whether the state is part
  --              of a normal rule, the leading state in a trailing context
  --              rule (i.e., the state which marks the transition from
  --              recognizing the text-to-be-matched to the beginning of
  --              the trailing context), or a subsequent state in a trailing
  --              context rule
  -- rule_type - a RULE_xxx type identifying whether this a a ho-hum
  --             normal rule or one which has variable head & trailing
  --             context
  -- rule_linenum - line number associated with rule

  CURRENT_MNS, NUM_RULES, CURRENT_MAX_RULES, LASTNFA : INTEGER;
  FIRSTST, LASTST, FINALST, TRANSCHAR, TRANS1, TRANS2 : INT_PTR;
  ACCPTNUM, ASSOC_RULE, RULE_LINENUM : INT_PTR;
  RULE_TYPE : RULE_ENUM_PTR;
  STATE_TYPE : STATE_ENUM_PTR;

  -- global holding current type of state we're making

  CURRENT_STATE_ENUM : STATE_ENUM;

  -- true if the input rules include a rule with both variable-length head
  -- and trailing context, false otherwise

  VARIABLE_TRAILING_CONTEXT_RULES : BOOLEAN;


  -- variables for protos:
  -- numtemps - number of templates created
  -- numprots - number of protos created
  -- protprev - backlink to a more-recently used proto
  -- protnext - forward link to a less-recently used proto
  -- prottbl - base/def table entry for proto
  -- protcomst - common state of proto
  -- firstprot - number of the most recently used proto
  -- lastprot - number of the least recently used proto
  -- protsave contains the entire state array for protos

  NUMTEMPS, NUMPROTS, FIRSTPROT, LASTPROT : INTEGER;
  PROTPREV, PROTNEXT, PROTTBL, PROTCOMST : array (0 .. MSP - 1) of INTEGER;
  PROTSAVE : array (0 .. PROT_SAVE_SIZE - 1) of INTEGER;


  -- variables for managing equivalence classes:
  -- numecs - number of equivalence classes
  -- nextecm - forward link of Equivalence Class members
  -- ecgroup - class number or backward link of EC members
  -- nummecs - number of meta-equivalence classes (used to compress
  --   templates)
  -- tecfwd - forward link of meta-equivalence classes members
  -- * tecbck - backward link of MEC's

  NUMECS, NUMMECS : INTEGER;
  subtype C_SIZE_ARRAY is UNBOUNDED_INT_ARRAY (0 .. CSIZE);
  type C_SIZE_BOOL_ARRAY is array (0 .. CSIZE) of BOOLEAN;
  NEXTECM, ECGROUP, TECFWD, TECBCK : C_SIZE_ARRAY;


  -- variables for start conditions:
  -- lastsc - last start condition created
  -- current_max_scs - current limit on number of start conditions
  -- scset - set of rules active in start condition
  -- scbol - set of rules active only at the beginning of line in a s.c.
  -- scxclu - true if start condition is exclusive
  -- sceof - true if start condition has EOF rule
  -- scname - start condition name
  -- actvsc - stack of active start conditions for the current rule

  LASTSC, CURRENT_MAX_SCS : INTEGER;
  SCSET, SCBOL : INT_PTR;
  SCXCLU, SCEOF : BOOLEAN_PTR;
  ACTVSC : INT_PTR;
  SCNAME : VSTRING_PTR;


  -- variables for dfa machine data:
  -- current_max_dfa_size - current maximum number of NFA states in DFA
  -- current_max_xpairs - current maximum number of non-template xtion pairs
  -- current_max_template_xpairs - current maximum number of template pairs
  -- current_max_dfas - current maximum number DFA states
  -- lastdfa - last dfa state number created
  -- nxt - state to enter upon reading character
  -- chk - check value to see if "nxt" applies
  -- tnxt - internal nxt table for templates
  -- base - offset into "nxt" for given state
  -- def - where to go if "chk" disallows "nxt" entry
  -- tblend - last "nxt/chk" table entry being used
  -- firstfree - first empty entry in "nxt/chk" table
  -- dss - nfa state set for each dfa
  -- dfasiz - size of nfa state set for each dfa
  -- dfaacc - accepting set for each dfa state (or accepting number, if
  --    -r is not given)
  -- accsiz - size of accepting set for each dfa state
  -- dhash - dfa state hash value
  -- numas - number of DFA accepting states created; note that this
  --    is not necessarily the same value as num_rules, which is the analogous
  --    value for the NFA
  -- numsnpairs - number of state/nextstate transition pairs
  -- jambase - position in base/def where the default jam table starts
  -- jamstate - state number corresponding to "jam" state
  -- end_of_buffer_state - end-of-buffer dfa state number

  CURRENT_MAX_DFA_SIZE, CURRENT_MAX_XPAIRS : INTEGER;
  CURRENT_MAX_TEMPLATE_XPAIRS, CURRENT_MAX_DFAS : INTEGER;
  LASTDFA, LASTTEMP : INTEGER;
  NXT, CHK, TNXT : INT_PTR;
  BASE, DEF , DFASIZ : INT_PTR;
  TBLEND, FIRSTFREE : INTEGER;
  DSS : INT_STAR_PTR;
  DFAACC : DFAACC_PTR;

  -- type declaration for dfaacc_type moved above

  ACCSIZ, DHASH : INT_PTR;
  END_OF_BUFFER_STATE, NUMSNPAIRS, JAMBASE, JAMSTATE, NUMAS : INTEGER;

  -- variables for ccl information:
  -- lastccl - ccl index of the last created ccl
  -- current_maxccls - current limit on the maximum number of unique ccl's
  -- cclmap - maps a ccl index to its set pointer
  -- ccllen - gives the length of a ccl
  -- cclng - true for a given ccl if the ccl is negated
  -- cclreuse - counts how many times a ccl is re-used
  -- current_max_ccl_tbl_size - current limit on number of characters needed
  --	to represent the unique ccl's
  -- ccltbl - holds the characters in each ccl - indexed by cclmap

  CURRENT_MAX_CCL_TBL_SIZE, LASTCCL, CURRENT_MAXCCLS, CCLREUSE : INTEGER;
  CCLMAP, CCLLEN, CCLNG : INT_PTR;

  CCLTBL : CHAR_PTR;


  -- variables for miscellaneous information:
  -- starttime - real-time when we started
  -- endtime - real-time when we ended
  -- nmstr - last NAME scanned by the scanner
  -- sectnum - section number currently being parsed
  -- nummt - number of empty nxt/chk table entries
  -- hshcol - number of hash collisions detected by snstods
  -- dfaeql - number of times a newly created dfa was equal to an old one
  -- numeps - number of epsilon NFA states created
  -- eps2 - number of epsilon states which have 2 out-transitions
  -- num_reallocs - number of times it was necessary to realloc() a group
  --		  of arrays
  -- tmpuses - number of DFA states that chain to templates
  -- totnst - total number of NFA states used to make DFA states
  -- peakpairs - peak number of transition pairs we had to store internally
  -- numuniq - number of unique transitions
  -- numdup - number of duplicate transitions
  -- hshsave - number of hash collisions saved by checking number of states
  -- num_backtracking - number of DFA states requiring back-tracking
  -- bol_needed - whether scanner needs beginning-of-line recognition

  NMSTR : VSTRING;
  SECTNUM, NUMMT, HSHCOL, DFAEQL, NUMEPS, EPS2, NUM_REALLOCS : INTEGER;
  TMPUSES, TOTNST, PEAKPAIRS, NUMUNIQ, NUMDUP, HSHSAVE : INTEGER;
  NUM_BACKTRACKING : INTEGER;
  BOL_NEEDED : BOOLEAN;

  function ALLOCATE_INTEGER_ARRAY (SIZE : in INTEGER) return INT_PTR;

  function ALLOCATE_INT_PTR_ARRAY (SIZE : in INTEGER) return INT_STAR_PTR;



  function ALLOCATE_VSTRING_ARRAY (SIZE : in INTEGER) return VSTRING_PTR;

  function ALLOCATE_DFAACC_UNION (SIZE : in INTEGER) return DFAACC_PTR;

  function  ALLOCATE_CHARACTER_ARRAY (SIZE : in INTEGER) return CHAR_PTR;

  function ALLOCATE_RULE_ENUM_ARRAY (SIZE : in INTEGER) return RULE_ENUM_PTR;

  function ALLOCATE_STATE_ENUM_ARRAY (SIZE : in INTEGER) return STATE_ENUM_PTR;

  function ALLOCATE_BOOLEAN_ARRAY (SIZE : in INTEGER) return BOOLEAN_PTR;

  procedure REALLOCATE_INTEGER_ARRAY (ARR : in out INT_PTR;
       SIZE : in INTEGER);

  procedure REALLOCATE_INT_PTR_ARRAY (ARR : in out INT_STAR_PTR;
       SIZE : in INTEGER);

  procedure REALLOCATE_VSTRING_ARRAY (ARR : in out VSTRING_PTR;
        SIZE : in INTEGER);

  procedure REALLOCATE_DFAACC_UNION (ARR : in out DFAACC_PTR;
      SIZE : in INTEGER);

  procedure REALLOCATE_CHARACTER_ARRAY (ARR : in out CHAR_PTR;
       SIZE : in INTEGER);

  procedure REALLOCATE_RULE_ENUM_ARRAY (ARR : in out RULE_ENUM_PTR;
       SIZE : in INTEGER);

  procedure REALLOCATE_STATE_ENUM_ARRAY (ARR : in out STATE_ENUM_PTR;
       SIZE : in INTEGER);

  procedure REALLOCATE_BOOLEAN_ARRAY (ARR : in out BOOLEAN_PTR;
       SIZE : in INTEGER);

end MISC_DEFS;
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE NFA construction routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION builds the NFA.
-- NOTES this file mirrors flex as closely as possible.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/nfaB.a,v 1.6 90/01/12 15:20:27 self Exp Locker: self $ 

with MISC_DEFS, NFA, MISC, ECS; 
with TSTRING, INT_IO, TEXT_IO, EXTERNAL_FILE_MANAGER; use MISC_DEFS, TSTRING, 
  EXTERNAL_FILE_MANAGER; 

package body NFA is 

-- add_accept - add an accepting state to a machine
--
-- accepting_number becomes mach's accepting number.

  procedure ADD_ACCEPT(MACH             : in out INTEGER; 
                       ACCEPTING_NUMBER : in INTEGER) is 
  -- hang the accepting number off an epsilon state.  if it is associated
  -- with a state that has a non-epsilon out-transition, then the state
  -- will accept BEFORE it makes that transition, i.e., one character
  -- too soon
    ASTATE : INTEGER; 
  begin
    if (TRANSCHAR(FINALST(MACH)) = SYM_EPSILON) then 
      ACCPTNUM(FINALST(MACH)) := ACCEPTING_NUMBER; 
    else 
      ASTATE := MKSTATE(SYM_EPSILON); 
      ACCPTNUM(ASTATE) := ACCEPTING_NUMBER; 
      MACH := LINK_MACHINES(MACH, ASTATE); 
    end if; 
  end ADD_ACCEPT; 


  -- copysingl - make a given number of copies of a singleton machine
  --
  --     newsng - a new singleton composed of num copies of singl
  --     singl  - a singleton machine
  --     num    - the number of copies of singl to be present in newsng

  function COPYSINGL(SINGL, NUM : in INTEGER) return INTEGER is 
    COPY : INTEGER; 
  begin
    COPY := MKSTATE(SYM_EPSILON); 

    for I in 1 .. NUM loop
      COPY := LINK_MACHINES(COPY, DUPMACHINE(SINGL)); 
    end loop; 

    return COPY; 
  end COPYSINGL; 


  -- dumpnfa - debugging routine to write out an nfa

  procedure DUMPNFA(STATE1 : in INTEGER) is 
    SYM, TSP1, TSP2, ANUM : INTEGER; 
    use TEXT_IO; 
  begin
    TEXT_IO.NEW_LINE(STANDARD_ERROR); 
    TEXT_IO.NEW_LINE(STANDARD_ERROR); 
    TEXT_IO.PUT(STANDARD_ERROR, 
      "********** beginning dump of nfa with start state "); 
    INT_IO.PUT(STANDARD_ERROR, STATE1, 0); 
    TEXT_IO.NEW_LINE(STANDARD_ERROR); 

    -- we probably should loop starting at firstst[state1] and going to
    -- lastst[state1], but they're not maintained properly when we "or"
    -- all of the rules together.  So we use our knowledge that the machine
    -- starts at state 1 and ends at lastnfa.
    for NS in 1 .. LASTNFA loop
      TEXT_IO.PUT(STANDARD_ERROR, "state # "); 
      INT_IO.PUT(STANDARD_ERROR, NS, 4); 
      TEXT_IO.PUT(ASCII.HT); 
      SYM := TRANSCHAR(NS); 
      TSP1 := TRANS1(NS); 
      TSP2 := TRANS2(NS); 
      ANUM := ACCPTNUM(NS); 

      INT_IO.PUT(STANDARD_ERROR, SYM, 5); 
      TEXT_IO.PUT(STANDARD_ERROR, ":    "); 
      INT_IO.PUT(STANDARD_ERROR, TSP1, 4); 
      TEXT_IO.PUT(STANDARD_ERROR, ","); 
      INT_IO.PUT(STANDARD_ERROR, TSP2, 4); 
      if (ANUM /= NIL) then 
        TEXT_IO.PUT(STANDARD_ERROR, "  ["); 
        INT_IO.PUT(STANDARD_ERROR, ANUM, 0); 
        TEXT_IO.PUT(STANDARD_ERROR, "]"); 
      end if; 
      TEXT_IO.NEW_LINE(STANDARD_ERROR); 
    end loop; 

    TEXT_IO.PUT(STANDARD_ERROR, "********** end of dump"); 
    TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  end DUMPNFA; 

  -- dupmachine - make a duplicate of a given machine
  --
  --     copy - holds duplicate of mach
  --     mach - machine to be duplicated
  --
  -- note that the copy of mach is NOT an exact duplicate; rather, all the
  -- transition states values are adjusted so that the copy is self-contained,
  -- as the original should have been.
  --
  -- also note that the original MUST be contiguous, with its low and high
  -- states accessible by the arrays firstst and lastst

  function DUPMACHINE(MACH : in INTEGER) return INTEGER is 
    INIT, STATE_OFFSET : INTEGER; 
    STATE              : INTEGER := 0; 
    LAST               : INTEGER := LASTST(MACH); 
    I                  : INTEGER; 
  begin
    I := FIRSTST(MACH); 
    while (I <= LAST) loop
      STATE := MKSTATE(TRANSCHAR(I)); 

      if (TRANS1(I) /= NO_TRANSITION) then 
        MKXTION(FINALST(STATE), TRANS1(I) + STATE - I); 

        if ((TRANSCHAR(I) = SYM_EPSILON) and (TRANS2(I) /= NO_TRANSITION)) then 
          MKXTION(FINALST(STATE), TRANS2(I) + STATE - I); 
        end if; 
      end if; 

      ACCPTNUM(STATE) := ACCPTNUM(I); 
      I := I + 1; 
    end loop; 

    if (STATE = 0) then 
      MISC.AFLEXFATAL("empty machine in dupmachine()"); 
    end if; 

    STATE_OFFSET := STATE - I + 1; 

    INIT := MACH + STATE_OFFSET; 
    FIRSTST(INIT) := FIRSTST(MACH) + STATE_OFFSET; 
    FINALST(INIT) := FINALST(MACH) + STATE_OFFSET; 
    LASTST(INIT) := LASTST(MACH) + STATE_OFFSET; 

    return INIT; 
  end DUPMACHINE; 

  -- finish_rule - finish up the processing for a rule
  --
  -- An accepting number is added to the given machine.  If variable_trail_rule
  -- is true then the rule has trailing context and both the head and trail
  -- are variable size.  Otherwise if headcnt or trailcnt is non-zero then
  -- the machine recognizes a pattern with trailing context and headcnt is
  -- the number of characters in the matched part of the pattern, or zero
  -- if the matched part has variable length.  trailcnt is the number of
  -- trailing context characters in the pattern, or zero if the trailing
  -- context has variable length.

  procedure FINISH_RULE(MACH                : in INTEGER; 
                        VARIABLE_TRAIL_RULE : in BOOLEAN; 
                        HEADCNT, TRAILCNT   : in INTEGER) is 
    P_MACH : INTEGER; 
    use TEXT_IO; 
  begin
    P_MACH := MACH; 
    ADD_ACCEPT(P_MACH, NUM_RULES); 

    -- we did this in new_rule(), but it often gets the wrong
    -- number because we do it before we start parsing the current rule
    RULE_LINENUM(NUM_RULES) := LINENUM; 

    TEXT_IO.PUT(TEMP_ACTION_FILE, "when "); 
    INT_IO.PUT(TEMP_ACTION_FILE, NUM_RULES, 1); 
    TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, " => "); 

    if (VARIABLE_TRAIL_RULE) then 
      RULE_TYPE(NUM_RULES) := RULE_VARIABLE; 

      if (PERFORMANCE_REPORT) then 
        TEXT_IO.PUT(STANDARD_ERROR, "Variable trailing context rule at line "); 
        INT_IO.PUT(STANDARD_ERROR, RULE_LINENUM(NUM_RULES), 1); 
        TEXT_IO.NEW_LINE(STANDARD_ERROR); 
      end if; 

      VARIABLE_TRAILING_CONTEXT_RULES := TRUE; 
    else 
      RULE_TYPE(NUM_RULES) := RULE_NORMAL; 

      if ((HEADCNT > 0) or (TRAILCNT > 0)) then 

        -- do trailing context magic to not match the trailing characters
        TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, 
          "yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext"
          ); 

        if (HEADCNT > 0) then 
          TEXT_IO.PUT(TEMP_ACTION_FILE, " yy_cp := yy_bp + "); 
          INT_IO.PUT(TEMP_ACTION_FILE, HEADCNT, 1); 
          TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, ";"); 
        else 
          TEXT_IO.PUT(TEMP_ACTION_FILE, "yy_cp := yy_cp - "); 
          INT_IO.PUT(TEMP_ACTION_FILE, TRAILCNT, 1); 
          TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, ";"); 
        end if; 

        TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, "yy_c_buf_p := yy_cp;"); 
        TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, 
          "YY_DO_BEFORE_ACTION; -- set up yytext again"); 
      end if; 
    end if; 

    MISC.LINE_DIRECTIVE_OUT(TEMP_ACTION_FILE); 
  end FINISH_RULE; 

  -- link_machines - connect two machines together
  --
  --     new    - a machine constructed by connecting first to last
  --     first  - the machine whose successor is to be last
  --     last   - the machine whose predecessor is to be first
  --
  -- note: this routine concatenates the machine first with the machine
  --  last to produce a machine new which will pattern-match first first
  --  and then last, and will fail if either of the sub-patterns fails.
  --  FIRST is set to new by the operation.  last is unmolested.

  function LINK_MACHINES(FIRST, LAST : in INTEGER) return INTEGER is 
  begin
    if (FIRST = NIL) then 
      return LAST; 
    else 
      if (LAST = NIL) then 
        return FIRST; 
      else 
        MKXTION(FINALST(FIRST), LAST); 
        FINALST(FIRST) := FINALST(LAST); 
        LASTST(FIRST) := MAX(LASTST(FIRST), LASTST(LAST)); 
        FIRSTST(FIRST) := MIN(FIRSTST(FIRST), FIRSTST(LAST)); 
        return (FIRST); 
      end if; 
    end if; 
  end LINK_MACHINES; 


  -- mark_beginning_as_normal - mark each "beginning" state in a machine
--                            as being a "normal" (i.e., not trailing context-
  --                            associated) states
  --
  -- The "beginning" states are the epsilon closure of the first state

  procedure MARK_BEGINNING_AS_NORMAL(MACH : in INTEGER) is 
  begin
    case (STATE_TYPE(MACH)) is 
      when STATE_NORMAL => 

        -- oh, we've already visited here
        return; 

      when STATE_TRAILING_CONTEXT => 
        STATE_TYPE(MACH) := STATE_NORMAL; 

        if (TRANSCHAR(MACH) = SYM_EPSILON) then 
          if (TRANS1(MACH) /= NO_TRANSITION) then 
            MARK_BEGINNING_AS_NORMAL(TRANS1(MACH)); 
          end if; 

          if (TRANS2(MACH) /= NO_TRANSITION) then 
            MARK_BEGINNING_AS_NORMAL(TRANS2(MACH)); 
          end if; 
        end if; 
      when others => 
        MISC.AFLEXERROR("bad state type in mark_beginning_as_normal()"); 
    end case; 
  end MARK_BEGINNING_AS_NORMAL; 

  -- mkbranch - make a machine that branches to two machines
  --
  --     branch - a machine which matches either first's pattern or second's
--     first, second - machines whose patterns are to be or'ed (the | operator)
  --
  -- note that first and second are NEITHER destroyed by the operation.  Also,
  -- the resulting machine CANNOT be used with any other "mk" operation except
  -- more mkbranch's.  Compare with mkor()
  function MKBRANCH(FIRST, SECOND : in INTEGER) return INTEGER is 
    EPS : INTEGER; 
  begin
    if (FIRST = NO_TRANSITION) then 
      return SECOND; 
    else 
      if (SECOND = NO_TRANSITION) then 
        return FIRST; 
      end if; 
    end if; 

    EPS := MKSTATE(SYM_EPSILON); 

    MKXTION(EPS, FIRST); 
    MKXTION(EPS, SECOND); 

    return EPS; 
  end MKBRANCH; 


  -- mkclos - convert a machine into a closure
  --
  --     new - a new state which matches the closure of "state"

  function MKCLOS(STATE : in INTEGER) return INTEGER is 
  begin
    return NFA.MKOPT(MKPOSCL(STATE)); 
  end MKCLOS; 


  -- mkopt - make a machine optional
  --
  --     new  - a machine which optionally matches whatever mach matched
  --     mach - the machine to make optional
  --
  -- notes:
  --     1. mach must be the last machine created
  --     2. mach is destroyed by the call

  function MKOPT(MACH : in INTEGER) return INTEGER is 
    EPS    : INTEGER; 
    RESULT : INTEGER; 
  begin
    RESULT := MACH; 
    if (not SUPER_FREE_EPSILON(FINALST(RESULT))) then 
      EPS := NFA.MKSTATE(SYM_EPSILON); 
      RESULT := NFA.LINK_MACHINES(RESULT, EPS); 
    end if; 

    -- can't skimp on the following if FREE_EPSILON(mach) is true because
    -- some state interior to "mach" might point back to the beginning
    -- for a closure
    EPS := NFA.MKSTATE(SYM_EPSILON); 
    RESULT := NFA.LINK_MACHINES(EPS, RESULT); 

    NFA.MKXTION(RESULT, FINALST(RESULT)); 

    return RESULT; 
  end MKOPT; 


  -- mkor - make a machine that matches either one of two machines
  --
  --     new - a machine which matches either first's pattern or second's
--     first, second - machines whose patterns are to be or'ed (the | operator)
  --
  -- note that first and second are both destroyed by the operation
  -- the code is rather convoluted because an attempt is made to minimize
  -- the number of epsilon states needed

  function MKOR(FIRST, SECOND : in INTEGER) return INTEGER is 
    EPS, OREND : INTEGER; 
    P_FIRST    : INTEGER; 
  begin
    P_FIRST := FIRST; 
    if (P_FIRST = NIL) then 
      return SECOND; 
    else 
      if (SECOND = NIL) then 
        return P_FIRST; 
      else 

        -- see comment in mkopt() about why we can't use the first state
        -- of "first" or "second" if they satisfy "FREE_EPSILON"
        EPS := MKSTATE(SYM_EPSILON); 

        P_FIRST := LINK_MACHINES(EPS, P_FIRST); 

        MKXTION(P_FIRST, SECOND); 

        if ((SUPER_FREE_EPSILON(FINALST(P_FIRST))) and (ACCPTNUM(FINALST(P_FIRST
          )) = NIL)) then 
          OREND := FINALST(P_FIRST); 
          MKXTION(FINALST(SECOND), OREND); 
        else 
          if ((SUPER_FREE_EPSILON(FINALST(SECOND))) and (ACCPTNUM(FINALST(SECOND
            )) = NIL)) then 
            OREND := FINALST(SECOND); 
            MKXTION(FINALST(P_FIRST), OREND); 
          else 
            EPS := MKSTATE(SYM_EPSILON); 
            P_FIRST := LINK_MACHINES(P_FIRST, EPS); 
            OREND := FINALST(P_FIRST); 

            MKXTION(FINALST(SECOND), OREND); 
          end if; 
        end if; 
      end if; 
    end if; 

    FINALST(P_FIRST) := OREND; 
    return P_FIRST; 
  end MKOR; 


  -- mkposcl - convert a machine into a positive closure
  --
  --    new - a machine matching the positive closure of "state"

  function MKPOSCL(STATE : in INTEGER) return INTEGER is 
    EPS : INTEGER; 
  begin
    if (SUPER_FREE_EPSILON(FINALST(STATE))) then 
      MKXTION(FINALST(STATE), STATE); 
      return (STATE); 
    else 
      EPS := MKSTATE(SYM_EPSILON); 
      MKXTION(EPS, STATE); 
      return (LINK_MACHINES(STATE, EPS)); 
    end if; 
  end MKPOSCL; 

  -- mkrep - make a replicated machine
  --
  --    new - a machine that matches whatever "mach" matched from "lb"
  --          number of times to "ub" number of times
  --
  -- note
--   if "ub" is INFINITY then "new" matches "lb" or more occurrences of "mach"

  function MKREP(MACH, LB, UB : in INTEGER) return INTEGER is 
    BASE_MACH, TAIL, COPY : INTEGER; 
    P_MACH                : INTEGER; 
  begin
    P_MACH := MACH; 
    BASE_MACH := COPYSINGL(P_MACH, LB - 1); 

    if (UB = INFINITY) then 
      COPY := DUPMACHINE(P_MACH); 
      P_MACH := LINK_MACHINES(P_MACH, LINK_MACHINES(BASE_MACH, MKCLOS(COPY))); 
    else 
      TAIL := MKSTATE(SYM_EPSILON); 

      for I in LB .. UB - 1 loop
        COPY := DUPMACHINE(P_MACH); 
        TAIL := MKOPT(LINK_MACHINES(COPY, TAIL)); 
      end loop; 

      P_MACH := LINK_MACHINES(P_MACH, LINK_MACHINES(BASE_MACH, TAIL)); 
    end if; 

    return P_MACH; 
  end MKREP; 

  -- mkstate - create a state with a transition on a given symbol
  --
  --     state - a new state matching sym
  --     sym   - the symbol the new state is to have an out-transition on
  --
  -- note that this routine makes new states in ascending order through the
  -- state array (and increments LASTNFA accordingly).  The routine DUPMACHINE
  -- relies on machines being made in ascending order and that they are
  -- CONTIGUOUS.  Change it and you will have to rewrite DUPMACHINE (kludge
  -- that it admittedly is)

  function MKSTATE(SYM : in INTEGER) return INTEGER is 
  begin
    LASTNFA := LASTNFA + 1; 
    if (LASTNFA >= CURRENT_MNS) then 
      CURRENT_MNS := CURRENT_MNS + MNS_INCREMENT; 
      if (CURRENT_MNS >= MAXIMUM_MNS) then 
        MISC.AFLEXERROR("input rules are too complicated (>= " & INTEGER'IMAGE(
          CURRENT_MNS) & " NFA states) )"); 
      end if; 

      NUM_REALLOCS := NUM_REALLOCS + 1; 

      REALLOCATE_INTEGER_ARRAY(FIRSTST, CURRENT_MNS); 
      REALLOCATE_INTEGER_ARRAY(LASTST, CURRENT_MNS); 
      REALLOCATE_INTEGER_ARRAY(FINALST, CURRENT_MNS); 
      REALLOCATE_INTEGER_ARRAY(TRANSCHAR, CURRENT_MNS); 
      REALLOCATE_INTEGER_ARRAY(TRANS1, CURRENT_MNS); 
      REALLOCATE_INTEGER_ARRAY(TRANS2, CURRENT_MNS); 
      REALLOCATE_INTEGER_ARRAY(ACCPTNUM, CURRENT_MNS); 
      REALLOCATE_INTEGER_ARRAY(ASSOC_RULE, CURRENT_MNS); 
      REALLOCATE_STATE_ENUM_ARRAY(STATE_TYPE, CURRENT_MNS); 
    end if; 

    FIRSTST(LASTNFA) := LASTNFA; 
    FINALST(LASTNFA) := LASTNFA; 
    LASTST(LASTNFA) := LASTNFA; 
    TRANSCHAR(LASTNFA) := SYM; 
    TRANS1(LASTNFA) := NO_TRANSITION; 
    TRANS2(LASTNFA) := NO_TRANSITION; 
    ACCPTNUM(LASTNFA) := NIL; 
    ASSOC_RULE(LASTNFA) := NUM_RULES; 
    STATE_TYPE(LASTNFA) := CURRENT_STATE_ENUM; 

    -- fix up equivalence classes base on this transition.  Note that any
    -- character which has its own transition gets its own equivalence class.
    -- Thus only characters which are only in character classes have a chance
    -- at being in the same equivalence class.  E.g. "a|b" puts 'a' and 'b'
    -- into two different equivalence classes.  "[ab]" puts them in the same
    -- equivalence class (barring other differences elsewhere in the input).
    if (SYM < 0) then 

      -- we don't have to update the equivalence classes since that was
      -- already done when the ccl was created for the first time
      null; 
    else 
      if (SYM = SYM_EPSILON) then 
        NUMEPS := NUMEPS + 1; 
      else 
        if (USEECS) then 
          ECS.MKECHAR(SYM, NEXTECM, ECGROUP); 
        end if; 
      end if; 
    end if; 

    return LASTNFA; 
  end MKSTATE; 

  -- mkxtion - make a transition from one state to another
  --
  --     statefrom - the state from which the transition is to be made
  --     stateto   - the state to which the transition is to be made

  procedure MKXTION(STATEFROM, STATETO : in INTEGER) is 
  begin
    if (TRANS1(STATEFROM) = NO_TRANSITION) then 
      TRANS1(STATEFROM) := STATETO; 
    else 
      if ((TRANSCHAR(STATEFROM) /= SYM_EPSILON) or (TRANS2(STATEFROM) /= 
        NO_TRANSITION)) then 
        MISC.AFLEXFATAL("found too many transitions in mkxtion()"); 
      else 

        -- second out-transition for an epsilon state
        EPS2 := EPS2 + 1; 
        TRANS2(STATEFROM) := STATETO; 
      end if; 
    end if; 
  end MKXTION; 

  -- new_rule - initialize for a new rule
  --
  -- the global num_rules is incremented and the any corresponding dynamic
  -- arrays (such as rule_type()) are grown as needed.

  procedure NEW_RULE is 
  begin
    NUM_RULES := NUM_RULES + 1; 
    if (NUM_RULES >= CURRENT_MAX_RULES) then 
      NUM_REALLOCS := NUM_REALLOCS + 1; 
      CURRENT_MAX_RULES := CURRENT_MAX_RULES + MAX_RULES_INCREMENT; 
      REALLOCATE_RULE_ENUM_ARRAY(RULE_TYPE, CURRENT_MAX_RULES); 
      REALLOCATE_INTEGER_ARRAY(RULE_LINENUM, CURRENT_MAX_RULES); 
    end if; 

    if (NUM_RULES > MAX_RULE) then 
      MISC.AFLEXERROR("too many rules  (> " & INTEGER'IMAGE(MAX_RULE) & ")!"); 
    end if; 

    RULE_LINENUM(NUM_RULES) := LINENUM; 
  end NEW_RULE; 

end NFA; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE NFA construction routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION builds the NFA.
-- NOTES this file mirrors flex as closely as possible.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/nfaS.a,v 1.4 90/01/12 15:20:30 self Exp Locker: self $ 

package NFA is 
  procedure ADD_ACCEPT(MACH             : in out INTEGER; 
                       ACCEPTING_NUMBER : in INTEGER); 
  function COPYSINGL(SINGL, NUM : in INTEGER) return INTEGER; 
  procedure DUMPNFA(STATE1 : in INTEGER); 
  function DUPMACHINE(MACH : in INTEGER) return INTEGER; 
  procedure FINISH_RULE(MACH                : in INTEGER; 
                        VARIABLE_TRAIL_RULE : in BOOLEAN; 
                        HEADCNT, TRAILCNT   : in INTEGER); 
  function LINK_MACHINES(FIRST, LAST : in INTEGER) return INTEGER; 
  procedure MARK_BEGINNING_AS_NORMAL(MACH : in INTEGER); 
  function MKBRANCH(FIRST, SECOND : in INTEGER) return INTEGER; 
  function MKCLOS(STATE : in INTEGER) return INTEGER; 
  function MKOPT(MACH : in INTEGER) return INTEGER; 
  function MKOR(FIRST, SECOND : in INTEGER) return INTEGER; 
  function MKPOSCL(STATE : in INTEGER) return INTEGER; 
  function MKREP(MACH, LB, UB : in INTEGER) return INTEGER; 
  function MKSTATE(SYM : in INTEGER) return INTEGER; 
  procedure MKXTION(STATEFROM, STATETO : in INTEGER); 
  procedure NEW_RULE; 
end NFA; 

with Parse_Tokens, Parse_Goto, Parse_Shift_Reduce, Text_IO, scanner;
with NFA, ccl, misc, misc_defs, sym, ecs, aflex_scanner;
with tstring, int_io, main_body, text_io, external_file_manager;
use aflex_scanner, external_file_manager;

package parser is
  procedure build_eof_action;
  procedure yyerror(msg: string);
  procedure YYParse;
  def_rule:integer;
end parser;

package body parser is
-- build_eof_action - build the "<<EOF>>" action for the active start
--                    conditions

use text_io, misc_defs;
procedure build_eof_action is
begin
    text_io.put( temp_action_file, "when " );
    for i in 1..actvp loop
	if ( sceof(actvsc(i)) ) then
	    text_io.put( Standard_Error,
		"multiple <<EOF>> rules for start condition ");
	    tstring.put( Standard_Error, scname(actvsc(i)));
	    main_body.aflexend(1);
	else
	    sceof(actvsc(i)) := true;
	    text_io.put( temp_action_file, "YY_END_OF_BUFFER +" );
	    tstring.put( temp_action_file,  scname(actvsc(i)) );
	    text_io.put_line( temp_action_file, " + 1 " );
	    if (i /= actvp) then
	        text_io.put_line( temp_action_file, " |" );
	    else
	        text_io.put_line( temp_action_file, " =>" );
	    end if;
        end if;
    end loop;
    misc.line_directive_out( temp_action_file );
end build_eof_action;

--  yyerror - eat up an error message from the parser
-- 
--  synopsis
--     char msg[];
--     yyerror( msg );

procedure yyerror( msg : string ) is
begin
null;
end yyerror;

use  Parse_Goto, Parse_Shift_Reduce, Text_IO, misc_defs, tstring;
procedure YYParse is

   -- Rename User Defined Packages to Internal Names.
    package yy_goto_tables         renames
      Parse_Goto;
    package yy_shift_reduce_tables renames
      Parse_Shift_Reduce;
    package yy_tokens              renames
      Parse_Tokens;

   use yy_tokens, yy_goto_tables, yy_shift_reduce_tables;

   procedure yyerrok;
   procedure yyclearin;

   package yy is

       -- the size of the value and state stacks
       stack_size : constant Natural := 300;

       -- subtype rule         is natural;
       subtype parse_state  is natural;
       -- subtype nonterminal  is integer;

       -- encryption constants
       default           : constant := -1;
       first_shift_entry : constant :=  0;
       accept_code       : constant := -1001;
       error_code        : constant := -1000;

       -- stack data used by the parser
       tos                : natural := 0;
       value_stack        : array(0..stack_size) of yy_tokens.yystype;
       state_stack        : array(0..stack_size) of parse_state;

       -- current input symbol and action the parser is on
       action             : integer;
       rule_id            : rule;
       input_symbol       : yy_tokens.token;


       -- error recovery flag
       error_flag : natural := 0;
          -- indicates  3 - (number of valid shifts after an error occurs)

       look_ahead : boolean := true;
       index      : integer;

       -- Is Debugging option on or off
        DEBUG : constant boolean := FALSE;

    end yy;


    function goto_state
      (state : yy.parse_state;
       sym   : nonterminal) return yy.parse_state;

    function parse_action
      (state : yy.parse_state;
       t     : yy_tokens.token) return integer;

    pragma inline(goto_state, parse_action);


    function goto_state(state : yy.parse_state;
                        sym   : nonterminal) return yy.parse_state is
        index : integer;
    begin
        index := goto_offset(state);
        while  integer(goto_matrix(index).nonterm) /= sym loop
            index := index + 1;
        end loop;
        return integer(goto_matrix(index).newstate);
    end goto_state;


    function parse_action(state : yy.parse_state;
                          t     : yy_tokens.token) return integer is
        index      : integer;
        tok_pos    : integer;
        default    : constant integer := -1;
    begin
        tok_pos := yy_tokens.token'pos(t);
        index   := shift_reduce_offset(state);
        while integer(shift_reduce_matrix(index).t) /= tok_pos and then
              integer(shift_reduce_matrix(index).t) /= default
        loop
            index := index + 1;
        end loop;
        return integer(shift_reduce_matrix(index).act);
    end parse_action;

-- error recovery stuff

    procedure handle_error is
      temp_action : integer;
    begin

      if yy.error_flag = 3 then -- no shift yet, clobber input.
      if yy.debug then
          put_line("Ayacc.YYParse: Error Recovery Clobbers " &
                   yy_tokens.token'image(yy.input_symbol));
      end if;
        if yy.input_symbol = yy_tokens.end_of_input then  -- don't discard,
        if yy.debug then
            put_line("Ayacc.YYParse: Can't discard END_OF_INPUT, quiting...");
        end if;
        raise yy_tokens.syntax_error;
        end if;

            yy.look_ahead := true;   -- get next token
        return;                  -- and try again...
    end if;

    if yy.error_flag = 0 then -- brand new error
        yyerror("Syntax Error");
    end if;

    yy.error_flag := 3;

    -- find state on stack where error is a valid shift --

    if yy.debug then
        put_line("Ayacc.YYParse: Looking for state with error as valid shift");
    end if;

    loop
        if yy.debug then
        put_line("Ayacc.YYParse: Examining State " &
              yy.parse_state'image(yy.state_stack(yy.tos)));
        end if;
        temp_action := parse_action(yy.state_stack(yy.tos), error);

            if temp_action >= yy.first_shift_entry then
                yy.tos := yy.tos + 1;
                yy.state_stack(yy.tos) := temp_action;
                exit;
            end if;

        Decrement_Stack_Pointer :
        begin
          yy.tos := yy.tos - 1;
        exception
          when Constraint_Error =>
            yy.tos := 0;
        end Decrement_Stack_Pointer;

        if yy.tos = 0 then
          if yy.debug then
            put_line("Ayacc.YYParse: Error recovery popped entire stack, aborting...");
          end if;
          raise yy_tokens.syntax_error;
        end if;
    end loop;

    if yy.debug then
        put_line("Ayacc.YYParse: Shifted error token in state " &
              yy.parse_state'image(yy.state_stack(yy.tos)));
    end if;

    end handle_error;

   -- print debugging information for a shift operation
   procedure shift_debug(state_id: yy.parse_state; lexeme: yy_tokens.token) is
   begin
       put_line("Ayacc.YYParse: Shift "& yy.parse_state'image(state_id)&" on input symbol "&
               yy_tokens.token'image(lexeme) );
   end;

   -- print debugging information for a reduce operation
   procedure reduce_debug(rule_id: rule; state_id: yy.parse_state) is
   begin
       put_line("Ayacc.YYParse: Reduce by rule "&rule'image(rule_id)&" goto state "&
               yy.parse_state'image(state_id));
   end;

   -- make the parser believe that 3 valid shifts have occured.
   -- used for error recovery.
   procedure yyerrok is
   begin
       yy.error_flag := 0;
   end yyerrok;

   -- called to clear input symbol that caused an error.
   procedure yyclearin is
   begin
       -- yy.input_symbol := yylex;
       yy.look_ahead := true;
   end yyclearin;


begin
    -- initialize by pushing state 0 and getting the first input symbol
    yy.state_stack(yy.tos) := 0;

    loop

        yy.index := shift_reduce_offset(yy.state_stack(yy.tos));
        if integer(shift_reduce_matrix(yy.index).t) = yy.default then
            yy.action := integer(shift_reduce_matrix(yy.index).act);
        else
            if yy.look_ahead then
                yy.look_ahead   := false;
                yy.input_symbol := yylex;
            end if;
            yy.action :=
             parse_action(yy.state_stack(yy.tos), yy.input_symbol);
        end if;

        if yy.action >= yy.first_shift_entry then  -- SHIFT

            if yy.debug then
                shift_debug(yy.action, yy.input_symbol);
            end if;

            -- Enter new state
            yy.tos := yy.tos + 1;
            yy.state_stack(yy.tos) := yy.action;
            yy.value_stack(yy.tos) := yylval;

        if yy.error_flag > 0 then  -- indicate a valid shift
            yy.error_flag := yy.error_flag - 1;
        end if;

            -- Advance lookahead
            yy.look_ahead := true;

        elsif yy.action = yy.error_code then       -- ERROR
            handle_error;

        elsif yy.action = yy.accept_code then
            if yy.debug then
                put_line("Ayacc.YYParse: Accepting Grammar...");
            end if;
            exit;

        else -- Reduce Action

            -- Convert action into a rule
            yy.rule_id  := -1 * yy.action;

            -- Execute User Action
            -- user_action(yy.rule_id);
            case yy.rule_id is

when  1 =>
--#line  44
 -- add default rule

			pat := ccl.cclinit;
			ccl.cclnegate( pat );

			def_rule := nfa.mkstate( -pat );

			nfa.finish_rule( def_rule, false, 0, 0 );

			for i in 1 .. lastsc loop
			    scset(i) := nfa.mkbranch( scset(i), def_rule );
			end loop;
			
			if ( spprdflt ) then
			    text_io.put(temp_action_file,
					"raise AFLEX_SCANNER_JAMMED;");
			else
			    text_io.put( temp_action_file, "ECHO" );

			text_io.put_line( temp_action_file, ";" );
			end if;
			

when  2 =>
--#line  69

			-- initialize for processing rules

       			-- create default DFA start condition
			sym.scinstal( tstring.vstr("INITIAL"), false );
			

when  5 =>
--#line  80
 misc.synerr( "unknown error processing section 1" );

when  7 =>
--#line  87

			 -- these productions are separate from the s1object
			 -- rule because the semantics must be done before
			 -- we parse the remainder of an s1object
			

			xcluflg := false;
			

when  8 =>
--#line  97
 xcluflg := true; 

when  9 =>
--#line  101
 sym.scinstal( nmstr, xcluflg ); 

when  10 =>
--#line  104
 sym.scinstal( nmstr, xcluflg ); 

when  11 =>
--#line  107
 misc.synerr( "bad start condition list" ); 

when  14 =>
--#line  115

			-- initialize for a parse of one rule
			trlcontxt := false;
			variable_trail_rule := false;
			varlength := false;
			trailcnt := 0;
			headcnt := 0;
			rulelen := 0;
			current_state_enum := STATE_NORMAL;
			previous_continued_action := continued_action;
			nfa.new_rule;
			

when  15 =>
--#line  130

			pat := nfa.link_machines( 
yy.value_stack(yy.tos-1), 
yy.value_stack(yy.tos) );
			nfa.finish_rule( pat, variable_trail_rule,
				     headcnt, trailcnt );

			for i in 1 .. actvp loop
			    scbol(actvsc(i)) :=
				nfa.mkbranch( scbol(actvsc(i)), pat );
			end loop;	
				
			if ( not bol_needed ) then
			    bol_needed := true;

			    if ( performance_report ) then
				text_io.put( Standard_Error,
			"'^' operator results in sub-optimal performance");
			        text_io.new_line(Standard_Error);
    	    	    	    end if;
			end if;
			

when  16 =>
--#line  152

			pat := nfa.link_machines( 
yy.value_stack(yy.tos-1), 
yy.value_stack(yy.tos) );
			nfa.finish_rule( pat, variable_trail_rule,
				     headcnt, trailcnt );

			for i in 1 .. actvp loop
			    scset(actvsc(i)) := 
				nfa.mkbranch( scset(actvsc(i)), pat );
			end loop;
		        

when  17 =>
--#line  163

			pat := nfa.link_machines( 
yy.value_stack(yy.tos-1), 
yy.value_stack(yy.tos) );
			nfa.finish_rule( pat, variable_trail_rule,
				     headcnt, trailcnt );

			-- add to all non-exclusive start conditions,
			-- including the default (0) start condition

			for i in 1 .. lastsc loop
			    if ( not scxclu(i) ) then
				scbol(i) := nfa.mkbranch( scbol(i), pat );
			    end if;	
			end loop;

			if ( not bol_needed ) then
			    bol_needed := true;

			    if ( performance_report ) then
				text_io.put( Standard_Error,
			"'^' operator results in sub-optimal performance");
			        text_io.new_line(Standard_Error);
			    end if;
			end if;
    	    	    	

when  18 =>
--#line  188

			pat := nfa.link_machines( 
yy.value_stack(yy.tos-1), 
yy.value_stack(yy.tos) );
			nfa.finish_rule( pat, variable_trail_rule,
				     headcnt, trailcnt );

			for i in 1 .. lastsc loop
			    if ( not scxclu(i) ) then
				scset(i) := nfa.mkbranch( scset(i), pat );
			    end if;
			end loop;
			

when  19 =>
--#line  201
 build_eof_action; 

when  20 =>
--#line  204

			-- this EOF applies only to the INITIAL start cond.
			actvp := 1;
			actvsc(actvp) := 1;
			build_eof_action;
			

when  21 =>
--#line  212
 misc.synerr( "unrecognized rule" ); 

when  23 =>
--#line  219

			scnum := sym.sclookup( nmstr );
			if (scnum = 0 ) then
		            text_io.put( Standard_Error,
					 "undeclared start condition ");
		            tstring.put( Standard_Error, nmstr );
			    main_body.aflexend( 1 );
			else
			  actvp := actvp + 1;
			    actvsc(actvp) := scnum;
			end if;
			

when  24 =>
--#line  233

			scnum := sym.sclookup( nmstr );
			if (scnum = 0 ) then
		            text_io.put( Standard_Error,
					"undeclared start condition ");
		            tstring.put( Standard_Error,	 nmstr );
			    main_body.aflexend ( 1 );
			else
			    actvp := 1;
			    actvsc(actvp) := scnum;
			end if;
			

when  25 =>
--#line  247
 misc.synerr( "bad start condition list" ); 

when  26 =>
--#line  251

			if trlcontxt then
			    misc.synerr( "trailing context used twice" );
			    
yyval := nfa.mkstate( SYM_EPSILON );
			else
			    trlcontxt := true;

			    if ( not varlength ) then
				headcnt := rulelen;
			    end if;

			    rulelen := rulelen + 1;
			    trailcnt := 1;

			    eps := nfa.mkstate( SYM_EPSILON );
			    
yyval := nfa.link_machines( eps,
					  nfa.mkstate( CHARACTER'POS(ASCII.LF) ) );
    	    	    	end if;
			

when  27 =>
--#line  272

		        
yyval := nfa.mkstate( SYM_EPSILON );

			if ( trlcontxt ) then
			    if ( varlength and (headcnt = 0) ) then
				-- both head and trail are variable-length
				variable_trail_rule := true;
			    else
				trailcnt := rulelen;
			    end if;
    	    	    	end if;
		        

when  28 =>
--#line  287

			varlength := true;

			
yyval := nfa.mkor( 
yy.value_stack(yy.tos-2), 
yy.value_stack(yy.tos) );
			

when  29 =>
--#line  294

			if ( transchar(lastst(
yy.value_stack(yy.tos))) /= SYM_EPSILON ) then
			    -- provide final transition \now/ so it
			    -- will be marked as a trailing context
			    -- state

			    
yy.value_stack(yy.tos) := nfa.link_machines( 
yy.value_stack(yy.tos), nfa.mkstate( SYM_EPSILON ) );
			end if;

			nfa.mark_beginning_as_normal( 
yy.value_stack(yy.tos) );
			current_state_enum := STATE_NORMAL;

			if ( previous_continued_action ) then
			    -- we need to treat this as variable trailing
			    -- context so that the backup does not happen
			    -- in the action but before the action switch
			    -- statement.  If the backup happens in the
			    -- action, then the rules "falling into" this
			    -- one's action will *also* do the backup,
			    -- erroneously.

			    	if ( (not varlength) or  headcnt /= 0 ) then
				     text_io.put( Standard_Error,
                              "alex: warning - trailing context rule at line");
                                     int_io.put(Standard_Error, linenum);
				     text_io.put( Standard_Error,
                           "made variable because of preceding '|' action" );
                                     int_io.put(Standard_Error, linenum);
    	    	    	    	end if;

			    -- mark as variable
			    varlength := true;
			    headcnt := 0;
    	    	    	end if;
			
			if ( varlength and (headcnt = 0) ) then
			    -- variable trailing context rule
			    -- mark the first part of the rule as the accepting
			    -- "head" part of a trailing context rule

			    -- by the way, we didn't do this at the beginning
			    -- of this production because back then
			    -- current_state_enum was set up for a trail
			    -- rule, and add_accept() can create a new
			    -- state ...

			    nfa.add_accept( 
yy.value_stack(yy.tos-1),
    	    	    	    	   misc.set_yy_trailing_head_mask(num_rules) );
    	    	    	end if;

			
yyval := nfa.link_machines( 
yy.value_stack(yy.tos-1), 
yy.value_stack(yy.tos) );
			

when  30 =>
--#line  348
 
yyval := 
yy.value_stack(yy.tos); 

when  31 =>
--#line  353

			-- this rule is separate from the others for "re" so
			-- that the reduction will occur before the trailing
			-- series is parsed

			if ( trlcontxt ) then
			    misc.synerr( "trailing context used twice" );
			else
			    trlcontxt := true;
			end if;    

			if ( varlength ) then
			    -- we hope the trailing context is fixed-length
			    varlength := false;
			else
			    headcnt := rulelen;
			end if;    

			rulelen := 0;

			current_state_enum := STATE_TRAILING_CONTEXT;
			
yyval := 
yy.value_stack(yy.tos-1);
			

when  32 =>
--#line  379

			-- this is where concatenation of adjacent patterns
			-- gets done

			
yyval := nfa.link_machines( 
yy.value_stack(yy.tos-1), 
yy.value_stack(yy.tos) );
			

when  33 =>
--#line  387
 
yyval := 
yy.value_stack(yy.tos); 

when  34 =>
--#line  391

			varlength := true;

			
yyval := nfa.mkclos( 
yy.value_stack(yy.tos-1) );
			

when  35 =>
--#line  398

			varlength := true;

			
yyval := nfa.mkposcl( 
yy.value_stack(yy.tos-1) );
			

when  36 =>
--#line  405

			varlength := true;

			
yyval := nfa.mkopt( 
yy.value_stack(yy.tos-1) );
			

when  37 =>
--#line  412

			varlength := true;

			if ( (
yy.value_stack(yy.tos-3) > 
yy.value_stack(yy.tos-1)) or (
yy.value_stack(yy.tos-3) < 0) ) then
			    misc.synerr( "bad iteration values" );
			    
yyval := 
yy.value_stack(yy.tos-5);
			else
			    if ( 
yy.value_stack(yy.tos-3) = 0 ) then
				
yyval := nfa.mkopt( nfa.mkrep( 
yy.value_stack(yy.tos-5), 
yy.value_stack(yy.tos-3), 
yy.value_stack(yy.tos-1) ) );
			    else
				
yyval := nfa.mkrep( 
yy.value_stack(yy.tos-5), 
yy.value_stack(yy.tos-3), 
yy.value_stack(yy.tos-1) );
			    end if;
    	    	    	end if;
			

when  38 =>
--#line  428

			varlength := true;

			if ( 
yy.value_stack(yy.tos-2) <= 0 ) then
			    misc.synerr( "iteration value must be positive" );
			    
yyval := 
yy.value_stack(yy.tos-4);
			else
			    
yyval := nfa.mkrep( 
yy.value_stack(yy.tos-4), 
yy.value_stack(yy.tos-2), INFINITY );
			end if;    
			

when  39 =>
--#line  440

			-- the singleton could be something like "(foo)",
			-- in which case we have no idea what its length
			-- is, so we punt here.

			varlength := true;

			if ( 
yy.value_stack(yy.tos-1) <= 0 ) then
			    misc.synerr( "iteration value must be positive" );
			    
yyval := 
yy.value_stack(yy.tos-3);
			else
			    
yyval := nfa.link_machines( 
yy.value_stack(yy.tos-3), nfa.copysingl( 
yy.value_stack(yy.tos-3), 
yy.value_stack(yy.tos-1) - 1 ) );
			end if;    
			

when  40 =>
--#line  456

			if ( not madeany ) then
			    -- create the '.' character class
			    anyccl := ccl.cclinit;
			    ccl.ccladd( anyccl, ASCII.LF );
			    ccl.cclnegate( anyccl );

			    if ( useecs ) then
				ecs.mkeccl(
		       ccltbl(cclmap(anyccl)..cclmap(anyccl) + ccllen(anyccl)),
					ccllen(anyccl), nextecm,
					ecgroup, CSIZE );
			    end if;
			    madeany := true;
    	    	    	end if;

			rulelen := rulelen + 1;

			
yyval := nfa.mkstate( -anyccl );
			

when  41 =>
--#line  478

			if ( not cclsorted ) then
			    -- sort characters for fast searching.  We use a
			    -- shell sort since this list could be large.

--			    misc.cshell( ccltbl + cclmap($1), ccllen($1) );
		      misc.cshell( ccltbl(cclmap(
yy.value_stack(yy.tos))..cclmap(
yy.value_stack(yy.tos)) + ccllen(
yy.value_stack(yy.tos))),
				   ccllen(
yy.value_stack(yy.tos)) );
			end if;

			if ( useecs ) then
		    ecs.mkeccl( ccltbl(cclmap(
yy.value_stack(yy.tos))..cclmap(
yy.value_stack(yy.tos)) + ccllen(
yy.value_stack(yy.tos))),
				ccllen(
yy.value_stack(yy.tos)),nextecm, ecgroup, CSIZE );
			end if;
				     
			rulelen := rulelen + 1;

			
yyval := nfa.mkstate( -
yy.value_stack(yy.tos) );
			

when  42 =>
--#line  499

			rulelen := rulelen + 1;

			
yyval := nfa.mkstate( -
yy.value_stack(yy.tos) );
			

when  43 =>
--#line  506
 
yyval := 
yy.value_stack(yy.tos-1); 

when  44 =>
--#line  509
 
yyval := 
yy.value_stack(yy.tos-1); 

when  45 =>
--#line  512

			rulelen := rulelen + 1;

			if ( 
yy.value_stack(yy.tos) = CHARACTER'POS(ASCII.NUL) ) then
			    misc.synerr( "null in rule" );
			end if;    

			if ( caseins and (
yy.value_stack(yy.tos) >= CHARACTER'POS('A')) and (
yy.value_stack(yy.tos) <= CHARACTER'POS('Z')) ) then
			    
yy.value_stack(yy.tos) := misc.clower( 
yy.value_stack(yy.tos) );
			end if;

			
yyval := nfa.mkstate( 
yy.value_stack(yy.tos) );
			

when  46 =>
--#line  528
 
yyval := 
yy.value_stack(yy.tos-1); 

when  47 =>
--#line  531

			-- *Sigh* - to be compatible Unix lex, negated ccls
			-- match newlines
			ccl.cclnegate( 
yy.value_stack(yy.tos-1) );
			
yyval := 
yy.value_stack(yy.tos-1);
			

when  48 =>
--#line  540

			if ( 
yy.value_stack(yy.tos-2) > 
yy.value_stack(yy.tos) ) then
			    misc.synerr( "negative range in character class" );
			else
			    if ( caseins ) then
				if ( (
yy.value_stack(yy.tos-2) >= CHARACTER'POS('A')) and (
yy.value_stack(yy.tos-2) <= CHARACTER'POS('Z')) ) then
				    
yy.value_stack(yy.tos-2) := misc.clower( 
yy.value_stack(yy.tos-2) );
				end if;					    
				if ( (
yy.value_stack(yy.tos) >= CHARACTER'POS('A')) and (
yy.value_stack(yy.tos) <= CHARACTER'POS('Z')) ) then
				    
yy.value_stack(yy.tos) := misc.clower( 
yy.value_stack(yy.tos) );
				end if;    
    	    	    	    end if;

			    for i in 
yy.value_stack(yy.tos-2) .. 
yy.value_stack(yy.tos) loop
			        ccl.ccladd( 
yy.value_stack(yy.tos-3), CHARACTER'VAL(i) );
    	    	    	    end loop;
			    
			    -- keep track if this ccl is staying in
			    -- alphabetical order

			    cclsorted := cclsorted and (
yy.value_stack(yy.tos-2) > lastchar);
			    lastchar := 
yy.value_stack(yy.tos);
    	    	    	end if;
			
			
yyval := 
yy.value_stack(yy.tos-3);
			

when  49 =>
--#line  568

			if ( caseins ) then
			    if ( (
yy.value_stack(yy.tos) >= CHARACTER'POS('A')) and (
yy.value_stack(yy.tos) <= CHARACTER'POS('Z')) ) then
				
yy.value_stack(yy.tos) := misc.clower( 
yy.value_stack(yy.tos) );
    	    	    	    end if;
			end if;    
			ccl.ccladd( 
yy.value_stack(yy.tos-1), CHARACTER'VAL(
yy.value_stack(yy.tos)) );
			cclsorted := cclsorted and (
yy.value_stack(yy.tos) > lastchar);
			lastchar := 
yy.value_stack(yy.tos);
			
yyval := 
yy.value_stack(yy.tos-1);
			

when  50 =>
--#line  581

			cclsorted := true;
			lastchar := 0;
			
yyval := ccl.cclinit;
			

when  51 =>
--#line  589

			if ( caseins ) then
			    if ( (
yy.value_stack(yy.tos) >= CHARACTER'POS('A')) and (
yy.value_stack(yy.tos) <= CHARACTER'POS('Z')) ) then
				
yy.value_stack(yy.tos) := misc.clower( 
yy.value_stack(yy.tos) );
			    end if;
			end if;    

			rulelen := rulelen + 1;

			
yyval := nfa.link_machines( 
yy.value_stack(yy.tos-1), nfa.mkstate( 
yy.value_stack(yy.tos) ) );
			

when  52 =>
--#line  602
 
yyval := nfa.mkstate( SYM_EPSILON ); 

                when others => null;
            end case;

            -- Pop RHS states and goto next state
            yy.tos      := yy.tos - rule_length(yy.rule_id) + 1;
            yy.state_stack(yy.tos) := goto_state(yy.state_stack(yy.tos-1) ,
                                 get_lhs_rule(yy.rule_id));

            yy.value_stack(yy.tos) := yyval;

            if yy.debug then
                reduce_debug(yy.rule_id,
                    goto_state(yy.state_stack(yy.tos - 1),
                               get_lhs_rule(yy.rule_id)));
            end if;

        end if;
    end loop;

end yyparse;
end parser;
package Parse_Goto is

    type Small_Integer is range -32_000 .. 32_000;

    type Goto_Entry is record
        Nonterm  : Small_Integer;
        Newstate : Small_Integer;
    end record;

  --pragma suppress(index_check);

    subtype Row is Integer range -1 .. Integer'Last;

    type Goto_Parse_Table is array (Row range <>) of Goto_Entry;

    Goto_Matrix : constant Goto_Parse_Table :=
       ((-1,-1)  -- Dummy Entry.
-- State  0
,(-3, 1),(-2, 2)
-- State  1
,(-4, 3)
-- State  2

-- State  3
,(-8, 10)
,(-5, 9)
-- State  4

-- State  5

-- State  6

-- State  7

-- State  8

-- State  9
,(-6, 12)
-- State  10

-- State  11

-- State  12
,(-7, 14)
-- State  13
,(-9, 15)

-- State  14
,(-18, 28),(-17, 26),(-16, 24),(-15, 25)
,(-12, 20),(-11, 18),(-10, 34)
-- State  15

-- State  16

-- State  17

-- State  18
,(-18, 28)
,(-17, 26),(-16, 24),(-15, 25),(-12, 37)

-- State  19
,(-18, 28),(-17, 26),(-16, 24),(-15, 25)
,(-12, 40)
-- State  20
,(-13, 42)
-- State  21

-- State  22

-- State  23
,(-14, 45)
-- State  24
,(-18, 28)
,(-17, 26),(-15, 48)
-- State  25
,(-18, 28),(-17, 49)

-- State  26

-- State  27

-- State  28

-- State  29

-- State  30
,(-19, 54)
-- State  31
,(-18, 28),(-17, 26),(-16, 24)
,(-15, 25),(-12, 55)
-- State  32

-- State  33
,(-20, 56)
-- State  34

-- State  35

-- State  36

-- State  37
,(-13, 60)

-- State  38
,(-18, 28),(-17, 26),(-16, 24),(-15, 25)
,(-12, 61)
-- State  39

-- State  40
,(-13, 62)
-- State  41

-- State  42

-- State  43
,(-18, 28),(-17, 26)
,(-15, 63)
-- State  44

-- State  45

-- State  46

-- State  47

-- State  48
,(-18, 28),(-17, 49)
-- State  49

-- State  50

-- State  51

-- State  52

-- State  53

-- State  54

-- State  55

-- State  56

-- State  57
,(-20, 72)

-- State  58

-- State  59

-- State  60

-- State  61
,(-13, 73)
-- State  62

-- State  63
,(-18, 28),(-17, 49)
-- State  64

-- State  65

-- State  66

-- State  67

-- State  68

-- State  69

-- State  70

-- State  71

-- State  72

-- State  73

-- State  74

-- State  75

-- State  76

-- State  77

-- State  78

-- State  79

-- State  80

-- State  81

-- State  82

);
--  The offset vector
GOTO_OFFSET : array (0.. 82) of Integer :=
( 0,
 2, 3, 3, 5, 5, 5, 5, 5, 5, 6,
 6, 6, 7, 8, 15, 15, 15, 15, 20, 25,
 26, 26, 26, 27, 30, 32, 32, 32, 32, 32,
 33, 38, 38, 39, 39, 39, 39, 40, 45, 45,
 46, 46, 46, 49, 49, 49, 49, 49, 51, 51,
 51, 51, 51, 51, 51, 51, 51, 52, 52, 52,
 52, 53, 53, 55, 55, 55, 55, 55, 55, 55,
 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
 55, 55);

subtype Rule        is Natural;
subtype Nonterminal is Integer;

   Rule_Length : array (Rule range  0 ..  52) of Natural := ( 2,
 5, 0, 5, 0, 2, 1, 1, 1,
 3, 1, 1, 4, 0, 0, 4, 3,
 3, 2, 2, 1, 1, 3, 3, 1,
 1, 1, 0, 3, 2, 1, 2, 2,
 1, 2, 2, 2, 6, 5, 4, 1,
 1, 1, 3, 3, 1, 3, 4, 4,
 2, 0, 2, 0);
   Get_LHS_Rule: array (Rule range  0 ..  52) of Nonterminal := (-1,
-2,-3,-4,-4,-4,-5,-8,-8,
-9,-9,-9,-6,-6,-7,-10,-10,
-10,-10,-10,-10,-10,-11,-14,-14,
-14,-13,-13,-12,-12,-12,-16,-15,
-15,-17,-17,-17,-17,-17,-17,-17,
-17,-17,-17,-17,-17,-18,-18,-20,
-20,-20,-19,-19);
end Parse_Goto;
package Parse_Shift_Reduce is

    type Small_Integer is range -32_000 .. 32_000;

    type Shift_Reduce_Entry is record
        T   : Small_Integer;
        Act : Small_Integer;
    end record;
    pragma Pack(Shift_Reduce_Entry);

    subtype Row is Integer range -1 .. Integer'Last;

  --pragma suppress(index_check);

    type Shift_Reduce_Array is array (Row  range <>) of Shift_Reduce_Entry;

    Shift_Reduce_Matrix : constant Shift_Reduce_Array :=
        ( (-1,-1) -- Dummy Entry

-- state  0
,(-1,-2)
-- state  1
,( 1, 4),(-1,-4)
-- state  2
,( 0,-1001)
,(-1,-1000)
-- state  3
,( 4, 6),( 5, 7),( 6, 8)
,(-1,-1000)
-- state  4
,( 11, 11),(-1,-1000)
-- state  5
,(-1,-1000)

-- state  6
,(-1,-6)
-- state  7
,(-1,-7)
-- state  8
,(-1,-8)
-- state  9
,(-1,-13)

-- state  10
,( 7, 13),(-1,-1000)
-- state  11
,(-1,-5)
-- state  12
,(-1,-14)

-- state  13
,( 1, 17),( 8, 16),(-1,-1000)
-- state  14
,( 1, 22)
,( 2, 32),( 9, 29),( 10, 21),( 12, 19)
,( 13, 23),( 24, 27),( 25, 30),( 26, 31)
,( 28, 33),(-1,-1)
-- state  15
,( 7, 36),( 11, 35)
,(-1,-1000)
-- state  16
,(-1,-10)
-- state  17
,(-1,-11)
-- state  18
,( 2, 32)
,( 9, 29),( 10, 39),( 12, 38),( 24, 27)
,( 25, 30),( 26, 31),( 28, 33),(-1,-1000)

-- state  19
,( 2, 32),( 9, 29),( 24, 27),( 25, 30)
,( 26, 31),( 28, 33),(-1,-1000)
-- state  20
,( 16, 41)
,( 17, 43),( 18, 44),(-1,-27)
-- state  21
,(-1,-20)

-- state  22
,(-1,-21)
-- state  23
,( 1, 47),( 8, 46),(-1,-1000)

-- state  24
,( 2, 32),( 9, 29),( 24, 27),( 25, 30)
,( 26, 31),( 28, 33),(-1,-1000)
-- state  25
,( 2, 32)
,( 9, 29),( 24, 27),( 25, 30),( 26, 31)
,( 28, 33),(-1,-30)
-- state  26
,( 19, 50),( 20, 51)
,( 21, 52),( 22, 53),(-1,-33)
-- state  27
,(-1,-40)

-- state  28
,(-1,-41)
-- state  29
,(-1,-42)
-- state  30
,(-1,-52)
-- state  31
,( 2, 32)
,( 9, 29),( 24, 27),( 25, 30),( 26, 31)
,( 28, 33),(-1,-1000)
-- state  32
,(-1,-45)
-- state  33
,( 12, 57)
,(-1,-50)
-- state  34
,( 11, 58),(-1,-1000)
-- state  35
,(-1,-3)

-- state  36
,( 8, 59),(-1,-1000)
-- state  37
,( 16, 41),( 17, 43)
,( 18, 44),(-1,-27)
-- state  38
,( 2, 32),( 9, 29)
,( 24, 27),( 25, 30),( 26, 31),( 28, 33)
,(-1,-1000)
-- state  39
,(-1,-19)
-- state  40
,( 16, 41),( 17, 43)
,( 18, 44),(-1,-27)
-- state  41
,(-1,-26)
-- state  42
,(-1,-18)

-- state  43
,( 2, 32),( 9, 29),( 24, 27),( 25, 30)
,( 26, 31),( 28, 33),(-1,-1000)
-- state  44
,(-1,-31)

-- state  45
,( 14, 64),( 15, 65),(-1,-1000)
-- state  46
,(-1,-24)

-- state  47
,(-1,-25)
-- state  48
,( 2, 32),( 9, 29),( 24, 27)
,( 25, 30),( 26, 31),( 28, 33),(-1,-29)

-- state  49
,( 19, 50),( 20, 51),( 21, 52),( 22, 53)
,(-1,-32)
-- state  50
,(-1,-34)
-- state  51
,(-1,-35)
-- state  52
,(-1,-36)

-- state  53
,( 3, 66),(-1,-1000)
-- state  54
,( 2, 68),( 25, 67)
,(-1,-1000)
-- state  55
,( 17, 43),( 18, 44),( 27, 69)
,(-1,-1000)
-- state  56
,( 2, 71),( 29, 70),(-1,-1000)

-- state  57
,(-1,-50)
-- state  58
,(-1,-12)
-- state  59
,(-1,-9)
-- state  60
,(-1,-16)

-- state  61
,( 16, 41),( 17, 43),( 18, 44),(-1,-27)

-- state  62
,(-1,-17)
-- state  63
,( 2, 32),( 9, 29),( 24, 27)
,( 25, 30),( 26, 31),( 28, 33),(-1,-28)

-- state  64
,(-1,-22)
-- state  65
,( 8, 74),(-1,-1000)
-- state  66
,( 15, 75)
,( 23, 76),(-1,-1000)
-- state  67
,(-1,-43)
-- state  68
,(-1,-51)

-- state  69
,(-1,-44)
-- state  70
,(-1,-46)
-- state  71
,( 30, 77),(-1,-49)

-- state  72
,( 2, 71),( 29, 78),(-1,-1000)
-- state  73
,(-1,-15)

-- state  74
,(-1,-23)
-- state  75
,( 3, 79),( 23, 80),(-1,-1000)

-- state  76
,(-1,-39)
-- state  77
,( 2, 81),(-1,-1000)
-- state  78
,(-1,-47)

-- state  79
,( 23, 82),(-1,-1000)
-- state  80
,(-1,-38)
-- state  81
,(-1,-48)

-- state  82
,(-1,-37)
);
--  The offset vector
SHIFT_REDUCE_OFFSET : array (0.. 82) of Integer :=
( 0,
 1, 3, 5, 9, 11, 12, 13, 14, 15, 16,
 18, 19, 20, 23, 34, 37, 38, 39, 48, 55,
 59, 60, 61, 64, 71, 78, 83, 84, 85, 86,
 87, 94, 95, 97, 99, 100, 102, 106, 113, 114,
 118, 119, 120, 127, 128, 131, 132, 133, 140, 145,
 146, 147, 148, 150, 153, 157, 160, 161, 162, 163,
 164, 168, 169, 176, 177, 179, 182, 183, 184, 185,
 186, 188, 191, 192, 193, 196, 197, 199, 200, 202,
 203, 204);
end Parse_Shift_Reduce;
with  Text_Io;
with  Ccl;
with  Nfa;
with  Parse_Shift_Reduce;
with  Parse_Goto;
with  Misc_Defs;
use   Misc_Defs;
with  External_File_Manager;
use   External_File_Manager;
package Parse_Tokens is


  subtype YYSType is Integer;

    YYLVal, YYVal : YYSType; 
    type Token is
        (End_Of_Input, Error, Char, Number,
         Sectend, Scdecl, Xscdecl,
         Whitespace, Name, Prevccl,
         Eof_Op, Newline, '^',
         '<', '>', ',',
         '$', '|', '/',
         '*', '+', '?',
         '{', '}', '.',
         '"', '(', ')',
         '[', ']', '-' );

    Syntax_Error : exception;

end Parse_Tokens;
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE skeleton manager
-- AUTHOR: John Self (UCI)
-- DESCRIPTION outputs skeleton sections when called by gen.
-- NOTES allows use of internal or external skeleton
-- $Header: /tmp_mnt/dc/uc/self/arcadia/aflex/ada/src/RCS/skeleton_managerB.a,v 1.18 1991/08/06 17:58:45 self Exp self $ 

with MISC_DEFS, TEXT_IO, FILE_STRING;
package body SKELETON_MANAGER is 
  use FILE_STRING; -- to save having to type FILE_STRING 177 times
  USE_EXTERNAL_SKELETON : BOOLEAN := FALSE; 
                                          -- are we using an external skelfile?
  CURRENT_LINE          : INTEGER := 1; 
  type FILE_ARRAY is array(POSITIVE range <>) of FILE_STRING.VSTRING; 
  SKEL_TEMPLATE : FILE_ARRAY(1 .. 177) := (
  -- START OF SKELETON
  -- START OF S1
VSTR("-- A lexical scanner generated by aflex"),
VSTR("with text_io; use text_io;"),
VSTR("%% user's code up to the double pound goes right here"),
-- BEGIN S2
VSTR("function YYLex return Token is"),
VSTR("subtype short is integer range -32768..32767;"),
VSTR("    yy_act : integer;"),
VSTR("    yy_c : short;"),
VSTR(""),
VSTR("-- returned upon end-of-file"),
VSTR("YY_END_TOK : constant integer := 0;"),
VSTR("%% tables get generated here."),
-- BEGIN S3
VSTR(""),
VSTR("-- copy whatever the last rule matched to the standard output"),
VSTR(""),
VSTR("procedure ECHO is"),
VSTR("begin"),
VSTR("    text_io.put( yytext );"),
VSTR("end ECHO;"),
VSTR(""),
VSTR("-- enter a start condition."),
VSTR("-- Using procedure requires a () after the ENTER, but makes everything"),
VSTR("-- much neater."),
VSTR(""),
VSTR("procedure ENTER( state : integer ) is"),
VSTR("begin"),
VSTR("     yy_start := 1 + 2 * state;"),
VSTR("end ENTER;"),
VSTR(""),
VSTR("-- action number for EOF rule of a given start state"),
VSTR("function YY_STATE_EOF(state : integer) return integer is"),
VSTR("begin"),
VSTR("     return YY_END_OF_BUFFER + state + 1;"),
VSTR("end YY_STATE_EOF;"),
VSTR(""),
VSTR("-- return all but the first 'n' matched characters back to the input stream"),
VSTR("procedure yyless(n : integer) is"),
VSTR("begin"),
VSTR("        yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext"),
VSTR("        yy_cp := yy_bp + n;"),
VSTR("        yy_c_buf_p := yy_cp;"),
VSTR("        YY_DO_BEFORE_ACTION; -- set up yytext again"),
VSTR("end yyless;"),
VSTR(""),
VSTR("-- redefine this if you have something you want each time."),
VSTR("procedure YY_USER_ACTION is"),
VSTR("begin"),
VSTR("        null;"),
VSTR("end;"),
VSTR(""),
VSTR("-- yy_get_previous_state - get the state just before the EOB char was reached"),
VSTR(""),
VSTR("function yy_get_previous_state return yy_state_type is"),
VSTR("    yy_current_state : yy_state_type;"),
VSTR("    yy_c : short;"),
VSTR("%% a local declaration of yy_bp goes here if bol_needed"),
VSTR("begin"),
VSTR("%% code to get the start state into yy_current_state goes here"), 
-- BEGIN S3A
VSTR(""),
VSTR("    for yy_cp in yytext_ptr..yy_c_buf_p - 1 loop"),
VSTR("%% code to find the next state goes here"),
-- BEGIN S4
VSTR("    end loop;"),
VSTR(""),
VSTR("    return yy_current_state;"),
VSTR("end yy_get_previous_state;"),
VSTR(""),
VSTR("procedure yyrestart( input_file : file_type ) is"),
VSTR("begin"),
VSTR("   set_input(input_file);"),
VSTR("   yy_init := true;"),
VSTR("end yyrestart;"),
VSTR(""),
VSTR("begin -- of YYLex"),
VSTR("<<new_file>>"),
VSTR("        -- this is where we enter upon encountering an end-of-file and"),
VSTR("        -- yywrap() indicating that we should continue processing"),
VSTR(""),
VSTR("    if ( yy_init ) then"),
VSTR("        if ( yy_start = 0 ) then"),
VSTR("            yy_start := 1;      -- first start state"),
VSTR("        end if;"),
VSTR(""),
VSTR("        -- we put in the '\n' and start reading from [1] so that an"),
VSTR("        -- initial match-at-newline will be true."),
VSTR(""),
VSTR("        yy_ch_buf(0) := ASCII.LF;"),
VSTR("        yy_n_chars := 1;"),
VSTR(""),
VSTR("        -- we always need two end-of-buffer characters.  The first causes"),
VSTR("        -- a transition to the end-of-buffer state.  The second causes"),
VSTR("        -- a jam in that state."),
VSTR(""),
VSTR("        yy_ch_buf(yy_n_chars) := YY_END_OF_BUFFER_CHAR;"),
VSTR("        yy_ch_buf(yy_n_chars + 1) := YY_END_OF_BUFFER_CHAR;"),
VSTR(""),
VSTR("        yy_eof_has_been_seen := false;"),
VSTR(""),
VSTR("        yytext_ptr := 1;"),
VSTR("        yy_c_buf_p := yytext_ptr;"),
VSTR("        yy_hold_char := yy_ch_buf(yy_c_buf_p);"),
VSTR("        yy_init := false;"),
VSTR("    end if; -- yy_init"),
VSTR(""),
VSTR("    loop                -- loops until end-of-file is reached"),
VSTR("        yy_cp := yy_c_buf_p;"),
VSTR(""),
VSTR("        -- support of yytext"),
VSTR("        yy_ch_buf(yy_cp) := yy_hold_char;"),
VSTR(""),
VSTR("        -- yy_bp points to the position in yy_ch_buf of the start of the"),
VSTR("        -- current run."),
VSTR("%%"),
-- BEGIN S5
VSTR(""),
VSTR("<<next_action>>"),
VSTR("%% call to gen_find_action goes here"),
-- BEGIN S6
VSTR("            YY_DO_BEFORE_ACTION;"),
VSTR("            YY_USER_ACTION;"),
VSTR(""),
VSTR("        if aflex_debug then  -- output acceptance info. for (-d) debug mode"),
VSTR("            text_io.put( Standard_Error, ""--accepting rule #"" );"),
VSTR("            text_io.put( Standard_Error, INTEGER'IMAGE(yy_act) );"),
VSTR("            text_io.put_line( Standard_Error, ""("""""" & yytext & """""")"");"),
VSTR("        end if;"),
VSTR(""),
VSTR("<<do_action>>   -- this label is used only to access EOF actions"),
VSTR("            case yy_act is"), VSTR("%% actions go here"),
-- BEGIN S7
VSTR("                when YY_END_OF_BUFFER =>"),
VSTR("                    -- undo the effects of YY_DO_BEFORE_ACTION"),
VSTR("                    yy_ch_buf(yy_cp) := yy_hold_char;"),
VSTR(""),
VSTR("                    yytext_ptr := yy_bp;"), VSTR(""),
VSTR("                    case yy_get_next_buffer is"),
VSTR("                        when EOB_ACT_END_OF_FILE =>"),
VSTR("                            begin"),
VSTR("                            if ( yywrap ) then"),
VSTR("                                -- note: because we've taken care in"),
VSTR("                                -- yy_get_next_buffer() to have set up yytext,"),
VSTR("                                -- we can now set up yy_c_buf_p so that if some"),
VSTR("                                -- total hoser (like aflex itself) wants"),
VSTR("                                -- to call the scanner after we return the"),
VSTR("                                -- End_Of_Input, it'll still work - another"),
VSTR("                                -- End_Of_Input will get returned."),
VSTR(""),
VSTR("                                yy_c_buf_p := yytext_ptr;"),
VSTR(""),
VSTR("                                yy_act := YY_STATE_EOF((yy_start - 1) / 2);"),
VSTR(""),
VSTR("                                goto do_action;"),
VSTR("                            else"),
VSTR("                                --  start processing a new file"),
VSTR("                                yy_init := true;"),
VSTR("                                goto new_file;"),
VSTR("                            end if;"),
VSTR("                            end;"),
VSTR("                        when EOB_ACT_RESTART_SCAN =>"),
VSTR("                            yy_c_buf_p := yytext_ptr;"),
VSTR("                            yy_hold_char := yy_ch_buf(yy_c_buf_p);"),
VSTR("                        when EOB_ACT_LAST_MATCH =>"),
VSTR("                            yy_c_buf_p := yy_n_chars;"),
VSTR("                            yy_current_state := yy_get_previous_state;"),
VSTR(""),
VSTR("                            yy_cp := yy_c_buf_p;"),
VSTR("                            yy_bp := yytext_ptr;"),
VSTR("                            goto next_action;"),
VSTR("                        when others => null;"),
VSTR("                        end case; -- case yy_get_next_buffer()"),
VSTR("                when others =>"),
VSTR("                    text_io.put( ""action # "" );"),
VSTR("                    text_io.put( INTEGER'IMAGE(yy_act) );"),
VSTR("                    text_io.new_line;"),
VSTR("                    raise AFLEX_INTERNAL_ERROR;"),
VSTR("            end case; -- case (yy_act)"),
VSTR("        end loop; -- end of loop waiting for end of file"),
VSTR("end YYLex;"),
VSTR("%%"),
VSTR("ERROR tried to output beyond end of skeleton file")
-- END OF SKELETON
); 

  -- set_external_skeleton
  --
  -- DESCRIPTION
  -- sets flag so we know to use an external skelfile

  procedure SET_EXTERNAL_SKELETON is 
  begin
    USE_EXTERNAL_SKELETON := TRUE; 
  end SET_EXTERNAL_SKELETON; 

  procedure GET_INTERNAL(BUFFER : in out FILE_STRING.VSTRING) is 
  begin
    BUFFER := SKEL_TEMPLATE(CURRENT_LINE); 
    CURRENT_LINE := CURRENT_LINE + 1; 
  end GET_INTERNAL; 

  procedure GET_EXTERNAL(BUFFER : in out FILE_STRING.VSTRING) is 
  begin
    FILE_STRING.GET_LINE(MISC_DEFS.SKELFILE, BUFFER); 
  end GET_EXTERNAL; 

  -- end_of_skeleton
  --
  -- DESCRIPTION
  -- returns true if there are no more lines left to output in the skeleton

  function END_OF_SKELETON return BOOLEAN is 
  begin
    if (USE_EXTERNAL_SKELETON) then 

      -- we're using an external skelfile
      return TEXT_IO.END_OF_FILE(MISC_DEFS.SKELFILE); 
    else 

      -- internal skeleton
      return CURRENT_LINE > SKEL_TEMPLATE'LAST; 
    end if; 
  end END_OF_SKELETON; 

  procedure GET_FILE_LINE(BUFFER : in out FILE_STRING.VSTRING) is 
  begin
    if (USE_EXTERNAL_SKELETON) then 
      GET_EXTERNAL(BUFFER); 
    else 
      GET_INTERNAL(BUFFER); 
    end if; 
  end GET_FILE_LINE; 

  -- skelout - write out one section of the skeleton file
  --
  -- DESCRIPTION
  --    Either outputs internal skeleton, or from a file with "%%" dividers
  --    if a skeleton file is specified by the user.
  --    Copies from skelfile to stdout until a line beginning with "%%" or
  --    EOF is found.

  procedure SKELOUT is 
    BUF      : FILE_STRING.VSTRING; 
    LINE_LEN : INTEGER; 
  begin
    while (not END_OF_SKELETON) loop
      GET_FILE_LINE(BUF); 
      if ((FILE_STRING.LEN(BUF) >= 2)
          and then ((FILE_STRING.CHAR(BUF, 1) = '%')
                     and (FILE_STRING.CHAR(BUF, 2) = '%'))) then 
        exit; 
      else 
        FILE_STRING.PUT_LINE(BUF); 
      end if; 
    end loop; 
  end SKELOUT; 

end SKELETON_MANAGER; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE skeleton manager
-- AUTHOR: John Self (UCI)
-- DESCRIPTION outputs skeleton sections when called by gen.
-- NOTES allows use of internal or external skeleton
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/skeleton_managerS.a,v 1.3 90/01/12 15:20:38 self Exp Locker: self $ 

with TSTRING; use TSTRING; 
package SKELETON_MANAGER is 
  procedure SKELOUT; 
  procedure SET_EXTERNAL_SKELETON; 
end SKELETON_MANAGER; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE symbol table routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION implements only a simple symbol table using open hashing
-- NOTES could be faster, but it isn't used much
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/symB.a,v 1.6 90/01/12 15:20:39 self Exp Locker: self $ 

with MISC_DEFS, MISC, NFA, TEXT_IO, INT_IO, TSTRING; 

package body SYM is 
  use MISC_DEFS; 
  use TSTRING; 

  -- addsym - add symbol and definitions to symbol table
  --
  -- true is returned if the symbol already exists, and the change not made.

  procedure ADDSYM(SYM, STR_DEF : in VSTRING; 
                   INT_DEF      : in INTEGER; 
                   TABLE        : in out HASH_TABLE; 
                   TABLE_SIZE   : in INTEGER; 
                   RESULT       : out BOOLEAN) is 
    HASH_VAL             : INTEGER := HASHFUNCT(SYM, TABLE_SIZE); 
    SYM_ENTRY            : HASH_LINK := TABLE(HASH_VAL); 
    NEW_ENTRY, SUCCESSOR : HASH_LINK; 
  begin
    while (SYM_ENTRY /= null) loop
      if (SYM = SYM_ENTRY.NAME) then 

        -- entry already exists
        RESULT := TRUE; 
        return; 
      end if; 

      SYM_ENTRY := SYM_ENTRY.NEXT; 
    end loop; 

    -- create new entry
    NEW_ENTRY := new HASH_ENTRY; 

    SUCCESSOR := TABLE(HASH_VAL); 
    if ((SUCCESSOR /= null)) then 
      NEW_ENTRY.NEXT := SUCCESSOR; 
      SUCCESSOR.PREV := NEW_ENTRY; 
    else 
      NEW_ENTRY.NEXT := null; 
    end if; 

    NEW_ENTRY.PREV := null; 
    NEW_ENTRY.NAME := SYM; 
    NEW_ENTRY.STR_VAL := STR_DEF; 
    NEW_ENTRY.INT_VAL := INT_DEF; 

    TABLE(HASH_VAL) := NEW_ENTRY; 

    RESULT := FALSE; 
    return; 

  exception
    when STORAGE_ERROR => 
      MISC.AFLEXFATAL("symbol table memory allocation failed"); 
  end ADDSYM; 


  -- cclinstal - save the text of a character class

  procedure CCLINSTAL(CCLTXT : in VSTRING; 
                      CCLNUM : in INTEGER) is 
  -- we don't bother checking the return status because we are not called
  -- unless the symbol is new
    DUMMY : BOOLEAN; 
  begin
    ADDSYM(CCLTXT, NUL, CCLNUM, CCLTAB, CCL_HASH_SIZE, DUMMY); 
  end CCLINSTAL; 


  -- ccllookup - lookup the number associated with character class text

  function CCLLOOKUP(CCLTXT : in VSTRING) return INTEGER is 
  begin
    return FINDSYM(CCLTXT, CCLTAB, CCL_HASH_SIZE).INT_VAL; 
  end CCLLOOKUP; 

  -- findsym - find symbol in symbol table

  function FINDSYM(SYMBOL     : in VSTRING; 
                   TABLE      : in HASH_TABLE; 
                   TABLE_SIZE : in INTEGER) return HASH_LINK is 
    SYM_ENTRY   : HASH_LINK := TABLE(HASHFUNCT(SYMBOL, TABLE_SIZE)); 
    EMPTY_ENTRY : HASH_LINK; 
  begin
    while (SYM_ENTRY /= null) loop
      if (SYMBOL = SYM_ENTRY.NAME) then 
        return SYM_ENTRY; 
      end if; 
      SYM_ENTRY := SYM_ENTRY.NEXT; 
    end loop; 
    EMPTY_ENTRY := new HASH_ENTRY; 
    EMPTY_ENTRY.all := (null, null, NUL, NUL, 0); 

    return EMPTY_ENTRY; 
  exception
    when STORAGE_ERROR => 
      MISC.AFLEXFATAL("dynamic memory failure in findsym()"); 
      return EMPTY_ENTRY; 
  end FINDSYM; 

  -- hashfunct - compute the hash value for "str" and hash size "hash_size"

  function HASHFUNCT(STR       : in VSTRING; 
                     HASH_SIZE : in INTEGER) return INTEGER is 
    HASHVAL, LOCSTR : INTEGER; 
  begin
    HASHVAL := 0; 
    LOCSTR := TSTRING.FIRST; 

    while (LOCSTR <= TSTRING.LEN(STR)) loop
      HASHVAL := ((HASHVAL*2) + CHARACTER'POS(CHAR(STR, LOCSTR))) mod HASH_SIZE
        ; 
      LOCSTR := LOCSTR + 1; 
    end loop; 

    return HASHVAL; 
  end HASHFUNCT; 


  --ndinstal - install a name definition

  procedure NDINSTAL(ND, DEF : in VSTRING) is 
    RESULT : BOOLEAN; 
  begin
    ADDSYM(ND, DEF, 0, NDTBL, NAME_TABLE_HASH_SIZE, RESULT); 
    if (RESULT) then 
      MISC.SYNERR("name defined twice"); 
    end if; 
  end NDINSTAL; 

  -- ndlookup - lookup a name definition

  function NDLOOKUP(ND : in VSTRING) return VSTRING is 
  begin
    return FINDSYM(ND, NDTBL, NAME_TABLE_HASH_SIZE).STR_VAL; 
  end NDLOOKUP; 

  -- scinstal - make a start condition
  --
  -- NOTE
  --    the start condition is Exclusive if xcluflg is true

  procedure SCINSTAL(STR     : in VSTRING; 
                     XCLUFLG : in BOOLEAN) is 
  -- bit of a hack.  We know how the default start-condition is
  -- declared, and don't put out a define for it, because it
  -- would come out as "#define 0 1"

  -- actually, this is no longer the case.  The default start-condition
  -- is now called "INITIAL".  But we keep the following for the sake
  -- of future robustness.
    RESULT : BOOLEAN; 
  begin
    if (STR /= VSTR("0")) then 
      TSTRING.PUT(DEF_FILE, STR); 
      TEXT_IO.PUT(DEF_FILE, " : constant := "); 
      INT_IO.PUT(DEF_FILE, LASTSC, 1); 
      TEXT_IO.PUT_LINE(DEF_FILE, ";"); 
    end if; 

    LASTSC := LASTSC + 1; 
    if (LASTSC >= CURRENT_MAX_SCS) then 
      CURRENT_MAX_SCS := CURRENT_MAX_SCS + MAX_SCS_INCREMENT; 

      NUM_REALLOCS := NUM_REALLOCS + 1; 

      REALLOCATE_INTEGER_ARRAY(SCSET, CURRENT_MAX_SCS); 
      REALLOCATE_INTEGER_ARRAY(SCBOL, CURRENT_MAX_SCS); 
      REALLOCATE_BOOLEAN_ARRAY(SCXCLU, CURRENT_MAX_SCS); 
      REALLOCATE_BOOLEAN_ARRAY(SCEOF, CURRENT_MAX_SCS); 
      REALLOCATE_VSTRING_ARRAY(SCNAME, CURRENT_MAX_SCS); 
      REALLOCATE_INTEGER_ARRAY(ACTVSC, CURRENT_MAX_SCS); 
    end if; 

    SCNAME(LASTSC) := STR; 

    ADDSYM(SCNAME(LASTSC), NUL, LASTSC, SCTBL, START_COND_HASH_SIZE, RESULT); 
    if (RESULT) then 
      MISC.AFLEXERROR("start condition " & STR & " declared twice"); 
    end if; 

    SCSET(LASTSC) := NFA.MKSTATE(SYM_EPSILON); 
    SCBOL(LASTSC) := NFA.MKSTATE(SYM_EPSILON); 
    SCXCLU(LASTSC) := XCLUFLG; 
    SCEOF(LASTSC) := FALSE; 
  end SCINSTAL; 


  -- sclookup - lookup the number associated with a start condition

  function SCLOOKUP(STR : in VSTRING) return INTEGER is 
  begin
    return FINDSYM(STR, SCTBL, START_COND_HASH_SIZE).INT_VAL; 
  end SCLOOKUP; 

end SYM; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE symbol table routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION implements only a simple symbol table using open hashing
-- NOTES could be faster, but it isn't used much
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/symS.a,v 1.4 90/01/12 15:20:42 self Exp Locker: self $ 

with TSTRING; 
with MISC_DEFS; 
package SYM is 

  use TSTRING; 
  use MISC_DEFS; 

  procedure ADDSYM(SYM, STR_DEF : in VSTRING; 
                   INT_DEF      : in INTEGER; 
                   TABLE        : in out HASH_TABLE; 
                   TABLE_SIZE   : in INTEGER; 
                   RESULT       : out BOOLEAN); 
  -- result indicates success
  procedure CCLINSTAL(CCLTXT : in VSTRING; 
                      CCLNUM : in INTEGER); 
  function CCLLOOKUP(CCLTXT : in VSTRING) return INTEGER; 
  function FINDSYM(SYMBOL     : in VSTRING; 
                   TABLE      : in HASH_TABLE; 
                   TABLE_SIZE : in INTEGER) return HASH_LINK; 

  function HASHFUNCT(STR       : in VSTRING; 
                     HASH_SIZE : in INTEGER) return INTEGER; 
  procedure NDINSTAL(ND, DEF : in VSTRING); 
  function NDLOOKUP(ND : in VSTRING) return VSTRING; 
  procedure SCINSTAL(STR     : in VSTRING; 
                     XCLUFLG : in BOOLEAN); 
  function SCLOOKUP(STR : in VSTRING) return INTEGER; 
end SYM; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE table compression routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION used for compressed tables only
-- NOTES somewhat complicated but works fast and generates efficient scanners
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/tblcmpB.a,v 1.8 90/01/12 15:20:43 self Exp Locker: self $ 

with DFA, ECS, MISC_DEFS; use MISC_DEFS; 
package body TBLCMP is 

-- bldtbl - build table entries for dfa state
--
-- synopsis
--   int state[numecs], statenum, totaltrans, comstate, comfreq;
--   bldtbl( state, statenum, totaltrans, comstate, comfreq );
--
-- State is the statenum'th dfa state.  It is indexed by equivalence class and
-- gives the number of the state to enter for a given equivalence class.
-- totaltrans is the total number of transitions out of the state.  Comstate
-- is that state which is the destination of the most transitions out of State.
-- Comfreq is how many transitions there are out of State to Comstate.
--
-- A note on terminology:
--    "protos" are transition tables which have a high probability of
-- either being redundant (a state processed later will have an identical
-- transition table) or nearly redundant (a state processed later will have
-- many of the same out-transitions).  A "most recently used" queue of
-- protos is kept around with the hope that most states will find a proto
-- which is similar enough to be usable, and therefore compacting the
-- output tables.
--    "templates" are a special type of proto.  If a transition table is
-- homogeneous or nearly homogeneous (all transitions go to the same
-- destination) then the odds are good that future states will also go
-- to the same destination state on basically the same character set.
-- These homogeneous states are so common when dealing with large rule
-- sets that they merit special attention.  If the transition table were
-- simply made into a proto, then (typically) each subsequent, similar
-- state will differ from the proto for two out-transitions.  One of these
-- out-transitions will be that character on which the proto does not go
-- to the common destination, and one will be that character on which the
-- state does not go to the common destination.  Templates, on the other
-- hand, go to the common state on EVERY transition character, and therefore
-- cost only one difference.

  procedure BLDTBL(STATE                                   : in 
                     UNBOUNDED_INT_ARRAY; 
                   STATENUM, TOTALTRANS, COMSTATE, COMFREQ : in INTEGER) is 
    EXTPTR : INTEGER; 
    subtype CARRAY is UNBOUNDED_INT_ARRAY(0 .. CSIZE + 1); 
    EXTRCT                 : array(0 .. 1) of CARRAY; 
    MINDIFF, MINPROT, I, D : INTEGER; 
    CHECKCOM               : BOOLEAN; 
    LOCAL_COMSTATE         : INTEGER; 
  begin

    -- If extptr is 0 then the first array of extrct holds the result of the
    -- "best difference" to date, which is those transitions which occur in
    -- "state" but not in the proto which, to date, has the fewest differences
    -- between itself and "state".  If extptr is 1 then the second array of
    -- extrct hold the best difference.  The two arrays are toggled
    -- between so that the best difference to date can be kept around and
    -- also a difference just created by checking against a candidate "best"
    -- proto.
    LOCAL_COMSTATE := COMSTATE; 
    EXTPTR := 0; 

    -- if the state has too few out-transitions, don't bother trying to
    -- compact its tables
    if ((TOTALTRANS*100) < (NUMECS*PROTO_SIZE_PERCENTAGE)) then 
      MKENTRY(STATE, NUMECS, STATENUM, JAMSTATE_CONST, TOTALTRANS); 
    else 

      -- checkcom is true if we should only check "state" against
      -- protos which have the same "comstate" value
      CHECKCOM := COMFREQ*100 > TOTALTRANS*CHECK_COM_PERCENTAGE; 

      MINPROT := FIRSTPROT; 
      MINDIFF := TOTALTRANS; 

      if (CHECKCOM) then 

        -- find first proto which has the same "comstate"
        I := FIRSTPROT; 
        while (I /= NIL) loop
          if (PROTCOMST(I) = LOCAL_COMSTATE) then 
            MINPROT := I; 
            TBLDIFF(STATE, MINPROT, EXTRCT(EXTPTR), MINDIFF); 
            exit; 
          end if; 
          I := PROTNEXT(I); 
        end loop; 
      else 

        -- since we've decided that the most common destination out
        -- of "state" does not occur with a high enough frequency,
        -- we set the "comstate" to zero, assuring that if this state
        -- is entered into the proto list, it will not be considered
        -- a template.
        LOCAL_COMSTATE := 0; 

        if (FIRSTPROT /= NIL) then 
          MINPROT := FIRSTPROT; 
          TBLDIFF(STATE, MINPROT, EXTRCT(EXTPTR), MINDIFF); 
        end if; 
      end if; 

      -- we now have the first interesting proto in "minprot".  If
      -- it matches within the tolerances set for the first proto,
      -- we don't want to bother scanning the rest of the proto list
      -- to see if we have any other reasonable matches.
      if (MINDIFF*100 > TOTALTRANS*FIRST_MATCH_DIFF_PERCENTAGE) then 

        -- not a good enough match.  Scan the rest of the protos 
        I := MINPROT; 
        while (I /= NIL) loop
          TBLDIFF(STATE, I, EXTRCT(1 - EXTPTR), D); 
          if (D < MINDIFF) then 
            EXTPTR := 1 - EXTPTR; 
            MINDIFF := D; 
            MINPROT := I; 
          end if; 
          I := PROTNEXT(I); 
        end loop; 
      end if; 

      -- check if the proto we've decided on as our best bet is close
      -- enough to the state we want to match to be usable
      if (MINDIFF*100 > TOTALTRANS*ACCEPTABLE_DIFF_PERCENTAGE) then 

        -- no good.  If the state is homogeneous enough, we make a
        -- template out of it.  Otherwise, we make a proto.
        if (COMFREQ*100 >= TOTALTRANS*TEMPLATE_SAME_PERCENTAGE) then 
          MKTEMPLATE(STATE, STATENUM, LOCAL_COMSTATE); 
        else 
          MKPROT(STATE, STATENUM, LOCAL_COMSTATE); 
          MKENTRY(STATE, NUMECS, STATENUM, JAMSTATE_CONST, TOTALTRANS); 
        end if; 
      else 

        -- use the proto
        MKENTRY(EXTRCT(EXTPTR), NUMECS, STATENUM, PROTTBL(MINPROT), MINDIFF); 

        -- if this state was sufficiently different from the proto
        -- we built it from, make it, too, a proto
        if (MINDIFF*100 >= TOTALTRANS*NEW_PROTO_DIFF_PERCENTAGE) then 
          MKPROT(STATE, STATENUM, LOCAL_COMSTATE); 
        end if; 

        -- since mkprot added a new proto to the proto queue, it's possible
        -- that "minprot" is no longer on the proto queue (if it happened
        -- to have been the last entry, it would have been bumped off).
        -- If it's not there, then the new proto took its physical place
        -- (though logically the new proto is at the beginning of the
        -- queue), so in that case the following call will do nothing.
        MV2FRONT(MINPROT); 
      end if; 
    end if; 
  end BLDTBL; 

  -- cmptmps - compress template table entries
  --
  --  template tables are compressed by using the 'template equivalence
  --  classes', which are collections of transition character equivalence
--  classes which always appear together in templates - really meta-equivalence
  --  classes.  until this point, the tables for templates have been stored
  --  up at the top end of the nxt array; they will now be compressed and have
  --  table entries made for them.

  procedure CMPTMPS is 
    TMPSTORAGE        : C_SIZE_ARRAY; 
    TOTALTRANS, TRANS : INTEGER; 
  begin
    PEAKPAIRS := NUMTEMPS*NUMECS + TBLEND; 

    if (USEMECS) then 

      -- create equivalence classes base on data gathered on template
      -- transitions
      ECS.CRE8ECS(TECFWD, TECBCK, NUMECS, NUMMECS); 
    else 
      NUMMECS := NUMECS; 
    end if; 

    if (LASTDFA + NUMTEMPS + 1 >= CURRENT_MAX_DFAS) then 
      DFA.INCREASE_MAX_DFAS; 
    end if; 

    -- loop through each template
    for I in 1 .. NUMTEMPS loop
      TOTALTRANS := 0; 

      -- number of non-jam transitions out of this template
      for J in 1 .. NUMECS loop
        TRANS := TNXT(NUMECS*I + J); 

        if (USEMECS) then 

          -- the absolute value of tecbck is the meta-equivalence class
          -- of a given equivalence class, as set up by cre8ecs
          if (TECBCK(J) > 0) then 
            TMPSTORAGE(TECBCK(J)) := TRANS; 

            if (TRANS > 0) then 
              TOTALTRANS := TOTALTRANS + 1; 
            end if; 
          end if; 
        else 
          TMPSTORAGE(J) := TRANS; 

          if (TRANS > 0) then 
            TOTALTRANS := TOTALTRANS + 1; 
          end if; 
        end if; 
      end loop; 

      -- it is assumed (in a rather subtle way) in the skeleton that
      -- if we're using meta-equivalence classes, the def[] entry for
      -- all templates is the jam template, i.e., templates never default
      -- to other non-jam table entries (e.g., another template)

      -- leave room for the jam-state after the last real state
      MKENTRY(TMPSTORAGE, NUMMECS, LASTDFA + I + 1, JAMSTATE_CONST, TOTALTRANS)
        ; 
    end loop; 
  end CMPTMPS; 

  -- expand_nxt_chk - expand the next check arrays

  procedure EXPAND_NXT_CHK is 
    OLD_MAX : INTEGER := CURRENT_MAX_XPAIRS; 
  begin
    CURRENT_MAX_XPAIRS := CURRENT_MAX_XPAIRS + MAX_XPAIRS_INCREMENT; 

    NUM_REALLOCS := NUM_REALLOCS + 1; 

    REALLOCATE_INTEGER_ARRAY(NXT, CURRENT_MAX_XPAIRS); 
    REALLOCATE_INTEGER_ARRAY(CHK, CURRENT_MAX_XPAIRS); 

    for I in OLD_MAX .. CURRENT_MAX_XPAIRS loop
      CHK(I) := 0; 
    end loop; 
  end EXPAND_NXT_CHK; 

  -- find_table_space - finds a space in the table for a state to be placed
  --
  -- State is the state to be added to the full speed transition table.
  -- Numtrans is the number of out-transitions for the state.
  --
-- find_table_space() returns the position of the start of the first block (in
  -- chk) able to accommodate the state
  --
-- In determining if a state will or will not fit, find_table_space() must take
  -- into account the fact that an end-of-buffer state will be added at [0],
  -- and an action number will be added in [-1].

  function FIND_TABLE_SPACE(STATE    : in UNBOUNDED_INT_ARRAY; 
                            NUMTRANS : in INTEGER) return INTEGER is 
  -- firstfree is the position of the first possible occurrence of two
  -- consecutive unused records in the chk and nxt arrays

    I                                              : INTEGER; 
    STATE_PTR, CHK_PTR, PTR_TO_LAST_ENTRY_IN_STATE : INT_PTR; 
    CNT, SCNT                                      : INTEGER; 
    -- if there are too many out-transitions, put the state at the end of
    -- nxt and chk
  begin
    if (NUMTRANS > MAX_XTIONS_FULL_INTERIOR_FIT) then 

      -- if table is empty, return the first available spot in chk/nxt,
      -- which should be 1
      if (TBLEND < 2) then 
        return (1); 
      end if; 

      I := TBLEND - NUMECS; 

    -- start searching for table space near the
    -- end of chk/nxt arrays
    else 
      I := FIRSTFREE; 

    -- start searching for table space from the
    -- beginning (skipping only the elements
    -- which will definitely not hold the new
    -- state)
    end if; 

    loop

      -- loops until a space is found
      if (I + NUMECS > CURRENT_MAX_XPAIRS) then 
        EXPAND_NXT_CHK; 
      end if; 

      -- loops until space for end-of-buffer and action number are found
      loop
        if (CHK(I - 1) = 0) then 

          -- check for action number space
          if (CHK(I) = 0) then 

            -- check for end-of-buffer space
            exit; 
          else 
            I := I + 2; 

          -- since i != 0, there is no use checking to
          -- see if (++i) - 1 == 0, because that's the
          -- same as i == 0, so we skip a space
          end if; 
        else 
          I := I + 1; 
        end if; 

        if (I + NUMECS > CURRENT_MAX_XPAIRS) then 
          EXPAND_NXT_CHK; 
        end if; 
      end loop; 

      -- if we started search from the beginning, store the new firstfree for
      -- the next call of find_table_space()
      if (NUMTRANS <= MAX_XTIONS_FULL_INTERIOR_FIT) then 
        FIRSTFREE := I + 1; 
      end if; 

      -- check to see if all elements in chk (and therefore nxt) that are
      -- needed for the new state have not yet been taken
      CNT := I + 1; 
      SCNT := 1; 
      while (CNT /= I + NUMECS + 1) loop
        if ((STATE(SCNT) /= 0) and (CHK(CNT) /= 0)) then 
          exit; 
        end if; 
        SCNT := SCNT + 1; 
        CNT := CNT + 1; 
      end loop; 

      if (CNT = I + NUMECS + 1) then 
        return I; 
      else 
        I := I + 1; 
      end if; 
    end loop; 
  end FIND_TABLE_SPACE; 

  -- inittbl - initialize transition tables
  --
-- Initializes "firstfree" to be one beyond the end of the table.  Initializes
  -- all "chk" entries to be zero.  Note that templates are built in their
  -- own tbase/tdef tables.  They are shifted down to be contiguous
  -- with the non-template entries during table generation.

  procedure INITTBL is 
  begin
    for I in 0 .. CURRENT_MAX_XPAIRS loop
      CHK(I) := 0; 
    end loop; 

    TBLEND := 0; 
    FIRSTFREE := TBLEND + 1; 
    NUMTEMPS := 0; 

    if (USEMECS) then 

      -- set up doubly-linked meta-equivalence classes
      -- these are sets of equivalence classes which all have identical
      -- transitions out of TEMPLATES
      TECBCK(1) := NIL; 

      for I in 2 .. NUMECS loop
        TECBCK(I) := I - 1; 
        TECFWD(I - 1) := I; 
      end loop; 

      TECFWD(NUMECS) := NIL; 
    end if; 
  end INITTBL; 

  -- mkdeftbl - make the default, "jam" table entries

  procedure MKDEFTBL is 
  begin
    JAMSTATE := LASTDFA + 1; 

    TBLEND := TBLEND + 1; 

    -- room for transition on end-of-buffer character
    if (TBLEND + NUMECS > CURRENT_MAX_XPAIRS) then 
      EXPAND_NXT_CHK; 
    end if; 

    -- add in default end-of-buffer transition
    NXT(TBLEND) := END_OF_BUFFER_STATE; 
    CHK(TBLEND) := JAMSTATE; 

    for I in 1 .. NUMECS loop
      NXT(TBLEND + I) := 0; 
      CHK(TBLEND + I) := JAMSTATE; 
    end loop; 

    JAMBASE := TBLEND; 

    BASE(JAMSTATE) := JAMBASE; 
    DEF(JAMSTATE) := 0; 

    TBLEND := TBLEND + NUMECS; 
    NUMTEMPS := NUMTEMPS + 1; 
  end MKDEFTBL; 

  -- mkentry - create base/def and nxt/chk entries for transition array
  --
  -- "state" is a transition array "numchars" characters in size, "statenum"
  -- is the offset to be used into the base/def tables, and "deflink" is the
  -- entry to put in the "def" table entry.  If "deflink" is equal to
  -- "JAMSTATE", then no attempt will be made to fit zero entries of "state"
  -- (i.e., jam entries) into the table.  It is assumed that by linking to
  -- "JAMSTATE" they will be taken care of.  In any case, entries in "state"
  -- marking transitions to "SAME_TRANS" are treated as though they will be
  -- taken care of by whereever "deflink" points.  "totaltrans" is the total
-- number of transitions out of the state.  If it is below a certain threshold,
  -- the tables are searched for an interior spot that will accommodate the
  -- state array.

  procedure MKENTRY(STATE                                   : in 
                      UNBOUNDED_INT_ARRAY; 
                    NUMCHARS, STATENUM, DEFLINK, TOTALTRANS : in INTEGER) is 
    I, MINEC, MAXEC, BASEADDR, TBLBASE, TBLLAST : INTEGER; 
  begin
    if (TOTALTRANS = 0) then 

      -- there are no out-transitions
      if (DEFLINK = JAMSTATE_CONST) then 
        BASE(STATENUM) := JAMSTATE_CONST; 
      else 
        BASE(STATENUM) := 0; 
      end if; 

      DEF(STATENUM) := DEFLINK; 
      return; 
    end if; 

    MINEC := 1; 
    while (MINEC <= NUMCHARS) loop
      if (STATE(MINEC) /= SAME_TRANS) then 
        if ((STATE(MINEC) /= 0) or (DEFLINK /= JAMSTATE_CONST)) then 
          exit; 
        end if; 
      end if; 
      MINEC := MINEC + 1; 
    end loop; 

    if (TOTALTRANS = 1) then 

      -- there's only one out-transition.  Save it for later to fill
      -- in holes in the tables.
      STACK1(STATENUM, MINEC, STATE(MINEC), DEFLINK); 
      return; 
    end if; 

    MAXEC := NUMCHARS; 
    while (MAXEC >= 1) loop
      if (STATE(MAXEC) /= SAME_TRANS) then 
        if ((STATE(MAXEC) /= 0) or (DEFLINK /= JAMSTATE_CONST)) then 
          exit; 
        end if; 
      end if; 
      MAXEC := MAXEC - 1; 
    end loop; 

    -- Whether we try to fit the state table in the middle of the table
    -- entries we have already generated, or if we just take the state
    -- table at the end of the nxt/chk tables, we must make sure that we
    -- have a valid base address (i.e., non-negative).  Note that not only are
    -- negative base addresses dangerous at run-time (because indexing the
    -- next array with one and a low-valued character might generate an
    -- array-out-of-bounds error message), but at compile-time negative
    -- base addresses denote TEMPLATES.

    -- find the first transition of state that we need to worry about.
    if (TOTALTRANS*100 <= NUMCHARS*INTERIOR_FIT_PERCENTAGE) then 

      -- attempt to squeeze it into the middle of the tabls
      BASEADDR := FIRSTFREE; 

      while (BASEADDR < MINEC) loop

        -- using baseaddr would result in a negative base address below
        -- find the next free slot
        BASEADDR := BASEADDR + 1; 
        while (CHK(BASEADDR) /= 0) loop
          BASEADDR := BASEADDR + 1; 
        end loop; 
      end loop; 

      if (BASEADDR + MAXEC - MINEC >= CURRENT_MAX_XPAIRS) then 
        EXPAND_NXT_CHK; 
      end if; 

      I := MINEC; 
      while (I <= MAXEC) loop
        if (STATE(I) /= SAME_TRANS) then 
          if ((STATE(I) /= 0) or (DEFLINK /= JAMSTATE_CONST)) then 
            if (CHK(BASEADDR + I - MINEC) /= 0) then 

              -- baseaddr unsuitable - find another
              BASEADDR := BASEADDR + 1; 
              while ((BASEADDR < CURRENT_MAX_XPAIRS) and (CHK(BASEADDR) /= 0))
                loop
                BASEADDR := BASEADDR + 1; 
              end loop; 

              if (BASEADDR + MAXEC - MINEC >= CURRENT_MAX_XPAIRS) then 
                EXPAND_NXT_CHK; 
              end if; 

              -- reset the loop counter so we'll start all
              -- over again next time it's incremented
              I := MINEC - 1; 
            end if; 
          end if; 
        end if; 
        I := I + 1; 
      end loop; 
    else 

      -- ensure that the base address we eventually generate is
      -- non-negative
      BASEADDR := MAX(TBLEND + 1, MINEC); 
    end if; 

    TBLBASE := BASEADDR - MINEC; 
    TBLLAST := TBLBASE + MAXEC; 

    if (TBLLAST >= CURRENT_MAX_XPAIRS) then 
      EXPAND_NXT_CHK; 
    end if; 

    BASE(STATENUM) := TBLBASE; 
    DEF(STATENUM) := DEFLINK; 

    for J in MINEC .. MAXEC loop
      if (STATE(J) /= SAME_TRANS) then 
        if ((STATE(J) /= 0) or (DEFLINK /= JAMSTATE_CONST)) then 
          NXT(TBLBASE + J) := STATE(J); 
          CHK(TBLBASE + J) := STATENUM; 
        end if; 
      end if; 
    end loop; 

    if (BASEADDR = FIRSTFREE) then 

      -- find next free slot in tables
      FIRSTFREE := FIRSTFREE + 1; 
      while (CHK(FIRSTFREE) /= 0) loop
        FIRSTFREE := FIRSTFREE + 1; 
      end loop; 
    end if; 

    TBLEND := MAX(TBLEND, TBLLAST); 
  end MKENTRY; 

  -- mk1tbl - create table entries for a state (or state fragment) which
  --            has only one out-transition

  procedure MK1TBL(STATE, SYM, ONENXT, ONEDEF : in INTEGER) is 
  begin
    if (FIRSTFREE < SYM) then 
      FIRSTFREE := SYM; 
    end if; 

    while (CHK(FIRSTFREE) /= 0) loop
      FIRSTFREE := FIRSTFREE + 1; 
      if (FIRSTFREE >= CURRENT_MAX_XPAIRS) then 
        EXPAND_NXT_CHK; 
      end if; 
    end loop; 

    BASE(STATE) := FIRSTFREE - SYM; 
    DEF(STATE) := ONEDEF; 
    CHK(FIRSTFREE) := STATE; 
    NXT(FIRSTFREE) := ONENXT; 

    if (FIRSTFREE > TBLEND) then 
      TBLEND := FIRSTFREE; 
      FIRSTFREE := FIRSTFREE + 1; 

      if (FIRSTFREE >= CURRENT_MAX_XPAIRS) then 
        EXPAND_NXT_CHK; 
      end if; 
    end if; 
  end MK1TBL; 

  -- mkprot - create new proto entry

  procedure MKPROT(STATE              : in UNBOUNDED_INT_ARRAY; 
                   STATENUM, COMSTATE : in INTEGER) is 
    SLOT, TBLBASE : INTEGER; 
  begin
    NUMPROTS := NUMPROTS + 1; 
    if ((NUMPROTS >= MSP) or (NUMECS*NUMPROTS >= PROT_SAVE_SIZE)) then 

      -- gotta make room for the new proto by dropping last entry in
      -- the queue
      SLOT := LASTPROT; 
      LASTPROT := PROTPREV(LASTPROT); 
      PROTNEXT(LASTPROT) := NIL; 
    else 
      SLOT := NUMPROTS; 
    end if; 

    PROTNEXT(SLOT) := FIRSTPROT; 

    if (FIRSTPROT /= NIL) then 
      PROTPREV(FIRSTPROT) := SLOT; 
    end if; 

    FIRSTPROT := SLOT; 
    PROTTBL(SLOT) := STATENUM; 
    PROTCOMST(SLOT) := COMSTATE; 

    -- copy state into save area so it can be compared with rapidly
    TBLBASE := NUMECS*(SLOT - 1); 

    for I in 1 .. NUMECS loop
      PROTSAVE(TBLBASE + I) := STATE(I + STATE'FIRST); 
    end loop; 
  end MKPROT; 

-- mktemplate - create a template entry based on a state, and connect the state
  --              to it

  procedure MKTEMPLATE(STATE              : in UNBOUNDED_INT_ARRAY; 
                       STATENUM, COMSTATE : in INTEGER) is 
    NUMDIFF, TMPBASE : INTEGER; 
    TMP              : C_SIZE_ARRAY; 
    subtype TARRAY is CHAR_ARRAY(0 .. CSIZE); 
    TRANSSET : TARRAY; 
    TSPTR    : INTEGER; 
  begin
    NUMTEMPS := NUMTEMPS + 1; 

    TSPTR := 0; 

    -- calculate where we will temporarily store the transition table
    -- of the template in the tnxt[] array.  The final transition table
    -- gets created by cmptmps()
    TMPBASE := NUMTEMPS*NUMECS; 

    if (TMPBASE + NUMECS >= CURRENT_MAX_TEMPLATE_XPAIRS) then 
      CURRENT_MAX_TEMPLATE_XPAIRS := CURRENT_MAX_TEMPLATE_XPAIRS + 
        MAX_TEMPLATE_XPAIRS_INCREMENT; 

      NUM_REALLOCS := NUM_REALLOCS + 1; 

      REALLOCATE_INTEGER_ARRAY(TNXT, CURRENT_MAX_TEMPLATE_XPAIRS); 
    end if; 

    for I in 1 .. NUMECS loop
      if (STATE(I) = 0) then 
        TNXT(TMPBASE + I) := 0; 
      else 
        TRANSSET(TSPTR) := CHARACTER'VAL(I); 
        TSPTR := TSPTR + 1; 
        TNXT(TMPBASE + I) := COMSTATE; 
      end if; 
    end loop; 

    if (USEMECS) then 
      ECS.MKECCL(TRANSSET, TSPTR, TECFWD, TECBCK, NUMECS); 
    end if; 

    MKPROT(TNXT(TMPBASE .. CURRENT_MAX_TEMPLATE_XPAIRS),  -NUMTEMPS, COMSTATE); 

    -- we rely on the fact that mkprot adds things to the beginning
    -- of the proto queue
    TBLDIFF(STATE, FIRSTPROT, TMP, NUMDIFF); 
    MKENTRY(TMP, NUMECS, STATENUM,  -NUMTEMPS, NUMDIFF); 
  end MKTEMPLATE; 

  -- mv2front - move proto queue element to front of queue

  procedure MV2FRONT(QELM : in INTEGER) is 
  begin
    if (FIRSTPROT /= QELM) then 
      if (QELM = LASTPROT) then 
        LASTPROT := PROTPREV(LASTPROT); 
      end if; 

      PROTNEXT(PROTPREV(QELM)) := PROTNEXT(QELM); 

      if (PROTNEXT(QELM) /= NIL) then 
        PROTPREV(PROTNEXT(QELM)) := PROTPREV(QELM); 
      end if; 

      PROTPREV(QELM) := NIL; 
      PROTNEXT(QELM) := FIRSTPROT; 
      PROTPREV(FIRSTPROT) := QELM; 
      FIRSTPROT := QELM; 
    end if; 
  end MV2FRONT; 

  -- place_state - place a state into full speed transition table
  --
  -- State is the statenum'th state.  It is indexed by equivalence class and
  -- gives the number of the state to enter for a given equivalence class.
  -- Transnum is the number of out-transitions for the state.

  procedure PLACE_STATE(STATE              : in UNBOUNDED_INT_ARRAY; 
                        STATENUM, TRANSNUM : in INTEGER) is 
    I        : INTEGER; 
    POSITION : INTEGER := FIND_TABLE_SPACE(STATE, TRANSNUM); 
  begin

    -- base is the table of start positions
    BASE(STATENUM) := POSITION; 

    -- put in action number marker; this non-zero number makes sure that
    -- find_table_space() knows that this position in chk/nxt is taken
    -- and should not be used for another accepting number in another state
    CHK(POSITION - 1) := 1; 

    -- put in end-of-buffer marker; this is for the same purposes as above
    CHK(POSITION) := 1; 

    -- place the state into chk and nxt
    I := 1; 
    while (I <= NUMECS) loop
      if (STATE(I) /= 0) then 
        CHK(POSITION + I) := I; 
        NXT(POSITION + I) := STATE(I); 
      end if; 
      I := I + 1; 
    end loop; 

    if (POSITION + NUMECS > TBLEND) then 
      TBLEND := POSITION + NUMECS; 
    end if; 
  end PLACE_STATE; 

  -- stack1 - save states with only one out-transition to be processed later
  --
  -- if there's room for another state one the "one-transition" stack, the
  -- state is pushed onto it, to be processed later by mk1tbl.  If there's
  -- no room, we process the sucker right now.

  procedure STACK1(STATENUM, SYM, NEXTSTATE, DEFLINK : in INTEGER) is 
  begin
    if (ONESP >= ONE_STACK_SIZE - 1) then 
      MK1TBL(STATENUM, SYM, NEXTSTATE, DEFLINK); 
    else 
      ONESP := ONESP + 1; 
      ONESTATE(ONESP) := STATENUM; 
      ONESYM(ONESP) := SYM; 
      ONENEXT(ONESP) := NEXTSTATE; 
      ONEDEF(ONESP) := DEFLINK; 
    end if; 
  end STACK1; 

  -- tbldiff - compute differences between two state tables
  --
  -- "state" is the state array which is to be extracted from the pr'th
  -- proto.  "pr" is both the number of the proto we are extracting from
  -- and an index into the save area where we can find the proto's complete
  -- state table.  Each entry in "state" which differs from the corresponding
  -- entry of "pr" will appear in "ext".
  -- Entries which are the same in both "state" and "pr" will be marked
  -- as transitions to "SAME_TRANS" in "ext".  The total number of differences
  -- between "state" and "pr" is returned as function value.  Note that this
  -- number is "numecs" minus the number of "SAME_TRANS" entries in "ext".

  procedure TBLDIFF(STATE  : in UNBOUNDED_INT_ARRAY; 
                    PR     : in INTEGER; 
                    EXT    : out UNBOUNDED_INT_ARRAY; 
                    RESULT : out INTEGER) is 
    SP      : INTEGER := 0; 
    EP      : INTEGER := 0; 
    NUMDIFF : INTEGER := 0; 
    PROTP   : INTEGER; 
  begin
    PROTP := NUMECS*(PR - 1); 

    for I in reverse 1 .. NUMECS loop
      PROTP := PROTP + 1; 
      SP := SP + 1; 
      if (PROTSAVE(PROTP) = STATE(SP)) then 
        EP := EP + 1; 
        EXT(EP) := SAME_TRANS; 
      else 
        EP := EP + 1; 
        EXT(EP) := STATE(SP); 
        NUMDIFF := NUMDIFF + 1; 
      end if; 
    end loop; 

    RESULT := NUMDIFF; 
    return; 
  end TBLDIFF; 

end TBLCMP; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE table compression routines
-- AUTHOR: John Self (UCI)
-- DESCRIPTION used for compressed tables only
-- NOTES somewhat complicated but works fast and generates efficient scanners
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/tblcmpS.a,v 1.3 90/01/12 15:20:47 self Exp Locker: self $ 

with MISC_DEFS; use MISC_DEFS; 

package TBLCMP is 

-- bldtbl - build table entries for dfa state

  procedure BLDTBL(STATE                                   : in 
                     UNBOUNDED_INT_ARRAY; 
                   STATENUM, TOTALTRANS, COMSTATE, COMFREQ : in INTEGER); 

  procedure CMPTMPS; 

  -- expand_nxt_chk - expand the next check arrays

  procedure EXPAND_NXT_CHK; 

  -- find_table_space - finds a space in the table for a state to be placed

  function FIND_TABLE_SPACE(STATE    : in UNBOUNDED_INT_ARRAY; 
                            NUMTRANS : in INTEGER) return INTEGER; 

  -- inittbl - initialize transition tables

  procedure INITTBL; 

  -- mkdeftbl - make the default, "jam" table entries

  procedure MKDEFTBL; 

  -- mkentry - create base/def and nxt/chk entries for transition array

  procedure MKENTRY(STATE                                   : in 
                      UNBOUNDED_INT_ARRAY; 
                    NUMCHARS, STATENUM, DEFLINK, TOTALTRANS : in INTEGER); 

  -- mk1tbl - create table entries for a state (or state fragment) which
  --            has only one out-transition

  procedure MK1TBL(STATE, SYM, ONENXT, ONEDEF : in INTEGER); 

  -- mkprot - create new proto entry

  procedure MKPROT(STATE              : in UNBOUNDED_INT_ARRAY; 
                   STATENUM, COMSTATE : in INTEGER); 

-- mktemplate - create a template entry based on a state, and connect the state
  --              to it

  procedure MKTEMPLATE(STATE              : in UNBOUNDED_INT_ARRAY; 
                       STATENUM, COMSTATE : in INTEGER); 

  -- mv2front - move proto queue element to front of queue

  procedure MV2FRONT(QELM : in INTEGER); 

  -- place_state - place a state into full speed transition table

  procedure PLACE_STATE(STATE              : in UNBOUNDED_INT_ARRAY; 
                        STATENUM, TRANSNUM : in INTEGER); 

  -- stack1 - save states with only one out-transition to be processed later

  procedure STACK1(STATENUM, SYM, NEXTSTATE, DEFLINK : in INTEGER); 

  -- tbldiff - compute differences between two state tables

  procedure TBLDIFF(STATE  : in UNBOUNDED_INT_ARRAY; 
                    PR     : in INTEGER; 
                    EXT    : out UNBOUNDED_INT_ARRAY; 
                    RESULT : out INTEGER); 

end TBLCMP; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE template manager
-- AUTHOR: John Self (UCI)
-- DESCRIPTION supports output of internalized templates for the IO and DFA
--             packages.
-- NOTES This package is quite a memory hog, and is really only useful on
--       virtual memory systems.  It could use an external file to store the
--       templates like the skeleton manager.  This would save memory at the
--       cost of a slight reduction in speed and the necessity of keeping
--       copies of the template files in a known place.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/template_managerB.a,v 1.20 90/10/15 20:00:53 self Exp Locker: self $ 

with FILE_STRING, MISC_DEFS, TEXT_IO, EXTERNAL_FILE_MANAGER, MISC, TSTRING; use 
  FILE_STRING, MISC_DEFS, TEXT_IO; 
package body TEMPLATE_MANAGER is 

  type FILE_ARRAY is array(POSITIVE range <>) of VSTRING; 

  DFA_TEMPLATE     : FILE_ARRAY(1 .. 66) := (
  --DFA TEMPLATE START
VSTR("yytext_ptr : integer; -- points to start of yytext in buffer"),
VSTR(""),
VSTR("-- yy_ch_buf has to be 2 characters longer than YY_BUF_SIZE because we need"),
VSTR("-- to put in 2 end-of-buffer characters (this is explained where it is"), 
VSTR("-- done) at the end of yy_ch_buf"),
VSTR("YY_READ_BUF_SIZE : constant integer :=  8192;"),
VSTR("YY_BUF_SIZE : constant integer := YY_READ_BUF_SIZE * 2; -- size of input buffer"),
VSTR("type unbounded_character_array is array(integer range <>) of character;"),
VSTR("subtype ch_buf_type is unbounded_character_array(0..YY_BUF_SIZE + 1);"),
VSTR("yy_ch_buf : ch_buf_type;"), VSTR("yy_cp, yy_bp : integer;"),
VSTR(""),
VSTR("-- yy_hold_char holds the character lost when yytext is formed"),
VSTR("yy_hold_char : character;"),
VSTR("yy_c_buf_p : integer;   -- points to current character in buffer"),
VSTR(""),
VSTR("function YYText return string;"),
VSTR("function YYLength return integer;"),
VSTR("procedure YY_DO_BEFORE_ACTION;"),
VSTR("--These variables are needed between calls to YYLex."),
VSTR("yy_init : boolean := true; -- do we need to initialize YYLex?"),
VSTR("yy_start : integer := 0; -- current start state number"),
VSTR("subtype yy_state_type is integer;"),
VSTR("yy_last_accepting_state : yy_state_type;"),
VSTR("yy_last_accepting_cpos : integer;"), VSTR("%%"),
VSTR("function YYText return string is"),
VSTR("    i : integer;"),
VSTR("    str_loc : integer := 1;"),
VSTR("    buffer : string(1..1024);"),
VSTR("    EMPTY_STRING : constant string := """";"),
VSTR("begin"),
VSTR("    -- find end of buffer"),
VSTR("    i := yytext_ptr;"),
VSTR("    while ( yy_ch_buf(i) /= ASCII.NUL ) loop"),
VSTR("    buffer(str_loc ) := yy_ch_buf(i);"),
VSTR("        i := i + 1;"),
VSTR("    str_loc := str_loc + 1;"),
VSTR("    end loop;"),
VSTR("--    return yy_ch_buf(yytext_ptr.. i - 1);"),
VSTR(""),
VSTR("    if (str_loc < 2) then"),
VSTR("        return EMPTY_STRING;"),
VSTR("    else"),
VSTR("      return buffer(1..str_loc-1);"),
VSTR("    end if;"),
VSTR(""),
VSTR("end;"),
VSTR(""),
VSTR("-- returns the length of the matched text"),
VSTR("function YYLength return integer is"),
VSTR("begin"), VSTR("    return yy_cp - yy_bp;"),
VSTR("end YYLength;"),
VSTR(""),
VSTR("-- done after the current pattern has been matched and before the"),
VSTR("-- corresponding action - sets up yytext"),
VSTR(""),
VSTR("procedure YY_DO_BEFORE_ACTION is"),
VSTR("begin"),
VSTR("    yytext_ptr := yy_bp;"),
VSTR("    yy_hold_char := yy_ch_buf(yy_cp);"), 
VSTR("    yy_ch_buf(yy_cp) := ASCII.NUL;"),
VSTR("    yy_c_buf_p := yy_cp;"),
VSTR("end YY_DO_BEFORE_ACTION;"),
VSTR("")
--DFA TEMPLATE END
); 

  DFA_CURRENT_LINE : INTEGER := 1; 

  IO_TEMPLATE      : FILE_ARRAY(1 .. 264) := (
  --IO TEMPLATE START
VSTR("with text_io; use text_io;"),
VSTR(""),
VSTR("%%"),
VSTR("NULL_IN_INPUT : exception;"),
VSTR("AFLEX_INTERNAL_ERROR : exception;"),
VSTR("UNEXPECTED_LAST_MATCH : exception;"),
VSTR("PUSHBACK_OVERFLOW : exception;"),
VSTR("AFLEX_SCANNER_JAMMED : exception;"),
VSTR("type eob_action_type is ( EOB_ACT_RESTART_SCAN,"),
VSTR("                          EOB_ACT_END_OF_FILE,"),
VSTR("                          EOB_ACT_LAST_MATCH );"),
VSTR("YY_END_OF_BUFFER_CHAR :  constant character:=  ASCII.NUL;"),
VSTR("yy_n_chars : integer;       -- number of characters read into yy_ch_buf"),
VSTR(""),
VSTR("-- true when we've seen an EOF for the current input file"),
VSTR("yy_eof_has_been_seen : boolean;"), VSTR(""),
VSTR("procedure YY_INPUT(buf: out unbounded_character_array; result: out integer; max_size: in integer);"),
VSTR("function yy_get_next_buffer return eob_action_type;"),
VSTR("procedure yyunput( c : character; yy_bp: in out integer );"),
VSTR("procedure unput(c : character);"),
VSTR("function input return character;"),
VSTR("procedure output(c : character);"),
VSTR("function yywrap return boolean;"),
VSTR("procedure Open_Input(fname : in String);"),
VSTR("procedure Close_Input;"),
VSTR("procedure Create_Output(fname : in String := """");"),
VSTR("procedure Close_Output;"),
VSTR("%%"),
VSTR("-- gets input and stuffs it into 'buf'.  number of characters read, or YY_NULL,"),
VSTR("-- is returned in 'result'."),
VSTR(""),
VSTR("procedure YY_INPUT(buf: out unbounded_character_array; result: out integer; max_size: in integer) is"),
VSTR("    c : character;"),
VSTR("    i : integer := 1;"),
VSTR("    loc : integer := buf'first;"),
VSTR("begin"),
VSTR("    while ( i <= max_size ) loop"),
VSTR("    if (end_of_line) then -- Ada ate our newline, put it back on the end."),
VSTR("            buf(loc) := ASCII.LF;"),
VSTR("            skip_line(1);"),
VSTR("%%"),
VSTR("        else"),
VSTR("            get(buf(loc));"), 
VSTR("    end if; "),
VSTR("    "),
VSTR("        loc := loc + 1;"),
VSTR("    i := i + 1;"),
VSTR("    end loop;"),
VSTR("    "),
VSTR("    result := i - 1; "),
VSTR("    exception"),
VSTR("        when END_ERROR => result := i - 1;"),
VSTR("    -- when we hit EOF we need to set yy_eof_has_been_seen"),
VSTR("    yy_eof_has_been_seen := true;"),
VSTR("end YY_INPUT;"),
VSTR(""),
VSTR("-- yy_get_next_buffer - try to read in new buffer"),
VSTR("--"),
VSTR("-- returns a code representing an action"),
VSTR("--     EOB_ACT_LAST_MATCH - "),
VSTR("--     EOB_ACT_RESTART_SCAN - restart the scanner"),
VSTR("--     EOB_ACT_END_OF_FILE - end of file"),
VSTR(""),
VSTR("function yy_get_next_buffer return eob_action_type is"),
VSTR("    dest : integer := 0;"),
VSTR("    source : integer := yytext_ptr - 1; -- copy prev. char, too"),
VSTR("    number_to_move : integer;"),
VSTR("    ret_val : eob_action_type;"), 
VSTR("    num_to_read : integer;"),
VSTR("begin    "),
VSTR("    if ( yy_c_buf_p > yy_n_chars + 1 ) then"),
VSTR("        raise NULL_IN_INPUT;"),
VSTR("    end if;"),
VSTR(""),
VSTR("    -- try to read more data"),
VSTR(""),
VSTR("    -- first move last chars to start of buffer"),
VSTR("    number_to_move := yy_c_buf_p - yytext_ptr;"),
VSTR(""),
VSTR("    for i in 0..number_to_move - 1 loop"),
VSTR("        yy_ch_buf(dest) := yy_ch_buf(source);"),
VSTR("    dest := dest + 1;"),
VSTR("    source := source + 1;"),
VSTR("    end loop;"),
VSTR("        "),
VSTR("    if ( yy_eof_has_been_seen ) then"),
VSTR("    -- don't do the read, it's not guaranteed to return an EOF,"),
VSTR("    -- just force an EOF"),
VSTR(""),
VSTR("    yy_n_chars := 0;"),
VSTR("    else"),
VSTR("    num_to_read := YY_BUF_SIZE - number_to_move - 1;"), 
VSTR(""),
VSTR("    if ( num_to_read > YY_READ_BUF_SIZE ) then"),
VSTR("        num_to_read := YY_READ_BUF_SIZE;"),
VSTR("        end if;"),
VSTR(""),
VSTR("    -- read in more data"),
VSTR("    YY_INPUT( yy_ch_buf(number_to_move..yy_ch_buf'last), yy_n_chars, num_to_read );"),
VSTR("    end if;"),
VSTR("    if ( yy_n_chars = 0 ) then"),
VSTR("    if ( number_to_move = 1 ) then"),
VSTR("        ret_val := EOB_ACT_END_OF_FILE;"),
VSTR("    else"),
VSTR("        ret_val := EOB_ACT_LAST_MATCH;"),
VSTR("        end if;"),
VSTR(""),
VSTR("    yy_eof_has_been_seen := true;"),
VSTR("    else"),
VSTR("    ret_val := EOB_ACT_RESTART_SCAN;"),
VSTR("    end if;"),
VSTR("    "), 
VSTR("    yy_n_chars := yy_n_chars + number_to_move;"),
VSTR("    yy_ch_buf(yy_n_chars) := YY_END_OF_BUFFER_CHAR;"),
VSTR("    yy_ch_buf(yy_n_chars + 1) := YY_END_OF_BUFFER_CHAR;"),
VSTR(""),
VSTR("    -- yytext begins at the second character in"),
VSTR("    -- yy_ch_buf; the first character is the one which"),
VSTR("    -- preceded it before reading in the latest buffer;"),
VSTR("    -- it needs to be kept around in case it's a"),
VSTR("    -- newline, so yy_get_previous_state() will have"),
VSTR("    -- with '^' rules active"),
VSTR(""),
VSTR("    yytext_ptr := 1;"),
VSTR(""),
VSTR("    return ret_val;"),
VSTR("end yy_get_next_buffer;"),
VSTR(""),
VSTR("procedure yyunput( c : character; yy_bp: in out integer ) is"), 
VSTR("    number_to_move : integer;"),
VSTR("    dest : integer;"),
VSTR("    source : integer;"),
VSTR("    tmp_yy_cp : integer;"),
VSTR("begin"),
VSTR("    tmp_yy_cp := yy_c_buf_p;"),
VSTR("    yy_ch_buf(tmp_yy_cp) := yy_hold_char; -- undo effects of setting up yytext"),
VSTR(""),
VSTR("    if ( tmp_yy_cp < 2 ) then"),
VSTR("    -- need to shift things up to make room"),
VSTR("    number_to_move := yy_n_chars + 2; -- +2 for EOB chars"),
VSTR("    dest := YY_BUF_SIZE + 2;"),
VSTR("    source := number_to_move;"),
VSTR(""),
VSTR("    while ( source > 0 ) loop"),
VSTR("        dest := dest - 1;"),
VSTR("        source := source - 1;"),
VSTR("            yy_ch_buf(dest) := yy_ch_buf(source);"),
VSTR("    end loop;"),
VSTR(""),
VSTR("    tmp_yy_cp := tmp_yy_cp + dest - source;"),
VSTR("    yy_bp := yy_bp + dest - source;"),
VSTR("    yy_n_chars := YY_BUF_SIZE;"),
VSTR(""),
VSTR("    if ( tmp_yy_cp < 2 ) then"),
VSTR("        raise PUSHBACK_OVERFLOW;"),
VSTR("    end if;"),
VSTR("    end if;"),
VSTR(""),
VSTR("    if ( tmp_yy_cp > yy_bp and then yy_ch_buf(tmp_yy_cp-1) = ASCII.LF ) then"),
VSTR("    yy_ch_buf(tmp_yy_cp-2) := ASCII.LF;"),
VSTR("    end if;"),
VSTR(""),
VSTR("    tmp_yy_cp := tmp_yy_cp - 1;"),
VSTR("    yy_ch_buf(tmp_yy_cp) := c;"),
VSTR(""),
VSTR("--  Note:  this code is the text of YY_DO_BEFORE_ACTION, only"),
VSTR("--         here we get different yy_cp and yy_bp's"),
VSTR("    yytext_ptr := yy_bp;"),
VSTR("    yy_hold_char := yy_ch_buf(tmp_yy_cp);"),
VSTR("    yy_ch_buf(tmp_yy_cp) := ASCII.NUL;"),
VSTR("    yy_c_buf_p := tmp_yy_cp;"),
VSTR("end yyunput;"),
VSTR(""),
VSTR("procedure unput(c : character) is"),
VSTR("begin"),
VSTR("     yyunput( c, yy_bp );"),
VSTR("end unput;"),
VSTR(""),
VSTR("function input return character is"),
VSTR("    c : character;"),
VSTR("    yy_cp : integer := yy_c_buf_p;"),
VSTR("begin"),
VSTR("    yy_ch_buf(yy_cp) := yy_hold_char;"),
VSTR(""),
VSTR("    if ( yy_ch_buf(yy_c_buf_p) = YY_END_OF_BUFFER_CHAR ) then"),
VSTR("    -- need more input"),
VSTR("    yytext_ptr := yy_c_buf_p;"),
VSTR("    yy_c_buf_p := yy_c_buf_p + 1;"),
VSTR(""),
VSTR("    case yy_get_next_buffer is"),
VSTR("        -- this code, unfortunately, is somewhat redundant with"),
VSTR("        -- that above"),
VSTR(""),
VSTR("        when EOB_ACT_END_OF_FILE =>"),
VSTR("        if ( yywrap ) then"), 
VSTR("            yy_c_buf_p := yytext_ptr;"),
VSTR("            return ASCII.NUL;"),
VSTR("        end if;"),
VSTR(""),
VSTR("        yy_ch_buf(0) := ASCII.LF;"),
VSTR("        yy_n_chars := 1;"),
VSTR("        yy_ch_buf(yy_n_chars) := YY_END_OF_BUFFER_CHAR;"),
VSTR("        yy_ch_buf(yy_n_chars + 1) := YY_END_OF_BUFFER_CHAR;"),
VSTR("        yy_eof_has_been_seen := false;"),
VSTR("        yy_c_buf_p := 1;"),
VSTR("        yytext_ptr := yy_c_buf_p;"),
VSTR("        yy_hold_char := yy_ch_buf(yy_c_buf_p);"),
VSTR(""),
VSTR("        return ( input );"),
VSTR("        when EOB_ACT_RESTART_SCAN =>"), 
VSTR("        yy_c_buf_p := yytext_ptr;"),
VSTR(""),
VSTR("        when EOB_ACT_LAST_MATCH =>"),
VSTR("        raise UNEXPECTED_LAST_MATCH;"),
VSTR("        when others => null;"),
VSTR("        end case;"),
VSTR("    end if;"),
VSTR(""),
VSTR("    c := yy_ch_buf(yy_c_buf_p);"),
VSTR("    yy_c_buf_p := yy_c_buf_p + 1;"),
VSTR("    yy_hold_char := yy_ch_buf(yy_c_buf_p);"),
VSTR(""),
VSTR("    return c;"),
VSTR("end input;"),
VSTR(""),
VSTR("procedure output(c : character) is"),
VSTR("begin"),
VSTR("    text_io.put(c);"),
VSTR("end output;"),
VSTR(""),
VSTR("-- default yywrap function - always treat EOF as an EOF"),
VSTR("function yywrap return boolean is"),
VSTR("begin"),
VSTR("    return true;"),
VSTR("end yywrap;"),
VSTR(""),
VSTR("procedure Open_Input(fname : in String) is"),
VSTR("    f : file_type;"),
VSTR("begin"),
VSTR("    yy_init := true;"),
VSTR("    open(f, in_file, fname);"),
VSTR("    set_input(f);"),
VSTR("end Open_Input;"),
VSTR(""),
VSTR("procedure Create_Output(fname : in String := """") is"),
VSTR("    f : file_type;"),
VSTR("begin"),
VSTR("    if (fname /= """") then"),
VSTR("        create(f, out_file, fname);"),
VSTR("        set_output(f);"),
VSTR("    end if;"),
VSTR("end Create_Output;"),
VSTR(""),
VSTR("procedure Close_Input is"),
VSTR("begin"),
VSTR("    null;"),
VSTR("end Close_Input;"),
VSTR(""),
VSTR("procedure Close_Output is"),
VSTR("begin"),
VSTR("    null;"),
VSTR("end Close_Output;"),
VSTR("")
--IO TEMPLATE END
); 

  IO_CURRENT_LINE  : INTEGER := 1; 

  procedure TEMPLATE_OUT(OUTFILE          : in FILE_TYPE; 
                         CURRENT_TEMPLATE : in FILE_ARRAY; 
                         LINE_NUMBER      : in out INTEGER) is 
    BUF : VSTRING; 
  begin
    while (not (LINE_NUMBER > CURRENT_TEMPLATE'LAST)) loop
      BUF := CURRENT_TEMPLATE(LINE_NUMBER); 
      LINE_NUMBER := LINE_NUMBER + 1; 
      if ((FILE_STRING.LEN(BUF) >= 2) and then ((CHAR(BUF, 1) = '%') and (CHAR(
        BUF, 2) = '%'))) then 
        exit; 
      else 
        FILE_STRING.PUT_LINE(OUTFILE, BUF); 
      end if; 
    end loop; 
  end TEMPLATE_OUT; 

  procedure GENERATE_DFA_FILE is 
    DFA_OUT_FILE : FILE_TYPE; 
  begin
    EXTERNAL_FILE_MANAGER.GET_DFA_FILE(DFA_OUT_FILE); 
    TEXT_IO.PUT_LINE(DFA_OUT_FILE, "package " & TSTRING.STR(MISC.BASENAME) & 
      "_dfa" & " is"); 

    if (DDEBUG) then 

      -- make a scanner that output acceptance information
      TEXT_IO.PUT_LINE(DFA_OUT_FILE, "aflex_debug : boolean := true;"); 
    else 
      TEXT_IO.PUT_LINE(DFA_OUT_FILE, "aflex_debug : boolean := false;"); 
    end if; 
    TEMPLATE_OUT(DFA_OUT_FILE, DFA_TEMPLATE, DFA_CURRENT_LINE); 
    TEXT_IO.PUT_LINE(DFA_OUT_FILE, "end " & TSTRING.STR(MISC.BASENAME) & "_dfa;"
      ); 
    TEXT_IO.NEW_LINE(DFA_OUT_FILE); 
    TEXT_IO.PUT(DFA_OUT_FILE, "with " & TSTRING.STR(MISC.BASENAME) & "_dfa" & 
      "; "); 
    TEXT_IO.PUT_LINE(DFA_OUT_FILE, "use " & TSTRING.STR(MISC.BASENAME) & "_dfa"
      & "; "); 
    TEXT_IO.PUT_LINE(DFA_OUT_FILE, "package body " & TSTRING.STR(MISC.BASENAME)
      & "_dfa" & " is"); 
    TEMPLATE_OUT(DFA_OUT_FILE, DFA_TEMPLATE, DFA_CURRENT_LINE); 
    TEXT_IO.PUT_LINE(DFA_OUT_FILE, "end " & TSTRING.STR(MISC.BASENAME) & "_dfa;"
      ); 
  end GENERATE_DFA_FILE; 

  procedure GENERATE_IO_FILE is 
    IO_OUT_FILE : FILE_TYPE; 
  begin
    EXTERNAL_FILE_MANAGER.GET_IO_FILE(IO_OUT_FILE); 
    TEXT_IO.PUT(IO_OUT_FILE, "with " & TSTRING.STR(MISC.BASENAME) & "_dfa" & 
      "; "); 
    TEXT_IO.PUT_LINE(IO_OUT_FILE, "use " & TSTRING.STR(MISC.BASENAME) & "_dfa"
      & "; "); 
    TEMPLATE_OUT(IO_OUT_FILE, IO_TEMPLATE, IO_CURRENT_LINE); 
    TEXT_IO.PUT_LINE(IO_OUT_FILE, "package " & TSTRING.STR(MISC.BASENAME) & 
      "_io" & " is"); 
    TEMPLATE_OUT(IO_OUT_FILE, IO_TEMPLATE, IO_CURRENT_LINE); 
    TEXT_IO.PUT_LINE(IO_OUT_FILE, "end " & TSTRING.STR(MISC.BASENAME) & "_io;")
      ; 
    TEXT_IO.NEW_LINE(IO_OUT_FILE); 
    TEXT_IO.PUT_LINE(IO_OUT_FILE, "package body " & TSTRING.STR(MISC.BASENAME)
      & "_io" & " is"); 
    TEMPLATE_OUT(IO_OUT_FILE, IO_TEMPLATE, IO_CURRENT_LINE); 
    -- If we're generating a scanner for interactive mode we need to generate
    -- a YY_INPUT that stops at the end of each line
    if INTERACTIVE then
        TEXT_IO.PUT_LINE(IO_OUT_FILE,
	    "            i := i + 1; -- update counter, miss end of loop");
	TEXT_IO.PUT_LINE(IO_OUT_FILE,
	    "            exit; -- in interactive mode return at end of line.");
    end if;
    TEMPLATE_OUT(IO_OUT_FILE, IO_TEMPLATE, IO_CURRENT_LINE);     
    TEXT_IO.PUT_LINE(IO_OUT_FILE, "end " & TSTRING.STR(MISC.BASENAME) & "_io;")
      ; 
  end GENERATE_IO_FILE; 

end TEMPLATE_MANAGER; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE template manager
-- AUTHOR: John Self (UCI)
-- DESCRIPTION supports output of internalized templates for the IO and DFA
--             packages.
-- NOTES This package is quite a memory hog, and is really only useful on
--       virtual memory systems.  It could use an external file to store the
--       templates like the skeleton manager.  This would save memory at the
--       cost of a slight reduction in speed and the necessity of keeping
--       copies of the template files in a known place.
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/template_managerS.a,v 1.3 90/01/12 15:20:49 self Exp Locker: self $ 

package TEMPLATE_MANAGER is 
  procedure GENERATE_DFA_FILE; 
  procedure GENERATE_IO_FILE; 
end TEMPLATE_MANAGER; 
-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
-- This software was developed by John Self of the Arcadia project
-- at the University of California, Irvine.
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- TITLE variable length strings
-- AUTHOR: John Self (UCI)
-- DESCRIPTION these strings are used for many functions
-- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/tstrings.a,v 1.4 90/01/12 15:20:51 self Exp Locker: self $ 

with VSTRINGS; 
package TSTRING is 
  new VSTRINGS(1024);  -- This is MAXLINE in misc_defs

-- UNIT: generic package body of VSTRINGS
--
-- FILES: vstring_body.a in publiclib
--        related file is vstring_spec.a in publiclib
--
-- PURPOSE:  An implementation of the abstract data type "variable-length
--           string."
--
-- DESCRIPTION:  This package provides a private type VSTRING.  VSTRING objects
--               are "strings" that have a length between zero and LAST, where
--               LAST is the generic parameter supplied in the package
--               instantiation.
--
--               In addition to the type VSTRING, a subtype and two constants
--               are declared.  The subtype STRINDEX is an index to a VSTRING,
--               The STRINDEX constant FIRST is an index to the first character
--               of the string, and the VSTRING constant NUL is a VSTRING of
--               length zero.  NUL is the default initial value of a VSTRING.
--
--               The following sets of functions, procedures, and operators
--               are provided as operations on the type VSTRING:
--
--               ATTRIBUTE FUNCTIONS:  LEN, MAX, STR, CHAR
--                 The attribute functions return the characteristics of
--                 a VSTRING.
--
--               COMPARISON OPERATORS: "=", "/=", "<", ">", "<=", ">="
--                 The comparison operators are the same as for the predefined
--                 type STRING.
--
--               INPUT/OUTPUT PROCEDURES: GET, GET_LINE, PUT, PUT_LINE
--                                        
--                 The input/output procedures are similar to those for the
--                 predefined type STRING, with the following exceptions:
--
--                   - GET has an optional parameter LENGTH, which indicates
--                     the number of characters to get (default is LAST).
--
--                   - GET_LINE does not have a parameter to return the length
--                     of the string (the LEN function should be used instead).
--
--               EXTRACTION FUNCTIONS: SLICE, SUBSTR, DELETE
--                 The SLICE function returns the slice of a VSTRING between
--                 two indices (equivalent to STR(X)(A .. B)).
--
--                 SUBSTR returns a substring of a VSTRING taken from a given
--                 index and extending a given length.
--
--                 The DELETE function returns the VSTRING which results from
--                 removing the slice between two indices.
--
--               EDITING FUNCTIONS: INSERT, APPEND, REPLACE
--                 The editing functions return the VSTRING which results from
--                 inserting, appending, or replacing at a given index with a
--                 VSTRING, STRING, or CHARACTER.  The index must be in the
--                 current range of the VSTRING; i.e., zero cannot be used.
--
--               CONCATENATION OPERATOR:  "&"
--                 The concatenation operator is the same as for the type
--                 STRING.  It should be used instead of APPEND when the
--                 APPEND would always be after the last character.
--
--               POSITION FUNCTIONS: INDEX, RINDEX
--                 The position functions return an index to the Nth occurrence
--                 of a VSTRING, STRING, or CHARACTER from the front or back
--                 of a VSTRING.  Zero is returned if the search is not
--                 successful.
--
--               CONVERSION FUNCTIONS AND OPERATOR: VSTR, CONVERT, "+"
--                 VSTR converts a STRING or a CHARACTER to a VSTRING.
--
--                 CONVERT is a generic function which can be instantiated to
--                 convert from any given variable-length string to another,
--                 provided the FROM type has a function equivelent to STR
--                 defined for it, and that the TO type has a function equiv-
--                 elent to VSTR defined for it.  This provides a means for
--                 converting between VSTRINGs declared in separate instant-
--                 iations of VSTRINGS.  When instantiating CONVERT for 
--                 VSTRINGs, the STR and VSTR functions are implicitly defined,
--                 provided that they have been made visible (by a use clause).
--
--                 Note:  CONVERT is NOT implicitly associated with the type 
--                 VSTRING declared in this package (since it would not be a
--                 derivable function (see RM 3.4(11))).
--
--                 Caution:  CONVERT cannot be instantiated directly with the
--                 names VSTR and STR, since the name of the subprogram being
--                 declared would hide the generic parameters with the same
--                 names (see RM 8.3(16)).  CONVERT can be instantiated with
--                 the operator "+", and any instantiation of CONVERT can
--                 subsequently be renamed VSTR or STR.
--
--                 Example:  Given two VSTRINGS instantiations X and Y:
--                   function "+" is new X.CONVERT(X.VSTRING, Y.VSTRING);
--                   function "+" is new X.CONVERT(Y.VSTRING, X.VSTRING);
--
--                   (Y.CONVERT could have been used in place of X.CONVERT)
--
--                   function VSTR(A : X.VSTRING) return Y.VSTRING renames "+";
--                   function VSTR(A : Y.VSTRING) return X.VSTRING renames "+";
--
--                 "+" is equivelent to VSTR.  It is supplied as a short-hand
--                 notation for the function.  The "+" operator cannot immed-
--                 iately follow the "&" operator; use ... & (+ ...) instead.
pragma PAGE;
\f


--  DISCUSSION:
--
--	This package implements the type "variable-length string" (vstring)
--	using generics.  The alternative approaches are to use a discriminant 
--	record in which the discriminant controls the length of a STRING inside
--	the record, or a record containing an access type which points to a
--      string, which can be deallocated and reallocated when necessary.
--
--	Advantages of this package:
--	  * The other approaches force the vstring to be a limited private 
--          type.  Thus, their vstrings cannot appear on the left side of
--          the assignment operator; ie., their vstrings cannot be given
--          initial values or values by direct assignment.  This package
--          uses a private type; therefore, these things can be done.
--         
--	  * The other approach stores the vstring in a string whose length
--	    is determined dynamically.  This package uses a fixed length 
--          string.  This difference might be reflected in faster and more
--          consistent execution times (this has NOT been verified).
--
--	Disadvantages of this package:
--	  * Different instantiations must be used to declare vstrings with
--	    different maximum lengths (this may be desirable, since
--	    CONSTRAINT_ERROR will be raised if the maximum is exceeded).
--
--	  * A second declaration is required to give the type declared by
--	    the instantiation a name other than "VSTRING."
--
--	  * The storage required for a vstring is determined by the generic
--	    parameter LAST and not the actual length of its contents.  Thus,
--          each object is allocated the maximum amount of storage, regardless
--          of its actual size.
--
--  MISCELLANEOUS:
--     Constraint checking is done explicitly in the code; thus, it cannot
--     be suppressed.  On the other hand, constraint checking is not lost
--     if pragma suppress is supplied to the compilation (-S option) 
--     (The robustness of the explicit constraint checking has NOT been 
--     determined).
--
--     Compiling with the optimizer (-O option) may significantly reduce
--     the size (and possibly execution time) of the resulting executable.
--
--     Compiling an instantiation of VSTRINGS is roughly equivelent to
--     recompiling VSTRINGS.  Since this takes a significant amount of time,
--     and the instantiation does not depend on any other library units,
--     it is STRONGLY recommended that the instantiation be compiled
--     separately, and thus done only ONCE.
--
--  USAGE: with VSTRINGS;
--         package package_name is new VSTRINGS(maximum_length);
-- .......................................................................... --
pragma PAGE;
\f


package body VSTRINGS is

  -- local declarations

  FILL_CHAR : constant CHARACTER := ASCII.NUL;

  procedure FORMAT(THE_STRING : in out VSTRING; OLDLEN : in STRINDEX := LAST) is
    -- fill the string with FILL_CHAR to null out old values

    begin -- FORMAT (Local Procedure)
      THE_STRING.VALUE(THE_STRING.LEN + 1 .. OLDLEN) := 
                                        (others => FILL_CHAR);
    end FORMAT;


  -- bodies of visible operations

  function LEN(FROM : VSTRING) return STRINDEX is

    begin -- LEN
      return(FROM.LEN);
    end LEN;


  function MAX(FROM : VSTRING) return STRINDEX is
    begin -- MAX
      return(LAST);
    end MAX;


  function STR(FROM : VSTRING) return STRING is
    begin -- STR
      return(FROM.VALUE(FIRST .. FROM.LEN));
    end STR;


  function CHAR(FROM : VSTRING; POSITION : STRINDEX := FIRST)
                 return CHARACTER is

    begin -- CHAR
      if POSITION not in FIRST .. FROM.LEN
        then raise CONSTRAINT_ERROR;
       end if;
      return(FROM.VALUE(POSITION));
    end CHAR;


  function "<" (LEFT: VSTRING; RIGHT: VSTRING) return BOOLEAN is
    begin -- "<"
      return(LEFT.VALUE < RIGHT.VALUE);
    end "<";


  function ">" (LEFT: VSTRING; RIGHT: VSTRING) return BOOLEAN is
    begin -- ">"
      return(LEFT.VALUE > RIGHT.VALUE);
    end ">";


  function "<=" (LEFT: VSTRING; RIGHT: VSTRING) return BOOLEAN is
    begin -- "<="
      return(LEFT.VALUE <= RIGHT.VALUE);
    end "<=";


  function ">=" (LEFT: VSTRING; RIGHT: VSTRING) return BOOLEAN is
    begin -- ">="
      return(LEFT.VALUE >= RIGHT.VALUE);
    end ">=";


  procedure PUT(FILE : in FILE_TYPE; ITEM : in VSTRING) is
    begin -- PUT
      PUT(FILE, ITEM.VALUE(FIRST .. ITEM.LEN));
    end PUT;

  procedure Put(ITEM : in VSTRING) is
    begin -- PUT
      PUT(ITEM.VALUE(FIRST .. ITEM.LEN));
    end PUT;


  procedure PUT_LINE(FILE : in FILE_TYPE; ITEM : in VSTRING) is
    begin -- PUT_LINE
      PUT_LINE(FILE, ITEM.VALUE(FIRST .. ITEM.LEN));
    end PUT_LINE;

  procedure PUT_LINE(ITEM : in VSTRING) is
    begin -- PUT_LINE
      PUT_LINE(ITEM.VALUE(FIRST .. ITEM.LEN));
    end PUT_LINE;


  procedure GET(FILE : in FILE_TYPE; ITEM : out VSTRING;
                LENGTH : in STRINDEX := LAST) is
    begin -- GET
      if LENGTH not in FIRST .. LAST
        then raise CONSTRAINT_ERROR;
       end if;

      ITEM := NUL;
      for INDEX in FIRST .. LENGTH loop
        GET(FILE, ITEM.VALUE(INDEX));
        ITEM.LEN := INDEX;
       end loop;
    end GET;

  procedure GET(ITEM : out VSTRING; LENGTH : in STRINDEX := LAST) is
    begin -- GET
      if LENGTH not in FIRST .. LAST
        then raise CONSTRAINT_ERROR;
       end if;

      ITEM := NUL;
      for INDEX in FIRST .. LENGTH loop
        GET(ITEM.VALUE(INDEX));
        ITEM.LEN := INDEX;
       end loop;
    end GET;


  procedure GET_LINE(FILE : in FILE_TYPE; ITEM : in out VSTRING) is

    OLDLEN : constant STRINDEX := ITEM.LEN;

    begin -- GET_LINE
      GET_LINE(FILE, ITEM.VALUE, ITEM.LEN);
      FORMAT(ITEM, OLDLEN);
    end GET_LINE;
       
  procedure GET_LINE(ITEM : in out VSTRING) is

    OLDLEN : constant STRINDEX := ITEM.LEN;

    begin -- GET_LINE
      GET_LINE(ITEM.VALUE, ITEM.LEN);
      FORMAT(ITEM, OLDLEN);
    end GET_LINE;


  function SLICE(FROM : VSTRING; FRONT, BACK : STRINDEX) return VSTRING is

    begin -- SLICE
      if ((FRONT not in FIRST .. FROM.LEN) or else 
         (BACK not in FIRST .. FROM.LEN)) and then FRONT <= BACK
        then raise CONSTRAINT_ERROR;
       end if;

      return(Vstr(FROM.VALUE(FRONT .. BACK)));
    end SLICE;


  function SUBSTR(FROM : VSTRING; START, LENGTH : STRINDEX) return VSTRING is

    begin -- SUBSTR
      if (START not in FIRST .. FROM.LEN) or else
         ((START + LENGTH - 1 not in FIRST .. FROM.LEN)
          and then (LENGTH > 0))
        then raise CONSTRAINT_ERROR;
       end if;

      return(Vstr(FROM.VALUE(START .. START + LENGTH -1)));
    end SUBSTR;


  function DELETE(FROM : VSTRING; FRONT, BACK : STRINDEX) return VSTRING is

    TEMP : VSTRING := FROM;

    begin -- DELETE
      if ((FRONT not in FIRST .. FROM.LEN) or else
         (BACK not in FIRST .. FROM.LEN)) and then FRONT <= BACK
        then raise CONSTRAINT_ERROR;
       end if;

      if FRONT > BACK then return(FROM); end if;
      TEMP.LEN := FROM.LEN - (BACK - FRONT) - 1;

      TEMP.VALUE(FRONT .. TEMP.LEN) := FROM.VALUE(BACK + 1 .. FROM.LEN);
      FORMAT(TEMP, FROM.LEN);
      return(TEMP);
    end DELETE;


  function INSERT(TARGET: VSTRING; ITEM: VSTRING;
                  POSITION : STRINDEX := FIRST) return VSTRING is

    TEMP : VSTRING;

    begin -- INSERT
      if POSITION not in FIRST .. TARGET.LEN
        then raise CONSTRAINT_ERROR;
       end if;

      if TARGET.LEN + ITEM.LEN > LAST
        then raise CONSTRAINT_ERROR;
        else TEMP.LEN := TARGET.LEN + ITEM.LEN;
       end if;

      TEMP.VALUE(FIRST .. POSITION - 1) := TARGET.VALUE(FIRST .. POSITION - 1);
      TEMP.VALUE(POSITION .. (POSITION + ITEM.LEN - 1)) :=
        ITEM.VALUE(FIRST .. ITEM.LEN);
      TEMP.VALUE((POSITION + ITEM.LEN) .. TEMP.LEN) :=
        TARGET.VALUE(POSITION .. TARGET.LEN);

      return(TEMP);
    end INSERT;

  function INSERT(TARGET: VSTRING; ITEM: STRING;
                  POSITION : STRINDEX := FIRST) return VSTRING is
    begin -- INSERT
      return INSERT(TARGET, VSTR(ITEM), POSITION);
    end INSERT;
  
  function INSERT(TARGET: VSTRING; ITEM: CHARACTER;
                  POSITION : STRINDEX := FIRST) return VSTRING is
    begin -- INSERT
      return INSERT(TARGET, VSTR(ITEM), POSITION);
    end INSERT;


  function APPEND(TARGET: VSTRING; ITEM: VSTRING; POSITION : STRINDEX)
                  return VSTRING is

    TEMP : VSTRING;
    POS : STRINDEX := POSITION;

    begin -- APPEND
      if POSITION not in FIRST .. TARGET.LEN
        then raise CONSTRAINT_ERROR;
       end if;

      if TARGET.LEN + ITEM.LEN > LAST
        then raise CONSTRAINT_ERROR;
        else TEMP.LEN := TARGET.LEN + ITEM.LEN;
       end if;

      TEMP.VALUE(FIRST .. POS) := TARGET.VALUE(FIRST .. POS);
      TEMP.VALUE(POS + 1 .. (POS + ITEM.LEN)) := ITEM.VALUE(FIRST .. ITEM.LEN);
      TEMP.VALUE((POS + ITEM.LEN + 1) .. TEMP.LEN) :=
        TARGET.VALUE(POS + 1 .. TARGET.LEN);

      return(TEMP);
    end APPEND;

  function APPEND(TARGET: VSTRING; ITEM: STRING; POSITION : STRINDEX)
                  return VSTRING is
    begin -- APPEND
      return APPEND(TARGET, VSTR(ITEM), POSITION);
    end APPEND;

  function APPEND(TARGET: VSTRING; ITEM: CHARACTER; POSITION : STRINDEX)
                  return VSTRING is
    begin -- APPEND
      return APPEND(TARGET, VSTR(ITEM), POSITION);
    end APPEND;


  function APPEND(TARGET: VSTRING; ITEM: VSTRING) return VSTRING is
    begin -- APPEND
      return(APPEND(TARGET, ITEM, TARGET.LEN));
    end APPEND;

  function APPEND(TARGET: VSTRING; ITEM: STRING) return VSTRING is
    begin -- APPEND
      return(APPEND(TARGET, VSTR(ITEM), TARGET.LEN));
    end APPEND;

  function APPEND(TARGET: VSTRING; ITEM: CHARACTER) return VSTRING is
    begin -- APPEND
      return(APPEND(TARGET, VSTR(ITEM), TARGET.LEN));
    end APPEND;


  function REPLACE(TARGET: VSTRING; ITEM: VSTRING;
                   POSITION : STRINDEX := FIRST) return VSTRING is

    TEMP : VSTRING;

    begin -- REPLACE
      if POSITION not in FIRST .. TARGET.LEN
        then raise CONSTRAINT_ERROR;
       end if;

      if POSITION + ITEM.LEN - 1 <= TARGET.LEN
        then TEMP.LEN := TARGET.LEN;
        elsif POSITION + ITEM.LEN - 1 > LAST
          then raise CONSTRAINT_ERROR;
          else TEMP.LEN := POSITION + ITEM.LEN - 1;
       end if;

      TEMP.VALUE(FIRST .. POSITION - 1) := TARGET.VALUE(FIRST .. POSITION - 1);
      TEMP.VALUE(POSITION .. (POSITION + ITEM.LEN - 1)) := 
        ITEM.VALUE(FIRST .. ITEM.LEN);
      TEMP.VALUE((POSITION + ITEM.LEN) .. TEMP.LEN) :=
        TARGET.VALUE((POSITION + ITEM.LEN) .. TARGET.LEN);

      return(TEMP);
    end REPLACE;

  function REPLACE(TARGET: VSTRING; ITEM: STRING;
                   POSITION : STRINDEX := FIRST) return VSTRING is
    begin -- REPLACE
      return REPLACE(TARGET, VSTR(ITEM), POSITION);
    end REPLACE;

  function REPLACE(TARGET: VSTRING; ITEM: CHARACTER;
                   POSITION : STRINDEX := FIRST) return VSTRING is
    begin -- REPLACE
      return REPLACE(TARGET, VSTR(ITEM), POSITION);
    end REPLACE;


  function "&"(LEFT:VSTRING; RIGHT : VSTRING) return VSTRING is

    TEMP : VSTRING;

    begin -- "&"
      if LEFT.LEN + RIGHT.LEN > LAST
        then raise CONSTRAINT_ERROR;
        else TEMP.LEN := LEFT.LEN + RIGHT.LEN;
       end if;

      TEMP.VALUE(FIRST .. TEMP.LEN) := LEFT.VALUE(FIRST .. LEFT.LEN) &
        RIGHT.VALUE(FIRST .. RIGHT.LEN);
      return(TEMP);
    end "&";

  function "&"(LEFT:VSTRING; RIGHT : STRING) return VSTRING is
    begin -- "&"
      return LEFT & VSTR(RIGHT);
    end "&";

  function "&"(LEFT:VSTRING; RIGHT : CHARACTER) return VSTRING is
    begin -- "&"
      return LEFT & VSTR(RIGHT);
    end "&";

  function "&"(LEFT : STRING; RIGHT : VSTRING) return VSTRING is
    begin -- "&"
      return VSTR(LEFT) & RIGHT;
    end "&";

  function "&"(LEFT : CHARACTER; RIGHT : VSTRING) return VSTRING is
    begin -- "&"
      return VSTR(LEFT) & RIGHT;
    end "&";


  Function INDEX(WHOLE : VSTRING; PART : VSTRING; OCCURRENCE : NATURAL := 1)
                 return STRINDEX is

    NOT_FOUND : constant NATURAL := 0;
    INDEX : NATURAL := FIRST;
    COUNT : NATURAL := 0;

    begin -- INDEX
      if PART = NUL then return(NOT_FOUND); -- by definition
        end if;

      while INDEX + PART.LEN - 1 <= WHOLE.LEN and then COUNT < OCCURRENCE loop
        if WHOLE.VALUE(INDEX .. PART.LEN + INDEX - 1) =
           PART.VALUE(1 .. PART.LEN)
          then COUNT := COUNT + 1;
         end if;
        INDEX := INDEX + 1;
       end loop;

      if COUNT = OCCURRENCE
        then return(INDEX - 1);
        else return(NOT_FOUND);
       end if;
    end INDEX;

  Function INDEX(WHOLE : VSTRING; PART : STRING; OCCURRENCE : NATURAL := 1)
                 return STRINDEX is

    begin -- Index
      return(Index(WHOLE, VSTR(PART), OCCURRENCE));
    end INDEX;


  Function INDEX(WHOLE : VSTRING; PART : CHARACTER; OCCURRENCE : NATURAL := 1)
                 return STRINDEX is

    begin -- Index
      return(Index(WHOLE, VSTR(PART), OCCURRENCE));
    end INDEX;


  function RINDEX(WHOLE: VSTRING; PART:VSTRING; OCCURRENCE:NATURAL := 1) 
                 return STRINDEX is

    NOT_FOUND : constant NATURAL := 0;
    INDEX : INTEGER := WHOLE.LEN - (PART.LEN -1);
    COUNT : NATURAL := 0;

    begin -- RINDEX
      if PART = NUL then return(NOT_FOUND); -- by definition
        end if;

      while INDEX >= FIRST and then COUNT < OCCURRENCE loop
        if WHOLE.VALUE(INDEX .. PART.LEN + INDEX - 1) =
           PART.VALUE(1 .. PART.LEN)
          then COUNT := COUNT + 1;
         end if;
        INDEX := INDEX - 1;
       end loop;

      if COUNT = OCCURRENCE
        then
          if COUNT > 0
            then return(INDEX + 1);
            else return(NOT_FOUND);
           end if;
        else return(NOT_FOUND);
       end if;
    end RINDEX;

  Function RINDEX(WHOLE : VSTRING; PART : STRING; OCCURRENCE : NATURAL := 1)
                 return STRINDEX is

    begin -- Rindex
      return(RINDEX(WHOLE, VSTR(PART), OCCURRENCE));
    end RINDEX;


  Function RINDEX(WHOLE : VSTRING; PART : CHARACTER; OCCURRENCE : NATURAL := 1)
                 return STRINDEX is

    begin -- Rindex
      return(RINDEX(WHOLE, VSTR(PART), OCCURRENCE));
    end RINDEX;


  function VSTR(FROM : CHARACTER) return VSTRING is
    
    TEMP : VSTRING;

    begin -- VSTR
      if LAST < 1
        then raise CONSTRAINT_ERROR;
        else TEMP.LEN := 1;
       end if;

      TEMP.VALUE(FIRST) := FROM;
      return(TEMP);
    end VSTR;


  function VSTR(FROM : STRING) return VSTRING is

    TEMP : VSTRING;

    begin -- VSTR
      if FROM'LENGTH > LAST
        then raise CONSTRAINT_ERROR;
        else TEMP.LEN := FROM'LENGTH;
       end if;

      TEMP.VALUE(FIRST .. FROM'LENGTH) := FROM;
      return(TEMP);
    end VSTR;

  Function "+" (FROM : STRING) return VSTRING is
    begin -- "+"
      return(VSTR(FROM));
    end "+";

  Function "+" (FROM : CHARACTER) return VSTRING is
    begin
     return(VSTR(FROM));
    end "+";


  function CONVERT(X : FROM) return TO is

    begin -- CONVERT
      return(VSTR(STR(X)));
    end CONVERT;   
end VSTRINGS;
-- .......................................................................... --
--
-- DISTRIBUTION AND COPYRIGHT:
--                                                           
-- This software is released to the Public Domain (note:
--   software released to the Public Domain is not subject
--   to copyright protection).
-- Restrictions on use or distribution:  NONE
--                                                           
-- DISCLAIMER:
--                                                           
-- This software and its documentation are provided "AS IS" and
-- without any expressed or implied warranties whatsoever.
-- No warranties as to performance, merchantability, or fitness
-- for a particular purpose exist.
--
-- Because of the diversity of conditions and hardware under
-- which this software may be used, no warranty of fitness for
-- a particular purpose is offered.  The user is advised to
-- test the software thoroughly before relying on it.  The user
-- must assume the entire risk and liability of using this
-- software.
--
-- In no event shall any person or organization of people be
-- held responsible for any direct, indirect, consequential
-- or inconsequential damages or lost profits.
-- UNIT: generic package spec of VSTRINGS
--
-- FILES: vstring_spec.a in publiclib
--        related file is vstring_body.a in publiclib
--
-- PURPOSE:  An implementation of the abstract data type "variable-length
--           string."
--
-- DESCRIPTION:  This package provides a private type VSTRING.  VSTRING objects
--               are "strings" that have a length between zero and LAST, where
--               LAST is the generic parameter supplied in the package
--               instantiation.
--
--               In addition to the type VSTRING, a subtype and two constants
--               are declared.  The subtype STRINDEX is an index to a VSTRING,
--               The STRINDEX constant FIRST is an index to the first character
--               of the string, and the VSTRING constant NUL is a VSTRING of
--               length zero.  NUL is the default initial value of a VSTRING.
--
--               The following sets of functions, procedures, and operators
--               are provided as operations on the type VSTRING:
--
--               ATTRIBUTE FUNCTIONS:  LEN, MAX, STR, CHAR
--                 The attribute functions return the characteristics of
--                 a VSTRING.
--
--               COMPARISON OPERATORS: "=", "/=", "<", ">", "<=", ">="
--                 The comparison operators are the same as for the predefined
--                 type STRING.
--
--               INPUT/OUTPUT PROCEDURES: GET, GET_LINE, PUT, PUT_LINE
--                                        
--                 The input/output procedures are similar to those for the
--                 predefined type STRING, with the following exceptions:
--
--                   - GET has an optional parameter LENGTH, which indicates
--                     the number of characters to get (default is LAST).
--
--                   - GET_LINE does not have a parameter to return the length
--                     of the string (the LEN function should be used instead).
--
--               EXTRACTION FUNCTIONS: SLICE, SUBSTR, DELETE
--                 The SLICE function returns the slice of a VSTRING between
--                 two indices (equivalent to STR(X)(A .. B)).
--
--                 SUBSTR returns a substring of a VSTRING taken from a given
--                 index and extending a given length.
--
--                 The DELETE function returns the VSTRING which results from
--                 removing the slice between two indices.
--
--               EDITING FUNCTIONS: INSERT, APPEND, REPLACE
--                 The editing functions return the VSTRING which results from
--                 inserting, appending, or replacing at a given index with a
--                 VSTRING, STRING, or CHARACTER.  The index must be in the
--                 current range of the VSTRING; i.e., zero cannot be used.
--
--               CONCATENATION OPERATOR:  "&"
--                 The concatenation operator is the same as for the type
--                 STRING.  It should be used instead of APPEND when the
--                 APPEND would always be after the last character.
--
--               POSITION FUNCTIONS: INDEX, RINDEX
--                 The position functions return an index to the Nth occurrence
--                 of a VSTRING, STRING, or CHARACTER from the front or back
--                 of a VSTRING.  Zero is returned if the search is not
--                 successful.
--
--               CONVERSION FUNCTIONS AND OPERATOR: VSTR, CONVERT, "+"
--                 VSTR converts a STRING or a CHARACTER to a VSTRING.
--
--                 CONVERT is a generic function which can be instantiated to
--                 convert from any given variable-length string to another,
--                 provided the FROM type has a function equivelent to STR
--                 defined for it, and that the TO type has a function equiv-
--                 elent to VSTR defined for it.  This provides a means for
--                 converting between VSTRINGs declared in separate instant-
--                 iations of VSTRINGS.  When instantiating CONVERT for 
--                 VSTRINGs, the STR and VSTR functions are implicitly defined,
--                 provided that they have been made visible (by a use clause).
--
--                 Note:  CONVERT is NOT implicitly associated with the type 
--                 VSTRING declared in this package (since it would not be a
--                 derivable function (see RM 3.4(11))).
--
--                 Caution:  CONVERT cannot be instantiated directly with the
--                 names VSTR and STR, since the name of the subprogram being
--                 declared would hide the generic parameters with the same
--                 names (see RM 8.3(16)).  CONVERT can be instantiated with
--                 the operator "+", and any instantiation of CONVERT can
--                 subsequently be renamed VSTR or STR.
--
--                 Example:  Given two VSTRINGS instantiations X and Y:
--                   function "+" is new X.CONVERT(X.VSTRING, Y.VSTRING);
--                   function "+" is new X.CONVERT(Y.VSTRING, X.VSTRING);
--
--                   (Y.CONVERT could have been used in place of X.CONVERT)
--
--                   function VSTR(A : X.VSTRING) return Y.VSTRING renames "+";
--                   function VSTR(A : Y.VSTRING) return X.VSTRING renames "+";
--
--                 "+" is equivelent to VSTR.  It is supplied as a short-hand
--                 notation for the function.  The "+" operator cannot immed-
--                 iately follow the "&" operator; use ... & (+ ...) instead.
pragma PAGE;
\f


--  DISCUSSION:
--
--	This package implements the type "variable-length string" (vstring)
--	using generics.  The alternative approaches are to use a discriminant 
--	record in which the discriminant controls the length of a STRING inside
--	the record, or a record containing an access type which points to a
--      string, which can be deallocated and reallocated when necessary.
--
--	Advantages of this package:
--	  * The other approaches force the vstring to be a limited private 
--          type.  Thus, their vstrings cannot appear on the left side of
--          the assignment operator; ie., their vstrings cannot be given
--          initial values or values by direct assignment.  This package
--          uses a private type; therefore, these things can be done.
--         
--	  * The other approach stores the vstring in a string whose length
--	    is determined dynamically.  This package uses a fixed length 
--          string.  This difference might be reflected in faster and more
--          consistent execution times (this has NOT been verified).
--
--	Disadvantages of this package:
--	  * Different instantiations must be used to declare vstrings with
--	    different maximum lengths (this may be desirable, since
--	    CONSTRAINT_ERROR will be raised if the maximum is exceeded).
--
--	  * A second declaration is required to give the type declared by
--	    the instantiation a name other than "VSTRING."
--
--	  * The storage required for a vstring is determined by the generic
--	    parameter LAST and not the actual length of its contents.  Thus,
--          each object is allocated the maximum amount of storage, regardless
--          of its actual size.
--
--  MISCELLANEOUS:
--     Constraint checking is done explicitly in the code; thus, it cannot
--     be suppressed.  On the other hand, constraint checking is not lost
--     if pragma suppress is supplied to the compilation (-S option) 
--     (The robustness of the explicit constraint checking has NOT been 
--     determined).
--
--     Compiling with the optimizer (-O option) may significantly reduce
--     the size (and possibly execution time) of the resulting executable.
--
--     Compiling an instantiation of VSTRINGS is roughly equivelent to
--     recompiling VSTRINGS.  Since this takes a significant amount of time,
--     and the instantiation does not depend on any other library units,
--     it is STRONGLY recommended that the instantiation be compiled
--     separately, and thus done only ONCE.
--
--  USAGE: with VSTRINGS;
--         package package_name is new VSTRINGS(maximum_length);
-- .......................................................................... --
pragma PAGE;
\f


with TEXT_IO; use TEXT_IO;
generic
  LAST : NATURAL;
package VSTRINGS is

  subtype STRINDEX is NATURAL;
  FIRST : constant STRINDEX := STRINDEX'FIRST + 1;
  type VSTRING is private;
  NUL : constant VSTRING;

-- Attributes of a VSTRING

  function LEN(FROM : VSTRING) return STRINDEX;
  function MAX(FROM : VSTRING) return STRINDEX;
  function STR(FROM : VSTRING) return STRING;
  function CHAR(FROM: VSTRING; POSITION : STRINDEX := FIRST)
                return CHARACTER;

-- Comparisons

  function "<" (LEFT: VSTRING; RIGHT: VSTRING) return BOOLEAN;
  function ">" (LEFT: VSTRING; RIGHT: VSTRING) return BOOLEAN;
  function "<=" (LEFT: VSTRING; RIGHT: VSTRING) return BOOLEAN;
  function ">=" (LEFT: VSTRING; RIGHT: VSTRING) return BOOLEAN;
  -- "=" and "/=" are predefined

-- Input/Output

  procedure PUT(FILE : in FILE_TYPE; ITEM : in VSTRING);
  procedure PUT(ITEM : in VSTRING);

  procedure PUT_LINE(FILE : in FILE_TYPE; ITEM : in VSTRING);
  procedure PUT_LINE(ITEM : in VSTRING);

  procedure GET(FILE : in FILE_TYPE; ITEM : out VSTRING;
                LENGTH : in STRINDEX := LAST);
  procedure GET(ITEM : out VSTRING; LENGTH : in STRINDEX := LAST);

  procedure GET_LINE(FILE : in FILE_TYPE; ITEM : in out VSTRING);
  procedure GET_LINE(ITEM : in out VSTRING);

-- Extraction

  function SLICE(FROM: VSTRING; FRONT, BACK : STRINDEX) return VSTRING;
  function SUBSTR(FROM: VSTRING; START, LENGTH: STRINDEX) return VSTRING;
  function DELETE(FROM: VSTRING; FRONT, BACK : STRINDEX) return VSTRING;

-- Editing

  function INSERT(TARGET: VSTRING; ITEM: VSTRING;
                  POSITION: STRINDEX := FIRST) return VSTRING;
  function INSERT(TARGET: VSTRING; ITEM: STRING;
                  POSITION: STRINDEX := FIRST) return VSTRING;
  function INSERT(TARGET: VSTRING; ITEM: CHARACTER;
                  POSITION: STRINDEX := FIRST) return VSTRING;

  function APPEND(TARGET: VSTRING; ITEM: VSTRING; POSITION: STRINDEX)
                  return VSTRING;
  function APPEND(TARGET: VSTRING; ITEM: STRING; POSITION: STRINDEX)
                  return VSTRING;
  function APPEND(TARGET: VSTRING; ITEM: CHARACTER; POSITION: STRINDEX)
                  return VSTRING;

  function APPEND(TARGET: VSTRING; ITEM: VSTRING) return VSTRING;
  function APPEND(TARGET: VSTRING; ITEM: STRING) return VSTRING;
  function APPEND(TARGET: VSTRING; ITEM: CHARACTER) return VSTRING;

  function REPLACE(TARGET: VSTRING; ITEM: VSTRING;
                   POSITION: STRINDEX := FIRST) return VSTRING;
  function REPLACE(TARGET: VSTRING; ITEM: STRING;
                   POSITION: STRINDEX := FIRST) return VSTRING;
  function REPLACE(TARGET: VSTRING; ITEM: CHARACTER;
                   POSITION: STRINDEX := FIRST) return VSTRING;

-- Concatenation

  function "&" (LEFT: VSTRING; RIGHT : VSTRING) return VSTRING;
  function "&" (LEFT: VSTRING; RIGHT : STRING) return VSTRING;
  function "&" (LEFT: VSTRING; RIGHT : CHARACTER) return VSTRING;
  function "&" (LEFT: STRING; RIGHT : VSTRING) return VSTRING;
  function "&" (LEFT: CHARACTER; RIGHT : VSTRING) return VSTRING;

-- Determine the position of a substring

  function INDEX(WHOLE: VSTRING; PART: VSTRING; OCCURRENCE : NATURAL := 1)
                 return STRINDEX;
  function INDEX(WHOLE : VSTRING; PART : STRING; OCCURRENCE : NATURAL := 1)
                 return STRINDEX;
  function INDEX(WHOLE : VSTRING; PART : CHARACTER; OCCURRENCE : NATURAL := 1)
                 return STRINDEX;


  function RINDEX(WHOLE: VSTRING; PART: VSTRING; OCCURRENCE : NATURAL := 1)
                 return STRINDEX;
  function RINDEX(WHOLE : VSTRING; PART : STRING; OCCURRENCE : NATURAL := 1)
                 return STRINDEX;
  function RINDEX(WHOLE : VSTRING; PART : CHARACTER; OCCURRENCE : NATURAL := 1)
                 return STRINDEX;

-- Conversion from other associated types

  function VSTR(FROM : STRING) return VSTRING;
  function VSTR(FROM : CHARACTER) return VSTRING;
  function "+" (FROM : STRING) return VSTRING;
  function "+" (FROM : CHARACTER) return VSTRING;

  generic
    type FROM is private;
    type TO is private;
    with function STR(X : FROM) return STRING is <>;
    with function VSTR(Y : STRING) return TO is <>;
   function CONVERT(X : FROM) return TO;

pragma PAGE;
\f


  private
    type VSTRING is
      record 
        LEN : STRINDEX := STRINDEX'FIRST;
        VALUE : STRING(FIRST .. LAST) := (others => ASCII.NUL);
      end record;
 
    NUL : constant VSTRING := (STRINDEX'FIRST, (others => ASCII.NUL));
end VSTRINGS;
--
-- .......................................................................... --
--
-- DISTRIBUTION AND COPYRIGHT:
--                                                           
-- This software is released to the Public Domain (note:
--   software released to the Public Domain is not subject
--   to copyright protection).
-- Restrictions on use or distribution:  NONE
--                                                           
-- DISCLAIMER:
--                                                           
-- This software and its documentation are provided "AS IS" and
-- without any expressed or implied warranties whatsoever.
-- No warranties as to performance, merchantability, or fitness
-- for a particular purpose exist.
--
-- Because of the diversity of conditions and hardware under
-- which this software may be used, no warranty of fitness for
-- a particular purpose is offered.  The user is advised to
-- test the software thoroughly before relying on it.  The user
-- must assume the entire risk and liability of using this
-- software.
--
-- In no event shall any person or organization of people be
-- held responsible for any direct, indirect, consequential
-- or inconsequential damages or lost profits.