-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathAbstractTuringMachine.h
127 lines (98 loc) · 3.29 KB
/
AbstractTuringMachine.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once
#include <iostream>
#include <sstream>
#include <optional>
#include <cassert>
#include <algorithm>
#include <exception>
#include "StringStream.h"
namespace trmch {
enum Move {
LEFT, RIGHT
};
template<
class State = int,
class InputSymbol = char,
class TapeSymbol = char,
class Input = std::string,
class Tape = std::string>
class AbstractTuringMachine {
public:
struct NextStep {
State nextState;
TapeSymbol writeSymbol;
Move whereToMove;
};
virtual ~AbstractTuringMachine() = default;
AbstractTuringMachine(State q0, State qA, State qR)
: initialState(q0),
acceptState(qA),
rejectState(qR) {}
void checkAccept(std::initializer_list<Input> shouldAccept, std::initializer_list<Input> shouldReject) {
using std::cerr;
using std::endl;
for (auto &in : shouldAccept)
if (!accept(in)) {
cerr << "Error" << endl;
}
for (auto &in : shouldReject)
if (!reject(in)) {
cerr << "Error" << endl;
}
}
void debug(const Input &input) const {
Tape finalTape;
bool accepted = accept(input, &finalTape);
std::cout << "Execution of " << quote(input) << ":" << std::endl;
std::cout << (accepted ? "Accepted" : "Rejected") << ", final tape: " << quote(finalTape) << std::endl;
}
[[nodiscard]] bool reject(const Input &input, Tape *finalTape = nullptr) const {
return !accept(input, finalTape);
}
[[nodiscard]] bool accept(const Input &input, Tape *finalTape = nullptr) const {
std::optional<bool> ret;
Tape tape;
State currentState = initialState;
std::size_t currentSymbol = 0;
// First copy input to tape
tape = {input.begin(), input.end()};
while (!ret.has_value()) {
if (currentSymbol >= tape.size()) {
// Expand tape
tape.resize(currentSymbol + 1, blankSymbol);
}
NextStep nextStep;
nextStep.whereToMove = Move::RIGHT; /* Arbitrarly advance to right by default */
nextStep.writeSymbol = tape[currentSymbol]; /* By default don't overwrite anything */
nextStep.nextState = rejectState; /* If no transition found, reject */
oneStep(currentState, tape[currentSymbol], nextStep);
tape[currentSymbol] = nextStep.writeSymbol;
switch (nextStep.whereToMove) {
case Move::LEFT:
if (currentSymbol != 0) --currentSymbol;
break;
case Move::RIGHT:
++currentSymbol;
break;
}
currentState = nextStep.nextState;
if (currentState == acceptState) {
ret = true;
} else if (currentState == rejectState) {
ret = false;
}
}
if (finalTape) {
*finalTape = tape;
}
return ret.value();
}
protected:
virtual void oneStep(State currentState, TapeSymbol currentSymbol, NextStep &nextStep) const = 0;
private:
State acceptState;
State rejectState;
State initialState;
TapeSymbol blankSymbol = ' ';
};
}