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"
|
#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 {
|
namespace solar {
|
||||||
|
|
||||||
class generator_slr_t : public generator_t {
|
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:
|
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);
|
return std::get<1>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static symbol_t make_nonterm(const std::string &value) {
|
static symbol_t make_nonterm(const std::string &value) {
|
||||||
return symbol_t(SYMBOL_TYPE_NONTERM, 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};
|
char v[2] = {char(value), 0};
|
||||||
return symbol_t(SYMBOL_TYPE_CHAR, v);
|
return symbol_t(SYMBOL_TYPE_CHAR, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static symbol_t empty() {
|
||||||
|
return make_term("");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue