|
|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 Tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: B T
Length: 21499 (0x53fb)
Types: TextFile
Names: »B«
└─⟦a7d1ea751⟧ Bits:30000550 8mm tape, Rational 1000, !users!projects 94_04_11
└─⟦129cab021⟧ »DATA«
└─⟦this⟧
└─⟦2f6cfab89⟧ Bits:30000547 8mm tape, Rational 1000, !projects 94-01-04
└─⟦d65440be7⟧ »DATA«
└─⟦this⟧
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 $