| /* Implementation of subroutines for the GNU C++ pretty-printer. |
| Copyright (C) 2003 Free Software Foundation, Inc. |
| Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net> |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 2, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING. If not, write to the Free |
| Software Foundation, 59 Temple Place - Suite 330, Boston, MA |
| 02111-1307, USA. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "real.h" |
| #include "cxx-pretty-print.h" |
| #include "cp-tree.h" |
| #include "toplev.h" |
| |
| static void pp_cxx_unqualified_id (cxx_pretty_printer *, tree); |
| static void pp_cxx_nested_name_specifier (cxx_pretty_printer *, tree); |
| static void pp_cxx_qualified_id (cxx_pretty_printer *, tree); |
| static void pp_cxx_assignment_expression (cxx_pretty_printer *, tree); |
| static void pp_cxx_expression (cxx_pretty_printer *, tree); |
| static void pp_cxx_template_argument_list (cxx_pretty_printer *, tree); |
| static void pp_cxx_type_specifier_seq (cxx_pretty_printer *, tree); |
| static void pp_cxx_ptr_operator (cxx_pretty_printer *, tree); |
| static void pp_cxx_type_id (cxx_pretty_printer *, tree); |
| static void pp_cxx_direct_abstract_declarator (cxx_pretty_printer *, tree); |
| static void pp_cxx_declarator (cxx_pretty_printer *, tree); |
| static void pp_cxx_abstract_declarator (cxx_pretty_printer *, tree); |
| static void pp_cxx_template_parameter (cxx_pretty_printer *, tree); |
| |
| #define pp_cxx_whitespace(PP) pp_c_whitespace (pp_c_base (PP)) |
| #define pp_cxx_left_paren(PP) pp_c_left_paren (pp_c_base (PP)) |
| #define pp_cxx_right_paren(PP) pp_c_right_paren (pp_c_base (PP)) |
| #define pp_cxx_left_brace(PP) pp_c_left_brace (pp_c_base (PP)) |
| #define pp_cxx_right_brace(PP) pp_c_right_brace (pp_c_base (PP)) |
| #define pp_cxx_dot(PP) pp_c_dot (pp_c_base (PP)) |
| #define pp_cxx_arrow(PP) pp_c_arrow (pp_c_base (PP)) |
| #define pp_cxx_semicolon(PP) pp_c_semicolon (pp_c_base (PP)) |
| |
| static inline void |
| pp_cxx_nonconsecutive_character (cxx_pretty_printer *pp, int c) |
| { |
| const char *p = pp_last_position_in_text (pp); |
| |
| if (p != NULL && *p == c) |
| pp_cxx_whitespace (pp); |
| pp_character (pp, c); |
| pp_base (pp)->padding = pp_none; |
| } |
| |
| #define pp_cxx_begin_template_argument_list(PP) \ |
| pp_cxx_nonconsecutive_character (PP, '<') |
| #define pp_cxx_end_template_argument_list(PP) \ |
| pp_cxx_nonconsecutive_character (PP, '>') |
| |
| #define pp_cxx_identifier(PP, ID) pp_c_identifier (pp_c_base (PP), ID) |
| #define pp_cxx_tree_identifier(PP, T) pp_c_tree_identifier (pp_c_base (PP), T) |
| |
| #define pp_cxx_cv_qualifier_seq(PP, T) \ |
| pp_c_type_qualifier_list (pp_c_base (PP), T) |
| #define pp_cxx_storage_class_specifier(PP, T) \ |
| pp_c_storage_class_specifier (pp_c_base (PP), T) |
| #define pp_cxx_expression_list(PP, T) \ |
| pp_c_expression_list (pp_c_base (PP), T) |
| #define pp_cxx_space_for_pointer_operator(PP, T) \ |
| pp_c_space_for_pointer_operator (pp_c_base (PP), T) |
| #define pp_cxx_init_declarator(PP, T) \ |
| pp_c_init_declarator (pp_c_base (PP), T) |
| #define pp_cxx_call_argument_list(PP, T) \ |
| pp_c_call_argument_list (pp_c_base (PP), T) |
| |
| static void |
| pp_cxx_colon_colon (cxx_pretty_printer *pp) |
| { |
| pp_colon_colon (pp); |
| pp_base (pp)->padding = pp_none; |
| } |
| |
| |
| /* Expressions. */ |
| |
| static inline bool |
| is_destructor_name (tree name) |
| { |
| return name == complete_dtor_identifier |
| || name == base_dtor_identifier |
| || name == deleting_dtor_identifier; |
| } |
| |
| /* conversion-function-id: |
| operator conversion-type-id |
| |
| conversion-type-id: |
| type-specifier-seq conversion-declarator(opt) |
| |
| conversion-declarator: |
| ptr-operator conversion-declarator(opt) */ |
| static inline void |
| pp_cxx_conversion_function_id (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_identifier (pp, "operator"); |
| pp_cxx_type_specifier_seq (pp, TREE_TYPE (t)); |
| } |
| |
| static inline void |
| pp_cxx_template_id (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_unqualified_id (pp, TREE_OPERAND (t, 0)); |
| pp_cxx_begin_template_argument_list (pp); |
| pp_cxx_template_argument_list (pp, TREE_OPERAND (t, 1)); |
| pp_cxx_end_template_argument_list (pp); |
| } |
| |
| /* unqualified-id: |
| identifier |
| operator-function-id |
| conversion-function-id |
| ~ class-name |
| template-id */ |
| static void |
| pp_cxx_unqualified_id (cxx_pretty_printer *pp, tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| switch (code) |
| { |
| case RESULT_DECL: |
| pp_cxx_identifier (pp, "<return-value>"); |
| break; |
| |
| case OVERLOAD: |
| t = OVL_CURRENT (t); |
| case VAR_DECL: |
| case PARM_DECL: |
| case CONST_DECL: |
| case TYPE_DECL: |
| case FUNCTION_DECL: |
| case NAMESPACE_DECL: |
| case FIELD_DECL: |
| case LABEL_DECL: |
| case USING_DECL: |
| case TEMPLATE_DECL: |
| t = DECL_NAME (t); |
| |
| case IDENTIFIER_NODE: |
| if (t == NULL) |
| pp_cxx_identifier (pp, "<anonymous>"); |
| else if (IDENTIFIER_TYPENAME_P (t)) |
| pp_cxx_conversion_function_id (pp, t); |
| else |
| { |
| if (is_destructor_name (t)) |
| { |
| pp_complement (pp); |
| /* FIXME: Why is this necessary? */ |
| if (TREE_TYPE (t)) |
| t = constructor_name (TREE_TYPE (t)); |
| } |
| pp_cxx_tree_identifier (pp, t); |
| } |
| break; |
| |
| case TEMPLATE_ID_EXPR: |
| pp_cxx_template_id (pp, t); |
| break; |
| |
| case BASELINK: |
| pp_cxx_unqualified_id (pp, BASELINK_FUNCTIONS (t)); |
| break; |
| |
| case RECORD_TYPE: |
| case UNION_TYPE: |
| case ENUMERAL_TYPE: |
| pp_cxx_unqualified_id (pp, TYPE_NAME (t)); |
| break; |
| |
| case TEMPLATE_TYPE_PARM: |
| t = TYPE_FIELDS (t); |
| case TEMPLATE_PARM_INDEX: |
| pp_cxx_unqualified_id (pp, TEMPLATE_PARM_DECL (t)); |
| break; |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| break; |
| } |
| } |
| |
| static inline void |
| pp_cxx_template_keyword_if_needed (cxx_pretty_printer *pp, tree scope, tree t) |
| { |
| if (TREE_CODE (t) == TEMPLATE_ID_EXPR |
| && TYPE_P (scope) && dependent_type_p (scope)) |
| pp_cxx_identifier (pp, "template"); |
| } |
| |
| /* nested-name-specifier: |
| class-or-namespace-name :: nested-name-specifier(opt) |
| class-or-namespace-name :: template nested-name-specifier */ |
| static void |
| pp_cxx_nested_name_specifier (cxx_pretty_printer *pp, tree t) |
| { |
| if (t != NULL && t != pp->enclosing_scope) |
| { |
| tree scope = TYPE_P (t) ? TYPE_CONTEXT (t) : DECL_CONTEXT (t); |
| pp_cxx_nested_name_specifier (pp, scope); |
| pp_cxx_template_keyword_if_needed (pp, scope, t); |
| pp_cxx_unqualified_id (pp, t); |
| pp_cxx_colon_colon (pp); |
| } |
| } |
| |
| /* qualified-id: |
| nested-name-specifier template(opt) unqualified-id */ |
| static void |
| pp_cxx_qualified_id (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case PTRMEM_CST: |
| pp_cxx_nested_name_specifier (pp, PTRMEM_CST_CLASS (t)); |
| pp_cxx_unqualified_id (pp, PTRMEM_CST_MEMBER (t)); |
| break; |
| |
| case OVERLOAD: |
| t = OVL_CURRENT (t); |
| case FUNCTION_DECL: |
| if (DECL_FUNCTION_MEMBER_P (t)) |
| pp_cxx_nested_name_specifier (pp, DECL_CONTEXT (t)); |
| pp_cxx_unqualified_id |
| (pp, DECL_CONSTRUCTOR_P (t) ? DECL_CONTEXT (t) : t); |
| break; |
| |
| case OFFSET_REF: |
| case SCOPE_REF: |
| pp_cxx_nested_name_specifier (pp, TREE_OPERAND (t, 0)); |
| pp_cxx_unqualified_id (pp, TREE_OPERAND (t, 1)); |
| break; |
| |
| default: |
| { |
| tree scope = TYPE_P (t) ? TYPE_CONTEXT (t) : DECL_CONTEXT (t); |
| if (scope != pp->enclosing_scope) |
| { |
| pp_cxx_nested_name_specifier (pp, scope); |
| pp_cxx_template_keyword_if_needed (pp, scope, t); |
| } |
| pp_cxx_unqualified_id (pp, t); |
| } |
| break; |
| } |
| } |
| |
| /* id-expression: |
| unqualified-id |
| qualified-id */ |
| static inline void |
| pp_cxx_id_expression (cxx_pretty_printer *pp, tree t) |
| { |
| if (TREE_CODE (t) == OVERLOAD) |
| t = OVL_CURRENT (t); |
| if (DECL_P (t) && DECL_CONTEXT (t)) |
| pp_cxx_qualified_id (pp, t); |
| else |
| pp_cxx_unqualified_id (pp, t); |
| } |
| |
| /* primary-expression: |
| literal |
| this |
| :: identifier |
| :: operator-function-id |
| :: qualifier-id |
| ( expression ) |
| id-expression */ |
| static void |
| pp_cxx_primary_expression (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case STRING_CST: |
| case INTEGER_CST: |
| case REAL_CST: |
| pp_c_constant (pp_c_base (pp), t); |
| break; |
| |
| case BASELINK: |
| t = BASELINK_FUNCTIONS (t); |
| case VAR_DECL: |
| case PARM_DECL: |
| case FIELD_DECL: |
| case FUNCTION_DECL: |
| case OVERLOAD: |
| case CONST_DECL: |
| case TEMPLATE_DECL: |
| pp_cxx_id_expression (pp, t); |
| break; |
| |
| case RESULT_DECL: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| pp_cxx_unqualified_id (pp, t); |
| break; |
| |
| default: |
| pp_c_primary_expression (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| /* postfix-expression: |
| primary-expression |
| postfix-expression [ expression ] |
| postfix-expression ( expression-list(opt) ) |
| simple-type-specifier ( expression-list(opt) ) |
| typename ::(opt) nested-name-specifier identifier ( expression-list(opt) ) |
| typename ::(opt) nested-name-specifier template(opt) |
| template-id ( expression-list(opt) ) |
| postfix-expression . template(opt) ::(opt) id-expression |
| postfix-expression -> template(opt) ::(opt) id-expression |
| postfix-expression . pseudo-destructor-name |
| postfix-expression -> pseudo-destructor-name |
| postfix-expression ++ |
| postfix-expression -- |
| dynamic_cast < type-id > ( expression ) |
| static_cast < type-id > ( expression ) |
| reinterpret_cast < type-id > ( expression ) |
| const_cast < type-id > ( expression ) |
| typeid ( expression ) |
| typeif ( type-id ) */ |
| |
| static void |
| pp_cxx_postfix_expression (cxx_pretty_printer *pp, tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| |
| switch (code) |
| { |
| case AGGR_INIT_EXPR: |
| case CALL_EXPR: |
| { |
| tree fun = TREE_OPERAND (t, 0); |
| tree args = TREE_OPERAND (t, 1); |
| tree saved_scope = pp->enclosing_scope; |
| |
| if (TREE_CODE (fun) == ADDR_EXPR) |
| fun = TREE_OPERAND (fun, 0); |
| |
| /* In templates, where there is no way to tell whether a given |
| call uses an actual member function. So the parser builds |
| FUN as a COMPONENT_REF or a plain IDENTIFIER_NODE until |
| instantiation time. */ |
| if (TREE_CODE (fun) != FUNCTION_DECL) |
| ; |
| else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)) |
| { |
| tree object = code == AGGR_INIT_EXPR && AGGR_INIT_VIA_CTOR_P (t) |
| ? TREE_OPERAND (t, 2) |
| : TREE_VALUE (args); |
| |
| while (TREE_CODE (object) == NOP_EXPR) |
| object = TREE_OPERAND (object, 0); |
| |
| if (TREE_CODE (object) == ADDR_EXPR) |
| object = TREE_OPERAND (object, 0); |
| |
| if (TREE_CODE (TREE_TYPE (object)) != POINTER_TYPE) |
| { |
| pp_cxx_postfix_expression (pp, object); |
| pp_cxx_dot (pp); |
| } |
| else |
| { |
| pp_cxx_postfix_expression (pp, object); |
| pp_cxx_arrow (pp); |
| } |
| args = TREE_CHAIN (args); |
| pp->enclosing_scope = strip_pointer_operator (TREE_TYPE (object)); |
| } |
| |
| pp_cxx_postfix_expression (pp, fun); |
| pp->enclosing_scope = saved_scope; |
| pp_cxx_call_argument_list (pp, args); |
| } |
| if (code == AGGR_INIT_EXPR && AGGR_INIT_VIA_CTOR_P (t)) |
| { |
| pp_separate_with (pp, ','); |
| pp_cxx_postfix_expression (pp, TREE_OPERAND (t, 2)); |
| } |
| break; |
| |
| case BASELINK: |
| case VAR_DECL: |
| case PARM_DECL: |
| case FIELD_DECL: |
| case FUNCTION_DECL: |
| case OVERLOAD: |
| case CONST_DECL: |
| case TEMPLATE_DECL: |
| case RESULT_DECL: |
| pp_cxx_primary_expression (pp, t); |
| break; |
| |
| case DYNAMIC_CAST_EXPR: |
| case STATIC_CAST_EXPR: |
| case REINTERPRET_CAST_EXPR: |
| case CONST_CAST_EXPR: |
| if (code == DYNAMIC_CAST_EXPR) |
| pp_identifier (pp, "dynamic_cast"); |
| else if (code == STATIC_CAST_EXPR) |
| pp_identifier (pp, "static_cast"); |
| else if (code == REINTERPRET_CAST_EXPR) |
| pp_identifier (pp, "reinterpret_cast"); |
| else |
| pp_identifier (pp, "const_cast"); |
| pp_cxx_begin_template_argument_list (pp); |
| pp_cxx_type_id (pp, TREE_TYPE (t)); |
| pp_cxx_end_template_argument_list (pp); |
| pp_left_paren (pp); |
| pp_cxx_expression (pp, TREE_OPERAND (t, 0)); |
| pp_right_paren (pp); |
| break; |
| |
| case EMPTY_CLASS_EXPR: |
| pp_cxx_type_id (pp, TREE_TYPE (t)); |
| pp_left_paren (pp); |
| pp_right_paren (pp); |
| break; |
| |
| case TYPEID_EXPR: |
| t = TREE_OPERAND (t, 0); |
| pp_cxx_identifier (pp, "typeid"); |
| pp_left_paren (pp); |
| if (TYPE_P (t)) |
| pp_cxx_type_id (pp, t); |
| else |
| pp_cxx_expression (pp, t); |
| pp_right_paren (pp); |
| break; |
| |
| case PSEUDO_DTOR_EXPR: |
| pp_cxx_postfix_expression (pp, TREE_OPERAND (t, 0)); |
| pp_cxx_dot (pp); |
| pp_cxx_qualified_id (pp, TREE_OPERAND (t, 1)); |
| pp_cxx_colon_colon (pp); |
| pp_complement (pp); |
| pp_cxx_unqualified_id (pp, TREE_OPERAND (t, 2)); |
| break; |
| |
| default: |
| pp_c_postfix_expression (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| /* new-expression: |
| ::(opt) new new-placement(opt) new-type-id new-initializer(opt) |
| ::(opt) new new-placement(opt) ( type-id ) new-initializer(opt) |
| |
| new-placement: |
| ( expression-list ) |
| |
| new-type-id: |
| type-specifier-seq new-declarator(opt) |
| |
| new-declarator: |
| ptr-operator new-declarator(opt) |
| direct-new-declarator |
| |
| direct-new-declarator |
| [ expression ] |
| direct-new-declarator [ constant-expression ] |
| |
| new-initializer: |
| ( expression-list(opt) ) */ |
| static void |
| pp_cxx_new_expression (cxx_pretty_printer *pp, tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| switch (code) |
| { |
| case NEW_EXPR: |
| case VEC_NEW_EXPR: |
| if (NEW_EXPR_USE_GLOBAL (t)) |
| pp_cxx_colon_colon (pp); |
| pp_cxx_identifier (pp, "new"); |
| if (TREE_OPERAND (t, 0)) |
| { |
| pp_cxx_call_argument_list (pp, TREE_OPERAND (t, 0)); |
| pp_space (pp); |
| } |
| /* FIXME: array-types are built with one more element. */ |
| pp_cxx_type_id (pp, TREE_OPERAND (t, 1)); |
| if (TREE_OPERAND (t, 2)) |
| { |
| pp_left_paren (pp); |
| t = TREE_OPERAND (t, 2); |
| if (TREE_CODE (t) == TREE_LIST) |
| pp_c_expression_list (pp_c_base (pp), t); |
| else if (t == void_zero_node) |
| ; /* OK, empty initializer list. */ |
| else |
| pp_cxx_expression (pp, t); |
| pp_right_paren (pp); |
| } |
| break; |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| } |
| } |
| |
| /* delete-expression: |
| ::(opt) delete cast-expression |
| ::(opt) delete [ ] cast-expression */ |
| static void |
| pp_cxx_delete_expression (cxx_pretty_printer *pp, tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| switch (code) |
| { |
| case DELETE_EXPR: |
| case VEC_DELETE_EXPR: |
| if (DELETE_EXPR_USE_GLOBAL (t)) |
| pp_cxx_colon_colon (pp); |
| pp_cxx_identifier (pp, "delete"); |
| if (code == VEC_DELETE_EXPR) |
| { |
| pp_left_bracket (pp); |
| pp_right_bracket (pp); |
| } |
| pp_c_cast_expression (pp_c_base (pp), TREE_OPERAND (t, 0)); |
| break; |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| } |
| } |
| |
| /* unary-expression: |
| postfix-expression |
| ++ cast-expression |
| -- cast-expression |
| unary-operator cast-expression |
| sizeof unary-expression |
| sizeof ( type-id ) |
| new-expression |
| delete-expression |
| |
| unary-operator: one of |
| * & + - ! |
| |
| GNU extensions: |
| __alignof__ unary-expression |
| __alignof__ ( type-id ) */ |
| static void |
| pp_cxx_unary_expression (cxx_pretty_printer *pp, tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| switch (code) |
| { |
| case NEW_EXPR: |
| case VEC_NEW_EXPR: |
| pp_cxx_new_expression (pp, t); |
| break; |
| |
| case DELETE_EXPR: |
| case VEC_DELETE_EXPR: |
| pp_cxx_delete_expression (pp, t); |
| break; |
| |
| default: |
| pp_c_unary_expression (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| /* cast-expression: |
| unary-expression |
| ( type-id ) cast-expression */ |
| static void |
| pp_cxx_cast_expression (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case CAST_EXPR: |
| pp_cxx_type_id (pp, TREE_TYPE (t)); |
| pp_cxx_call_argument_list (pp, TREE_OPERAND (t, 0)); |
| break; |
| |
| default: |
| pp_c_cast_expression (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| /* pm-expression: |
| cast-expression |
| pm-expression .* cast-expression |
| pm-expression ->* cast-expression */ |
| static void |
| pp_cxx_pm_expression (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| /* Handle unfortunate OFFESET_REF overloading here. */ |
| case OFFSET_REF: |
| if (TYPE_P (TREE_OPERAND (t, 0))) |
| { |
| pp_cxx_qualified_id (pp, t); |
| break; |
| } |
| /* Else fall through. */ |
| case MEMBER_REF: |
| case DOTSTAR_EXPR: |
| pp_cxx_pm_expression (pp, TREE_OPERAND (t, 0)); |
| pp_cxx_dot (pp); |
| pp_star(pp); |
| pp_cxx_cast_expression (pp, TREE_OPERAND (t, 1)); |
| break; |
| |
| |
| default: |
| pp_cxx_cast_expression (pp, t); |
| break; |
| } |
| } |
| |
| /* multiplicative-expression: |
| pm-expression |
| multiplicative-expression * pm-expression |
| multiplicative-expression / pm-expression |
| multiplicative-expression % pm-expression */ |
| static void |
| pp_cxx_multiplicative_expression (cxx_pretty_printer *pp, tree e) |
| { |
| enum tree_code code = TREE_CODE (e); |
| switch (code) |
| { |
| case MULT_EXPR: |
| case TRUNC_DIV_EXPR: |
| case TRUNC_MOD_EXPR: |
| pp_cxx_multiplicative_expression (pp, TREE_OPERAND (e, 0)); |
| pp_space (pp); |
| if (code == MULT_EXPR) |
| pp_star (pp); |
| else if (code == TRUNC_DIV_EXPR) |
| pp_slash (pp); |
| else |
| pp_modulo (pp); |
| pp_space (pp); |
| pp_cxx_pm_expression (pp, TREE_OPERAND (e, 1)); |
| break; |
| |
| default: |
| pp_cxx_pm_expression (pp, e); |
| break; |
| } |
| } |
| |
| /* conditional-expression: |
| logical-or-expression |
| logical-or-expression ? expression : assignment-expression */ |
| static void |
| pp_cxx_conditional_expression (cxx_pretty_printer *pp, tree e) |
| { |
| if (TREE_CODE (e) == COND_EXPR) |
| { |
| pp_c_logical_or_expression (pp_c_base (pp), TREE_OPERAND (e, 0)); |
| pp_space (pp); |
| pp_question (pp); |
| pp_space (pp); |
| pp_cxx_expression (pp, TREE_OPERAND (e, 1)); |
| pp_space (pp); |
| pp_cxx_assignment_expression (pp, TREE_OPERAND (e, 2)); |
| } |
| else |
| pp_c_logical_or_expression (pp_c_base (pp), e); |
| } |
| |
| static void |
| pp_cxx_assignment_operator (cxx_pretty_printer *pp, tree t) |
| { |
| const char *op; |
| |
| switch (TREE_CODE (t)) |
| { |
| case NOP_EXPR: |
| op = "="; |
| break; |
| |
| case PLUS_EXPR: |
| op = "+="; |
| break; |
| |
| case MINUS_EXPR: |
| op = "-="; |
| break; |
| |
| case TRUNC_DIV_EXPR: |
| op = "/="; |
| break; |
| |
| case TRUNC_MOD_EXPR: |
| op = "%="; |
| break; |
| |
| default: |
| op = tree_code_name[TREE_CODE (t)]; |
| break; |
| } |
| |
| pp_cxx_identifier (pp, op); |
| } |
| |
| |
| /* assignment-expression: |
| conditional-expression |
| logical-or-expression assignment-operator assignment-expression |
| throw-expression |
| |
| throw-expression: |
| throw assignment-expression(opt) |
| |
| assignment-operator: one of |
| = *= /= %= += -= >>= <<= &= ^= |= */ |
| static void |
| pp_cxx_assignment_expression (cxx_pretty_printer *pp, tree e) |
| { |
| switch (TREE_CODE (e)) |
| { |
| case MODIFY_EXPR: |
| case INIT_EXPR: |
| pp_c_logical_or_expression (pp_c_base (pp), TREE_OPERAND (e, 0)); |
| pp_space (pp); |
| pp_equal (pp); |
| pp_space (pp); |
| pp_cxx_assignment_expression (pp, TREE_OPERAND (e, 1)); |
| break; |
| |
| case THROW_EXPR: |
| pp_cxx_identifier (pp, "throw"); |
| if (TREE_OPERAND (e, 0)) |
| pp_cxx_assignment_expression (pp, TREE_OPERAND (e, 0)); |
| break; |
| |
| case MODOP_EXPR: |
| pp_c_logical_or_expression (pp_c_base (pp), TREE_OPERAND (e, 0)); |
| pp_cxx_assignment_operator (pp, TREE_OPERAND (e, 1)); |
| pp_cxx_assignment_expression (pp, TREE_OPERAND (e, 2)); |
| break; |
| |
| default: |
| pp_cxx_conditional_expression (pp, e); |
| break; |
| } |
| } |
| |
| static void |
| pp_cxx_expression (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case STRING_CST: |
| case INTEGER_CST: |
| case REAL_CST: |
| pp_c_constant (pp_c_base (pp), t); |
| break; |
| |
| case RESULT_DECL: |
| pp_cxx_unqualified_id (pp, t); |
| break; |
| |
| #if 0 |
| case OFFSET_REF: |
| #endif |
| case SCOPE_REF: |
| case PTRMEM_CST: |
| pp_cxx_qualified_id (pp, t); |
| break; |
| |
| case OVERLOAD: |
| t = OVL_CURRENT (t); |
| case VAR_DECL: |
| case PARM_DECL: |
| case FIELD_DECL: |
| case CONST_DECL: |
| case FUNCTION_DECL: |
| case BASELINK: |
| case TEMPLATE_DECL: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| pp_cxx_primary_expression (pp, t); |
| break; |
| |
| case CALL_EXPR: |
| case DYNAMIC_CAST_EXPR: |
| case STATIC_CAST_EXPR: |
| case REINTERPRET_CAST_EXPR: |
| case CONST_CAST_EXPR: |
| #if 0 |
| case MEMBER_REF: |
| #endif |
| case EMPTY_CLASS_EXPR: |
| case TYPEID_EXPR: |
| case PSEUDO_DTOR_EXPR: |
| case AGGR_INIT_EXPR: |
| pp_cxx_postfix_expression (pp, t); |
| break; |
| |
| case NEW_EXPR: |
| case VEC_NEW_EXPR: |
| pp_cxx_new_expression (pp, t); |
| break; |
| |
| case DELETE_EXPR: |
| case VEC_DELETE_EXPR: |
| pp_cxx_delete_expression (pp, t); |
| break; |
| |
| case CAST_EXPR: |
| pp_cxx_cast_expression (pp, t); |
| break; |
| |
| case OFFSET_REF: |
| case MEMBER_REF: |
| case DOTSTAR_EXPR: |
| pp_cxx_pm_expression (pp, t); |
| break; |
| |
| case MULT_EXPR: |
| case TRUNC_DIV_EXPR: |
| case TRUNC_MOD_EXPR: |
| pp_cxx_multiplicative_expression (pp, t); |
| break; |
| |
| case COND_EXPR: |
| pp_cxx_conditional_expression (pp, t); |
| break; |
| |
| case MODIFY_EXPR: |
| case INIT_EXPR: |
| case THROW_EXPR: |
| case MODOP_EXPR: |
| pp_cxx_assignment_expression (pp, t); |
| break; |
| |
| default: |
| pp_c_expression (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| |
| /* Declarations. */ |
| |
| /* function-specifier: |
| inline |
| virtual |
| explicit */ |
| static void |
| pp_cxx_function_specifier (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case FUNCTION_DECL: |
| if (DECL_VIRTUAL_P (t)) |
| pp_cxx_identifier (pp, "virtual"); |
| else if (DECL_CONSTRUCTOR_P (t) && DECL_NONCONVERTING_P (t)) |
| pp_cxx_identifier (pp, "explicit"); |
| else |
| pp_c_function_specifier (pp_c_base (pp), t); |
| |
| default: |
| break; |
| } |
| } |
| |
| /* decl-specifier-seq: |
| decl-specifier-seq(opt) decl-specifier |
| |
| decl-specifier: |
| storage-class-specifier |
| type-specifier |
| function-specifier |
| friend |
| typedef */ |
| static void |
| pp_cxx_decl_specifier_seq (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case VAR_DECL: |
| case PARM_DECL: |
| case CONST_DECL: |
| case FIELD_DECL: |
| pp_cxx_storage_class_specifier (pp, t); |
| pp_cxx_decl_specifier_seq (pp, TREE_TYPE (t)); |
| break; |
| |
| case TYPE_DECL: |
| pp_cxx_identifier (pp, "typedef"); |
| pp_cxx_decl_specifier_seq (pp, TREE_TYPE (t)); |
| break; |
| |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (t)) |
| { |
| tree pfm = TYPE_PTRMEMFUNC_FN_TYPE (t); |
| pp_cxx_decl_specifier_seq (pp, TREE_TYPE (TREE_TYPE (pfm))); |
| pp_cxx_whitespace (pp); |
| pp_cxx_ptr_operator (pp, t); |
| } |
| break; |
| |
| case FUNCTION_DECL: |
| /* Constructors don't have return types. And conversion functions |
| do not have a type-specifier in their return types. */ |
| if (DECL_CONSTRUCTOR_P (t) || DECL_CONV_FN_P (t)) |
| pp_cxx_function_specifier (pp, t); |
| else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t)) |
| pp_cxx_decl_specifier_seq (pp, TREE_TYPE (TREE_TYPE (t))); |
| else |
| default: |
| pp_c_declaration_specifiers (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| /* simple-type-specifier: |
| ::(opt) nested-name-specifier(opt) type-name |
| ::(opt) nested-name-specifier(opt) template(opt) template-id |
| char |
| wchar_t |
| bool |
| short |
| int |
| long |
| signed |
| unsigned |
| float |
| double |
| void */ |
| static void |
| pp_cxx_simple_type_specifier (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case RECORD_TYPE: |
| case UNION_TYPE: |
| case ENUMERAL_TYPE: |
| pp_cxx_qualified_id (pp, t); |
| break; |
| |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| pp_cxx_unqualified_id (pp, t); |
| break; |
| |
| case TYPENAME_TYPE: |
| pp_cxx_identifier (pp, "typename"); |
| pp_cxx_nested_name_specifier (pp, TYPE_CONTEXT (t)); |
| pp_cxx_unqualified_id (pp, TYPE_NAME (t)); |
| break; |
| |
| default: |
| pp_c_type_specifier (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| /* type-specifier-seq: |
| type-specifier type-specifier-seq(opt) |
| |
| type-specifier: |
| simple-type-specifier |
| class-specifier |
| enum-specifier |
| elaborated-type-specifier |
| cv-qualifier */ |
| |
| static void |
| pp_cxx_type_specifier_seq (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case TEMPLATE_DECL: |
| case TEMPLATE_TYPE_PARM: |
| case TYPE_DECL: |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| pp_c_type_qualifier_list (pp_c_base (pp), t); |
| pp_cxx_simple_type_specifier (pp, t); |
| break; |
| |
| case METHOD_TYPE: |
| pp_cxx_type_specifier_seq (pp, TREE_TYPE (t)); |
| pp_cxx_space_for_pointer_operator (pp, TREE_TYPE (t)); |
| pp_cxx_nested_name_specifier (pp, TYPE_METHOD_BASETYPE (t)); |
| break; |
| |
| default: |
| if (!(TREE_CODE (t) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (t))) |
| pp_c_specifier_qualifier_list (pp_c_base (pp), t); |
| } |
| } |
| |
| /* ptr-operator: |
| * cv-qualifier-seq(opt) |
| & |
| ::(opt) nested-name-specifier * cv-qualifier-seq(opt) */ |
| |
| static void |
| pp_cxx_ptr_operator (cxx_pretty_printer *pp, tree t) |
| { |
| if (!TYPE_P (t) && TREE_CODE (t) != TYPE_DECL) |
| t = TREE_TYPE (t); |
| switch (TREE_CODE (t)) |
| { |
| case REFERENCE_TYPE: |
| case POINTER_TYPE: |
| if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE |
| || TYPE_PTR_TO_MEMBER_P (TREE_TYPE (t))) |
| pp_cxx_ptr_operator (pp, TREE_TYPE (t)); |
| if (TREE_CODE (t) == POINTER_TYPE) |
| { |
| pp_star (pp); |
| pp_cxx_cv_qualifier_seq (pp, t); |
| } |
| else |
| pp_ampersand (pp); |
| break; |
| |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (t)) |
| { |
| pp_cxx_left_paren (pp); |
| pp_cxx_nested_name_specifier (pp, TYPE_PTRMEMFUNC_OBJECT_TYPE (t)); |
| pp_star (pp); |
| break; |
| } |
| case OFFSET_TYPE: |
| if (TYPE_PTR_TO_MEMBER_P (t)) |
| { |
| pp_cxx_nested_name_specifier (pp, TYPE_PTRMEM_CLASS_TYPE (t)); |
| pp_star (pp); |
| pp_cxx_cv_qualifier_seq (pp, t); |
| break; |
| } |
| /* else fall through. */ |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| break; |
| } |
| } |
| |
| static inline tree |
| pp_cxx_implicit_parameter_type (tree mf) |
| { |
| return TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (mf)))); |
| } |
| |
| /* |
| parameter-declaration: |
| decl-specifier-seq declarator |
| decl-specifier-seq declarator = assignment-expression |
| decl-specifier-seq abstract-declarator(opt) |
| decl-specifier-seq abstract-declarator(opt) assignment-expression */ |
| static inline void |
| pp_cxx_parameter_declaration (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_decl_specifier_seq (pp, t); |
| if (TYPE_P (t)) |
| pp_cxx_abstract_declarator (pp, t); |
| else |
| pp_cxx_declarator (pp, t); |
| } |
| |
| /* parameter-declaration-clause: |
| parameter-declaration-list(opt) ...(opt) |
| parameter-declaration-list , ... |
| |
| parameter-declaration-list: |
| parameter-declaration |
| parameter-declaration-list , parameter-declaration */ |
| static void |
| pp_cxx_parameter_declaration_clause (cxx_pretty_printer *pp, tree t) |
| { |
| tree args = TYPE_P (t) ? NULL : FUNCTION_FIRST_USER_PARM (t); |
| tree types = TYPE_P (t) ? TYPE_ARG_TYPES (t) : FUNCTION_FIRST_USER_PARMTYPE (t); |
| const bool abstract = args == NULL |
| || pp_c_base (pp)->flags & pp_c_flag_abstract; |
| bool first = true; |
| |
| /* Skip artificial parameter for nonstatic member functions. */ |
| if (TREE_CODE (t) == METHOD_TYPE) |
| types = TREE_CHAIN (types); |
| |
| pp_cxx_left_paren (pp); |
| for (; args; args = TREE_CHAIN (args), types = TREE_CHAIN (types)) |
| { |
| if (!first) |
| pp_separate_with (pp, ','); |
| first = false; |
| pp_cxx_parameter_declaration (pp, abstract ? TREE_VALUE (types) : args); |
| if (!abstract && pp_c_base (pp)->flags & pp_cxx_flag_default_argument) |
| { |
| pp_cxx_whitespace (pp); |
| pp_equal (pp); |
| pp_cxx_whitespace (pp); |
| pp_cxx_assignment_expression (pp, TREE_PURPOSE (types)); |
| } |
| } |
| pp_cxx_right_paren (pp); |
| } |
| |
| /* exception-specification: |
| throw ( type-id-list(opt) ) |
| |
| type-id-list |
| type-id |
| type-id-list , type-id */ |
| static void |
| pp_cxx_exception_specification (cxx_pretty_printer *pp, tree t) |
| { |
| tree ex_spec = TYPE_RAISES_EXCEPTIONS (t); |
| |
| if (!TYPE_NOTHROW_P (t) && ex_spec == NULL) |
| return; |
| pp_cxx_identifier (pp, "throw"); |
| pp_cxx_left_paren (pp); |
| for (; ex_spec && TREE_VALUE (ex_spec); ex_spec = TREE_CHAIN (ex_spec)) |
| { |
| pp_cxx_type_id (pp, TREE_VALUE (ex_spec)); |
| if (TREE_CHAIN (ex_spec)) |
| pp_separate_with (pp, ','); |
| } |
| pp_cxx_right_paren (pp); |
| } |
| |
| /* direct-declarator: |
| declarator-id |
| direct-declarator ( parameter-declaration-clause ) cv-qualifier-seq(opt) |
| exception-specification(opt) |
| direct-declaration [ constant-expression(opt) ] |
| ( declarator ) */ |
| static void |
| pp_cxx_direct_declarator (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case VAR_DECL: |
| case PARM_DECL: |
| case CONST_DECL: |
| case FIELD_DECL: |
| if (DECL_NAME (t)) |
| { |
| pp_cxx_space_for_pointer_operator (pp, TREE_TYPE (t)); |
| pp_cxx_id_expression (pp, DECL_NAME (t)); |
| } |
| pp_cxx_abstract_declarator (pp, TREE_TYPE (t)); |
| break; |
| |
| case FUNCTION_DECL: |
| pp_cxx_space_for_pointer_operator (pp, TREE_TYPE (TREE_TYPE (t))); |
| pp_cxx_id_expression (pp, t); |
| pp_cxx_parameter_declaration_clause (pp, t); |
| |
| if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t)) |
| { |
| pp_base (pp)->padding = pp_before; |
| pp_cxx_cv_qualifier_seq (pp, pp_cxx_implicit_parameter_type (t)); |
| } |
| |
| pp_cxx_exception_specification (pp, TREE_TYPE (t)); |
| break; |
| |
| case TYPENAME_TYPE: |
| case TEMPLATE_DECL: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| break; |
| |
| default: |
| pp_c_direct_declarator (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| /* declarator: |
| direct-declarator |
| ptr-operator declarator */ |
| static void |
| pp_cxx_declarator (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_direct_declarator (pp, t); |
| } |
| |
| /* ctor-initializer: |
| : mem-initializer-list |
| |
| mem-initializer-list: |
| mem-initializer |
| mem-initializer , mem-initializer-list |
| |
| mem-initializer: |
| mem-initializer-id ( expression-list(opt) ) |
| |
| mem-initializer-id: |
| ::(opt) nested-name-specifier(opt) class-name |
| identifier */ |
| static void |
| pp_cxx_ctor_initializer (cxx_pretty_printer *pp, tree t) |
| { |
| t = TREE_OPERAND (t, 0); |
| pp_cxx_whitespace (pp); |
| pp_colon (pp); |
| pp_cxx_whitespace (pp); |
| for (; t; t = TREE_CHAIN (t)) |
| { |
| pp_cxx_primary_expression (pp, TREE_PURPOSE (t)); |
| pp_cxx_call_argument_list (pp, TREE_VALUE (t)); |
| if (TREE_CHAIN (t)) |
| pp_separate_with (pp, ','); |
| } |
| } |
| |
| /* function-definition: |
| decl-specifier-seq(opt) declarator ctor-initializer(opt) function-body |
| decl-specifier-seq(opt) declarator function-try-block */ |
| |
| void |
| pp_cxx_function_definition (cxx_pretty_printer *pp, tree t) |
| { |
| tree saved_scope = pp->enclosing_scope; |
| pp_cxx_decl_specifier_seq (pp, t); |
| pp_cxx_declarator (pp, t); |
| pp_needs_newline (pp) = true; |
| pp->enclosing_scope = DECL_CONTEXT (t); |
| if (DECL_SAVED_TREE (t)) |
| { |
| tree body = DECL_SAVED_TREE (t); |
| if (TREE_CODE (body) == COMPOUND_STMT |
| && TREE_CODE (COMPOUND_BODY (body)) == CTOR_INITIALIZER) |
| { |
| body = COMPOUND_BODY (body); |
| pp_cxx_ctor_initializer (pp, body); |
| body = TREE_CHAIN (body); |
| } |
| pp_cxx_statement (pp, body); |
| } |
| else |
| { |
| pp_cxx_semicolon (pp); |
| pp_needs_newline (pp) = true; |
| } |
| pp_flush (pp); |
| pp->enclosing_scope = saved_scope; |
| } |
| |
| /* abstract-declarator: |
| ptr-operator abstract-declarator(opt) |
| direct-abstract-declarator */ |
| static void |
| pp_cxx_abstract_declarator (cxx_pretty_printer *pp, tree t) |
| { |
| if (TYPE_PTRMEM_P (t) || TYPE_PTRMEMFUNC_P (t)) |
| pp_cxx_right_paren (pp); |
| else if (POINTER_TYPE_P (t)) |
| { |
| if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE |
| || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) |
| pp_cxx_right_paren (pp); |
| t = TREE_TYPE (t); |
| } |
| pp_cxx_direct_abstract_declarator (pp, t); |
| } |
| |
| /* direct-abstract-declarator: |
| direct-abstract-declarator(opt) ( parameter-declaration-clause ) |
| cv-qualifier-seq(opt) exception-specification(opt) |
| direct-abstract-declarator(opt) [ constant-expression(opt) ] |
| ( abstract-declarator ) */ |
| static void |
| pp_cxx_direct_abstract_declarator (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case REFERENCE_TYPE: |
| pp_cxx_abstract_declarator (pp, t); |
| break; |
| |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (t)) |
| pp_cxx_direct_abstract_declarator (pp, TYPE_PTRMEMFUNC_FN_TYPE (t)); |
| break; |
| |
| case METHOD_TYPE: |
| case FUNCTION_TYPE: |
| pp_cxx_parameter_declaration_clause (pp, t); |
| pp_cxx_direct_abstract_declarator (pp, TREE_TYPE (t)); |
| if (TREE_CODE (t) == METHOD_TYPE) |
| { |
| pp_base (pp)->padding = pp_before; |
| pp_cxx_cv_qualifier_seq |
| (pp, TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t)))); |
| } |
| pp_cxx_exception_specification (pp, t); |
| break; |
| |
| case TYPENAME_TYPE: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_TEMPLATE_PARM: |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| case UNBOUND_CLASS_TEMPLATE: |
| break; |
| |
| default: |
| pp_c_direct_abstract_declarator (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| /* type-id: |
| type-specifier-seq abstract-declarator(opt) */ |
| static void |
| pp_cxx_type_id (cxx_pretty_printer *pp, tree t) |
| { |
| pp_flags saved_flags = pp_c_base (pp)->flags; |
| pp_c_base (pp)->flags |= pp_c_flag_abstract; |
| |
| switch (TREE_CODE (t)) |
| { |
| case TYPE_DECL: |
| case UNION_TYPE: |
| case RECORD_TYPE: |
| case ENUMERAL_TYPE: |
| case TYPENAME_TYPE: |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| case UNBOUND_CLASS_TEMPLATE: |
| case TEMPLATE_TEMPLATE_PARM: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| case TEMPLATE_DECL: |
| case TYPEOF_TYPE: |
| case TEMPLATE_ID_EXPR: |
| /* FIXME: Should be pp_cxx_type_specifier_seq. */ |
| pp_cxx_type_specifier_seq (pp, t); |
| pp_cxx_declarator (pp, t); |
| break; |
| |
| default: |
| pp_c_type_id (pp_c_base (pp), t); |
| break; |
| } |
| |
| pp_c_base (pp)->flags = saved_flags; |
| } |
| |
| /* template-argument-list: |
| template-argument |
| template-argument-list, template-argument |
| |
| template-argument: |
| assignment-expression |
| type-id |
| template-name */ |
| static void |
| pp_cxx_template_argument_list (cxx_pretty_printer *pp, tree t) |
| { |
| int i; |
| if (t == NULL) |
| return; |
| for (i = 0; i < TREE_VEC_LENGTH (t); ++i) |
| { |
| tree arg = TREE_VEC_ELT (t, i); |
| if (i != 0) |
| pp_separate_with (pp, ','); |
| if (TYPE_P (arg) || (TREE_CODE (arg) == TEMPLATE_DECL |
| && TYPE_P (DECL_TEMPLATE_RESULT (arg)))) |
| pp_cxx_type_id (pp, arg); |
| else |
| pp_cxx_expression (pp, arg); |
| } |
| } |
| |
| |
| static void |
| pp_cxx_exception_declaration (cxx_pretty_printer *pp, tree t) |
| { |
| t = DECL_STMT_DECL (t); |
| pp_cxx_type_specifier_seq (pp, t); |
| if (TYPE_P (t)) |
| pp_cxx_abstract_declarator (pp, t); |
| else |
| pp_cxx_declarator (pp, t); |
| } |
| |
| /* Statements. */ |
| |
| void |
| pp_cxx_statement (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case USING_STMT: |
| pp_cxx_identifier (pp, "using"); |
| pp_cxx_identifier (pp, "namespace"); |
| pp_cxx_qualified_id (pp, USING_STMT_NAMESPACE (t)); |
| break; |
| |
| case USING_DECL: |
| pp_cxx_identifier (pp, "using"); |
| pp_cxx_nested_name_specifier (pp, DECL_INITIAL (t)); |
| pp_cxx_unqualified_id (pp, DECL_NAME (t)); |
| break; |
| |
| case EH_SPEC_BLOCK: |
| break; |
| |
| /* try-block: |
| try compound-statement handler-seq */ |
| case TRY_BLOCK: |
| pp_maybe_newline_and_indent (pp, 0); |
| pp_cxx_identifier (pp, "try"); |
| pp_newline_and_indent (pp, 3); |
| pp_cxx_statement (pp, TRY_STMTS (t)); |
| pp_newline_and_indent (pp, -3); |
| if (CLEANUP_P (t)) |
| ; |
| else |
| pp_cxx_statement (pp, TRY_HANDLERS (t)); |
| break; |
| |
| /* |
| handler-seq: |
| handler handler-seq(opt) |
| |
| handler: |
| catch ( exception-declaration ) compound-statement |
| |
| exception-declaration: |
| type-specifier-seq declarator |
| type-specifier-seq abstract-declarator |
| ... */ |
| case HANDLER: |
| pp_cxx_identifier (pp, "catch"); |
| pp_cxx_left_paren (pp); |
| pp_cxx_exception_declaration (pp, HANDLER_PARMS (t)); |
| pp_cxx_right_paren (pp); |
| pp_indentation (pp) += 3; |
| pp_needs_newline (pp) = true; |
| pp_cxx_statement (pp, HANDLER_BODY (t)); |
| pp_indentation (pp) -= 3; |
| pp_needs_newline (pp) = true; |
| break; |
| |
| default: |
| pp_c_statement (pp_c_base (pp), t); |
| break; |
| } |
| } |
| |
| /* original-namespace-definition: |
| namespace identifier { namespace-body } |
| |
| As an edge case, we also handle unnamed namespace definition here. */ |
| |
| static void |
| pp_cxx_original_namespace_definition (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_identifier (pp, "namespace"); |
| if (DECL_NAME (t)) |
| pp_cxx_unqualified_id (pp, t); |
| pp_cxx_whitespace (pp); |
| pp_cxx_left_brace (pp); |
| /* We do not print the namespace-body. */ |
| pp_cxx_whitespace (pp); |
| pp_cxx_right_brace (pp); |
| } |
| |
| /* namespace-alias: |
| identifier |
| |
| namespace-alias-definition: |
| namespace identifier = qualified-namespace-specifier ; |
| |
| qualified-namespace-specifier: |
| ::(opt) nested-name-specifier(opt) namespace-name */ |
| |
| static void |
| pp_cxx_namespace_alias_definition (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_identifier (pp, "namespace"); |
| pp_cxx_unqualified_id (pp, t); |
| pp_cxx_whitespace (pp); |
| pp_equal (pp); |
| pp_cxx_whitespace (pp); |
| pp_cxx_qualified_id (pp, DECL_NAMESPACE_ALIAS (t)); |
| pp_cxx_semicolon (pp); |
| } |
| |
| /* simple-declaration: |
| decl-specifier-seq(opt) init-declarator-list(opt) */ |
| static void |
| pp_cxx_simple_declaration (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_decl_specifier_seq (pp, t); |
| pp_cxx_init_declarator (pp, t); |
| pp_cxx_semicolon (pp); |
| pp_needs_newline (pp) = true; |
| } |
| |
| /* |
| template-parameter-list: |
| template-parameter |
| template-parameter-list , template-parameter */ |
| |
| static inline void |
| pp_cxx_template_parameter_list (cxx_pretty_printer *pp, tree t) |
| { |
| const int n = TREE_VEC_LENGTH (t); |
| int i; |
| for (i = 0; i < n; ++i) |
| { |
| if (i) |
| pp_separate_with (pp, ','); |
| pp_cxx_template_parameter (pp, TREE_VEC_ELT (t, i)); |
| } |
| } |
| |
| /* template-parameter: |
| type-parameter |
| parameter-declaration |
| |
| type-parameter: |
| class identifier(opt) |
| class identifier(op) = type-id |
| typename identifier(opt) |
| typename identifier(opt) = type-id |
| template < template-parameter-list > class identifier(opt) |
| template < template-parameter-list > class identifier(opt) = template-name |
| */ |
| static void |
| pp_cxx_template_parameter (cxx_pretty_printer *pp, tree t) |
| { |
| tree parameter = TREE_VALUE (t); |
| switch (TREE_CODE (parameter)) |
| { |
| case TYPE_DECL: |
| pp_cxx_identifier (pp, "class"); |
| if (DECL_NAME (parameter)) |
| pp_cxx_tree_identifier (pp, DECL_NAME (parameter)); |
| /* FIXME: Chech if we should print also default argument. */ |
| break; |
| |
| case PARM_DECL: |
| pp_cxx_parameter_declaration (pp, parameter); |
| break; |
| |
| case TEMPLATE_DECL: |
| break; |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| break; |
| } |
| } |
| |
| /* Pretty-print a template parameter in the canonical form |
| "template-parameter-<level>-<position in parameter list>". */ |
| |
| void |
| pp_cxx_canonical_template_parameter (cxx_pretty_printer *pp, tree parm) |
| { |
| const enum tree_code code = TREE_CODE (parm); |
| |
| /* Brings type template parameters to the canonical forms. */ |
| if (code == TEMPLATE_TYPE_PARM || code == TEMPLATE_TEMPLATE_PARM |
| || code == BOUND_TEMPLATE_TEMPLATE_PARM) |
| parm = TEMPLATE_TYPE_PARM_INDEX (parm); |
| |
| pp_cxx_begin_template_argument_list (pp); |
| pp_cxx_identifier (pp, "template-parameter-"); |
| pp_wide_integer (pp, TEMPLATE_PARM_LEVEL (parm)); |
| pp_minus (pp); |
| pp_wide_integer (pp, TEMPLATE_PARM_IDX (parm) + 1); |
| pp_cxx_end_template_argument_list (pp); |
| } |
| |
| /* |
| template-declaration: |
| export(opt) template < template-parameter-list > declaration */ |
| static void |
| pp_cxx_template_declaration (cxx_pretty_printer *pp, tree t) |
| { |
| tree tmpl = most_general_template (t); |
| tree level; |
| int i = 0; |
| |
| pp_maybe_newline_and_indent (pp, 0); |
| for (level = DECL_TEMPLATE_PARMS (tmpl); level; level = TREE_CHAIN (level)) |
| { |
| pp_cxx_identifier (pp, "template"); |
| pp_cxx_begin_template_argument_list (pp); |
| pp_cxx_template_parameter_list (pp, TREE_VALUE (level)); |
| pp_cxx_end_template_argument_list (pp); |
| pp_newline_and_indent (pp, 3); |
| i += 3; |
| } |
| if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_TREE (t)) |
| pp_cxx_function_definition (pp, t); |
| else |
| pp_cxx_simple_declaration (pp, t); |
| } |
| |
| static void |
| pp_cxx_explicit_specialization (cxx_pretty_printer *pp, tree t) |
| { |
| pp_unsupported_tree (pp, t); |
| } |
| |
| static void |
| pp_cxx_explicit_instantiation (cxx_pretty_printer *pp, tree t) |
| { |
| pp_unsupported_tree (pp, t); |
| } |
| |
| /* |
| declaration: |
| block-declaration |
| function-definition |
| template-declaration |
| explicit-instantiation |
| explicit-specialization |
| linkage-specification |
| namespace-definition |
| |
| block-declaration: |
| simple-declaration |
| asm-definition |
| namespace-alias-definition |
| using-declaration |
| using-directive */ |
| void |
| pp_cxx_declaration (cxx_pretty_printer *pp, tree t) |
| { |
| if (!DECL_LANG_SPECIFIC (t)) |
| pp_cxx_simple_declaration (pp, t); |
| else if (DECL_USE_TEMPLATE (t)) |
| switch (DECL_USE_TEMPLATE (t)) |
| { |
| case 1: |
| pp_cxx_template_declaration (pp, t); |
| break; |
| |
| case 2: |
| pp_cxx_explicit_specialization (pp, t); |
| break; |
| |
| case 3: |
| pp_cxx_explicit_instantiation (pp, t); |
| break; |
| |
| default: |
| break; |
| } |
| else switch (TREE_CODE (t)) |
| { |
| case VAR_DECL: |
| case TYPE_DECL: |
| pp_cxx_simple_declaration (pp, t); |
| break; |
| |
| case FUNCTION_DECL: |
| if (DECL_SAVED_TREE (t)) |
| pp_cxx_function_definition (pp, t); |
| else |
| pp_cxx_simple_declaration (pp, t); |
| break; |
| |
| case NAMESPACE_DECL: |
| if (DECL_NAMESPACE_ALIAS (t)) |
| pp_cxx_namespace_alias_definition (pp, t); |
| else |
| pp_cxx_original_namespace_definition (pp, t); |
| break; |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| break; |
| } |
| } |
| |
| |
| typedef c_pretty_print_fn pp_fun; |
| |
| void |
| pp_cxx_pretty_printer_init (cxx_pretty_printer *pp) |
| { |
| pp_c_pretty_printer_init (pp_c_base (pp)); |
| pp_set_line_maximum_length (pp, 0); |
| |
| pp->c_base.declaration = (pp_fun) pp_cxx_declaration; |
| pp->c_base.declaration_specifiers = (pp_fun) pp_cxx_decl_specifier_seq; |
| pp->c_base.function_specifier = (pp_fun) pp_cxx_function_specifier; |
| pp->c_base.type_specifier_seq = (pp_fun) pp_cxx_type_specifier_seq; |
| pp->c_base.declarator = (pp_fun) pp_cxx_declarator; |
| pp->c_base.direct_declarator = (pp_fun) pp_cxx_direct_declarator; |
| pp->c_base.parameter_list = (pp_fun) pp_cxx_parameter_declaration_clause; |
| pp->c_base.type_id = (pp_fun) pp_cxx_type_id; |
| pp->c_base.abstract_declarator = (pp_fun) pp_cxx_abstract_declarator; |
| pp->c_base.direct_abstract_declarator = |
| (pp_fun) pp_cxx_direct_abstract_declarator; |
| pp->c_base.simple_type_specifier = (pp_fun)pp_cxx_simple_type_specifier; |
| |
| /* pp->c_base.statement = (pp_fun) pp_cxx_statement; */ |
| |
| pp->c_base.id_expression = (pp_fun) pp_cxx_id_expression; |
| pp->c_base.primary_expression = (pp_fun) pp_cxx_primary_expression; |
| pp->c_base.postfix_expression = (pp_fun) pp_cxx_postfix_expression; |
| pp->c_base.unary_expression = (pp_fun) pp_cxx_unary_expression; |
| pp->c_base.multiplicative_expression = (pp_fun) pp_cxx_multiplicative_expression; |
| pp->c_base.conditional_expression = (pp_fun) pp_cxx_conditional_expression; |
| pp->c_base.assignment_expression = (pp_fun) pp_cxx_assignment_expression; |
| pp->c_base.expression = (pp_fun) pp_cxx_expression; |
| pp->enclosing_scope = global_namespace; |
| } |