#pragma once #ifndef PARSODUS_PARSER_{{name}}_H #define PARSODUS_PARSER_{{name}}_H #include #include #include #include /** * Represents the type of the symbol (both terminals and nonterminals) */ enum class {{name}}_Symbol : std::uint64_t { {{#symbols}} {{symbol}}, {{/symbols}} }; template class {{name}} { public: {{name}}() {} virtual ~{{name}}() {} /** * Parse it */ Value parse(); protected: /** * A token, consisting of a Symbol type (should be a terminal) and a Value */ struct Token { {{name}}_Symbol symbol; Value value; }; /****************************************** * Functions to be supplied by the user * ******************************************/ /** * Get the next token from the lexer */ virtual Token lex() = 0; /** * Apply a reduction (a grammar rule in reverse) */ {{#rules}} {{#rname}}virtual Value reduce_{{rname}}(std::deque subparts) = 0;{{/rname}} {{^rname}}virtual Value reduce_{{index}}(std::deque subparts) = 0;{{/rname}} {{/rules}} private: }; #define TABLE {{name}}___Table___{{name}} #define REDUCE_COUNT {{name}}___Num_Reduces___{{name}} // Not a static member because the table should not be replicated for different instantiations of the parser extern const std::uint64_t TABLE[{{num_states}}][{{num_symbols}}]; extern const unsigned char REDUCE_COUNT[{{num_rules}}]; enum Action { ERROR = 0, SHIFT = 1, REDUCE = 2, ACCEPT = 3 }; /*************************** * Parser implementation * ***************************/ template Value {{name}}::parse() { std::stack valueStack; std::stack stateStack; stateStack.push(0); Token tok = lex(); while (true) { std::uint64_t act = TABLE[stateStack.top()][tok.symbol]; switch (act & 0x3) { case ERROR: //TODO: error handling assert(false); break; case SHIFT: valueStack.emplace(std::move(tok)); stateStack.push(act >> 2); tok = lex(); break; case REDUCE: { std::uint64_t tmp = act >> 2; {{name}}_Symbol symbol = static_cast<{{name}}_Symbol>(tmp >> 31); std::uint32_t rule = tmp & ((1ull << 32) - 1); std::deque dq; for (unsigned char i = 0; i < REDUCE_COUNT[rule]; i++) { dq.emplace_front(std::move(valueStack.top())); valueStack.pop(); stateStack.pop(); } switch (rule) { {{#rules}} case {{index}}: {{#rname}}valueStack.emplace({symbol, reduce_{{rname}}(std::move(dq))});{{/rname}} {{^rname}}valueStack.emplace({symbol, reduce_{{index}}(std::move(dq))});{{/rname}} break; {{/rules}} default: assert(false); //There should be no such rule break; } stateStack.push(TABLE[stateStack.top()][valueStack.top().symbol] >> 2); } break; case ACCEPT: assert(stateStack.size() == 2); assert(valueStack.size() == 1); return valueStack.top().value; default: //IMPOSSIBLE break; } } } #undef REDUCE_COUNT #undef TABLE #endif /* PARSODUS_PARSER_{{name}}_H */