Parsodus/templates/c++/lr.h

140 lines
3.8 KiB
C
Raw Normal View History

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>
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
template <typename Value>
class {{name}} {
public:
{{name}}() {}
virtual ~{{name}}() {}
/**
* Parse it
*/
Value parse();
protected:
/**
* Represents the type of the symbol (both terminals and nonterminals)
*/
enum Symbol {
{{#symbols}}
{{symbol}},
{{/symbols}}
}
/**
* A token, consisting of a Symbol type (should be a terminal) and a Value
*/
struct Token {
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}}
{{#name}}virtual Value reduce_{{name}}(std::deque<Token> subparts) = 0;{{/name}}
{{^name}}virtual Value reduce_{{index}}(std::deque<Token> subparts) = 0;{{/name}}
2016-12-31 16:16:26 +01:00
{{/rules}}
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-01 12:44:40 +01:00
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
};
2016-12-31 16:16:26 +01:00
/***************************
* Parser implementation *
***************************/
template <typename Value>
Value {{name}}::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) {
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;
Symbol symbol = tmp >> 31;
std::uint32_t rule = tmp & ((1ull << 32) - 1);
2017-01-01 12:44:40 +01:00
std::deque<Token> dq;
for (decltype(RECUDE_COUNT[rule]) i = 0; i < REDUCE_COUNT[rule]; i++) {
dq.emplace_front(std::move(valueStack.top()));
valueStack.pop();
stateStack.pop();
}
switch (rule) {
{{#rules}}
case {{index}}:
{{#name}}valueStack.emplace({symbol, reduce_{{name}}(std::move(dq))}){{/name}}
{{^name}}valueStack.emplace({symbol, reduce_{{index}}(std::move(dq))}){{/name}}
2017-01-01 12:44:40 +01:00
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;
}
}
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 */