LR(1) table generation

This commit is contained in:
Robin Jadoul 2017-01-11 17:24:21 +01:00
parent e9d56797ac
commit 2e95d671bf
9 changed files with 237 additions and 1 deletions

View File

@ -10,6 +10,7 @@
#include "Parsodus/lrtables/generator.h"
#include "Parsodus/lrtables/LR0Itemset.h"
#include "Parsodus/lrtables/SLR1Itemset.h"
#include "Parsodus/lrtables/LR1Itemset.h"
#include "Parsodus/util/parserType.h"
namespace pds {
@ -30,6 +31,7 @@ namespace pds {
void registerLR() {
registerBackend(std::make_unique<T<lr::Generator<lr::LR0Itemset>>>(util::ParserType::LR_0));
registerBackend(std::make_unique<T<lr::Generator<lr::SLR1Itemset>>>(util::ParserType::SLR_1));
registerBackend(std::make_unique<T<lr::Generator<lr::LR1Itemset>>>(util::ParserType::LR_1));
}
/**

View File

@ -0,0 +1,22 @@
#pragma once
#ifndef PARSODUS_LRTABLES_LR1ITEM_H_OEUCDMZL
#define PARSODUS_LRTABLES_LR1ITEM_H_OEUCDMZL
#include "Parsodus/lrtables/LR0Item.h"
namespace pds {
namespace lr {
struct LR1Item {
std::shared_ptr<Rule> rule;
std::size_t dotIdx;
std::set<std::string> lookaheads;
bool operator<(const LR1Item& rhs) const; ///< Useful to keep it in a set/map
bool operator==(const LR1Item& rhs) const;
};
} /* lr */
} /* pds */
#endif /* PARSODUS_LRTABLES_LR1ITEM_H_OEUCDMZL */

View File

@ -0,0 +1,24 @@
#pragma once
#ifndef PARSODUS_LRTABLES_LR1ITEMSET_H_AFGBM4VN
#define PARSODUS_LRTABLES_LR1ITEMSET_H_AFGBM4VN
#include "Parsodus/lrtables/LR1ItemsetBase.h"
namespace pds {
namespace lr {
class LR1Itemset : public LR1ItemsetBase<LR1Itemset> {
public:
LR1Itemset();
LR1Itemset(std::shared_ptr<Rule> start);
bool canMerge(const LR1Itemset& rhs) const;
void merge(const LR1Itemset& rhs);
private:
};
} /* lr */
} /* pds */
#endif /* PARSODUS_LRTABLES_LR1ITEMSET_H_AFGBM4VN */

View File

@ -0,0 +1,142 @@
#pragma once
#ifndef PARSODUS_LRTABLES_LR1ITEMSETBASE_H_EREKWQSM
#define PARSODUS_LRTABLES_LR1ITEMSETBASE_H_EREKWQSM
#include "Parsodus/lrtables/LR1Item.h"
#include "Parsodus/util/symbols.h"
#include <algorithm>
namespace pds {
namespace lr {
template <typename Itemset>
class LR1ItemsetBase {
public:
LR1ItemsetBase();
LR1ItemsetBase(std::shared_ptr<Rule> start);
static bool needsFollow();
void close(const Grammar& g);
Itemset succ(std::string sym) const;
bool operator==(const Itemset& rhs) const;
bool empty() const;
std::set<std::size_t> getReduces(const Grammar& g, std::string lookahead) const;
private:
std::set<LR1Item> m_items;
};
template <typename Itemset>
LR1ItemsetBase<Itemset>::LR1ItemsetBase()
{}
template <typename Itemset>
LR1ItemsetBase<Itemset>::LR1ItemsetBase(std::shared_ptr<Rule> start) {
m_items.emplace(LR1Item{start, 0, {util::EOF_PLACEHOLDER}});
}
template <typename Itemset>
bool LR1ItemsetBase<Itemset>::needsFollow() {
return true;
}
template <typename Itemset>
void LR1ItemsetBase<Itemset>::close(const Grammar& g) {
bool changes = true;
std::vector<LR1Item> todo;
std::set<std::pair<std::string, std::string>> added; // (variable, lookahead)
while (changes) {
changes = false;
std::set<LR1Item> toAdd;
for (const LR1Item& i : m_items) {
if (i.dotIdx < i.rule->tail.size()) {
std::string& sym = i.rule->tail[i.dotIdx];
if (g.variables.count(sym)) {
std::vector<std::string> seq(std::vector<std::string>(i.rule->tail.begin() + i.dotIdx + 1, i.rule->tail.end()));
std::set<std::string> first = (*g.first)(seq);
if (first.count("") || !first.size()) {
first.insert(i.lookaheads.begin(), i.lookaheads.end());
first.erase("");
}
for (std::string newLookahead : first) {
if (!added.count({sym, newLookahead})) {
added.emplace(sym, newLookahead);
changes = true;
for (const auto& rule : g.rules) {
if (rule->head == sym) {
toAdd.insert(LR1Item{rule, 0, {newLookahead}});
}
}
}
}
}
}
}
std::vector<LR1Item> newItems;
for (auto& it : m_items) {
newItems.emplace_back(std::move(it));
}
for (const auto& newItem : toAdd) {
bool found = false;
for (auto& oldItem : newItems) {
if (newItem.dotIdx == oldItem.dotIdx && newItem.rule == oldItem.rule) {
found = true;
oldItem.lookaheads.insert(newItem.lookaheads.begin(), newItem.lookaheads.end());
break;
}
}
if (!found) {
newItems.push_back(newItem);
}
}
m_items.clear();
for (auto& it : newItems) {
m_items.emplace(std::move(it));
}
}
}
template <typename Itemset>
Itemset LR1ItemsetBase<Itemset>::succ(std::string sym) const {
Itemset sc;
for (auto& item : m_items) {
if (item.dotIdx < item.rule->tail.size()) {
if (item.rule->tail[item.dotIdx] == sym) {
sc.m_items.insert(LR1Item{item.rule, item.dotIdx + 1, item.lookaheads});
}
}
}
return sc;
}
template <typename Itemset>
bool LR1ItemsetBase<Itemset>::operator==(const Itemset& rhs) const {
return m_items == rhs.m_items;
}
template <typename Itemset>
bool LR1ItemsetBase<Itemset>::empty() const {
return m_items.empty();
}
template <typename Itemset>
std::set<std::size_t> LR1ItemsetBase<Itemset>::getReduces(const Grammar& g, std::string lookahead) const {
std::set<std::size_t> result;
for (const auto& item : m_items) {
if (item.dotIdx >= item.rule->tail.size() && item.lookaheads.count(lookahead)) {
result.insert(std::find(g.rules.begin(), g.rules.end(), item.rule) - g.rules.begin());
}
}
return result;
}
} /* lr */
} /* pds */
#endif /* PARSODUS_LRTABLES_LR1ITEMSETBASE_H_EREKWQSM */

View File

@ -5,7 +5,7 @@
namespace pds {
namespace util {
enum class ParserType {LR_0, SLR_1, LALR_1};
enum class ParserType {LR_0, SLR_1, LR_1, LALR_1};
}
}

View File

@ -23,6 +23,8 @@ add_library(Parsodus-tables
lrtables/LR0Item.cpp
lrtables/LR0Itemset.cpp
lrtables/SLR1Itemset.cpp
lrtables/LR1Item.cpp
lrtables/LR1Itemset.cpp
)
# add_library(Parsodus-backends

View File

@ -36,6 +36,8 @@ namespace pds {
config.parserType = util::ParserType::LALR_1;
} else if(token.content == "SLR(1)") {
config.parserType = util::ParserType::SLR_1;
} else if(token.content == "LR(1)") {
config.parserType = util::ParserType::LR_1;
} else
throw InputParserException("Unkown parser type");
} else {

21
src/lrtables/LR1Item.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "Parsodus/lrtables/LR1Item.h"
namespace pds {
namespace lr {
bool LR1Item::operator<(const LR1Item& rhs) const {
if (dotIdx != rhs.dotIdx) {
return dotIdx < rhs.dotIdx;
} else if (rule != rhs.rule) {
return rule < rhs.rule;
} else {
return lookaheads < rhs.lookaheads;
}
}
bool LR1Item::operator==(const LR1Item& rhs) const {
return dotIdx == rhs.dotIdx && rule == rhs.rule && lookaheads == rhs.lookaheads;
}
} /* lr */
} /* pds */

View File

@ -0,0 +1,21 @@
#include "Parsodus/lrtables/LR1Itemset.h"
namespace pds {
namespace lr {
LR1Itemset::LR1Itemset() : LR1ItemsetBase<LR1Itemset>()
{}
LR1Itemset::LR1Itemset(std::shared_ptr<Rule> start) : LR1ItemsetBase<LR1Itemset>(start)
{}
bool LR1Itemset::canMerge(const LR1Itemset&) const {
return false;
}
void LR1Itemset::merge(const LR1Itemset&) {
//NO-OP
}
} /* lr */
} /* pds */