1634 lines
44 KiB
C++
1634 lines
44 KiB
C++
/************************************************************************
|
|
MeOS - Orienteering Software
|
|
Copyright (C) 2009-2023 Melin Software HB
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Melin Software HB - software@melin.nu - www.melin.nu
|
|
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
|
|
|
************************************************************************/
|
|
#include "stdafx.h"
|
|
|
|
#include <vector>
|
|
#include <set>
|
|
#include <map>
|
|
#include "parser.h"
|
|
#include "meosException.h"
|
|
#include "meos_util.h"
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
#include "gdioutput.h"
|
|
#include "gdifonts.h"
|
|
#include "localizer.h"
|
|
extern gdioutput *gdi_main;
|
|
|
|
static string readWord(const string &expr, size_t &pos) {
|
|
bool pureNum = true;
|
|
bool firstNum = false;
|
|
bool first = true;
|
|
string res;
|
|
while (pos < expr.size() && isalnum(expr[pos])) {
|
|
res.push_back(expr.at(pos));
|
|
if (!isdigit(expr[pos]))
|
|
pureNum = false;
|
|
else if (first)
|
|
firstNum = true;
|
|
|
|
first = false;
|
|
pos++;
|
|
}
|
|
|
|
if (firstNum && !pureNum)
|
|
throw meosException("Invalid symbol X#" + res);
|
|
|
|
return res;
|
|
}
|
|
|
|
static void matchSE(const string &expr, size_t &pos, char start, char end) {
|
|
assert(expr[pos] == start);
|
|
int count = 1;
|
|
pos++;
|
|
while (pos < expr.size() && count>0) {
|
|
if (expr[pos] == start)
|
|
count++;
|
|
else if (expr[pos] == end)
|
|
count--;
|
|
pos++;
|
|
}
|
|
if (count != 0) {
|
|
string ss, ee;
|
|
ss.push_back(start);
|
|
ee.push_back(end);
|
|
throw meosException("Mismatch of X and Y#" + ss + "#" + ee);
|
|
}
|
|
}
|
|
|
|
static void splitStatements(const string &expr, char separator, const map<char, char> &se, vector<string> &statements) {
|
|
size_t p = 0;
|
|
size_t pold = 0;
|
|
while (p < expr.size()) {
|
|
if (expr[p] == separator) {
|
|
string ex2 = trim(expr.substr(pold, p-pold));
|
|
if (!ex2.empty())
|
|
statements.push_back(ex2);
|
|
pold = ++p;
|
|
}
|
|
else if (se.find(expr[p]) != se.end()) {
|
|
int cut = 0;
|
|
//if (pold == p)
|
|
// cut = 1;
|
|
|
|
matchSE(expr, p, expr[p], se.find(expr[p])->second);
|
|
string ex2 = trim(expr.substr(pold+cut, p-pold-2*cut));
|
|
pold = p;
|
|
|
|
//if (ex2.back() == separator)
|
|
// ex2.pop_back();
|
|
if (!ex2.empty())
|
|
statements.push_back(ex2);
|
|
}
|
|
else if (expr[p] == '(') {
|
|
matchSE(expr, p, '(', ')');
|
|
}
|
|
else
|
|
p++;
|
|
}
|
|
if (p-pold > 0) {
|
|
string end = trim(expr.substr(pold, p-pold));
|
|
if (end.length() > 0)
|
|
statements.push_back(end);
|
|
}
|
|
}
|
|
|
|
ParseNode *Parser::parseif (const string &expr, size_t &pos) {
|
|
eatWhite(expr, pos);
|
|
if (expr[pos] != '(')
|
|
throw meosException("Expected ( after if,\nX#" + expr);
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '(', ')');
|
|
|
|
IfNode *ifn = getif ();
|
|
ifn->condition = parseStatement(expr.substr(start, pos - start - 1), false);
|
|
eatWhite(expr, pos);
|
|
|
|
ifn->iftrue = parseStatement(expr.substr(pos), true);
|
|
|
|
return ifn;
|
|
}
|
|
|
|
ParseNode *Parser::parseReturn(const string &expr, size_t &pos) {
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->right = parseStatement(expr.substr(pos), false);
|
|
un->op = OpReturn;
|
|
return un;
|
|
}
|
|
|
|
ParseNode *Parser::parseWhile(const string &expr, size_t &pos) {
|
|
eatWhite(expr, pos);
|
|
if (expr[pos] != '(')
|
|
throw meosException("Expected ( after while,\nX#" + expr);
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '(', ')');
|
|
|
|
WhileNode *wh = getWhile();
|
|
wh->condition = parseStatement(expr.substr(start, pos - start - 1), false);
|
|
eatWhite(expr, pos);
|
|
|
|
wh->body = parseStatement(expr.substr(pos), true);
|
|
|
|
return wh;
|
|
}
|
|
|
|
ParseNode *Parser::parseFor(const string &expr, size_t &pos) {
|
|
eatWhite(expr, pos);
|
|
if (expr[pos] != '(')
|
|
throw meosException("Expected ( after while,\nX#" + expr);
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '(', ')');
|
|
map<char,char> se;
|
|
vector<string> parts;
|
|
splitStatements(expr.substr(start, pos - start - 1), ';', se, parts);
|
|
|
|
if (parts.size() != 3)
|
|
throw meosException("Syntax error in for(.;.;.),\nX#" + expr);
|
|
|
|
ForNode *fn = getFor();
|
|
if (!trim(parts[0]).empty())
|
|
fn->start = parseStatement(parts[0], false);
|
|
else
|
|
fn->start = getStatement();
|
|
|
|
fn->condition = parseStatement(parts[1], false);
|
|
|
|
if (!trim(parts[2]).empty())
|
|
fn->update = parseStatement(parts[2], false);
|
|
else
|
|
fn->update = getStatement();
|
|
|
|
eatWhite(expr, pos);
|
|
|
|
fn->body = parseStatement(expr.substr(pos), true);
|
|
return fn;
|
|
}
|
|
|
|
int Parser::getLevel(Operator op) {
|
|
switch (op) {
|
|
case OpNone:
|
|
return -1;
|
|
case OpPlus:
|
|
case OpMinus:
|
|
return 2;
|
|
case OpTimes:
|
|
case OpDivide:
|
|
case OpMod:
|
|
return 3;
|
|
|
|
case OpMax:
|
|
case OpMin:
|
|
case OpInc:
|
|
case OpDec:
|
|
return 4;
|
|
|
|
case OpEquals:
|
|
case OpNotEquals:
|
|
case OpLess:
|
|
case OpMore:
|
|
case OpLessEquals:
|
|
case OpMoreEquals:
|
|
return 1;
|
|
|
|
case OpAnd:
|
|
case OpOr:
|
|
return 0;
|
|
|
|
case OpAssign:
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
string Parser::parseMethod(const string &expr, size_t &pos) {
|
|
pos++;
|
|
string sword = readWord(expr, pos);
|
|
eatWhite(expr, pos);
|
|
if (expr[pos] != '(')
|
|
throw meosException("Expected ( after X#" + sword);
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '(', ')');
|
|
if (trim(expr.substr(start, pos-start-1)).size() > 0)
|
|
throw meosException("No arguments expected for X()#" + sword);
|
|
|
|
return sword;
|
|
}
|
|
|
|
ParseNode *Parser::parseValue(const string &word, const string &expr, size_t &pos) {
|
|
eatWhite(expr, pos);
|
|
if (expr[pos] == '[' || expr[pos] == '.') {
|
|
if (isdigit(word[0]))
|
|
throw meosException("Invalid operator in litteral,\nX#" + expr);
|
|
|
|
if (expr[pos] == '[') {
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '[', ']');
|
|
ArrayValueNode *arr = getArrayValue();
|
|
arr->expr = word;
|
|
arr->index = parseStatement(expr.substr(start, pos-start-1), false);
|
|
|
|
eatWhite(expr, pos);
|
|
if (expr[pos] == '[') {
|
|
start = pos + 1;
|
|
matchSE(expr, pos, '[', ']');
|
|
arr->index2 = arr->index;
|
|
arr->index = parseStatement(expr.substr(start, pos-start-1), false);
|
|
}
|
|
else if (expr[pos] == '.') {
|
|
string sword = parseMethod(expr, pos);
|
|
if (sword != "size") {
|
|
throw meosException("Unknown method X#" + word + "." + sword);
|
|
}
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->op = OpSizeSub;
|
|
un->right = arr;
|
|
return un;
|
|
}
|
|
|
|
return arr;
|
|
}
|
|
else if (expr[pos] == '.') {
|
|
string sword = parseMethod(expr, pos);
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->op = OpNone;
|
|
|
|
if (sword == "size") {
|
|
if (isMatrix(word))
|
|
un->op = OpSizeBase;
|
|
else
|
|
un->op = OpSize;
|
|
}
|
|
else if (sword == "sort") {
|
|
un->op = OpSortArray;
|
|
}
|
|
|
|
if (un->op != OpNone) {
|
|
ValueNode *vn = getValue();
|
|
vn->value = word;
|
|
un->right = vn;
|
|
return un;
|
|
}
|
|
else
|
|
throw meosException("Unknown method X#" + word + "." + sword);
|
|
}
|
|
}
|
|
ValueNode *vn = getValue();
|
|
vn->value = word;
|
|
return vn;
|
|
}
|
|
|
|
|
|
ParseNode *Parser::parseFunction(const string &name, const string &expr, size_t &pos) {
|
|
Operator op = OpNone;
|
|
|
|
if (name == "if" || name == "for" || name == "while" || name == "break" || name == "return")
|
|
throw meosException("Unexpected " + name + ",\n#" + expr);
|
|
|
|
if (name == "max")
|
|
op = OpMax;
|
|
else if (name == "min")
|
|
op = OpMin;
|
|
|
|
if (op == OpNone)
|
|
return 0;
|
|
|
|
eatWhite(expr, pos);
|
|
|
|
if (expr[pos] != '(')
|
|
throw meosException("Expected (,\nX#" + expr);
|
|
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '(', ')');
|
|
|
|
//splitStatements
|
|
map<char, char> se;
|
|
se['('] = ')';
|
|
vector<string> arg;
|
|
splitStatements(expr.substr(start, pos-start-1), ',', se, arg);
|
|
|
|
if (arg.size() != 2)
|
|
throw meosException("Expected 2 arguments, got X,\nY#"+itos(arg.size()) + "#" + expr);
|
|
|
|
BinaryOperatorNode *bin = getBinary();
|
|
bin->left = parseStatement(arg[0], false);
|
|
bin->right = parseStatement(arg[1], false);
|
|
bin->op = op;
|
|
|
|
return bin;
|
|
}
|
|
|
|
|
|
Parser::Operator Parser::parseOperator(const string &expr, size_t &pos, int level) {
|
|
size_t npos = pos;
|
|
Operator op = parseOperatorAux(expr, npos);
|
|
|
|
if (op == OpNone || getLevel(op) != level)
|
|
return OpNone;
|
|
pos = npos;
|
|
return op;
|
|
}
|
|
|
|
void Parser::eatWhite(const string &expr, size_t &pos) {
|
|
while (pos < expr.size() && isspace(expr.at(pos))) {
|
|
pos++;
|
|
}
|
|
}
|
|
|
|
Parser::Operator Parser::parseOperatorAux(const string &expr, size_t &pos) {
|
|
eatWhite(expr, pos);
|
|
|
|
size_t pos2 = pos;
|
|
string opWord = readWord(expr, pos2);
|
|
if (opWord == "or") {
|
|
pos = pos2;
|
|
return OpOr;
|
|
}
|
|
else if (opWord == "and") {
|
|
pos = pos2;
|
|
return OpAnd;
|
|
}
|
|
|
|
if (pos < expr.size()) {
|
|
char p1 = 0, p2 = 0;
|
|
p1 = expr[pos++];
|
|
if (pos < expr.size() && p1 != '(' && p1 != ')' ) {
|
|
p2 = expr[pos++];
|
|
if (p2 == 0 || isalnum(p2) || isspace(p2) || (p2 == '-' && p1 != '-') ||
|
|
p2 == '!' || (p2 == '+' && p1 != '+') || p2=='(') {
|
|
pos--;
|
|
p2 = 0;
|
|
}
|
|
}
|
|
|
|
if (p1 == '(')
|
|
return OpLeftP;
|
|
else if (p1 == ')')
|
|
return OpRightP;
|
|
else if (p1 == '=' && p2 == '=')
|
|
return OpEquals;
|
|
else if (p1 == '=' && p2 == 0)
|
|
return OpAssign;
|
|
else if (p1 == '!' && p2 == '=')
|
|
return OpNotEquals;
|
|
else if (p1 == '<' && p2 == '=')
|
|
return OpLessEquals;
|
|
else if (p1 == '>' && p2 == '=')
|
|
return OpMoreEquals;
|
|
else if (p1 == '<' && p2 == 0)
|
|
return OpLess;
|
|
else if (p1 == '>' && p2 == 0)
|
|
return OpMore;
|
|
else if (p1 == '+' && p2 == 0)
|
|
return OpPlus;
|
|
else if (p1 == '-' && p2 == 0)
|
|
return OpMinus;
|
|
else if (p1 == '*' && p2 == 0)
|
|
return OpTimes;
|
|
else if (p1 == '/' && p2 == 0)
|
|
return OpDivide;
|
|
else if (p1 == '%' && p2 == 0)
|
|
return OpMod;
|
|
else if (p1 == '&' && p2 == '&')
|
|
return OpAnd;
|
|
else if (p1 == '|' && p2 == '|')
|
|
return OpOr;
|
|
else if (p1 == '!' && p2 == 0)
|
|
return OpNot;
|
|
else if (p1 == '+' && p2 == '+')
|
|
return OpInc;
|
|
else if (p1 == '-' && p2 == '-')
|
|
return OpDec;
|
|
|
|
string op = expr.substr(0, 10);
|
|
throw meosException("Invalid operator X#" + op);
|
|
}
|
|
return OpNone;
|
|
}
|
|
|
|
// 3*2 + 4*4 == 5
|
|
|
|
ParseNode *Parser::parseStatement(ParseNode *left, const string &expr,
|
|
size_t &pos, int level, bool reverseSign) {
|
|
eatWhite(expr, pos);
|
|
if (pos == expr.length())
|
|
return left;
|
|
Operator op = parseOperator(expr, pos, level);
|
|
while (op == OpNone) {
|
|
if (level <= levelMax) {
|
|
ParseNode *newLeft = parseStatement(left, expr, pos, level + 1, reverseSign);
|
|
if (newLeft == left)
|
|
return left;
|
|
else
|
|
left = newLeft;
|
|
}
|
|
else
|
|
return left;
|
|
|
|
op = parseOperator(expr, pos, level);
|
|
}
|
|
|
|
if (op == OpInc || op == OpDec) {
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->op = op == OpInc ? OpIncPost : OpDecPost;
|
|
un->right = left;
|
|
return un;
|
|
}
|
|
|
|
if (reverseSign) {
|
|
if (op == OpMinus) {
|
|
op = OpPlus;
|
|
}
|
|
else if (op == OpPlus) {
|
|
op = OpMinus;
|
|
reverseSign = false;
|
|
}
|
|
}
|
|
else if (op == OpMinus) {
|
|
reverseSign = true;
|
|
}
|
|
|
|
if (op == OpAssign && !left->isVariable()) {
|
|
throw meosException("Invalid assignment X#" + expr);
|
|
}
|
|
|
|
BinaryOperatorNode *bin = getBinary();
|
|
bin->left = left;
|
|
bin->op = op;
|
|
|
|
eatWhite(expr, pos);
|
|
|
|
if (op == OpAssign) {
|
|
bin->right = parseStatement(expr.substr(pos),false);
|
|
return bin;
|
|
}
|
|
/*else if (expr[pos] == '(') {
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '(', ')');
|
|
string subExpr = expr.substr(start, pos-start-1);
|
|
ParseNode *pn = parseStatement(subExpr, false);
|
|
bin->right = parseStatement(pn, expr, pos, level);
|
|
|
|
//bin->right = parseStatement(subExpr, false);
|
|
return bin;
|
|
}*/
|
|
else {
|
|
size_t pos2 = pos;
|
|
Operator op2 = OpNone;
|
|
if (!isalnum(expr[pos])) {
|
|
op2 = parseOperatorAux(expr, pos2);
|
|
if (op2 == OpMinus || op2 == OpPlus || op2 == OpNot) {
|
|
pos = pos2;
|
|
}
|
|
else if (op2 == OpInc) {
|
|
pos = pos2;
|
|
op2 = OpIncPre;
|
|
}
|
|
else if (op2 == OpDec) {
|
|
pos = pos2;
|
|
op2 = OpDecPre;
|
|
}
|
|
else if (op2 == OpLeftP) {
|
|
op2 = OpNone;
|
|
}
|
|
else if (op2 != OpNone) {
|
|
throw meosException("Syntax error,\nX#" + expr);
|
|
}
|
|
eatWhite(expr, pos);
|
|
}
|
|
|
|
if (expr[pos] == '(') {
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '(', ')');
|
|
string subExpr = expr.substr(start, pos-start-1);
|
|
ParseNode *pn = parseStatement(subExpr, false);
|
|
|
|
if (op2 != 0) {
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->op = op2;
|
|
un->right = pn;
|
|
pn = un;
|
|
}
|
|
|
|
bin->right = parseStatement(pn, expr, pos, level, false);
|
|
|
|
//bin->right = parseStatement(subExpr, false);
|
|
return bin;
|
|
}
|
|
else if (isalnum(expr[pos])) {
|
|
string word = readWord(expr, pos);
|
|
ParseNode *right;
|
|
ParseNode *pn = parseFunction(word, expr, pos);
|
|
if (pn != 0) {
|
|
if (op2 != 0) {
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->op = op2;
|
|
un->right = pn;
|
|
pn = un;
|
|
}
|
|
right = parseStatement(pn, expr, pos, level, reverseSign);
|
|
}
|
|
else if (!word.empty()) {
|
|
ParseNode *vn = parseValue(word, expr, pos);
|
|
//ValueNode *vn = getValue();
|
|
//vn->value = word;
|
|
pn = vn;
|
|
if (op2 != 0) {
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->op = op2;
|
|
un->right = pn;
|
|
pn = un;
|
|
}
|
|
right = parseStatement(pn, expr, pos, level, reverseSign);
|
|
}
|
|
else {
|
|
throw meosException("Unexpected ending operator X#" + expr);
|
|
}
|
|
|
|
bin->right = right;
|
|
return bin;
|
|
}
|
|
}
|
|
throw meosException("Syntax error,\nX#" + expr);
|
|
}
|
|
|
|
ParseNode *Parser::parseStatement(const string &expr, bool primary) {
|
|
size_t pos = 0;
|
|
eatWhite(expr, pos);
|
|
ParseNode *left = 0;
|
|
if (expr[pos] == '(') {
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '(', ')');
|
|
string subExpr = expr.substr(start, pos-start-1);
|
|
left = parseStatement(subExpr, false);
|
|
}
|
|
else if (expr[pos] == '{') {
|
|
if (!primary)
|
|
throw meosException("Unexpeccted {,\nX" + expr);
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '{', '}');
|
|
string subExpr = expr.substr(start, pos-start-1);
|
|
return parse(subExpr);
|
|
}
|
|
else {
|
|
size_t pos2 = pos;
|
|
Operator op2 = OpNone;
|
|
if (!isalnum(expr[pos])) {
|
|
op2 = parseOperatorAux(expr, pos2);
|
|
if (op2 == OpMinus || op2 == OpPlus || op2 == OpNot) {
|
|
pos = pos2;
|
|
}
|
|
else if (op2 == OpInc) {
|
|
pos = pos2;
|
|
op2 = OpIncPre;
|
|
}
|
|
else if (op2 == OpDec) {
|
|
pos = pos2;
|
|
op2 = OpDecPre;
|
|
}
|
|
else if (op2 != OpNone) {
|
|
throw meosException("Syntax error,\nX#" + expr);
|
|
}
|
|
primary = false;
|
|
}
|
|
|
|
eatWhite(expr, pos);
|
|
if (op2 != OpNone && expr[pos] == '(') {
|
|
size_t start = pos + 1;
|
|
matchSE(expr, pos, '(', ')');
|
|
string subExpr = expr.substr(start, pos-start-1);
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->op = op2;
|
|
un->right = parseStatement(subExpr, false);
|
|
left = un;
|
|
}
|
|
else if (isalnum(expr[pos])) {
|
|
string word = readWord(expr, pos);
|
|
if (word == "if") {
|
|
if (!primary)
|
|
throw meosException("Unexpected if\nX#" + expr);
|
|
return parseif (expr, pos);
|
|
}
|
|
else if (word == "return") {
|
|
if (!primary)
|
|
throw meosException("Unexpected return\nX#" + expr);
|
|
return parseReturn(expr, pos);
|
|
}
|
|
else if (word == "while") {
|
|
if (!primary)
|
|
throw meosException("Unexpected while\nX#" + expr);
|
|
return parseWhile(expr, pos);
|
|
}
|
|
else if (word == "for") {
|
|
if (!primary)
|
|
throw meosException("Unexpected for\nX#" + expr);
|
|
return parseFor(expr, pos);
|
|
}
|
|
else if (word == "break") {
|
|
if (!primary)
|
|
throw meosException("Unexpected break\nX#" + expr);
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->op = OpBreak;
|
|
return un;
|
|
}
|
|
|
|
left = parseFunction(word, expr, pos);
|
|
|
|
if (left == 0) {
|
|
//ValueNode *vn = getValue();
|
|
//vn->value = word;
|
|
left = parseValue(word, expr, pos);
|
|
}
|
|
|
|
if (op2 != OpNone) {
|
|
UnaryOperatorNode *un = getUnary();
|
|
un->op = op2;
|
|
un->right = left;
|
|
left = un;
|
|
}
|
|
}
|
|
else
|
|
throw meosException("Syntax error,\nX#" + expr);
|
|
}
|
|
ParseNode *node = parseStatement(left, expr, pos, 0, false);
|
|
|
|
if (node == 0)
|
|
throw meosException("Syntax error,\nX#" + expr);
|
|
|
|
return node;
|
|
}
|
|
|
|
ParseNode *Parser::parse(const string &expr) {
|
|
vector<string> lines;
|
|
split(expr, "\n", lines);
|
|
string exprNoComments;
|
|
exprNoComments.reserve(expr.size()+4);
|
|
for (size_t k = 0; k < lines.size(); k++) {
|
|
int ix = lines[k].find("//");
|
|
if (ix != lines[k].npos)
|
|
exprNoComments.append(lines[k].substr(0, ix));
|
|
else
|
|
exprNoComments.append(lines[k]);
|
|
|
|
exprNoComments.append("\n");
|
|
}
|
|
|
|
vector<string> spv;
|
|
map<char, char> se;
|
|
se['{'] = '}';
|
|
splitStatements(exprNoComments, ';', se, spv);
|
|
/*for (size_t k = 0; k < spv.size(); k++) {
|
|
int ix = spv[k].find_first_of("//");
|
|
if (ix != spv[k].npos)
|
|
spv[k] = trim(spv[k].substr(0, ix));
|
|
}*/
|
|
|
|
if (spv.size() == 1)
|
|
return parseStatement(spv[0], true);
|
|
else {
|
|
StatementNode *sn = getStatement();
|
|
ParseNode *ret = sn;
|
|
StatementNode *oldSN = 0;
|
|
for (size_t k = 0; k < spv.size(); k++) {
|
|
size_t pos = 0;
|
|
eatWhite(spv[k], pos);
|
|
if (readWord(spv[k], pos) == "else") {
|
|
if (oldSN != 0 && typeid(*(oldSN->node))==typeid(IfNode)) {
|
|
oldSN->next = 0;
|
|
sn = oldSN;
|
|
IfNode *ifn = dynamic_cast<IfNode *>(sn->node);
|
|
while (ifn != 0 && ifn->iffalse) {
|
|
ifn = dynamic_cast<IfNode *>(ifn->iffalse);
|
|
}
|
|
if (ifn) {
|
|
oldSN = 0;
|
|
ifn->iffalse = parseStatement(spv[k].substr(pos), true);
|
|
}
|
|
else
|
|
throw meosException("else without matching if,\nX#" + spv[k]);
|
|
}
|
|
else
|
|
throw meosException("else without matching if,\nX#" + spv[k]);
|
|
}
|
|
else
|
|
sn->node = parseStatement(spv[k], true);
|
|
|
|
if (k+1 < spv.size())
|
|
sn->next = getStatement();
|
|
oldSN = sn;
|
|
sn = sn->next;
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
int Parser::evaluate(const string &input) const {
|
|
if (input.empty())
|
|
throw meosException("Empty expression");
|
|
|
|
if (isdigit(input[0]))
|
|
return atoi(input.c_str());
|
|
|
|
{
|
|
map<string, Symbol>::const_iterator res = symb.find(input);
|
|
if (res != symb.end()) {
|
|
if (res->second.value.empty())
|
|
throw meosException("Internal error");
|
|
if (res->second.value[0].size() == 1)
|
|
return res->second.value[0][0];
|
|
throw meosException("X is an array.#" + input);
|
|
}
|
|
}
|
|
|
|
map<string, vector<int> >::iterator res = var.find(input);
|
|
if (res != var.end()) {
|
|
if (res->second.size() == 1)
|
|
return res->second[0];
|
|
throw meosException("X is an array.#" + input);
|
|
}
|
|
throw meosException("Unknown symbol X#" + input);
|
|
}
|
|
|
|
int Parser::evaluate(const string &input, int index, int index2) const {
|
|
if (input.empty())
|
|
throw meosException("Empty expression");
|
|
|
|
if (isdigit(input[0]))
|
|
return atoi(input.c_str());
|
|
|
|
map<string, Symbol>::const_iterator res = symb.find(input);
|
|
if (res != symb.end()) {
|
|
if (size_t(index2) < res->second.value.size() &&
|
|
size_t(index) < res->second.value[index2].size())
|
|
return res->second.value[index2][index];
|
|
if (index2 == 0)
|
|
throw meosException("Index X in Y is out of range.#" + itos(index) + "#" + input);
|
|
else
|
|
throw meosException("Index X in Y is out of range.#" + itos(index2) + "," + itos(index) + "#" + input);
|
|
}
|
|
|
|
map<string, vector<int> >::const_iterator res2 = var.find(input);
|
|
if (res2 != var.end()) {
|
|
if (index2 != 0)
|
|
throw meosException("Index X in Y is out of range.#" + itos(index2) + "#" + input);
|
|
if (size_t(index) < res2->second.size())
|
|
return res2->second[index];
|
|
throw meosException("Index X in Y is out of range.#" + itos(index) + "#" + input);
|
|
}
|
|
throw meosException("Unknown symbol X#" + input);
|
|
}
|
|
|
|
int Parser::evaluateSize(const string &input, int index) const {
|
|
if (input.empty())
|
|
throw meosException("Empty expression");
|
|
|
|
if (isdigit(input[0]))
|
|
throw meosException("Constant expression");
|
|
{
|
|
map<string, Symbol >::const_iterator res = symb.find(input);
|
|
|
|
if (res != symb.end()) {
|
|
if (index == -1)
|
|
return res->second.value.size();
|
|
else {
|
|
if (size_t(index) < res->second.value.size())
|
|
return res->second.value[index].size();
|
|
else
|
|
throw meosException("Index out of range for X.#" + input);
|
|
}
|
|
}
|
|
}
|
|
|
|
map<string, vector<int> >::const_iterator res = var.find(input);
|
|
if (res != var.end()) {
|
|
if (index != 0)
|
|
throw meosException("Index out of range for X.#" + input);
|
|
return res->second.size();
|
|
}
|
|
throw meosException("Unknown symbol X#" + input);
|
|
}
|
|
|
|
void Parser::sortArray(const string &input) const {
|
|
map<string, vector<int> >::iterator res = var.find(input);
|
|
if (res != var.end()) {
|
|
sort(res->second.begin(), res->second.end());
|
|
return;
|
|
}
|
|
throw meosException("Unknown symbol X#" + input);
|
|
}
|
|
|
|
void Parser::storeVariable(const string &input, const vector<int> &value) const {
|
|
if (symb.count(input))
|
|
throw meosException("Duplicate symbol X#" + input);
|
|
var[input] = value;
|
|
}
|
|
|
|
void Parser::storeVariable(const string &input, int value) const {
|
|
if (symb.count(input))
|
|
throw meosException("Duplicate symbol X#" + input);
|
|
vector<int> &iv = var[input];
|
|
iv.resize(1);
|
|
iv[0] = value;
|
|
}
|
|
|
|
void Parser::storeVariable(const string &input, int index, int value) const {
|
|
if (symb.count(input))
|
|
throw meosException("Duplicate symbol X#" + input);
|
|
if (index < 0 || index>1024)
|
|
throw meosException("Index out of range for X.#" + input);
|
|
|
|
vector<int> &iv = var[input];
|
|
if (iv.size() <= size_t(index))
|
|
iv.resize(index+1);
|
|
iv[index] = value;
|
|
}
|
|
|
|
Parser::Parser() {
|
|
|
|
}
|
|
|
|
Parser::~Parser() {
|
|
clear();
|
|
}
|
|
|
|
void Parser::clear() {
|
|
for (size_t k = 0; k < nodes.size(); k++) {
|
|
delete nodes[k];
|
|
nodes[k] = 0;
|
|
}
|
|
nodes.clear();
|
|
}
|
|
|
|
Parser::UnaryOperatorNode *Parser::getUnary() {
|
|
nodes.push_back(new UnaryOperatorNode());
|
|
return (UnaryOperatorNode *)nodes.back();
|
|
}
|
|
|
|
Parser::BinaryOperatorNode *Parser::getBinary() {
|
|
nodes.push_back(new BinaryOperatorNode());
|
|
return (BinaryOperatorNode *)nodes.back();
|
|
}
|
|
|
|
Parser::ValueNode *Parser::getValue() {
|
|
nodes.push_back(new ValueNode());
|
|
return (ValueNode *)nodes.back();
|
|
}
|
|
|
|
Parser::ArrayValueNode *Parser::getArrayValue() {
|
|
nodes.push_back(new ArrayValueNode());
|
|
return (ArrayValueNode *)nodes.back();
|
|
}
|
|
|
|
Parser::StatementNode *Parser::getStatement() {
|
|
nodes.push_back(new StatementNode());
|
|
return (StatementNode *)nodes.back();
|
|
}
|
|
|
|
Parser::IfNode *Parser::getif () {
|
|
nodes.push_back(new IfNode());
|
|
return (IfNode *)nodes.back();
|
|
}
|
|
|
|
Parser::WhileNode *Parser::getWhile() {
|
|
nodes.push_back(new WhileNode());
|
|
return (WhileNode *)nodes.back();
|
|
}
|
|
|
|
Parser::ForNode *Parser::getFor() {
|
|
nodes.push_back(new ForNode());
|
|
return (ForNode *)nodes.back();
|
|
}
|
|
|
|
ParseNode::~ParseNode() {
|
|
}
|
|
|
|
|
|
Parser::StatementNode::StatementNode() {
|
|
node = 0;
|
|
next = 0;
|
|
}
|
|
|
|
Parser::StatementNode::~StatementNode() {
|
|
node = 0;
|
|
next = 0;
|
|
}
|
|
|
|
int Parser::StatementNode::evaluate(const Parser &parser) const {
|
|
if (node == 0)
|
|
throw meosException("Nullpointer");
|
|
parser.returnMode = false;
|
|
parser.breakMode = 0;
|
|
const StatementNode *c = this;
|
|
int ret = 0;
|
|
while(c && !parser.returnMode) {
|
|
parser.ignoreValue = false;
|
|
int val = c->node->evaluate(parser);
|
|
if (!parser.ignoreValue)
|
|
ret = val;
|
|
if (parser.breakMode>0) {
|
|
break;
|
|
}
|
|
c = c->next;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
Parser::ValueNode::ValueNode() {
|
|
}
|
|
Parser::ValueNode::~ValueNode() {
|
|
}
|
|
|
|
int Parser::ValueNode::evaluate(const Parser &parser) const {
|
|
return parser.evaluate(value);
|
|
}
|
|
bool Parser::ValueNode::isVariable() const {
|
|
return value.length()>0 && isalpha(value[0]);
|
|
}
|
|
|
|
Parser::BinaryOperatorNode::BinaryOperatorNode() {
|
|
left = 0;
|
|
right = 0;
|
|
}
|
|
|
|
Parser::BinaryOperatorNode::~BinaryOperatorNode() {
|
|
left = 0;
|
|
right = 0;
|
|
}
|
|
|
|
int Parser::BinaryOperatorNode::evaluate(const Parser &parser) const {
|
|
if (left == 0 || right == 0)
|
|
throw meosException("Internal error");
|
|
|
|
switch (op) {
|
|
case OpPlus:
|
|
return left->evaluate(parser) + right->evaluate(parser);
|
|
case OpMinus:
|
|
return left->evaluate(parser) - right->evaluate(parser);
|
|
case OpTimes:
|
|
return left->evaluate(parser) * right->evaluate(parser);
|
|
case OpDivide:
|
|
return left->evaluate(parser) / right->evaluate(parser);
|
|
case OpMod:
|
|
return left->evaluate(parser) % right->evaluate(parser);
|
|
|
|
case OpEquals:
|
|
return left->evaluate(parser) == right->evaluate(parser);
|
|
case OpNotEquals:
|
|
return left->evaluate(parser) != right->evaluate(parser);
|
|
case OpLess:
|
|
return left->evaluate(parser) < right->evaluate(parser);
|
|
case OpLessEquals:
|
|
return left->evaluate(parser) <= right->evaluate(parser);
|
|
case OpMore:
|
|
return left->evaluate(parser) > right->evaluate(parser);
|
|
case OpMoreEquals:
|
|
return left->evaluate(parser) >= right->evaluate(parser);
|
|
|
|
case OpOr:
|
|
return left->evaluate(parser) || right->evaluate(parser);
|
|
case OpAnd:
|
|
return left->evaluate(parser) && right->evaluate(parser);
|
|
|
|
case OpMax:
|
|
return max(left->evaluate(parser), right->evaluate(parser));
|
|
case OpMin:
|
|
return min(left->evaluate(parser), right->evaluate(parser));
|
|
|
|
case OpAssign: {
|
|
ValueNode *vn = dynamic_cast<ValueNode *>(right);
|
|
if (vn != 0) {
|
|
if (parser.isMatrix(vn->value))
|
|
throw meosException("Cannot assign matrix X#"+vn->value);
|
|
if (parser.isVector(vn->value)) {
|
|
left->assignVector(parser, parser.getVector(vn->value, 0));
|
|
parser.ignoreValue = true;
|
|
return -1;
|
|
}
|
|
}
|
|
ArrayValueNode *avn = dynamic_cast<ArrayValueNode *>(right);
|
|
if (avn != 0 && parser.isMatrix(avn->expr) && avn->index2 == 0) {
|
|
left->assignVector(parser, parser.getVector(avn->expr, avn->index->evaluate(parser)));
|
|
parser.ignoreValue = true;
|
|
return -1;
|
|
}
|
|
|
|
int val = right->evaluate(parser);
|
|
left->assign(parser, val);
|
|
return val;
|
|
}
|
|
|
|
}
|
|
|
|
throw meosException("Internal error, unknown operator");
|
|
}
|
|
|
|
|
|
Parser::UnaryOperatorNode::UnaryOperatorNode() {
|
|
right = 0;
|
|
}
|
|
|
|
Parser::UnaryOperatorNode::~UnaryOperatorNode() {
|
|
right = 0;
|
|
}
|
|
|
|
int Parser::UnaryOperatorNode::evaluate(const Parser &parser) const {
|
|
if (op == OpBreak) {
|
|
parser.ignoreValue = true;
|
|
parser.breakMode = 1;
|
|
return -1;
|
|
}
|
|
|
|
if (right == 0)
|
|
throw meosException("Internal error");
|
|
|
|
switch (op) {
|
|
case OpReturn: {
|
|
int val = right->evaluate(parser);
|
|
parser.returnMode = true;
|
|
return val;
|
|
}
|
|
case OpMinus:
|
|
return -right->evaluate(parser);
|
|
case OpNot: {
|
|
return right->evaluate(parser) == 0;
|
|
}
|
|
case OpPlus:
|
|
return right->evaluate(parser);
|
|
case OpIncPost: {
|
|
int val = right->evaluate(parser);
|
|
right->assign(parser, val + 1);
|
|
return val;
|
|
}
|
|
case OpDecPost: {
|
|
int val = right->evaluate(parser);
|
|
right->assign(parser, val-1);
|
|
return val;
|
|
}
|
|
case OpIncPre: {
|
|
int val = right->evaluate(parser) + 1;
|
|
right->assign(parser, val);
|
|
return val;
|
|
}
|
|
case OpDecPre: {
|
|
int val = right->evaluate(parser) - 1;
|
|
right->assign(parser, val);
|
|
return val;
|
|
}
|
|
case OpSize: {
|
|
ValueNode &vn= dynamic_cast<ValueNode &>(*right);
|
|
return parser.evaluateSize(vn.value, 0);
|
|
}
|
|
case OpSizeBase: {
|
|
ValueNode &vn= dynamic_cast<ValueNode &>(*right);
|
|
return parser.evaluateSize(vn.value, -1);
|
|
}
|
|
case OpSizeSub: {
|
|
ArrayValueNode &vn= dynamic_cast<ArrayValueNode &>(*right);
|
|
return parser.evaluateSize(vn.expr, vn.index->evaluate(parser));
|
|
}
|
|
case OpSortArray: {
|
|
ValueNode &vn= dynamic_cast<ValueNode &>(*right);
|
|
parser.sortArray(vn.value);
|
|
parser.ignoreValue = true;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
throw meosException("Internal error, unknown operator");
|
|
}
|
|
|
|
Parser::IfNode::IfNode() {
|
|
condition = 0;
|
|
iftrue = 0;
|
|
iffalse = 0;
|
|
}
|
|
|
|
Parser::IfNode::~IfNode() {
|
|
condition = 0;
|
|
iftrue = 0;
|
|
iffalse = 0;
|
|
}
|
|
|
|
int Parser::IfNode::evaluate(const Parser &parser) const {
|
|
if (condition->evaluate(parser) != 0) {
|
|
return iftrue->evaluate(parser);
|
|
}
|
|
if (iffalse)
|
|
return iffalse->evaluate(parser);
|
|
|
|
parser.ignoreValue = true;
|
|
return -1;
|
|
}
|
|
|
|
Parser::WhileNode::WhileNode() {
|
|
condition = 0;
|
|
body = 0;
|
|
}
|
|
|
|
Parser::WhileNode::~WhileNode() {
|
|
condition = 0;
|
|
body = 0;
|
|
}
|
|
|
|
int Parser::WhileNode::evaluate(const Parser &parser) const {
|
|
if (condition == 0 || body == 0)
|
|
throw meosException("Internal error in while");
|
|
int maxCount = 1000;
|
|
int ret = -1;
|
|
bool used = false;
|
|
while (condition->evaluate(parser) != 0 && !parser.returnMode && --maxCount > 0) {
|
|
ret = body->evaluate(parser);
|
|
if (parser.breakMode>0) {
|
|
parser.breakMode--;
|
|
break;
|
|
}
|
|
used = true;
|
|
}
|
|
if (maxCount <= 0) {
|
|
throw meosException("Stalled while loop");
|
|
}
|
|
|
|
if (!used)
|
|
parser.ignoreValue = true;
|
|
return ret;
|
|
}
|
|
|
|
|
|
Parser::ForNode::ForNode() {
|
|
condition = 0;
|
|
start = 0;
|
|
update = 0;
|
|
body = 0;
|
|
}
|
|
|
|
Parser::ForNode::~ForNode() {
|
|
condition = 0;
|
|
start = 0;
|
|
update = 0;
|
|
body = 0;
|
|
}
|
|
|
|
int Parser::ForNode::evaluate(const Parser &parser) const {
|
|
if (start == 0 || condition == 0 || update == 0 || body == 0)
|
|
throw meosException("Internal error in for");
|
|
int maxCount = 1000;
|
|
int ret = -1;
|
|
bool used = false;
|
|
for (start->evaluate(parser);
|
|
condition->evaluate(parser) != 0 && !parser.returnMode && --maxCount > 0;
|
|
update->evaluate(parser) ) {
|
|
ret = body->evaluate(parser);
|
|
used = true;
|
|
}
|
|
if (maxCount <= 0) {
|
|
throw meosException("Stalled for loop");
|
|
}
|
|
|
|
if (!used)
|
|
parser.ignoreValue = true;
|
|
return ret;
|
|
}
|
|
|
|
Parser::ArrayValueNode::ArrayValueNode() {
|
|
index = 0;
|
|
index2 = 0;
|
|
}
|
|
Parser::ArrayValueNode::~ArrayValueNode() {
|
|
index = 0;
|
|
index2 = 0;
|
|
}
|
|
|
|
int Parser::ArrayValueNode::evaluate(const Parser &parser) const {
|
|
if (index2 == 0)
|
|
return parser.evaluate(expr, index->evaluate(parser), 0);
|
|
else
|
|
return parser.evaluate(expr, index->evaluate(parser), index2->evaluate(parser));
|
|
}
|
|
|
|
bool Parser::ArrayValueNode::isVariable() const {
|
|
return true;
|
|
}
|
|
|
|
void ParseNode::assign(const Parser &parser, int value) const {
|
|
throw meosException("Illegal assignment");
|
|
}
|
|
|
|
void ParseNode::assignVector(const Parser &parser, const vector<int> &value) const {
|
|
throw meosException("Illegal assignment");
|
|
}
|
|
|
|
void Parser::ValueNode::assign(const Parser &parser, int in_value) const {
|
|
parser.storeVariable(value, in_value);
|
|
}
|
|
|
|
void Parser::ValueNode::assignVector(const Parser &parser, const vector<int> &in_value) const {
|
|
parser.storeVariable(value, in_value);
|
|
}
|
|
|
|
|
|
void Parser::ArrayValueNode::assign(const Parser &parser, int value) const {
|
|
int ix2;
|
|
if (index2 != 0 && (ix2 = index2->evaluate(parser)) != 0)
|
|
throw meosException("Index X in Y is out of range.#" + itos(ix2) + "#" + expr);
|
|
parser.storeVariable(expr, index->evaluate(parser), value);
|
|
}
|
|
|
|
void Parser::ArrayValueNode::assignVector(const Parser &parser, const vector<int> &in_value) const {
|
|
if (in_value.size() != 1)
|
|
throw meosException("Vector cannot be assigned to X[i]#" + expr);
|
|
parser.storeVariable(expr, index->evaluate(parser), in_value[0]);
|
|
}
|
|
|
|
void Parser::declareSymbol(const char *name, const string &desc, bool isVector, bool isMatrix) {
|
|
assert(symb.count(name) == 0 || (symb[name].isVector == isVector && symb[name].isMatrix == isMatrix));
|
|
symb[name].desc = desc;
|
|
symb[name].isVector = isVector;
|
|
symb[name].isMatrix = isMatrix;
|
|
}
|
|
|
|
bool Parser::isMatrix(const string &input) const {
|
|
map<string, Symbol>::const_iterator res = symb.find(input);
|
|
return res != symb.end() && res->second.isMatrix;
|
|
}
|
|
|
|
bool Parser::isVector(const string &input) const {
|
|
map<string, Symbol>::const_iterator res = symb.find(input);
|
|
if (res != symb.end())
|
|
return !res->second.isMatrix && res->second.value[0].size() != 1;
|
|
|
|
map<string, vector<int> >::const_iterator resv = var.find(input);
|
|
return resv != var.end() && resv->second.size() != 1;
|
|
}
|
|
|
|
const vector<int> &Parser::getVector(const string &symbol, int index) const{
|
|
map<string, Symbol>::const_iterator res = symb.find(symbol);
|
|
if (res != symb.end()) {
|
|
if (size_t(index) < res->second.value.size())
|
|
return res->second.value[index];
|
|
else
|
|
throw meosException("Index out of range for X.#" + symbol);
|
|
}
|
|
map<string, vector<int> >::const_iterator resv = var.find(symbol);
|
|
if (resv != var.end())
|
|
return resv->second;
|
|
|
|
throw meosException("Unknown symbol X#" + symbol);
|
|
}
|
|
|
|
void Parser::addSymbol(const char *name, const string &value) {
|
|
assert(symb.count(name) && !symb[name].isVector);
|
|
symb[name].value.resize(1);
|
|
vector<int> &v = symb[name].value[0];
|
|
v.resize(1);
|
|
v[0] = atoi(value.c_str());
|
|
}
|
|
|
|
void Parser::addSymbol(const char *name, int value) {
|
|
assert(symb.count(name) && !symb[name].isVector);
|
|
symb[name].value.resize(1);
|
|
vector<int> &v = symb[name].value[0];
|
|
v.resize(1);
|
|
v[0] = value;
|
|
}
|
|
|
|
void Parser::addSymbol(const char *name, const vector<string> &value) {
|
|
assert(symb.count(name) && symb[name].isVector);
|
|
symb[name].value.resize(1);
|
|
vector<int> &v = symb[name].value[0];
|
|
v.resize(value.size());
|
|
for (size_t k = 0; k < value.size(); k++)
|
|
v[k] = atoi(value[k].c_str());
|
|
}
|
|
|
|
void Parser::addSymbol(const char *name, const vector<int> &value) {
|
|
assert(symb.count(name) && symb[name].isVector);
|
|
symb[name].value.resize(1);
|
|
symb[name].value[0] = value;
|
|
}
|
|
|
|
void Parser::addSymbol(const char *name, vector< vector<int> > &value) {
|
|
assert(symb.count(name) && symb[name].isVector);
|
|
symb[name].value.swap(value);
|
|
}
|
|
|
|
void Parser::removeSymbol(const char *name) {
|
|
symb[name].value.clear();
|
|
}
|
|
|
|
void Parser::clearSymbols() {
|
|
symb.clear();
|
|
}
|
|
|
|
void Parser::clearVariables() const {
|
|
var.clear();
|
|
}
|
|
|
|
void Parser::takeVariable(const char*name, vector<int> &val) const {
|
|
map<string, vector<int> >::iterator resv = var.find(name);
|
|
if (resv != var.end()) {
|
|
vector<int> &res = resv->second;
|
|
val.swap(res);
|
|
}
|
|
else
|
|
val.clear();
|
|
}
|
|
|
|
void Parser::getSymbols(vector< pair<wstring, size_t> > &symbOut) const {
|
|
int iter = 0;
|
|
for(map<string, Symbol>::const_iterator it = symb.begin(); it != symb.end(); ++it) {
|
|
if (it->second.isMatrix)
|
|
symbOut.push_back(make_pair(gdi_main->widen(it->first) + L"[][]\t" + lang.tl(it->second.desc), iter++));
|
|
else if (it->second.isVector)
|
|
symbOut.push_back(make_pair(gdi_main->widen(it->first) + L"[]\t" + lang.tl(it->second.desc), iter++));
|
|
else
|
|
symbOut.push_back(make_pair(gdi_main->widen(it->first) + L"\t" + lang.tl(it->second.desc), iter++));
|
|
}
|
|
}
|
|
|
|
void Parser::getSymbolInfo(int ix, wstring &name, wstring &desc) const {
|
|
int iter = 0;
|
|
for(map<string, Symbol>::const_iterator it = symb.begin(); it != symb.end(); ++it) {
|
|
if (ix == iter++) {
|
|
if (it->second.isMatrix)
|
|
name = gdi_main->widen(it->first) + L"[][]";
|
|
else if (it->second.isVector)
|
|
name = gdi_main->widen(it->first) + L"[]";
|
|
else
|
|
name = gdi_main->widen(it->first);
|
|
desc = gdi_main->widen(it->second.desc);
|
|
|
|
return;
|
|
}
|
|
}
|
|
throw meosException("Internal error");
|
|
}
|
|
|
|
|
|
static void assertEq(int a, int b) {
|
|
if (a != b) {
|
|
string s = "Expected X, was Y#" + itos(a) + "#" + itos(b);
|
|
throw s;
|
|
}
|
|
}
|
|
|
|
void Parser::test() {
|
|
Parser parser;
|
|
vector<int> tt;
|
|
tt.push_back(1);
|
|
tt.push_back(4);
|
|
tt.push_back(9);
|
|
parser.declareSymbol("tt", "", true);
|
|
parser.declareSymbol("tt2", "", true);
|
|
parser.declareSymbol("ttt", "", true, true);
|
|
parser.declareSymbol("t", "", false);
|
|
|
|
vector<int> tt2;
|
|
|
|
tt2.push_back(3);
|
|
tt2.push_back(4);
|
|
tt2.push_back(2);
|
|
tt2.push_back(1);
|
|
|
|
parser.addSymbol("tt", tt);
|
|
parser.addSymbol("tt2", tt2);
|
|
parser.addSymbol("t", 3);
|
|
vector< vector<int> > ttt;
|
|
ttt.push_back(tt);
|
|
ttt.push_back(tt);
|
|
ttt.back().push_back(55);
|
|
parser.addSymbol("ttt", ttt);
|
|
|
|
ParseNode *pn;
|
|
pn = parser.parse("a*b*e + c*d + f == 5*4 + 3*2; if (foo) {aa; {x;y} } rolf2=nasse; rolf2 ");
|
|
|
|
pn = parser.parse("{g=1;}{h=1} {(1)} {{(h++) }} return g+h");
|
|
assertEq(pn->evaluate(parser), 3);
|
|
|
|
pn = parser.parse("16-8+4-2+1"); // 16-(8-4+2-1)
|
|
// 16-(8-(4-2+1))
|
|
// 16-(8-(4-(2-1))
|
|
assertEq(pn->evaluate(parser), 11);
|
|
|
|
pn = parser.parse("16-8-4-2-1)");
|
|
assertEq(pn->evaluate(parser), 1);
|
|
|
|
pn = parser.parse("16-8+4-2-1)");
|
|
assertEq(pn->evaluate(parser), 9);
|
|
|
|
pn = parser.parse("16-(8+4-2+1)");
|
|
assertEq(pn->evaluate(parser), 5);
|
|
|
|
pn = parser.parse("16-2*4*1+2*2*1-2*1");
|
|
assertEq(pn->evaluate(parser), 10);
|
|
|
|
pn = parser.parse("a = (1+2) * (3+4);b = a-2*10");
|
|
assertEq(pn->evaluate(parser), 1);
|
|
|
|
pn = parser.parse("1 + 2*2");
|
|
assertEq(pn->evaluate(parser), 5);
|
|
|
|
pn = parser.parse("1 + (1+1)*2");
|
|
assertEq(pn->evaluate(parser), 5);
|
|
|
|
pn = parser.parse("1 * -(1+1)*+(1+1)+10");
|
|
assertEq(pn->evaluate(parser), 6);
|
|
|
|
pn = parser.parse("3*5 + (3-1)*3*2 - 5*3");
|
|
assertEq(pn->evaluate(parser), 12);
|
|
|
|
pn = parser.parse("{a = 1; {b=2;}} if (t == a+1*b) {a++; if (a>1) {a = a*2}; return a+6;} else a--; +1+1");
|
|
assertEq(pn->evaluate(parser), 10);
|
|
|
|
pn = parser.parse("a = 3; if (1+1 == a) return 2; return 5*5*5-20;");
|
|
assertEq(pn->evaluate(parser), 105);
|
|
|
|
pn = parser.parse("max(1,2);");
|
|
assertEq(pn->evaluate(parser), 2);
|
|
|
|
pn = parser.parse("max(1,2) + min(max(0,1),2)");
|
|
assertEq(pn->evaluate(parser), 3);
|
|
|
|
pn = parser.parse("-1*-1*2+-3*3+-max(-1, 2)");
|
|
assertEq(pn->evaluate(parser), -9);
|
|
|
|
pn = parser.parse("1+-1+1");
|
|
assertEq(pn->evaluate(parser), 1);
|
|
|
|
pn = parser.parse("1+tt[1+1]");
|
|
assertEq(pn->evaluate(parser), 10);
|
|
|
|
pn = parser.parse("a[3] = 12; tt.size() + a.size() + a[3]");
|
|
assertEq(pn->evaluate(parser), 19);
|
|
|
|
pn = parser.parse("a = 2; k = 1; while(a-- > 0) { k = k*2;} return k;");
|
|
assertEq(pn->evaluate(parser), 4);
|
|
|
|
pn = parser.parse("a=1; while(1) {a=a*2; if (a>60) break;} return a;");
|
|
assertEq(pn->evaluate(parser), 64);
|
|
|
|
pn = parser.parse("res = 1; for(k = 0; k < 10; ++k) res=res*2");
|
|
assertEq(pn->evaluate(parser), 1024);
|
|
|
|
pn = parser.parse("m = 1; n = 1; a = ++m + 4*n++; return a + 100*m + 1000*n");
|
|
assertEq(pn->evaluate(parser), 2206);
|
|
|
|
pn = parser.parse("m = 1; n = 1; a = m++ + 4*++n; return a + 100*m + 1000*n");
|
|
assertEq(pn->evaluate(parser), 2209);
|
|
|
|
pn = parser.parse("m = 2; n = 2; a = m-- + 4*--n; return a + 100*m + 1000*n");
|
|
assertEq(pn->evaluate(parser), 1106);
|
|
|
|
pn = parser.parse("for(m=0; m < 10; m++) arr[m] = m * m; ret = 0; for(m = 0; m < arr.size(); m++) ret = ret + arr[m];");
|
|
assertEq(pn->evaluate(parser), 1+4+9+16+25+36+49+64+81);
|
|
|
|
pn = parser.parse("a = 0; if (1!=2) a = a + 1; if (1<2) a=a+2; if (1<=2) a=a+4; if (1>2) a=a+8; if (!(1==2)) a=a+16; if (1>=2) a=a+32; if (1>5 or 1+1 < 5) a=a+64; return a;");
|
|
assertEq(pn->evaluate(parser), 1+2+4+16+64);
|
|
|
|
pn = parser.parse("i = 3; return ttt[1][i];");
|
|
assertEq(pn->evaluate(parser), 55);
|
|
|
|
pn = parser.parse("return ttt[3][0];");
|
|
try {
|
|
pn->evaluate(parser);
|
|
assertEq(0,1);
|
|
}
|
|
catch (const meosException &) {
|
|
}
|
|
|
|
pn = parser.parse("return ttt[0][5];");
|
|
try {
|
|
pn->evaluate(parser);
|
|
assertEq(0,1);
|
|
}
|
|
catch (const meosException &) {
|
|
}
|
|
|
|
pn = parser.parse("return ttt[4].size();");
|
|
try {
|
|
pn->evaluate(parser);
|
|
assertEq(0,1);
|
|
}
|
|
catch (const meosException &) {
|
|
}
|
|
|
|
pn = parser.parse("ttt.size()");
|
|
assertEq(pn->evaluate(parser), 2);
|
|
|
|
pn = parser.parse("sum = 0; for (k = 0; k < ttt.size(); k++) {for (m = 0; m < ttt[k].size(); m++) sum = sum + ttt[k][m];}");
|
|
assertEq(pn->evaluate(parser), 83);
|
|
|
|
pn = parser.parse("ma = tt2; ma.sort(); s = 0; for(k = 0; k < ma.size(); k++) {s = s + (k+1)*ma[k];} return s;");
|
|
pn->evaluate(parser);
|
|
assertEq(pn->evaluate(parser), 1*1+2*2+3*3+4*4);
|
|
|
|
pn = parser.parse("arr = ttt[1]; s = 0; for(k = 0; k < arr.size(); k++) {s = s + arr[k];} return s;");
|
|
pn->evaluate(parser);
|
|
assertEq(pn->evaluate(parser), 69);
|
|
|
|
pn = parser.parse("k=5; //Test\n//Info\nreturn k+1;//Return 7;");
|
|
pn->evaluate(parser);
|
|
assertEq(pn->evaluate(parser), 6);
|
|
|
|
pn = parser.parse("if (1>2) return 10; else if (1<2) return 11; else return 5;");
|
|
pn->evaluate(parser);
|
|
assertEq(pn->evaluate(parser), 11);
|
|
|
|
try {
|
|
parser.parse("if (1>2) return 10; else return 11; else return 5;");
|
|
assertEq(0,1);
|
|
}
|
|
catch (const meosException &) {
|
|
}
|
|
|
|
try {
|
|
parser.parse("return 10; else return 11;");
|
|
assertEq(0,1);
|
|
}
|
|
catch (const meosException &) {
|
|
}
|
|
|
|
}
|
|
|
|
void Parser::dumpVariables(gdioutput &gdi, int c1, int c2) const {
|
|
for (map<string, vector<int> >::iterator it = var.begin(); it != var.end(); ++it) {
|
|
const vector<int> &v = it->second;
|
|
string val;
|
|
if (v.size() == 1) {
|
|
val = itos(v[0]);
|
|
}
|
|
else {
|
|
val = "[";
|
|
for (size_t k = 0; k < v.size(); k++) {
|
|
if (k > 0)
|
|
val += ",";
|
|
val += itos(v[k]);
|
|
}
|
|
val += "]";
|
|
}
|
|
int cy = gdi.getCY();
|
|
gdi.addStringUT(cy, c1, monoText, it->first, c2-c1-10);
|
|
gdi.addStringUT(cy, c2, monoText, val);
|
|
}
|
|
}
|
|
|
|
void Parser::dumpSymbols(gdioutput &gdi, int c1, int c2) const {
|
|
for (map<string, Symbol>::const_iterator it = symb.begin(); it != symb.end(); ++it) {
|
|
const vector< vector<int> > &v = it->second.value;
|
|
if (v.empty())
|
|
continue;
|
|
|
|
int cy = gdi.getCY();
|
|
gdi.addStringUT(cy, c1, monoText, it->first, c2-c1-10);
|
|
|
|
string val;
|
|
|
|
if (v.size() == 1) {
|
|
if (v[0].size() == 1) {
|
|
val = itos(v[0][0]);
|
|
}
|
|
else {
|
|
val = "[";
|
|
for (size_t k = 0; k < v[0].size(); k++) {
|
|
if (k > 0)
|
|
val += ",";
|
|
val += itos(v[0][k]);
|
|
}
|
|
val += "]";
|
|
}
|
|
gdi.addStringUT(cy, c2, monoText, val);
|
|
}
|
|
else {
|
|
for (size_t j = 0; j < v.size(); j++) {
|
|
val = itos(j) + ": [";
|
|
for (size_t k = 0; k < v[j].size(); k++) {
|
|
if (k > 0)
|
|
val += ",";
|
|
val += itos(v[j][k]);
|
|
}
|
|
val += "]";
|
|
gdi.addStringUT(cy, c2, monoText, val);
|
|
cy = gdi.getCY();
|
|
}
|
|
}
|
|
}
|
|
}
|