mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Fix #231
This commit is contained in:
parent
eab2ea05cd
commit
c4772a1b00
File diff suppressed because one or more lines are too long
BIN
docs/native.wasm
BIN
docs/native.wasm
Binary file not shown.
85
peglib.h
85
peglib.h
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)*
|
||||||
|
Loading…
Reference in New Issue
Block a user