2016-12-31 16:16:26 +01:00
|
|
|
#pragma once
|
|
|
|
#ifndef PARSODUS_PARSER_{{name}}_H
|
|
|
|
#define PARSODUS_PARSER_{{name}}_H
|
|
|
|
|
2017-01-01 12:44:40 +01:00
|
|
|
#include <cassert>
|
2017-01-02 17:02:43 +01:00
|
|
|
#include <cstdint>
|
2016-12-31 16:16:26 +01:00
|
|
|
#include <deque>
|
2017-01-01 12:44:40 +01:00
|
|
|
#include <stack>
|
2016-12-31 16:16:26 +01:00
|
|
|
|
2017-01-02 17:02:43 +01:00
|
|
|
/**
|
|
|
|
* Represents the type of the symbol (both terminals and nonterminals)
|
|
|
|
*/
|
|
|
|
enum class {{name}}_Symbol : std::uint64_t {
|
|
|
|
{{#symbols}}
|
|
|
|
{{symbol}},
|
|
|
|
{{/symbols}}
|
|
|
|
};
|
|
|
|
|
2016-12-31 16:16:26 +01:00
|
|
|
template <typename Value>
|
|
|
|
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 {
|
2017-01-02 19:00:07 +01:00
|
|
|
Token(const {{name}}_Symbol& sym, const Value& val) : symbol(sym), value(val) {}
|
2017-01-02 17:02:43 +01:00
|
|
|
{{name}}_Symbol symbol;
|
|
|
|
Value value;
|
2016-12-31 16:16:26 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************
|
|
|
|
* 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)
|
|
|
|
*/
|
2017-01-16 19:04:21 +01:00
|
|
|
{{#rulenames}}
|
|
|
|
virtual Value reduce_{{rname}}(std::deque<Token> subparts) = 0;
|
|
|
|
{{/rulenames}}
|
2016-12-31 16:16:26 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
2017-01-01 12:44:40 +01:00
|
|
|
#define TABLE {{name}}___Table___{{name}}
|
|
|
|
#define REDUCE_COUNT {{name}}___Num_Reduces___{{name}}
|
2016-12-31 16:16:26 +01:00
|
|
|
// Not a static member because the table should not be replicated for different instantiations of the parser
|
2017-01-02 11:45:50 +01:00
|
|
|
extern const std::uint64_t TABLE[{{num_states}}][{{num_symbols}}];
|
|
|
|
extern const unsigned char REDUCE_COUNT[{{num_rules}}];
|
2017-01-01 12:44:40 +01:00
|
|
|
|
|
|
|
enum Action {
|
|
|
|
ERROR = 0,
|
|
|
|
SHIFT = 1,
|
|
|
|
REDUCE = 2,
|
|
|
|
ACCEPT = 3
|
|
|
|
};
|
2016-12-31 16:16:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
/***************************
|
|
|
|
* Parser implementation *
|
|
|
|
***************************/
|
|
|
|
template <typename Value>
|
2017-01-02 17:02:43 +01:00
|
|
|
Value {{name}}<Value>::parse() {
|
2017-01-01 12:44:40 +01:00
|
|
|
std::stack<Token> valueStack;
|
|
|
|
std::stack<std::uint64_t> stateStack;
|
|
|
|
|
|
|
|
stateStack.push(0);
|
|
|
|
Token tok = lex();
|
|
|
|
|
|
|
|
while (true) {
|
2017-01-02 19:00:07 +01:00
|
|
|
std::uint64_t act = TABLE[stateStack.top()][static_cast<std::uint64_t>(tok.symbol)];
|
2017-01-01 12:44:40 +01:00
|
|
|
|
|
|
|
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:
|
|
|
|
{
|
2017-01-01 13:16:24 +01:00
|
|
|
std::uint64_t tmp = act >> 2;
|
2017-01-02 17:02:43 +01:00
|
|
|
{{name}}_Symbol symbol = static_cast<{{name}}_Symbol>(tmp >> 31);
|
2017-01-02 19:00:07 +01:00
|
|
|
std::uint32_t rule = tmp & ((1ull << 31) - 1);
|
2017-01-01 13:16:24 +01:00
|
|
|
|
2017-01-01 12:44:40 +01:00
|
|
|
std::deque<Token> dq;
|
2017-01-02 17:02:43 +01:00
|
|
|
for (unsigned char i = 0; i < REDUCE_COUNT[rule]; i++) {
|
2017-01-01 12:44:40 +01:00
|
|
|
dq.emplace_front(std::move(valueStack.top()));
|
|
|
|
valueStack.pop();
|
|
|
|
stateStack.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (rule) {
|
|
|
|
{{#rules}}
|
|
|
|
case {{index}}:
|
2017-01-02 19:00:07 +01:00
|
|
|
{{#rname}}valueStack.emplace(symbol, reduce_{{rname}}(std::move(dq)));{{/rname}}
|
|
|
|
{{^rname}}valueStack.emplace(symbol, reduce_{{index}}(std::move(dq)));{{/rname}}
|
2017-01-01 12:44:40 +01:00
|
|
|
break;
|
|
|
|
{{/rules}}
|
|
|
|
default:
|
|
|
|
assert(false); //There should be no such rule
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-01-02 19:00:07 +01:00
|
|
|
stateStack.push(TABLE[stateStack.top()][static_cast<std::uint64_t>(valueStack.top().symbol)] >> 2);
|
2017-01-01 12:44:40 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ACCEPT:
|
|
|
|
assert(stateStack.size() == 2);
|
|
|
|
assert(valueStack.size() == 1);
|
|
|
|
return valueStack.top().value;
|
|
|
|
default:
|
|
|
|
//IMPOSSIBLE
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-12-31 16:16:26 +01:00
|
|
|
}
|
2017-01-01 12:44:40 +01:00
|
|
|
#undef REDUCE_COUNT
|
|
|
|
#undef TABLE
|
2016-12-31 16:16:26 +01:00
|
|
|
|
|
|
|
#endif /* PARSODUS_PARSER_{{name}}_H */
|