tutorial 3 -- Calculator α
This time is an example of calcucator.
The Grammar File
%token Number<int> Add Sub Mul Div;
%namespace calc;
%dont_use_stl;
Expr<int> : [Identity] Term(0)
          | [MakeAdd] Expr(0) Add Term(1)
          | [MakeSub] Expr(0) Sub Term(1)
          ;
Term<int> : [Identity] Number(0)
          | [MakeMul] Term(0) Mul Number(1)
          | [MakeDiv] Term(0) Div Number(1)
          ;
		  If you experienced usage of BNF, you can easily understand almost all. As described above, the element not followed by "(digit)" is not used in the semantic action.
The Handling File
#include "calc0.hpp"
#include <iostream>
class unexpected_char : public std::exception {};
template < class It >
class scanner {
public:
        typedef int char_type;
public:
        scanner( It b, It e ) : b_(b), e_(e), c_(b), unget_(EOF) { }
        calc::Token get( int& v )
        {
                int c;
                do {
                        c = getc();
                } while( isspace( c ) );
                // symbols
                switch( c ) {
                case '+': return calc::token_Add;
                case '-': return calc::token_Sub;
                case '*': return calc::token_Mul;
                case '/': return calc::token_Div;
                case EOF: return calc::token_eof;
                }
                // integers
                if( isdigit( c ) ) {
                        int n = 0;
                        while( c != EOF && isdigit( c ) ) {
                                n *= 10;
                                n += c - '0';
                                c = getc();
                        }
                        ungetc( c );
                        v = n;
                        return calc::token_Number;
                }
                std::cerr << char(c) << std::endl;
                throw unexpected_char();
        }
private:
        char_type getc()
        {
                int c;
                if( unget_ != EOF ) {
                        c = unget_;
                        unget_ = EOF;
                } else if( c_ == e_ ) {
                        c = EOF; 
                } else {
                        c = *c_++;
                }
                return c;
        }
        void ungetc( char_type c )
        {
                if( c != EOF ) {
                        unget_ = c;
                }
        }
private:
        It              b_;
        It              e_;
        It              c_;
        char_type       unget_;
};
struct SemanticAction {
        void syntax_error(){}
        void stack_overflow(){}
        void downcast( int& x, int y ) { x = y; }
        void upcast( int& x, int y ) { x = y; }
        int Identity( int n ) { return n; }
        int MakeAdd( int x, int y )
        {
                std::cerr << "expr " << x << " + " << y << std::endl;
                return x + y ; 
        }
        int MakeSub( int x, int y )
        {
                std::cerr << "expr " << x << " - " << y << std::endl;
                return x - y ; 
        }
        int MakeMul( int x, int y )
        {
                std::cerr << "expr " << x << " * " << y << std::endl;
                return x * y ;
        }
        int MakeDiv( int x, int y )
        {
                std::cerr << "expr " << x << " / " << y << std::endl;
                return x / y ;
        }
};
int main( int, char** )
{
        // The scanner
        typedef std::istreambuf_iterator<char> is_iterator;
        is_iterator b( std::cin );
        is_iterator e;
        scanner< is_iterator > s( b, e );
        SemanticAction sa;
        calc::Parser< int, SemanticAction > parser( sa );
        calc::Token token;
        for(;;) {
                int v;
                token = s.get( v );
                if( parser.post( token, v ) ) { break; }
        }
        int v;
        if( parser.accept( v ) ) {
                std::cerr << "accpeted\n";
                std::cerr << v << std::endl;
        }
        return 0;
}
		This time, for a scanner was necessary, so I prepared a handwritten scanner.
		There is no difficult stuffs. Read the source carefully.
		If handwriting is troublesome for you, you can use boost::regex etc.
At semantic actions, there is no new type items.
The main function introduced some new items as below:
  The return value of parser.post
		Returns true when the whole was accepted or error was detected; otherwise returns false.
  The return value of parser.accept
		parser.accept is valid only after parser.post returned true.
		If error occurs, v becomes an indefinite value and the function returns false.
		Otherwise it is successful, v is assigned the value of the left side of the root grammar, and
		the function returns true.
If you experienced yacc etc., there is no difficult thing.
Execution
% ./calc0 8+3*7 ^D expr 3 * 7 expr 8 + 21 accepted 29