Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r69378 - trunk/libs/spirit/example/qi/compiler_tutorial/calc7
From: joel_at_[hidden]
Date: 2011-02-28 01:06:53


Author: djowel
Date: 2011-02-28 01:06:50 EST (Mon, 28 Feb 2011)
New Revision: 69378
URL: http://svn.boost.org/trac/boost/changeset/69378

Log:
Better error handling
Text files modified:
   trunk/libs/spirit/example/qi/compiler_tutorial/calc7/annotation.hpp | 3
   trunk/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.cpp | 89 +++++++++++++++++++++++----------------
   trunk/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.hpp | 42 +++++++++++++-----
   trunk/libs/spirit/example/qi/compiler_tutorial/calc7/error_handler.hpp | 26 +++++++----
   trunk/libs/spirit/example/qi/compiler_tutorial/calc7/expression_def.hpp | 12 +++--
   trunk/libs/spirit/example/qi/compiler_tutorial/calc7/main.cpp | 33 ++++++++------
   trunk/libs/spirit/example/qi/compiler_tutorial/calc7/statement_def.hpp | 8 ++-
   7 files changed, 129 insertions(+), 84 deletions(-)

Modified: trunk/libs/spirit/example/qi/compiler_tutorial/calc7/annotation.hpp
==============================================================================
--- trunk/libs/spirit/example/qi/compiler_tutorial/calc7/annotation.hpp (original)
+++ trunk/libs/spirit/example/qi/compiler_tutorial/calc7/annotation.hpp 2011-02-28 01:06:50 EST (Mon, 28 Feb 2011)
@@ -40,8 +40,7 @@
                 x.id = id;
             }
 
- template <typename T>
- void operator()(T& x) const
+ void operator()(...) const
             {
                 // no need for tags
             }

Modified: trunk/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.cpp
==============================================================================
--- trunk/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.cpp (original)
+++ trunk/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.cpp 2011-02-28 01:06:50 EST (Mon, 28 Feb 2011)
@@ -9,8 +9,6 @@
 #include <boost/foreach.hpp>
 #include <boost/variant/apply_visitor.hpp>
 #include <boost/assert.hpp>
-#include <iostream>
-#include <string>
 
 namespace client
 {
@@ -54,80 +52,99 @@
         }
     }
 
- void compiler::operator()(unsigned int x) const
+ bool compiler::operator()(unsigned int x) const
     {
         program.op(op_int, x);
+ return true;
     }
 
- void compiler::operator()(ast::variable const& x) const
+ bool compiler::operator()(ast::variable const& x) const
     {
         int const* p = program.find_var(x.name);
         if (p == 0)
         {
- // $$$ undefined variable throw exception
- std::cout << "undefined variable: " << x.name << std::endl;
+ std::cout << x.id << std::endl;
+ error_handler(x.id, "Undeclared variable: " + x.name);
+ return false;
         }
         program.op(op_load, *p);
+ return true;
     }
 
- void compiler::operator()(ast::operation const& x) const
+ bool compiler::operator()(ast::operation const& x) const
     {
- boost::apply_visitor(*this, x.operand_);
+ if (!boost::apply_visitor(*this, x.operand_))
+ return false;
         switch (x.operator_)
         {
             case '+': program.op(op_add); break;
             case '-': program.op(op_sub); break;
             case '*': program.op(op_mul); break;
             case '/': program.op(op_div); break;
- default: BOOST_ASSERT(0); break;
+ default: BOOST_ASSERT(0); return false;
         }
+ return true;
     }
 
- void compiler::operator()(ast::signed_ const& x) const
+ bool compiler::operator()(ast::signed_ const& x) const
     {
- boost::apply_visitor(*this, x.operand_);
+ if (!boost::apply_visitor(*this, x.operand_))
+ return false;
         switch (x.sign)
         {
             case '-': program.op(op_neg); break;
             case '+': break;
- default: BOOST_ASSERT(0); break;
+ default: BOOST_ASSERT(0); return false;
         }
+ return true;
     }
 
- void compiler::operator()(ast::expression const& x) const
+ bool compiler::operator()(ast::expression const& x) const
     {
- boost::apply_visitor(*this, x.first);
+ if (!boost::apply_visitor(*this, x.first))
+ return false;
         BOOST_FOREACH(ast::operation const& oper, x.rest)
         {
- (*this)(oper);
+ if (!(*this)(oper))
+ return false;
         }
+ return true;
     }
 
- void compiler::operator()(ast::assignment const& x) const
+ bool compiler::operator()(ast::assignment const& x) const
     {
- (*this)(x.rhs);
+ if (!(*this)(x.rhs))
+ return false;
         int const* p = program.find_var(x.lhs.name);
         if (p == 0)
         {
- // $$$ undefined variable throw exception
- std::cout << "undefined variable: " << x.lhs.name << std::endl;
+ std::cout << x.lhs.id << std::endl;
+ error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name);
+ return false;
         }
         program.op(op_store, *p);
+ return true;
     }
 
- void compiler::operator()(ast::variable_declaration const& x) const
+ bool compiler::operator()(ast::variable_declaration const& x) const
     {
         int const* p = program.find_var(x.assign.lhs.name);
         if (p != 0)
         {
- // $$$ duplicate variable throw exception
- std::cout << "duplicate variable: " << x.assign.lhs.name << std::endl;
+ std::cout << x.assign.lhs.id << std::endl;
+ error_handler(x.assign.lhs.id, "Duplicate variable: " + x.assign.lhs.name);
+ return false;
         }
- program.add_var(x.assign.lhs.name);
- (*this)(x.assign);
+ bool r = (*this)(x.assign.rhs);
+ if (r) // don't add the variable if the RHS fails
+ {
+ program.add_var(x.assign.lhs.name);
+ program.op(op_store, *program.find_var(x.assign.lhs.name));
+ }
+ return r;
     }
 
- void compiler::operator()(ast::statement const& x) const
+ bool compiler::operator()(ast::statement const& x) const
     {
         typedef
             boost::variant<
@@ -135,22 +152,20 @@
                 ast::assignment>
         statement;
 
- try
- {
- program.clear();
+ program.clear();
 
- // op_adstk 0 for now. we'll know how many variables we'll have later
- program.op(op_adstk, 0);
- BOOST_FOREACH(statement const& s, x)
+ // op_adstk 0 for now. we'll know how many variables we'll have later
+ program.op(op_adstk, 0);
+ BOOST_FOREACH(statement const& s, x)
+ {
+ if (!boost::apply_visitor(*this, s))
             {
- boost::apply_visitor(*this, s);
+ program.clear();
+ return false;
             }
- program[1] = program.nvars(); // now store the actual number of variables
- }
- catch(...)
- {
- program.clear();
         }
+ program[1] = program.nvars(); // now store the actual number of variables
+ return true;
     }
 }
 

Modified: trunk/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.hpp
==============================================================================
--- trunk/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.hpp (original)
+++ trunk/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.hpp 2011-02-28 01:06:50 EST (Mon, 28 Feb 2011)
@@ -8,8 +8,13 @@
 #define BOOST_SPIRIT_CALC7_COMPILER_HPP
 
 #include "ast.hpp"
+#include "error_handler.hpp"
 #include <vector>
 #include <map>
+#include <boost/function.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_function.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
 
 namespace client
 {
@@ -44,22 +49,33 @@
     ///////////////////////////////////////////////////////////////////////////
     struct compiler
     {
- typedef void result_type;
+ typedef bool result_type;
 
- compiler(client::program& program)
- : program(program) {}
-
- void operator()(ast::nil) const { BOOST_ASSERT(0); }
- void operator()(unsigned int x) const;
- void operator()(ast::variable const& x) const;
- void operator()(ast::operation const& x) const;
- void operator()(ast::signed_ const& x) const;
- void operator()(ast::expression const& x) const;
- void operator()(ast::assignment const& x) const;
- void operator()(ast::variable_declaration const& x) const;
- void operator()(ast::statement const& x) const;
+ template <typename IterList, typename Iterator>
+ compiler(client::program& program, IterList const& iters, Iterator last)
+ : program(program)
+ {
+ using boost::phoenix::arg_names::_1;
+ using boost::phoenix::arg_names::_2;
+ using boost::phoenix::cref;
+ error_handler = client::error_handler("Error! ", _2, cref(iters)[_1], last);
+ }
+
+ bool operator()(ast::nil) const { BOOST_ASSERT(0); return false; }
+ bool operator()(unsigned int x) const;
+ bool operator()(ast::variable const& x) const;
+ bool operator()(ast::operation const& x) const;
+ bool operator()(ast::signed_ const& x) const;
+ bool operator()(ast::expression const& x) const;
+ bool operator()(ast::assignment const& x) const;
+ bool operator()(ast::variable_declaration const& x) const;
+ bool operator()(ast::statement const& x) const;
 
         client::program& program;
+
+ boost::function<
+ void(int tag, std::string const& what)>
+ error_handler;
     };
 }
 

Modified: trunk/libs/spirit/example/qi/compiler_tutorial/calc7/error_handler.hpp
==============================================================================
--- trunk/libs/spirit/example/qi/compiler_tutorial/calc7/error_handler.hpp (original)
+++ trunk/libs/spirit/example/qi/compiler_tutorial/calc7/error_handler.hpp 2011-02-28 01:06:50 EST (Mon, 28 Feb 2011)
@@ -7,13 +7,12 @@
 #if !defined(BOOST_SPIRIT_CALC7_ERROR_HANDLER_HPP)
 #define BOOST_SPIRIT_CALC7_ERROR_HANDLER_HPP
 
-#include <boost/spirit/include/support_info.hpp>
 #include <iostream>
 #include <string>
+#include <boost/spirit/include/phoenix_function.hpp>
 
 namespace client
 {
- namespace qi = boost::spirit::qi;
     using boost::phoenix::function;
 
     ///////////////////////////////////////////////////////////////////////////////
@@ -21,23 +20,32 @@
     ///////////////////////////////////////////////////////////////////////////////
     struct error_handler_
     {
- template <typename, typename, typename>
+ template <typename, typename, typename, typename>
         struct result { typedef void type; };
 
- template <typename Iterator>
- void operator()(
- boost::spirit::qi::info const& what
+ template <typename Message, typename What, typename Iterator>
+ void operator()(Message const& message, What const& what
           , Iterator err_pos, Iterator last) const
         {
             std::cout
- << "Error! Expecting "
- << what // what failed?
+ << message
+ << what
                 << " here: \""
- << std::string(err_pos, last) // iterators to error-pos, end
+ << get_line(err_pos, last)
                 << "\""
                 << std::endl
             ;
         }
+
+ template <typename Iterator>
+ std::string get_line(Iterator err_pos, Iterator last) const
+ {
+ Iterator i = err_pos;
+ // position i to the next EOL
+ while (i != last && (*i != '\r' && *i != '\n'))
+ ++i;
+ return std::string(err_pos, i);
+ }
     };
 
     boost::phoenix::function<error_handler_> const

Modified: trunk/libs/spirit/example/qi/compiler_tutorial/calc7/expression_def.hpp
==============================================================================
--- trunk/libs/spirit/example/qi/compiler_tutorial/calc7/expression_def.hpp (original)
+++ trunk/libs/spirit/example/qi/compiler_tutorial/calc7/expression_def.hpp 2011-02-28 01:06:50 EST (Mon, 28 Feb 2011)
@@ -14,12 +14,14 @@
     expression<Iterator>::expression()
       : expression::base_type(expr)
     {
- qi::char_type char_;
- qi::uint_type uint_;
- qi::_val_type _val;
+ qi::_1_type _1;
         qi::_2_type _2;
         qi::_3_type _3;
         qi::_4_type _4;
+
+ qi::char_type char_;
+ qi::uint_type uint_;
+ qi::_val_type _val;
         qi::raw_type raw;
         qi::lexeme_type lexeme;
         qi::alpha_type alpha;
@@ -74,13 +76,13 @@
         );
 
         // Error handling: on error in expr, call error_handler.
- on_error<fail>(expr, error_handler(_4, _3, _2));
+ on_error<fail>(expr, error_handler("Error! Expecting ", _4, _3, _2));
 
         // Annotation: on success in primary_expr, call annotation.
         typedef client::annotation<Iterator> annotation_;
         typename function<annotation_>
             annotation = annotation_(iters);
- on_success(primary_expr, annotation(_val, _3));
+ on_success(primary_expr, annotation(_val, _1));
     }
 }
 

Modified: trunk/libs/spirit/example/qi/compiler_tutorial/calc7/main.cpp
==============================================================================
--- trunk/libs/spirit/example/qi/compiler_tutorial/calc7/main.cpp (original)
+++ trunk/libs/spirit/example/qi/compiler_tutorial/calc7/main.cpp 2011-02-28 01:06:50 EST (Mon, 28 Feb 2011)
@@ -47,34 +47,37 @@
     iterator_type iter = source.begin();
     iterator_type end = source.end();
 
- client::vmachine vm; // Our virtual machine
- client::program program; // Our VM program
- client::statement<iterator_type> parser; // Our parser
- client::ast::statement ast; // Our AST
- client::compiler compile(program); // Our compiler
+ client::vmachine vm; // Our virtual machine
+ client::program program; // Our VM program
+ client::statement<iterator_type> parser; // Our parser
+ client::ast::statement ast; // Our AST
+ client::compiler
+ compile(program, parser.expr.iters, end); // Our compiler
 
     boost::spirit::ascii::space_type space;
- bool r = phrase_parse(iter, end, parser, space, ast);
+ bool success = phrase_parse(iter, end, parser, space, ast);
 
- if (r && iter == end)
+ std::cout << "-------------------------\n";
+
+ if (success && iter == end)
+ success = compile(ast);
+ else
+ std::cout << "Parsing failed\n";
+
+ if (success)
     {
- std::cout << "-------------------------\n";
- std::cout << "Parsing succeeded\n";
- compile(ast);
+ std::cout << "Success\n";
         vm.execute(program());
 
         std::cout << "Results------------------\n\n";
         program.print_variables(vm.get_stack());
- std::cout << "-------------------------\n\n";
     }
     else
     {
- std::string rest(iter, end);
- std::cout << "-------------------------\n";
- std::cout << "Parsing failed\n";
- std::cout << "-------------------------\n";
+ std::cout << "Compiling failed\n";
     }
 
+ std::cout << "-------------------------\n\n";
     return 0;
 }
 

Modified: trunk/libs/spirit/example/qi/compiler_tutorial/calc7/statement_def.hpp
==============================================================================
--- trunk/libs/spirit/example/qi/compiler_tutorial/calc7/statement_def.hpp (original)
+++ trunk/libs/spirit/example/qi/compiler_tutorial/calc7/statement_def.hpp 2011-02-28 01:06:50 EST (Mon, 28 Feb 2011)
@@ -14,10 +14,12 @@
     statement<Iterator>::statement()
       : statement::base_type(start)
     {
- qi::_val_type _val;
+ qi::_1_type _1;
         qi::_2_type _2;
         qi::_3_type _3;
         qi::_4_type _4;
+
+ qi::_val_type _val;
         qi::raw_type raw;
         qi::lexeme_type lexeme;
         qi::alpha_type alpha;
@@ -56,13 +58,13 @@
         );
 
         // Error handling: on error in start, call error_handler.
- on_error<fail>(start, error_handler(_4, _3, _2));
+ on_error<fail>(start, error_handler("Error! Expecting ", _4, _3, _2));
 
         // Annotation: on success in variable, call annotation.
         typedef client::annotation<Iterator> annotation_;
         typename function<annotation_>
             annotation = annotation_(expr.iters);
- on_success(assignment, annotation(_val, _3));
+ on_success(assignment, annotation(_val, _1));
     }
 }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk