# # Copyright (C) 2006-2022 Matthias Koefferlein # # This program 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 of the License, or # (at your option) any later version. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # require "cpp_classes.rb" require "cpp_parser_classes.rb" grammar CPP rule s [ \t\n\r]* end rule sp [ \t\n\r]+ end rule string_const '"' ( [^\\"] / "\\" . )* '"' end rule char_const "'" ( [^\\'] / "\\" . )* "'" end rule numeric_const "-"? ( [0-9]+ ( "." [0-9]* )? / "." [0-9]+ ) ( [eE] "-"? [0-9]+ )? end rule hex_const "0x" [0-9a-fA-F]+ end rule attribute_value "(" ( s ( "," s )? attribute_value )* s ")" / numeric_const / string_const / id end rule a s ( "__attribute__" s attribute_value s / "__asm" s attribute_value s / "__extension__" s / "decltype" s attribute_value s )* end rule unary_op "~" / "!" / "-" / "*" / "&" end rule bin_op_wo_gt "+=" / "++" / "+" / "->" / "-=" / "--" / "-" / "()" / "[]" / "&&" / "&=" / "&" / "||" / "|=" / "|" / "==" / "=" / "!=" / "*=" / "*" / "/=" / "/" / "%=" / "%" / "<=" / "<<=" / "<<" / "<" / "~=" / "^=" / "^" / "~=" / ">=" / ">>=" end rule bin_op bin_op_wo_gt / ">>" / ">" end rule id "operator" s "," / "operator" s ( bin_op / unary_op / "," ) / "operator" sp [a-zA-Z\*\& \t\n\r]+ &( s "(" ) / "~"? [a-zA-Z_] [a-zA-Z_0-9]* end rule template_arg_part_any block_wo_gt end rule template_arg_part qualified_id &( ( s ">" / "," ) ) / template_arg_part_any end rule template_args template_arg_part ( s "," s template_arg_part )* end rule id_with_template_args id:id taspec:( s "<" s ta:template_args s ">" )? end rule qualified_id globalspec:( "::" s )? id_with_template_args ( s "::" id_with_template_args )* end rule int_type_attr "signed" ![a-zA-Z0-9_] / "unsigned" ![a-zA-Z0-9_] / "long" ( sp "long" )? ![a-zA-Z0-9_] / "short" ![a-zA-Z0-9_] end rule int_type ( ( int_type_attr s )* "int" ![a-zA-Z0-9_] / int_type_attr ( s int_type_attr )* !"char" ( s "int" ![a-zA-Z0-9_] )? ) end rule char_type ( "signed" sp / "unsigned" sp )? s !"int" "char" ![a-zA-Z0-9_] end rule bool_type "bool" ![a-zA-Z0-9_] end rule void_type "void" ![a-zA-Z0-9_] end rule float_type ( "long" sp )? ( "double" / "float" ) ![a-zA-Z0-9_] end rule enum_spec id:id initspec:( s "=" s init:block_wo_comma )? end rule enum_body enum_spec ( s "," s enum_spec )* end rule enum_type "enum" ![a-zA-Z0-9_] a s id:id? bodyspec:( s "{" s body:enum_body s "}" )? end rule virtual_spec "virtual" ![a-zA-Z0-9_] end rule explicit_key "explicit" ![a-zA-Z0-9_] end rule mutable_key "mutable" ![a-zA-Z0-9_] end rule member_declaration_wo_semicolon template:( d:template_decl s )? attr:( ( explicit_key / mutable_key / storage_class / inline_spec / virtual_spec / constexpr_key ) s )* t:type # type declaration ends with a } .. does not need a semicolon # (i.e. nested struct or enum) &{ |seq| seq[-1].text_value_ends_with_curly_brace } s ( ":" s block_wo_curly_braces s )? a ( "{" s block s "}" / ";"? ) end rule member_declaration_w_semicolon template:( d:template_decl s )? attr:( ( explicit_key / mutable_key / storage_class / inline_spec / virtual_spec / constexpr_key ) s )* t:type # opposite case (member_see declaration_wo_semicolon) # (i.e. nested struct or enum) !{ |seq| seq[-1].text_value_ends_with_curly_brace } s ( ":" s block_wo_curly_braces s )? a ( "{" s block s "}" / ";" ) end rule member_declaration a ( member_declaration_wo_semicolon / member_declaration_w_semicolon ) end rule friend_decl a template:( d:template_decl s )? "friend" ![a-zA-Z0-9_] s t:member_declaration end rule class_struct_body_declarations ( s ";" / s friend_decl / s using / s typedef / s !( "public" / "private" / "protected" ) member_declaration )* end rule class_struct_body class_struct_body_declarations ( s "public" s ":" d:class_struct_body_declarations / s "private" s ":" d:class_struct_body_declarations / s "protected" s ":" d:class_struct_body_declarations )* end rule class_id # In order to easily distinguish between constructor methods without # a return type and class or typedef names we assume that all "name(" # constructs are considered constructor names but "name (*func_ptr) ()" is not. qualified_id s !( "(" !( s "*" ) ) end rule typeof "__typeof" s "(" s qid:qualified_id s ")" end rule base_class attr:( "public" ![a-zA-Z0-9_] s / "private" ![a-zA-Z0-9_] s / "protected" ![a-zA-Z0-9_] s / "virtual" ![a-zA-Z0-9_] s )* a cid:class_id end rule base_classes base_class ( s "," s base_classes )? end rule class_or_struct_type stype:( "union" ![a-zA-Z0-9_] / "struct" ![a-zA-Z0-9_] / "class" ![a-zA-Z0-9_] ) a idspec:( s id:class_id )? bcspec:( s ":" s bc:base_classes )? bodyspec:( s "{" s body:class_struct_body s "}" )? end rule concrete_type ( constexpr_key / class_or_struct_type / enum_type / float_type / char_type / int_type / bool_type / void_type / typeof / class_id )? end rule cv ( constexpr_key / "const" ![a-zA-Z0-9_] / "__const" ![a-zA-Z0-9_] / "volatile" ![a-zA-Z0-9_] / "__volatile" ![a-zA-Z0-9_] ) end rule pointer cvspec:( cv:cv s )? "*" itspec:( s it:inner_type )? end rule reference cvspec:( cv:cv s )? "&" itspec:( s it:inner_type )? end rule array_spec "[" s block_wo_comma s "]" end rule func_arg_part t:type_wo_comma !"..." end rule ellipsis "..." end rule func_args &")" / func_arg_part ( s "," s func_arg_part )* ( s "," s ellipsis )? / ellipsis end rule noexcept_spec "noexcept" ( s "=" s block / s "(" s block ")" )? end rule func_spec "(" s fa:( a:func_args )? s ")" cvspec:( s cv:cv )? ( s "throw" s "(" s ( type_wo_comma s )? ")" / s noexcept_spec )* ( s override_key )? a end rule member_pointer cspec:( qid:qualified_id s "::*" s ) itspec:( it:inner_type )? cvspec:( s cv:cv )? end rule inner_type_with_cv cvspec:cv s it:inner_type end rule inner_type it:( "(" s inner_type s ")" / inner_type_with_cv / pointer / reference / member_pointer / ( "__restrict" ![a-zA-Z0-9_] s )? qualified_id ) pfx:( s spec:( array_spec / func_spec ) )* end rule type cvspec:( cv:cv s )? a ( "typename" ![a-zA-Z0-9_] s )? ct:concrete_type a il:( s t1:inner_type i1:(s "=" s is1:block_wo_comma)? tt:( s "," s t2:inner_type i2:(s "=" s is2:block_wo_comma)? )* )? # alternative initialization if only a concrete type is given: pi:( s "=" s is:block_wo_comma )? end rule type_wo_comma cvspec:( cv:cv s )? a ( "typename" ![a-zA-Z0-9_] s )? ct:concrete_type il:( s t:inner_type i:(s "=" s is:block_wo_comma)? )? # alternative initialization if only a concrete type is given: pi:( s "=" s is:block_wo_comma )? end rule type_for_template cvspec:( cv:cv s )? a ( "typename" ![a-zA-Z0-9_] s )? ct:concrete_type il:( s t:inner_type )? end rule storage_class ( "static" ![a-zA-Z0-9_] / "extern" ![a-zA-Z0-9_] ( s '"C"' / s '"C++"' / s '"Pascal"' )? ) end rule override_key "override" ![a-zA-Z0-9_] end rule constexpr_key "constexpr" ![a-zA-Z0-9_] end rule inline_spec "inline" ![a-zA-Z0-9_] end # parse over blocks as gracefully as possible ... rule block_atom_wo_gt "(" s block s ")" / "[" s block s "]" / "<" s block_wo_gt ( s "," s block_wo_gt )* s ">" / numeric_const / hex_const / string_const / char_const / id / unary_op / bin_op_wo_gt / "?" / "::" / "." / ":" / ";" end rule block_wo_gt ( s block_atom_wo_gt / s "{" s block s "}" )* end # parse over blocks as gracefully as possible ... rule block_atom "(" s block s ")" / "[" s block s "]" / "<" s block_wo_gt ( s "," s block_wo_gt )* s ">" / numeric_const / hex_const / string_const / char_const / id / unary_op / bin_op / "?" / "::" / "." / ":" end rule block ( s block_atom / s ";" / s "," / s "{" s block s "}" )* end rule block_wo_curly_braces ( s block_atom / s "," )* end rule block_wo_comma ( s block_atom / s "{" s block s "}" )* end rule using "using" ![a-zA-Z0-9_] ( s "namespace" )? ![a-zA-Z0-9_] s id:qualified_id a ";" end rule static_assert "static_assert" s "(" s block s ")" end rule typedef a "typedef" ![a-zA-Z0-9_] s t:type a ";" end rule template_decl_arg ( "class" / "typename" ) ![a-zA-Z0-9_] s id:id dtspec:( s "=" s dt:type_for_template )? / t:type_for_template initspec:( s "=" s init:block_wo_gt )? end rule template_decl "template" s "<" s ( !">" template_decl_arg s ( "," s template_decl_arg )* )? s ">" end rule declaration_w_semicolon template:( d:template_decl s )? template_member:( d_member:template_decl s )? attr:( ( storage_class / inline_spec / constexpr_key ) s )* a ( constexpr_key s )? t:type # type declaration ends with a } .. does not need a semicolon # (i.e. nested struct or enum) !{ |seq| seq[-1].text_value_ends_with_curly_brace } s ( ":" s block_wo_curly_braces s )? a ( "{" s block s "}" / ";" ) end rule declaration_wo_semicolon template:( d:template_decl s )? attr:( ( storage_class / inline_spec / constexpr_key ) s )* a ( constexpr_key s )? t:type # opposite case (see declaration_wo_semicolon) # (i.e. nested struct or enum) &{ |seq| seq[-1].text_value_ends_with_curly_brace } s ( ":" s block_wo_curly_braces s )? a ( "{" s block s "}" / ";"? ) end rule declaration declaration_w_semicolon / declaration_wo_semicolon end rule namespace "namespace" ![a-zA-Z0-9_] s n:id a "{" decls:( a ( ";" / static_assert / using / typedef / namespace / declaration ) )* s "}" end rule extern_decl "extern" s n:( '"C"' / '"C++"' / '"Pascal"' ) s a "{" decls:( a ( ";" / typedef / namespace / extern_decl / declaration ) )* s "}" end rule module ( a ( ";" / static_assert / using / typedef / namespace / extern_decl / declaration ) )* s end end