/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2020 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 . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ #include "stdafx.h" #include #include #include #include "parser.h" #include "meosException.h" #include "meos_util.h" #include #include #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 &se, vector &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 se; vector 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 se; se['('] = ')'; vector 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 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 spv; map 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(sn->node); while (ifn != 0 && ifn->iffalse) { ifn = dynamic_cast(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::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 >::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::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 >::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::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 >::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 >::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 &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 &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 &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(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(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(*right); return parser.evaluateSize(vn.value, 0); } case OpSizeBase: { ValueNode &vn= dynamic_cast(*right); return parser.evaluateSize(vn.value, -1); } case OpSizeSub: { ArrayValueNode &vn= dynamic_cast(*right); return parser.evaluateSize(vn.expr, vn.index->evaluate(parser)); } case OpSortArray: { ValueNode &vn= dynamic_cast(*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 &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 &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 &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::const_iterator res = symb.find(input); return res != symb.end() && res->second.isMatrix; } bool Parser::isVector(const string &input) const { map::const_iterator res = symb.find(input); if (res != symb.end()) return !res->second.isMatrix && res->second.value[0].size() != 1; map >::const_iterator resv = var.find(input); return resv != var.end() && resv->second.size() != 1; } const vector &Parser::getVector(const string &symbol, int index) const{ map::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 >::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 &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 &v = symb[name].value[0]; v.resize(1); v[0] = value; } void Parser::addSymbol(const char *name, const vector &value) { assert(symb.count(name) && symb[name].isVector); symb[name].value.resize(1); vector &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 &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 > &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 &val) const { map >::iterator resv = var.find(name); if (resv != var.end()) { vector &res = resv->second; val.swap(res); } else val.clear(); } void Parser::getSymbols(vector< pair > &symbOut) const { int iter = 0; for(map::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::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 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 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 > 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 >::iterator it = var.begin(); it != var.end(); ++it) { const vector &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::const_iterator it = symb.begin(); it != symb.end(); ++it) { const vector< vector > &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(); } } } }