Skip to content

Commit ad0f101

Browse files
author
Roland Leißa
committed
numbering + critical_edge_elimination
1 parent 4177cb6 commit ad0f101

File tree

5 files changed

+133
-10
lines changed

5 files changed

+133
-10
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,7 @@ s = ','
5858
| ';'
5959
| (ID | g) '->' ... '->' (ID | g) (* edge statement *)
6060
```
61+
62+
## Entry \& Exit
63+
64+
The first node mentioned is considered the *entry*, the last one the *exit.

include/graphtool/graph.h

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <ostream>
34
#include <fe/driver.h>
45

56
namespace graphtool {
@@ -13,48 +14,88 @@ class Graph {
1314

1415
class Node {
1516
private:
17+
static constexpr auto Not_Visited = size_t(-1);
18+
1619
Node(Sym name)
1720
: name_(name) {}
1821

1922
public:
23+
Sym name() const { return name_; }
24+
size_t pre() const { return pre_; }
25+
size_t post() const { return post_; }
26+
size_t rp() const { return rp_; }
27+
2028
void link(Node* succ) {
2129
this->succs_.emplace(succ);
2230
succ->preds_.emplace(this);
2331
}
2432
const auto& preds() const { return preds_; }
2533
const auto& succs() const { return succs_; }
2634

35+
friend std::ostream& operator<<(std::ostream&, const Node&);
36+
2737
private:
38+
std::pair<size_t, size_t> number(size_t, size_t);
39+
2840
Sym name_;
29-
NodeSet preds_;
30-
NodeSet succs_;
41+
NodeSet preds_, succs_;
42+
size_t pre_ = Not_Visited;
43+
size_t post_ = Not_Visited;
44+
size_t rp_ = Not_Visited;
3145

3246
friend class Graph;
3347
};
3448

35-
Graph() = default;
3649
Graph(const Graph&) = delete;
50+
Graph(fe::Driver& driver)
51+
: driver_(driver) {}
3752
Graph(Graph&& other)
38-
: name_(other.name_)
53+
: driver_(other.driver_)
54+
, name_(other.name_)
55+
, entry_(other.entry_)
56+
, exit_(other.exit_)
3957
, nodes_(std::move(other.nodes_)) {}
4058
~Graph();
4159

4260
Graph& operator=(const Graph&) = delete;
4361
Graph& operator=(Graph&&) = delete;
4462

63+
/// @name Getters
64+
///@{
65+
fe::Driver& driver() { return driver_; }
66+
Sym name() const { return name_; }
67+
const auto& nodes() const { return nodes_; }
68+
const auto& rpo() const { return rpo_; }
69+
///@}
70+
4571
void set_name(Sym name) { name_ = name; }
4672
Node* node(Sym name);
73+
void critical_edge_elimination();
74+
75+
void number();
76+
77+
friend std::ostream& operator<<(std::ostream&, const Graph&);
4778

4879
friend void swap(Graph& g1, Graph& g2) noexcept {
4980
using std::swap;
50-
swap(g1.name_, g2.name_);
51-
swap(g1.nodes_, g2.nodes_);
81+
// clang-format off
82+
swap(g1.driver_, g2.driver_);
83+
swap(g1.name_, g2.name_);
84+
swap(g1.entry_, g2.entry_);
85+
swap(g1.exit_, g2.exit_);
86+
swap(g1.nodes_, g2.nodes_);
87+
// clang-format on
5288
}
5389

5490
private:
91+
fe::Driver& driver_;
5592
Sym name_;
93+
Node* entry_ = nullptr;
94+
Node* exit_ = nullptr;
5695
fe::SymMap<Node*> nodes_;
96+
std::vector<Node*> rpo_;
5797
};
5898

59-
6099
} // namespace graphtool
100+
101+
template<> struct std::formatter<graphtool::Graph::Node> : fe::ostream_formatter {};

src/graphtool/graph.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,78 @@ Graph::~Graph() {
99
Graph::Node* Graph::node(Sym name) {
1010
if (auto i = nodes_.find(name); i != nodes_.end()) return i->second;
1111
auto node = new Node(name);
12+
if (entry_ == nullptr) entry_ = node;
13+
exit_ = node;
1214
auto [_, ins] = nodes_.emplace(name, node);
1315
assert_unused(ins);
1416
return node;
1517
}
1618

19+
/*
20+
* number
21+
*/
22+
23+
void Graph::number() {
24+
auto [n, m] = entry_->number(0, 0);
25+
assert(n == m);
26+
rpo_.resize(n);
27+
for (auto [_, node] : nodes()) {
28+
if (node->post_ != Graph::Node::Not_Visited) {
29+
size_t i = n - node->post_ - 1;
30+
node->rp_ = i;
31+
rpo_[i] = node;
32+
}
33+
}
34+
}
35+
36+
std::pair<size_t, size_t> Graph::Node::number(size_t pre, size_t post) {
37+
if (pre_ == Not_Visited) {
38+
pre_ = pre++;
39+
for (auto succ : succs()) std::tie(pre, post) = succ->number(pre, post);
40+
post_ = post++;
41+
}
42+
return {pre, post};
43+
}
44+
45+
void Graph::critical_edge_elimination() {
46+
std::vector<std::pair<Node*, Node*>> crit;
47+
48+
for (auto [_, node] : nodes_) {
49+
if (node->succs().size() > 1) {
50+
for (auto succ : node->succs()) {
51+
for (auto pred : succ->preds()) {
52+
if (pred->succs().size() > 1) crit.emplace_back(succ, pred);
53+
}
54+
}
55+
}
56+
}
57+
58+
for (auto [v, w] : crit) {
59+
auto name = driver().sym(v->name().str() + "." + w->name().str());
60+
auto x = node(name);
61+
v->succs_.erase(w);
62+
w->preds_.erase(v);
63+
v->link(x);
64+
x->link(w);
65+
}
66+
}
67+
68+
/*
69+
* ostream
70+
*/
71+
72+
std::ostream& operator<<(std::ostream& os, const Graph::Node& node) {
73+
return os << std::format("\t\"{}|{}|{}|{}\"", node.name(), node.pre(), node.post(), node.rp());
74+
}
75+
76+
std::ostream& operator<<(std::ostream& os, const Graph& graph) {
77+
os << std::format("digraph {} {{", graph.name()) << std::endl;
78+
for (const char* sep = ""; auto node : graph.rpo()) {
79+
for (auto succ : node->succs())
80+
os << std::format("\t{} -> {}", *node, *succ) << sep;
81+
sep = "\n";
82+
}
83+
return os << '}' << std::endl;;
84+
}
85+
1786
} // namespace graphtool

src/graphtool/parser.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ namespace graphtool {
1010
using Tag = Tok::Tag;
1111

1212
Parser::Parser(Driver& driver, std::istream& istream, const std::filesystem::path* path)
13-
: lexer_(driver, istream, path)
13+
: graph_(driver)
14+
, lexer_(driver, istream, path)
1415
, error_(driver.sym("<error>"s)) {
1516
init(path);
1617
}

src/main.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ int main(int argc, char** argv) {
1919
"OPTIONS, ARGUMENTS:\n"
2020
" -?, -h, --help"
2121
" -v, --version Display version info and exit.\n"
22-
" -d, --dump Dumps the graphtool program again.\n"
23-
" -e, --eval Evaluate the graphtool program.\n"
22+
" -c, --crit Eliminate critical edges.\n"
2423
" <file> Input file.\n";
2524
std::string input;
25+
bool crit = false;
2626

2727
for (int i = 1; i < argc; ++i) {
2828
if (argv[i] == "-v"s || argv[i] == "--version"s) {
@@ -31,6 +31,8 @@ int main(int argc, char** argv) {
3131
} else if (argv[i] == "-?"s || argv[i] == "-h"s || argv[i] == "--help"s) {
3232
std::cerr << usage;
3333
return EXIT_SUCCESS;
34+
} else if (argv[i] == "-c"s || argv[i] == "--crit"s) {
35+
crit = true;
3436
} else {
3537
if (!input.empty()) throw std::invalid_argument("more than one input file given");
3638
input = argv[i];
@@ -50,6 +52,12 @@ int main(int argc, char** argv) {
5052
std::cerr << num << " error(s) encountered" << std::endl;
5153
return EXIT_FAILURE;
5254
}
55+
56+
if (crit) graph.critical_edge_elimination();
57+
graph.number();
58+
59+
std::ofstream ofs("out.dot");
60+
ofs << graph;
5361
} catch (const std::exception& e) {
5462
std::cerr << "error: " << e.what() << std::endl;
5563
return EXIT_FAILURE;

0 commit comments

Comments
 (0)