// sample code: arithmetics.cpp // demonstrates stateful cttl parser //#define NDEBUG // must appear before assert.h is included to stop assertions from being compiled //#define CTTL_TRACE_EVERYTHING #include #include "cttl/cttl.h" using namespace cttl; struct parser { /* Arithmetic expression grammar production rules in EBNF form: * * --> ( '+' | '-' )* * --> ( '*' | '/' )* * --> | '(' ')' | '-' | '+' * --> ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )+ * */ int ip_cnt; parser( int ip_cnt_ = 0 ) : ip_cnt( ip_cnt_ ) { } size_t rule_factor( const_edge< policy_space<> >& universe_ ) { return ( ( isdigit & rule( *this, &parser::numeric_literal ) ) | ( '(' + rule( *this, &parser::rule_expr ) + ')' ) | ( '-' + ( rule( *this, &parser::rule_factor ) & rule( *this, &parser::unary_minus ) ) ) | ( '+' + rule( *this, &parser::rule_factor ) // unary plus is simply ignored ) | rule( *this, &parser::parse_error ) ).match( universe_ ) ; } size_t rule_term( const_edge< policy_space<> >& universe_ ) { return ( rule( *this, &parser::rule_factor ) + * ( ( ( '*' + rule( *this, &parser::rule_factor ) ) & rule( *this, &parser::multiply ) ) | ( ( '/' + rule( *this, &parser::rule_factor ) ) & rule( *this, &parser::divide ) ) ) ).match( universe_ ) ; } size_t rule_expr( const_edge< policy_space<> >& universe_ ) { return ( rule( *this, &parser::rule_term ) + *( ( ( '+' + rule( *this, &parser::rule_term ) ) & rule( *this, &parser::add ) ) | ( ( '-' + rule( *this, &parser::rule_term ) ) & rule( *this, &parser::subtract ) ) ) ).match( universe_ ) ; } size_t numeric_literal( const_edge<>& edge_ ) { std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl; std::cout << "\t" << ++ip_cnt << "\t PUSH \t " << edge_.text() << std::endl; return edge_.second.offset(); } size_t divide( const_edge<>& edge_ ) { std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl; std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl; std::cout << "\t" << ++ip_cnt << "\t POP \t R2" << std::endl; std::cout << "\t" << ++ip_cnt << "\t DIV \t R2, R1 \t; R2 = R2 " << edge_.text() << std::endl; std::cout << "\t" << ++ip_cnt << "\t PUSH \t R2" << std::endl; return edge_.second.offset(); } size_t multiply( const_edge<>& edge_ ) { std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl; std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl; std::cout << "\t" << ++ip_cnt << "\t POP \t R2" << std::endl; std::cout << "\t" << ++ip_cnt << "\t MUL \t R2, R1 \t; R2 = R2 " << edge_.text() << std::endl; std::cout << "\t" << ++ip_cnt << "\t PUSH \t R2" << std::endl; return edge_.second.offset(); } size_t add( const_edge<>& edge_ ) { std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl; std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl; std::cout << "\t" << ++ip_cnt << "\t POP \t R2" << std::endl; std::cout << "\t" << ++ip_cnt << "\t ADD \t R2, R1 \t; R2 = R2 " << edge_.text() << std::endl; std::cout << "\t" << ++ip_cnt << "\t PUSH \t R2" << std::endl; return edge_.second.offset(); } size_t subtract( const_edge<>& edge_ ) { std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl; std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl; std::cout << "\t" << ++ip_cnt << "\t POP \t R2" << std::endl; std::cout << "\t" << ++ip_cnt << "\t SUB \t R2, R1 \t; R2 = R2 " << edge_.text() << std::endl; std::cout << "\t" << ++ip_cnt << "\t PUSH \t R2" << std::endl; return edge_.second.offset(); } size_t unary_minus( const_edge<>& edge_ ) { std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl; std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl; std::cout << "\t" << ++ip_cnt << "\t NEG \t R1 \t\t; R1 = -(" << edge_.text() << ")" << std::endl; std::cout << "\t" << ++ip_cnt << "\t PUSH \t R1" << std::endl; return edge_.second.offset(); } size_t parse_error( const_edge< policy_space<> >& edge_ ) const { std::cout << "*** syntax error ***" << std::endl << edge_.parent().text() << std::endl ; for ( size_t pos = 0; pos < edge_.first.offset(); ++pos ) std::cout << '\x20'; std::cout << "^-- at position " << edge_.first.offset() << std::endl; return std::string::npos; } }; int main(int argc, char* argv[]) { if ( argc == 1 ) { std::cout << "\t usage: enter arithmetic expression to parse" << std::endl; return 1; } // construct input string from arguments on the command line: input<> inp( &argv[ 1 ], ' ' ); // construct universe to be parsed const_edge< policy_space<> > universe( new_edge( inp ) ); // construct the parser: parser arithmetic_parser; // evaluate arithmetic expression: if ( arithmetic_parser.rule_expr( universe ) != std::string::npos ) { if( universe.length() ) { std::cout << std::endl << "*** error: parser terminated: ***" << std::endl << inp.text() << std::endl ; for ( size_t pos = 0; pos < universe.first.offset(); ++pos ) std::cout << '\x20'; std::cout << "^-- at position " << universe.first.offset() << std::endl; } } else std::cout << "*** parser terminated" << std::endl; return 0; }