Cleanup 'debug' code
[miniREPL.git] / Sources / interp.cpp
blob5cce08de466ef803b0324be61cb35decd1f99f21
1 /*
2 * miniREPL
3 * https://github.com/vrmiguel/minirepl
5 * Copyright (c) 2020 Vinícius R. Miguel <vinicius.miguel at unifesp.br>
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
26 #include "Headers/interp.h"
27 #include "Headers/os.h"
28 #include <algorithm>
29 #include <cmath>
31 using std::stoi;
32 using std::to_string;
34 inline bool isdigit(char c)
36 return (c > 47 && c < 58);
39 inline bool ischar(char c)
41 return (c > 64 && c < 91) || (c > 96 && c < 123);
44 Interpreter::Interpreter(string text)
46 this->text = text;
47 this->pos = 0;
50 void Interpreter::eval_bin_op(vector<Token> &tokens, int optype, int index)
52 try
54 if(tokens[index-1].var_type == INTEGER && tokens[index+1].var_type == INTEGER)
56 int left_oper = stoi(tokens[index-1].var_value);
57 int right_oper = stoi(tokens[index+1].var_value);
58 if (optype == PLUS)
59 tokens[index-1].var_value = to_string(left_oper + right_oper);
60 else if (optype == MINUS)
61 tokens[index-1].var_value = to_string(left_oper - right_oper);
62 else if (optype == MULT)
63 tokens[index-1].var_value = to_string(left_oper * right_oper);
64 else if (optype == DIV)
65 tokens[index-1].var_value = to_string(left_oper / right_oper);
66 else if (optype == EXP)
67 tokens[index-1].var_value = to_string((int) pow(left_oper, right_oper));
68 tokens.erase(tokens.begin() + index);
69 tokens.erase(tokens.begin() + index);
71 } catch (const std::exception& e) {
72 cerr << "Syntax error.\n" << e.what() << '\n';
73 exit(2);
77 Token Interpreter::get_token()
79 if (pos > (text.size() -1))
81 return Token(EOL, "");
84 char cur_char = text[pos];
86 if (cur_char == ' ')
88 pos++;
89 return Token(SPACE, cur_char);
92 if (cur_char == '=')
94 pos++;
95 return Token(ATTRIB, cur_char);
98 if (cur_char == '^')
100 pos++;
101 return Token(EXP, cur_char);
104 // if (cur_char == '(')
105 // {
106 // pos++;
107 // return Token(OPENPAR, cur_char);
108 // }
110 // if (cur_char == ')')
111 // {
112 // pos++;
113 // return Token(CLOSEPAR, cur_char);
114 // }
116 if (isdigit(cur_char))
118 string intval (1, cur_char);
121 while(isdigit(text[pos+1]))
122 intval = intval + text[++pos];
123 pos++;
124 return Token(INTEGER, intval);
126 catch (const std::out_of_range& oor)
128 cout << "Exception " << oor.what() << " catched.";
129 pos++;
130 return Token(INTEGER, intval);
134 if (ischar(cur_char))
136 string varname (1, cur_char);
139 while(ischar(text[pos+1]))
140 varname = varname + text[++pos];
141 pos++;
142 return Token(STRING, varname);
144 catch (const std::out_of_range& oor)
146 cout << "Exception " << oor.what() << " catched.";
147 pos++;
148 return Token(STRING, varname);
152 if (cur_char == '+')
154 pos++;
155 return Token(PLUS, cur_char);
159 if (cur_char == '-')
161 pos++;
162 return Token(MINUS, cur_char);
165 if (cur_char == '*')
167 pos++;
168 return Token(MULT, cur_char);
171 if (cur_char == '/')
173 pos++;
174 return Token(DIV, cur_char);
177 cerr << cur_char << " is an invalid token.";
178 return Token(EOL, "");
181 void Interpreter::perform_mult_and_div(vector<Token>& tokens)
183 Token mul(MULT, '*'), div(DIV, '/'); // TODO: pls optimize this
184 while (contains(tokens, mul) || contains(tokens, div))
186 for(unsigned long int i = 0; i < (unsigned int) tokens.size(); i++)
188 if (tokens[i].var_type == MULT)
190 eval_bin_op(tokens, MULT, i);
191 break;
194 if (tokens[i].var_type == DIV)
196 eval_bin_op(tokens, DIV, i);
197 break;
203 void Interpreter::perform_add_and_subtraction(vector<Token>& tokens)
205 while (tokens.size() > 2)
207 for(unsigned long int i = 0; i < (unsigned int) tokens.size(); i++)
209 if (tokens[i].var_type == PLUS)
211 eval_bin_op(tokens, PLUS, i);
212 break;
215 if (tokens[i].var_type == MINUS)
217 eval_bin_op(tokens, MINUS, i);
218 break;
224 void Interpreter::perform_unary_minus(vector<Token> &tokens)
226 if(tokens[0].var_type == MINUS)
228 if(tokens[1].var_type != INTEGER)
230 cerr << "Syntax error.\n";
231 exit(0);
233 if(stoi(tokens[1].var_value) > 0)
234 tokens[1].var_value = "-" + tokens[1].var_value;
236 tokens.erase(tokens.begin());
240 void Interpreter::perform_exp(vector<Token> &tokens)
242 Token exp(EXP, '^');
243 while (contains(tokens, exp))
245 for(unsigned long int i = 0; i < (unsigned int) tokens.size(); i++)
247 if (tokens[i].var_type == EXP)
249 eval_bin_op(tokens, EXP, i);
250 break;
256 Token Interpreter::replace_variable(vector<Token>& tokens)
258 //Token var_symbol (STRING, var.var_name);
259 for(unsigned long int i = 0; i < (unsigned int) tokens.size(); i++)
261 if (tokens[i].var_type == STRING)
263 findres_t res = var_find(tokens[i].var_value); // Looks for a variable with the given string value
264 if (!res.was_found) // Variable not found
266 cerr << "Variable " << tokens[i].var_value << " is not defined.";
267 return Token(EOL, "");
269 else{
270 // The variable was found
271 tokens[i].var_type = INTEGER;
272 tokens[i].var_value = res.var; // so we'll replace it on the expression.
276 return Token(STRING, "success");
279 Token Interpreter::expr()
281 vector<Token> created_tokens;
282 string var_name;
284 for(;;)
286 Token tok = get_token(); // Iterates through Interpreter::text and saves all tokens (except whitespaces)
287 if(is_verbose)
288 cout << tok << ' ';
289 if (tok.var_type != SPACE)
290 created_tokens.push_back(tok);
291 if(tok.var_type == EOL || tok.var_type == EOFile)
292 break;
295 // Verifies if a string was read
296 if (created_tokens[0].var_type == STRING)
298 // Verifies if there was an attribution of value
299 if (created_tokens[1].var_type != ATTRIB)
301 findres_t res = var_find(created_tokens[0].var_value);
302 if (!res.was_found)
303 { // Variable not found
304 cerr << "Variable " << created_tokens[0].var_value << " is not defined.";
305 return Token(EOL, "");
307 if(created_tokens.size() == 2) // User wants to print a variable ..
308 return Token(INTEGER, res.var); // .. so let's return the value of that variable
310 else
312 // In this case, there was attribution. We'll calculate the value of the expression and then
313 // attribute this value to the given variable later on.
314 if (created_tokens.size() == 3)
316 cerr << "Variable without a value.";
317 return Token(EOL, "");
319 var_name = created_tokens[0].var_value;
320 created_tokens.erase(created_tokens.begin());
321 created_tokens.erase(created_tokens.begin());
325 // Verifies if there are variables inside of the expression
326 // If there are, it replaces the variables with their contents
327 // If the expression uses undefined variables, a warning is sent ..
328 // .. and an EOL token is returned.
329 Token response = replace_variable(created_tokens);
330 if (response.var_type == EOL)
331 return response; // Expression uses an undefined variable.
333 perform_unary_minus(created_tokens);
334 perform_exp(created_tokens);
336 // Does multiplication and division operations, if they exist
337 perform_mult_and_div(created_tokens);
339 // Does addition and subtraction operations, if they exist
340 perform_add_and_subtraction(created_tokens);
342 if (!var_name.empty())
344 // var_name isn't empty, so we'll create a variable with that value
345 findres_t res = var_find(var_name);
346 if (!res.was_found) // Variable didn't exist, so we'll create it.
348 var_list[var_name] = created_tokens[0].var_value;
350 else
351 { // Variable already exists, so we need to update its value.
352 var_list[var_name] = created_tokens[0].var_value;
355 return created_tokens[0];