-
Notifications
You must be signed in to change notification settings - Fork 0
/
trigraphs.cpp
140 lines (122 loc) · 4.22 KB
/
trigraphs.cpp
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
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_map>
enum class State { NORMAL, COMMENT, LITERAL };
class Parser {
public:
Parser(const std::string& inputFileName, const std::string& outputFileName);
~Parser();
void parse() noexcept;
private:
void insert(char character) noexcept;
void insertRestOfLine(const std::string& line, size_t startIndex) noexcept;
void toggle(const State state) noexcept;
/// Buffer
std::stringstream buffer_;
/// Current state
State currentState_ = State::NORMAL;
/// Input file
std::ifstream inputFile_;
/// Ouput file
std::ofstream outputFile_;
/// Trigraphs equivalents
std::unordered_map<char, std::string> trigraphEquivalent_;
};
Parser::Parser(const std::string& inputFileName,
const std::string& outputFileName)
: inputFile_(inputFileName), outputFile_(outputFileName) {
// Fill the trigraphs equivalent map
trigraphEquivalent_.emplace('#', "\x3f\x3f\x3d"); // ??=
trigraphEquivalent_.emplace('\\', "\x3f\x3f\x2f"); // ??/
trigraphEquivalent_.emplace('^', "\x3f\x3f\x27"); // ??'
trigraphEquivalent_.emplace('[', "\x3f\x3f\x28"); // ??(
trigraphEquivalent_.emplace(']', "\x3f\x3f\x29"); // ??)
trigraphEquivalent_.emplace('|', "\x3f\x3f\x21"); // ??!
trigraphEquivalent_.emplace('{', "\x3f\x3f\x3c"); // ??<
trigraphEquivalent_.emplace('}', "\x3f\x3f\x3e"); // ??>
trigraphEquivalent_.emplace('~', "\x3f\x3f\x2d"); // ??-
outputFile_
<< "\x3f\x3f\x3dpragma clang diagnostic ignored \"-Wtrigraphs\"\n";
}
Parser::~Parser() {
inputFile_.close();
outputFile_.close();
}
/// Parse `inputFile_`
void Parser::parse() noexcept {
std::string line;
// Parse one line at a time
while (getline(inputFile_, line)) {
char previousChar = 0;
for (size_t i = 0; i < line.size(); ++i) {
// Single line comment
if (line[i] == '/' && line[i] == previousChar &&
currentState_ == State::NORMAL) {
insertRestOfLine(line, i);
break;
}
// Multi-line comment
else if (previousChar == '/' && line[i] == '*' &&
currentState_ == State::NORMAL) {
toggle(State::COMMENT);
} else if (previousChar == '*' && line[i] == '/' &&
currentState_ == State::COMMENT) {
toggle(State::COMMENT);
}
// String literal
else if (line[i] == '\"' && previousChar != '\\' &&
currentState_ != State::COMMENT) {
toggle(State::LITERAL);
}
insert(line[i]);
previousChar = line[i];
}
insert('\n');
}
}
/// Insert a character in the `outputFile_`
void Parser::insert(char character) noexcept {
// If in a comment or a string literal, don't format
if (currentState_ == State::COMMENT || currentState_ == State::LITERAL ||
character == '\n') {
outputFile_ << character;
} else {
const auto it = trigraphEquivalent_.find(character);
if (it != trigraphEquivalent_.end()) {
outputFile_ << it->second;
} else {
outputFile_ << character;
}
}
}
/// Insert the rest of a line without formatting
void Parser::insertRestOfLine(const std::string& line,
size_t startIndex) noexcept {
outputFile_ << line.substr(startIndex, line.size());
}
/// Toggle between `currentState_` and `state`
void Parser::toggle(State state) noexcept {
if (currentState_ == State::NORMAL) {
currentState_ = state;
} else if (currentState_ == state) {
currentState_ = State::NORMAL;
}
}
/// Show the correct usage
static void showUsage() {
std::cout << "trigraphs: invalid arguments" << std::endl;
std::cout << "usage: trigraphs SOURCE DEST" << std::endl;
}
int main(int argc, char* argv[]) {
if (argc != 3) {
showUsage();
return -1;
}
const std::string inputFileName = argv[1];
const std::string outputFileName = argv[2];
Parser parser(inputFileName, outputFileName);
parser.parse();
return 0;
}