-- Abstract : -- -- see spec -- -- Copyright (C) 2012 - 2015, 2017 - 2023 Free Software Foundation, Inc. -- -- This program is free software; you can redistribute it and/or -- modify it under terms of the GNU General Public License as -- published by the Free Software Foundation; either version 3, or (at -- your option) any later version. This program is distributed in the -- hope that it will be useful, but WITHOUT ANY WARRANTY; without even -- the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -- PURPOSE. See the GNU General Public License for more details. You -- should have received a copy of the GNU General Public License -- distributed with this program; see file COPYING. If not, write to -- the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, -- MA 02110-1335, USA. pragma License (GPL); with Ada.Command_Line; with Ada.Directories; with Ada.Environment_Variables; with Ada.Strings.Fixed; with Ada.Text_IO; package body WisiToken.BNF is function Is_Valid_Interface (Item : in String) return Boolean is Lower_Item : constant String := To_Lower (Item); begin return Lower_Item = "process" or Lower_Item = "module"; end Is_Valid_Interface; procedure Add (Set : in out Generate_Set_Access; Tuple : in Generate_Tuple) is Prev : Generate_Set_Access := Set; Last : constant Integer := (if Prev = null then 1 else Prev.all'Length + 1); begin Set := new Generate_Set (1 .. Last); for I in 1 .. Last - 1 loop Set (I) := Prev (I); end loop; Set (Last) := Tuple; Free (Prev); end Add; function Image (Item : in Generate_Tuple) return String is begin return "(" & Generate_Algorithm_Image (Item.Gen_Alg).all & ", " & Output_Language_Image (Item.Out_Lang).all & ", " & Lexer_Image (Item.Lexer).all & (if Item.Interface_Kind = None then "" else ", " & Interface_Image (Item.Interface_Kind).all) & (if Item.Text_Rep then ", text_rep" else "") & ")"; end Image; function To_Generate_Algorithm (Item : in String) return Generate_Algorithm is begin for I in Generate_Algorithm loop if To_Lower (Generate_Algorithm_Image (I).all) = To_Lower (Item) then return I; end if; end loop; raise User_Error with "invalid generate algorithm name: '" & Item & "'"; end To_Generate_Algorithm; function From_Generate_Env_Var return Generate_Algorithm_Set is Gen_String : constant String := Ada.Environment_Variables.Value ("GENERATE", ""); begin -- GENERATE env var defined in wisitoken_test.gpr if Gen_String = "" then return (others => True); elsif Gen_String = "BNF_EBNF_Tree_Sitter" then return (others => True); elsif Gen_String = "BNF_EBNF" or Gen_String = "BNF" or Gen_String = "EBNF" then return (Tree_Sitter => False, others => True); elsif Gen_String = "Tree_Sitter" then return (Tree_Sitter => True, others => False); else raise SAL.Programmer_Error with "unsupported GENERATE env var value '" & Gen_String & "'"; end if; end From_Generate_Env_Var; function To_Output_Language (Item : in String) return Output_Language is begin for I in Output_Language loop if To_Lower (Output_Language_Image (I).all) = To_Lower (Item) then return I; end if; end loop; raise User_Error with "invalid output language name: '" & Item & "'"; end To_Output_Language; function To_Lexer (Item : in String) return Lexer_Type is begin for I in Valid_Lexer loop if Lexer_Image (I).all = To_Lower (Item) then return I; end if; end loop; raise User_Error with "invalid lexer name: '" & Item & "'"; end To_Lexer; function Split_Lines (Item : in String) return String_Lists.List is CR : Character renames ASCII.CR; LF : Character renames ASCII.LF; Result : WisiToken.BNF.String_Lists.List; I : Integer := Item'First; First : Integer := Item'First; Last_Char : Character := ' '; begin loop exit when I > Item'Last; if Item (I) = LF then Result.Append (Item (First .. I - (if Last_Char = CR then 2 else 1))); First := I + 1; elsif I = Item'Last then Result.Append (Item (First .. I)); end if; Last_Char := Item (I); I := I + 1; end loop; return Result; end Split_Lines; function Trim (Item : in String_Lists.List; Comment_Start : in String) return String_Lists.List is use Ada.Strings; use Ada.Strings.Fixed; Result : String_Lists.List; Comment : Integer; procedure Maybe_Append (Line : in String) is begin if Line'Length > 0 then Result.Append (Line); end if; end Maybe_Append; begin for Line of Item loop Comment := Index (Line, Comment_Start, Going => Backward); if Comment /= 0 then Maybe_Append (Trim (Line (Line'First .. Comment - 1), Both)); else Maybe_Append (Trim (Line, Both)); end if; end loop; return Result; end Trim; procedure Put_Raw_Code (Comment_Syntax : in String_2; Code : in String_Lists.List; Comment_Only : in Boolean := False) is use Ada.Text_IO; Real_Comment_Only : Boolean := Comment_Only; begin for Line of Code loop if Line'Length >= 2 and then ((Line (Line'First) = Line (Line'First + 1)) and Line (Line'First) /= ' ') then -- The line is a comment. Real_Comment_Only := Real_Comment_Only or Line (Line'First .. Line'First + 1) /= Comment_Syntax; Put_Line (Comment_Syntax & Line (Line'First + 2 .. Line'Last)); elsif Comment_Syntax = Elisp_Comment and (Line'Length > 0 and then Line (Line'First) /= '(') then null; elsif not Comment_Only then Put_Line (Line); end if; end loop; end Put_Raw_Code; procedure Put_File_Header (Comment_Syntax : in String_2; Emacs_Local_Vars : in String := ""; Use_Tuple : in Boolean := False; Tuple : in Generate_Tuple := (others => <>)) is use Ada.Text_IO; begin Put_Line (Comment_Syntax & " generated parser support file. -*- buffer-read-only:t " & Emacs_Local_Vars & " -*-"); Put_Command_Line (Comment_Syntax & " ", Use_Tuple, Tuple); Put_Line (Comment_Syntax); end Put_File_Header; function Image (Item : in Labeled_Token) return String is use Ada.Strings.Unbounded; begin return (if Length (Item.Label) > 0 then -Item.Label & "=" else "") & (-Item.Identifier); end Image; function Is_Present (List : in WisiToken.BNF.String_Pair_Lists.List; Name : in String) return Boolean is use all type Ada.Strings.Unbounded.Unbounded_String; begin for Pair of List loop if Pair.Name = Name then return True; end if; end loop; return False; end Is_Present; function Value (List : in WisiToken.BNF.String_Pair_Lists.List; Name : in String) return String is use all type Ada.Strings.Unbounded.Unbounded_String; begin for Pair of List loop if Pair.Name = Name then return -Pair.Value; end if; end loop; raise Not_Found; end Value; function Count (Tokens : in Token_Lists.List) return Integer is Result : Integer := 0; begin for Kind of Tokens loop Result := Result + Integer (Kind.Tokens.Length); end loop; return Result; end Count; procedure Add_Token (Tokens : in out Token_Lists.List; Kind : in String; Name : in String; Value : in String; Repair_Image : in String := "") is use type Ada.Strings.Unbounded.Unbounded_String; begin for Token_Kind of Tokens loop if Token_Kind.Kind = Kind then Token_Kind.Tokens.Append ((+Name, +Value, +Repair_Image)); return; end if; end loop; -- Kind not found; add it declare Temp : String_Triple_Lists.List; begin Temp.Append ((+Name, +Value, +Repair_Image)); Tokens.Append ((+Kind, Temp)); end; end Add_Token; function Is_In (Tokens : in Token_Lists.List; Kind : in String) return Boolean is begin for Token of Tokens loop if -Token.Kind = Kind then return True; end if; end loop; return False; end Is_In; function Is_In (Tokens : in Token_Lists.List; Kind : in String; Value : in String) return Boolean is begin for Token of Tokens loop if -Token.Kind = Kind then for Item of Token.Tokens loop if -Item.Value = Value then return True; end if; end loop; end if; end loop; return False; end Is_In; function Is_Present (Rules : in Rule_Lists.List; LHS : in String) return Boolean is use Rule_Lists; Found : Boolean := False; procedure Process (Position : in Cursor) is begin if -Rules (Position).Left_Hand_Side = LHS then Found := True; end if; end Process; begin Rules.Iterate (Process'Access); return Found; end Is_Present; function Find (Rules : in Rule_Lists.List; LHS : in String) return Rule_Lists.Cursor is use Rule_Lists; Found : Cursor := No_Element; procedure Process (Position : in Cursor) is begin if -Rules (Position).Left_Hand_Side = LHS then Found := Position; end if; end Process; begin Rules.Iterate (Process'Access); return Found; end Find; function "+" (List : in String_Lists.List; Item : in String) return String_Lists.List is Result : String_Lists.List := List; begin Result.Append (Item); return Result; end "+"; function String_To_String_List (Item : in String) return String_Lists.List is Result : String_Lists.List; begin Result.Append (Item); return Result; end String_To_String_List; function RHS_To_RHS_List (Item : in RHS_Type) return RHS_Lists.List is Result : RHS_Lists.List; begin Result.Append (Item); return Result; end RHS_To_RHS_List; function "+" (List : in RHS_Lists.List; Item : in RHS_Type) return RHS_Lists.List is Result : RHS_Lists.List := List; begin Result.Append (Item); return Result; end "+"; procedure Put_Command_Line (Comment_Prefix : in String; Use_Tuple : in Boolean := False; Tuple : in Generate_Tuple := (others => <>)) is use Ada.Command_Line; use Ada.Text_IO; Max_Line_Length : constant := 120; Col : Integer := 0; procedure Put (Item : in String; Leading_Space : in Boolean) is begin if Col > 0 and Col + Item'Length + 1 > Max_Line_Length then New_Line; Col := Comment_Prefix'Length; Put (Comment_Prefix); else if Leading_Space then Put (" "); Col := Col + 1; end if; end if; Col := Col + Item'Length; Put (Item); end Put; begin Put (Comment_Prefix & "command line:", False); Put (Ada.Directories.Simple_Name (Command_Name), True); if Use_Tuple then Put (" --generate " & Generate_Algorithm'Image (Tuple.Gen_Alg) & " " & Output_Language_Image (Tuple.Out_Lang).all & (if Tuple.Lexer /= None then " " & Lexer_Image (Tuple.Lexer).all else "") & (if Tuple.Interface_Kind /= None then " " & Interface_Type'Image (Tuple.Interface_Kind) else "") & (if Tuple.Text_Rep then " text_rep" else "") & " " & Argument (Argument_Count), -- .wy file True); else for I in 1 .. Argument_Count loop Put (Argument (I), True); end loop; end if; New_Line; end Put_Command_Line; end WisiToken.BNF;