-
Notifications
You must be signed in to change notification settings - Fork 0
/
InterpretationEngine.cpp
245 lines (224 loc) · 8.28 KB
/
InterpretationEngine.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#include <iostream>
#include <assert.h>
#include <vector>
#include "InterpretationEngine.h"
#include "Command.h"
using namespace std;
///////////////////////////////////////////////////////////////////////////////
////////////////////// INTERPRETATION ENGINE CLASS START //////////////////////
///////////////////////////////////////////////////////////////////////////////
//initialize singleton intEngine_ to nullptr
shared_ptr<InterpretationEngine> InterpretationEngine::inpretEngine_ = nullptr;
//constructor
InterpretationEngine::InterpretationEngine() {
PIntEng_ = make_shared<PImplIntEngine> ();
PIntEng_->commands_ = COMMANDS;
}
shared_ptr<InterpretationEngine> InterpretationEngine::instance() {
if (inpretEngine_ == nullptr) {
inpretEngine_ = shared_ptr<InterpretationEngine>(new InterpretationEngine());
}
return inpretEngine_;
}
//CORE LOGIC FUNCTIONS
//process input for commands. Only primitive commands atm
deque<string> InterpretationEngine::interpretCommands(istream& sin) {
//SKIP WHITESPACE
sin >> skipws;
//set up
deque <string> result;
string cmd = "";
sin >> cmd;
int multiplicity = getMultiplicity(cmd); //determine multiplicity of command
string realCmd = getRealCommand(cmd); //determine real command
//check validity of cmd
if (!assertValidCommand()) {
cout << "Command " << realCmd << " is invalid" << endl;
return result;
};
result.push_back(realCmd);
//check for arguments
int subIter = 0;
while (subIter < COMMAND_ARGS.at(realCmd)) {
string arg = "";
sin >> arg;
//note no checking of validity of arg atm
result.push_back(arg);
subIter++; //increment subIter (over numArgs for this command)
}
deque<string> mainCmds = MultiplyCommand(result, multiplicity);
string postCmd = getPostCommand(realCmd);
if (postCmd != "") {
mainCmds.push_back(postCmd);
}
return mainCmds;
}
//process input for Command Line Arguments
//since user's cannot define compound (and recursive) clas, we can linearlly process argv
deque<string> InterpretationEngine::interpretCLAs(int argc, char** argv) {
deque<string> result;
int iter = 1;
while (iter < argc) {
string cla = argv[iter];
//check validity of cla
assertValidCla(cla);
result.push_back(cla); //valid, add to deque
iter++;
//check for arguments
int subIter = 0;
while (subIter < CLA_ARGS.at(cla)) {
if (iter >= argc) {
cerr << "Illegal Number of Command Line Argument - Missing argument(s) for command \"" + cla
<< "\"" << endl << "Exiting program" << endl;
exit(1);
}
//note no checking of validity of arg atm
result.push_back(argv[iter]);
subIter++; //increment subIter (over numArgs for this command)
iter++; //increment Iter over all elements
}
}
return result;
}
//retrive what command to execute after cmd
string InterpretationEngine::getPostCommand(string cmd) {
//depending on command, apply any commmands that must
//occur after that cmd (or set of those commands)
if (cmd == "left" || cmd == "right" || cmd == "down"
|| cmd == "clockwise" || cmd == "counterclockwise") {
//directional block move
return "POSTMOVE";
}
else if (cmd == "sequence") {
//post execution of sequence(s)
return "POSTSEQUENCE";
}
else {
return "";
}
}
//get the multiplicity of the command from input
int InterpretationEngine::getMultiplicity(string cmd) {
string mult = "";
//get all prefixed chars
for (int i = 0; i < cmd.length(); i++) {
if (isdigit(cmd[i])) {
string curr(1, cmd[i]);
mult.append(curr);
} else break;
}
//return multiplicity as a number
int res = (mult.length() == 0)? 1 : stoi(mult);
if (mult.length() == 0) return 1;
else return stoi(mult);
}
//get the parsed command (ie without numbers)
string InterpretationEngine::getRealCommand(string cmd) {
//remove any prefixed numbers
int numNumbers = 0;
for (int i = 0; i < cmd.length(); i++) {
if (isdigit(cmd[i])) {
numNumbers++;
} else break;
}
//get full form of command if prefixed
return getFullCommand(cmd.substr(numNumbers));
}
//get the real, recognized command from input
string InterpretationEngine::getFullCommand(string cmd) {
//if cmd is already a full command name, return it
//need to consider if it's an aliased name as well
if (assertRecognizedCommand(cmd)) {
setValidCommand();
return decodeAliasCommand(cmd);
}
//char by char compare with other commands until a unique
vector<string> possibleCmds;
for (int i = 0; i < cmd.length(); i++) {
for (auto &realCmd : PIntEng_->commands_) {
//if real command and cmd are the same up to i, add realCommand
//to list of possible commands determined from this prefix
if (cmd.substr(0, i+1) == realCmd.substr(0, i+1) && cmd.length() <= realCmd.length()) {
possibleCmds.push_back(realCmd);
}
}
//if only one possible command determined, then we have unique rep
if (possibleCmds.size() == 1) {
setValidCommand();
//in case of an aliased command, must return real command
return decodeAliasCommand(possibleCmds.front());
}
//else clear possible commands and check again by increasing prefix depth
possibleCmds.clear();
}
//if nothing returned upon termination of loop, either nothing is represented by cmd
//or cmd represents multiple commands so we cannot perform either -> returning protected command for failure
setInvalidCommand();
return cmd;
}
//if recognized command is an alias, decode its mapping to get the real command
string InterpretationEngine::decodeAliasCommand(string cmd) {
//if cmd is an alias command, return real command, otherwise return cmd
for (auto &aliasCmd : PIntEng_->cmdAlias) {
if (cmd == aliasCmd.first) {
//it's an alias command, return real command
return aliasCmd.second;
}
}
//not an alias command
//since this is only called on recognized commands, it must be a primitive command name
return cmd;
}
//multiply a command by given multiple
deque<std::string> InterpretationEngine::MultiplyCommand(std::deque<std::string> cmds, int mult) {
deque<std::string> result;
for (int i = 0; i < mult; i++) {
//repeatedly append cmmds to result to get "repeating commands" effect
result.insert(result.end(), cmds.begin(), cmds.end());
}
return result;
}
//UTILITY METHODS
bool InterpretationEngine::assertRecognizedCommand(string cmd) {
//check that cmd is in list of recognized comands in InterpretaionEngine instant
return (PIntEng_->commands_.find(cmd) != PIntEng_->commands_.end());
}
bool InterpretationEngine::assertValidCommand() {
//check that the command was processed to be a recognized command
return PIntEng_->isValidCmd;
}
void InterpretationEngine::assertValidCla(string cla) {
//check that cla is in list of valid clas
if(CLAS.find(cla) != CLAS.end()) {
return;
}
cerr << "Illegal Command Line Argument: \"" + cla << "\"" << endl << "Exiting program" << endl;
exit(1);
}
//MUTATORS
void InterpretationEngine::addAlias (string newCmd, string cmd) {
PIntEng_->cmdAlias.insert(pair<string, string>(newCmd, cmd));
}
void InterpretationEngine::removeAlias (string cmd) {
//check if cmd is key to an alias, and remove it
map<string, string>::iterator it;
it = PIntEng_->cmdAlias.find(cmd);
if (it != PIntEng_->cmdAlias.end()) {
//delete alias
PIntEng_->cmdAlias.erase(it);
}
}
void InterpretationEngine::addCommand (string newCmd) {
//adds cmd to recognized commands
PIntEng_->commands_.insert(newCmd);
}
void InterpretationEngine::removeCommand (string cmd) {
//reomves cmd from recognized commands
PIntEng_->commands_.erase(cmd);
}
void InterpretationEngine::setValidCommand() {
PIntEng_->isValidCmd = true;
}
void InterpretationEngine::setInvalidCommand() {
PIntEng_->isValidCmd = false;
}