------------------------------------ -------------------------------------------- -- -- -- OCARINA COMPONENTS -- -- -- -- OCARINA.AADL.PARSER.COMPONENTS.FEATURES -- -- -- -- B o d y -- -- -- -- Copyright (C) 2005-2007, GET-Telecom Paris. -- -- -- -- Ocarina 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 2, or (at your option) any -- -- later version. Ocarina 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 Ocarina; see file COPYING. -- -- If not, write to the Free Software Foundation, 51 Franklin Street, Fifth -- -- Floor, Boston, MA 02111-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- Ocarina is maintained by the Ocarina team -- -- (ocarina-users@listes.enst.fr) -- -- -- ------------------------------------------------------------------------------ with Locations; with Ocarina.Nodes; with Ocarina.AADL.Lexer; with Ocarina.AADL.Tokens; with Ocarina.AADL.Parser.Identifiers; with Ocarina.AADL.Parser.Properties; with Ocarina.Builder.Components.Features; package body Ocarina.AADL.Parser.Components.Features is function P_In_Out_Item (Container : Types.node_id; Identifier : node_id; Is_Refinement : Boolean; Code : parsing_code) return node_id; -- Parse item begins with 'in' or 'out' -- Examples: Port_Spec, Parameter, ... and refinements function P_Port_Group_Spec (Container : Types.node_id; Identifier : node_id; Is_Refinement : Boolean) return node_id; -- Current token must be reserved word 'port' -- If Is_Refinement = TRUE, parse a Port_Group_Spec function P_Port_Spec (Container : node_id; Identifier : node_id; Is_Refinement : Boolean; Is_In : Boolean; Is_Out : Boolean) return node_id; -- Current token must be reserved word 'data' or 'event' -- If Is_Refinement = TRUE, parse a Port_Refinement function P_Parameter (Container : node_id; Identifier : node_id; Is_Refinement : Boolean; Is_In : Boolean; Is_Out : Boolean) return node_id; -- Parse Parameter and Parameter_Refinement function P_Subprogram_Spec (Container : Types.node_id; Identifier : node_id; Is_Refinement : Boolean) return node_id; -- Current token must be reserved word 'subprogram' or 'server' -- If Is_Refinement = TRUE, parse Data_Subprogram_Refinement or -- Server_Subprogram_Refinement -- else, parse Data_Subprogram_Spec or Server_Subprogram function P_Subcomponent_Access (Container : Types.node_id; Identifier : node_id; Is_Refinement : Boolean) return node_id; -- Parse Subcomponent_Access and Subcomponent_Access_Refinement ------------------- -- P_In_Out_Item -- ------------------- function P_In_Out_Item (Container : Types.node_id; Identifier : node_id; Is_Refinement : Boolean; Code : parsing_code) return node_id is use Tokens; use Lexer; Is_In : Boolean := False; Is_Out : Boolean := False; begin if Token = t_in then Is_In := True; Scan_Token; if Token = t_out then Is_Out := True; Scan_Token; end if; else Is_Out := True; Scan_Token; if Token = t_in then Is_In := True; Scan_Token; end if; end if; case Token is when t_data | t_event => if Code = pc_parameter or else Code = pc_parameter_refinement then DPE (Code, t_parameter); Skip_Tokens (t_semicolon); return No_Node; else return P_Port_Spec (Container, Identifier, Is_Refinement, Is_In, Is_Out); end if; when t_parameter => if Code = pc_port_spec or else Code = pc_port_refinement then DPE (Code, (t_data, t_event)); Skip_Tokens (t_semicolon); return No_Node; else return P_Parameter (Container, Identifier, Is_Refinement, Is_In, Is_Out); end if; when others => DPE (Code); Skip_Tokens (t_semicolon); return No_Node; end case; end P_In_Out_Item; ----------------- -- P_Parameter -- ----------------- -- parameter ::= -- defining_parameter_identifier : -- ( in | out | in out ) parameter data_classifier_reference -- [ { { parameter_property_association }+ } ] ; -- parameter_refinement ::= -- defining_parameter_identifier : refined to -- ( in | out | in out ) parameter data_classifier_reference -- [ { { parameter_property_association }+ } ] ; function P_Parameter (Container : node_id; Identifier : node_id; Is_Refinement : Boolean; Is_In : Boolean; Is_Out : Boolean) return node_id is use Locations; use Ocarina.Nodes; use Lexer; use Tokens; use Parser.Properties; use Parser.Identifiers; use Ocarina.Builder.Components.Features; Param : node_id := No_Node; Class_Ref : node_id := No_Node; Code : parsing_code; Loc : location; OK : Boolean; begin if Is_Refinement then Code := pc_parameter_refinement; else Code := pc_parameter; end if; Save_Lexer (Loc); Scan_Token; -- next token and ignore 'parameter' -- The data classifier is not mandatory if Token = t_identifier then Restore_Lexer (Loc); Class_Ref := P_Entity_Reference (Code); if No (Class_Ref) then Skip_Tokens (t_semicolon); return No_Node; end if; else Restore_Lexer (Loc); Class_Ref := No_Node; end if; Param := Add_New_Parameter (Loc => Ocarina.Nodes.Loc (Identifier), Container => Container, Name => Identifier, Is_In => Is_In, Is_Out => Is_Out, Is_Refinement => Is_Refinement); OK := P_Property_Associations (Param, True, pat_simple, Code); if not OK then return No_Node; end if; Save_Lexer (Loc); Scan_Token; if Token /= t_semicolon then DPE (Code, t_semicolon); Restore_Lexer (Loc); return No_Node; end if; if Param /= No_Node then Set_Entity_Ref (Param, Class_Ref); end if; return Param; end P_Parameter; ----------------------- -- P_Port_Group_Spec -- ----------------------- -- port_group_spec ::= -- defining_port_group_identifier : port group -- unique_port_group_type_reference -- [ { { portgroup_property_association }+ } ] ; -- port_group_refinement ::= -- defining_port_group_identifier : refined to port group -- unique_port_group_type_reference -- [ { { portgroup_property_association }+ } ] ; -- unique_port_group_type_reference ::= -- [ package_name :: ] port_group_type_identifier function P_Port_Group_Spec (Container : Types.node_id; Identifier : node_id; Is_Refinement : Boolean) return node_id is use Ocarina.Nodes; use Lexer; use Tokens; use Locations; use Parser.Properties; use Parser.Identifiers; use Ocarina.Builder.Components.Features; pragma assert (Container /= No_Node and then (Kind (Container) = k_component_implementation or else Kind (Container) = k_component_type or else Kind (Container) = k_port_group_type)); Group_Type_Ref : node_id := No_Node; Port_Group_Spec : node_id := No_Node; Code : parsing_code; OK : Boolean; Loc : location; begin if Is_Refinement then Code := pc_port_group_refinement; else Code := pc_port_group_spec; end if; Scan_Token; -- ignore 'port' if Token /= t_group then DPE (Code, t_group); Skip_Tokens (t_semicolon); return No_Node; end if; Save_Lexer (Loc); Scan_Token; if Token = t_identifier then Restore_Lexer (Loc); Group_Type_Ref := P_Entity_Reference (pc_unique_port_group_type_reference); if No (Group_Type_Ref) then Skip_Tokens (t_semicolon); return No_Node; end if; else Restore_Lexer (Loc); Group_Type_Ref := No_Node; -- OK, no port group type is given end if; Port_Group_Spec := Add_New_Port_Group_Spec (Loc => Ocarina.Nodes.Loc (Identifier), Name => Identifier, Container => Container, Is_Refinement => Is_Refinement); OK := P_Property_Associations (Port_Group_Spec, True, pat_simple, Code); if not OK then return No_Node; end if; Save_Lexer (Loc); Scan_Token; if Token /= t_semicolon then DPE (Code, t_semicolon); Restore_Lexer (Loc); return No_Node; end if; if Port_Group_Spec /= No_Node then Set_Entity_Ref (Port_Group_Spec, Group_Type_Ref); end if; return Port_Group_Spec; end P_Port_Group_Spec; ----------------- -- P_Port_Spec -- ----------------- -- port_spec ::= -- defining_port_identifier : ( in | out | in out ) port_type -- [ { { port_property_association }+ } ] ; -- port_refinement ::= -- defining_port_identifier : refined to -- ( in | out | in out ) port_type -- [ { { port_property_association }+ } ] ; function P_Port_Spec (Container : node_id; Identifier : node_id; Is_Refinement : Boolean; Is_In : Boolean; Is_Out : Boolean) return node_id is use Ocarina.Nodes; use Lexer; use Tokens; use Locations; use Parser.Properties; use Parser.Identifiers; use Ocarina.Builder.Components.Features; Class_Ref : node_id := No_Node; Port_Spec : node_id := No_Node; Is_Data : Boolean := False; Is_Event : Boolean := False; Code : parsing_code; OK : Boolean; Loc : location; begin if Is_Refinement then Code := pc_port_refinement; else Code := pc_port_spec; end if; if Token = t_event then Is_Event := True; Save_Lexer (Loc); Scan_Token; if Token = t_data then Is_Data := True; else Restore_Lexer (Loc); end if; elsif Token = t_data then Is_Data := True; else DPE (pc_port_type, ((t_event, t_data))); return No_Node; end if; Scan_Token; if Token /= t_port then DPE (pc_port_type, t_port); return No_Node; end if; if Is_Data then Save_Lexer (Loc); Scan_Token; if Token = t_identifier then Restore_Lexer (Loc); Class_Ref := P_Entity_Reference (pc_port_type); if No (Class_Ref) then -- Error when parsing Classifier_Reference, quit return No_Node; end if; else Restore_Lexer (Loc); end if; end if; Port_Spec := Add_New_Port_Spec (Loc => Ocarina.Nodes.Loc (Identifier), Container => Container, Name => Identifier, Is_In => Is_In, Is_Out => Is_Out, Is_Event => Is_Event, Is_Data => Is_Data, Is_Refinement => Is_Refinement, Associated_Entity => Class_Ref); OK := P_Property_Associations (Port_Spec, True, pat_simple, Code); if not OK then return No_Node; end if; Save_Lexer (Loc); Scan_Token; if Token /= t_semicolon then DPE (Code, t_semicolon); Restore_Lexer (Loc); return No_Node; end if; return Port_Spec; end P_Port_Spec; ------------------------------------ -- P_Port_Spec_Or_Port_Group_Spec -- ------------------------------------ function P_Port_Spec_Or_Port_Group_Spec (Container : Types.node_id; Refinable : Boolean) return node_id is use Ocarina.Nodes; use Tokens; use Lexer; use Ocarina.AADL.Parser.Identifiers; Identifier : node_id; Is_Refinement : Boolean; OK : Boolean; begin P_Identifier_Refined_To (Refinable_To_RT (Refinable), False, pc_port_spec_or_port_group_spec, pc_port_refinement_or_port_group_refinement, t_semicolon, Identifier, Is_Refinement, OK); if not OK then return No_Node; end if; Scan_Token; case Token is when t_in | t_out => -- parse port_spec or port_refinement if Is_Refinement then return P_In_Out_Item (Container => Container, Identifier => Identifier, Is_Refinement => True, Code => pc_port_refinement); else return P_In_Out_Item (Container => Container, Identifier => Identifier, Is_Refinement => False, Code => pc_port_spec); end if; when t_port => -- parse port_group_spec or port_group_refinement return P_Port_Group_Spec (Container => Container, Identifier => Identifier, Is_Refinement => Is_Refinement); when others => if Is_Refinement then DPE (pc_port_refinement_or_port_group_refinement, (t_in, t_out, t_port)); else DPE (pc_port_spec_or_port_group_spec, (t_in, t_out, t_port)); end if; Skip_Tokens (t_semicolon); return No_Node; end case; end P_Port_Spec_Or_Port_Group_Spec; ----------------------- -- P_Subprogram_Spec -- ----------------------- -- data_subprogram_spec ::= -- defining_subprogram_identifier_list : subprogram -- [ unique_subprogram_reference ] -- [ { { subprogram_property_association }+ } ] ; -- data_subprogram_refinement ::= -- defining_subprogram_identifier_list : refined to subprogram -- [ unique_subprogram_reference ] -- [ { { subprogram_property_association }+ } ] ; -- server_subprogram ::= -- defining_subprogram_identifier_list : server subprogram -- [ unique_subprogram_reference ] -- [ { { subprogram_property_association }+ } ] ; -- server_subprogram_refinement ::= -- defining_subprogram_identifier_list : refined to server subprogram -- [ unique_subprogram_reference ] -- [ { { subprogram_property_association }+ } ] ; -- unique_subprogram_reference ::= -- subprogram_classifier_reference | -- subprogram_feature_classifier_reference -- subprogram_feature_classifier_reference ::= -- [ package_name :: ] data_type_identifier . subprogram_identifier function P_Subprogram_Spec (Container : Types.node_id; Identifier : node_id; Is_Refinement : Boolean) return node_id is use Locations; use Ocarina.Nodes; use Lexer; use Tokens; use Parser.Properties; use Ocarina.AADL.Parser.Identifiers; use Ocarina.Builder.Components.Features; Subprog_Spec : node_id := No_Node; Is_Server : Boolean := False; Subprog_Ref : node_id := No_Node; Loc : location; Code : parsing_code; OK : Boolean; -- Sub-function determining parsing code to display error messages function Subprogram_Parsing_Code return parsing_code; pragma inline (Subprogram_Parsing_Code); function Subprogram_Parsing_Code return parsing_code is begin if Is_Refinement then if Is_Server then return pc_server_subprogram_refinement; else return pc_data_subprogram_refinement; end if; else if Is_Server then return pc_server_subprogram; else return pc_data_subprogram_spec; end if; end if; end Subprogram_Parsing_Code; begin if Token = t_server then Is_Server := True; Scan_Token; end if; Code := Subprogram_Parsing_Code; if Token /= t_subprogram then DPE (Code, t_subprogram); Skip_Tokens (t_semicolon); return No_Node; end if; Save_Lexer (Loc); Scan_Token; if Token = t_identifier then Restore_Lexer (Loc); Subprog_Ref := P_Entity_Reference (Code); if No (Subprog_Ref) then Skip_Tokens (t_semicolon); return No_Node; end if; else Restore_Lexer (Loc); end if; if Is_Server then Subprog_Spec := Add_New_Server_Subprogram (Loc => Ocarina.Nodes.Loc (Identifier), Name => Identifier, Container => Container, Is_Refinement => Is_Refinement); else Subprog_Spec := Add_New_Data_Subprogram_Spec (Loc => Ocarina.Nodes.Loc (Identifier), Name => Identifier, Container => Container, Is_Refinement => Is_Refinement); end if; Set_Entity_Ref (Subprog_Spec, Subprog_Ref); Save_Lexer (Loc); Scan_Token; if Token /= t_semicolon then Restore_Lexer (Loc); OK := P_Property_Associations (Subprog_Spec, True, pat_simple_or_contained, Code); if not OK then Subprog_Spec := No_Node; else Save_Lexer (Loc); Scan_Token; if Token /= t_semicolon then DPE (Code, t_semicolon); Restore_Lexer (Loc); return No_Node; end if; end if; end if; return Subprog_Spec; end P_Subprogram_Spec; --------------------------- -- P_Subcomponent_Access -- --------------------------- -- subcomponent_access ::= -- defining_subcomponent_access_identifier : -- subcomponent_access_classifier -- [ { { access_property_association }+ } ] ; -- subcomponent_access_refinement ::= -- defining_subcomponent_access_identifier : refined to -- subcomponent_access_classifier -- [ { { access_property_association }+ } ] ; function P_Subcomponent_Access (Container : Types.node_id; Identifier : node_id; Is_Refinement : Boolean) return node_id is use Locations; use Ocarina.Nodes; use Lexer; use Tokens; use Parser.Properties; use Parser.Identifiers; use Ocarina.Builder.Components.Features; Subcomp_Access : node_id := No_Node; Subcomp_Access_Class : node_id := No_Node; Is_Provided : Boolean := False; Subcomponent_Category : component_category; Code : parsing_code; OK : Boolean; Loc : location; begin if Token = t_provides then Is_Provided := True; elsif Token /= t_requires then DPE (pc_subcomponent_access_classifier, (t_provides, t_requires)); return No_Node; end if; Scan_Token; if Token = t_data then Subcomponent_Category := cc_data; elsif Token = t_bus then Subcomponent_Category := cc_bus; elsif Token = t_subprogram then Subcomponent_Category := cc_subprogram; else DPE (pc_subcomponent_access_classifier, (t_data, t_bus)); return No_Node; end if; Scan_Token; if Token /= t_access then DPE (pc_subcomponent_access_classifier, t_access); return No_Node; end if; Save_Lexer (Loc); Scan_Token; if Token = t_identifier then Restore_Lexer (Loc); Subcomp_Access_Class := P_Entity_Reference (pc_subcomponent_access_classifier); if Subcomp_Access_Class = No_Node then -- Error when parsing Subcomponent_Access_Classifier, quit Skip_Tokens (t_semicolon); return No_Node; end if; else Restore_Lexer (Loc); end if; if Is_Refinement then Code := pc_subcomponent_access_refinement; else Code := pc_subcomponent_access; end if; Subcomp_Access := Add_New_Subcomponent_Access (Loc => Ocarina.Nodes.Loc (Identifier), Name => Identifier, Container => Container, Is_Refinement => Is_Refinement, Category => Subcomponent_Category, Is_Provided => Is_Provided); OK := P_Property_Associations (Subcomp_Access, True, pat_access, Code); if not OK then return No_Node; end if; Save_Lexer (Loc); Scan_Token; if Token /= t_semicolon then DPE (Code, t_semicolon); Restore_Lexer (Loc); return No_Node; end if; if Subcomp_Access /= No_Node then Set_Entity_Ref (Subcomp_Access, Subcomp_Access_Class); end if; return Subcomp_Access; end P_Subcomponent_Access; --------------- -- P_Feature -- --------------- -- feature ::= port_spec | port_group_spec -- | server_subprogram | data_subprogram_spec -- | subcomponent_access | parameter -- feature_refinement ::= port_refinement -- | port_group_refinement -- | server_subprogram_refinement -- | data_subprogram_refinement -- | subcomponent_access_refinement -- | parameter_refinement function P_Feature (Container : Types.node_id; Refinable : Boolean) return node_id is use Parser.Identifiers; use Tokens; use Lexer; Identifier : node_id; Is_Refinement : Boolean; Code : parsing_code; OK : Boolean; Node : node_id; begin P_Identifier_Refined_To (Refinable_To_RT (Refinable), False, pc_feature, pc_feature_refinement, t_semicolon, Identifier, Is_Refinement, OK); if not OK then return No_Node; end if; if Is_Refinement then Code := pc_feature_refinement; else Code := pc_feature; end if; Scan_Token; case Token is when t_in | t_out => Node := P_In_Out_Item (Container, Identifier, Is_Refinement, Code); when t_port => Node := P_Port_Group_Spec (Container, Identifier, Is_Refinement); when t_server | t_subprogram => Node := P_Subprogram_Spec (Container, Identifier, Is_Refinement); when t_provides | t_requires => Node := P_Subcomponent_Access (Container, Identifier, Is_Refinement); when others => DPE (Code); Skip_Tokens (t_semicolon); Node := No_Node; end case; return Node; end P_Feature; -------------------------- -- P_Feature_Refinement -- -------------------------- -- feature_refinement ::= port_refinement -- | port_group_refinement -- | server_subprogram_refinement -- | data_subprogram_refinement -- | subcomponent_access_refinement -- | parameter_refinement function P_Feature_Refinement (Container : Types.node_id) return node_id is use Parser.Identifiers; use Lexer; use Tokens; use Ocarina.Nodes; pragma assert (Container /= No_Node and then (Kind (Container) = k_component_implementation or else Kind (Container) = k_component_type or else Kind (Container) = k_port_group_type)); Identifier : node_id; Is_Refinement : Boolean; OK : Boolean; begin P_Identifier_Refined_To (rt_refinement, False, pc_feature, pc_feature_refinement, t_semicolon, Identifier, Is_Refinement, OK); if not OK then return No_Node; end if; Scan_Token; case Token is when t_in | t_out => return P_In_Out_Item (Container, Identifier, True, pc_feature_refinement); when t_port => return P_Port_Group_Spec (Container, Identifier, True); when t_server | t_subprogram => return P_Subprogram_Spec (Container, Identifier, True); when t_provides | t_requires => return P_Subcomponent_Access (Container, Identifier, True); when others => DPE (pc_feature_refinement); Skip_Tokens (t_semicolon); return No_Node; end case; end P_Feature_Refinement; end Ocarina.AADL.Parser.Components.Features;