Fix a bug in #228

This commit is contained in:
yhirose 2022-07-02 18:28:57 -04:00
parent 5934f0abba
commit 030659aabc
3 changed files with 94 additions and 57 deletions

View File

@ -466,14 +466,14 @@ Simple symbol table support is available with `declare_symbol` and `check_symbol
```peg ```peg
S <- (Decl / Ref)* S <- (Decl / Ref)*
Decl <- 'decl' symbol(Name) Decl <- 'decl' symbol
Ref <- 'ref' is_symbol(Name) Ref <- 'ref' is_symbol
Name <- < [a-zA-Z]+ > Name <- < [a-zA-Z]+ >
%whitespace <- [ \t\r\n]* %whitespace <- [ \t\r\n]*
# 'var_table' is a table name. # 'var_table' is a table name.
symbol(s) <- s { declare_symbol var_table } # Declare symbol instruction symbol <- Name { declare_symbol var_table } # Declare symbol instruction
is_symbol(s) <- s { check_symbol var_table } # Check symbol instruction is_symbol <- Name { check_symbol var_table } # Check symbol instruction
``` ```
If we parse the following text with the above grammar, it will fail. If we parse the following text with the above grammar, it will fail.

View File

@ -2695,42 +2695,6 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &vs,
c.rule_stack.push_back(outer_); c.rule_stack.push_back(outer_);
auto len = ope_->parse(s, n, vs, c, dt); auto len = ope_->parse(s, n, vs, c, dt);
c.rule_stack.pop_back(); c.rule_stack.pop_back();
std::string msg;
if (success(len)) {
if (outer_->predicate && !outer_->predicate(vs, dt, msg)) {
len = static_cast<size_t>(-1);
} else if (outer_->declare_symbol) {
assert(outer_->is_token());
auto symbol = vs.token_to_string();
auto &table = c.symbol_tables[outer_->symbol_table_name];
auto ret = table.find(symbol) != table.end();
if (ret) {
msg = "'" + symbol + "' already exists.";
len = static_cast<size_t>(-1);
} else {
table.insert(symbol);
}
} else if (outer_->check_symbol) {
assert(outer_->is_token());
auto symbol = vs.token_to_string();
auto &table = c.symbol_tables[outer_->symbol_table_name];
auto ret = table.find(symbol) != table.end();
if (!ret) {
msg = "'" + symbol + "' doesn't exist.";
len = static_cast<size_t>(-1);
}
}
}
if (fail(len)) {
if (c.log && !msg.empty() && c.error_info.message_pos < s) {
c.error_info.message_pos = s;
c.error_info.message = msg;
}
}
return len; return len;
} }
@ -2768,8 +2732,33 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &vs,
c.error_info.message = msg; c.error_info.message = msg;
} }
len = static_cast<size_t>(-1); len = static_cast<size_t>(-1);
} else if (outer_->declare_symbol) {
assert(outer_->is_token());
auto symbol = chldvs.token_to_string();
auto &table = c.symbol_tables[outer_->symbol_table_name];
if (table.find(symbol) != table.end()) {
msg = "'" + symbol + "' already exists.";
len = static_cast<size_t>(-1);
} else { } else {
table.insert(symbol);
}
} else if (outer_->check_symbol) {
assert(outer_->is_token());
auto symbol = chldvs.token_to_string();
auto &table = c.symbol_tables[outer_->symbol_table_name];
if (table.find(symbol) == table.end()) {
msg = "'" + symbol + "' doesn't exist.";
len = static_cast<size_t>(-1);
}
}
if (success(len)) {
a_val = reduce(chldvs, dt); a_val = reduce(chldvs, dt);
} else {
if (c.log && !msg.empty() && c.error_info.message_pos < s) {
c.error_info.message_pos = s;
c.error_info.message = msg;
}
} }
} }
}); });

View File

@ -864,13 +864,13 @@ 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(Name) Decl <- 'decl' symbol
Ref <- 'ref' is_symbol(Name) Ref <- 'ref' is_symbol
Name <- < [a-zA-Z]+ > Name <- < [a-zA-Z]+ >
%whitespace <- [ \t\r\n]* %whitespace <- [ \t\r\n]*
symbol(s) <- s { declare_symbol var_table } symbol <- Name { declare_symbol var_table }
is_symbol(s) <- s { check_symbol var_table } is_symbol <- Name { check_symbol var_table }
)"); )");
{ {
@ -900,17 +900,65 @@ decl aaa
} }
} }
TEST(SymbolTableTest, with_predicate_test) { TEST(SymbolTableTest, typedef_test) {
parser parser(R"(
S <- (Decl / TypeDef)*
Decl <- 'decl' type
TypeDef <- 'typedef' type_ref type ';'
type <- Name { declare_symbol type_table }
type_ref <- Name { check_symbol type_table }
Name <- < [a-zA-Z0-9_]+ >
%whitespace <- [ \t\r\n]*
)");
{
const auto source = R"(decl long
typedef long __off64_t;
typedef __off64_t __loff_t;
)";
EXPECT_TRUE(parser.parse(source));
}
{
const auto source = R"(decl long
typedef long __off64_t;
typedef __off64_T __loff_t;
)";
parser.log = [](size_t line, size_t col, const std::string &msg) {
EXPECT_EQ(3, line);
EXPECT_EQ(9, col);
EXPECT_EQ("'__off64_T' doesn't exist.", msg);
};
EXPECT_FALSE(parser.parse(source));
}
{
const auto source = R"(decl long
typedef long __off64_t;
typedef __off64_t __loff_t;
typedef __off64_t __loff_t;
)";
parser.log = [](size_t line, size_t col, const std::string &msg) {
EXPECT_EQ(4, line);
EXPECT_EQ(19, col);
EXPECT_EQ("'__loff_t' already exists.", msg);
};
EXPECT_FALSE(parser.parse(source));
}
}
TEST(SymbolTableTest, predicate_test) {
parser parser(R"( parser parser(R"(
S <- (Decl / Ref)* S <- (Decl / Ref)*
Decl <- 'decl' symbol(Name) Decl <- 'decl' symbol
Ref <- 'ref' is_symbol(Name) Ref <- 'ref' is_symbol
Name <- < [a-zA-Z]+ > Name <- < [a-zA-Z]+ >
%whitespace <- [ \t\r\n]* %whitespace <- [ \t\r\n]*
# These must be tokens. # These must be tokens.
symbol(s) <- < s > symbol <- < Name >
is_symbol(s) <- < s > is_symbol <- < Name >
)"); )");
std::set<std::string> dic; std::set<std::string> dic;