aboutsummaryrefslogtreecommitdiffstats
path: root/src/psl/psl-build.adb
diff options
context:
space:
mode:
Diffstat (limited to 'src/psl/psl-build.adb')
-rw-r--r--src/psl/psl-build.adb1009
1 files changed, 1009 insertions, 0 deletions
diff --git a/src/psl/psl-build.adb b/src/psl/psl-build.adb
new file mode 100644
index 000000000..c3e47baa6
--- /dev/null
+++ b/src/psl/psl-build.adb
@@ -0,0 +1,1009 @@
+with GNAT.Table;
+with Ada.Text_IO; use Ada.Text_IO;
+with Types; use Types;
+with PSL.Errors; use PSL.Errors;
+with PSL.CSE; use PSL.CSE;
+with PSL.QM;
+with PSL.Disp_NFAs; use PSL.Disp_NFAs;
+with PSL.Optimize; use PSL.Optimize;
+with PSL.NFAs.Utils;
+with PSL.Prints;
+with PSL.NFAs; use PSL.NFAs;
+
+package body PSL.Build is
+ function Build_SERE_FA (N : Node) return NFA;
+
+
+ package Intersection is
+ function Build_Inter (L, R : NFA; Match_Len : Boolean) return NFA;
+ end Intersection;
+
+ package body Intersection is
+
+ type Stack_Entry_Id is new Natural;
+ No_Stack_Entry : constant Stack_Entry_Id := 0;
+ type Stack_Entry is record
+ L, R : NFA_State;
+ Res : NFA_State;
+ Next_Unhandled : Stack_Entry_Id;
+ end record;
+
+ package Stackt is new GNAT.Table
+ (Table_Component_Type => Stack_Entry,
+ Table_Index_Type => Stack_Entry_Id,
+ Table_Low_Bound => 1,
+ Table_Initial => 128,
+ Table_Increment => 100);
+
+ First_Unhandled : Stack_Entry_Id;
+
+ procedure Init_Stack is
+ begin
+ Stackt.Init;
+ First_Unhandled := No_Stack_Entry;
+ end Init_Stack;
+
+ function Not_Empty return Boolean is
+ begin
+ return First_Unhandled /= No_Stack_Entry;
+ end Not_Empty;
+
+ procedure Pop_State (L, R : out NFA_State) is
+ begin
+ L := Stackt.Table (First_Unhandled).L;
+ R := Stackt.Table (First_Unhandled).R;
+ First_Unhandled := Stackt.Table (First_Unhandled).Next_Unhandled;
+ end Pop_State;
+
+ function Get_State (N : NFA; L, R : NFA_State) return NFA_State
+ is
+ Res : NFA_State;
+ begin
+ for I in Stackt.First .. Stackt.Last loop
+ if Stackt.Table (I).L = L
+ and then Stackt.Table (I).R = R
+ then
+ return Stackt.Table (I).Res;
+ end if;
+ end loop;
+ Res := Add_State (N);
+ Stackt.Append ((L => L, R => R, Res => Res,
+ Next_Unhandled => First_Unhandled));
+ First_Unhandled := Stackt.Last;
+ return Res;
+ end Get_State;
+
+ function Build_Inter (L, R : NFA; Match_Len : Boolean) return NFA
+ is
+ Start_L, Start_R : NFA_State;
+ Final_L, Final_R : NFA_State;
+ S_L, S_R : NFA_State;
+ E_L, E_R : NFA_Edge;
+ Res : NFA;
+ Start : NFA_State;
+ Extra_L, Extra_R : NFA_Edge;
+ begin
+ Start_L := Get_Start_State (L);
+ Start_R := Get_Start_State (R);
+ Final_R := Get_Final_State (R);
+ Final_L := Get_Final_State (L);
+
+ if False then
+ Disp_Body (L);
+ Disp_Body (R);
+ Put ("//start state: ");
+ Disp_State (Start_L);
+ Put (",");
+ Disp_State (Start_R);
+ New_Line;
+ end if;
+
+ if Match_Len then
+ Extra_L := No_Edge;
+ Extra_R := No_Edge;
+ else
+ Extra_L := Add_Edge (Final_L, Final_L, True_Node);
+ Extra_R := Add_Edge (Final_R, Final_R, True_Node);
+ end if;
+
+ Res := Create_NFA;
+ Init_Stack;
+ Start := Get_State (Res, Start_L, Start_R);
+ Set_Start_State (Res, Start);
+
+ while Not_Empty loop
+ Pop_State (S_L, S_R);
+
+ if False then
+ Put ("//poped state: ");
+ Disp_State (S_L);
+ Put (",");
+ Disp_State (S_R);
+ New_Line;
+ end if;
+
+ E_L := Get_First_Src_Edge (S_L);
+ while E_L /= No_Edge loop
+ E_R := Get_First_Src_Edge (S_R);
+ while E_R /= No_Edge loop
+ if not (E_L = Extra_L and E_R = Extra_R) then
+ Add_Edge (Get_State (Res, S_L, S_R),
+ Get_State (Res,
+ Get_Edge_Dest (E_L),
+ Get_Edge_Dest (E_R)),
+ Build_Bool_And (Get_Edge_Expr (E_L),
+ Get_Edge_Expr (E_R)));
+ end if;
+ E_R := Get_Next_Src_Edge (E_R);
+ end loop;
+ E_L := Get_Next_Src_Edge (E_L);
+ end loop;
+ end loop;
+ Set_Final_State (Res, Get_State (Res, Final_L, Final_R));
+ Remove_Unreachable_States (Res);
+
+ if not Match_Len then
+ Remove_Edge (Extra_L);
+ Remove_Edge (Extra_R);
+ end if;
+
+ -- FIXME: free L and R.
+ return Res;
+ end Build_Inter;
+ end Intersection;
+
+ -- All edges from A are duplicated using B as a source.
+ -- Handle epsilon-edges.
+ procedure Duplicate_Src_Edges (N : NFA; A, B : NFA_State)
+ is
+ pragma Unreferenced (N);
+ E : NFA_Edge;
+ Expr : Node;
+ Dest : NFA_State;
+ begin
+ pragma Assert (A /= B);
+ E := Get_First_Src_Edge (A);
+ while E /= No_Edge loop
+ Expr := Get_Edge_Expr (E);
+ Dest := Get_Edge_Dest (E);
+ if Expr /= Null_Node then
+ Add_Edge (B, Dest, Expr);
+ end if;
+ E := Get_Next_Src_Edge (E);
+ end loop;
+ end Duplicate_Src_Edges;
+
+ -- All edges to A are duplicated using B as a destination.
+ -- Handle epsilon-edges.
+ procedure Duplicate_Dest_Edges (N : NFA; A, B : NFA_State)
+ is
+ pragma Unreferenced (N);
+ E : NFA_Edge;
+ Expr : Node;
+ Src : NFA_State;
+ begin
+ pragma Assert (A /= B);
+ E := Get_First_Dest_Edge (A);
+ while E /= No_Edge loop
+ Expr := Get_Edge_Expr (E);
+ Src := Get_Edge_Src (E);
+ if Expr /= Null_Node then
+ Add_Edge (Src, B, Expr);
+ end if;
+ E := Get_Next_Dest_Edge (E);
+ end loop;
+ end Duplicate_Dest_Edges;
+
+ procedure Remove_Epsilon_Edge (N : NFA; S, D : NFA_State) is
+ begin
+ if Get_First_Src_Edge (S) = No_Edge then
+ -- No edge from S.
+ -- Move edges to S to D.
+ Redest_Edges (S, D);
+ Remove_Unconnected_State (N, S);
+ if Get_Start_State (N) = S then
+ Set_Start_State (N, D);
+ end if;
+ elsif Get_First_Dest_Edge (D) = No_Edge then
+ -- No edge to D.
+ -- Move edges from D to S.
+ Resource_Edges (D, S);
+ Remove_Unconnected_State (N, D);
+ if Get_Final_State (N) = D then
+ Set_Final_State (N, S);
+ end if;
+ else
+ Duplicate_Dest_Edges (N, S, D);
+ Duplicate_Src_Edges (N, D, S);
+ Remove_Identical_Src_Edges (S);
+ end if;
+ end Remove_Epsilon_Edge;
+
+ procedure Remove_Epsilon (N : NFA;
+ E : NFA_Edge) is
+ S : constant NFA_State := Get_Edge_Src (E);
+ D : constant NFA_State := Get_Edge_Dest (E);
+ begin
+ Remove_Edge (E);
+
+ Remove_Epsilon_Edge (N, S, D);
+ end Remove_Epsilon;
+
+ function Build_Concat (L, R : NFA) return NFA
+ is
+ Start_L, Start_R : NFA_State;
+ Final_L, Final_R : NFA_State;
+ Eps_L, Eps_R : Boolean;
+ E_L, E_R : NFA_Edge;
+ begin
+ Start_L := Get_Start_State (L);
+ Start_R := Get_Start_State (R);
+ Final_R := Get_Final_State (R);
+ Final_L := Get_Final_State (L);
+ Eps_L := Get_Epsilon_NFA (L);
+ Eps_R := Get_Epsilon_NFA (R);
+
+ Merge_NFA (L, R);
+
+ Set_Start_State (L, Start_L);
+ Set_Final_State (L, Final_R);
+ Set_Epsilon_NFA (L, False);
+
+ if Eps_L then
+ E_L := Add_Edge (Start_L, Final_L, Null_Node);
+ end if;
+
+ if Eps_R then
+ E_R := Add_Edge (Start_R, Final_R, Null_Node);
+ end if;
+
+ Remove_Epsilon_Edge (L, Final_L, Start_R);
+
+ if Eps_L then
+ Remove_Epsilon (L, E_L);
+ end if;
+ if Eps_R then
+ Remove_Epsilon (L, E_R);
+ end if;
+
+ if (Start_L = Final_L or else Eps_L)
+ and then (Start_R = Final_R or else Eps_R)
+ then
+ Set_Epsilon_NFA (L, True);
+ end if;
+
+ Remove_Identical_Src_Edges (Final_L);
+ Remove_Identical_Dest_Edges (Start_R);
+
+ return L;
+ end Build_Concat;
+
+ function Build_Or (L, R : NFA) return NFA
+ is
+ Start_L, Start_R : NFA_State;
+ Final_L, Final_R : NFA_State;
+ Eps : Boolean;
+ Start, Final : NFA_State;
+ E_S_L, E_S_R, E_L_F, E_R_F : NFA_Edge;
+ begin
+ Start_L := Get_Start_State (L);
+ Start_R := Get_Start_State (R);
+ Final_R := Get_Final_State (R);
+ Final_L := Get_Final_State (L);
+ Eps := Get_Epsilon_NFA (L) or Get_Epsilon_NFA (R);
+
+ -- Optimize [*0] | R.
+ if Start_L = Final_L
+ and then Get_First_Src_Edge (Start_L) = No_Edge
+ then
+ if Start_R /= Final_R then
+ Set_Epsilon_NFA (R, True);
+ end if;
+ -- FIXME
+ -- delete_NFA (L);
+ return R;
+ end if;
+
+ Merge_NFA (L, R);
+
+ -- Use Thompson construction.
+ Start := Add_State (L);
+ Set_Start_State (L, Start);
+ E_S_L := Add_Edge (Start, Start_L, Null_Node);
+ E_S_R := Add_Edge (Start, Start_R, Null_Node);
+
+ Final := Add_State (L);
+ Set_Final_State (L, Final);
+ E_L_F := Add_Edge (Final_L, Final, Null_Node);
+ E_R_F := Add_Edge (Final_R, Final, Null_Node);
+
+ Set_Epsilon_NFA (L, Eps);
+
+ Remove_Epsilon (L, E_S_L);
+ Remove_Epsilon (L, E_S_R);
+ Remove_Epsilon (L, E_L_F);
+ Remove_Epsilon (L, E_R_F);
+
+ return L;
+ end Build_Or;
+
+ function Build_Fusion (L, R : NFA) return NFA
+ is
+ Start_R : NFA_State;
+ Final_L, Final_R, S_L : NFA_State;
+ E_L : NFA_Edge;
+ E_R : NFA_Edge;
+ N_L, Expr : Node;
+ begin
+ Start_R := Get_Start_State (R);
+ Final_R := Get_Final_State (R);
+ Final_L := Get_Final_State (L);
+
+ Merge_NFA (L, R);
+
+ E_L := Get_First_Dest_Edge (Final_L);
+ while E_L /= No_Edge loop
+ S_L := Get_Edge_Src (E_L);
+ N_L := Get_Edge_Expr (E_L);
+
+ E_R := Get_First_Src_Edge (Start_R);
+ while E_R /= No_Edge loop
+ Expr := Build_Bool_And (N_L, Get_Edge_Expr (E_R));
+ Expr := PSL.QM.Reduce (Expr);
+ if Expr /= False_Node then
+ Add_Edge (S_L, Get_Edge_Dest (E_R), Expr);
+ end if;
+ E_R := Get_Next_Src_Edge (E_R);
+ end loop;
+ Remove_Identical_Src_Edges (S_L);
+ E_L := Get_Next_Dest_Edge (E_L);
+ end loop;
+
+ Set_Final_State (L, Final_R);
+
+ Set_Epsilon_NFA (L, False);
+
+ if Get_First_Src_Edge (Final_L) = No_Edge then
+ Remove_State (L, Final_L);
+ end if;
+ if Get_First_Dest_Edge (Start_R) = No_Edge then
+ Remove_State (L, Start_R);
+ end if;
+
+ return L;
+ end Build_Fusion;
+
+ function Build_Star_Repeat (N : Node) return NFA is
+ Res : NFA;
+ Start, Final, S : NFA_State;
+ Seq : Node;
+ begin
+ Seq := Get_Sequence (N);
+ if Seq = Null_Node then
+ -- Epsilon.
+ Res := Create_NFA;
+ S := Add_State (Res);
+ Set_Start_State (Res, S);
+ Set_Final_State (Res, S);
+ return Res;
+ end if;
+ Res := Build_SERE_FA (Seq);
+ Start := Get_Start_State (Res);
+ Final := Get_Final_State (Res);
+ Redest_Edges (Final, Start);
+ Set_Final_State (Res, Start);
+ Remove_Unconnected_State (Res, Final);
+ Set_Epsilon_NFA (Res, False);
+ return Res;
+ end Build_Star_Repeat;
+
+ function Build_Plus_Repeat (N : Node) return NFA is
+ Res : NFA;
+ Start, Final : NFA_State;
+ T : NFA_Edge;
+ begin
+ Res := Build_SERE_FA (Get_Sequence (N));
+ Start := Get_Start_State (Res);
+ Final := Get_Final_State (Res);
+ T := Get_First_Dest_Edge (Final);
+ while T /= No_Edge loop
+ Add_Edge (Get_Edge_Src (T), Start, Get_Edge_Expr (T));
+ T := Get_Next_Src_Edge (T);
+ end loop;
+ return Res;
+ end Build_Plus_Repeat;
+
+ -- Association actual to formals, so that when a formal is referenced, the
+ -- actual can be used instead.
+ procedure Assoc_Instance (Decl : Node; Instance : Node)
+ is
+ Formal : Node;
+ Actual : Node;
+ begin
+ -- Temporary associates actuals to formals.
+ Formal := Get_Parameter_List (Decl);
+ Actual := Get_Association_Chain (Instance);
+ while Formal /= Null_Node loop
+ if Actual = Null_Node then
+ -- Not enough actual.
+ raise Internal_Error;
+ end if;
+ if Get_Actual (Formal) /= Null_Node then
+ -- Recursion
+ raise Internal_Error;
+ end if;
+ Set_Actual (Formal, Get_Actual (Actual));
+ Formal := Get_Chain (Formal);
+ Actual := Get_Chain (Actual);
+ end loop;
+ if Actual /= Null_Node then
+ -- Too many actual.
+ raise Internal_Error;
+ end if;
+ end Assoc_Instance;
+
+ procedure Unassoc_Instance (Decl : Node)
+ is
+ Formal : Node;
+ begin
+ -- Remove temporary association.
+ Formal := Get_Parameter_List (Decl);
+ while Formal /= Null_Node loop
+ Set_Actual (Formal, Null_Node);
+ Formal := Get_Chain (Formal);
+ end loop;
+ end Unassoc_Instance;
+
+ function Build_SERE_FA (N : Node) return NFA
+ is
+ Res : NFA;
+ S1, S2 : NFA_State;
+ begin
+ case Get_Kind (N) is
+ when N_Booleans =>
+ Res := Create_NFA;
+ S1 := Add_State (Res);
+ S2 := Add_State (Res);
+ Set_Start_State (Res, S1);
+ Set_Final_State (Res, S2);
+ if N /= False_Node then
+ Add_Edge (S1, S2, N);
+ end if;
+ return Res;
+ when N_Braced_SERE =>
+ return Build_SERE_FA (Get_SERE (N));
+ when N_Concat_SERE =>
+ return Build_Concat (Build_SERE_FA (Get_Left (N)),
+ Build_SERE_FA (Get_Right (N)));
+ when N_Fusion_SERE =>
+ return Build_Fusion (Build_SERE_FA (Get_Left (N)),
+ Build_SERE_FA (Get_Right (N)));
+ when N_Match_And_Seq =>
+ return Intersection.Build_Inter (Build_SERE_FA (Get_Left (N)),
+ Build_SERE_FA (Get_Right (N)),
+ True);
+ when N_And_Seq =>
+ return Intersection.Build_Inter (Build_SERE_FA (Get_Left (N)),
+ Build_SERE_FA (Get_Right (N)),
+ False);
+ when N_Or_Prop
+ | N_Or_Seq =>
+ return Build_Or (Build_SERE_FA (Get_Left (N)),
+ Build_SERE_FA (Get_Right (N)));
+ when N_Star_Repeat_Seq =>
+ return Build_Star_Repeat (N);
+ when N_Plus_Repeat_Seq =>
+ return Build_Plus_Repeat (N);
+ when N_Sequence_Instance
+ | N_Endpoint_Instance =>
+ declare
+ Decl : Node;
+ begin
+ Decl := Get_Declaration (N);
+ Assoc_Instance (Decl, N);
+ Res := Build_SERE_FA (Get_Sequence (Decl));
+ Unassoc_Instance (Decl);
+ return Res;
+ end;
+ when N_Boolean_Parameter
+ | N_Sequence_Parameter =>
+ declare
+ Actual : constant Node := Get_Actual (N);
+ begin
+ if Actual = Null_Node then
+ raise Internal_Error;
+ end if;
+ return Build_SERE_FA (Actual);
+ end;
+ when others =>
+ Error_Kind ("build_sere_fa", N);
+ end case;
+ end Build_SERE_FA;
+
+ function Count_Edges (S : NFA_State) return Natural
+ is
+ Res : Natural;
+ E : NFA_Edge;
+ begin
+ Res := 0;
+ E := Get_First_Src_Edge (S);
+ while E /= No_Edge loop
+ Res := Res + 1;
+ E := Get_Next_Src_Edge (E);
+ end loop;
+ return Res;
+ end Count_Edges;
+
+ type Count_Vector is array (Natural range <>) of Natural;
+
+ procedure Count_All_Edges (N : NFA; Res : out Count_Vector)
+ is
+ S : NFA_State;
+ begin
+ S := Get_First_State (N);
+ while S /= No_State loop
+ Res (Natural (Get_State_Label (S))) := Count_Edges (S);
+ S := Get_Next_State (S);
+ end loop;
+ end Count_All_Edges;
+
+ pragma Unreferenced (Count_All_Edges);
+
+ package Determinize is
+ -- Create a new NFA that reaches its final state only when N fails
+ -- (ie when the final state is not reached).
+ function Determinize (N : NFA) return NFA;
+ end Determinize;
+
+ package body Determinize is
+ -- In all the comments N stands for the initial NFA (ie the NFA to
+ -- determinize).
+
+ use Prints;
+
+ Flag_Trace : constant Boolean := False;
+ Last_Label : Int32 := 0;
+
+ -- The tree associates a set of states in N to *an* uniq set in the
+ -- result NFA.
+ --
+ -- As the NFA is labelized, each node represent a state in N, and has
+ -- two branches: one for state is present and one for state is absent.
+ --
+ -- The leaves contain the state in the result NFA.
+ --
+ -- The leaves are chained to create a stack of state to handle.
+ --
+ -- The root of the tree is node Start_Tree_Id and represent the start
+ -- state of N.
+ type Deter_Tree_Id is new Natural;
+ No_Tree_Id : constant Deter_Tree_Id := 0;
+ Start_Tree_Id : constant Deter_Tree_Id := 1;
+
+ -- List of unhanded leaves.
+ Deter_Head : Deter_Tree_Id;
+
+ type Deter_Tree_Id_Bool_Array is array (Boolean) of Deter_Tree_Id;
+
+ -- Node in the tree.
+ type Deter_Tree_Entry is record
+ Parent : Deter_Tree_Id;
+
+ -- For non-leaf:
+ Child : Deter_Tree_Id_Bool_Array;
+
+ -- For leaf:
+ Link : Deter_Tree_Id;
+ State : NFA_State;
+ -- + value ?
+ end record;
+
+ package Detert is new GNAT.Table
+ (Table_Component_Type => Deter_Tree_Entry,
+ Table_Index_Type => Deter_Tree_Id,
+ Table_Low_Bound => 1,
+ Table_Initial => 128,
+ Table_Increment => 100);
+
+ type Bool_Vector is array (Natural range <>) of Boolean;
+ pragma Pack (Bool_Vector);
+
+ -- Convert a set of states in N to a state in the result NFA.
+ -- The set is represented by a vector of boolean. An element of the
+ -- vector is true iff the corresponding state is present.
+ function Add_Vector (V : Bool_Vector; N : NFA) return NFA_State
+ is
+ E : Deter_Tree_Id;
+ Added : Boolean;
+ Res : NFA_State;
+ begin
+ E := Start_Tree_Id;
+ Added := False;
+ for I in V'Range loop
+ if Detert.Table (E).Child (V (I)) = No_Tree_Id then
+ Detert.Append ((Child => (No_Tree_Id, No_Tree_Id),
+ Parent => E,
+ Link => No_Tree_Id,
+ State => No_State));
+ Detert.Table (E).Child (V (I)) := Detert.Last;
+ E := Detert.Last;
+ Added := True;
+ else
+ E := Detert.Table (E).Child (V (I));
+ Added := False;
+ end if;
+ end loop;
+ if Added then
+ -- Create the new state.
+ Res := Add_State (N);
+ Detert.Table (E).State := Res;
+
+ if Flag_Trace then
+ Set_State_Label (Res, Last_Label);
+ Put ("Result state" & Int32'Image (Last_Label) & " for");
+ for I in V'Range loop
+ if V (I) then
+ Put (Natural'Image (I));
+ end if;
+ end loop;
+ New_Line;
+ Last_Label := Last_Label + 1;
+ end if;
+
+ -- Put it to the list of states to be handled.
+ Detert.Table (E).Link := Deter_Head;
+ Deter_Head := E;
+
+ return Res;
+ else
+ return Detert.Table (E).State;
+ end if;
+ end Add_Vector;
+
+ -- Return true iff the stack is empty (ie all the states have been
+ -- handled).
+ function Stack_Empty return Boolean is
+ begin
+ return Deter_Head = No_Tree_Id;
+ end Stack_Empty;
+
+ -- Get an element from the stack.
+ -- Extract the state in the result NFA.
+ -- Rebuild the set of states in N (ie rebuild the vector of states).
+ procedure Stack_Pop (V : out Bool_Vector; S : out NFA_State)
+ is
+ L, P : Deter_Tree_Id;
+ begin
+ L := Deter_Head;
+ pragma Assert (L /= No_Tree_Id);
+ S := Detert.Table (L).State;
+ Deter_Head := Detert.Table (L).Link;
+
+ for I in reverse V'Range loop
+ pragma Assert (L /= Start_Tree_Id);
+ P := Detert.Table (L).Parent;
+ if L = Detert.Table (P).Child (True) then
+ V (I) := True;
+ elsif L = Detert.Table (P).Child (False) then
+ V (I) := False;
+ else
+ raise Program_Error;
+ end if;
+ L := P;
+ end loop;
+ pragma Assert (L = Start_Tree_Id);
+ end Stack_Pop;
+
+ type State_Vector is array (Natural range <>) of Natural;
+ type Expr_Vector is array (Natural range <>) of Node;
+
+ procedure Build_Arcs (N : NFA;
+ State : NFA_State;
+ States : State_Vector;
+ Exprs : Expr_Vector;
+ Expr : Node;
+ V : Bool_Vector)
+ is
+ begin
+ if Expr = False_Node then
+ return;
+ end if;
+
+ if States'Length = 0 then
+ declare
+ Reduced_Expr : constant Node := PSL.QM.Reduce (Expr);
+ --Reduced_Expr : constant Node := Expr;
+ S : NFA_State;
+ begin
+ if Reduced_Expr = False_Node then
+ return;
+ end if;
+ S := Add_Vector (V, N);
+ Add_Edge (State, S, Reduced_Expr);
+ if Flag_Trace then
+ Put (" Add edge");
+ Put (Int32'Image (Get_State_Label (State)));
+ Put (" to");
+ Put (Int32'Image (Get_State_Label (S)));
+ Put (", expr=");
+ Dump_Expr (Expr);
+ Put (", reduced=");
+ Dump_Expr (Reduced_Expr);
+ New_Line;
+ end if;
+ end;
+ else
+ declare
+ N_States : State_Vector renames
+ States (States'First + 1 .. States'Last);
+ N_V : Bool_Vector (V'Range) := V;
+ S : constant Natural := States (States'First);
+ E : constant Node := Exprs (S);
+ begin
+ N_V (S) := True;
+ if Expr = Null_Node then
+ Build_Arcs (N, State, N_States, Exprs, E, N_V);
+ Build_Arcs (N, State, N_States, Exprs,
+ Build_Bool_Not (E), V);
+ else
+ Build_Arcs (N, State, N_States, Exprs,
+ Build_Bool_And (E, Expr), N_V);
+ Build_Arcs (N, State, N_States, Exprs,
+ Build_Bool_And (Build_Bool_Not (E), Expr), V);
+ end if;
+ end;
+ end if;
+ end Build_Arcs;
+
+ function Determinize_1 (N : NFA; Nbr_States : Natural) return NFA
+ is
+ Final : Natural;
+ V : Bool_Vector (0 .. Nbr_States - 1);
+ Exprs : Expr_Vector (0 .. Nbr_States - 1);
+ S : NFA_State;
+ E : NFA_Edge;
+ D : Natural;
+ Edge_Expr : Node;
+ Expr : Node;
+ Nbr_Dest : Natural;
+ States : State_Vector (0 .. Nbr_States - 1);
+ Res : NFA;
+ State : NFA_State;
+ begin
+ Final := Natural (Get_State_Label (Get_Final_State (N)));
+
+ -- FIXME: handle epsilon or final = start -> create an empty NFA.
+
+ -- Initialize the tree.
+ Res := Create_NFA;
+ Detert.Init;
+ Detert.Append ((Child => (No_Tree_Id, No_Tree_Id),
+ Parent => No_Tree_Id,
+ Link => No_Tree_Id,
+ State => No_State));
+ pragma Assert (Detert.Last = Start_Tree_Id);
+ Deter_Head := No_Tree_Id;
+
+ -- Put the initial state in the tree and in the stack.
+ -- FIXME: ok, we know that its label is 0.
+ V := (0 => True, others => False);
+ State := Add_Vector (V, Res);
+ Set_Start_State (Res, State);
+
+ -- The failure state. As there is nothing to do with this
+ -- state, remove it from the stack.
+ V := (others => False);
+ State := Add_Vector (V, Res);
+ Set_Final_State (Res, State);
+ Stack_Pop (V, State);
+
+ -- Iterate on states in the result NFA that haven't yet been handled.
+ while not Stack_Empty loop
+ Stack_Pop (V, State);
+
+ if Flag_Trace then
+ Put_Line ("Handle result state"
+ & Int32'Image (Get_State_Label (State)));
+ end if;
+
+ -- Build edges vector.
+ Exprs := (others => Null_Node);
+ Expr := Null_Node;
+
+ S := Get_First_State (N);
+ Nbr_Dest := 0;
+ while S /= No_State loop
+ if V (Natural (Get_State_Label (S))) then
+ E := Get_First_Src_Edge (S);
+ while E /= No_Edge loop
+ D := Natural (Get_State_Label (Get_Edge_Dest (E)));
+ Edge_Expr := Get_Edge_Expr (E);
+
+ if False and Flag_Trace then
+ Put_Line (" edge" & Int32'Image (Get_State_Label (S))
+ & " to" & Natural'Image (D));
+ end if;
+
+ if D = Final then
+ Edge_Expr := Build_Bool_Not (Edge_Expr);
+ if Expr = Null_Node then
+ Expr := Edge_Expr;
+ else
+ Expr := Build_Bool_And (Expr, Edge_Expr);
+ end if;
+ else
+ if Exprs (D) = Null_Node then
+ Exprs (D) := Edge_Expr;
+ States (Nbr_Dest) := D;
+ Nbr_Dest := Nbr_Dest + 1;
+ else
+ Exprs (D) := Build_Bool_Or (Exprs (D),
+ Edge_Expr);
+ end if;
+ end if;
+ E := Get_Next_Src_Edge (E);
+ end loop;
+ end if;
+ S := Get_Next_State (S);
+ end loop;
+
+ if Flag_Trace then
+ Put (" Final: expr=");
+ Print_Expr (Expr);
+ New_Line;
+ for I in 0 .. Nbr_Dest - 1 loop
+ Put (" Dest");
+ Put (Natural'Image (States (I)));
+ Put (" expr=");
+ Print_Expr (Exprs (States (I)));
+ New_Line;
+ end loop;
+ end if;
+
+ -- Build arcs.
+ if not (Nbr_Dest = 0 and Expr = Null_Node) then
+ Build_Arcs (Res, State,
+ States (0 .. Nbr_Dest - 1), Exprs, Expr,
+ Bool_Vector'(0 .. Nbr_States - 1 => False));
+ end if;
+ end loop;
+
+ --Remove_Unreachable_States (Res);
+ return Res;
+ end Determinize_1;
+
+ function Determinize (N : NFA) return NFA
+ is
+ Nbr_States : Natural;
+ begin
+ Labelize_States (N, Nbr_States);
+
+ if Flag_Trace then
+ Put_Line ("NFA to determinize:");
+ Disp_NFA (N);
+ Last_Label := 0;
+ end if;
+
+ return Determinize_1 (N, Nbr_States);
+ end Determinize;
+ end Determinize;
+
+ function Build_Initial_Rep (N : NFA) return NFA
+ is
+ S : constant NFA_State := Get_Start_State (N);
+ begin
+ Add_Edge (S, S, True_Node);
+ return N;
+ end Build_Initial_Rep;
+
+ procedure Build_Strong (N : NFA)
+ is
+ S : NFA_State;
+ Final : constant NFA_State := Get_Final_State (N);
+ begin
+ S := Get_First_State (N);
+ while S /= No_State loop
+ -- FIXME.
+ if S /= Final then
+ Add_Edge (S, Final, EOS_Node);
+ end if;
+ S := Get_Next_State (S);
+ end loop;
+ end Build_Strong;
+
+ procedure Build_Abort (N : NFA; Expr : Node)
+ is
+ S : NFA_State;
+ E : NFA_Edge;
+ Not_Expr : Node;
+ begin
+ Not_Expr := Build_Bool_Not (Expr);
+ S := Get_First_State (N);
+ while S /= No_State loop
+ E := Get_First_Src_Edge (S);
+ while E /= No_Edge loop
+ Set_Edge_Expr (E, Build_Bool_And (Not_Expr, Get_Edge_Expr (E)));
+ E := Get_Next_Src_Edge (E);
+ end loop;
+ S := Get_Next_State (S);
+ end loop;
+ end Build_Abort;
+
+ function Build_Property_FA (N : Node) return NFA
+ is
+ L, R : NFA;
+ begin
+ case Get_Kind (N) is
+ when N_Sequences
+ | N_Booleans =>
+ -- Build A(S) or A(B)
+ R := Build_SERE_FA (N);
+ return Determinize.Determinize (R);
+ when N_Strong =>
+ R := Build_Property_FA (Get_Property (N));
+ Build_Strong (R);
+ return R;
+ when N_Imp_Seq =>
+ -- R |=> P --> {R; TRUE} |-> P
+ L := Build_SERE_FA (Get_Sequence (N));
+ R := Build_Property_FA (Get_Property (N));
+ return Build_Concat (L, R);
+ when N_Overlap_Imp_Seq =>
+ -- S |-> P is defined as Ac(S) : A(P)
+ L := Build_SERE_FA (Get_Sequence (N));
+ R := Build_Property_FA (Get_Property (N));
+ return Build_Fusion (L, R);
+ when N_Log_Imp_Prop =>
+ -- B -> P --> {B} |-> P --> Ac(B) : A(P)
+ L := Build_SERE_FA (Get_Left (N));
+ R := Build_Property_FA (Get_Right (N));
+ return Build_Fusion (L, R);
+ when N_And_Prop =>
+ -- P1 && P2 --> A(P1) | A(P2)
+ L := Build_Property_FA (Get_Left (N));
+ R := Build_Property_FA (Get_Right (N));
+ return Build_Or (L, R);
+ when N_Never =>
+ R := Build_SERE_FA (Get_Property (N));
+ return Build_Initial_Rep (R);
+ when N_Always =>
+ R := Build_Property_FA (Get_Property (N));
+ return Build_Initial_Rep (R);
+ when N_Abort =>
+ R := Build_Property_FA (Get_Property (N));
+ Build_Abort (R, Get_Boolean (N));
+ return R;
+ when N_Property_Instance =>
+ declare
+ Decl : Node;
+ begin
+ Decl := Get_Declaration (N);
+ Assoc_Instance (Decl, N);
+ R := Build_Property_FA (Get_Property (Decl));
+ Unassoc_Instance (Decl);
+ return R;
+ end;
+ when others =>
+ Error_Kind ("build_property_fa", N);
+ end case;
+ end Build_Property_FA;
+
+ function Build_FA (N : Node) return NFA
+ is
+ use PSL.NFAs.Utils;
+ Res : NFA;
+ begin
+ Res := Build_Property_FA (N);
+ if Optimize_Final then
+ pragma Debug (Check_NFA (Res));
+
+ Remove_Unreachable_States (Res);
+ Remove_Simple_Prefix (Res);
+ Merge_Identical_States (Res);
+ Merge_Edges (Res);
+ end if;
+ -- Clear the QM table.
+ PSL.QM.Reset;
+ return Res;
+ end Build_FA;
+end PSL.Build;