Add rudimentary error messages to the special nodes parser
- It tells you the line number, but not the nature of the error - Unfortunately it can't currently cope with files that don't end in a newline
This commit is contained in:
@@ -10,4 +10,4 @@ def Varn = 3
|
||||
msg 2 # Shows string 2; the omitted argument is assumed to be -1
|
||||
@town-visible = 5 # Explicitly specify node number
|
||||
msg 3,4 # Shows strings 3 and 4 in the message dialog
|
||||
ex1 Varn,1 # Town 3, set visibility to true
|
||||
ex1 Varn,1 # Town 3, set visibility to true
|
||||
|
@@ -12,11 +12,24 @@
|
||||
#include "special.h"
|
||||
#include <boost/spirit/include/classic.hpp>
|
||||
|
||||
enum eParseError {
|
||||
generic_error,
|
||||
expect_op,
|
||||
expect_def,
|
||||
expect_dat,
|
||||
expect_eq,
|
||||
expect_int,
|
||||
expect_val,
|
||||
};
|
||||
|
||||
namespace spirit = boost::spirit::classic;
|
||||
typedef spirit::rule<> Rule;
|
||||
typedef spirit::assertion<eParseError> Err;
|
||||
typedef spirit::guard<eParseError> Guard;
|
||||
|
||||
class SpecialParser {
|
||||
using Iter = Rule::scanner_t::iterator_t;
|
||||
using ErrStatus = spirit::error_status<>;
|
||||
static void init_file(Iter, Iter);
|
||||
static void init_block(Iter, Iter);
|
||||
static void prep_add_symbol(Iter, Iter);
|
||||
@@ -33,18 +46,23 @@ class SpecialParser {
|
||||
static void set_first(int i);
|
||||
static void set_second(int i);
|
||||
static void set_third(int i);
|
||||
static void next_line(Iter, Iter);
|
||||
static std::string temp_symbol;
|
||||
static int cur_node, cur_fld;
|
||||
static cSpecial curSpec;
|
||||
static int lineno, last_line_start;
|
||||
static Iter file_start;
|
||||
static std::map<size_t, cSpecial> specials;
|
||||
static spirit::symbols<> defn;
|
||||
static Rule ws, comment, symbol, symbol_ch;
|
||||
static Rule ws, comment, symbol, symbol_ch, eol;
|
||||
static Rule datcode, command, init_line, null_line, def_line, cmd_line, op_line, cmd_block, nodes_file;
|
||||
static Err err;
|
||||
static Guard guard;
|
||||
static bool grammar_built;
|
||||
static ErrStatus on_error(const Rule::scanner_t&, spirit::parser_error<eParseError, Iter>);
|
||||
public:
|
||||
SpecialParser();
|
||||
std::map<size_t,cSpecial> parse(std::string code);
|
||||
void init_debug();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -25,10 +25,14 @@ int SpecialParser::cur_node, SpecialParser::cur_fld;
|
||||
cSpecial SpecialParser::curSpec;
|
||||
std::map<size_t, cSpecial> SpecialParser::specials;
|
||||
spirit::symbols<> SpecialParser::defn;
|
||||
Rule SpecialParser::ws, SpecialParser::comment, SpecialParser::symbol, SpecialParser::symbol_ch;
|
||||
Rule SpecialParser::ws, SpecialParser::comment, SpecialParser::symbol, SpecialParser::symbol_ch, SpecialParser::eol;
|
||||
Rule SpecialParser::datcode, SpecialParser::command, SpecialParser::def_line, SpecialParser::cmd_line;
|
||||
Rule SpecialParser::init_line, SpecialParser::null_line;
|
||||
Rule SpecialParser::op_line, SpecialParser::cmd_block, SpecialParser::nodes_file;
|
||||
int SpecialParser::lineno, SpecialParser::last_line_start;
|
||||
SpecialParser::Iter SpecialParser::file_start;
|
||||
Err SpecialParser::err(generic_error);
|
||||
Guard SpecialParser::guard;
|
||||
|
||||
SpecialParser::SpecialParser() {
|
||||
if(grammar_built) return;
|
||||
@@ -37,6 +41,7 @@ SpecialParser::SpecialParser() {
|
||||
comment = ch_p('#') >> *(range_p('!','~') | ws);
|
||||
symbol_ch = chset<>("A-Za-z$_-");
|
||||
symbol = symbol_ch >> *symbol_ch;
|
||||
eol = eol_p[_(next_line)];
|
||||
|
||||
datcode = str_p("sdf")[_(for_sdf)] | str_p("pic")[_(for_pic)] | str_p("msg")[_(for_msg)] |
|
||||
str_p("ex1")[_(for_ex1)] | str_p("ex2")[_(for_ex2)] | str_p("goto")[_(for_goto)];
|
||||
@@ -45,20 +50,41 @@ SpecialParser::SpecialParser() {
|
||||
!(*ws >> ch_p(',') >> *ws >> (int_p[_(set_second)] | defn[_(set_second)]) >>
|
||||
!(*ws >> ch_p(',') >> *ws >> (int_p[_(set_third)] | defn[_(set_third)])));
|
||||
|
||||
null_line = !comment >> eol_p;
|
||||
null_line = !comment >> eol;
|
||||
init_line = null_line | def_line;
|
||||
def_line = str_p("def") >> +ws >> symbol[_(prep_add_symbol)] >> *ws >> ch_p('=') >> *ws >> int_p[_(add_symbol)] >> *ws >> !comment >> eol_p;
|
||||
cmd_line = command >> *ws >> !comment >> eol_p;
|
||||
op_line = ch_p('@') >> opcode[_(set_type)] >> *ws >> !(ch_p('=') >> *ws >> int_p[_(skip_to)]) >> *ws >> !comment >> eol_p;
|
||||
def_line = str_p("def") >> +ws >> symbol[_(prep_add_symbol)] >> *ws >> ch_p('=') >> *ws >> int_p[_(add_symbol)] >> *ws >> !comment >> eol;
|
||||
cmd_line = command >> *ws >> !comment >> eol;
|
||||
op_line = ch_p('@') >> opcode[_(set_type)] >> *ws >> !(ch_p('=') >> *ws >> int_p[_(skip_to)]) >> *ws >> !comment >> eol;
|
||||
|
||||
cmd_block = eps_p[_(init_block)] >> op_line >> *(*ws >> (cmd_line | def_line | null_line));
|
||||
|
||||
nodes_file = eps_p[_(init_file)] >> *(*ws >> init_line) >> *cmd_block[_(add_command)] >> end_p;
|
||||
// TODO: This fails if the file doesn't end in a newline.
|
||||
nodes_file = /*guard*/err(eps_p[_(init_file)] >> *(*ws >> init_line) >> *cmd_block[_(add_command)] >> end_p);//[_(on_error)];
|
||||
|
||||
// Debugging. If BOOST_SPIRIT_DEBUG not defined, all these expand to nothing.
|
||||
BOOST_SPIRIT_DEBUG_NODE(ws);
|
||||
BOOST_SPIRIT_DEBUG_NODE(eol);
|
||||
BOOST_SPIRIT_DEBUG_NODE(comment);
|
||||
BOOST_SPIRIT_DEBUG_NODE(symbol);
|
||||
BOOST_SPIRIT_DEBUG_NODE(symbol_ch);
|
||||
BOOST_SPIRIT_DEBUG_NODE(datcode);
|
||||
BOOST_SPIRIT_DEBUG_NODE(command);
|
||||
BOOST_SPIRIT_DEBUG_NODE(def_line);
|
||||
BOOST_SPIRIT_DEBUG_NODE(cmd_line);
|
||||
BOOST_SPIRIT_DEBUG_NODE(init_line);
|
||||
BOOST_SPIRIT_DEBUG_NODE(null_line);
|
||||
BOOST_SPIRIT_DEBUG_NODE(op_line);
|
||||
BOOST_SPIRIT_DEBUG_NODE(cmd_block);
|
||||
BOOST_SPIRIT_DEBUG_NODE(nodes_file);
|
||||
|
||||
grammar_built = true;
|
||||
}
|
||||
|
||||
#undef A
|
||||
#undef _
|
||||
|
||||
auto SpecialParser::on_error(const Rule::scanner_t& scan, spirit::parser_error<eParseError, Iter> error) -> ErrStatus {
|
||||
return ErrStatus(ErrStatus::fail);
|
||||
}
|
||||
|
||||
void init_specials_parse() {
|
||||
opcode.add((*eSpecType::NONE).opcode().c_str(), eSpecType::NONE);
|
||||
@@ -78,9 +104,17 @@ void init_specials_parse() {
|
||||
}
|
||||
}
|
||||
|
||||
void SpecialParser::init_file(Iter, Iter) {
|
||||
void SpecialParser::init_file(Iter start, Iter) {
|
||||
file_start = start;
|
||||
specials.clear();
|
||||
cur_node = -1;
|
||||
lineno = 1;
|
||||
last_line_start = 0;
|
||||
}
|
||||
|
||||
void SpecialParser::next_line(Iter, Iter end) {
|
||||
lineno++;
|
||||
last_line_start = end - file_start;
|
||||
}
|
||||
|
||||
void SpecialParser::init_block(Iter, Iter) {
|
||||
@@ -156,7 +190,8 @@ void SpecialParser::set_first(int i) {
|
||||
case 3: curSpec.ex1a = i; break;
|
||||
case 4: curSpec.ex2a = i; break;
|
||||
case 5: curSpec.jumpto = i; break;
|
||||
default: bool pass = false; break;
|
||||
// TODO: Figure out how to get an iterator to the matched number
|
||||
//default: throw spirit::parser_error(start, generic_error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +202,8 @@ void SpecialParser::set_second(int i) {
|
||||
case 2: curSpec.m2 = i; break;
|
||||
case 3: curSpec.ex1b = i; break;
|
||||
case 4: curSpec.ex2b = i; break;
|
||||
default: bool pass = false; break;
|
||||
// TODO: Figure out how to get an iterator to the matched number
|
||||
//default: throw spirit::parser_error(start, generic_error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,28 +212,27 @@ void SpecialParser::set_third(int i) {
|
||||
case 2: curSpec.m3 = i; break;
|
||||
case 3: curSpec.ex1c = i; break;
|
||||
case 4: curSpec.ex2c = i; break;
|
||||
default: bool pass = false; break;
|
||||
// TODO: Figure out how to get an iterator to the matched number
|
||||
//default: throw spirit::parser_error(start, generic_error);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<size_t,cSpecial> SpecialParser::parse(std::string code) {
|
||||
static bool inited = false;
|
||||
if(!inited) init_specials_parse();
|
||||
auto result = spirit::parse(code.c_str(), nodes_file);
|
||||
const char* code_raw = code.c_str();
|
||||
try {
|
||||
auto result = spirit::parse(code_raw, nodes_file);
|
||||
(void) result; // Mark the variable unused
|
||||
} catch(spirit::parser_error<eParseError> x) {
|
||||
int offset = x.where - code_raw;
|
||||
int col = offset - last_line_start;
|
||||
(void) col; // Mark the variable unused
|
||||
std::cerr << "Parse error on line " << lineno << std::endl;
|
||||
}
|
||||
return specials;
|
||||
}
|
||||
|
||||
void SpecialParser::init_debug() {
|
||||
// BOOST_SPIRIT_DEBUG_NODE(comment);
|
||||
// BOOST_SPIRIT_DEBUG_NODE(datcode);
|
||||
// BOOST_SPIRIT_DEBUG_NODE(command);
|
||||
// BOOST_SPIRIT_DEBUG_NODE(def_line);
|
||||
// BOOST_SPIRIT_DEBUG_NODE(cmd_line);
|
||||
// BOOST_SPIRIT_DEBUG_NODE(op_line);
|
||||
// BOOST_SPIRIT_DEBUG_NODE(cmd_block);
|
||||
// BOOST_SPIRIT_DEBUG_NODE(nodes_file);
|
||||
}
|
||||
|
||||
void test_special_parse(std::string file); // Suppress "no prototype" warning
|
||||
void test_special_parse(std::string file) {
|
||||
std::ostringstream code;
|
||||
@@ -205,7 +240,6 @@ void test_special_parse(std::string file) {
|
||||
code << fin.rdbuf();
|
||||
fin.close();
|
||||
SpecialParser parser;
|
||||
parser.init_debug();
|
||||
auto specials = parser.parse(code.str());
|
||||
std::ofstream fout(file + ".out");
|
||||
for(auto p : specials) {
|
||||
|
Reference in New Issue
Block a user