generator_slr: implement first and follow set generation
This commit is contained in:
parent
70fc6ba8d2
commit
8feccee75d
3 changed files with 142 additions and 1 deletions
|
@ -25,3 +25,119 @@
|
|||
|
||||
|
||||
#include "generator_slr.hpp"
|
||||
|
||||
|
||||
namespace solar {
|
||||
|
||||
void generator_slr_t::generate_first_sets() {
|
||||
std::set<item_t> items;
|
||||
|
||||
for (const std::string &nonterm : get_nonterminals())
|
||||
first_sets.insert(std::make_pair(nonterm, std::set<symbol_t>()));
|
||||
|
||||
for (const rule_t &rule : get_grammar().rules)
|
||||
items.insert(rule.item);
|
||||
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
|
||||
for (const item_t &item : items) {
|
||||
std::set<symbol_t> ¤t = first_sets[item.get_lhs()];
|
||||
|
||||
if (!item.has_next()) {
|
||||
changed = changed || current.insert(symbol_t::empty()).second;
|
||||
continue;
|
||||
}
|
||||
|
||||
const symbol_t &sym = item.get_next_symbol();
|
||||
|
||||
if (sym.get_type() != SYMBOL_TYPE_NONTERM) {
|
||||
changed = changed || current.insert(sym).second;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const symbol_t &sym2 : first_sets[sym.get_value()]) {
|
||||
changed = changed || current.insert(sym2).second;
|
||||
|
||||
if (sym2 == symbol_t::empty()) {
|
||||
item_t next = item;
|
||||
next.shift();
|
||||
changed = changed || items.insert(next).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generator_slr_t::generate_follow_sets() {
|
||||
generate_first_sets();
|
||||
|
||||
for (const std::string &nonterm : get_nonterminals())
|
||||
follow_sets.insert(std::make_pair(nonterm, std::set<symbol_t>()));
|
||||
|
||||
follow_sets[""].insert(symbol_t::empty());
|
||||
|
||||
bool changed = true;
|
||||
|
||||
while (changed) {
|
||||
changed = false;
|
||||
|
||||
for (const rule_t &rule : get_grammar().rules) {
|
||||
for (item_t item = rule.item; item.has_next(); item.shift()) {
|
||||
const symbol_t &sym = item.get_next_symbol();
|
||||
if (sym.get_type() != SYMBOL_TYPE_NONTERM)
|
||||
continue;
|
||||
|
||||
const std::set<symbol_t> &lhs = follow_sets[item.get_lhs()];
|
||||
std::set<symbol_t> &rhs = follow_sets[sym.get_value()];
|
||||
|
||||
item_t next = item;
|
||||
next.shift();
|
||||
|
||||
bool next_empty = false;
|
||||
|
||||
if (next.has_next()) {
|
||||
const symbol_t &next_sym = next.get_next_symbol();
|
||||
|
||||
if (next_sym.get_type() == SYMBOL_TYPE_NONTERM) {
|
||||
for (const symbol_t &sym2 : first_sets[next_sym.get_value()]) {
|
||||
if (sym2 == symbol_t::empty())
|
||||
next_empty = true;
|
||||
else
|
||||
changed = changed || rhs.insert(sym2).second;
|
||||
}
|
||||
}
|
||||
else {
|
||||
changed = changed || rhs.insert(next_sym).second;
|
||||
}
|
||||
}
|
||||
else {
|
||||
next_empty = true;
|
||||
}
|
||||
|
||||
if (next_empty) {
|
||||
for (const symbol_t &sym2 : lhs)
|
||||
changed = changed || rhs.insert(sym2).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool generator_slr_t::has_reduce_conflict(size_t from, const symbol_t &sym) {
|
||||
return reductions.count(std::make_pair(from, sym));
|
||||
}
|
||||
|
||||
void generator_slr_t::add_reduction(size_t from, size_t rule) {
|
||||
const item_t &item = get_grammar().rules[rule].item;
|
||||
for (const symbol_t sym : follow_sets[item.get_lhs()]) {
|
||||
if (get_shifts().count(std::make_pair(from, sym)))
|
||||
throw conflict_error("shift/reduce conflict");
|
||||
|
||||
if (!reductions.insert(std::make_pair(std::make_pair(from, sym), rule)).second)
|
||||
throw conflict_error("reduce/reduce conflict");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,8 +32,28 @@
|
|||
namespace solar {
|
||||
|
||||
class generator_slr_t : public generator_t {
|
||||
private:
|
||||
std::map<std::pair<size_t, symbol_t>, size_t> reductions;
|
||||
|
||||
std::map<std::string, std::set<symbol_t>> first_sets;
|
||||
std::map<std::string, std::set<symbol_t>> follow_sets;
|
||||
|
||||
void generate_first_sets();
|
||||
void generate_follow_sets();
|
||||
|
||||
protected:
|
||||
virtual bool has_reduce_conflict(size_t from, const symbol_t &sym);
|
||||
virtual void add_reduction(size_t from, size_t rule);
|
||||
|
||||
public:
|
||||
generator_slr_t(const grammar_t &grammar) : generator_t(grammar) {}
|
||||
const std::map<std::pair<size_t, symbol_t>, size_t> & get_reductions() const {
|
||||
return reductions;
|
||||
}
|
||||
|
||||
generator_slr_t(const grammar_t &grammar) : generator_t(grammar) {
|
||||
generate_follow_sets();
|
||||
generate();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ struct symbol_t : public std::tuple<symbol_type_t, std::string> {
|
|||
return std::get<1>(*this);
|
||||
}
|
||||
|
||||
|
||||
static symbol_t make_nonterm(const std::string &value) {
|
||||
return symbol_t(SYMBOL_TYPE_NONTERM, value);
|
||||
}
|
||||
|
@ -61,6 +62,10 @@ struct symbol_t : public std::tuple<symbol_type_t, std::string> {
|
|||
char v[2] = {char(value), 0};
|
||||
return symbol_t(SYMBOL_TYPE_CHAR, v);
|
||||
}
|
||||
|
||||
static symbol_t empty() {
|
||||
return make_term("");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Reference in a new issue