Re: Need to improve syntax error diagnostic message for Spirit grammar
"Mccall, Kurt E. \(MSFC-EV41\) via Spirit-general" <[email protected]> Thu, 24 Sep 2020 18:31:14 +0000
| Newsgroups | gmane.comp.parsers.spirit.general |
|---|---|
| Message-ID | <SA9PR09MB5808E57596468C65A17609E1C6390@SA9PR09MB5808.namprd09.prod.outlook.com> |
Seth,
I tried to imitate your example, but my code is still not pointing to the missing double quote in my input string. The error message is:
error: line 3 col 23: Missing ending semicolon
liftoff2 = "time > 0.35";
^-- here
Parsing failed
Here is the self-contained example, hopefully less of a jigsaw puzzle.
************************************
#include <iostream>
#include <map>
#include <string>
#include <iomanip>
#include "/opt/boost_pgc/include/boost/spirit/include/qi.hpp"
#include "/opt/boost_pgc/include/boost/spirit/include/qi_expect.hpp"
#include "/opt/boost_pgc/include/boost/spirit/home/support/iterators/line_pos_iterator.hpp"
#include "/opt/boost_pgc/include/boost/locale.hpp"
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
using qi::eps;
using qi::lexeme;
using ascii::char_;
using ascii::space;
// for on_error
using qi::on_error;
using qi::fail;
using phoenix::val;
using std::cout;
using std::cerr;
using std::endl;
using std::string;
using Position_Itr_T = boost::spirit::line_pos_iterator<std::string::iterator>;
template <typename Iterator, typename Skipper>
class Grammar4 : boost::spirit::qi::grammar<Iterator, Skipper>
{
public:
using rule_T = boost::spirit::qi::rule<Iterator>;
using rule_nil_T = boost::spirit::qi::rule<Iterator, Skipper>;
using rule_str_T = boost::spirit::qi::rule<Iterator, string()>;
// thanks for this idea!
using diagnostics = std::map<std::string, std::string>;
struct error_handler_impl
{
template <typename, typename, typename, typename, typename> struct result {
typedef void type;
};
template <typename D, typename I>
void operator()(D& _diagnostics, Iterator _begin,
Iterator _end, Iterator _where,
I const& _info) const {
string const& tag(_info.tag);
string const scratch = "Invalid syntax: expected " + tag;
string const scratch2 = "Missing ";
auto diagnostic(_diagnostics[tag]);
if (diagnostic.empty())
diagnostic = scratch;
else
diagnostic = scratch2 + diagnostic;
// raise_parsing_error(diagnostic, _begin, _end, _where);
auto bol = get_line_start(_begin, _where);
auto eol = get_line_end(_where, _end);
auto line = get_line(_where);
auto col = get_column(bol, _where);
std::string subject(bol, eol);
auto pos = std::distance(bol, _where);
cerr << "error: line " << line << " col " << col << ": " << diagnostic << "\n";
cerr << subject << "\n";
cerr << std::setw(pos) << "" << "^-- here\n";
}
};
diagnostics d0, d1, d2, d3;
boost::phoenix::function<error_handler_impl> error_handler;
rule_T comma, colon, semi, equals, keyword_events, dquote;
rule_str_T ident, quoted_str;
rule_nil_T start, event_list, event;
Grammar4(void) : Grammar4::base_type{start}
{
comma = ','; comma.name(",");
colon = ':'; colon.name(":");
semi = ';'; semi.name(";");
equals = '='; equals.name("=");
dquote = '"'; dquote.name("\"");
keyword_events = "events";
ident = lexeme [ qi::raw [ (qi::alpha | '_') >> *(qi::alnum | '_') ] ];
quoted_str = lexeme [ dquote > +(char_ - '"') > dquote ];
//d0 = {
// { dquote.name(), "double quote" }
//};
ident.name("ident");
quoted_str.name("quoted_str");
start.name("start");
keyword_events.name("keyword_events");
event_list.name("event_list");
event.name("event");
start
= eps
> keyword_events
> colon
> event_list
> semi
> qi::eoi
;
d1 = {
{ keyword_events.name(), "events keyword" },
{ colon.name(), "colon after events keyword" },
{ event_list.name(), "event list", },
{ semi.name(), "ending semicolon" }
};
event_list
= eps
> event % comma
;
d2 = {
{ event.name(), "event definition" },
{ comma.name(), "comma" }
};
event
= eps
> ident
> equals
> quoted_str
;
d3 = {
{ ident.name(), "identifier" },
{ equals.name(), "equals sign" },
{ quoted_str.name(), "quoted C-expression string" }
};
//auto handler_bind0 = error_handler(phoenix::ref(d0), qi::_1, qi::_2, qi::_3, qi::_4);
auto handler_bind1 = error_handler(phoenix::ref(d1), qi::_1, qi::_2, qi::_3, qi::_4);
auto handler_bind2 = error_handler(phoenix::ref(d2), qi::_1, qi::_2, qi::_3, qi::_4);
auto handler_bind3 = error_handler(phoenix::ref(d3), qi::_1, qi::_2, qi::_3, qi::_4);
//on_error<fail>(quoted_str, handler_bind0);
on_error<fail>(start, handler_bind1);
on_error<fail>(event_list, handler_bind2);
on_error<fail>(event, handler_bind3);
}
~Grammar4(void) { };
void parseInputFile(Iterator itr, Iterator itr_end)
{
try {
bool r = phrase_parse(itr, itr_end, start, space);
if (r) cout << "Parsing succeeded\n";
else cout << "Parsing failed\n";
} catch (qi::expectation_failure<Position_Itr_T> const& ef)
{
cout << "Parsing failed2\n";
//std::cout << "what 1: " << ef.what() << "\n";
//std::cout << "what 2: " << ef.what_ << "\n";
}
}
};
int main(int argc, char **argv)
{
boost::locale::generator gen;
std::locale loc = gen("en_US.UTF-8");
cout.imbue(loc);
Grammar4<Position_Itr_T, boost::spirit::ascii::space_type> g;
// SYNTAX ERROR: missing closing double quote after time > 0.25
string input("events : \n \
liftoff = \"time > 0.25, \n \
liftoff2 = \"time > 0.35\";");
Position_Itr_T begin(input.begin());
Position_Itr_T end(input.end());
g.parseInputFile(begin, end);
return 0;
};
_______________________________________________
Spirit-general mailing list
[email protected]
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.sourceforge.net_lists_listinfo_spirit-2Dgeneral&d=DwICAg&c=ApwzowJNAKKw3xye91w7BE1XMRKi2LN9kiMk5Csz9Zk&r=6cP1IfXu3IZOHSDh_vBqciYiIh4uuVgs1MSi5K7l5fQ&m=JQv3mClgVZPLRAmss85i3oF_jcnuGGJhiPqwdIMlHkk&s=_bKJ982Q1OiWqSD7sijWnuzIZN0HoBj2AinndrUuMLw&e=
_______________________________________________
Spirit-general mailing list
[email protected]
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.sourceforge.net_lists_listinfo_spirit-2Dgeneral&d=DwICAg&c=ApwzowJNAKKw3xye91w7BE1XMRKi2LN9kiMk5Csz9Zk&r=6cP1IfXu3IZOHSDh_vBqciYiIh4uuVgs1MSi5K7l5fQ&m=MRjyf7v_iV5tkJSmWgAboOnAQQlSXc9uj9tZ3UN_FSs&s=cJPsFURy9_ClYFBDfvHj68wgV1xrWH476-9iAI0We10&e=