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
26 #include "Headers/interp.h"
27 #include "Headers/os.h"
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
)
50 void Interpreter::eval_bin_op(vector
<Token
> &tokens
, int optype
, int index
)
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
);
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';
77 Token
Interpreter::get_token()
79 if (pos
> (text
.size() -1))
81 return Token(EOL
, "");
84 char cur_char
= text
[pos
];
89 return Token(SPACE
, cur_char
);
95 return Token(ATTRIB
, cur_char
);
101 return Token(EXP
, cur_char
);
104 // if (cur_char == '(')
107 // return Token(OPENPAR, cur_char);
110 // if (cur_char == ')')
113 // return Token(CLOSEPAR, cur_char);
116 if (isdigit(cur_char
))
118 string
intval (1, cur_char
);
121 while(isdigit(text
[pos
+1]))
122 intval
= intval
+ text
[++pos
];
124 return Token(INTEGER
, intval
);
126 catch (const std::out_of_range
& oor
)
128 cout
<< "Exception " << oor
.what() << " catched.";
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
];
142 return Token(STRING
, varname
);
144 catch (const std::out_of_range
& oor
)
146 cout
<< "Exception " << oor
.what() << " catched.";
148 return Token(STRING
, varname
);
155 return Token(PLUS
, cur_char
);
162 return Token(MINUS
, cur_char
);
168 return Token(MULT
, cur_char
);
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
);
194 if (tokens
[i
].var_type
== DIV
)
196 eval_bin_op(tokens
, DIV
, i
);
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
);
215 if (tokens
[i
].var_type
== MINUS
)
217 eval_bin_op(tokens
, MINUS
, i
);
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";
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
)
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
);
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
, "");
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
;
286 Token tok
= get_token(); // Iterates through Interpreter::text and saves all tokens (except whitespaces)
289 if (tok
.var_type
!= SPACE
)
290 created_tokens
.push_back(tok
);
291 if(tok
.var_type
== EOL
|| tok
.var_type
== EOFile
)
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
);
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
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
;
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];