// Copyright (c) 2008 by Dr. Colin Hirsch
// Please see license.txt for license.
#include
namespace calculator
{
// The first program used during development and debugging
// of the library that uses actions. It evaluates each command
// line argument as arithmetic expression consisting of
// - integers with optional sign,
// - the four basic arithmetic operations,
// - grouping brackets.
// For example input "3 * ( -7 + 9)" yields result 6.
using namespace pegtl;
// The state.
// Canonical use of an evaluation stack,
// here implemented with a std::vector.
typedef int value_type;
typedef std::vector< value_type > stack_type;
// Helper function that's [exception] safe with ints as values.
value_type pull( stack_type & s )
{
assert( ! s.empty() );
value_type nrv( s.back() );
s.pop_back();
return nrv;
}
// The actions.
// This action converts the matched sub-string
// to an integer and pushes it on the stack,
// which must be its only additional state argument.
// Deriving from action_base<> is necessary since
// version 0.26; the base class takes care of the pretty-
// printing for diagnostic messages, it is necessary for
// all action classes that do not derive from a rule class.
struct push_action
: action_base< push_action >
{
static void apply( const std::string & m, stack_type & s )
{
s.push_back( string_to_signed< value_type >( m ) );
}
};
// Class op_action performs an operation on the two
// top-most elements of the evaluation stack. This
// should always be possible in the sense that the
// grammar must make sure to only apply this action
// when sufficiently many operands are on the stack.
template< typename Operation >
struct op_action
: action_base< op_action< Operation > >
{
static void apply( const std::string &, stack_type & s )
{
const value_type a = pull( s );
const value_type b = pull( s );
s.push_back( Operation()( b, a ) );
}
};
template<>
struct op_action< std::divides< value_type > >
: action_base< op_action< std::divides< value_type > > >
{
template< typename State >
static void apply( const std::string &, State & s )
{
const value_type rhs = pull( s );
if ( ! rhs ) {
PEGTL_THROW( "pegtl: division by zero" );
}
const value_type lhs = pull( s );
s.push_back( std::divides< value_type >()( lhs, rhs ) );
}
};
// The grammar rules.
struct read_number
: seq< opt< one< '+', '-' > >, plus< digit > > {};
// This rule uses the rule read_number to match a
// number in the input and, on success, applies the
// push_action to the matched sub-string and the
// state, in calculator.cc: an instance of stack_type,
// in order to push the number on the evaluation stack.
struct push_rule
: pad< ifapply< read_number, push_action >, space > {};
template< int C >
struct calc_pad
: pad_one< C, space > {};
struct read_open
: calc_pad< '(' > {};
struct read_close
: calc_pad< ')' > {};
struct read_expr;
struct read_atom
: sor< push_rule, seq< read_open, read_expr, read_close > > {};
struct read_mul
: ifapply< ifmust< calc_pad< '*' >, read_atom >, op_action< std::multiplies< value_type > > > {};
struct read_div
: ifapply< ifmust< calc_pad< '/' >, read_atom >, op_action< std::divides< value_type > > > {};
struct read_prod
: seq< read_atom, star< sor< read_mul, read_div > > > {};
struct read_add
: ifapply< ifmust< calc_pad< '+' >, read_prod >, op_action< std::plus< value_type > > > {};
struct read_sub
: ifapply< ifmust< calc_pad< '-' >, read_prod >, op_action< std::minus< value_type > > > {};
struct read_expr
: seq< read_prod, star< sor< read_add, read_sub > > > {};
struct read_calc
: seq< read_expr, space_until_eof > {};
} // calculator
int main( int argc, char ** argv )
{
for ( int arg = 1; arg < argc; ++arg ) {
calculator::stack_type stack;
pegtl::basic_parse_string< calculator::read_calc >( argv[ arg ], stack );
assert( stack.size() == 1 );
std::cerr << "input " << argv[ arg ] << " result " << stack.front() << "\n";
}
return 0;
}