~ubuntu-branches/debian/sid/adabrowse/sid

« back to all changes in this revision

Viewing changes to ad-expressions.adb

  • Committer: Bazaar Package Importer
  • Author(s): Ludovic Brenta
  • Date: 2004-02-14 13:22:40 UTC
  • Revision ID: james.westby@ubuntu.com-20040214132240-cqumhiq1677pkvzo
Tags: upstream-4.0.2
ImportĀ upstreamĀ versionĀ 4.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
-------------------------------------------------------------------------------
 
2
--
 
3
--  This file is part of AdaBrowse.
 
4
--
 
5
-- <STRONG>Copyright (c) 2002 by Thomas Wolf.</STRONG>
 
6
-- <BLOCKQUOTE>
 
7
--    AdaBrowse is free software; you can redistribute it and/or modify it
 
8
--    under the terms of the  GNU General Public License as published by the
 
9
--    Free Software  Foundation; either version 2, or (at your option) any
 
10
--    later version. AdaBrowse is distributed in the hope that it will be
 
11
--    useful, but <EM>without any warranty</EM>; without even the implied
 
12
--    warranty of <EM>merchantability or fitness for a particular purpose.</EM>
 
13
--    See the GNU General Public License for  more details. You should have
 
14
--    received a copy of the GNU General Public License with this distribution,
 
15
--    see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
 
16
--    Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 
17
--    USA.
 
18
-- </BLOCKQUOTE>
 
19
--
 
20
-- <DL><DT><STRONG>
 
21
-- Author:</STRONG><DD>
 
22
--   Thomas Wolf  (TW)
 
23
--   <ADDRESS><A HREF="mailto:twolf@acm.org">twolf@acm.org</A></ADDRESS></DL>
 
24
--
 
25
-- <DL><DT><STRONG>
 
26
-- Purpose:</STRONG><DD>
 
27
--   Parsing and evaluation of expressions; storage of expressions.</DL>
 
28
--
 
29
-- <!--
 
30
-- Revision History
 
31
--
 
32
--   18-JUN-2003   TW  Initial version.
 
33
--   08-JUL-2003   TW  Added the "package" predefined predicate and the @
 
34
--                     prefix operator.
 
35
-- -->
 
36
-------------------------------------------------------------------------------
 
37
 
 
38
pragma License (GPL);
 
39
 
 
40
with Ada.Characters.Handling;
 
41
with Ada.Exceptions;
 
42
with Ada.Unchecked_Deallocation;
 
43
 
 
44
with AD.Predicates;
 
45
 
 
46
with GAL.ADT.Hash_Tables;
 
47
with GAL.Storage.Standard;
 
48
with GAL.Support.Hashing;
 
49
 
 
50
with Util.Strings;
 
51
 
 
52
pragma Elaborate_All (GAL.ADT.Hash_Tables);
 
53
 
 
54
package body AD.Expressions is
 
55
 
 
56
   package ACH renames Ada.Characters.Handling;
 
57
   package ASU renames Ada.Strings.Unbounded;
 
58
 
 
59
   package Hashing is
 
60
      new GAL.ADT.Hash_Tables
 
61
            (Key_Type => String,
 
62
             Item     => Expression,
 
63
             Memory   => GAL.Storage.Standard,
 
64
             Hash     => GAL.Support.Hashing.Hash_Case_Insensitive,
 
65
             "="      => Util.Strings.Equal);
 
66
   --  Initial_Size is the default (23);
 
67
 
 
68
   Macros : Hashing.Hash_Table;
 
69
   Predef : Hashing.Hash_Table;
 
70
 
 
71
   function Is_Nil
 
72
     (Expr : in Expression)
 
73
     return Boolean
 
74
   is
 
75
   begin
 
76
      return Expr.Ptr = null;
 
77
   end Is_Nil;
 
78
 
 
79
   function Is_Boolean
 
80
     (Expr : in Expression)
 
81
     return Boolean
 
82
   is
 
83
   begin
 
84
      return Expr.Ptr /= null and then Expr.Ptr.all in Bool_Exp'Class;
 
85
   end Is_Boolean;
 
86
 
 
87
   function Parse
 
88
     (Text : in String)
 
89
     return Expression
 
90
   is
 
91
 
 
92
      Curr : Natural := Text'First;
 
93
      --  Current position in 'Text'.
 
94
 
 
95
      procedure Error
 
96
        (Msg : in String)
 
97
      is
 
98
      begin
 
99
         Ada.Exceptions.Raise_Exception (Parse_Error'Identity, Msg);
 
100
      end Error;
 
101
 
 
102
      procedure Get
 
103
        (Name  : in     String;
 
104
         Expr  :    out Expression;
 
105
         Found :    out Boolean)
 
106
      is
 
107
      begin
 
108
         Found := True;
 
109
         begin
 
110
            Expr := Hashing.Retrieve (Predef, Name);
 
111
         exception
 
112
            when Hashing.Not_Found =>
 
113
               begin
 
114
                  Expr := Hashing.Retrieve (Macros, Name);
 
115
               exception
 
116
                  when Hashing.Container_Empty |
 
117
                       Hashing.Not_Found =>
 
118
                     Found := False;
 
119
                     Expr  := Nil_Expression;
 
120
               end;
 
121
         end;
 
122
      end Get;
 
123
 
 
124
      procedure Skip
 
125
        (May_Fail : in Boolean := False)
 
126
      is
 
127
         Start : constant Natural := Curr;
 
128
      begin
 
129
         Curr := Util.Strings.Next_Non_Blank (Text (Curr .. Text'Last));
 
130
         if not May_Fail and then Curr = 0 then
 
131
            Error
 
132
              ("Unexpected end of expression: " & Text (Start .. Text'Last));
 
133
         end if;
 
134
         if Curr = 0 then Curr := Text'Last + 1; end if;
 
135
      end Skip;
 
136
 
 
137
      function Create
 
138
        (Op          : in Operator;
 
139
         Left, Right : in Expression;
 
140
         Pos         : in Natural)
 
141
        return Expression
 
142
      is
 
143
         --  Combine expressions, including semantic checks!
 
144
 
 
145
         function Create
 
146
           (Op          : in Operator;
 
147
            Left, Right : in Expression;
 
148
            Pos         : in Natural)
 
149
           return Expression_Ptr
 
150
         is
 
151
         begin
 
152
            case Op is
 
153
               when Op_Not =>
 
154
                  if not Is_Nil (Right) then
 
155
                     Ada.Exceptions.Raise_Exception
 
156
                       (Program_Error'Identity,
 
157
                        "Error in expression parser: binary 'not' operator?!");
 
158
                  end if;
 
159
                  if Left.Ptr.all not in Bool_Exp'Class then
 
160
                     Error ("'not' needs boolean argument: " &
 
161
                            Text (Pos .. Text'Last));
 
162
                  end if;
 
163
                  return new Not_Exp'(Exp with Arg => Left);
 
164
               when Op_Or | Op_Xor | Op_And =>
 
165
                  if Left.Ptr.all not in Bool_Exp'Class or else
 
166
                     Right.Ptr.all not in Bool_Exp'Class
 
167
                  then
 
168
                     Error ("boolean operator with string argument: " &
 
169
                            Text (Pos .. Text'Last));
 
170
                  end if;
 
171
                  if Op = Op_Or then
 
172
                     return
 
173
                       new Or_Exp'(Exp with Left => Left, Right => Right);
 
174
                  elsif Op = Op_Xor then
 
175
                     return
 
176
                       new Xor_Exp'(Exp with Left => Left, Right => Right);
 
177
                  else
 
178
                     return
 
179
                       new And_Exp'(Exp with Left => Left, Right => Right);
 
180
                  end if;
 
181
               when Op_Eq | Op_Neq =>
 
182
                  if Left.Ptr.all in Bool_Exp'Class xor
 
183
                     Right.Ptr.all in Bool_Exp'Class
 
184
                  then
 
185
                     Error ("equality operator with mixed arguments: " &
 
186
                            Text (Pos .. Text'Last));
 
187
                  end if;
 
188
                  declare
 
189
                     Expr : constant Expression_Ptr :=
 
190
                       new Eq_Exp'(Exp with Left => Left, Right => Right);
 
191
                  begin
 
192
                     if Op = Op_Neq then
 
193
                        return
 
194
                          new Not_Exp'
 
195
                            (Exp with
 
196
                               Arg => (Ada.Finalization.Controlled with
 
197
                                         Ptr => Expr));
 
198
                     else
 
199
                        return Expr;
 
200
                     end if;
 
201
                  end;
 
202
               when Op_Concat | Op_Prefix =>
 
203
                  if Left.Ptr.all not in String_Exp'Class or else
 
204
                     Right.Ptr.all not in String_Exp'Class
 
205
                  then
 
206
                     Error ("'&' and '@' need string arguments: " &
 
207
                            Text (Pos .. Text'Last));
 
208
                  end if;
 
209
                  if Op = Op_Concat then
 
210
                     return
 
211
                       new Concat_Exp'(Exp with Left => Left, Right => Right);
 
212
                  else
 
213
                     return
 
214
                       new Prefix_Exp'(Exp with Left => Left, Right => Right);
 
215
                  end if;
 
216
               when others =>
 
217
                  Ada.Exceptions.Raise_Exception
 
218
                    (Program_Error'Identity,
 
219
                     "Error in expression parser (Op_None in Create)");
 
220
            end case;
 
221
            return null;
 
222
         end Create;
 
223
 
 
224
      begin
 
225
         return
 
226
           (Ada.Finalization.Controlled with
 
227
              Ptr => Create (Op, Left, Right, Pos));
 
228
      end Create;
 
229
 
 
230
      Precedence : constant array (Operator) of Natural :=
 
231
        (Op_Not | Op_Concat => 1,
 
232
         Op_Prefix          => 2,
 
233
         Op_Eq | Op_Neq     => 3,
 
234
         Op_And             => 4,
 
235
         Op_Or | Op_Xor     => 5,
 
236
         Op_None            => 6);
 
237
 
 
238
      Lowest_Precedence  : constant Natural := Precedence (Op_None);
 
239
 
 
240
      Last_Op : Operator := Op_None;
 
241
      --  An operator precedence parser needs a one-token look-ahead. We could
 
242
      --  have implemented this by setting 'Curr' at the beginning of the last
 
243
      --  operator and later rescanning, but that would incur a higher
 
244
      --  overhead.
 
245
 
 
246
      Last_Pos : Natural := 0;
 
247
      --  But we still keep the position of the last operator for error
 
248
      --  reporting purposes!
 
249
 
 
250
      function Parse_Operator
 
251
        return Operator
 
252
      is
 
253
         --  Binary operators only!
 
254
      begin
 
255
         Skip (May_Fail => True);
 
256
         --  If nothing follows, we've hit the end of the expression.
 
257
         if Curr > Text'Last then return Op_None; end if;
 
258
         if Text (Curr) = ')' or else Text (Curr) = ';' then
 
259
            return Op_None;
 
260
         elsif Text (Curr) = '=' then
 
261
            Curr := Curr + 1;
 
262
            return Op_Eq;
 
263
         elsif Text (Curr) = '&' then
 
264
            Curr := Curr + 1;
 
265
            return Op_Concat;
 
266
         elsif Text (Curr) = '@' then
 
267
            Curr := Curr + 1;
 
268
            return Op_Prefix;
 
269
         elsif Curr < Text'Last and then
 
270
               Text (Curr .. Curr + 1) = "/=" then
 
271
            Curr := Curr + 2;
 
272
            return Op_Neq;
 
273
         else
 
274
            declare
 
275
               Found : Boolean;
 
276
               Expr  : Expression;
 
277
               I     : constant Natural :=
 
278
                 Util.Strings.Identifier (Text (Curr .. Text'Last));
 
279
               Op    : Operator;
 
280
            begin
 
281
               if I = 0 then
 
282
                  Error ("Operator missing: " &
 
283
                         Text (Curr .. Text'Last));
 
284
               end if;
 
285
               Get (Text (Curr .. I), Expr, Found);
 
286
               if not Found then
 
287
                  Error ("Unknown function """ & Text (Curr .. I) & '"');
 
288
               end if;
 
289
               if Expr.Ptr.all in Predefined'Class then
 
290
                  Op := Predefined (Expr.Ptr.all).Op;
 
291
               else
 
292
                  Error ("Operator missing: " &
 
293
                         Text (Curr .. Text'Last));
 
294
               end if;
 
295
               if Op = Op_Not then
 
296
                  Error
 
297
                    ("'not' not allowed here: " &
 
298
                     Text (Curr .. Text'Last));
 
299
               end if;
 
300
               Curr := I + 1;
 
301
               return Op;
 
302
            end;
 
303
         end if;
 
304
         return Op_None;
 
305
      end Parse_Operator;
 
306
 
 
307
      function Parse_Expr
 
308
        (Max_Op : in Natural := Lowest_Precedence)
 
309
        return Expression
 
310
      is
 
311
 
 
312
         function Parse_Term
 
313
           return Expression
 
314
         is
 
315
 
 
316
            function Parse_Factor
 
317
              return Expression
 
318
            is
 
319
               Expr : Expression;
 
320
            begin
 
321
               Last_Op := Op_None;
 
322
               Skip;
 
323
               if Text (Curr) = '(' then
 
324
                  declare
 
325
                     Start : constant Natural := Curr;
 
326
                  begin
 
327
                     Expr := Parse_Expr;
 
328
                     Last_Op := Op_None;
 
329
                     Skip (May_Fail => True);
 
330
                     --  We allow failing because we want to emit a more
 
331
                     --  meaningful error message.
 
332
                     if Curr > Text'Last or else Text (Curr) /= ')' then
 
333
                        Error ("Missing ')': " & Text (Start .. Curr - 1));
 
334
                     end if;
 
335
                     Curr := Curr + 1;
 
336
                  end;
 
337
               elsif Text (Curr) = '"' then
 
338
                  --  String literal:
 
339
                  declare
 
340
                     Start : constant Natural := Curr;
 
341
                     I     : constant Natural :=
 
342
                       Util.Strings.Skip_String
 
343
                         (Text (Curr .. Text'Last), '"', '"');
 
344
                  begin
 
345
                     if I = 0 then
 
346
                        Error
 
347
                          ("String not closed: " & Text (Curr .. Text'Last));
 
348
                     end if;
 
349
                     Curr := I + 1;
 
350
                     return
 
351
                       (Ada.Finalization.Controlled with
 
352
                          Ptr => new Exp'Class'
 
353
                            (Exp'Class
 
354
                               (Literal'
 
355
                                  (Exp with
 
356
                                     Val =>
 
357
                                       ASU.To_Unbounded_String
 
358
                                         (Util.Strings.Unquote
 
359
                                            (Text (Start + 1 .. I - 1),
 
360
                                             '"', '"'))))));
 
361
                  end;
 
362
               else
 
363
                  declare
 
364
                     Found : Boolean;
 
365
                     I     : constant Natural :=
 
366
                       Util.Strings.Identifier (Text (Curr .. Text'Last));
 
367
                  begin
 
368
                     if I = 0 then
 
369
                        Error
 
370
                          ("Identifier expected: " & Text (Curr .. Text'Last));
 
371
                     end if;
 
372
                     Get (Text (Curr .. I), Expr, Found);
 
373
                     if not Found then
 
374
                        Error ("Unknown function """ & Text (Curr .. I) & '"');
 
375
                     end if;
 
376
                     if Expr.Ptr.all in Predefined'Class then
 
377
                        Error
 
378
                          ("Unexpected operator: " & Text (Curr .. Text'Last));
 
379
                     end if;
 
380
                     Curr := I + 1;
 
381
                  end;
 
382
               end if;
 
383
               return Expr;
 
384
            end Parse_Factor;
 
385
 
 
386
         begin
 
387
            Last_Op := Op_None;
 
388
            Skip;
 
389
            declare
 
390
               Start : constant Natural := Curr;
 
391
               I     : constant Natural :=
 
392
                 Util.Strings.Identifier (Text (Curr .. Text'Last));
 
393
            begin
 
394
               if I = Curr + 2 and then
 
395
                  Util.Strings.To_Lower (Text (Curr .. I)) = "not"
 
396
               then
 
397
                  Curr := I + 1;
 
398
                  return Create
 
399
                           (Op_Not, Parse_Factor, Nil_Expression, Start);
 
400
               end if;
 
401
            end;
 
402
            return Parse_Factor;
 
403
         end Parse_Term;
 
404
 
 
405
         Expr  : Expression;
 
406
         Start : Natural;
 
407
         Op    : Operator;
 
408
 
 
409
      begin
 
410
         --  This is an operator precedence parser.
 
411
         Expr := Parse_Term;
 
412
         while Curr <= Text'Last loop
 
413
            if Last_Op = Op_None then
 
414
               Start := Curr;
 
415
               Op    := Parse_Operator;
 
416
               if Op = Op_None then
 
417
                  --  OK if text exhausted, or at a probable expression end.
 
418
                  exit when
 
419
                    Curr > Text'Last or else
 
420
                    Text (Curr) = ')' or else
 
421
                    Text (Curr) = ';';
 
422
                  Error ("Operator expected: " & Text (Start .. Text'Last));
 
423
               end if;
 
424
            else
 
425
               Op    := Last_Op;
 
426
               Start := Last_Pos;
 
427
            end if;
 
428
            if Precedence (Op) >= Max_Op then
 
429
               Last_Op  := Op;
 
430
               Last_Pos := Start;
 
431
               return Expr;
 
432
            end if;
 
433
            Last_Op := Op_None;
 
434
            Expr :=
 
435
              Create
 
436
                (Op, Expr, Parse_Expr (Max_Op => Precedence (Op)), Start);
 
437
         end loop;
 
438
         return Expr;
 
439
      end Parse_Expr;
 
440
 
 
441
      Expr : Expression;
 
442
 
 
443
   begin
 
444
      Expr := Parse_Expr;
 
445
      if Last_Op /= Op_None then
 
446
         Error ("Spurious operator at end of expression: " &
 
447
                Text (Last_Pos .. Text'Last));
 
448
      end if;
 
449
      if Curr <= Text'Last then
 
450
         --  We allow a semicolon at the end.
 
451
         if Text (Curr) = ';' then Curr := Curr + 1; end if;
 
452
         Skip (May_Fail => True);
 
453
         --  If there's still something following, we have an error.
 
454
         if Curr <= Text'Last then
 
455
            Error
 
456
              ("Garbage following expression: " & Text (Curr .. Text'Last));
 
457
         end if;
 
458
      end if;
 
459
      return Expr;
 
460
   end Parse;
 
461
 
 
462
   procedure Define_Macro
 
463
     (Name      : in     String;
 
464
      Expr      : in     Expression;
 
465
      Redefined :    out Boolean)
 
466
   is
 
467
   begin
 
468
      if Hashing.Contains (Predef, Name) then
 
469
         Ada.Exceptions.Raise_Exception
 
470
           (Parse_Error'Identity,
 
471
            "Predefined functions and operators cannot be redefined!");
 
472
      end if;
 
473
      Redefined := Hashing.Contains (Macros, Name);
 
474
      Hashing.Replace (Macros, Name, Expr);
 
475
   end Define_Macro;
 
476
 
 
477
   function Evaluate
 
478
     (Expr     : in Expression;
 
479
      Argument : in Asis.Element)
 
480
     return Boolean
 
481
   is
 
482
   begin
 
483
      return Eval (Bool_Exp'Class (Expr.Ptr.all), Argument);
 
484
   end Evaluate;
 
485
 
 
486
   function Eval
 
487
     (E        : in Terminal;
 
488
      Argument : in Asis.Element)
 
489
     return Boolean
 
490
   is
 
491
   begin
 
492
      return E.P /= null and then E.P (Argument);
 
493
   end Eval;
 
494
 
 
495
   function Eval
 
496
     (E        : in Value;
 
497
      Argument : in Asis.Element)
 
498
     return Boolean
 
499
   is
 
500
      pragma Warnings (Off, Argument); --  silence -gnatwa
 
501
   begin
 
502
      return E.Val;
 
503
   end Eval;
 
504
 
 
505
   function Eval
 
506
     (E        : in And_Exp;
 
507
      Argument : in Asis.Element)
 
508
     return Boolean
 
509
   is
 
510
   begin
 
511
      return Eval (Bool_Exp'Class (E.Left.Ptr.all), Argument)
 
512
             and then
 
513
             Eval (Bool_Exp'Class (E.Right.Ptr.all), Argument);
 
514
   end Eval;
 
515
 
 
516
   function Eval
 
517
     (E        : in Or_Exp;
 
518
      Argument : in Asis.Element)
 
519
     return Boolean
 
520
   is
 
521
   begin
 
522
      return Eval (Bool_Exp'Class (E.Left.Ptr.all), Argument)
 
523
             or else
 
524
             Eval (Bool_Exp'Class (E.Right.Ptr.all), Argument);
 
525
   end Eval;
 
526
 
 
527
   function Eval
 
528
     (E        : in Xor_Exp;
 
529
      Argument : in Asis.Element)
 
530
     return Boolean
 
531
   is
 
532
   begin
 
533
      return Eval (Bool_Exp'Class (E.Left.Ptr.all), Argument)
 
534
             xor
 
535
             Eval (Bool_Exp'Class (E.Right.Ptr.all), Argument);
 
536
   end Eval;
 
537
 
 
538
   function Eval
 
539
     (E        : in Eq_Exp;
 
540
      Argument : in Asis.Element)
 
541
     return Boolean
 
542
   is
 
543
   begin
 
544
      if E.Left.Ptr.all in Bool_Exp'Class then
 
545
         return Eval (Bool_Exp'Class (E.Left.Ptr.all), Argument)
 
546
                =
 
547
                Eval (Bool_Exp'Class (E.Right.Ptr.all), Argument);
 
548
      else
 
549
         return Util.Strings.Equal
 
550
                  (Eval (String_Exp'Class (E.Left.Ptr.all), Argument),
 
551
                   Eval (String_Exp'Class (E.Right.Ptr.all), Argument));
 
552
      end if;
 
553
   end Eval;
 
554
 
 
555
   function Eval
 
556
     (E        : in Prefix_Exp;
 
557
      Argument : in Asis.Element)
 
558
     return Boolean
 
559
   is
 
560
   begin
 
561
      --  We know we have two string expressions!
 
562
      declare
 
563
         Left : constant String :=
 
564
           Util.Strings.To_Lower
 
565
             (Eval (String_Exp'Class (E.Left.Ptr.all), Argument));
 
566
         Right : constant String :=
 
567
           Util.Strings.To_Lower
 
568
             (Eval (String_Exp'Class (E.Right.Ptr.all), Argument));
 
569
      begin
 
570
         return Util.Strings.Is_Prefix (Left, Right);
 
571
      end;
 
572
   end Eval;
 
573
 
 
574
   function Eval
 
575
     (E        : in Not_Exp;
 
576
      Argument : in Asis.Element)
 
577
     return Boolean
 
578
   is
 
579
   begin
 
580
      return not Eval (Bool_Exp'Class (E.Arg.Ptr.all), Argument);
 
581
   end Eval;
 
582
 
 
583
   ----------------------------------------------------------------------------
 
584
 
 
585
   function Eval
 
586
     (E        : in String_Terminal;
 
587
      Argument : in Asis.Element)
 
588
     return String
 
589
   is
 
590
   begin
 
591
      if E.P = null then return ""; end if;
 
592
      return ACH.To_String (E.P (Argument));
 
593
   end Eval;
 
594
 
 
595
   function Eval
 
596
     (E        : in Literal;
 
597
      Argument : in Asis.Element)
 
598
     return String
 
599
   is
 
600
      pragma Warnings (Off, Argument); --  silence -gnatwa
 
601
   begin
 
602
      return ASU.To_String (E.Val);
 
603
   end Eval;
 
604
 
 
605
   function Eval
 
606
     (E        : in Concat_Exp;
 
607
      Argument : in Asis.Element)
 
608
     return String
 
609
   is
 
610
   begin
 
611
      return Eval (String_Exp'Class (E.Left.Ptr.all), Argument) &
 
612
             Eval (String_Exp'Class (E.Right.Ptr.all), Argument);
 
613
   end Eval;
 
614
 
 
615
   ----------------------------------------------------------------------------
 
616
 
 
617
   procedure Adjust
 
618
     (E : in out Expression)
 
619
   is
 
620
   begin
 
621
      if E.Ptr /= null then
 
622
         E.Ptr.Ref_Count := E.Ptr.Ref_Count + 1;
 
623
      end if;
 
624
   end Adjust;
 
625
 
 
626
   procedure Finalize
 
627
     (E : in out Expression)
 
628
   is
 
629
 
 
630
      procedure Free is
 
631
         new Ada.Unchecked_Deallocation (Exp'Class, Expression_Ptr);
 
632
 
 
633
   begin
 
634
      if E.Ptr /= null then
 
635
         E.Ptr.Ref_Count := E.Ptr.Ref_Count - 1;
 
636
         if E.Ptr.Ref_Count = 0 then
 
637
            Free (E.Ptr);
 
638
         end if;
 
639
      end if;
 
640
   end Finalize;
 
641
 
 
642
   ----------------------------------------------------------------------------
 
643
 
 
644
begin
 
645
   Hashing.Set_Resize (Macros, 0.75);
 
646
   Hashing.Set_Resize (Predef, 0.75);
 
647
   declare
 
648
      Linear_Growth : GAL.Support.Hashing.Linear_Growth_Policy (20);
 
649
   begin
 
650
      Hashing.Set_Growth_Policy (Macros, Linear_Growth);
 
651
      Hashing.Set_Growth_Policy (Predef, Linear_Growth);
 
652
   end;
 
653
   Add_Predefined :
 
654
   declare
 
655
 
 
656
      procedure Add_Expression
 
657
        (Name : in String;
 
658
         Expr : in Exp'Class)
 
659
      is
 
660
         E : Expression :=
 
661
           (Ada.Finalization.Controlled with Ptr => new Exp'Class'(Expr));
 
662
      begin
 
663
         Hashing.Insert (Predef, Name, E);
 
664
      end Add_Expression;
 
665
 
 
666
      use AD.Predicates;
 
667
   begin
 
668
      Add_Expression
 
669
        ("private", Terminal'(Exp with P => Is_Private'Access));
 
670
      Add_Expression
 
671
        ("separate", Terminal'(Exp with P => Is_Separate'Access));
 
672
      Add_Expression
 
673
        ("unit", Terminal'(Exp with P => Is_Unit'Access));
 
674
      Add_Expression
 
675
        ("package", Terminal'(Exp with P => Is_Package'Access));
 
676
      Add_Expression
 
677
        ("child", Terminal'(Exp with P => Is_Child'Access));
 
678
      Add_Expression
 
679
        ("constant", Terminal'(Exp with P => Is_Constant'Access));
 
680
      Add_Expression
 
681
        ("pragma", Terminal'(Exp with P => Is_Pragma'Access));
 
682
      Add_Expression
 
683
        ("representation", Terminal'(Exp with P => Is_Clause'Access));
 
684
      Add_Expression
 
685
        ("variable", Terminal'(Exp with P => Is_Variable'Access));
 
686
      Add_Expression
 
687
        ("type", Terminal'(Exp with P => Is_Type'Access));
 
688
      Add_Expression
 
689
        ("subtype", Terminal'(Exp with P => Is_Subtype'Access));
 
690
      Add_Expression
 
691
        ("procedure", Terminal'(Exp with P => Is_Procedure'Access));
 
692
      Add_Expression
 
693
        ("function", Terminal'(Exp with P => Is_Function'Access));
 
694
      Add_Expression
 
695
        ("subprogram", Terminal'(Exp with P => Is_Subprogram'Access));
 
696
      Add_Expression
 
697
        ("entry", Terminal'(Exp with P => Is_Entry'Access));
 
698
      Add_Expression
 
699
        ("elementary", Terminal'(Exp with P => Is_Elementary'Access));
 
700
      Add_Expression
 
701
        ("scalar", Terminal'(Exp with P => Is_Scalar'Access));
 
702
      Add_Expression
 
703
        ("discrete", Terminal'(Exp with P => Is_Discrete'Access));
 
704
      Add_Expression
 
705
        ("enum", Terminal'(Exp with P => Is_Enumeration'Access));
 
706
      Add_Expression
 
707
        ("integral", Terminal'(Exp with P => Is_Integral'Access));
 
708
      Add_Expression
 
709
        ("signed", Terminal'(Exp with P => Is_Signed'Access));
 
710
      Add_Expression
 
711
        ("modular", Terminal'(Exp with P => Is_Modular'Access));
 
712
      Add_Expression
 
713
        ("real", Terminal'(Exp with P => Is_Real'Access));
 
714
      Add_Expression
 
715
        ("float", Terminal'(Exp with P => Is_Float'Access));
 
716
      Add_Expression
 
717
        ("fixed", Terminal'(Exp with P => Is_Fixed'Access));
 
718
      Add_Expression
 
719
        ("ordinary_fixed", Terminal'(Exp with P => Is_Ordinary_Fixed'Access));
 
720
      Add_Expression
 
721
        ("decimal_fixed", Terminal'(Exp with P => Is_Decimal_Fixed'Access));
 
722
      Add_Expression
 
723
        ("numeric", Terminal'(Exp with P => Is_Numeric'Access));
 
724
      Add_Expression
 
725
        ("access", Terminal'(Exp with P => Is_Access'Access));
 
726
      Add_Expression
 
727
        ("access_object", Terminal'(Exp with P => Is_Access_To_Object'Access));
 
728
      Add_Expression
 
729
        ("access_subprogram",
 
730
         Terminal'(Exp with P => Is_Access_To_Subprogram'Access));
 
731
      Add_Expression
 
732
        ("composite", Terminal'(Exp with P => Is_Composite'Access));
 
733
      Add_Expression
 
734
        ("array", Terminal'(Exp with P => Is_Array'Access));
 
735
      Add_Expression
 
736
        ("record", Terminal'(Exp with P => Is_Record'Access));
 
737
      Add_Expression
 
738
        ("tagged", Terminal'(Exp with P => Is_Tagged'Access));
 
739
      Add_Expression
 
740
        ("task", Terminal'(Exp with P => Is_Task'Access));
 
741
      Add_Expression
 
742
        ("protected", Terminal'(Exp with P => Is_Protected'Access));
 
743
      Add_Expression
 
744
        ("limited", Terminal'(Exp with P => Is_Limited'Access));
 
745
      Add_Expression
 
746
        ("class_wide", Terminal'(Exp with P => Is_Class_Wide'Access));
 
747
      Add_Expression
 
748
        ("controlled", Terminal'(Exp with P => Is_Controlled'Access));
 
749
      Add_Expression
 
750
        ("private_type", Terminal'(Exp with P => Is_Private_Type'Access));
 
751
      Add_Expression
 
752
        ("incomplete", Terminal'(Exp with P => Is_Incomplete'Access));
 
753
      Add_Expression
 
754
        ("aliased", Terminal'(Exp with P => Is_Aliased'Access));
 
755
      Add_Expression
 
756
        ("exception", Terminal'(Exp with P => Is_Exception'Access));
 
757
      Add_Expression
 
758
        ("renaming", Terminal'(Exp with P => Is_Renaming'Access));
 
759
      Add_Expression
 
760
        ("generic", Terminal'(Exp with P => Is_Generic'Access));
 
761
      Add_Expression
 
762
        ("formal", Terminal'(Exp with P => Is_Generic_Formal'Access));
 
763
      Add_Expression
 
764
        ("instance", Terminal'(Exp with P => Is_Instance'Access));
 
765
      Add_Expression
 
766
        ("abstract", Terminal'(Exp with P => Is_Abstract'Access));
 
767
      Add_Expression
 
768
        ("full_name", String_Terminal'(Exp with P => Unique_Name'Access));
 
769
      Add_Expression
 
770
        ("name", String_Terminal'(Exp with P => Simple_Name'Access));
 
771
      Add_Expression
 
772
        ("true", Value'(Exp with Val => True));
 
773
      Add_Expression
 
774
        ("false", Value'(Exp with Val => False));
 
775
      --  Also insert the keywords (facilitates checking whether someone had
 
776
      --  the glorious idea to name a macro "not").
 
777
      Add_Expression
 
778
        ("not", Predefined'(Exp with Op => Op_Not));
 
779
      Add_Expression
 
780
        ("and", Predefined'(Exp with Op => Op_And));
 
781
      Add_Expression
 
782
        ("or",  Predefined'(Exp with Op => Op_Or));
 
783
      Add_Expression
 
784
        ("xor", Predefined'(Exp with Op => Op_Xor));
 
785
   end Add_Predefined;
 
786
end AD.Expressions;