diff --git a/language/interpreter.cc b/language/interpreter.cc index 0f0f7aa..12d0a8a 100644 --- a/language/interpreter.cc +++ b/language/interpreter.cc @@ -1,5 +1,6 @@ #include "interpreter.hpp" #include "parser.hpp" +#include using namespace peglib; using namespace std; @@ -187,19 +188,28 @@ std::ostream& operator<<(std::ostream& os, const Value& val) return val.out(os); } -bool run(Env& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast) +bool run(const string& path, Env& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast) { try { shared_ptr ast; - if (get_parser().parse_n(expr, len, ast)) { + + auto& parser = get_parser(); + + parser.log = [&](size_t ln, size_t col, const string& err_msg) { + stringstream ss; + ss << path << ":" << ln << ":" << col << ": " << err_msg << endl; + msg = ss.str(); + }; + + if (parser.parse_n(expr, len, ast)) { if (print_ast) { ast->print(); } val = Eval::eval(*ast, env); return true; - } - } catch (exception& e) { + } + } catch (runtime_error& e) { msg = e.what(); } diff --git a/language/interpreter.hpp b/language/interpreter.hpp index d7555ca..a72d829 100644 --- a/language/interpreter.hpp +++ b/language/interpreter.hpp @@ -193,4 +193,4 @@ private: std::map dic_; }; -bool run(Env& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast); +bool run(const std::string& path, Env& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast); diff --git a/language/main.cc b/language/main.cc index 032d72c..376dd81 100644 --- a/language/main.cc +++ b/language/main.cc @@ -44,27 +44,31 @@ int main(int argc, const char** argv) shell = path_list.empty(); } - Env env; - env.setup_built_in_functions(); + try { + Env env; + env.setup_built_in_functions(); - for (auto path: path_list) { - vector buff; - if (!read_file(path, buff)) { - cerr << "can't open '" << path << "'." << endl; - return -1; + for (auto path: path_list) { + vector buff; + if (!read_file(path, buff)) { + cerr << "can't open '" << path << "'." << endl; + return -1; + } + + Value val; + string msg; + if (!run(path, env, buff.data(), buff.size(), val, msg, print_ast)) { + cerr << msg; + return -1; + } } - Value val; - string msg; - if (!run(env, buff.data(), buff.size(), val, msg, print_ast)) { - cerr << "error in '" << path << "'." << endl; - cerr << msg.c_str() << endl; - return -1; + if (shell) { + repl(env, print_ast); } - } - - if (shell) { - repl(env, print_ast); + } catch (exception& e) { + cerr << e.what() << endl; + return -1; } return 0; diff --git a/language/parser.cc b/language/parser.cc index 23f9068..2ab992f 100644 --- a/language/parser.cc +++ b/language/parser.cc @@ -40,33 +40,46 @@ static auto g_grammar = R"( Comment <- '/*' (!'*/' .)* '*/' / ('#' / '//') (!(EndOfLine / EndOfFile) .)* (EndOfLine / EndOfFile) )"; -static auto g_parser = peg(g_grammar) - .ast_node_optimizable("STATEMENTS", Statements) - .ast_node("WHILE", While) - .ast_node("ASSIGNMENT", Assignment) - .ast_node("IF", If) - .ast_node("FUNCTION", Function) - .ast_node("PARAMETERS") - .ast_node("FUNCTION_CALL", FunctionCall) - .ast_node("ARGUMENTS") - .ast_node_optimizable("PRIMARY", Condition) - .ast_node_optimizable("CONDITION", BinExpresion) - .ast_node_optimizable("TERM", BinExpresion) - .ast_token("CONDITION_OPERATOR") - .ast_token("TERM_OPERATOR") - .ast_token("FACTOR_OPERATOR") - .ast_token("NUMBER", Number) - .ast_token("BOOLEAN", Boolean) - .ast_token("STRING") - .ast_token("IDENTIFIER", Identifier) - .ast_end() - .set_logger([&](size_t ln, size_t col, const string& msg) { - cerr << ln << ":" << col << ": " << msg << endl; - }); - -const peglib::peg& get_parser() +peglib::peg& get_parser() { - return g_parser; + static peg parser; + + static bool initialized = false; + + if (!initialized) { + initialized = true; + + parser.log = [&](size_t ln, size_t col, const string& msg) { + cerr << ln << ":" << col << ": " << msg << endl; + }; + + if (!parser.load_grammar(g_grammar)) { + throw logic_error("invalid peg grammar"); + } + + parser + .ast_node_optimizable("STATEMENTS", Statements) + .ast_node("WHILE", While) + .ast_node("ASSIGNMENT", Assignment) + .ast_node("IF", If) + .ast_node("FUNCTION", Function) + .ast_node("PARAMETERS") + .ast_node("FUNCTION_CALL", FunctionCall) + .ast_node("ARGUMENTS") + .ast_node_optimizable("PRIMARY", Condition) + .ast_node_optimizable("CONDITION", BinExpresion) + .ast_node_optimizable("TERM", BinExpresion) + .ast_token("CONDITION_OPERATOR") + .ast_token("TERM_OPERATOR") + .ast_token("FACTOR_OPERATOR") + .ast_token("NUMBER", Number) + .ast_token("BOOLEAN", Boolean) + .ast_token("STRING") + .ast_token("IDENTIFIER", Identifier) + .ast_end(); + } + + return parser; } // vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/language/parser.hpp b/language/parser.hpp index dee8a6f..fc1c9e2 100644 --- a/language/parser.hpp +++ b/language/parser.hpp @@ -6,6 +6,6 @@ enum AstType Identifier, Number, Boolean, Function }; -const peglib::peg& get_parser(); +peglib::peg& get_parser(); // vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/language/repl.cc b/language/repl.cc index 590d66b..688b18a 100644 --- a/language/repl.cc +++ b/language/repl.cc @@ -16,11 +16,11 @@ int repl(Env& env, bool print_ast) if (!line.empty()) { Value val; string msg; - if (run(env, line.c_str(), line.size(), val, msg, print_ast)) { + if (run("(repl)", env, line.c_str(), line.size(), val, msg, print_ast)) { cout << val << endl; linenoise::AddHistory(line.c_str()); } else if (!msg.empty()) { - cout << msg << endl; + cout << msg; } } }