Debug output from the table generator

This commit is contained in:
Thomas Avé 2017-01-26 21:02:30 +01:00
parent dd895152f7
commit 10798dea7a
7 changed files with 117 additions and 33 deletions

16
TODO
View File

@ -18,28 +18,28 @@ K> Parsodus Parsodus parser
#R 1 enkel LR(1) #R 1 enkel LR(1)
#K 1 LR(1) + LALR(1) #K 1 LR(1) + LALR(1)
#T 1 LR(0) #T 1 LR(0)
-> Table generator (independent of specific tables)??? -> Table generator (independent of specific tables)???
-> JSON/example tests
-> presentation -> presentation
-> Error reporting
-> publication / LICENSE -> publication / LICENSE
-> --- logging
-> write configuration sets, table
-> Generator: logging
-> driver/main: debug flag
----------------------------------------------------------------------- -----------------------------------------------------------------------
- MOSTLY DONE - - MOSTLY DONE -
----------------------------------------------------------------------- -----------------------------------------------------------------------
R> README R> README: bash completion + precedence
R> JSON port -> rewrite once named rules exist R> JSON port -> rewrite once named rules exist
----------------------------------------------------------------------- -----------------------------------------------------------------------
- DONE - - DONE -
----------------------------------------------------------------------- -----------------------------------------------------------------------
-> logging
-> write configuration sets, table
-> Generator: logging
-> driver/main: debug flag
-> Error reporting
-> bool specialization in backend? -> bool specialization in backend?
T> Parsodus regex parser in Lexesis T> Parsodus regex parser in Lexesis
-> Vrijgeven in libraryformaat: mogelijkheid verschillende tokens opvragen -> Vrijgeven in libraryformaat: mogelijkheid verschillende tokens opvragen

View File

@ -4,6 +4,9 @@
#include "Parsodus/lrtables/LR0Item.h" #include "Parsodus/lrtables/LR0Item.h"
#include <ostream>
#include <set>
namespace pds { namespace pds {
namespace lr { namespace lr {
@ -24,6 +27,21 @@ public:
bool merge(const Itemset& rhs); bool merge(const Itemset& rhs);
bool empty() const; bool empty() const;
friend std::ostream& operator<<(std::ostream& os, const LR0ItemsetBase<Itemset>& its) {
for (const auto& it : its.m_items) {
os << it.rule->head << " ->";
for (std::size_t i = 0; i < it.rule->tail.size(); i++) {
if (i == it.dotIdx)
os << " ·";
os << " " << it.rule->tail[i];
}
if (it.dotIdx == it.rule->tail.size())
os << " ·";
os << std::endl;
}
return os;
}
protected: protected:
std::set<LR0Item> m_items; std::set<LR0Item> m_items;
}; };

View File

@ -6,6 +6,8 @@
#include "Parsodus/util/symbols.h" #include "Parsodus/util/symbols.h"
#include <algorithm> #include <algorithm>
#include <ostream>
#include <set>
namespace pds { namespace pds {
namespace lr { namespace lr {
@ -24,6 +26,28 @@ public:
bool empty() const; bool empty() const;
std::set<std::size_t> getReduces(const Grammar& g, std::string lookahead) const; std::set<std::size_t> getReduces(const Grammar& g, std::string lookahead) const;
friend std::ostream& operator<<(std::ostream& os, const LR1ItemsetBase<Itemset>& its) {
for (const auto& it : its.m_items) {
os << it.rule->head << " ->";
for (std::size_t i = 0; i < it.rule->tail.size(); i++) {
if (i == it.dotIdx)
os << " ·";
os << " " << it.rule->tail[i];
}
if (it.dotIdx == it.rule->tail.size())
os << " ·";
os << " [";
for (auto la = it.lookaheads.cbegin(); la != it.lookaheads.cend(); la++) {
if (la != it.lookaheads.cbegin())
os << ", ";
os << *la;
}
os << "]" << std::endl;
}
return os;
}
protected: protected:
std::vector<LR1Item> m_items; std::vector<LR1Item> m_items;
}; };

View File

@ -6,6 +6,8 @@
#include "Parsodus/util/symbols.h" #include "Parsodus/util/symbols.h"
#include "Parsodus/lrtables/table.h" #include "Parsodus/lrtables/table.h"
#include "g3log/g3log.hpp"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <memory> #include <memory>
@ -80,6 +82,9 @@ LRTable Generator<Itemset>::generate() {
m_gram.variables.begin(), m_gram.variables.end(), m_gram.variables.begin(), m_gram.variables.end(),
std::inserter(symbols, symbols.end())); std::inserter(symbols, symbols.end()));
std::map<std::size_t, std::map<std::string, std::pair<Action, std::size_t>>> errors;
bool reduceReduce = false;
std::queue<std::pair<std::size_t, Itemset>> q; std::queue<std::pair<std::size_t, Itemset>> q;
q.emplace(0, itemsets[0]); q.emplace(0, itemsets[0]);
while (!q.empty()) { while (!q.empty()) {
@ -131,7 +136,6 @@ LRTable Generator<Itemset>::generate() {
table.act[curIdx][term] = std::make_pair(Action::ACCEPT, 0); table.act[curIdx][term] = std::make_pair(Action::ACCEPT, 0);
} else if (table.act[curIdx].count(term)) { } else if (table.act[curIdx].count(term)) {
if (table.act[curIdx][term].first == Action::SHIFT) { if (table.act[curIdx][term].first == Action::SHIFT) {
//Shift-Reduce conflict, rapport and resolve it (TODO)
bool handled = false; bool handled = false;
auto rightTokenIt = m_gram.precedence.find(term); auto rightTokenIt = m_gram.precedence.find(term);
@ -151,15 +155,21 @@ LRTable Generator<Itemset>::generate() {
} else if (leftPrec.second == PrecedenceType::RIGHT) { } else if (leftPrec.second == PrecedenceType::RIGHT) {
// Keep the shift // Keep the shift
handled = true; handled = true;
} //Nonassoc falls through } else {
//make it an error
table.act[curIdx][term] = {Action::ERROR, 0};
handled = true;
}
}
if (!handled) {
LOG(WARNING) << "Shift/reduce conflict in state " << curIdx << ", favouring shift" << std::endl;
errors[curIdx][term] = {Action::REDUCE, rule_applied};
} }
if (!handled)
throw std::runtime_error("shift-reduce");
} else if (table.act[curIdx][term].first == Action::REDUCE } else if (table.act[curIdx][term].first == Action::REDUCE
&& table.act[curIdx][term].second != rule_applied) { && table.act[curIdx][term].second != rule_applied) {
//Reduce-Reduce conflict, rapport it (TODO) LOG(WARNING) << "Reduce/reduce conflict in state " << curIdx << std::endl;
throw std::runtime_error("reduce-reduce"); errors[curIdx][term] = {Action::REDUCE, rule_applied};
reduceReduce = true;
} else { } else {
//Reduce using the same rule, no problem, NO-OP //Reduce using the same rule, no problem, NO-OP
} }
@ -171,10 +181,59 @@ LRTable Generator<Itemset>::generate() {
} }
} }
auto reporter = [&table](std::size_t idx, std::string sym, const std::pair<Action, std::size_t>& p) -> std::string {
switch (p.first) {
case Action::ERROR:
return "on " + sym + " fail\n";
case Action::SHIFT:
return "on " + sym + " shift and go to " + std::to_string(table.act[idx][sym].second) + "\n";
case Action::REDUCE:
return "on " + sym + " reduce with rule " + std::to_string(table.act[idx][sym].second) + "\n";
case Action::ACCEPT:
return "on " + sym + " accept\n";
default:
return "";
}
};
for (std::size_t idx = 0; idx < itemsets.size(); idx++) {
LOG(INFO) << "State " << idx << std::endl
<< itemsets[idx] << std::endl;
for (std::string terminal : m_gram.terminals) {
auto pIt = table.act[idx].find(terminal);
if (pIt != table.act[idx].end()) {
LOG(INFO) << reporter(idx, terminal, pIt->second);
} else {
LOG(INFO) << reporter(idx, terminal, {Action::ERROR, 0});
}
}
LOG(INFO) << std::endl;
bool doneGoto = false, doneError = false;
for (std::string var : m_gram.variables) {
if (table.goto_[idx].count(var)) {
LOG(INFO) << "after " << var << " go to state " << table.goto_[idx][var] << std::endl;
doneGoto = true;
}
}
if (doneGoto)
LOG(INFO) << std::endl;
for (auto& p : errors[idx]) {
doneError = true;
LOG(INFO) << "! " << reporter(idx, p.first, p.second);
}
if (doneError)
LOG(INFO) << std::endl;
LOG(INFO) << std::string(50, '=') << std::endl << std::endl;
}
if (reduceReduce) {
throw std::runtime_error("Stopped generating because of errors in the file");
}
return table; return table;
} }
} /* lr */ } /* lr */
} /* pdf */ } /* pds */
#endif /* PARSODUS_LRTABLES_GENERATOR_H_YW3GIUNH */ #endif /* PARSODUS_LRTABLES_GENERATOR_H_YW3GIUNH */

View File

@ -119,9 +119,6 @@ inline std::string to_string({{name}}_Symbol s) {
case {{name}}_Symbol::{{symbol}}: case {{name}}_Symbol::{{symbol}}:
return "{{symbol}}"; return "{{symbol}}";
{{/symbols}} {{/symbols}}
default:
//should not happen
return "?";
} }
} }

View File

@ -45,15 +45,6 @@ TEST(lr0, test0) {
grammar.rules.push_back(std::make_shared<pds::Rule>(*rule)); grammar.rules.push_back(std::make_shared<pds::Rule>(*rule));
{
pds::lr::Generator<pds::lr::LR0Itemset> g(grammar);
ASSERT_THROW(g.generate(), std::runtime_error);
try {
g.generate();
} catch (std::runtime_error& e) {
ASSERT_EQ(std::string("shift-reduce"), e.what());
}
}
{ {
pds::lr::Generator<pds::lr::SLR1Itemset> g(grammar); pds::lr::Generator<pds::lr::SLR1Itemset> g(grammar);
ASSERT_NO_THROW(g.generate()); ASSERT_NO_THROW(g.generate());

View File

@ -86,11 +86,6 @@ TEST(lr1, only) {
{ {
pds::lr::Generator<pds::lr::LALR1Itemset> g(grammar); pds::lr::Generator<pds::lr::LALR1Itemset> g(grammar);
ASSERT_THROW(g.generate(), std::runtime_error); ASSERT_THROW(g.generate(), std::runtime_error);
try {
g.generate();
} catch (std::runtime_error& e) {
ASSERT_EQ(std::string("reduce-reduce"), e.what());
}
} }
} }