mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Fixed problem with AST.
This commit is contained in:
parent
de1f7ebad6
commit
aa78055654
@ -55,7 +55,7 @@ int main(int argc, const char** argv)
|
|||||||
shared_ptr<Ast> ast;
|
shared_ptr<Ast> ast;
|
||||||
if (parser.parse(expr, ast)) {
|
if (parser.parse(expr, ast)) {
|
||||||
ast = AstOptimizer(true).optimize(ast);
|
ast = AstOptimizer(true).optimize(ast);
|
||||||
ast->print();
|
AstPrint::print(ast);
|
||||||
cout << expr << " = " << eval(*ast) << endl;
|
cout << expr << " = " << eval(*ast) << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
203
example/pl0.cc
203
example/pl0.cc
@ -78,11 +78,11 @@ bool read_file(const char* path, vector<char>& buff)
|
|||||||
/*
|
/*
|
||||||
* Ast
|
* Ast
|
||||||
*/
|
*/
|
||||||
struct Scope;
|
struct SymbolScope;
|
||||||
|
|
||||||
struct Annotation
|
struct Annotation
|
||||||
{
|
{
|
||||||
shared_ptr<Scope> scope;
|
shared_ptr<SymbolScope> scope;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef AstBase<Annotation> AstPL0;
|
typedef AstBase<Annotation> AstPL0;
|
||||||
@ -90,142 +90,124 @@ typedef AstBase<Annotation> AstPL0;
|
|||||||
/*
|
/*
|
||||||
* Symbol Table
|
* Symbol Table
|
||||||
*/
|
*/
|
||||||
struct Symbol {
|
struct SymbolScope
|
||||||
int value;
|
|
||||||
bool is_constant;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Scope
|
|
||||||
{
|
{
|
||||||
Scope(shared_ptr<Scope> outer = nullptr) : outer(outer) {}
|
SymbolScope(shared_ptr<SymbolScope> outer) : outer(outer) {}
|
||||||
|
|
||||||
bool has_symbol(const string& ident) const {
|
bool has_symbol(const string& ident) const {
|
||||||
auto it = symbols.find(ident);
|
auto ret = constants.find(ident) != constants.end() || variables.find(ident) != variables.end();
|
||||||
if (it != symbols.end()) {
|
return ret ? true : (outer ? outer->has_symbol(ident) : false);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return outer ? outer->has_symbol(ident) : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_constant(const string& ident) const {
|
bool has_constant(const string& ident) const {
|
||||||
auto it = symbols.find(ident);
|
auto ret = constants.find(ident) != constants.end();
|
||||||
if (it != symbols.end() && it->second.is_constant) {
|
return ret ? true : (outer ? outer->has_constant(ident) : false);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return outer ? outer->has_constant(ident) : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_variable(const string& ident) const {
|
bool has_variable(const string& ident) const {
|
||||||
auto it = symbols.find(ident);
|
auto ret = variables.find(ident) != variables.end();
|
||||||
if (it != symbols.end() && !it->second.is_constant) {
|
return ret ? true : (outer ? outer->has_variable(ident) : false);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return outer ? outer->has_variable(ident) : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_procedure(const string& ident) const {
|
bool has_procedure(const string& ident) const {
|
||||||
auto it = procedures.find(ident);
|
auto ret = procedures.find(ident) != procedures.end();
|
||||||
if (it != procedures.end()) {
|
return ret ? true : (outer ? outer->has_procedure(ident) : false);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return outer ? outer->has_procedure(ident) : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<AstPL0> get_procedure(const string& ident) const {
|
map<string, int> constants;
|
||||||
auto it = procedures.find(ident);
|
set<string> variables;
|
||||||
if (it != procedures.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
return outer->get_procedure(ident);
|
|
||||||
}
|
|
||||||
|
|
||||||
map<string, Symbol> symbols;
|
|
||||||
map<string, shared_ptr<AstPL0>> procedures;
|
map<string, shared_ptr<AstPL0>> procedures;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
shared_ptr<Scope> outer;
|
shared_ptr<SymbolScope> outer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void throw_runtime_error(const shared_ptr<AstPL0> node, const string& msg) {
|
||||||
|
throw runtime_error(format_error_message(node->path, node->line, node->column, msg));
|
||||||
|
}
|
||||||
|
|
||||||
struct SymbolTable
|
struct SymbolTable
|
||||||
{
|
{
|
||||||
static void build(const shared_ptr<AstPL0> ast, shared_ptr<Scope> scope = nullptr) {
|
static void build_on_ast(const shared_ptr<AstPL0> ast, shared_ptr<SymbolScope> scope = nullptr) {
|
||||||
switch (ast->tag) {
|
switch (ast->tag) {
|
||||||
case "block"_: visit_block(ast, scope); break;
|
case "block"_: block(ast, scope); break;
|
||||||
case "assignment"_: visit_assignment(ast, scope); break;
|
case "assignment"_: assignment(ast, scope); break;
|
||||||
case "call"_: visit_call(ast, scope); break;
|
case "call"_: call(ast, scope); break;
|
||||||
case "ident"_: visit_ident(ast, scope); break;
|
case "ident"_: ident(ast, scope); break;
|
||||||
default: for (auto node: ast->nodes) { build(node, scope); } break;
|
default: for (auto node: ast->nodes) { build_on_ast(node, scope); } break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void visit_block(const shared_ptr<AstPL0> ast, shared_ptr<Scope> outer) {
|
static void block(const shared_ptr<AstPL0> ast, shared_ptr<SymbolScope> outer) {
|
||||||
// block <- const var procedure statement
|
// block <- const var procedure statement
|
||||||
auto scope = make_shared<Scope>(outer);
|
auto scope = make_shared<SymbolScope>(outer);
|
||||||
const auto& nodes = ast->nodes;
|
const auto& nodes = ast->nodes;
|
||||||
visit_constants(nodes[0], scope);
|
constants(nodes[0], scope);
|
||||||
visit_variables(nodes[1], scope);
|
variables(nodes[1], scope);
|
||||||
visit_procedures(nodes[2], scope);
|
procedures(nodes[2], scope);
|
||||||
build(nodes[3], scope);
|
build_on_ast(nodes[3], scope);
|
||||||
ast->scope = scope;
|
ast->scope = scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void visit_constants(const shared_ptr<AstPL0> ast, shared_ptr<Scope> scope) {
|
static void constants(const shared_ptr<AstPL0> ast, shared_ptr<SymbolScope> scope) {
|
||||||
// const <- ('CONST' _ ident '=' _ number(',' _ ident '=' _ number)* ';' _) ?
|
// const <- ('CONST' _ ident '=' _ number(',' _ ident '=' _ number)* ';' _) ?
|
||||||
const auto& nodes = ast->nodes;
|
const auto& nodes = ast->nodes;
|
||||||
for (auto i = 0u; i < nodes.size(); i += 2) {
|
for (auto i = 0u; i < nodes.size(); i += 2) {
|
||||||
const auto& ident = nodes[i + 0]->token;
|
const auto& ident = nodes[i + 0]->token;
|
||||||
|
if (scope->has_symbol(ident)) {
|
||||||
|
throw_runtime_error(nodes[i], "'" + ident + "' is already defined...");
|
||||||
|
}
|
||||||
auto number = stoi(nodes[i + 1]->token);
|
auto number = stoi(nodes[i + 1]->token);
|
||||||
scope->symbols.emplace(ident, Symbol{ number, true });
|
scope->constants.emplace(ident, number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void visit_variables(const shared_ptr<AstPL0> ast, shared_ptr<Scope> scope) {
|
static void variables(const shared_ptr<AstPL0> ast, shared_ptr<SymbolScope> scope) {
|
||||||
// var <- ('VAR' _ ident(',' _ ident)* ';' _) ?
|
// var <- ('VAR' _ ident(',' _ ident)* ';' _) ?
|
||||||
const auto& nodes = ast->nodes;
|
const auto& nodes = ast->nodes;
|
||||||
for (auto i = 0u; i < nodes.size(); i += 1) {
|
for (auto i = 0u; i < nodes.size(); i += 1) {
|
||||||
const auto& ident = nodes[i]->token;
|
const auto& ident = nodes[i]->token;
|
||||||
scope->symbols.emplace(ident, Symbol{ 0, false });
|
if (scope->has_symbol(ident)) {
|
||||||
|
throw_runtime_error(nodes[i], "'" + ident + "' is already defined...");
|
||||||
|
}
|
||||||
|
scope->variables.emplace(ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void visit_procedures(const shared_ptr<AstPL0> ast, shared_ptr<Scope> scope) {
|
static void procedures(const shared_ptr<AstPL0> ast, shared_ptr<SymbolScope> scope) {
|
||||||
// procedure <- ('PROCEDURE' _ ident ';' _ block ';' _)*
|
// procedure <- ('PROCEDURE' _ ident ';' _ block ';' _)*
|
||||||
const auto& nodes = ast->nodes;
|
const auto& nodes = ast->nodes;
|
||||||
for (auto i = 0u; i < nodes.size(); i += 2) {
|
for (auto i = 0u; i < nodes.size(); i += 2) {
|
||||||
const auto& ident = nodes[i + 0]->token;
|
const auto& ident = nodes[i + 0]->token;
|
||||||
auto block = nodes[i + 1];
|
auto block = nodes[i + 1];
|
||||||
scope->procedures[ident] = block;
|
scope->procedures[ident] = block;
|
||||||
build(block, scope);
|
build_on_ast(block, scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void visit_assignment(const shared_ptr<AstPL0> ast, shared_ptr<Scope> scope) {
|
static void assignment(const shared_ptr<AstPL0> ast, shared_ptr<SymbolScope> scope) {
|
||||||
// assignment <- ident ':=' _ expression
|
// assignment <- ident ':=' _ expression
|
||||||
const auto& ident = ast->nodes[0]->token;
|
const auto& ident = ast->nodes[0]->token;
|
||||||
if (!scope->has_variable(ident)) {
|
if (scope->has_constant(ident)) {
|
||||||
string msg = "undefined variable '" + ident + "'...";
|
throw_runtime_error(ast->nodes[0], "cannot modify constant value '" + ident + "'...");
|
||||||
string s = format_error_message(ast->path, ast->line, ast->column, msg);
|
} else if (!scope->has_variable(ident)) {
|
||||||
throw runtime_error(s);
|
throw_runtime_error(ast->nodes[0], "undefined variable '" + ident + "'...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void visit_call(const shared_ptr<AstPL0> ast, shared_ptr<Scope> scope) {
|
static void call(const shared_ptr<AstPL0> ast, shared_ptr<SymbolScope> scope) {
|
||||||
// call <- 'CALL' _ ident
|
// call <- 'CALL' _ ident
|
||||||
const auto& ident = ast->nodes[0]->token;
|
const auto& ident = ast->nodes[0]->token;
|
||||||
if (!scope->has_procedure(ident)) {
|
if (!scope->has_procedure(ident)) {
|
||||||
string msg = "undefined procedure '" + ident + "'...";
|
throw_runtime_error(ast->nodes[0], "undefined procedure '" + ident + "'...");
|
||||||
string s = format_error_message(ast->path, ast->line, ast->column, msg);
|
|
||||||
throw runtime_error(s);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void visit_ident(const shared_ptr<AstPL0> ast, shared_ptr<Scope> scope) {
|
static void ident(const shared_ptr<AstPL0> ast, shared_ptr<SymbolScope> scope) {
|
||||||
const auto& ident = ast->token;
|
const auto& ident = ast->token;
|
||||||
if (!scope->has_symbol(ident)) {
|
if (!scope->has_symbol(ident)) {
|
||||||
string msg = "undefined variable '" + ident + "'...";
|
throw_runtime_error(ast, "undefined variable '" + ident + "'...");
|
||||||
string s = format_error_message(ast->path, ast->line, ast->column, msg);
|
|
||||||
throw runtime_error(s);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -235,33 +217,36 @@ private:
|
|||||||
*/
|
*/
|
||||||
struct Environment
|
struct Environment
|
||||||
{
|
{
|
||||||
Environment(shared_ptr<Scope> scope = nullptr, shared_ptr<Environment> outer = nullptr) : scope(scope), outer(outer) {
|
Environment(shared_ptr<SymbolScope> scope, shared_ptr<Environment> outer)
|
||||||
if (scope) {
|
: scope(scope), outer(outer) {}
|
||||||
symbols = scope->symbols;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_value(const string& ident) const {
|
int get_value(const string& ident) const {
|
||||||
auto it = symbols.find(ident);
|
auto it = scope->constants.find(ident);
|
||||||
if (it != symbols.end()) {
|
if (it != scope->constants.end()) {
|
||||||
return it->second.value;
|
return it->second;
|
||||||
|
} else if (scope->variables.find(ident) != scope->variables.end()) {
|
||||||
|
return variables.at(ident);
|
||||||
}
|
}
|
||||||
return outer->get_value(ident);
|
return outer->get_value(ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_variable(const string& ident, int val) {
|
void set_variable(const string& ident, int val) {
|
||||||
auto it = symbols.find(ident);
|
if (scope->variables.find(ident) != scope->variables.end()) {
|
||||||
if (it != symbols.end() && !it->second.is_constant) {
|
variables[ident] = val;
|
||||||
symbols[ident].value = val;
|
|
||||||
} else {
|
} else {
|
||||||
outer->set_variable(ident, val);
|
outer->set_variable(ident, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<Scope> scope;
|
shared_ptr<AstPL0> get_procedure(const string& ident) const {
|
||||||
|
auto it = scope->procedures.find(ident);
|
||||||
|
return it != scope->procedures.end() ? it->second : outer->get_procedure(ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<SymbolScope> scope;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
map<string, Symbol> symbols;
|
map<string, int> variables;
|
||||||
shared_ptr<Environment> outer;
|
shared_ptr<Environment> outer;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -270,7 +255,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
struct Interpreter
|
struct Interpreter
|
||||||
{
|
{
|
||||||
static void exec(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static void exec(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env = nullptr) {
|
||||||
switch (ast->tag) {
|
switch (ast->tag) {
|
||||||
case "block"_: exec_block(ast, env); break;
|
case "block"_: exec_block(ast, env); break;
|
||||||
case "statement"_: exec_statement(ast, env); break;
|
case "statement"_: exec_statement(ast, env); break;
|
||||||
@ -288,12 +273,11 @@ struct Interpreter
|
|||||||
private:
|
private:
|
||||||
static void exec_block(const shared_ptr<AstPL0> ast, shared_ptr<Environment> outer) {
|
static void exec_block(const shared_ptr<AstPL0> ast, shared_ptr<Environment> outer) {
|
||||||
// block <- const var procedure statement
|
// block <- const var procedure statement
|
||||||
auto env = make_shared<Environment>(ast->scope, outer);
|
exec(ast->nodes[3], make_shared<Environment>(ast->scope, outer));
|
||||||
exec(ast->nodes[3], env);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_statement(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static void exec_statement(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
// statement <-(assignment / call / statements / if / while / out / in) ?
|
// statement <- (assignment / call / statements / if / while / out / in)?
|
||||||
if (!ast->nodes.empty()) {
|
if (!ast->nodes.empty()) {
|
||||||
exec(ast->nodes[0], env);
|
exec(ast->nodes[0], env);
|
||||||
}
|
}
|
||||||
@ -301,17 +285,12 @@ private:
|
|||||||
|
|
||||||
static void exec_assignment(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static void exec_assignment(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
// assignment <- ident ':=' _ expression
|
// assignment <- ident ':=' _ expression
|
||||||
const auto& ident = ast->nodes[0]->token;
|
env->set_variable(ast->nodes[0]->token, eval(ast->nodes[1], env));
|
||||||
auto expr = ast->nodes[1];
|
|
||||||
auto val = eval(expr, env);
|
|
||||||
env->set_variable(ident, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_call(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static void exec_call(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
// call <- 'CALL' _ ident
|
// call <- 'CALL' _ ident
|
||||||
const auto& ident = ast->nodes[0]->token;
|
exec_block(env->get_procedure(ast->nodes[0]->token), env);
|
||||||
auto proc = env->scope->get_procedure(ident);
|
|
||||||
exec_block(proc, env);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_statements(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static void exec_statements(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
@ -323,10 +302,8 @@ private:
|
|||||||
|
|
||||||
static void exec_if(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static void exec_if(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
// if <- 'IF' _ condition 'THEN' _ statement
|
// if <- 'IF' _ condition 'THEN' _ statement
|
||||||
auto cond = eval_condition(ast->nodes[0], env);
|
if (eval_condition(ast->nodes[0], env)) {
|
||||||
if (cond) {
|
exec(ast->nodes[1], env);
|
||||||
auto stmt = ast->nodes[1];
|
|
||||||
exec(stmt, env);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,25 +311,21 @@ private:
|
|||||||
// while <- 'WHILE' _ condition 'DO' _ statement
|
// while <- 'WHILE' _ condition 'DO' _ statement
|
||||||
auto cond = ast->nodes[0];
|
auto cond = ast->nodes[0];
|
||||||
auto stmt = ast->nodes[1];
|
auto stmt = ast->nodes[1];
|
||||||
auto ret = eval_condition(cond, env);
|
while (eval_condition(cond, env)) {
|
||||||
while (ret) {
|
|
||||||
exec(stmt, env);
|
exec(stmt, env);
|
||||||
ret = eval_condition(cond, env);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_out(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static void exec_out(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
// out <- '!' _ expression
|
// out <- '!' _ expression
|
||||||
auto val = eval(ast->nodes[0], env);
|
cout << eval(ast->nodes[0], env) << endl;
|
||||||
cout << val << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_in(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static void exec_in(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
// in <- '?' _ ident
|
// in <- '?' _ ident
|
||||||
int val;
|
int val;
|
||||||
cin >> val;
|
cin >> val;
|
||||||
const auto& ident = ast->nodes[0]->token;
|
env->set_variable(ast->nodes[0]->token, val);
|
||||||
env->set_variable(ident, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool eval_condition(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static bool eval_condition(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
@ -367,8 +340,7 @@ private:
|
|||||||
|
|
||||||
static bool eval_odd(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static bool eval_odd(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
// odd <- 'ODD' _ expression
|
// odd <- 'ODD' _ expression
|
||||||
auto val = eval_expression(ast->nodes[0], env);
|
return eval_expression(ast->nodes[0], env) != 0;
|
||||||
return val != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool eval_compare(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static bool eval_compare(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
@ -427,8 +399,7 @@ private:
|
|||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
if (rval == 0) {
|
if (rval == 0) {
|
||||||
string msg = "divide by 0 error";
|
throw_runtime_error(ast, "divide by 0 error");
|
||||||
throw runtime_error(format_error_message(ast->path, ast->line, ast->column, msg));
|
|
||||||
}
|
}
|
||||||
val = val / rval;
|
val = val / rval;
|
||||||
break;
|
break;
|
||||||
@ -438,8 +409,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int eval_ident(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static int eval_ident(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
const auto& ident = ast->token;
|
return env->get_value(ast->token);
|
||||||
return env->get_value(ident);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int eval_number(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
static int eval_number(const shared_ptr<AstPL0> ast, shared_ptr<Environment> env) {
|
||||||
@ -468,20 +438,19 @@ int main(int argc, const char** argv)
|
|||||||
// Setup a PEG parser
|
// Setup a PEG parser
|
||||||
peg parser(grammar);
|
peg parser(grammar);
|
||||||
parser.enable_ast<AstPL0>();
|
parser.enable_ast<AstPL0>();
|
||||||
parser.log = [&](size_t ln, size_t col, const string& err_msg) {
|
parser.log = [&](size_t ln, size_t col, const string& msg) {
|
||||||
cerr << format_error_message(path, ln, col, err_msg) << endl;
|
cerr << format_error_message(path, ln, col, msg) << endl;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse the source and make an AST
|
// Parse the source and make an AST
|
||||||
shared_ptr<AstPL0> ast;
|
shared_ptr<AstPL0> ast;
|
||||||
if (parser.parse_n(source.data(), source.size(), ast, path)) {
|
if (parser.parse_n(source.data(), source.size(), ast, path)) {
|
||||||
if (argc > 2 && string("--ast") == argv[2]) {
|
if (argc > 2 && string("--ast") == argv[2]) {
|
||||||
ast->print();
|
AstPrint::print(ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SymbolTable::build(ast);
|
SymbolTable::build_on_ast(ast);
|
||||||
Interpreter::exec(ast, make_shared<Environment>());
|
Interpreter::exec(ast);
|
||||||
} catch (const runtime_error& e) {
|
} catch (const runtime_error& e) {
|
||||||
cerr << e.what() << endl;
|
cerr << e.what() << endl;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ int main(int argc, const char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ast = peglib::AstOptimizer(opt_optimize_ast_nodes).optimize(ast);
|
ast = peglib::AstOptimizer(opt_optimize_ast_nodes).optimize(ast);
|
||||||
peglib::AstPrint().print(*ast);
|
peglib::AstPrint::print(ast);
|
||||||
} else {
|
} else {
|
||||||
if (!peg.parse_n(source.data(), source.size())) {
|
if (!peg.parse_n(source.data(), source.size())) {
|
||||||
return -1;
|
return -1;
|
||||||
|
49
peglib.h
49
peglib.h
@ -1955,8 +1955,8 @@ inline constexpr unsigned int operator "" _(const char* s, size_t) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename MixedIn>
|
template <typename Annotation>
|
||||||
struct AstBase : public MixedIn
|
struct AstBase : public Annotation
|
||||||
{
|
{
|
||||||
AstBase(const char* path, size_t line, size_t column, const char* name, const std::vector<std::shared_ptr<AstBase>>& nodes)
|
AstBase(const char* path, size_t line, size_t column, const char* name, const std::vector<std::shared_ptr<AstBase>>& nodes)
|
||||||
: path(path ? path : "")
|
: path(path ? path : "")
|
||||||
@ -2001,8 +2001,6 @@ struct AstBase : public MixedIn
|
|||||||
, nodes(ast.nodes)
|
, nodes(ast.nodes)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void print() const;
|
|
||||||
|
|
||||||
const std::string path;
|
const std::string path;
|
||||||
const size_t line;
|
const size_t line;
|
||||||
const size_t column;
|
const size_t column;
|
||||||
@ -2017,62 +2015,53 @@ struct AstBase : public MixedIn
|
|||||||
const bool is_token;
|
const bool is_token;
|
||||||
const std::string token;
|
const std::string token;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<AstBase<MixedIn>>> nodes;
|
std::vector<std::shared_ptr<AstBase<Annotation>>> nodes;
|
||||||
std::shared_ptr<AstBase<MixedIn>> parent_node;
|
std::shared_ptr<AstBase<Annotation>> parent_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename MixedIn>
|
struct AstPrint
|
||||||
struct AstPrintBase
|
|
||||||
{
|
{
|
||||||
AstPrintBase() : level_(-1) {}
|
template <typename T>
|
||||||
|
static void print(const std::shared_ptr<T>& ptr, int level = 0) {
|
||||||
void print(const AstBase<MixedIn>& ast) {
|
const auto& ast = *ptr;
|
||||||
level_ += 1;
|
for (auto i = 0; i < level; i++) { std::cout << " "; }
|
||||||
for (auto i = 0; i < level_; i++) { std::cout << " "; }
|
|
||||||
if (ast.is_token) {
|
if (ast.is_token) {
|
||||||
std::cout << "- " << name(ast) << ": '" << ast.token << "'" << std::endl;
|
std::cout << "- " << name(ast) << ": '" << ast.token << "'" << std::endl;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "+ " << name(ast) << std::endl;
|
std::cout << "+ " << name(ast) << std::endl;
|
||||||
}
|
}
|
||||||
for (auto node : ast.nodes) { print(*node); }
|
for (auto node : ast.nodes) { print(node, level + 1); }
|
||||||
level_ -= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name(const AstBase<MixedIn>& ast) {
|
template <typename T>
|
||||||
|
static std::string name(const T& ast) {
|
||||||
if (ast.name == ast.original_name) {
|
if (ast.name == ast.original_name) {
|
||||||
return ast.name;
|
return ast.name;
|
||||||
} else {
|
} else {
|
||||||
return ast.original_name + " (" + ast.name + ")";
|
return ast.original_name + " (" + ast.name + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int level_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename MixedIn>
|
struct AstOptimizer
|
||||||
inline void AstBase<MixedIn>::print() const {
|
|
||||||
AstPrintBase<MixedIn>().print(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename MixedIn>
|
|
||||||
struct AstOptimizerBase
|
|
||||||
{
|
{
|
||||||
AstOptimizerBase(bool optimize_nodes, const std::vector<std::string>& filters = {})
|
AstOptimizer(bool optimize_nodes, const std::vector<std::string>& filters = {})
|
||||||
: optimize_nodes_(optimize_nodes)
|
: optimize_nodes_(optimize_nodes)
|
||||||
, filters_(filters) {}
|
, filters_(filters) {}
|
||||||
|
|
||||||
std::shared_ptr<AstBase<MixedIn>> optimize(std::shared_ptr<AstBase<MixedIn>> original, std::shared_ptr<AstBase<MixedIn>> parent = nullptr) {
|
template <typename T>
|
||||||
|
std::shared_ptr<T> optimize(std::shared_ptr<T> original, std::shared_ptr<T> parent = nullptr) {
|
||||||
|
|
||||||
auto found = std::find(filters_.begin(), filters_.end(), original->name) != filters_.end();
|
auto found = std::find(filters_.begin(), filters_.end(), original->name) != filters_.end();
|
||||||
bool opt = optimize_nodes_ ? !found : found;
|
bool opt = optimize_nodes_ ? !found : found;
|
||||||
|
|
||||||
if (opt && original->nodes.size() == 1) {
|
if (opt && original->nodes.size() == 1) {
|
||||||
auto child = optimize(original->nodes[0], parent);
|
auto child = optimize(original->nodes[0], parent);
|
||||||
return std::make_shared<AstBase<MixedIn>>(*child, original->name.c_str());
|
return std::make_shared<T>(*child, original->name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ast = std::make_shared<AstBase<MixedIn>>(*original);
|
auto ast = std::make_shared<T>(*original);
|
||||||
ast->parent_node = parent;
|
ast->parent_node = parent;
|
||||||
ast->nodes.clear();
|
ast->nodes.clear();
|
||||||
for (auto node : original->nodes) {
|
for (auto node : original->nodes) {
|
||||||
@ -2089,8 +2078,6 @@ private:
|
|||||||
|
|
||||||
struct EmptyType {};
|
struct EmptyType {};
|
||||||
typedef AstBase<EmptyType> Ast;
|
typedef AstBase<EmptyType> Ast;
|
||||||
typedef AstPrintBase<EmptyType> AstPrint;
|
|
||||||
typedef AstOptimizerBase<EmptyType> AstOptimizer;
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* peg
|
* peg
|
||||||
|
Loading…
Reference in New Issue
Block a user