blob: 48b9a032e947aa753f1126e61996893731407f9c [file] [log] [blame]
// Hannibal: partial C++ grammar to parse C++ type information
// Copyright (c) 2005-2006 Danny Havenith
//
// Boost.Wave: A Standard compliant C++ preprocessor
// Copyright (c) 2001-2009 Hartmut Kaiser
//
// http://www.boost.org/
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(HANNIBAL_TRANSLATION_UNIT_GRAMMAR_H_INCLUDED)
#define HANNIBAL_TRANSLATION_UNIT_GRAMMAR_H_INCLUDED
#include <map>
#include <boost/assert.hpp>
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_confix.hpp>
#include <boost/wave/wave_config.hpp>
#include <boost/wave/token_ids.hpp>
#include <boost/wave/util/pattern_parser.hpp>
//
// If so required, trace every declaration and member-declaration.
// This can be a much faster alternative to BOOST_SPIRIT_DEBUG-type of
// debugging.
//
#ifdef HANNIBAL_TRACE_DECLARATIONS
struct trace_actor
{
trace_actor(
const char rule_type[],
std::ostream &strm
)
: strm_( strm), rule_type_( rule_type)
{
// nop
}
template<typename PositionIterator>
void operator()(PositionIterator begin, PositionIterator end) const
{
typedef const boost::wave::cpplexer::lex_token<>::position_type
position_type;
//typedef pos_iterator_type::token_type::position_type position_type;
position_type &begin_pos(begin->get_position());
strm_ << "Parsed " << rule_type_ << std::endl;
strm_ << " from: " << begin_pos.get_file()
<< "(" << begin_pos.get_line() << ")"
<< std::endl;
};
private:
std::ostream &strm_;
char const* const rule_type_;
};
#define HANNIBAL_TRACE_ACTION( type) [trace_actor( (type), std::cout)]
#else
#define HANNIBAL_TRACE_ACTION( type)
#endif
///////////////////////////////////////////////////////////////////////////////
#define HANNIBAL_TRACE_TRANSLATION_UNIT_GRAMMAR \
bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR) \
/**/
///////////////////////////////////////////////////////////////////////////////
// Helper macro to register rules for debugging
#if HANNIBAL_DUMP_PARSE_TREE != 0
#define HANNIBAL_REGISTER_RULE(r) \
BOOST_SPIRIT_DEBUG_NODE(r); \
self.declare_rule(r, #r) \
/**/
#else
#define HANNIBAL_REGISTER_RULE(r) \
BOOST_SPIRIT_DEBUG_NODE(r) \
/**/
#endif
///////////////////////////////////////////////////////////////////////////////
struct dump_actor {
template<typename ForwardIterator>
void operator()(ForwardIterator begin, ForwardIterator end)
{
std::cerr << "*** COULD NOT PARSE THE FOLLOWING ***" << std::endl;
while (begin != end)
{
std::cerr << begin->get_value();
++begin;
}
}
} dump_a;
///////////////////////////////////////////////////////////////////////////////
struct translation_unit_grammar
: public boost::spirit::classic::grammar<translation_unit_grammar>
{
#if HANNIBAL_DUMP_PARSE_TREE != 0
//
// allow an external map with rule-id -> rule-name mappings.
// this map is external so it can be altered by the definition constructor,
// which receives a const grammar object.
//
// Please Note: the lifetime of the rule map should at least extend beyond the
// call of the definition constructor...
//
typedef std::map<boost::spirit::classic::parser_id, std::string>
rule_map_type;
translation_unit_grammar(rule_map_type *rule_map_ptr_ = 0)
: rule_map_ptr(rule_map_ptr_)
#else
translation_unit_grammar()
#endif
{
BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this,
"translation_unit_grammar", HANNIBAL_TRACE_TRANSLATION_UNIT_GRAMMAR);
}
template <typename ScannerT>
struct definition
{
// declare non-terminals
typedef boost::spirit::classic::rule<ScannerT> rule_type;
rule_type constant_expression;
rule_type logical_or_exp, logical_and_exp;
rule_type inclusive_or_exp, exclusive_or_exp, and_exp;
rule_type cmp_equality, cmp_relational;
rule_type shift_exp;
rule_type add_exp, multiply_exp;
rule_type unary_exp, primary_exp, constant;
boost::spirit::classic::subrule<0> const_exp_subrule;
boost::spirit::classic::subrule<1> shift_exp_clos;
rule_type simple_type_name, class_keywords;
rule_type storage_class_specifier, cv_qualifier, function_specifier;
rule_type access_specifier;
rule_type extension_type_decorator;
rule_type operator_sym;
rule_type class_key;
rule_type enumerator;
rule_type enumerator_list;
rule_type enumerator_definition;
rule_type member_declarator;
rule_type member_declarator_list;
rule_type member_declaration;
rule_type constant_initializer;
rule_type pure_specifier;
rule_type namespace_body;
rule_type type_id;
rule_type unnamed_namespace_definition;
rule_type extension_namespace_definition;
rule_type original_namespace_definition;
rule_type named_namespace_definition;
rule_type namespace_definition;
rule_type linkage_specification;
rule_type explicit_specialization;
rule_type using_directive;
rule_type using_declaration;
rule_type type_parameter;
rule_type template_parameter;
rule_type template_parameter_list;
rule_type template_declaration;
rule_type explicit_instantiation;
rule_type qualified_namespace_specifier;
rule_type namespace_alias_definition;
rule_type expression_list;
rule_type initializer_list;
rule_type initializer_clause;
rule_type initializer;
rule_type init_declarator;
rule_type init_declarator_list;
rule_type asm_definition;
rule_type simple_declaration;
rule_type block_declaration;
rule_type declaration;
rule_type declaration_seq;
rule_type translation_unit;
rule_type function_definition, function_definition_helper, declarator;
rule_type direct_declarator, parameters_or_array_spec;
rule_type abstract_declarator, direct_abstract_declarator;
rule_type direct_abstract_declarator_helper;
rule_type parameter_declaration_clause, parameter_declaration_list;
rule_type parameter_declaration, assignment_expression, decimal_literal;
rule_type octal_literal, hexadecimal_literal;
rule_type declarator_id, id_expression, qualified_id, unqualified_id;
rule_type operator_function_id, conversion_function_id, conversion_type_id;
rule_type conversion_declarator, function_body;
rule_type compound_statement, ctor_initializer, ptr_operator;
rule_type decl_specifier, type_specifier;
rule_type type_specifier_seq, cv_qualifier_seq, enum_specifier;
rule_type enum_keyword, simple_type_specifier;
rule_type class_specifier, member_specification, class_head;
rule_type type_name, elaborated_type_specifier, template_argument_list;
rule_type template_argument, nested_name_specifier;
rule_type class_or_namespace_name, class_name, enum_name, typedef_name;
rule_type namespace_name, template_id;
rule_type decl_specifier_seq, no_type_decl_specifier;
rule_type function_try_block, handler_seq, handler;
rule_type exception_specification, template_name;
rule_type original_namespace_name, base_specifier;
rule_type base_specifier_list, base_clause;
rule_type odd_language_extension, mem_initializer_id;
rule_type mem_initializer, mem_initializer_list;
rule_type ta_expression_operator;
rule_type ta_logical_or_expression;
rule_type ta_expression;
rule_type ta_conditional_expression;
rule_type ta_throw_expression;
rule_type ta_assignment_expression;
rule_type postfix_expression_helper;
rule_type simple_postfix_expression;
rule_type pseudo_destructor_name;
rule_type direct_new_declarator;
rule_type new_declarator;
rule_type new_initializer;
rule_type new_type_id;
rule_type new_placement;
rule_type delete_expression;
rule_type new_expression;
rule_type unary_operator;
rule_type postfix_expression;
rule_type unary_expression;
rule_type expression_operator;
rule_type cast_expression;
rule_type throw_expression;
rule_type assignment_operator;
rule_type logical_or_expression;
rule_type conditional_expression;
rule_type boolean_literal;
rule_type string_literal;
rule_type floating_literal;
rule_type character_literal;
rule_type integer_literal;
rule_type expression;
rule_type literal;
rule_type primary_expression;
//
// grammar definition.
definition(translation_unit_grammar const& self)
{
using namespace boost::spirit::classic;
using namespace boost::wave;
using boost::wave::util::pattern_p;
//
// First, a long list of expression rules.
//
HANNIBAL_REGISTER_RULE( primary_expression);
primary_expression
= literal
| ch_p(T_THIS)
| ch_p(T_COLON_COLON) >> ch_p(T_IDENTIFIER)
| ch_p(T_COLON_COLON) >> operator_function_id
| ch_p(T_COLON_COLON) >> qualified_id
| ch_p(T_LEFTPAREN) >> expression >> ch_p(T_RIGHTPAREN)
| id_expression
;
HANNIBAL_REGISTER_RULE( literal);
literal
= integer_literal
| character_literal
| floating_literal
| string_literal
| boolean_literal
;
HANNIBAL_REGISTER_RULE( integer_literal);
integer_literal
= pattern_p( IntegerLiteralTokenType, TokenTypeMask)
;
HANNIBAL_REGISTER_RULE( character_literal);
character_literal
= pattern_p( CharacterLiteralTokenType, TokenTypeMask)
;
HANNIBAL_REGISTER_RULE( floating_literal);
floating_literal
= pattern_p( FloatingLiteralTokenType, TokenTypeMask)
;
HANNIBAL_REGISTER_RULE( string_literal);
string_literal
= pattern_p( StringLiteralTokenType, TokenTypeMask)
;
HANNIBAL_REGISTER_RULE( boolean_literal);
boolean_literal
= pattern_p( BoolLiteralTokenType, TokenTypeMask)
;
//
// TODO: separate assignment expression into a grammar of it's own
//
HANNIBAL_REGISTER_RULE( assignment_expression);
assignment_expression
= conditional_expression
| logical_or_expression >> assignment_operator >> assignment_expression
| throw_expression
;
//
// Have a separate assignment expression for template arguments.
// This is needed, because without it, an expression of the form
// template < a, b, c > x;
// would not parse, since the 'c > x' part would be taken by the
// assignment expression.
//
// Note that this ta_xxxxx duplication cascades all the way down to
// logical_or_expression.
// Both the previous example and a declaration of the form
// template < a, b, (c > d) > x;
// should parse fine now.
//
//
HANNIBAL_REGISTER_RULE( ta_assignment_expression);
ta_assignment_expression
= ta_conditional_expression
| ta_logical_or_expression >> assignment_operator >> ta_assignment_expression
| ta_throw_expression
;
HANNIBAL_REGISTER_RULE( throw_expression);
throw_expression
= ch_p(T_THROW) >> !assignment_expression
;
HANNIBAL_REGISTER_RULE( ta_throw_expression);
ta_throw_expression
= ch_p(T_THROW) >> !ta_assignment_expression
;
HANNIBAL_REGISTER_RULE( conditional_expression);
conditional_expression
= logical_or_expression
>> !(
ch_p(T_QUESTION_MARK)
>> expression
>> ch_p(T_COLON)
>> assignment_expression
)
;
HANNIBAL_REGISTER_RULE( ta_conditional_expression);
ta_conditional_expression
= ta_logical_or_expression
>> !(
ch_p(T_QUESTION_MARK)
>> ta_expression
>> ch_p(T_COLON)
>> ta_assignment_expression
)
;
HANNIBAL_REGISTER_RULE( expression);
expression
= assignment_expression % ch_p(T_COMMA);
HANNIBAL_REGISTER_RULE( ta_expression);
ta_expression
= ta_assignment_expression % ch_p(T_COMMA);
HANNIBAL_REGISTER_RULE( assignment_operator);
assignment_operator
= pp(T_ASSIGN)
| pp(T_ANDASSIGN)
| pp(T_ORASSIGN)
| pp(T_XORASSIGN)
| pp(T_DIVIDEASSIGN)
| pp(T_MINUSASSIGN)
| pp(T_PERCENTASSIGN)
| pp(T_PLUSASSIGN)
| pp(T_SHIFTLEFTASSIGN)
| pp(T_SHIFTRIGHTASSIGN)
| pp(T_STARASSIGN)
;
// we skip quite a few rules here, since we're not interested in operator precedence
// just now.
HANNIBAL_REGISTER_RULE( logical_or_expression);
logical_or_expression
= cast_expression % expression_operator
;
HANNIBAL_REGISTER_RULE( ta_logical_or_expression);
ta_logical_or_expression
= cast_expression % ta_expression_operator
;
HANNIBAL_REGISTER_RULE( expression_operator );
expression_operator
= ta_expression_operator | pp(T_GREATER)
;
HANNIBAL_REGISTER_RULE( ta_expression_operator );
ta_expression_operator
= pp(T_OROR)
| pp(T_ANDAND)
| pp(T_OR)
| pp(T_XOR)
| pp(T_AND)
| pp(T_NOTEQUAL)
| pp(T_EQUAL)
| pp(T_GREATEREQUAL)
| pp(T_LESSEQUAL)
| pp(T_LESS)
| pp(T_SHIFTLEFT)
| pp(T_SHIFTRIGHT)
| pp(T_PLUS)
| pp(T_MINUS)
| pp(T_PERCENT)
| pp(T_DIVIDE)
| pp(T_STAR)
| pp(T_ARROWSTAR)
| pp(T_DOTSTAR)
;
HANNIBAL_REGISTER_RULE( cast_expression);
cast_expression
= ch_p(T_LEFTPAREN) >> type_id >> ch_p(T_RIGHTPAREN)
>> cast_expression
| unary_expression
;
HANNIBAL_REGISTER_RULE( unary_expression);
unary_expression
= postfix_expression
| ch_p(T_PLUSPLUS) >> cast_expression
| ch_p(T_MINUSMINUS) >> cast_expression
| unary_operator >> cast_expression
| ch_p(T_SIZEOF) >> unary_expression
| ch_p(T_SIZEOF)
>> ch_p(T_LEFTPAREN) >> type_id >> ch_p(T_RIGHTPAREN)
| new_expression
| delete_expression
;
HANNIBAL_REGISTER_RULE( unary_operator);
unary_operator
= ch_p(T_STAR)
| pp(T_AND)
| pp(T_PLUS)
| ch_p(T_MINUS)
| ch_p(T_NOT)
| pp(T_COMPL)
;
HANNIBAL_REGISTER_RULE( new_expression);
new_expression
= !ch_p(T_COLON_COLON) >> ch_p(T_NEW) >> !new_placement
>> (
new_type_id >> !new_initializer
| ch_p(T_LEFTPAREN) >> type_id >> ch_p(T_RIGHTPAREN) >> !new_initializer
)
;
HANNIBAL_REGISTER_RULE( new_placement);
new_placement
= ch_p(T_LEFTPAREN) >> expression_list >> ch_p(T_RIGHTPAREN)
;
HANNIBAL_REGISTER_RULE( new_type_id);
new_type_id
= type_specifier_seq >> !new_declarator
;
HANNIBAL_REGISTER_RULE( new_declarator);
new_declarator
= ptr_operator >> !new_declarator
| direct_new_declarator
;
HANNIBAL_REGISTER_RULE( direct_new_declarator);
direct_new_declarator
= *( pp(T_LEFTBRACKET) >> expression >> pp(T_RIGHTBRACKET) )
>> pp(T_LEFTBRACKET) >> constant_expression >> pp(T_RIGHTBRACKET)
;
HANNIBAL_REGISTER_RULE( new_initializer);
new_initializer
= ch_p(T_LEFTPAREN) >> !expression_list >> ch_p(T_RIGHTPAREN)
;
HANNIBAL_REGISTER_RULE( delete_expression);
delete_expression
= !ch_p(T_COLON_COLON) >> ch_p(T_DELETE) >> cast_expression
| !ch_p(T_COLON_COLON) >> ch_p(T_DELETE)
>> pp(T_LEFTBRACKET) >> pp(T_RIGHTBRACKET)
>> cast_expression
;
HANNIBAL_REGISTER_RULE( postfix_expression);
postfix_expression
= simple_postfix_expression >> *postfix_expression_helper
;
HANNIBAL_REGISTER_RULE( simple_postfix_expression);
simple_postfix_expression
= primary_expression
| simple_type_specifier
>> ch_p(T_LEFTPAREN) >> !expression_list >> ch_p(T_RIGHTPAREN)
| ch_p(T_DYNAMICCAST)
>> ch_p(T_LESS) >> type_id >> ch_p(T_GREATER)
>> ch_p(T_LEFTPAREN) >> expression >> ch_p(T_RIGHTPAREN)
| ch_p(T_STATICCAST)
>> ch_p(T_LESS) >> type_id >> ch_p(T_GREATER)
>> ch_p(T_LEFTPAREN) >> expression >> ch_p(T_RIGHTPAREN)
| ch_p(T_REINTERPRETCAST)
>> ch_p(T_LESS) >> type_id >> ch_p(T_GREATER)
>> ch_p(T_LEFTPAREN) >> expression >> ch_p(T_RIGHTPAREN)
| ch_p(T_CONSTCAST)
>> ch_p(T_LESS) >> type_id >> ch_p(T_GREATER)
>> ch_p(T_LEFTPAREN) >> expression >> ch_p(T_RIGHTPAREN)
| ch_p(T_TYPEID)
>> ch_p(T_LEFTPAREN) >> expression >> ch_p(T_RIGHTPAREN)
| ch_p(T_TYPEID)
>> ch_p(T_LEFTPAREN) >> type_id >> ch_p(T_RIGHTPAREN)
;
HANNIBAL_REGISTER_RULE( postfix_expression_helper );
postfix_expression_helper
= pp(T_LEFTBRACKET) >> expression >> pp(T_RIGHTBRACKET)
| ch_p(T_LEFTPAREN) >> !expression_list >> ch_p(T_RIGHTPAREN)
| ch_p(T_DOT) >> !ch_p(T_TEMPLATE) >> !ch_p(T_COLON_COLON) >> id_expression
| ch_p(T_ARROW) >> !ch_p(T_TEMPLATE) >> !ch_p(T_COLON_COLON) >> id_expression
| ch_p(T_DOT) >> pseudo_destructor_name
| ch_p(T_ARROW) >> pseudo_destructor_name
| ch_p(T_PLUSPLUS)
| ch_p(T_MINUSMINUS)
;
HANNIBAL_REGISTER_RULE( pseudo_destructor_name);
pseudo_destructor_name
= !ch_p(T_COLON_COLON) >> !nested_name_specifier
>> (
type_name >> ch_p(T_COLON_COLON) >> ch_p(T_COMPL) >> type_name
| ch_p(T_COMPL) >> type_name
)
;
HANNIBAL_REGISTER_RULE(constant_expression);
constant_expression
= conditional_expression
;
HANNIBAL_REGISTER_RULE(ctor_initializer);
ctor_initializer
= ch_p(T_COLON) >> mem_initializer_list
;
HANNIBAL_REGISTER_RULE(mem_initializer_list);
mem_initializer_list
= mem_initializer % ch_p(T_COMMA)
;
HANNIBAL_REGISTER_RULE(mem_initializer);
mem_initializer
= mem_initializer_id
>> comment_nest_p(ch_p(T_LEFTPAREN), ch_p(T_RIGHTPAREN))
// TODO: restore after assignment expression has been implemented
//ch_p(T_LEFTPAREN) >> !expression_list >> ch_p(T_RIGHTPAREN)
;
HANNIBAL_REGISTER_RULE(mem_initializer_id);
mem_initializer_id
= !ch_p(T_COLON_COLON) >> !nested_name_specifier >> class_name
| ch_p(T_IDENTIFIER)
;
//
// the eps_p is added to allow skipping of trailing whitespace
// (post-skip)
//
HANNIBAL_REGISTER_RULE(translation_unit);
translation_unit
= !declaration_seq >> end_p;
;
HANNIBAL_REGISTER_RULE(odd_language_extension);
odd_language_extension // read: microsoft extensions
= extension_type_decorator
>> !comment_nest_p(ch_p(T_LEFTPAREN), ch_p(T_RIGHTPAREN))
;
HANNIBAL_REGISTER_RULE(declaration_seq);
declaration_seq
= +declaration HANNIBAL_TRACE_ACTION( "declaration")
;
HANNIBAL_REGISTER_RULE(declaration);
declaration
= template_declaration
| explicit_instantiation
| explicit_specialization
| linkage_specification
| namespace_definition
| block_declaration
| function_definition
;
HANNIBAL_REGISTER_RULE(block_declaration);
block_declaration
= simple_declaration
| asm_definition
| namespace_alias_definition
| using_declaration
| using_directive
;
HANNIBAL_REGISTER_RULE(simple_declaration);
simple_declaration
= !decl_specifier_seq >> !init_declarator_list
>> ch_p(T_SEMICOLON)
;
HANNIBAL_REGISTER_RULE(asm_definition);
asm_definition
= ch_p(T_ASM)
>> ch_p(T_LEFTPAREN) >> ch_p(T_STRINGLIT) >> ch_p(T_RIGHTPAREN)
>> ch_p(T_SEMICOLON)
;
HANNIBAL_REGISTER_RULE(init_declarator_list);
init_declarator_list
= init_declarator % ch_p(T_COMMA)
;
HANNIBAL_REGISTER_RULE(init_declarator);
init_declarator
= declarator >> !initializer
;
HANNIBAL_REGISTER_RULE(initializer);
initializer
= ch_p(T_ASSIGN) >> initializer_clause
| ch_p(T_LEFTPAREN) >> expression_list >> ch_p(T_RIGHTPAREN)
;
HANNIBAL_REGISTER_RULE(initializer_clause);
initializer_clause
= assignment_expression
| ch_p(T_LEFTBRACE) >> initializer_list
>> !ch_p(T_COMMA) >> ch_p(T_RIGHTBRACE)
| ch_p(T_LEFTBRACE) >> ch_p(T_RIGHTBRACE)
;
HANNIBAL_REGISTER_RULE(initializer_list);
initializer_list
= initializer_clause % ch_p(T_COMMA)
;
HANNIBAL_REGISTER_RULE(expression_list);
expression_list
= assignment_expression % ch_p(T_COMMA)
;
HANNIBAL_REGISTER_RULE(namespace_alias_definition);
namespace_alias_definition
= ch_p(T_NAMESPACE) >> ch_p(T_IDENTIFIER) >> ch_p(T_ASSIGN)
>> qualified_namespace_specifier
>> ch_p(T_SEMICOLON)
;
HANNIBAL_REGISTER_RULE(qualified_namespace_specifier);
qualified_namespace_specifier
= !ch_p(T_COLON_COLON) >> !nested_name_specifier
>> namespace_name
;
HANNIBAL_REGISTER_RULE(explicit_instantiation);
explicit_instantiation
= template_declaration
;
HANNIBAL_REGISTER_RULE(template_declaration);
template_declaration
= !ch_p(T_EXPORT) >> ch_p(T_TEMPLATE)
>> ch_p(T_LESS) >> template_parameter_list >> ch_p(T_GREATER)
>> declaration
;
HANNIBAL_REGISTER_RULE(template_parameter_list);
template_parameter_list
= template_parameter % ch_p(T_COMMA)
;
HANNIBAL_REGISTER_RULE(template_parameter);
template_parameter
= type_parameter
| parameter_declaration
;
HANNIBAL_REGISTER_RULE(type_parameter);
type_parameter
= ch_p(T_CLASS) >> !ch_p(T_IDENTIFIER)
>> !(ch_p(T_ASSIGN) >> type_id)
| ch_p(T_TYPENAME) >> !ch_p(T_IDENTIFIER)
>> !(ch_p(T_ASSIGN) >> type_id)
| ch_p(T_TEMPLATE)
>> ch_p(T_LESS) >> template_parameter_list >> ch_p(T_GREATER)
>> ch_p(T_CLASS) >> !ch_p(T_IDENTIFIER)
>> !(ch_p(T_ASSIGN) >> template_name)
;
HANNIBAL_REGISTER_RULE(template_name);
template_name
= ch_p(T_IDENTIFIER)
;
HANNIBAL_REGISTER_RULE(using_declaration);
using_declaration // optimize?
= ch_p(T_USING) >> !ch_p(T_TYPENAME) >> !ch_p(T_COLON_COLON)
>> nested_name_specifier >> unqualified_id
>> ch_p(T_SEMICOLON)
| ch_p(T_USING) >> ch_p(T_COLON_COLON) >> unqualified_id
>> ch_p(T_SEMICOLON)
;
HANNIBAL_REGISTER_RULE(using_directive);
using_directive
= ch_p(T_USING) >> ch_p(T_NAMESPACE) >> !ch_p(T_COLON_COLON)
>> !nested_name_specifier >> namespace_name
>> ch_p(T_SEMICOLON)
;
HANNIBAL_REGISTER_RULE(explicit_specialization);
explicit_specialization
= ch_p(T_TEMPLATE) >> ch_p(T_LESS) >> ch_p(T_GREATER)
>> declaration
;
HANNIBAL_REGISTER_RULE(linkage_specification);
linkage_specification
= ch_p(T_EXTERN) >> ch_p(T_STRINGLIT)
>> ( ch_p(T_LEFTBRACE) >> !declaration_seq >> ch_p(T_RIGHTBRACE)
| declaration
)
;
HANNIBAL_REGISTER_RULE(namespace_definition);
namespace_definition
= named_namespace_definition
| unnamed_namespace_definition // TODO: optimize?
;
HANNIBAL_REGISTER_RULE(named_namespace_definition);
named_namespace_definition
= original_namespace_definition
// | extension_namespace_definition // optimization: extension namespace is syntactically identical
;
HANNIBAL_REGISTER_RULE(original_namespace_definition);
original_namespace_definition
= ch_p(T_NAMESPACE) >> ch_p(T_IDENTIFIER)
>> ch_p(T_LEFTBRACE) >> namespace_body >> ch_p(T_RIGHTBRACE)
;
HANNIBAL_REGISTER_RULE(extension_namespace_definition);
extension_namespace_definition
= ch_p(T_NAMESPACE) >> original_namespace_name
>> ch_p(T_LEFTBRACE) >> namespace_body >> ch_p(T_RIGHTBRACE)
;
HANNIBAL_REGISTER_RULE(original_namespace_name);
original_namespace_name
= ch_p(T_IDENTIFIER)
;
HANNIBAL_REGISTER_RULE(unnamed_namespace_definition);
unnamed_namespace_definition
= ch_p(T_NAMESPACE)
>> ch_p(T_LEFTBRACE) >> namespace_body >> ch_p(T_RIGHTBRACE)
;
HANNIBAL_REGISTER_RULE(namespace_body);
namespace_body
= !declaration_seq
;
HANNIBAL_REGISTER_RULE(function_definition);
function_definition
= function_definition_helper
>> !ctor_initializer >> !function_body // removed semicolons
| decl_specifier_seq >> declarator >> function_try_block
| declarator >> function_try_block
;
HANNIBAL_REGISTER_RULE(function_definition_helper);
function_definition_helper
= decl_specifier_seq >> declarator
| +no_type_decl_specifier >> declarator
| declarator
;
HANNIBAL_REGISTER_RULE(function_try_block);
function_try_block
= ch_p(T_TRY)
>> !ctor_initializer >> function_body >> handler_seq
;
HANNIBAL_REGISTER_RULE(handler_seq);
handler_seq
= +handler
;
HANNIBAL_REGISTER_RULE(handler);
handler // TODO
= ch_p(T_CATCH)
>> comment_nest_p(ch_p(T_LEFTPAREN), ch_p(T_RIGHTPAREN))
>> compound_statement
;
HANNIBAL_REGISTER_RULE(declarator);
declarator
= *( ptr_operator
| odd_language_extension
)
>> direct_declarator
;
HANNIBAL_REGISTER_RULE(direct_declarator);
direct_declarator
= ( declarator_id
| ch_p(T_LEFTPAREN) >> declarator >> ch_p(T_RIGHTPAREN)
)
>> *parameters_or_array_spec
;
HANNIBAL_REGISTER_RULE(parameters_or_array_spec);
parameters_or_array_spec
= ch_p(T_LEFTPAREN) >> parameter_declaration_clause >> ch_p(T_RIGHTPAREN)
>> !cv_qualifier_seq >> !exception_specification
| pp(T_LEFTBRACKET) >> !constant_expression >> pp(T_RIGHTBRACKET)
;
HANNIBAL_REGISTER_RULE(exception_specification);
exception_specification // TODO
= ch_p(T_THROW)
>> comment_nest_p(ch_p(T_LEFTPAREN), ch_p(T_RIGHTPAREN))
;
HANNIBAL_REGISTER_RULE(abstract_declarator);
abstract_declarator
= +( ptr_operator
| odd_language_extension
)
>> !direct_abstract_declarator
| direct_abstract_declarator
;
HANNIBAL_REGISTER_RULE(direct_abstract_declarator);
direct_abstract_declarator
= ch_p(T_LEFTPAREN) >> abstract_declarator >> ch_p(T_RIGHTPAREN)
>> *direct_abstract_declarator_helper
;
HANNIBAL_REGISTER_RULE(direct_abstract_declarator_helper);
direct_abstract_declarator_helper
= ch_p(T_LEFTPAREN) >> parameter_declaration_clause >> ch_p(T_RIGHTPAREN)
>> !cv_qualifier_seq >> !exception_specification
| pp(T_LEFTBRACKET) >> !constant_expression >> pp(T_RIGHTBRACKET)
;
HANNIBAL_REGISTER_RULE(parameter_declaration_clause);
parameter_declaration_clause
= parameter_declaration_list >> ch_p(T_COMMA)
>> ch_p(T_ELLIPSIS)
| !parameter_declaration_list >> !ch_p(T_ELLIPSIS)
;
HANNIBAL_REGISTER_RULE(parameter_declaration_list);
parameter_declaration_list
= parameter_declaration % ch_p(T_COMMA)
;
HANNIBAL_REGISTER_RULE(parameter_declaration);
parameter_declaration
= decl_specifier_seq
>> !(declarator | abstract_declarator)
>> !(ch_p(T_ASSIGN) >> assignment_expression)
;
HANNIBAL_REGISTER_RULE(declarator_id);
declarator_id
= !ch_p(T_COLON_COLON)
>> ( id_expression
| !nested_name_specifier >> type_name
)
;
HANNIBAL_REGISTER_RULE(id_expression);
id_expression
= qualified_id
| unqualified_id
;
HANNIBAL_REGISTER_RULE(qualified_id);
qualified_id
= nested_name_specifier >> !ch_p(T_TEMPLATE) >> unqualified_id
;
HANNIBAL_REGISTER_RULE(unqualified_id);
unqualified_id
= operator_function_id
| conversion_function_id
| ch_p(T_COMPL) >> class_name
| template_id
| ch_p(T_IDENTIFIER)
;
HANNIBAL_REGISTER_RULE(operator_function_id);
operator_function_id
= ch_p(T_OPERATOR) >> operator_sym // this is called 'operator' in the std grammar
;
HANNIBAL_REGISTER_RULE(operator_sym);
operator_sym
= ch_p(T_DELETE) >> !(pp(T_LEFTBRACKET) >> pp(T_RIGHTBRACKET))
| ch_p(T_NEW) >> !(pp(T_LEFTBRACKET) >> pp(T_RIGHTBRACKET))
| pp(T_LEFTBRACKET) >> pp(T_RIGHTBRACKET)
| ch_p(T_LEFTPAREN) >> ch_p(T_RIGHTPAREN)
| pattern_p(OperatorTokenType, TokenTypeMask)
;
HANNIBAL_REGISTER_RULE(conversion_function_id);
conversion_function_id
= ch_p(T_OPERATOR) >> conversion_type_id
;
HANNIBAL_REGISTER_RULE( conversion_type_id);
conversion_type_id
= type_specifier_seq >> !conversion_declarator
;
HANNIBAL_REGISTER_RULE(type_id);
type_id
= type_specifier_seq >> !abstract_declarator
;
HANNIBAL_REGISTER_RULE(conversion_declarator);
conversion_declarator
= ptr_operator >> !conversion_declarator
;
HANNIBAL_REGISTER_RULE(function_body);
function_body
= compound_statement
;
HANNIBAL_REGISTER_RULE(compound_statement);
compound_statement
= comment_nest_p(ch_p(T_LEFTBRACE), ch_p(T_RIGHTBRACE))
; // TODO later
HANNIBAL_REGISTER_RULE(ptr_operator);
ptr_operator
= ch_p(T_STAR) >> !cv_qualifier_seq
| ch_p(T_AND)
| !ch_p(T_COLON_COLON) >> nested_name_specifier
>> ch_p(T_STAR) >> !cv_qualifier_seq
;
HANNIBAL_REGISTER_RULE(decl_specifier);
decl_specifier
= no_type_decl_specifier
| type_specifier
;
HANNIBAL_REGISTER_RULE(no_type_decl_specifier);
no_type_decl_specifier
= storage_class_specifier
| function_specifier
| ch_p(T_FRIEND)
| ch_p(T_TYPEDEF)
| cv_qualifier
| odd_language_extension
;
HANNIBAL_REGISTER_RULE(type_specifier_seq);
type_specifier_seq
= +type_specifier
;
HANNIBAL_REGISTER_RULE(type_specifier);
type_specifier
= enum_specifier
| class_specifier
| elaborated_type_specifier
| simple_type_specifier
| cv_qualifier
;
HANNIBAL_REGISTER_RULE(cv_qualifier_seq);
cv_qualifier_seq
= cv_qualifier >> !cv_qualifier_seq
;
HANNIBAL_REGISTER_RULE(cv_qualifier);
cv_qualifier
= ch_p(T_CONST)
| ch_p(T_VOLATILE)
;
HANNIBAL_REGISTER_RULE(enum_specifier);
enum_specifier
= enum_keyword >> !ch_p(T_IDENTIFIER)
>> ch_p(T_LEFTBRACE) >> !enumerator_list >> ch_p(T_RIGHTBRACE)
;
HANNIBAL_REGISTER_RULE(enum_keyword);
enum_keyword
= ch_p(T_ENUM)
;
HANNIBAL_REGISTER_RULE(enumerator_list);
enumerator_list
= enumerator_definition % ch_p(T_COMMA)
>> !ch_p(T_COMMA)
// TODO find out if this last COMMA_T is an MS-"extension"?
// it seems not to be in the grammar but MSVC 7.0 accepts it.
;
HANNIBAL_REGISTER_RULE(enumerator_definition);
enumerator_definition
= enumerator >> !(ch_p(T_ASSIGN) >> constant_expression)
;
HANNIBAL_REGISTER_RULE(enumerator);
enumerator
= ch_p(T_IDENTIFIER)
;
HANNIBAL_REGISTER_RULE(simple_type_specifier);
simple_type_specifier
= !ch_p(T_COLON_COLON) >> !nested_name_specifier
>> ch_p(T_TEMPLATE) >> template_id
| +simple_type_name
| !ch_p(T_COLON_COLON) >> !nested_name_specifier >> type_name
;
HANNIBAL_REGISTER_RULE(class_head);
class_head // DH changed the order because otherwise it would always parse the (!IDENTIFIER) part.
= !access_specifier >> *odd_language_extension
>> class_key >> *odd_language_extension
>> (
!nested_name_specifier >> template_id
| nested_name_specifier >> ch_p(T_IDENTIFIER)
| !ch_p(T_IDENTIFIER)
)
>> !base_clause
;
HANNIBAL_REGISTER_RULE(type_name);
type_name
= class_name
| enum_name
| typedef_name
;
HANNIBAL_REGISTER_RULE(elaborated_type_specifier);
elaborated_type_specifier
= class_key >> *odd_language_extension
>> !ch_p(T_COLON_COLON)
>> !nested_name_specifier
>> (
!ch_p(T_TEMPLATE) >> template_id
| ch_p(T_IDENTIFIER)
)
| ch_p(T_ENUM) >> !ch_p(T_COLON_COLON)
>> !nested_name_specifier
>> ch_p(T_IDENTIFIER)
| ch_p(T_TYPENAME)
>> !ch_p(T_COLON_COLON)
>> nested_name_specifier
>> (
!ch_p(T_TEMPLATE) >> template_id
| ch_p(T_IDENTIFIER)
)
;
HANNIBAL_REGISTER_RULE(template_argument_list);
template_argument_list
= template_argument % ch_p(T_COMMA)
;
HANNIBAL_REGISTER_RULE(template_argument);
template_argument
= longest_d
[
type_id
| ta_assignment_expression
| template_name
]
;
HANNIBAL_REGISTER_RULE(class_key);
class_key
= class_keywords
;
HANNIBAL_REGISTER_RULE(class_keywords);
class_keywords
= ch_p(T_CLASS)
| ch_p(T_STRUCT)
| ch_p(T_UNION)
;
HANNIBAL_REGISTER_RULE(nested_name_specifier);
nested_name_specifier
= class_or_namespace_name >> ch_p(T_COLON_COLON)
>> ch_p(T_TEMPLATE) >> nested_name_specifier
| class_or_namespace_name >> ch_p(T_COLON_COLON)
>> !nested_name_specifier
;
HANNIBAL_REGISTER_RULE(class_or_namespace_name);
class_or_namespace_name
= class_name
| namespace_name
;
HANNIBAL_REGISTER_RULE(class_name);
class_name
= template_id
| ch_p(T_IDENTIFIER)
;
HANNIBAL_REGISTER_RULE(enum_name);
enum_name
= ch_p(T_IDENTIFIER)
;
HANNIBAL_REGISTER_RULE(typedef_name);
typedef_name
= ch_p(T_IDENTIFIER)
;
HANNIBAL_REGISTER_RULE(namespace_name);
namespace_name // TODO
= ch_p(T_IDENTIFIER)
;
HANNIBAL_REGISTER_RULE(template_id);
template_id
= template_name
>> ch_p(T_LESS) >> template_argument_list >> ch_p(T_GREATER)
;
//
// This is kind of a HACK. We want to prevent the decl_specifier_seq
// from eating the whole declaration, including the ch_p(T_IDENTIFIER).
// Therefore in the sequence, we only allow one 'unknown' word
// (the type_specifier), the rest of the decl_specifier sequence
// must consist of known keywords or constructs (the
// no_type_decl_specifier).
// This means that a declaration like:
// MYDLL_EXPORT int f();
// will not be accepted unless the MYDLL_EXPORT is properly
// expanded by the preprocessor first.
//
// This should not cause any problems normally, it just means that
// this rule is not very robust in the case where not all symbols
// are known.
//
HANNIBAL_REGISTER_RULE(decl_specifier_seq);
decl_specifier_seq
= *no_type_decl_specifier >> type_specifier >> *no_type_decl_specifier
;
// The following rule is more according to the standard grammar
// decl_specifier_seq // adapted
// = decl_specifier >> decl_specifier_seq
// | (decl_specifier - (declarator_id >> parameters_or_array_spec ))
// ;
HANNIBAL_REGISTER_RULE( storage_class_specifier);
storage_class_specifier
= ch_p(T_AUTO)
| ch_p(T_REGISTER)
| ch_p(T_STATIC)
| ch_p(T_EXTERN)
| ch_p(T_MUTABLE)
;
HANNIBAL_REGISTER_RULE( function_specifier);
function_specifier
= ch_p(T_INLINE)
| ch_p(T_VIRTUAL)
| ch_p(T_EXPLICIT)
;
HANNIBAL_REGISTER_RULE(class_specifier);
class_specifier
= class_head
>> ch_p(T_LEFTBRACE) >> !member_specification >> ch_p(T_RIGHTBRACE)
;
HANNIBAL_REGISTER_RULE(member_specification);
member_specification
= +( access_specifier >> ch_p(T_COLON)
| member_declaration HANNIBAL_TRACE_ACTION("member declaration")
)
;
// member_specification
// = access_specifier >> COLON_T >> !member_specification
// | member_declaration >> !member_specification
// ;
HANNIBAL_REGISTER_RULE(member_declaration);
member_declaration
= using_declaration
| template_declaration
| !decl_specifier_seq >> !member_declarator_list
>> ch_p(T_SEMICOLON)
| function_definition >>
!ch_p(T_SEMICOLON)
| qualified_id
>> ch_p(T_SEMICOLON)
;
HANNIBAL_REGISTER_RULE(member_declarator_list);
member_declarator_list
= member_declarator % ch_p(T_COMMA)
;
HANNIBAL_REGISTER_RULE(member_declarator);
member_declarator
= !ch_p(T_IDENTIFIER) >> ch_p(T_COLON) >> constant_expression
| declarator >> !(pure_specifier | constant_initializer)
;
HANNIBAL_REGISTER_RULE(pure_specifier);
pure_specifier
= ch_p(T_ASSIGN) >> ch_p(T_INTLIT)
;
HANNIBAL_REGISTER_RULE(constant_initializer);
constant_initializer
= ch_p(T_ASSIGN) >> constant_expression
;
HANNIBAL_REGISTER_RULE(access_specifier);
access_specifier
= ch_p(T_PUBLIC)
| ch_p(T_PROTECTED)
| ch_p(T_PRIVATE)
;
HANNIBAL_REGISTER_RULE(base_clause);
base_clause
= ch_p(T_COLON) >> base_specifier_list
;
HANNIBAL_REGISTER_RULE(base_specifier_list);
base_specifier_list
= base_specifier % ch_p(T_COMMA)
;
HANNIBAL_REGISTER_RULE(base_specifier);
base_specifier
= ch_p(T_VIRTUAL) >> !access_specifier >> !ch_p(T_COLON_COLON)
>> !nested_name_specifier >> class_name
| access_specifier >> !ch_p(T_VIRTUAL) >> !ch_p(T_COLON_COLON)
>> !nested_name_specifier >> class_name
| !ch_p(T_COLON_COLON) >> !nested_name_specifier >> class_name
;
HANNIBAL_REGISTER_RULE(extension_type_decorator);
extension_type_decorator
= ch_p(T_MSEXT_CDECL)
| ch_p(T_MSEXT_DECLSPEC)
| ch_p(T_MSEXT_BASED)
| ch_p(T_MSEXT_FASTCALL)
| ch_p(T_MSEXT_INLINE)
;
HANNIBAL_REGISTER_RULE(simple_type_name);
simple_type_name
= ch_p(T_CHAR)
| ch_p(T_WCHART)
| ch_p(T_BOOL)
| ch_p(T_SHORT)
| ch_p(T_INT)
| ch_p(T_LONG)
| ch_p(T_UNSIGNED)
| ch_p(T_SIGNED)
| ch_p(T_FLOAT)
| ch_p(T_DOUBLE)
| ch_p(T_VOID)
| ch_p(T_MSEXT_INT64)
| ch_p(T_MSEXT_INT8)
| ch_p(T_MSEXT_INT16)
| ch_p(T_MSEXT_INT32)
;
}
rule_type const& start() const { return translation_unit; }
// Helper function wrapping pattern_p
static inline boost::wave::util::pattern_and< boost::wave::token_id>
pp (boost::wave::token_id id)
{
using namespace boost::wave;
return util::pattern_p(id, MainTokenMask);
}
};
#if HANNIBAL_DUMP_PARSE_TREE != 0
private:
template<typename Rule>
void declare_rule(Rule const& rule, std::string const& rule_name) const
{
if (rule_map_ptr)
(*rule_map_ptr)[rule.id()] = rule_name;
}
rule_map_type *rule_map_ptr;
#endif
};
#undef HANNIBAL_REGISTER_RULE
#undef HANNIBAL_TRACE_TRANSLATION_UNIT_GRAMMAR
#endif // HANNIBAL_TRANSLATION_UNIT_GRAMMAR_H_INCLUDED