PNode operator()(PascalGrammar& g) { PrattParser<PNode>& p = *(g.parser); PascalGrammar::lbp_guard comma_lbp_guard(*(g.comma), 1); PascalGrammar::list_guard<ExprType> comma_guard(g, g.comma, "expression"); PNode elements = p.parse(0); /* must be less than lbp of subexpressions */ if (!node_traits::is_list_of<ExprType>(elements)) g.error("expected list of expressions"); return elements; }
void add_statements(PascalGrammar& g) { typedef PascalGrammar::RightAssociative RightAssociative; typedef PascalGrammar::LeftAssociative LeftAssociative; g.infix(":=", 40, [&g](PNode var, PNode expr) -> PNode { if (!node_traits::is_convertible_to<VariableNode>(var)) g.error("expected variable before ':=' token"); if (!node_traits::is_convertible_to<ExpressionNode>(expr)) g.error("expected expression after ':=' token"); return std::make_shared<AssignmentStatementNode>(var, expr); }); static auto parse_statement = [&g]() -> PNode { static auto process_if_identifier = [](PNode& node) { if (node_traits::has_type<IdentifierNode>(node)) { // function/procedure call node = std::make_shared<FunctionDesignatorNode>(node, std::make_shared<ExpressionListNode>()); } }; static auto statement_is_empty = [&g]() -> bool { auto next = g.parser -> next_token_as_string(); return (next == ";" || next == "end" || next == "until" || next == "else"); }; PrattParser<PNode>& p = *(g.parser); PascalGrammar::lbp_guard colon_lbp_guard(*(g.colon), 1); PascalGrammar::led_guard colon_guard(*(g.colon), [&g](PrattParser<PNode>& p, PNode left) -> PNode { if (!node_traits::is_convertible_to<IntegerNumberNode>(left)) g.error("expected integer number as label"); if (statement_is_empty()) return std::make_shared<EmptyNode>(); PNode node = p.parse(0); process_if_identifier(node); if (!node_traits::is_convertible_to<StatementNode>(node)) g.error("expected statement"); return std::make_shared<LabeledStatementNode>(left, node); }); if (statement_is_empty()) return std::make_shared<EmptyNode>(); PNode node = p.parse(0); process_if_identifier(node); if (!node_traits::is_convertible_to<StatementNode>(node)) g.error("expected statement"); return node; }; static auto parse_statement_sequence = [&g]() -> PNode { PrattParser<PNode>& p = *(g.parser); std::forward_list<PNode> statements; while (true) { auto next = p.next_token_as_string(); if (next == ";") { // some support for empty statements p.advance(); } next = p.next_token_as_string(); if (next == "end" || next == "until") break; PNode statement = parse_statement(); statements.push_front(statement); next = p.next_token_as_string(); if (next != ";") { break; // handling errors is duty of the caller } } statements.reverse(); return std::make_shared<StatementListNode>(std::move(statements)); }; g.add_symbol_to_dict("begin", 1) .nud = [&g](PrattParser<PNode>& p) -> PNode { #ifdef PRINT_DEBUG cout << "ENTERING BEGIN" << endl; #endif PascalGrammar::lbp_guard end_guard(*(g.end), 0); PascalGrammar::lbp_guard dot_guard(*(g.dot), 1000); PNode statements = parse_statement_sequence(); g.advance("end", "expected 'end' after statement-sequence"); return std::make_shared<CompoundStatementNode>(statements); }; g.add_symbol_to_dict("do", 0); g.add_symbol_to_dict("while", 1) .nud = [&g](PrattParser<PNode>& p) -> PNode { #ifdef PRINT_DEBUG cout << "ENTERING WHILE LOOP" << endl; #endif PNode condition = p.parse(0); if (!node_traits::is_convertible_to<ExpressionNode>(condition)) g.error("expected expression after 'while'"); g.advance("do", "expected 'do' after expression"); PNode body = parse_statement(); return std::make_shared<WhileStatementNode>(condition, body); }; g.add_symbol_to_dict("until", 0); g.add_symbol_to_dict("repeat", 1) .nud = [&g](PrattParser<PNode>& p) -> PNode { #ifdef PRINT_DEBUG cout << "ENTERING REPEAT LOOP" << endl; #endif PNode body = parse_statement_sequence(); g.advance("until", "expected 'until' after statement-sequence"); PNode condition = p.parse(1); // stop before semicolon if (!node_traits::is_convertible_to<ExpressionNode>(condition)) g.error("expected expression after 'until'"); return std::make_shared<RepeatStatementNode>(body, condition); }; g.add_symbol_to_dict("to", 0); g.add_symbol_to_dict("downto", 0); g.add_symbol_to_dict("for", 1) .nud = [&g](PrattParser<PNode>& p) -> PNode { #ifdef PRINT_DEBUG cout << "ENTERING FOR LOOP" << endl; #endif PNode assignment = parse_statement(); if (!node_traits::has_type<AssignmentStatementNode>(assignment)) g.error("expected assignment-statement after 'for'"); auto _assignment = std::static_pointer_cast<AssignmentStatementNode>(assignment); if (!node_traits::has_type<IdentifierNode>(_assignment -> variable)) g.error("expected identifier after 'for'"); int sign; std::string next = p.next_token_as_string(); if (next == "to") { sign = 1; } else if (next == "downto") { sign = -1; } else { g.error("expected 'to' or 'downto' after initial-expression"); } p.advance(); PNode final_expr = p.parse(1); if (!node_traits::is_convertible_to<ExpressionNode>(final_expr)) { std::string msg = "expected final-expression after "; msg = msg + '\'' + next + '\''; g.error(std::move(msg)); } g.advance("do", "expected 'do' after final-expression"); PNode body = parse_statement(); return std::make_shared<ForStatementNode>(_assignment, sign, final_expr, body); }; g.add_symbol_to_dict("then", 0); g.add_symbol_to_dict("else", 0); g.add_symbol_to_dict("if", 1) .nud = [&g](PrattParser<PNode>& p) -> PNode { #ifdef PRINT_DEBUG cout << "ENTERING IF STATEMENT" << endl; #endif PNode expr = p.parse(1); if (!node_traits::is_convertible_to<ExpressionNode>(expr)) g.error("expected expression after 'if'"); g.advance("then", "expected 'then'"); PNode st = parse_statement(); if (p.next_token_as_string() != "else") { return std::make_shared<IfThenNode>(expr, st); } else { p.advance(); return std::make_shared<IfThenElseNode>(expr, st, parse_statement()); } }; g.add_symbol_to_dict("do", 0); g.add_symbol_to_dict("with", 1) .nud = [&g](PrattParser<PNode>& p) -> PNode { #ifdef PRINT_DEBUG cout << "ENTERING WITH STATEMENT" << endl; #endif PascalGrammar::list_guard<VariableNode> comma_guard(g, g.comma, "record variable"); PNode list = p.parse(0); if (!node_traits::is_list_of<VariableNode>(list)) g.error("expected list of record variables after 'with'"); g.advance("do", "expected 'do' in with-statement"); PNode st = parse_statement(); return std::make_shared<WithStatementNode>(list, st); }; g.add_symbol_to_dict("case", 1) .nud = [&g](PrattParser<PNode>& p) -> PNode { #ifdef PRINT_DEBUG cout << "ENTERING CASE STATEMENT" << endl; #endif PNode expr = p.parse(0); if (!node_traits::is_convertible_to<ExpressionNode>(expr)) g.error("expected expression after 'case'"); g.advance("of", "expected 'of' after expression"); PascalGrammar::list_guard<ConstantNode> comma_guard(g, g.comma, "constant"); PascalGrammar::lbp_guard colon_lbp_guard(*(g.colon), 1); PascalGrammar::led_guard colon_guard(*(g.colon), [&g](PrattParser<PNode>& p, PNode left) -> PNode { if (!node_traits::is_list_of<ConstantNode>(left)) g.error("expected list of constants before ':'"); return std::make_shared<CaseLimbNode>(left, parse_statement()); }); PascalGrammar::lbp_guard semicolon_guard(*(g.semicolon), 0); std::forward_list<PNode> limbs; do { PNode limb = p.parse(0); if (!node_traits::has_type<CaseLimbNode>(limb)) g.error("expected case-limb"); limbs.push_front(limb); std::string next = p.next_token_as_string(); if (next == ";") { p.advance(); if (p.next_token_as_string() == "end") { p.advance(); break; } } else if (next == "end") { p.advance(); break; } else { g.error("expected ';' or 'end'"); } } while (true); limbs.reverse(); return std::make_shared<CaseStatementNode>(expr, std::make_shared<CaseLimbListNode>(std::move(limbs))); }; auto parse_output_list = [&g]() -> PNode { PrattParser<PNode>& p = *(g.parser); PascalGrammar::lbp_guard comma_guard(*(g.comma), 0); PascalGrammar::lbp_guard colon_guard(*(g.colon), 0); std::forward_list<PNode> output; do { PNode val = p.parse(0); if (!node_traits::is_convertible_to<ExpressionNode>(val)) g.error("expected expression as output value"); output.push_front(val); PNode& last_value = output.front(); auto next = p.next_token_as_string(); if (next == ",") { p.advance(); continue; } else if (next == ")") { break; } if (next != ":") g.error("expected ':', ',' or ')'"); p.advance(); // skip ':' PNode field_width, fraction_length; field_width = p.parse(0); if (!node_traits::is_convertible_to<ExpressionNode>(field_width)) g.error("expected expression as field width"); if (p.next_token_as_string() == ":") { p.advance(); fraction_length = p.parse(0); if (!node_traits::is_convertible_to<ExpressionNode>(fraction_length)) g.error("expected expression as fraction length"); } last_value = std::make_shared<OutputValueNode>(last_value, field_width, fraction_length ? fraction_length : std::make_shared<OutputValueNode>(last_value, field_width, std::make_shared<EmptyNode>())); next = p.next_token_as_string(); if (next == ",") { p.advance(); continue; } else if (next == ")") { break; } else g.error("expected ',' or ')' after output value"); } while (true); output.reverse(); return std::make_shared<OutputValueListNode>(std::move(output)); }; g.add_symbol_to_dict("write", 1) .nud = [&g, parse_output_list](PrattParser<PNode>& p) -> PNode { g.advance("(", "expected list of values to output"); PNode output = parse_output_list(); g.advance(")", "expected closing ')' in 'write'"); return std::make_shared<WriteNode>(output); }; g.add_symbol_to_dict("writeln", 1) .nud = [&g, parse_output_list](PrattParser<PNode>& p) -> PNode { if (p.next_token_as_string() != "(") return std::make_shared<WriteLineNode>(std::make_shared<OutputValueListNode>()); p.advance(); PNode output = parse_output_list(); g.advance(")", "expected closing ')' in 'writeln'"); return std::make_shared<WriteLineNode>(output); }; g.prefix("goto", std::numeric_limits<int>::max(), [&g](PNode node) -> PNode { if (!node_traits::is_convertible_to<IntegerNumberNode>(node)) g.error("expected label"); return std::make_shared<GotoStatementNode>(node); }); }
int main() { (comma_guard().operator,(foo())); }
void add_sections(PascalGrammar& g) { typedef PascalGrammar::RightAssociative RightAssociative; static auto begins_new_section = [](const std::string& symbol) -> bool { static const std::set<std::string> table = { "begin", "function", "procedure", "type", "label", "var", "const", "" }; return table.find(symbol) != table.end(); }; static auto opening_bracket_scan_enum = [&g](PrattParser<PNode>& p) -> PNode { PascalGrammar::list_guard<IdentifierNode> guard(g, g.comma, "identifier"); PNode x = p.parse(0); g.advance(")", "expected closing ')'"); if (!node_traits::is_list_of<IdentifierNode>(x)) g.error("expected list of identifiers"); return std::make_shared<EnumeratedTypeNode>(x); }; // Variable declarations g.colon = &g.infix(":", 70, [&g](PNode x, PNode y) -> PNode { if (!node_traits::is_list_of<IdentifierNode>(x)) g.error("expected identifier list"); if (!node_traits::is_type(y)) g.error("expected type name"); return std::make_shared<VariableDeclNode>(x, y); }); g.var = &g.add_symbol_to_dict("var", 1); g.var -> nud = [&g, opening_bracket_scan_enum](PrattParser<PNode>& p) -> PNode { PascalGrammar::lbp_guard semicolon_guard(*(g.semicolon), 0); PascalGrammar::nud_guard open_bracket_guard(*(g.opening_bracket), opening_bracket_scan_enum); PascalGrammar::list_guard<IdentifierNode> comma_guard(g, g.comma, "identifier"); std::forward_list<PNode> variable_declarations; do { PNode x = p.parse(1); if (!node_traits::has_type<VariableDeclNode>(x)) g.error("expected variable declaration"); variable_declarations.push_front(x); g.advance(";", "expected ';' after variable declaration"); if (begins_new_section(p.next_token_as_string())) break; } while (true); variable_declarations.reverse(); return std::make_shared<VariableSectionNode>( std::make_shared<VariableDeclListNode>( std::move(variable_declarations))); }; // Type declarations g.add_symbol_to_dict("type", 1) .nud = [&g, opening_bracket_scan_enum](PrattParser<PNode>& p) -> PNode { PascalGrammar::lbp_guard semicolon_guard(*(g.semicolon), 0); PascalGrammar::lbp_guard equal_sign_guard(*(g.sign_eq), 0); PascalGrammar::nud_guard open_bracket_guard(*(g.opening_bracket), opening_bracket_scan_enum); std::forward_list<PNode> type_definitions; do { PNode id = p.parse(1); if (!node_traits::has_type<IdentifierNode>(id)) g.error("expected identifier as a type name"); g.advance("=", "expected '=' after type name"); PNode type = p.parse(1); if (!node_traits::is_type(type)) g.error("expected type definition after '='"); g.advance(";", "expected ';' after type definition"); type_definitions.push_front(std::make_shared<TypeDefinitionNode>(id, type)); if (begins_new_section(p.next_token_as_string())) break; } while (true); type_definitions.reverse(); return std::make_shared<TypeSectionNode>(std::move(type_definitions)); }; // Constant definitions g.add_symbol_to_dict("const", 1) .nud = [&g](PrattParser<PNode>& p) -> PNode { PascalGrammar::lbp_guard semicolon_guard(*(g.semicolon), 0); PascalGrammar::lbp_guard equal_sign_guard(*(g.sign_eq), 0); std::forward_list<PNode> const_defs; do { PNode id = p.parse(0); if (!node_traits::has_type<IdentifierNode>(id)) g.error("expected identifier in constant definition"); g.advance("=", "expected '=' after identifier"); PNode constant = p.parse(0); if (!node_traits::is_convertible_to<ConstantNode>(constant)) g.error("expected constant after '='"); else constant = node::convert_to<ConstantNode>(constant); const_defs.push_front( std::make_shared<ConstDefinitionNode>(id, constant)); g.advance(";", "expected ';' after constant definition"); if (begins_new_section(p.next_token_as_string())) break; } while (true); const_defs.reverse(); return std::make_shared<ConstSectionNode>(std::move(const_defs)); }; g.add_symbol_to_dict("label", 1) .nud = [&g](PrattParser<PNode>& p) -> PNode { PascalGrammar::lbp_guard semicolon_guard(*(g.semicolon), 0); PascalGrammar::lbp_guard comma_lbp_guard(*(g.comma), 1); PascalGrammar::list_guard<IntegerNumberNode> comma_guard(g, g.comma, "integer number"); PNode labels = p.parse(0); g.advance(";", "expected ';' after label section"); return std::make_shared<LabelSectionNode>(labels); }; }