diff --git a/README.md b/README.md index ae4dfeb..88c273d 100644 --- a/README.md +++ b/README.md @@ -466,14 +466,14 @@ Simple symbol table support is available with `declare_symbol` and `check_symbol ```peg S <- (Decl / Ref)* -Decl <- 'decl' symbol(Name) -Ref <- 'ref' is_symbol(Name) +Decl <- 'decl' symbol +Ref <- 'ref' is_symbol Name <- < [a-zA-Z]+ > %whitespace <- [ \t\r\n]* # 'var_table' is a table name. -symbol(s) <- s { declare_symbol var_table } # Declare symbol instruction -is_symbol(s) <- s { check_symbol var_table } # Check symbol instruction +symbol <- Name { declare_symbol var_table } # Declare 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. diff --git a/peglib.h b/peglib.h index da9e89d..f3f5482 100644 --- a/peglib.h +++ b/peglib.h @@ -2695,42 +2695,6 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &vs, c.rule_stack.push_back(outer_); auto len = ope_->parse(s, n, vs, c, dt); c.rule_stack.pop_back(); - - std::string msg; - - if (success(len)) { - if (outer_->predicate && !outer_->predicate(vs, dt, msg)) { - len = static_cast(-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(-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(-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; } @@ -2768,8 +2732,33 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &vs, c.error_info.message = msg; } len = static_cast(-1); - } else { + } 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(-1); + } 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(-1); + } + } + + if (success(len)) { 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; + } } } }); diff --git a/test/test2.cc b/test/test2.cc index 846936c..3d12eba 100644 --- a/test/test2.cc +++ b/test/test2.cc @@ -864,13 +864,13 @@ TEST(PredicateTest, Semantic_predicate_test) { TEST(SymbolTableTest, symbol_instruction_test) { parser parser(R"( S <- (Decl / Ref)* -Decl <- 'decl' symbol(Name) -Ref <- 'ref' is_symbol(Name) +Decl <- 'decl' symbol +Ref <- 'ref' is_symbol Name <- < [a-zA-Z]+ > %whitespace <- [ \t\r\n]* -symbol(s) <- s { declare_symbol var_table } -is_symbol(s) <- s { check_symbol var_table } +symbol <- Name { declare_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"( S <- (Decl / Ref)* -Decl <- 'decl' symbol(Name) -Ref <- 'ref' is_symbol(Name) +Decl <- 'decl' symbol +Ref <- 'ref' is_symbol Name <- < [a-zA-Z]+ > %whitespace <- [ \t\r\n]* # These must be tokens. -symbol(s) <- < s > -is_symbol(s) <- < s > +symbol <- < Name > +is_symbol <- < Name > )"); std::set dic; @@ -1096,13 +1144,13 @@ TEST(MacroTest, Macro_invalid_macro_reference_error) { TEST(MacroTest, Macro_calculator) { // Create a PEG parser parser parser(R"( - # Grammar for simple calculator... - EXPRESSION <- _ LIST(TERM, TERM_OPERATOR) - TERM <- LIST(FACTOR, FACTOR_OPERATOR) - FACTOR <- NUMBER / T('(') EXPRESSION T(')') - TERM_OPERATOR <- T([-+]) - FACTOR_OPERATOR <- T([*/]) - NUMBER <- T([0-9]+) + # Grammar for simple calculator... + EXPRESSION <- _ LIST(TERM, TERM_OPERATOR) + TERM <- LIST(FACTOR, FACTOR_OPERATOR) + FACTOR <- NUMBER / T('(') EXPRESSION T(')') + TERM_OPERATOR <- T([-+]) + FACTOR_OPERATOR <- T([*/]) + NUMBER <- T([0-9]+) ~_ <- [ \t]* LIST(I, D) <- I (D I)* T(S) <- < S > _