Files
159201/assignment2/as2/assignment02_159201_final_version.cpps
mooophy 74643b0954 ready
renamed:    assignment2/as2/main.cpp -> assignment2/as2/assignment02_159201_final_version.cpps
2014-12-08 17:14:08 +13:00

302 lines
5.9 KiB
Plaintext

//!
//! @author Wang WeiXu 13114633
//! @date 08.12.2014
//!
//! @brief This code implemented a parser evaluating Reverse Polish Notation expression
//! using a stack.
//!
//! Assignment 2, 159.201,s3,2014
//!
#include <iostream>
#include <stdexcept>
#include <string>
#include <fstream>
#include <algorithm>
#include <map>
#include <functional>
namespace ads {
/**
* @brief The List class
*/
template<typename T>
class List
{
struct Node
{
T value;
Node* next;
};
public:
using SizeType = std::size_t;
List() = default;
T const& front() const
{
return head_->value;
}
void push_front(T const& new_data)
{
do_push_front(new_data);
}
void pop_front()
{
do_pop_front();
}
bool empty() const
{
return !head_ and !tail_;
}
std::size_t size() const
{
return size_;
}
~List()
{
do_deallocate();
}
private:
Node* head_{nullptr};
Node* tail_{nullptr};
SizeType size_{0};
void do_deallocate()
{
for(Node *ptr{head_}, *tmp; (tmp=ptr); delete tmp)
ptr = ptr->next;
}
void do_push_front(T const& new_value)
{
if(empty())
head_ = tail_ = new Node{new_value, nullptr};
else
head_ = new Node{new_value, head_};
++size_;
}
void do_pop_front()
{
if(empty())
throw std::runtime_error{"underflow!"};
if(head_ == tail_)
{
delete head_;
head_ = tail_ = nullptr;
size_ = 0;
}
else
{
auto tmp = head_;
head_ = head_->next;
delete tmp;
--size_;
}
}
};
///////////////////////////////////////////////////////////////////////////////
/**
* @brief The Stack class
*
* using linked list as underlying data structrue
*/
template<typename T, typename Container = ads::List<T> >
class Stack
{
public:
using SizeType = typename Container::SizeType;
Stack() = default;
void push(T const& new_value)
{
data_.push_front(new_value);
}
T const& top() const
{
return data_.front();
}
void pop()
{
data_.pop_front();
}
SizeType size() const
{
return data_.size();
}
bool empty() const
{
return data_.empty();
}
private:
Container data_{};
};
///////////////////////////////////////////////////////////////////////////////
/**
* @brief The RpnParser
*/
struct RpnParser
{
int parse(std::string const& fn)
{
return do_parse_and_evaluate(fn);
}
private:
/**
* @brief The Eval functor
*/
struct Eval
{
bool is_evaluable(char op) const
{
return dic_.find(op) != dic_.cend();
}
int operator ()(char op, int lhs, int rhs) const
{
return dic_.at(op)(lhs, rhs);
}
std::map<char, std::function<int(int,int)> > const dic_ =
{
{ '+', [](int lhs, int rhs){ return lhs + rhs;} },
{ '-', [](int lhs, int rhs){ return lhs - rhs;} },
{ '*', [](int lhs, int rhs){ return lhs * rhs;} },
{ '/', [](int lhs, int rhs){ return lhs / rhs;} },
};
}
const eval_;
ads::Stack<int> stk_;
//! abstraction II
int get_operand_and_check()
{
try{
if(stk_.empty())
throw std::runtime_error{"too many operators\n"};
}
catch (std::runtime_error e)
{
std::cout << e.what();
exit(0);
}
auto operand = stk_.top();
stk_.pop();
return operand;
}
//! abstraction II
int get_result_and_check()
{
try{
if(1 != stk_.size())
throw std::runtime_error{"too many numbers\n"};
}
catch (std::runtime_error e)
{
std::cout << e.what();
exit(0);
}
auto result = stk_.top();
stk_.pop();
return result;
}
//! abstraction II
void check_file(std::ifstream& ifs)
{
if(!ifs.good())
throw std::runtime_error{"Bad file name"};
}
//! abstraction I
//! implementation for parsing and evaluation
int do_parse_and_evaluate(std::string const& fn)
{
std::ifstream ifs{fn};
check_file(ifs);
for(std::string expr; !ifs.eof(); )
{
std::getline(ifs, expr);
auto it = expr.cbegin();
for( ; it != expr.cend() and std::isspace(*it); ++it);
if(std::isdigit(*it)) //parse number
{
auto peek = it;
for(; peek != expr.cend() and !std::isspace(*peek); ++peek);
auto num = std::stoi(std::string(it, peek));
stk_.push(num);
it = peek;
std::cout << "reading number " << num << std::endl;
continue;
}
if(eval_.is_evaluable(*it)) //parse operator
{
std::cout << "reading operator " << *it << std::endl;
auto rhs = get_operand_and_check();
auto lhs = get_operand_and_check();
stk_.push(eval_(*it, lhs, rhs));
continue;
}
}
return get_result_and_check();
}
};
}//namespace
///////////////////////////////////////////////////////////////////////////////
int main( int argc, char** argv )
{
try
{
if(argc != 2)
throw std::runtime_error{"Cannot read file.\n"};
}
catch (std::runtime_error e)
{
std::cerr << e.what() << "Programme terminated.\n";
return -1;
}
auto result = ads::RpnParser{}.parse(argv[1]);
std::cout << "The result is " << result << std::endl;
return 0;
}