|
#pragma once
#include "expressiontree.h"
#include "parser.h"
#include "visitors.h"
#include <boost/spirit.hpp>
#include <string>
#include <exception>
#include <iostream>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
namespace Calculator
{
typedef CExpressionTree* (*createPtr)( void );
// Forward declares
namespace Private
{
struct GetVariable;
struct SetVariable;
struct DoAssign;
struct OutputResult;
struct AddChild;
struct AddNumericChild;
struct AddParent;
struct SetModular;
struct FinishedProcessing;
} // namespace Private
////////////////////////////////////////////////////////////////////////////////
/// The syntax, defined according to specific boost::spirit requirements
///
////////////////////////////////////////////////////////////////////////////////
struct Syntax :
public boost::spirit::grammar<Syntax>
{
public:
Syntax( CParser &parser );
virtual ~Syntax();
template <typename ScannerT>
struct definition
{
public:
definition( Syntax const &self )
{
integer =
uint_p[ Private::AddNumericChild( self.m_parser ) ]
;
factor =
integer |
vars[ Private::GetVariable( self.m_parser ) ] |
'(' >> expression >> ')' |
( ch_p('-')[ Private::AddChild( self.m_parser, &CEmpty::Create ) ] >> factor )
[ Private::AddParent( self.m_parser, &COperatorUnaryMinus::Create ) ] |
( '+' >> factor )
;
term =
factor
>> *( ( '*' >> factor ) [ Private::AddParent( self.m_parser, &COperatorMultiply::Create ) ]
| ( '/' >> factor ) [ Private::AddParent( self.m_parser, &COperatorDivide::Create ) ]
)
;
expression =
term
>> *( ( '+' >> term ) [ Private::AddParent( self.m_parser, &COperatorPlus::Create ) ]
| ( '-' >> term ) [ Private::AddParent( self.m_parser, &COperatorMinus::Create ) ]
)
;
assignment =
vars[ Private::SetVariable( self.m_parser ) ]
>> '=' >> expression[ Private::DoAssign( self.m_parser ) ]
;
var_decl =
lexeme_d
[
( ( alpha_p >> *( alnum_p | '_' ) )
- vars )[vars.add]
]
;
declaration =
"int" >> var_decl >> *( ',' >> var_decl )
;
baseExpression =
str_p( "exit" )[ Private::FinishedProcessing( self.m_parser ) ] |
str_p( "mod" ) >> uint_p[ Private::SetModular( self.m_parser ) ] |
declaration |
assignment |
'?' >> expression [ Private::OutputResult( self.m_parser ) ]
;
}
boost::spirit::symbols<int> vars;
boost::spirit::rule<ScannerT> integer, factor, term,
expression, assignment, var_decl, declaration,
baseExpression;
const boost::spirit::rule<ScannerT> &start() const { return baseExpression; }
};
void SetCurrentVariable( int &var ) const { m_var = &var; }
int *&GetCurrentVariable() const { return m_var; }
friend struct definition;
private:
CParser &m_parser;
mutable int *m_var;
};
namespace Private
{
////////////////////////////////////////////////////////////////////////////////
/// A set of functors that are used as callbacks from within the parser framework
///
////////////////////////////////////////////////////////////////////////////////
struct GetVariable
{
public:
GetVariable( CParser &parser ) : m_parser( parser ) {}
void operator()( int n ) const
{
// Functor is passed the value of the required variable
// Push the value onto the tree
m_parser.GetRoot()->AddChild( new CValue( n ) );
TRACE( "Got Variable %d\n", n );
}
private:
CParser &m_parser;
};
struct SetVariable
{
public:
SetVariable( CParser &parser ) : m_parser( parser ) {}
void operator()( int &n ) const
{
// Functor is passed a reference to the variable to set
m_parser.GetGrammar()->SetCurrentVariable( n );
TRACE( "About to Set Variable\n" );
}
private:
CParser &m_parser;
};
struct DoAssign
{
public:
DoAssign( CParser &parser ) : m_parser( parser ) {}
template <typename IteratorT>
void operator()( IteratorT, IteratorT ) const
{
CCalculateTreeVisitor value( m_parser.GetModular() );
value( m_parser.GetRoot() );
int newValue = value.pop();
// Functor is called when an assignment is ready to be made
if ( m_parser.GetGrammar()->GetCurrentVariable() )
*m_parser.GetGrammar()->GetCurrentVariable() = newValue;
TRACE( "Assigning to Variable %d\n", newValue );
}
private:
CParser &m_parser;
};
struct OutputResult
{
public:
OutputResult( CParser &parser ) : m_parser( parser ) {}
template <typename IteratorT>
void operator()( IteratorT, IteratorT ) const
{
CCalculateTreeVisitor value( m_parser.GetModular() );
value( m_parser.GetRoot() );
cout << "= " << value.pop() << endl;
}
private:
CParser &m_parser;
};
struct AddChild
{
public:
AddChild( CParser &parser, createPtr create ) :
m_parser( parser ), m_create( create ) {}
template <typename IteratorT>
void operator()( IteratorT, IteratorT ) const
{
m_parser.GetRoot()->AddChild( m_create() );
}
template <typename IteratorT>
void operator()( IteratorT ) const
{
m_parser.GetRoot()->AddChild( m_create() );
}
private:
CParser &m_parser;
createPtr m_create;
};
struct AddNumericChild
{
public:
AddNumericChild( CParser &parser ) : m_parser( parser ) {}
void operator()( unsigned int num ) const
{
m_parser.GetRoot()->AddChild( new CValue( (int) num ) );
}
private:
CParser &m_parser;
};
struct AddParent
{
public:
AddParent( CParser &parser, createPtr create ) :
m_parser( parser ), m_create( create ) {}
template <typename IteratorT>
void operator()( IteratorT, IteratorT ) const
{
m_parser.GetRoot()->AddParent( m_create() );
}
private:
CParser &m_parser;
createPtr m_create;
};
struct SetModular
{
public:
SetModular( CParser &parser ) : m_parser( parser ) {}
void operator()( unsigned int num ) const
{
m_parser.SetModular( num );
}
private:
CParser &m_parser;
};
struct FinishedProcessing
{
public:
FinishedProcessing( CParser &parser ) : m_parser( parser ) {}
template <typename IteratorT>
void operator()( IteratorT, IteratorT ) const
{
m_parser.SetProcessingFinished();
}
template <typename CharT>
void operator()( CharT ) const
{
m_parser.SetProcessingFinished();
}
private:
CParser &m_parser;
};
} // namespace Private
} // namespace Calculator
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I started programming on 8 bit machines as a teenager, writing my first compiled programming language before I was 16. I went on to study Engineering and Computer Science at Oxford University, getting a first and the University Prize for the best results in Computer Science. Since then I have worked in a variety of roles, involving systems management and development management on a wide variety of platforms. Now I manage a software development company producing CAD software for Windows using C++.
My 3 favourite reference books are: Design Patterns, Gamma et al; The C++ Standard Library, Josuttis; and Computer Graphics, Foley et al.
Outside computers, I am also the drummer in a band, The Unbelievers and we have just released our first album. I am a pretty good juggler and close up magician, and in my more insane past, I have cycled from Spain to Eastern Turkey, and cycled across the Namib desert.