bool CalcExpr(const string & expr, int a1, int a2, Token & result) { map<string,TokenVector>::iterator its=cache.find(expr); if(its==cache.end()) { TokenVector a; bool r = ParseExpr(expr, a); if (!r) return false; TokenVector b; r = ConvertExpr(a, b); if (!r) return false; cache.insert(std::map<string,TokenVector> :: value_type(expr,b)); } map<string,TokenVector>::iterator it=cache.find(expr); TokenVector input; Token x; x.type = INT; x.value.i = a1; input.push_back(x); x.value.i = a2; input.push_back(x); return CalcExpr(input, it->second, result); }
void VerifyEscapedOctalDigits(unsigned int expectedToken, wstring octalDigitStringPrefix, wstring octalDigitStringSuffix) { vector<wstring> escapedOctalItems; //Test we recognize the basic set of Octal digits (0-7) (we use '8' below in make_pair as the range is the standard STL style range where it is //up to, but not including, the 'end' position). PopulateASCIICharacterCodes(escapedOctalItems, make_pair(static_cast<int>(L'0'), static_cast<int>(L'8')), wstring(L"\\")); //Test we recognize 1, 2 and 3 digit octal strings (obvioulsy exhustive tests for all possible octal numbers from 0-777 would take forever to run escapedOctalItems.push_back(wstring(L"\\1")); escapedOctalItems.push_back(wstring(L"\\11")); escapedOctalItems.push_back(wstring(L"\\111")); for_each(escapedOctalItems.begin(), escapedOctalItems.end(), [expectedToken, &octalDigitStringPrefix, &octalDigitStringSuffix] (const wstring& refStringLit) -> void { wstring toLex = octalDigitStringPrefix + refStringLit + octalDigitStringSuffix; TokenVector expectedTokens; expectedTokens.push_back(make_pair(expectedToken, toLex)); VerifyLex(toLex, expectedTokens); }); }
void VerifyLex(const wstring& refToLex, const TokenVector& expectedTokens, bool shouldSucceed /*= true*/) { wchar_t const* first = refToLex.c_str(); wchar_t const* last = first + refToLex.size(); TokenVector actualTokens; auto cur = g_lexer.begin(first, last); auto end = g_lexer.end(); for(; cur != end && cur->is_valid() ; ++cur) { try { actualTokens.push_back(make_pair(cur->id(), wstring(cur->value().begin(), cur->value().end()))); } catch(const std::bad_alloc&) { break; } } const bool lexingSucceeded = (cur == end); const bool lexResultAsExpected = lexingSucceeded == shouldSucceed; //Kind of goofy to have to do it this way but the unit test stuff is not set up to output wstrings :( if(!lexResultAsExpected) { wcout << endl << L"Lexing was expected to " << (shouldSucceed ? L"pass" : L"fail") << L"but it " << (shouldSucceed ? L"failed" : L"passed") << L" with input '" << refToLex << L"'" << endl; } BOOST_CHECK( lexResultAsExpected ); if(shouldSucceed) { const bool sizeMatches = actualTokens.size() == expectedTokens.size(); if(!sizeMatches) { wcout << endl << L"Expected lexing to result in " << expectedTokens.size() << L" but it actually resulted in " << actualTokens.size() << L" tokens." << endl; } BOOST_CHECK( sizeMatches ); //avoid annoying signed/unsigned mismatch or relying on the fact that ::size_type is == size_t typedef decltype(actualTokens.size()) IndexType; for(IndexType i = 0 ; i < actualTokens.size() ; ++i) { auto actual = actualTokens[i]; auto expected = expectedTokens[i]; const bool areEqual = (actual == expected); if(!areEqual) { wcout << endl << L"Expected token '" << expected.second + L"' (" << expected.first << "), but got '" << actual.second << L"' (" << actual.first << L") at token index " << i << endl; } BOOST_CHECK( areEqual ); } } }
void VerifyEscapedControlCodes(unsigned int expectedToken, wstring codeStringPrefix, wstring codeStringSuffix) { vector<wstring> controlEscapeStringLiteralItems; PopulateASCIICharacterCodes(controlEscapeStringLiteralItems, make_pair(64, 96), wstring(L"\\^")); for_each(controlEscapeStringLiteralItems.begin(), controlEscapeStringLiteralItems.end(), [expectedToken, &codeStringPrefix, &codeStringSuffix] (const wstring& refStringLit) -> void { wstring toLex = codeStringPrefix + refStringLit + codeStringSuffix; TokenVector expectedTokens; expectedTokens.push_back(make_pair(expectedToken, toLex)); VerifyLex(toLex, expectedTokens); }); }
// 词法分析,解析表达式 bool ParseExpr(const string & expr, TokenVector & tokens) { // 表达式的解析较简单,就不用状态机了,直接一个一个解析。。。 int i = 0; Token token; string buffer; tokens.clear(); while (i < expr.length()) { // 空白跳过 if (isblank(expr[i])) { ++i; continue; } // 单个字符的操作符和括号 if (expr[i] == '+' || expr[i] == '-' || expr[i] == '*' || expr[i] == '/' || expr[i] == '%' || expr[i] == '^' || expr[i] == '(' || expr[i] == ')') { token.type = OP; if (expr[i] == '+') token.value.op = ADD; else if (expr[i] == '-') token.value.op = SUB; else if (expr[i] == '*') token.value.op = MUL; else if (expr[i] == '/') token.value.op = DIV; else if (expr[i] == '%') token.value.op = MOD; else if (expr[i] == '^') token.value.op = POW; else if (expr[i] == '(') token.value.op = LEFT; else if (expr[i] == ')') token.value.op = RIGHT; tokens.push_back(token); ++i; continue; } // 整数或浮点数 else if (isdigit(expr[i])) { buffer.clear(); buffer += expr[i++]; bool point = false; while (i < expr.length()) { if (isdigit(expr[i])) { buffer += expr[i++]; } else if (expr[i] == '.' && !point) { buffer += expr[i++]; point = true; } else { break; } } if (point) { token.type = FLOAT; token.value.f = strtof(buffer.c_str(), NULL); } else { token.type = INT; token.value.i = strtoul(buffer.c_str(), NULL, 0); } tokens.push_back(token); } // 随机数 else if (expr[i] == 'r') { token.type = RAND; token.value.i = 0; tokens.push_back(token); ++i; } // 参数 else if (expr[i] == 'x') { ++i; buffer.clear(); while (i < expr.length() && isdigit(expr[i])) { buffer += expr[i]; ++i; } if (buffer.empty()) { return false; } token.type = ARG; token.value.index = strtoul(buffer.c_str(), NULL, 0); tokens.push_back(token); continue; } // > 或 >= else if (expr[i] == '>') { token.type = OP; ++i; if (i < expr.length() && expr[i] == '=') { token.value.op = GE; ++i; } else { token.value.op = GT; } tokens.push_back(token); } // < 或 <= else if (expr[i] == '<') { token.type = OP; ++i; if (i < expr.length() && expr[i] == '=') { token.value.op = LE; ++i; } else { token.value.op = LT; } tokens.push_back(token); } // == else if (i + 1 < expr.length() && expr[i] == '=' && expr[i + 1] == '=') { token.type = OP; token.value.op = EQ; tokens.push_back(token); i += 2; } // != else if (i + 1 < expr.length() && expr[i] == '!' && expr[i + 1] == '=') { token.type = OP; token.value.op = NE; tokens.push_back(token); i += 2; } // && else if (i + 1 < expr.length() && expr[i] == '&' && expr[i + 1] == '&') { token.type = OP; token.value.op = AND; tokens.push_back(token); i += 2; } // || else if (i + 1 < expr.length() && expr[i] == '|' && expr[i + 1] == '|') { token.type = OP; token.value.op = OR; tokens.push_back(token); i += 2; } else { return false; } } return true; }
// 把解析好的表达式转换成逆波兰式 bool ConvertExpr(const TokenVector & input, TokenVector & output) { TokenStack stack; output.clear(); TokenVector::const_iterator it = input.begin(); for (; it != input.end(); ++it) { if (it->type == OP) { // 左括号,直接压进操作符栈 if (it->value.op == LEFT) { stack.push(*it); } // 右括号,从栈里弹出操作符,直到碰到右括号 else if (it->value.op == RIGHT) { bool find_left = false; while (!stack.empty()) { if (stack.top().value.op == LEFT) { find_left = true; stack.pop(); break; } else { output.push_back(stack.top()); stack.pop(); } } if (!find_left) return false; } // 其它操作符,和栈顶操作符比较优先级 else { while (!stack.empty() && stack.top().value.op != LEFT && OPPriority(stack.top().value.op) >= OPPriority(it->value.op)) { output.push_back(stack.top()); stack.pop(); } stack.push(*it); } } // 非操作符直接输出 else { output.push_back(*it); } } while (!stack.empty()) { output.push_back(stack.top()); stack.pop(); } return true; }
/** * Nastavi svuj stav podle vstupniho XML, ktere parsuje. * * @param xml vstupni XML se stavem simulace * * @return true pokud se podarilo nastavit stav, jinak false */ bool SimState::setState(QString xml) { //inicializuji hodnoty places.clear(); transits.clear(); places_id.clear(); transits_id.clear(); QString errorStr; int errorLine; int errorColumn; QDomDocument document; if (!document.setContent(xml,&errorStr,&errorLine,&errorColumn)) { //proparsuju XML qCritical() << "Error during parsing xml on line: " << errorLine << ", column: " << errorColumn; return false; } QDomElement root = document.documentElement(); if (root.tagName() != "petrinet") { //nejedna se petriho sit qCritical() << "Error during parsing xml, not valid"; return false; } //nactu informace o siti author = root.attribute("author"); name = root.attribute("name"); version = root.attribute("version").toInt(); info = root.attribute("info"); //iteruji nad misty QDomElement xml_places = root.firstChildElement("places"); QDomElement one_place = xml_places.firstChildElement("place"); while (!one_place.isNull()) { TokenVector tokens; //projdu vsechny tokeny QDomElement one_token = one_place.firstChildElement("token"); while (!one_token.isNull()) { pntype token = one_token.text().toInt(); tokens.push_back(token); one_token = one_token.nextSiblingElement("token"); } //vytvorim nove misto, naplnim ho PNPlace *place = new PNPlace(one_place.attribute("posx"),one_place.attribute("posy") ,one_place.attribute("id"),tokens); places.push_back(place); //a zapisu do vektoru mist places_id[one_place.attribute("id")] = place; //zapisu jeho ID one_place = one_place.nextSiblingElement("place"); } //iteruji nad prechody QDomElement xml_trans = root.firstChildElement("transitions"); QDomElement one_trans = xml_trans.firstChildElement("transition"); while (!one_trans.isNull()) { StringToPnplaceMap in_names; StringToPnplaceMap out_names; ConstraintVector constraints; //nejdriv inicializuji vstupni mista QDomElement one_element = one_trans.firstChildElement("inplace"); while (!one_element.isNull()) { bool isNum = false; one_element.attribute("name").toInt(&isNum); //vstupni misto je konstanta if (isNum) { //pridam omezeni prechod == konstanta in_names[one_element.attribute("name")] = places_id[one_element.text()]; constraints.push_back(new Constraint(one_element.attribute("name"),OP_EQ,one_element.attribute("name").toInt())); } else { in_names[one_element.attribute("name")] = places_id[one_element.text()]; //uchovam ukazatel na vstupni misto } one_element = one_element.nextSiblingElement("inplace"); } //pote udelam to stejne s vystupnimi misty one_element = one_trans.firstChildElement("outplace"); while (!one_element.isNull()) { out_names[one_element.attribute("name")] = places_id[one_element.text()]; one_element = one_element.nextSiblingElement("outplace"); } //pak iteruji nad omezenimi QDomElement one_cond = one_trans.firstChildElement("constraint"); while (!one_cond.isNull()) { Constraint *cond; if (one_cond.attribute("type") == "const") { //druha hodnota je konstanta cond = new Constraint(one_cond.attribute("var1"),one_cond.attribute("op").toInt(),one_cond.attribute("const").toInt()); } else { //druha hodnota je promenna cond = new Constraint(one_cond.attribute("var1"),one_cond.attribute("op").toInt(),one_cond.attribute("var2")); } constraints.push_back(cond); //ulozim omezeni one_cond = one_cond.nextSiblingElement("constraint"); } //nakonec iteruji nad operacemi OutputOperations operations; QDomElement one_op = one_trans.firstChildElement("operation"); while (!one_op.isNull()){ OneOut oneout; oneout.output = one_op.attribute("output"); QDomElement one_operation = one_op.firstChildElement(); //iteruji nad jednou vstupni operaci while(!one_operation.isNull()) { Operation op; if (one_operation.tagName() == "plus") { op.op = ADD; } else { op.op = SUB; } op.var = one_operation.attribute("id"); oneout.operations.push_back(op); one_operation = one_operation.nextSiblingElement(); } operations.push_back(oneout); one_op = one_op.nextSiblingElement("operation"); } //vytvorim novy prechod a naplnim hodnotami PNTrans *trans = new PNTrans(one_trans.attribute("posx"), one_trans.attribute("posy"), one_trans.attribute("id"), constraints, in_names, out_names, operations); transits_id[one_trans.attribute("id")] = trans; transits.push_back(trans); //ulozim do vektoru mist one_trans = one_trans.nextSiblingElement("transition"); } return true; }