ocarina_cmd.adb 44.1 KB
Newer Older
1 2 3 4 5 6 7 8
------------------------------------------------------------------------------
--                                                                          --
--                           OCARINA COMPONENTS                             --
--                                                                          --
--                          O C A R I N A _ C M D                           --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
yoogx's avatar
yoogx committed
9
--    Copyright (C) 2004-2009 Telecom ParisTech, 2010-2015 ESA & ISAE.      --
10
--                                                                          --
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
-- Ocarina  is free software; you can redistribute it and/or modify under   --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
-- sion. 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.                     --
--                                                                          --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception,   --
-- version 3.1, as published by the Free Software Foundation.               --
--                                                                          --
-- You should have received a copy of the GNU General Public License and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
26
--                                                                          --
27 28
--                 Ocarina is maintained by the TASTE project               --
--                      (taste-users@lists.tuxfamily.org)                   --
29 30 31 32 33 34
--                                                                          --
------------------------------------------------------------------------------

--  This program is used to drive Ocarina, it is a wrapper to all
--  functions provided by the library.

35
with Errors;    use Errors;
36
with Locations; use Locations;
37 38
with Ocarina.Namet;     use Ocarina.Namet;
with Ocarina.Output;    use Ocarina.Output;
39
with Ocarina.Types;     use Ocarina.Types;
40 41 42
with Utils;     use Utils;

with Ada.Command_Line; use Ada.Command_Line;
yoogx's avatar
yoogx committed
43
with Ada.Command_Line.Response_File;
44 45 46 47 48 49 50 51 52 53 54 55 56
with Ada.Unchecked_Deallocation;
with Ada.Exceptions;   use Ada.Exceptions;
with Ada.IO_Exceptions;
with Ada.Text_IO;

with GNAT.Command_Line;         use GNAT.Command_Line;
with GNAT.Directory_Operations; use GNAT.Directory_Operations;
with GNAT.OS_Lib;               use GNAT.OS_Lib;

with Ocarina;                          use Ocarina;
with Ocarina.AADL_Values;              use Ocarina.AADL_Values;
with Ocarina.Analyzer;                 use Ocarina.Analyzer;
with Ocarina.Backends;                 use Ocarina.Backends;
57
with Ocarina.Backends.PO_HI_C;
58
with Ocarina.Backends.PO_HI_Ada;
59
with Ocarina.Backends.Execution_Tests; use Ocarina.Backends.Execution_Tests;
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
with Ocarina.Configuration;            use Ocarina.Configuration;
with Ocarina.Files;                    use Ocarina.Files;
with Ocarina.Instances;                use Ocarina.Instances;
with Ocarina.Instances.Queries;        use Ocarina.Instances.Queries;
with Ocarina.ME_AADL.AADL_Tree.Nodes;  use Ocarina.ME_AADL.AADL_Tree.Nodes;
with Ocarina.ME_AADL.AADL_Tree.Nutils; use Ocarina.ME_AADL.AADL_Tree.Nutils;
with Ocarina.Options;                  use Ocarina.Options;
with Ocarina.Parser;                   use Ocarina.Parser;
with Ocarina.Property_Sets;            use Ocarina.Property_Sets;
with Ocarina.FE_AADL.Parser;           use Ocarina.FE_AADL.Parser;
with Ocarina.FE_REAL;                  use Ocarina.FE_REAL;
with Ocarina.ME_REAL.Tokens;
with Ocarina.Transfo.Fusions;          use Ocarina.Transfo.Fusions;
with Ocarina.Transfo.Move;             use Ocarina.Transfo.Move;
with Ocarina.Transfo.Optim;            use Ocarina.Transfo.Optim;

with Ocarina.ME_AADL.AADL_Instances.Nodes;

procedure Ocarina_Cmd is

   procedure Process_Command_Line
81 82
     (Root_System_Name : out Name_Id;
      Success          : out Boolean);
83 84 85 86 87 88 89 90 91 92 93 94 95 96
   --  Process the command line to extract the options for the
   --  different modules of Ocarina.

   procedure Usage;
   --  Display a message describing the usage of Ocarina

   procedure Ocarina_Shell;
   --  Launch Ocarina interactive mode

   procedure Parse_Scenario_Files;
   --  Parse a set of scenario file and updates the global variable
   --  according to the extracted information.

   After_Scenario_Action : Action_Kind := Generate_Code;
97 98 99
   Standard_Input        : Boolean     := True;
   AADL_Root             : Node_Id     := No_Node;
   Success               : Boolean     := True;
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
   File_Name             : Name_Id;
   Buffer                : Location;
   Language              : Name_Id;
   Position              : String_String_Maps.Cursor;

   -------------------
   -- Ocarina_Shell --
   -------------------

   procedure Ocarina_Shell is

      use Ada.Text_IO;

      function "+" (S : String) return String_Access;
      procedure Show_Help;
      procedure Free is new Ada.Unchecked_Deallocation (String, String_Access);
      function Next return String;
      function Argument (Index : Natural) return String_Access;
      function Count (Prompt : String := "> ") return Natural;

      Syntax_Error : exception;

      type Command is
        (Help,
         Analyze,
         Instantiate,
         Generate,
         Load,
         Status,
         Fusion,
         Move,
         Optimize,
         Brute_Optimize,
         Version,
         Quit);

      Args    : array (1 .. 16) of String_Access;
      Argc    : Natural;
      Line    : String (1 .. 1024);
      Last    : Natural;
      Scan    : Natural;
      Argv    : String_Access;
      Cmmd    : Command;
      Success : Boolean;

      ---------
      -- "+" --
      ---------

      function "+" (S : String) return String_Access is
      begin
         return new String'(S);
      end "+";

      ---------------
      -- Show_Help --
      ---------------

158 159 160 161 162 163 164 165 166 167 168 169 170
      Help_Messages : constant array (Command) of String_Access :=
        (Help           => +"print this message",
         Analyze        => +"analyse model",
         Instantiate    => +"instantiate model",
         Generate       => +"generate code",
         Load           => +"load and parse file given as argument",
         Fusion         => +"fusion threads",
         Move           => +"move a thread",
         Optimize       => +"optimize model, using greedy algorithm",
         Brute_Optimize => +"optimize model, using brute force",
         Status         => +"print configuration",
         Version        => +"print Ocarina version information",
         Quit           => +"quit this shell");
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

      procedure Show_Help is
      begin
         for J in Help_Messages'Range loop
            Write_Line (J'Img & ASCII.HT & Help_Messages (J).all);
         end loop;
      end Show_Help;

      ------------------
      -- Print_Status --
      ------------------

      procedure Print_Status is
      begin
         Write_Line ("AADL version: " & Ocarina.AADL_Version'Img);
186 187
         Write_Line
           ("Library Path: " & Get_Name_String (Default_Library_Path));
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
      end Print_Status;

      --------------
      -- Argument --
      --------------

      function Argument (Index : Natural) return String_Access is
      begin
         if Index > Argc then
            raise Constraint_Error;
         end if;
         return Args (Index);
      end Argument;

      -----------
      -- Count --
      -----------

      function Count (Prompt : String := "> ") return Natural is
      begin
         if Standard_Input then
            Put (Prompt);
         end if;

         begin
            Get_Line (Current_Input, Line, Last);
         exception
            when Ada.IO_Exceptions.End_Error =>
               --  This means the user hit CTRL-D or the script does
               --  not end with a QUIT command. Not harmful, we just
               --  simulate a QUIT.

               Argc := 1;
               if Args (Argc) /= null then
                  Free (Args (Argc));
               end if;
               Args (Argc) := new String'(Command'Image (Quit));
               return Argc;

            when E : others =>
228
               Write_Line ("raised " & Exception_Information (E));
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
               Write_Line (Exception_Message (E));
               raise;
         end;

         Scan := 1;
         Argc := 0;
         loop
            declare
               Arg : constant String := Next;
            begin
               exit when Arg = "";
               Argc := Argc + 1;
               if Args (Argc) /= null then
                  Free (Args (Argc));
               end if;
               Args (Argc) := new String'(Arg);
            end;
         end loop;
         return Argc;
      end Count;

      ----------
      -- Next --
      ----------

      function Next return String is
         use ASCII;

         F, L : Natural;
      begin
         while Scan <= Last
           and then (Line (Scan) = ' ' or else Line (Scan) = HT)
         loop
            Scan := Scan + 1;
         end loop;

         if Scan > Last then
            return "";
         end if;

         if Line (Scan) = '"' then -- "
            Scan := Scan + 1;
            F    := Scan;

            while Scan <= Last loop
               if Line (Scan) = '"' then --  "
                  L    := Scan - 1;
                  Scan := Scan + 1;
                  return Line (F .. L);

               elsif Line (Scan) = NUL then
                  return "";

               end if;

               Scan := Scan + 1;
            end loop;
            return "";

         else
            F := Scan;
            while Scan <= Last
              and then Line (Scan) /= ' '
              and then Line (Scan) /= HT
            loop
               L    := Scan;
               Scan := Scan + 1;
            end loop;
            return Line (F .. L);
         end if;
      end Next;

   begin
      if Standard_Input then
         Write_Line ("Ocarina shell, type help for information");
      end if;

      --  Console main loop: read inputs and process them

      <<Main>>
      loop
         Argc := Count;
         if Argc > 0
           and then Argument (1) /= null
           and then Argument (1).all (Argument (1).all'First) /= '#'
         then
            begin
               Argv := Argument (1);

               begin
                  Cmmd := Command'Value (Argv.all);
320 321 322
               exception
                  when Constraint_Error =>
                     raise Syntax_Error;
323 324 325 326 327 328 329 330 331
               end;

               case Cmmd is
                  when Help =>
                     Show_Help;

                  when Analyze =>
                     Success := Analyze (Language, AADL_Root);
                     if not Success then
332
                        Write_Line ("Cannot analyze AADL specifications");
333 334 335 336 337 338
                     else
                        Write_Line ("Model analyzed sucessfully");
                     end if;

                  when Instantiate =>
                     if Argc = 2 then
339 340
                        Root_System_Name :=
                          To_Lower (Get_String_Name (Argument (2).all));
341 342 343 344 345 346 347 348 349 350 351
                     end if;
                     AADL_Root := Instantiate_Model (AADL_Root);
                     if Present (AADL_Root) then
                        Write_Line ("Model instantiated sucessfully");
                     end if;

                  when Generate =>
                     if Argc /= 2 then
                        raise Syntax_Error;
                     end if;
                     Set_Current_Backend_Name (Argument (2).all);
352
                     Write_Line ("Generating code for " & Argument (2).all);
353 354 355 356 357 358 359 360 361 362
                     Generate_Code (AADL_Root);

                  when Load =>
                     if Argc /= 2 then
                        raise Syntax_Error;
                     end if;
                     Set_Str_To_Name_Buffer (Argument (2).all);

                     File_Name := Search_File (Name_Find);
                     if File_Name = No_Name then
363
                        Write_Line ("cannot find file " & Argument (2).all);
364 365 366 367 368
                        goto Main;
                     end if;

                     Buffer := Load_File (File_Name);
                     if File_Name = No_Name then
369
                        Write_Line ("cannot read file " & Argument (2).all);
370 371 372 373 374 375 376 377
                        goto Main;
                     end if;
                     AADL_Root := Parse (Language, AADL_Root, Buffer);
                     Exit_On_Error
                       (No (AADL_Root),
                        "cannot parse AADL specifications");

                     Write_Line
378 379 380
                       ("File " &
                        Argument (2).all &
                        " loaded and parsed sucessfully");
381 382 383 384 385 386

                  when Brute_Optimize =>
                     declare
                        Instance_Root : Node_Id;
                     begin
                        Instance_Root := Instantiate_Model (AADL_Root);
387 388 389
                        Exit_On_Error
                          (No (Instance_Root),
                           "Cannot instantiate AADL models");
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406

                        Ocarina.Transfo.Optim.Init (Instance_Root);

                        Exhaustive_Space_Exploration (Instance_Root, Success);
                        Exit_On_Error
                          (not Success,
                           "cannot perform brute optimization on model");

                        Set_Current_Backend_Name ("aadl");
                        Generate_Code (AADL_Root);
                     end;

                  when Optimize =>
                     declare
                        Instance_Root : Node_Id;
                     begin
                        Instance_Root := Instantiate_Model (AADL_Root);
407 408 409
                        Exit_On_Error
                          (No (Instance_Root),
                           "Cannot instantiate AADL models");
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433

                        Ocarina.Transfo.Optim.Init (Instance_Root);

                        Greedy_Heuristic (Instance_Root, Success);
                        Exit_On_Error
                          (not Success,
                           "cannot perform optimization on model");

                        Set_Current_Backend_Name ("aadl");
                        Generate_Code (AADL_Root);
                     end;

                  when Fusion =>
                     declare
                        Thread_To_Fusion_1 : Name_Id := No_Name;
                        Thread_To_Fusion_2 : Name_Id := No_Name;
                        Owner_Process      : Name_Id := No_Name;
                        --  Transformation-related variables

                        AADL_Instance : Node_Id;
                        New_Thread    : Node_Id;
                        Success       : Boolean;
                     begin
                        AADL_Instance := Instantiate_Model (AADL_Root);
434 435 436
                        Exit_On_Error
                          (No (AADL_Instance),
                           "Cannot instantiate AADL models");
437 438

                        Owner_Process := Get_String_Name (Argument (2).all);
439 440 441 442 443 444 445 446 447 448 449 450
                        Thread_To_Fusion_1 :=
                          Get_String_Name (Argument (3).all);
                        Thread_To_Fusion_2 :=
                          Get_String_Name (Argument (4).all);

                        Fusion_Threads
                          (AADL_Root,
                           Owner_Process,
                           Thread_To_Fusion_1,
                           Thread_To_Fusion_2,
                           New_Thread,
                           Success);
451

452 453 454
                        Exit_On_Error
                          (not Success,
                           "Cannot fusion the AADL threads");
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469

                        Set_Current_Backend_Name ("aadl");
                        Generate_Code (AADL_Root);
                     end;

                  when Move =>
                     declare
                        Thread_To_Move : Name_Id := No_Name;
                        Src_Process    : Name_Id := No_Name;
                        Dst_Process    : Name_Id := No_Name;
                        --  Transformation-related variables

                        AADL_Instance : Node_Id;
                     begin
                        AADL_Instance := Instantiate_Model (AADL_Root);
470 471 472
                        Exit_On_Error
                          (No (AADL_Instance),
                           "Cannot instantiate AADL models");
473 474

                        Thread_To_Move := Get_String_Name (Argument (2).all);
475 476
                        Src_Process    := Get_String_Name (Argument (3).all);
                        Dst_Process    := Get_String_Name (Argument (4).all);
477

478
                        Move_Thread (Thread_To_Move, Src_Process, Dst_Process);
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497

                        Set_Current_Backend_Name ("aadl");
                        Generate_Code (AADL_Root);
                     end;

                  when Status =>
                     Print_Status;

                  when Version =>
                     Version;

                  when Quit =>
                     exit;
               end case;
            exception
               when Syntax_Error =>
                  Write_Line ("syntax error");

               when E : others =>
498
                  Write_Line ("raised " & Exception_Information (E));
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
                  Write_Line (Exception_Message (E));
            end;
         end if;
      end loop;
   end Ocarina_Shell;

   -------------------------
   -- Parse_Scenario_File --
   -------------------------

   --  Example of an AADL scenario:

   --  -----------------
   --  -- FILE_1.aadl --
   --  -----------------

   --  system RMA
   --  properties
   --    Ocarina_Config::AADL_Files => ("rma.aadl");
   --    --  "rma.aadl" contains common AADL components (processes,
   --    --  threads, data types)
   --
   --    Ocarina_Config::Needed_Property_Sets =>
   --      (value (Ocarina_Config::ARAO),
   --       value (Ocarina_Config::Cheddar_Properties));
   --    --  The non standard predefined property sets needed by the
   --    --  application.
   --  end RMA;

   --  -----------------
   --  -- FILE_2.aadl --
   --  -----------------

   --  system implementation RMA.Impl_C
   --  properties
   --    Ocarina_Config::AADL_Files +=> ("software_c.aadl");
   --    --  Note that this is an additive property
   --    --  association.
   --
   --    Ocarina_Config::Generator => PolyORB_HI_C;
   --    --  The code generator
   --  end RMA.Impl_C;

   --  -----------------
   --  -- FILE_3.aadl --
   --  -----------------

   --  system implementation RMA.Impl_Ada
   --  properties
   --    Source_Text +=> ("software_ada.aadl");
   --    --  Note that this is an additive property
   --    --  association.
   --
   --    Ocarina_Config::Generator => PolyORB_HI_Ada;
   --    --  The code generator
   --  end RMA.Impl_Ada;

   --  Calling the compiler on FILE_1.aadl and FILE_2.aadl will
   --  generate C code for the Poly_ORB-HI framework starting from
   --  "rma.aadl" and "software_c.aadl".

   --  Calling the compiler on FILE_1.aadl and FILE_3.aadl will
   --  generate Ada code for the Poly_ORB-HI framework starting from
   --  "rma.aadl" and "software_ada.aadl".

   procedure Parse_Scenario_Files is
565 566 567 568 569 570 571 572 573 574
      AADL_Root              : Node_Id := No_Node;
      Instance_Root          : Node_Id := No_Node;
      Root_System            : Node_Id := No_Node;
      Source_Files           : List_Id;
      Ref_Files              : List_Id;
      Needed_PS              : List_Id;
      Use_CL                 : Boolean := False;
      Used_Generator_Options : List_Id;
      Dirname                : Name_Id;
      Success                : Boolean := False;
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590

      The_Backend : Name_Id := No_Name;
      --  The current code generator

      Current_Scenario_Dirname : Name_Id := No_Name;
      --  The current dirname of all the scenario files.

      AADL_Version_Name : Name_Id := No_Name;
      --  The AADL version under which the model will be parsed

      Temp_AADL_Version : AADL_Version_Type;

      Ocarina_Config : constant String := "ocarina_config";
      --  The property set containing the Ocarina configuration
      --  properties.

591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
      AADL_Files : constant Name_Id :=
        Get_String_Name (Ocarina_Config & "::aadl_files");
      Use_Components_Library : constant Name_Id :=
        Get_String_Name (Ocarina_Config & "::use_components_library");
      Referencial_Files : constant Name_Id :=
        Get_String_Name (Ocarina_Config & "::referencial_files");
      The_Generator : constant Name_Id :=
        Get_String_Name (Ocarina_Config & "::generator");
      Generator_Options : constant Name_Id :=
        Get_String_Name (Ocarina_Config & "::generator_options");
      Predefined_PS : constant Name_Id :=
        Get_String_Name (Ocarina_Config & "::needed_property_sets");
      RS_Name : constant Name_Id :=
        Get_String_Name (Ocarina_Config & "::root_system_name");
      AADL_Version : constant Name_Id :=
        Get_String_Name (Ocarina_Config & "::aadl_version");
      Timeout_Property : constant Name_Id :=
        Get_String_Name (Ocarina_Config & "::timeout_property");
609 610 611 612 613 614

      -------------------------------
      -- Extract_Referencial_Files --
      -------------------------------

      procedure Extract_Referencial_Files
615 616
        (Ref_Files :        List_Id;
         Ref_Map   : in out String_String_Maps.Map)
617
      is
618
         N : Node_Id;
619 620 621 622 623
      begin
         if not Is_Empty (Ref_Files) then
            N := First_Node (Ref_Files);
            while Present (N) loop
               declare
624 625
                  App_Name : constant String :=
                    Image (Value (N), Quoted => False);
626 627 628 629
               begin
                  N := Next_Node (N);
                  if Present (N) then
                     declare
630 631
                        File : constant String :=
                          Image (Value (N), Quoted => False);
632 633
                     begin
                        Write_Line ("Inserting : " & App_Name & " / " & File);
634 635 636 637 638 639
                        String_String_Maps.Insert
                          (Container => Ref_Map,
                           Key       => App_Name,
                           New_Item  => File,
                           Position  => Position,
                           Inserted  => Success);
640 641
                     end;
                  else
642 643 644 645
                     Exit_On_Error
                       (True,
                        "Missing parameters in " &
                        "Referencial_Files property");
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
                  end if;
                  N := Next_Node (N);
               end;
            end loop;
         end if;
      end Extract_Referencial_Files;

      --------------------------
      -- Extract_Source_Files --
      --------------------------

      procedure Extract_Source_Files
        (Source_Files : List_Id;
         Needed_PS    : List_Id);
      --  FIXME : Update the sources with the full path of the given AADL
      --  source file list and the needed predefined property sets (???).

      procedure Extract_Source_Files
        (Source_Files : List_Id;
         Needed_PS    : List_Id)
      is
         N : Node_Id;

      begin
         if not Is_Empty (Needed_PS) then
671
            N := First_Node (Needed_PS);
672 673 674 675

            while Present (N) loop
               declare
                  P         : Name_Id;
676 677
                  File_Name : constant String :=
                    Image (Value (N), Quoted => False);
678 679 680 681 682
               begin
                  Set_Str_To_Name_Buffer (File_Name);
                  Set_Str_To_Name_Buffer
                    (Image
                       (Ocarina_Property_Set_Type'Value
683
                          ("O_" & Name_Buffer (1 .. Name_Len))));
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
                  P := Name_Find;

                  Get_Name_String (Default_Library_Path);
                  Get_Name_String_And_Append (P);
                  Add_Str_To_Name_Buffer (".aadl");

               exception
                  when others =>
                     --  If we fail here, this means that the user gave a
                     --  custom property set file, assume that this file
                     --  is located in the data directory.

                     --  Build the full-path file name
                     Get_Name_String (Default_Library_Path);
                     Add_Str_To_Name_Buffer (File_Name & ".aadl");
               end;

701 702
               Ocarina.Files.Add_File_To_Parse_List
                 (Name_Find, Add_Suffix => True);
703 704 705 706

               N := Next_Node (N);
            end loop;
         end if;
707 708 709 710

         N := First_Node (Source_Files);
         while Present (N) loop
            declare
711 712
               File_Name : constant String :=
                 Image (Value (N), Quoted => False);
713 714 715
            begin
               Get_Name_String (Current_Scenario_Dirname);
               Add_Str_To_Name_Buffer (File_Name);
716 717
               Ocarina.Files.Add_File_To_Parse_List
                 (Name_Find, Add_Suffix => True);
718 719 720
               N := Next_Node (N);
            end;
         end loop;
721 722 723 724
      end Extract_Source_Files;

      package OIQ renames Ocarina.Instances.Queries;

725
      F : Types.Int;
726
      N : Node_Id;
727

728 729 730
   begin
      Current_Scenario_Dirname := No_Name;

731 732 733 734 735
      AADL_Root := Process_Predefined_Property_Sets (AADL_Root);

      F := Sources.First;

      loop
736 737 738 739
         Dirname :=
           Get_String_Name
             (Dir_Name
                (Normalize_Pathname (Get_Name_String (Sources.Table (F)))));
740 741 742

         if Current_Scenario_Dirname = No_Name then
            Current_Scenario_Dirname := Dirname;
743 744
            Scenario_Dir             :=
              new String'(Get_Name_String (Current_Scenario_Dirname));
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
         end if;

         --  All scenario files have to be located in the same directory

         Exit_On_Error
           (Current_Scenario_Dirname /= Dirname,
            "Cannot locate scenario files in the directory");
         File_Name := Search_File (Sources.Table (F));
         Exit_On_Error
           ((File_Name = No_Name),
            "Cannot find file " & Get_Name_String (Sources.Table (F)));
         Buffer := Load_File (File_Name);
         Exit_On_Error
           ((File_Name = No_Name),
            "Cannot read file " & Get_Name_String (Sources.Table (F)));
         AADL_Root := Parse (Language, AADL_Root, Buffer);
761
         Exit_On_Error (No (AADL_Root), "Cannot parse AADL specifications");
762

763 764 765
         exit when F = Sources.Last; -- XXX Sources.Last may be modified
         F := F + 1;
      end loop;
766 767 768 769 770 771 772 773 774 775 776 777 778 779

      --  Analyze the AADL tree

      Success := Analyze (Language, AADL_Root);
      Exit_On_Error (not Success, "Cannot analyze AADL scenarios");

      --  Instantiate the AADL tree

      Instance_Root := Instantiate_Model (AADL_Root);
      Exit_On_Error (No (Instance_Root), "Cannot instantiate AADL scenarios");

      --  Every thing is fine, extract the information from the
      --  scenario model.

780 781
      Root_System :=
        Ocarina.ME_AADL.AADL_Instances.Nodes.Root_System (Instance_Root);
782 783 784 785 786 787 788 789 790 791 792 793 794

      --  Extract the generator

      Exit_On_Error
        (not Is_Defined_Enumeration_Property (Root_System, The_Generator),
         "You must specify a code generator");

      The_Backend := Get_Enumeration_Property (Root_System, The_Generator);

      --  Extract the AADL files to be parsed

      Exit_On_Error
        (not Is_Defined_List_Property (Root_System, AADL_Files),
795 796 797
         "AADL source files have to be specified by" &
         " means of the standard property" &
         " ""Source_Text""");
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823

      Source_Files := Get_List_Property (Root_System, AADL_Files);

      --  Extract the referencial files for regression tests

      if Is_Defined_List_Property (Root_System, Referencial_Files) then
         Ref_Files := Get_List_Property (Root_System, Referencial_Files);
      else
         Ref_Files := No_List;
      end if;

      --  Extract the timeout used to stop the test

      if OIQ.Is_Defined_Integer_Property (Root_System, Timeout_Property) then
         Timeout := OIQ.Get_Integer_Property (Root_System, Timeout_Property);
      end if;

      --  Extract the predefined property sets needed by the
      --  application

      if Is_Defined_List_Property (Root_System, Predefined_PS) then
         Needed_PS := Get_List_Property (Root_System, Predefined_PS);
      else
         Needed_PS := No_List;
      end if;

824
      if Is_Defined_Boolean_Property (Root_System, Use_Components_Library) then
julien.delange's avatar
julien.delange committed
825 826 827 828 829
         Use_CL := True;
      else
         Use_CL := False;
      end if;

830 831 832
      --  Extract the generator options.

      if Is_Defined_List_Property (Root_System, Generator_Options) then
833 834
         Used_Generator_Options :=
           Get_List_Property (Root_System, Generator_Options);
835 836 837 838 839 840 841 842 843 844 845
      else
         Used_Generator_Options := No_List;
      end if;

      --  Process options.

      if not Is_Empty (Used_Generator_Options) then
         N := First_Node (Used_Generator_Options);

         while Present (N) loop
            declare
846 847
               P      : Name_Id;
               Option : constant String := Image (Value (N), Quoted => False);
848 849 850 851 852 853 854 855 856
            begin

               Set_Str_To_Name_Buffer (Option);
               P := Name_Find;

               if P = Get_String_Name ("gprof") then
                  Ocarina.Backends.PO_HI_C.Set_Performance_Analysis (True);
               end if;

857 858
               if P = Get_String_Name ("asn1") then
                  Ocarina.Backends.PO_HI_C.Set_ASN1_Deployment (True);
859
                  Ocarina.Backends.PO_HI_Ada.Set_ASN1_Deployment (True);
860 861
               end if;

862 863 864 865 866
               N := Next_Node (N);
            end;
         end loop;
      end if;

867 868 869
      --  Extract the AADL version

      if Is_Defined_Enumeration_Property (Root_System, AADL_Version) then
870 871
         AADL_Version_Name :=
           Get_Enumeration_Property (Root_System, AADL_Version);
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889

         if Get_Name_String (AADL_Version_Name) = "aadlv1" then
            Temp_AADL_Version := Ocarina.AADL_V1;
         elsif Get_Name_String (AADL_Version_Name) = "aadlv2" then
            Temp_AADL_Version := Ocarina.AADL_V2;
         else
            raise Program_Error;
         end if;
      else
         Temp_AADL_Version := Ocarina.AADL_V1;
      end if;

      Ocarina.AADL_Version := Temp_AADL_Version;

      Sources.Free;
      Sources.Init;
      Extract_Source_Files (Source_Files, Needed_PS);

julien.delange's avatar
julien.delange committed
890 891
      if Use_CL then
         Set_Str_To_Name_Buffer ("ocarina_components.aadl");
892
         Ocarina.Files.Add_File_To_Parse_List (Name_Find, Add_Suffix => True);
julien.delange's avatar
julien.delange committed
893
         Set_Str_To_Name_Buffer ("base_types.aadl");
894
         Ocarina.Files.Add_File_To_Parse_List (Name_Find, Add_Suffix => True);
julien.delange's avatar
julien.delange committed
895 896
      end if;

897 898 899 900 901 902 903 904 905 906 907
      Extract_Referencial_Files (Ref_Files, Ref_Map);

      --  Extract the name of the root of the instance tree

      if Is_Defined_String_Property (Root_System, RS_Name) then
         Root_System_Name := Get_String_Property (Root_System, RS_Name);
      end if;

      --  Reset Ocarina to have a clean set up for the next step

      declare
908 909
         The_Backend_Name : constant String := Get_Name_String (The_Backend);
         Result           : Argument_List_Access :=
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
           new Argument_List
           (Integer (Sources.First) .. Integer (Sources.Last));
         Root_System_Name_Ptr : String_Access;
      begin
         if Root_System_Name /= No_Name then
            Root_System_Name_Ptr :=
              new String'(Get_Name_String (Root_System_Name));
         else
            Root_System_Name_Ptr := new String'("");
         end if;

         for J in Sources.First .. Sources.Last loop
            Result (Integer (J)) :=
              new String'(Get_Name_String (Sources.Table (J)));
         end loop;

         Ocarina.Configuration.Reset_Modules;
         Ocarina.Reset;
928
         --         Ocarina.Files.Sources.Init;
929 930

         Ocarina.Initialize;
931
         Language             := Get_String_Name ("aadl");
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
         Ocarina.AADL_Version := Temp_AADL_Version;
         Set_Current_Backend_Name (The_Backend_Name);

         Ocarina.Configuration.Init_Modules;
         Sources.Free;
         Sources.Init;

         --  Restore the root system name

         if Root_System_Name_Ptr.all /= "" then
            Set_Str_To_Name_Buffer (Root_System_Name_Ptr.all);
            Root_System_Name := Name_Find;
         else
            Root_System_Name := No_Name;
         end if;

         for J in Result'Range loop
            Set_Str_To_Name_Buffer (Result (J).all);
950 951
            Ocarina.Files.Add_File_To_Parse_List
              (Name_Find, Add_Suffix => True);
952 953 954 955 956 957 958 959 960 961 962 963 964 965
         end loop;

         --  Avoid memory leaks

         Free (Result);
         Free (Root_System_Name_Ptr);
      end;
   end Parse_Scenario_Files;

   --------------------------
   -- Process_Command_Line --
   --------------------------

   procedure Process_Command_Line
966 967 968
     (Root_System_Name : out Name_Id;
      Success          : out Boolean)
   is
969 970 971 972 973 974
   begin
      Root_System_Name := No_Name;
      Success          := True;

      Initialize_Option_Scan;
      loop
975 976 977 978 979 980
         case Getopt
           ("* aadlv1 aadlv2 help o: c d g: " &
            "r: real_lib: real_theorem: boundt_process: " &
            "disable-annexes=: " &
            "i p q v V s x t?")
         is
yoogx's avatar
yoogx committed
981

982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
            when 'a' =>
               if Full_Switch = "aadlv2" then
                  AADL_Version := AADL_V2;
               elsif Full_Switch = "aadlv1" then
                  AADL_Version := AADL_V1;
               else
                  raise Invalid_Switch;
               end if;

            when 'o' =>
               declare
                  D : constant String := Parameter;
               begin
                  if D'Length > 0 then
                     Output_Filename := Get_String_Name (D);
                  end if;
               end;

            when 'g' =>
               Set_Current_Action (Generate_Code);
               declare
                  G : constant String := Parameter;
               begin
                  if G'Length > 0 then
                     Set_Current_Backend_Name (G);
                  end if;
               end;

            when 'h' =>
               if Full_Switch /= "help" then
                  raise Invalid_Switch;
               end if;
               Set_Current_Action (Show_Help);

            when 'p' =>
               if Full_Switch = "p" then
                  After_Scenario_Action := Instantiate_Model;
               end if;

            when 'r' =>
               if Full_Switch = "r" then
                  declare
                     N : constant String := Parameter;
                  begin
                     if N'Length > 0 then
                        Root_System_Name := To_Lower (Get_String_Name (N));
                     end if;
                  end;
               end if;

            when 'i' =>
               Set_Current_Action (Instantiate_Model);

            when 'q' =>
               Quiet_Mode   := True;
               Verbose_Mode := False;

            when 'v' =>
               Quiet_Mode   := False;
               Verbose_Mode := True;

            when 'd' =>
               if Full_Switch = "disable-annexes=" then
                  Reset_Annex_Action;
                  Process_Annex_Action (Parameter);
               else
                  Debug_Mode := True;
               end if;

            when 'V' =>
               Set_Current_Action (Show_Version);
               exit;

            when 's' =>
               Set_Current_Action (Show_Libraries);

1058 1059 1060
            --  Note: we continue parsing the command line
            --  parameters to know whether the user specified also
            --  an AADL version flag.
1061 1062

            when 'x' =>
1063
               Use_Scenario_File := True;
1064 1065 1066 1067 1068
               Set_Current_Action (Parse_Scenario_Files_First);

            when 't' =>
               Set_Current_Action (Shell);
               declare
1069
                  N    : constant String := Get_Argument;
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
                  File : Ada.Text_IO.File_Type;
               begin
                  if N'Length > 0 then
                     Ada.Text_IO.Open (File, Ada.Text_IO.In_File, N);
                     Ada.Text_IO.Set_Input (File);
                     Standard_Input := False;
                  end if;
               end;

               exit;

            when ASCII.NUL =>
               exit;

            when others =>
               declare
                  S : constant String := Full_Switch;
               begin
                  if S (S'First) = '-' then
1089 1090
                     --  If there is a new switch, then the previous
                     --  files are discarded.
1091 1092
                     Sources.Init;

yoogx's avatar
yoogx committed
1093 1094
                  elsif S (S'First) = '@' then
                     declare
1095 1096
                        Files : constant Ada.Command_Line.Response_File
                          .Argument_List :=
yoogx's avatar
yoogx committed
1097
                          Ada.Command_Line.Response_File.Arguments_From
1098
                            (S (S'First + 1 .. S'Last));
yoogx's avatar
yoogx committed
1099 1100 1101 1102
                     begin
                        for J in Files'Range loop
                           Set_Str_To_Name_Buffer (Files (J).all);
                           Ocarina.Files.Add_File_To_Parse_List
1103 1104
                             (Name_Find,
                              Add_Suffix => False);
yoogx's avatar
yoogx committed
1105 1106 1107 1108
                        end loop;
                        --  Free (Files);
                     end;

1109 1110
                  else
                     Set_Str_To_Name_Buffer (S);
1111
                     Ocarina.Files.Add_File_To_Parse_List
1112 1113
                       (Name_Find,
                        Add_Suffix => False);
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
                  end if;
               end;
         end case;
      end loop;

      --  If no file is given, print the usage function and exit

      if Sources.Last = 0
        and then Get_Current_Action /= Show_Version
        and then Get_Current_Action /= Show_Libraries
        and then Get_Current_Action /= Show_Help
        and then Get_Current_Action /= Shell
1126
        and then Get_Current_Action /= Parse_Scenario_Files_First
1127 1128 1129
      then
         Set_Current_Action (Show_Usage);

1130
      elsif Sources.Last /= 0 and then Get_Current_Action = None then
1131 1132 1133 1134 1135
         Set_Current_Action (Analyze_Model);
      end if;

   exception
      when Invalid_Options =>
1136 1137
         Write_Line
           (Base_Name (Command_Name) & ": invalid combination of options");
1138 1139 1140 1141
         Write_Eol;
         OS_Exit (1);

      when GNAT.Command_Line.Invalid_Switch =>
1142 1143 1144 1145 1146
         Write_Line
           (Base_Name (Command_Name) &
            ": invalid switch " &
            Full_Switch &
            Parameter);
1147 1148 1149 1150
         Write_Eol;
         OS_Exit (1);

      when GNAT.Command_Line.Invalid_Parameter =>
1151 1152 1153 1154
         Write_Line
           (Base_Name (Command_Name) &
            ": invalid parameter for switch -" &
            Full_Switch);
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
         Write_Eol;
         OS_Exit (1);
   end Process_Command_Line;

   -----------
   -- Usage --
   -----------

   procedure Usage is
      Exec_Suffix : String_Access := Get_Executable_Suffix;
   begin
      Set_Standard_Error;
      Write_Line ("Usage: ");
1168 1169 1170 1171
      Write_Line
        ("      " &
         Base_Name (Command_Name, Exec_Suffix.all) &
         " [options] files");
1172
      Write_Line ("      OR");
1173 1174
      Write_Line
        ("      " & Base_Name (Command_Name, Exec_Suffix.all) & " -help");
1175 1176 1177 1178 1179 1180 1181 1182 1183
      Write_Line ("  files are a non null sequence of AADL files");

      Write_Eol;
      Write_Line ("  General purpose options:");
      Write_Line ("   -V  Output Ocarina version, then exit");
      Write_Line ("   -s  Output Ocarina search directory, then exit");

      Write_Eol;
      Write_Line ("  Scenario file options:");
1184 1185 1186
      Write_Line ("   -b  Generate and build code from the AADL model");
      Write_Line ("   -z  Clean code generated from the AADL model");
      Write_Line ("   -ec Execute the generated application code and");
1187
      Write_Line ("       retrieve coverage information");
1188
      Write_Line ("   -er Execute the generated application code and");
1189
      Write_Line ("       verify that there is no regression");
1190
      Write_Line ("   -p  Only parse and instantiate the application model");
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204

      Write_Eol;
      Write_Line ("  Advanced user options:");
      Write_Line ("   -d  Debug mode for developpers");
      Write_Line ("   -q  Quiet mode (default)");
      Write_Line ("   -t  [script] Run Ocarina in terminal interactive mode.");
      Write_Line ("       If a script is given, interpret it then exit.");
      Write_Line ("   -v  Verbose mode for users");
      Write_Line ("   -x  Parse AADL file as an AADL scenario file");

      Ocarina.FE_AADL.Usage;
      Ocarina.FE_REAL.Usage;
      Ocarina.Backends.Usage;

1205 1206
      Write_Line
        ("   -disable-annexes={annexes}" & "  Desactive one or all annexes");
1207 1208
      Write_Line ("       Annexes :");
      Write_Line ("        all");
1209
      Write_Line ("        behavior_specification");
1210 1211 1212 1213 1214 1215 1216
      Write_Line ("        real");
      Write_Eol;

      Free (Exec_Suffix);
   end Usage;

   package RT renames Ocarina.ME_REAL.Tokens;
1217

1218 1219 1220 1221
begin
   --  Init

   Ocarina.Initialize;
1222
   Language             := Get_String_Name ("aadl");
1223 1224 1225 1226 1227
   Default_AADL_Version := Get_Default_AADL_Version;
   AADL_Version         := Default_AADL_Version;

   --  Process the command line

1228
   Process_Command_Line (Root_System_Name, Success);
1229 1230 1231 1232 1233 1234
   Exit_On_Error (not Success, "Cannot process command line");

   --  Initialization Modules

   Ocarina.Configuration.Init_Modules;

1235 1236 1237 1238 1239
   if Verbose_Mode then
      Set_Standard_Error;
      Version;
   end if;

1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
   case Get_Current_Action is
      when Show_Version =>
         Version;
         OS_Exit (0);

      when Show_Help =>
         Usage;
         OS_Exit (0);

      when Show_Libraries =>
         Write_Line (Get_Name_String (Default_Library_Path));
         OS_Exit (0);

      when Show_Usage =>
         Usage;
         OS_Exit (1);

      when Shell =>
         Ocarina_Shell;
         OS_Exit (0);

      when Parse_Scenario_Files_First =>
         Parse_Scenario_Files;
         Reset_Current_Action;
         Set_Current_Action (After_Scenario_Action);
      when others =>
         null;
   end case;

yoogx's avatar
yoogx committed
1269
   --  Parse the AADL files
1270

yoogx's avatar
yoogx committed
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
   AADL_Root := No_Node;
   declare
      F : Types.Int := Sources.First;
   begin
      loop
         File_Name := Search_File (Sources.Table (F));
         Exit_On_Error
           ((File_Name = No_Name),
            "Cannot find file " & Get_Name_String (Sources.Table (F)));
         Buffer := Load_File (File_Name);
         Exit_On_Error
           ((File_Name = No_Name),
            "Cannot read file " & Get_Name_String (Sources.Table (F)));
         AADL_Root := Parse (Language, AADL_Root, Buffer);
         Exit_On_Error (No (AADL_Root), "Cannot parse AADL specifications");
         exit when F = Sources.Last;
         F := F + 1;
      end loop;
   end;
1290

yoogx's avatar
yoogx committed
1291 1292
   Success := Analyze (Language, AADL_Root);
   Exit_On_Error (not Success, "Cannot analyze AADL specifications");
1293

yoogx's avatar
yoogx committed
1294 1295 1296
   if Verbose_Mode then
      Write_Line ("Model parsing: completed");
      Write_Eol;
1297 1298 1299 1300 1301 1302 1303 1304 1305
   end if;

   case Get_Current_Action is
      when Analyze_Model =>
         null;

      when Instantiate_Model =>
         AADL_Root := Instantiate_Model (AADL_Root);
         Exit_On_Error (No (AADL_Root), "Cannot instantiate AADL models");
1306
         if Verbose_Mode then
1307
            Set_Standard_Error;
1308 1309
            Write_Line ("Model instantiation: completed");
            Write_Eol;
1310
            Set_Standard_Output;
1311
         end if;
1312 1313 1314

      when Generate_Code =>
         if Get_Current_Backend_Name = Get_String_Name ("real_theorem")
1315 1316
           or else Get_Current_Backend_Name = Get_String_Name ("real_pp")
         then
1317 1318 1319 1320 1321 1322 1323 1324

            AADL_Root := Instantiate_Model (AADL_Root);
            Exit_On_Error (No (AADL_Root), "Cannot instantiate AADL models");

            Success := Analyze (RT.REAL_Language, AADL_Root);
            Exit_On_Error (not Success, "Cannot analyze REAL specifications");
         end if;
         Generate_Code (AADL_Root);
1325
         if Verbose_Mode then
1326
            Set_Standard_Error;
1327 1328
            Write_Line ("Code generation: completed");
            Write_Eol;
1329
            Set_Standard_Output;
1330
         end if;
1331 1332 1333 1334 1335

      when others =>
         null;
   end case;
end Ocarina_Cmd;