This commit is contained in:
yhirose 2022-07-03 19:50:46 -04:00
parent eab2ea05cd
commit c4772a1b00
4 changed files with 115 additions and 13 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -819,6 +819,10 @@ public:
std::vector<std::map<std::string_view, std::string>> capture_scope_stack; std::vector<std::map<std::string_view, std::string>> capture_scope_stack;
size_t capture_scope_stack_size = 0; size_t capture_scope_stack_size = 0;
std::vector<std::map<std::string, std::unordered_set<std::string>>>
symbol_tables_stack;
size_t symbol_tables_stack_size = 0;
std::vector<bool> cut_stack; std::vector<bool> cut_stack;
const size_t def_count; const size_t def_count;
@ -834,8 +838,6 @@ public:
std::any trace_data; std::any trace_data;
const bool verbose_trace; const bool verbose_trace;
std::map<std::string, std::unordered_set<std::string>> symbol_tables;
Log log; Log log;
Context(const char *path, const char *s, size_t l, size_t def_count, Context(const char *path, const char *s, size_t l, size_t def_count,
@ -851,11 +853,19 @@ public:
trace_data(trace_data), verbose_trace(verbose_trace), log(log) { trace_data(trace_data), verbose_trace(verbose_trace), log(log) {
args_stack.resize(1); args_stack.resize(1);
push_capture_scope(); push_capture_scope();
push_symbol_tables();
} }
~Context() { assert(!value_stack_size); } ~Context() {
pop_capture_scope();
pop_symbol_tables();
assert(!value_stack_size);
assert(!capture_scope_stack_size);
assert(!symbol_tables_stack_size);
assert(cut_stack.empty());
}
Context(const Context &) = delete; Context(const Context &) = delete;
Context(Context &&) = delete; Context(Context &&) = delete;
@ -942,7 +952,7 @@ public:
void pop_capture_scope() { capture_scope_stack_size--; } void pop_capture_scope() { capture_scope_stack_size--; }
void shift_capture_values() { void shift_capture_values() {
assert(capture_scope_stack.size() >= 2); assert(capture_scope_stack_size >= 2);
auto curr = &capture_scope_stack[capture_scope_stack_size - 1]; auto curr = &capture_scope_stack[capture_scope_stack_size - 1];
auto prev = curr - 1; auto prev = curr - 1;
for (const auto &[k, v] : *curr) { for (const auto &[k, v] : *curr) {
@ -950,6 +960,50 @@ public:
} }
} }
void push_symbol_tables() {
assert(symbol_tables_stack_size <= symbol_tables_stack.size());
if (symbol_tables_stack_size == symbol_tables_stack.size()) {
symbol_tables_stack.emplace_back(
std::map<std::string, std::unordered_set<std::string>>());
} else {
auto &tables = symbol_tables_stack[symbol_tables_stack_size];
if (!tables.empty()) { tables.clear(); }
}
symbol_tables_stack_size++;
}
void pop_symbol_tables() { symbol_tables_stack_size--; }
void shift_symbol_tables() {
assert(symbol_tables_stack_size >= 2);
auto curr = &symbol_tables_stack[symbol_tables_stack_size - 1];
auto prev = curr - 1;
for (const auto &[k, v] : *curr) {
(*prev)[k].insert(v.begin(), v.end());
}
}
void declare_symbol(const std::string &table_name,
const std::string &symbol) {
assert(symbol_tables_stack_size >= 1);
auto &table = symbol_tables_stack[symbol_tables_stack_size - 1][table_name];
table.insert(symbol);
}
bool check_symbol(const std::string &table_name, const std::string &symbol) {
int i = symbol_tables_stack_size - 1;
while (i >= 0) {
const auto &tables = symbol_tables_stack[i];
if (auto it = tables.find(table_name); it != tables.end()) {
if (const auto &table = it->second; table.find(symbol) != table.end()) {
return true;
}
}
i--;
}
return false;
}
void set_error_pos(const char *a_s, const char *literal = nullptr); void set_error_pos(const char *a_s, const char *literal = nullptr);
void trace_enter(const Ope &ope, const char *a_s, size_t n, void trace_enter(const Ope &ope, const char *a_s, size_t n,
@ -1036,10 +1090,12 @@ public:
auto &chvs = c.push_semantic_values_scope(); auto &chvs = c.push_semantic_values_scope();
c.push_capture_scope(); c.push_capture_scope();
c.push_symbol_tables();
c.error_info.keep_previous_token = id > 0; c.error_info.keep_previous_token = id > 0;
auto se = scope_exit([&]() { auto se = scope_exit([&]() {
c.pop_semantic_values_scope(); c.pop_semantic_values_scope();
c.pop_capture_scope(); c.pop_capture_scope();
c.pop_symbol_tables();
c.error_info.keep_previous_token = false; c.error_info.keep_previous_token = false;
}); });
@ -1059,6 +1115,7 @@ public:
vs.tokens.emplace_back(std::move(tok)); vs.tokens.emplace_back(std::move(tok));
} }
c.shift_capture_values(); c.shift_capture_values();
c.shift_symbol_tables();
break; break;
} else if (!c.cut_stack.empty() && c.cut_stack.back()) { } else if (!c.cut_stack.empty() && c.cut_stack.back()) {
break; break;
@ -1092,9 +1149,11 @@ public:
while (count < min_) { while (count < min_) {
auto &chvs = c.push_semantic_values_scope(); auto &chvs = c.push_semantic_values_scope();
c.push_capture_scope(); c.push_capture_scope();
c.push_symbol_tables();
auto se = scope_exit([&]() { auto se = scope_exit([&]() {
c.pop_semantic_values_scope(); c.pop_semantic_values_scope();
c.pop_capture_scope(); c.pop_capture_scope();
c.pop_symbol_tables();
}); });
auto len = ope_->parse(s + i, n - i, chvs, c, dt); auto len = ope_->parse(s + i, n - i, chvs, c, dt);
@ -1111,6 +1170,7 @@ public:
vs.tokens.emplace_back(std::move(tok)); vs.tokens.emplace_back(std::move(tok));
} }
c.shift_capture_values(); c.shift_capture_values();
c.shift_symbol_tables();
} else { } else {
return len; return len;
} }
@ -1121,9 +1181,11 @@ public:
while (count < max_) { while (count < max_) {
auto &chvs = c.push_semantic_values_scope(); auto &chvs = c.push_semantic_values_scope();
c.push_capture_scope(); c.push_capture_scope();
c.push_symbol_tables();
auto se = scope_exit([&]() { auto se = scope_exit([&]() {
c.pop_semantic_values_scope(); c.pop_semantic_values_scope();
c.pop_capture_scope(); c.pop_capture_scope();
c.pop_symbol_tables();
}); });
auto len = ope_->parse(s + i, n - i, chvs, c, dt); auto len = ope_->parse(s + i, n - i, chvs, c, dt);
@ -1140,6 +1202,7 @@ public:
vs.tokens.emplace_back(std::move(tok)); vs.tokens.emplace_back(std::move(tok));
} }
c.shift_capture_values(); c.shift_capture_values();
c.shift_symbol_tables();
} else { } else {
break; break;
} }
@ -1182,9 +1245,11 @@ public:
Context &c, std::any &dt) const override { Context &c, std::any &dt) const override {
auto &chvs = c.push_semantic_values_scope(); auto &chvs = c.push_semantic_values_scope();
c.push_capture_scope(); c.push_capture_scope();
c.push_symbol_tables();
auto se = scope_exit([&]() { auto se = scope_exit([&]() {
c.pop_semantic_values_scope(); c.pop_semantic_values_scope();
c.pop_capture_scope(); c.pop_capture_scope();
c.pop_symbol_tables();
}); });
auto len = ope_->parse(s, n, chvs, c, dt); auto len = ope_->parse(s, n, chvs, c, dt);
@ -1209,9 +1274,11 @@ public:
Context &c, std::any &dt) const override { Context &c, std::any &dt) const override {
auto &chvs = c.push_semantic_values_scope(); auto &chvs = c.push_semantic_values_scope();
c.push_capture_scope(); c.push_capture_scope();
c.push_symbol_tables();
auto se = scope_exit([&]() { auto se = scope_exit([&]() {
c.pop_semantic_values_scope(); c.pop_semantic_values_scope();
c.pop_capture_scope(); c.pop_capture_scope();
c.pop_symbol_tables();
}); });
auto len = ope_->parse(s, n, chvs, c, dt); auto len = ope_->parse(s, n, chvs, c, dt);
if (success(len)) { if (success(len)) {
@ -2732,18 +2799,16 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &vs,
} else if (outer_->declare_symbol) { } else if (outer_->declare_symbol) {
assert(outer_->is_token()); assert(outer_->is_token());
auto symbol = chvs.token_to_string(); auto symbol = chvs.token_to_string();
auto &table = c.symbol_tables[outer_->symbol_table_name]; if (c.check_symbol(outer_->symbol_table_name, symbol)) {
if (table.find(symbol) != table.end()) {
msg = "'" + symbol + "' already exists."; msg = "'" + symbol + "' already exists.";
len = static_cast<size_t>(-1); len = static_cast<size_t>(-1);
} else { } else {
table.insert(symbol); c.declare_symbol(outer_->symbol_table_name, symbol);
} }
} else if (outer_->check_symbol) { } else if (outer_->check_symbol) {
assert(outer_->is_token()); assert(outer_->is_token());
auto symbol = chvs.token_to_string(); auto symbol = chvs.token_to_string();
auto &table = c.symbol_tables[outer_->symbol_table_name]; if (!c.check_symbol(outer_->symbol_table_name, symbol)) {
if (table.find(symbol) == table.end()) {
msg = "'" + symbol + "' doesn't exist."; msg = "'" + symbol + "' doesn't exist.";
len = static_cast<size_t>(-1); len = static_cast<size_t>(-1);
} }

View File

@ -862,8 +862,7 @@ TEST(PredicateTest, Semantic_predicate_test) {
} }
TEST(SymbolTableTest, symbol_instruction_test) { TEST(SymbolTableTest, symbol_instruction_test) {
parser parser(R"( parser parser(R"(S <- (Decl / Ref)*
S <- (Decl / Ref)*
Decl <- 'decl' symbol Decl <- 'decl' symbol
Ref <- 'ref' is_symbol Ref <- 'ref' is_symbol
Name <- < [a-zA-Z]+ > Name <- < [a-zA-Z]+ >
@ -900,6 +899,44 @@ decl aaa
} }
} }
TEST(SymbolTableTest, symbol_instruction_backtrack_test) {
parser parser(R"(S <- (DeclBT / Decl / Ref)*
DeclBT <- 'decl' symbol 'backtrack' # match fails, so symbol should not be set
Decl <- 'decl' symbol
Ref <- 'ref' is_symbol
Name <- < [a-zA-Z]+ >
%whitespace <- [ \t\r\n]*
# 'var_table' is a table name.
symbol <- Name { declare_symbol var_table } # Declare symbol instruction
is_symbol <- Name { check_symbol var_table } # Check symbol instruction
)");
const auto source = R"(decl foo
ref foo
)";
EXPECT_TRUE(parser.parse(source));
}
TEST(SymbolTableTest, symbol_instruction_backtrack_test2) {
parser parser(R"(S <- DeclBT* Decl Ref
DeclBT <- 'decl' symbol 'backtrack' # match fails, so symbol should not be set
Decl <- 'decl' symbol
Ref <- 'ref' is_symbol
Name <- < [a-zA-Z]+ >
%whitespace <- [ \t\r\n]*
# 'var_table' is a table name.
symbol <- Name { declare_symbol var_table } # Declare symbol instruction
is_symbol <- Name { check_symbol var_table } # Check symbol instruction
)");
const auto source = R"(decl foo
ref foo
)";
EXPECT_TRUE(parser.parse(source));
}
TEST(SymbolTableTest, typedef_test) { TEST(SymbolTableTest, typedef_test) {
parser parser(R"( parser parser(R"(
S <- (Decl / TypeDef)* S <- (Decl / TypeDef)*