1/* Definitions for Ada expressions 2 3 Copyright (C) 2020-2023 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20#ifndef ADA_EXP_H 21#define ADA_EXP_H 22 23#include "expop.h" 24 25extern struct value *ada_unop_neg (struct type *expect_type, 26 struct expression *exp, 27 enum noside noside, enum exp_opcode op, 28 struct value *arg1); 29extern struct value *ada_atr_tag (struct type *expect_type, 30 struct expression *exp, 31 enum noside noside, enum exp_opcode op, 32 struct value *arg1); 33extern struct value *ada_atr_size (struct type *expect_type, 34 struct expression *exp, 35 enum noside noside, enum exp_opcode op, 36 struct value *arg1); 37extern struct value *ada_abs (struct type *expect_type, 38 struct expression *exp, 39 enum noside noside, enum exp_opcode op, 40 struct value *arg1); 41extern struct value *ada_unop_in_range (struct type *expect_type, 42 struct expression *exp, 43 enum noside noside, enum exp_opcode op, 44 struct value *arg1, struct type *type); 45extern struct value *ada_mult_binop (struct type *expect_type, 46 struct expression *exp, 47 enum noside noside, enum exp_opcode op, 48 struct value *arg1, struct value *arg2); 49extern struct value *ada_equal_binop (struct type *expect_type, 50 struct expression *exp, 51 enum noside noside, enum exp_opcode op, 52 struct value *arg1, struct value *arg2); 53extern struct value *ada_ternop_slice (struct expression *exp, 54 enum noside noside, 55 struct value *array, 56 struct value *low_bound_val, 57 struct value *high_bound_val); 58extern struct value *ada_binop_in_bounds (struct expression *exp, 59 enum noside noside, 60 struct value *arg1, 61 struct value *arg2, 62 int n); 63extern struct value *ada_binop_minmax (struct type *expect_type, 64 struct expression *exp, 65 enum noside noside, enum exp_opcode op, 66 struct value *arg1, 67 struct value *arg2); 68extern struct value *ada_pos_atr (struct type *expect_type, 69 struct expression *exp, 70 enum noside noside, enum exp_opcode op, 71 struct value *arg); 72extern struct value *ada_val_atr (enum noside noside, struct type *type, 73 struct value *arg); 74extern struct value *ada_binop_exp (struct type *expect_type, 75 struct expression *exp, 76 enum noside noside, enum exp_opcode op, 77 struct value *arg1, struct value *arg2); 78 79namespace expr 80{ 81 82/* The base class for Ada type resolution. Ada operations that want 83 to participate in resolution implement this interface. */ 84struct ada_resolvable 85{ 86 /* Resolve this object. EXP is the expression being resolved. 87 DEPROCEDURE_P is true if a symbol that refers to a zero-argument 88 function may be turned into a function call. PARSE_COMPLETION 89 and TRACKER are passed in from the parser context. CONTEXT_TYPE 90 is the expected type of the expression, or nullptr if none is 91 known. This method should return true if the operation should be 92 replaced by a function call with this object as the callee. */ 93 virtual bool resolve (struct expression *exp, 94 bool deprocedure_p, 95 bool parse_completion, 96 innermost_block_tracker *tracker, 97 struct type *context_type) = 0; 98 99 /* Possibly replace this object with some other expression object. 100 This is like 'resolve', but can return a replacement. 101 102 The default implementation calls 'resolve' and wraps this object 103 in a function call if that call returns true. OWNER is a 104 reference to the unique pointer that owns the 'this'; it can be 105 'move'd from to construct the replacement. 106 107 This should either return a new object, or OWNER -- never 108 nullptr. */ 109 110 virtual operation_up replace (operation_up &&owner, 111 struct expression *exp, 112 bool deprocedure_p, 113 bool parse_completion, 114 innermost_block_tracker *tracker, 115 struct type *context_type); 116}; 117 118/* In Ada, some generic operations must be wrapped with a handler that 119 handles some Ada-specific type conversions. */ 120class ada_wrapped_operation 121 : public tuple_holding_operation<operation_up> 122{ 123public: 124 125 using tuple_holding_operation::tuple_holding_operation; 126 127 value *evaluate (struct type *expect_type, 128 struct expression *exp, 129 enum noside noside) override; 130 131 enum exp_opcode opcode () const override 132 { return std::get<0> (m_storage)->opcode (); } 133}; 134 135/* An Ada string constant. */ 136class ada_string_operation 137 : public string_operation 138{ 139public: 140 141 using string_operation::string_operation; 142 143 /* Return the underlying string. */ 144 const char *get_name () const 145 { 146 return std::get<0> (m_storage).c_str (); 147 } 148 149 value *evaluate (struct type *expect_type, 150 struct expression *exp, 151 enum noside noside) override; 152}; 153 154/* The Ada TYPE'(EXP) construct. */ 155class ada_qual_operation 156 : public tuple_holding_operation<operation_up, struct type *> 157{ 158public: 159 160 using tuple_holding_operation::tuple_holding_operation; 161 162 value *evaluate (struct type *expect_type, 163 struct expression *exp, 164 enum noside noside) override; 165 166 enum exp_opcode opcode () const override 167 { return UNOP_QUAL; } 168}; 169 170/* Ternary in-range operator. */ 171class ada_ternop_range_operation 172 : public tuple_holding_operation<operation_up, operation_up, operation_up> 173{ 174public: 175 176 using tuple_holding_operation::tuple_holding_operation; 177 178 value *evaluate (struct type *expect_type, 179 struct expression *exp, 180 enum noside noside) override; 181 182 enum exp_opcode opcode () const override 183 { return TERNOP_IN_RANGE; } 184}; 185 186using ada_neg_operation = unop_operation<UNOP_NEG, ada_unop_neg>; 187using ada_atr_tag_operation = unop_operation<OP_ATR_TAG, ada_atr_tag>; 188using ada_atr_size_operation = unop_operation<OP_ATR_SIZE, ada_atr_size>; 189using ada_abs_operation = unop_operation<UNOP_ABS, ada_abs>; 190using ada_pos_operation = unop_operation<OP_ATR_POS, ada_pos_atr>; 191 192/* The in-range operation, given a type. */ 193class ada_unop_range_operation 194 : public tuple_holding_operation<operation_up, struct type *> 195{ 196public: 197 198 using tuple_holding_operation::tuple_holding_operation; 199 200 value *evaluate (struct type *expect_type, 201 struct expression *exp, 202 enum noside noside) override 203 { 204 value *val = std::get<0> (m_storage)->evaluate (nullptr, exp, noside); 205 return ada_unop_in_range (expect_type, exp, noside, UNOP_IN_RANGE, 206 val, std::get<1> (m_storage)); 207 } 208 209 enum exp_opcode opcode () const override 210 { return UNOP_IN_RANGE; } 211}; 212 213/* The Ada + and - operators. */ 214class ada_binop_addsub_operation 215 : public tuple_holding_operation<enum exp_opcode, operation_up, operation_up> 216{ 217public: 218 219 using tuple_holding_operation::tuple_holding_operation; 220 221 value *evaluate (struct type *expect_type, 222 struct expression *exp, 223 enum noside noside) override; 224 225 enum exp_opcode opcode () const override 226 { return std::get<0> (m_storage); } 227}; 228 229using ada_binop_mul_operation = binop_operation<BINOP_MUL, ada_mult_binop>; 230using ada_binop_div_operation = binop_operation<BINOP_DIV, ada_mult_binop>; 231using ada_binop_rem_operation = binop_operation<BINOP_REM, ada_mult_binop>; 232using ada_binop_mod_operation = binop_operation<BINOP_MOD, ada_mult_binop>; 233 234using ada_binop_min_operation = binop_operation<BINOP_MIN, ada_binop_minmax>; 235using ada_binop_max_operation = binop_operation<BINOP_MAX, ada_binop_minmax>; 236 237using ada_binop_exp_operation = binop_operation<BINOP_EXP, ada_binop_exp>; 238 239/* Implement the equal and not-equal operations for Ada. */ 240class ada_binop_equal_operation 241 : public tuple_holding_operation<enum exp_opcode, operation_up, operation_up> 242{ 243public: 244 245 using tuple_holding_operation::tuple_holding_operation; 246 247 value *evaluate (struct type *expect_type, 248 struct expression *exp, 249 enum noside noside) override 250 { 251 value *arg1 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside); 252 value *arg2 = std::get<2> (m_storage)->evaluate (value_type (arg1), 253 exp, noside); 254 return ada_equal_binop (expect_type, exp, noside, std::get<0> (m_storage), 255 arg1, arg2); 256 } 257 258 enum exp_opcode opcode () const override 259 { return std::get<0> (m_storage); } 260}; 261 262/* Bitwise operators for Ada. */ 263template<enum exp_opcode OP> 264class ada_bitwise_operation 265 : public maybe_constant_operation<operation_up, operation_up> 266{ 267public: 268 269 using maybe_constant_operation::maybe_constant_operation; 270 271 value *evaluate (struct type *expect_type, 272 struct expression *exp, 273 enum noside noside) override 274 { 275 value *lhs = std::get<0> (m_storage)->evaluate (nullptr, exp, noside); 276 value *rhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside); 277 value *result = eval_op_binary (expect_type, exp, noside, OP, lhs, rhs); 278 return value_cast (value_type (lhs), result); 279 } 280 281 enum exp_opcode opcode () const override 282 { return OP; } 283}; 284 285using ada_bitwise_and_operation = ada_bitwise_operation<BINOP_BITWISE_AND>; 286using ada_bitwise_ior_operation = ada_bitwise_operation<BINOP_BITWISE_IOR>; 287using ada_bitwise_xor_operation = ada_bitwise_operation<BINOP_BITWISE_XOR>; 288 289/* Ada array- or string-slice operation. */ 290class ada_ternop_slice_operation 291 : public maybe_constant_operation<operation_up, operation_up, operation_up>, 292 public ada_resolvable 293{ 294public: 295 296 using maybe_constant_operation::maybe_constant_operation; 297 298 value *evaluate (struct type *expect_type, 299 struct expression *exp, 300 enum noside noside) override 301 { 302 value *array = std::get<0> (m_storage)->evaluate (nullptr, exp, noside); 303 value *low = std::get<1> (m_storage)->evaluate (nullptr, exp, noside); 304 value *high = std::get<2> (m_storage)->evaluate (nullptr, exp, noside); 305 return ada_ternop_slice (exp, noside, array, low, high); 306 } 307 308 enum exp_opcode opcode () const override 309 { return TERNOP_SLICE; } 310 311 bool resolve (struct expression *exp, 312 bool deprocedure_p, 313 bool parse_completion, 314 innermost_block_tracker *tracker, 315 struct type *context_type) override; 316}; 317 318/* Implement BINOP_IN_BOUNDS for Ada. */ 319class ada_binop_in_bounds_operation 320 : public maybe_constant_operation<operation_up, operation_up, int> 321{ 322public: 323 324 using maybe_constant_operation::maybe_constant_operation; 325 326 value *evaluate (struct type *expect_type, 327 struct expression *exp, 328 enum noside noside) override 329 { 330 value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside); 331 value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside); 332 return ada_binop_in_bounds (exp, noside, arg1, arg2, 333 std::get<2> (m_storage)); 334 } 335 336 enum exp_opcode opcode () const override 337 { return BINOP_IN_BOUNDS; } 338}; 339 340/* Implement several unary Ada OP_ATR_* operations. */ 341class ada_unop_atr_operation 342 : public maybe_constant_operation<operation_up, enum exp_opcode, int> 343{ 344public: 345 346 using maybe_constant_operation::maybe_constant_operation; 347 348 value *evaluate (struct type *expect_type, 349 struct expression *exp, 350 enum noside noside) override; 351 352 enum exp_opcode opcode () const override 353 { return std::get<1> (m_storage); } 354}; 355 356/* Variant of var_value_operation for Ada. */ 357class ada_var_value_operation 358 : public var_value_operation, public ada_resolvable 359{ 360public: 361 362 using var_value_operation::var_value_operation; 363 364 value *evaluate (struct type *expect_type, 365 struct expression *exp, 366 enum noside noside) override; 367 368 value *evaluate_for_cast (struct type *expect_type, 369 struct expression *exp, 370 enum noside noside) override; 371 372 const block *get_block () const 373 { return std::get<0> (m_storage).block; } 374 375 bool resolve (struct expression *exp, 376 bool deprocedure_p, 377 bool parse_completion, 378 innermost_block_tracker *tracker, 379 struct type *context_type) override; 380 381protected: 382 383 using operation::do_generate_ax; 384}; 385 386/* Variant of var_msym_value_operation for Ada. */ 387class ada_var_msym_value_operation 388 : public var_msym_value_operation 389{ 390public: 391 392 using var_msym_value_operation::var_msym_value_operation; 393 394 value *evaluate_for_cast (struct type *expect_type, 395 struct expression *exp, 396 enum noside noside) override; 397 398protected: 399 400 using operation::do_generate_ax; 401}; 402 403/* Implement the Ada 'val attribute. */ 404class ada_atr_val_operation 405 : public tuple_holding_operation<struct type *, operation_up> 406{ 407public: 408 409 using tuple_holding_operation::tuple_holding_operation; 410 411 value *evaluate (struct type *expect_type, 412 struct expression *exp, 413 enum noside noside) override; 414 415 enum exp_opcode opcode () const override 416 { return OP_ATR_VAL; } 417}; 418 419/* The indirection operator for Ada. */ 420class ada_unop_ind_operation 421 : public unop_ind_base_operation 422{ 423public: 424 425 using unop_ind_base_operation::unop_ind_base_operation; 426 427 value *evaluate (struct type *expect_type, 428 struct expression *exp, 429 enum noside noside) override; 430}; 431 432/* Implement STRUCTOP_STRUCT for Ada. */ 433class ada_structop_operation 434 : public structop_base_operation 435{ 436public: 437 438 using structop_base_operation::structop_base_operation; 439 440 value *evaluate (struct type *expect_type, 441 struct expression *exp, 442 enum noside noside) override; 443 444 enum exp_opcode opcode () const override 445 { return STRUCTOP_STRUCT; } 446 447 /* Set the completion prefix. */ 448 void set_prefix (std::string &&prefix) 449 { 450 m_prefix = std::move (prefix); 451 } 452 453 bool complete (struct expression *exp, completion_tracker &tracker) override 454 { 455 return structop_base_operation::complete (exp, tracker, m_prefix.c_str ()); 456 } 457 458 void dump (struct ui_file *stream, int depth) const override 459 { 460 structop_base_operation::dump (stream, depth); 461 dump_for_expression (stream, depth + 1, m_prefix); 462 } 463 464private: 465 466 /* We may need to provide a prefix to field name completion. See 467 ada-exp.y:find_completion_bounds for details. */ 468 std::string m_prefix; 469}; 470 471/* Function calls for Ada. */ 472class ada_funcall_operation 473 : public tuple_holding_operation<operation_up, std::vector<operation_up>>, 474 public ada_resolvable 475{ 476public: 477 478 using tuple_holding_operation::tuple_holding_operation; 479 480 value *evaluate (struct type *expect_type, 481 struct expression *exp, 482 enum noside noside) override; 483 484 bool resolve (struct expression *exp, 485 bool deprocedure_p, 486 bool parse_completion, 487 innermost_block_tracker *tracker, 488 struct type *context_type) override; 489 490 enum exp_opcode opcode () const override 491 { return OP_FUNCALL; } 492}; 493 494/* An Ada assignment operation. */ 495class ada_assign_operation 496 : public assign_operation 497{ 498public: 499 500 using assign_operation::assign_operation; 501 502 value *evaluate (struct type *expect_type, 503 struct expression *exp, 504 enum noside noside) override; 505 506 enum exp_opcode opcode () const override 507 { return BINOP_ASSIGN; } 508}; 509 510/* This abstract class represents a single component in an Ada 511 aggregate assignment. */ 512class ada_component 513{ 514public: 515 516 /* Assign to LHS, which is part of CONTAINER. EXP is the expression 517 being evaluated. INDICES, LOW, and HIGH indicate which 518 sub-components have already been assigned; INDICES should be 519 updated by this call. */ 520 virtual void assign (struct value *container, 521 struct value *lhs, struct expression *exp, 522 std::vector<LONGEST> &indices, 523 LONGEST low, LONGEST high) = 0; 524 525 /* Same as operation::uses_objfile. */ 526 virtual bool uses_objfile (struct objfile *objfile) = 0; 527 528 /* Same as operation::dump. */ 529 virtual void dump (ui_file *stream, int depth) = 0; 530 531 virtual ~ada_component () = default; 532 533protected: 534 535 ada_component () = default; 536 DISABLE_COPY_AND_ASSIGN (ada_component); 537}; 538 539/* Unique pointer specialization for Ada assignment components. */ 540typedef std::unique_ptr<ada_component> ada_component_up; 541 542/* An operation that holds a single component. */ 543class ada_aggregate_operation 544 : public tuple_holding_operation<ada_component_up> 545{ 546public: 547 548 using tuple_holding_operation::tuple_holding_operation; 549 550 /* Assuming that LHS represents an lvalue having a record or array 551 type, evaluate an assignment of this aggregate's value to LHS. 552 CONTAINER is an lvalue containing LHS (possibly LHS itself). 553 Does not modify the inferior's memory, nor does it modify the 554 contents of LHS (unless == CONTAINER). Returns the modified 555 CONTAINER. */ 556 557 value *assign_aggregate (struct value *container, 558 struct value *lhs, 559 struct expression *exp); 560 561 value *evaluate (struct type *expect_type, 562 struct expression *exp, 563 enum noside noside) override 564 { 565 error (_("Aggregates only allowed on the right of an assignment")); 566 } 567 568 enum exp_opcode opcode () const override 569 { return OP_AGGREGATE; } 570}; 571 572/* A component holding a vector of other components to assign. */ 573class ada_aggregate_component : public ada_component 574{ 575public: 576 577 explicit ada_aggregate_component (std::vector<ada_component_up> &&components) 578 : m_components (std::move (components)) 579 { 580 } 581 582 void assign (struct value *container, 583 struct value *lhs, struct expression *exp, 584 std::vector<LONGEST> &indices, 585 LONGEST low, LONGEST high) override; 586 587 bool uses_objfile (struct objfile *objfile) override; 588 589 void dump (ui_file *stream, int depth) override; 590 591private: 592 593 std::vector<ada_component_up> m_components; 594}; 595 596/* A component that assigns according to a provided index (which is 597 relative to the "low" value). */ 598class ada_positional_component : public ada_component 599{ 600public: 601 602 ada_positional_component (int index, operation_up &&op) 603 : m_index (index), 604 m_op (std::move (op)) 605 { 606 } 607 608 void assign (struct value *container, 609 struct value *lhs, struct expression *exp, 610 std::vector<LONGEST> &indices, 611 LONGEST low, LONGEST high) override; 612 613 bool uses_objfile (struct objfile *objfile) override; 614 615 void dump (ui_file *stream, int depth) override; 616 617private: 618 619 int m_index; 620 operation_up m_op; 621}; 622 623/* A component which handles an "others" clause. */ 624class ada_others_component : public ada_component 625{ 626public: 627 628 explicit ada_others_component (operation_up &&op) 629 : m_op (std::move (op)) 630 { 631 } 632 633 void assign (struct value *container, 634 struct value *lhs, struct expression *exp, 635 std::vector<LONGEST> &indices, 636 LONGEST low, LONGEST high) override; 637 638 bool uses_objfile (struct objfile *objfile) override; 639 640 void dump (ui_file *stream, int depth) override; 641 642private: 643 644 operation_up m_op; 645}; 646 647/* An interface that represents an association that is used in 648 aggregate assignment. */ 649class ada_association 650{ 651public: 652 653 /* Like ada_component::assign, but takes an operation as a 654 parameter. The operation is evaluated and then assigned into LHS 655 according to the rules of the concrete implementation. */ 656 virtual void assign (struct value *container, 657 struct value *lhs, 658 struct expression *exp, 659 std::vector<LONGEST> &indices, 660 LONGEST low, LONGEST high, 661 operation_up &op) = 0; 662 663 /* Same as operation::uses_objfile. */ 664 virtual bool uses_objfile (struct objfile *objfile) = 0; 665 666 /* Same as operation::dump. */ 667 virtual void dump (ui_file *stream, int depth) = 0; 668 669 virtual ~ada_association () = default; 670 671protected: 672 673 ada_association () = default; 674 DISABLE_COPY_AND_ASSIGN (ada_association); 675}; 676 677/* Unique pointer specialization for Ada assignment associations. */ 678typedef std::unique_ptr<ada_association> ada_association_up; 679 680/* A component that holds a vector of associations and an operation. 681 The operation is re-evaluated for each choice. */ 682class ada_choices_component : public ada_component 683{ 684public: 685 686 explicit ada_choices_component (operation_up &&op) 687 : m_op (std::move (op)) 688 { 689 } 690 691 /* Set the vector of associations. This is done separately from the 692 constructor because it was simpler for the implementation of the 693 parser. */ 694 void set_associations (std::vector<ada_association_up> &&assoc) 695 { 696 m_assocs = std::move (assoc); 697 } 698 699 void assign (struct value *container, 700 struct value *lhs, struct expression *exp, 701 std::vector<LONGEST> &indices, 702 LONGEST low, LONGEST high) override; 703 704 bool uses_objfile (struct objfile *objfile) override; 705 706 void dump (ui_file *stream, int depth) override; 707 708private: 709 710 std::vector<ada_association_up> m_assocs; 711 operation_up m_op; 712}; 713 714/* An association that uses a discrete range. */ 715class ada_discrete_range_association : public ada_association 716{ 717public: 718 719 ada_discrete_range_association (operation_up &&low, operation_up &&high) 720 : m_low (std::move (low)), 721 m_high (std::move (high)) 722 { 723 } 724 725 void assign (struct value *container, 726 struct value *lhs, struct expression *exp, 727 std::vector<LONGEST> &indices, 728 LONGEST low, LONGEST high, 729 operation_up &op) override; 730 731 bool uses_objfile (struct objfile *objfile) override; 732 733 void dump (ui_file *stream, int depth) override; 734 735private: 736 737 operation_up m_low; 738 operation_up m_high; 739}; 740 741/* An association that uses a name. The name may be an expression 742 that evaluates to an integer (for arrays), or an Ada string or 743 variable value operation. */ 744class ada_name_association : public ada_association 745{ 746public: 747 748 explicit ada_name_association (operation_up val) 749 : m_val (std::move (val)) 750 { 751 } 752 753 void assign (struct value *container, 754 struct value *lhs, struct expression *exp, 755 std::vector<LONGEST> &indices, 756 LONGEST low, LONGEST high, 757 operation_up &op) override; 758 759 bool uses_objfile (struct objfile *objfile) override; 760 761 void dump (ui_file *stream, int depth) override; 762 763private: 764 765 operation_up m_val; 766}; 767 768/* A character constant expression. This is a separate operation so 769 that it can participate in resolution, so that TYPE'(CST) can 770 work correctly for enums with character enumerators. */ 771class ada_char_operation : public long_const_operation, 772 public ada_resolvable 773{ 774public: 775 776 using long_const_operation::long_const_operation; 777 778 bool resolve (struct expression *exp, 779 bool deprocedure_p, 780 bool parse_completion, 781 innermost_block_tracker *tracker, 782 struct type *context_type) override 783 { 784 /* This should never be called, because this class also implements 785 'replace'. */ 786 gdb_assert_not_reached ("unexpected call"); 787 } 788 789 operation_up replace (operation_up &&owner, 790 struct expression *exp, 791 bool deprocedure_p, 792 bool parse_completion, 793 innermost_block_tracker *tracker, 794 struct type *context_type) override; 795 796 value *evaluate (struct type *expect_type, 797 struct expression *exp, 798 enum noside noside) override; 799}; 800 801class ada_concat_operation : public concat_operation 802{ 803public: 804 805 using concat_operation::concat_operation; 806 807 value *evaluate (struct type *expect_type, 808 struct expression *exp, 809 enum noside noside) override; 810}; 811 812} /* namespace expr */ 813 814#endif /* ADA_EXP_H */ 815