diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index 9e412ee3f..24410da24 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -137,7 +137,7 @@ static void appendCode(u256s& o_code, vector& o_locs, u256s _code, vec o_code.push_back(i); } -static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256s& o_code, vector& o_locs) +static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s& o_code, vector& o_locs) { std::map const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD } }; std::map const c_binary = { { "<", Instruction::LT }, { "<=", Instruction::LE }, { ">", Instruction::GT }, { ">=", Instruction::GE }, { "=", Instruction::EQ }, { "!=", Instruction::NOT } }; @@ -145,6 +145,7 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 std::set const c_allowed = { '+', '-', '*', '/', '%', '<', '>', '=', '!' }; bool exec = false; + int outs = 1; while (d != e) { @@ -166,11 +167,11 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 if (exec) { ++d; - return true; + return outs; } else // unexpected - return false as we don't know what to do with it. - return false; + return -1; default: { bool haveLiteral = false; @@ -214,7 +215,7 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 if (compileLispFragment(d, e, _quiet, codes, locs)) { appendCode(o_code, o_locs, codes, locs); - while (compileLispFragment(d, e, _quiet, codes, locs)) + while (compileLispFragment(d, e, _quiet, codes, locs) != -1) if (!_quiet) cwarn << "Additional items in bare store. Ignoring."; bareLoad = false; @@ -234,9 +235,14 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 u256s codes[4]; vector locs[4]; for (int i = 0; i < 3; ++i) - if (!compileLispFragment(d, e, _quiet, codes[i], locs[i])) - return false; - if (compileLispFragment(d, e, _quiet, codes[3], locs[3])) + { + int o = compileLispFragment(d, e, _quiet, codes[i], locs[i]); + if (i == 1) + outs = o; + if ((i == 0 && o != 1) || o == -1 || (i == 2 && o != outs)) + return -1; + } + if (compileLispFragment(d, e, _quiet, codes[3], locs[3]) != -1) return false; // Push the positive location. @@ -270,13 +276,19 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 } else if (t == "WHEN" || t == "UNLESS") { + outs = 0; // Compile all the code... u256s codes[3]; vector locs[3]; for (int i = 0; i < 2; ++i) - if (!compileLispFragment(d, e, _quiet, codes[i], locs[i])) + { + int o = compileLispFragment(d, e, _quiet, codes[i], locs[i]); + if (o == -1) return false; - if (compileLispFragment(d, e, _quiet, codes[2], locs[2])) + for (int i = 0; i < o; ++i) + o_code.push_back(Instruction::POP); // pop additional items off stack for the previous item (final item's returns get left on). + } + if (compileLispFragment(d, e, _quiet, codes[2], locs[2]) != -1) return false; // Push the positive location. @@ -301,13 +313,19 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 } else if (t == "FOR") { + outs = 0; // Compile all the code... u256s codes[3]; vector locs[3]; for (int i = 0; i < 2; ++i) - if (!compileLispFragment(d, e, _quiet, codes[i], locs[i])) + { + int o = compileLispFragment(d, e, _quiet, codes[i], locs[i]); + if (o == -1) return false; - if (compileLispFragment(d, e, _quiet, codes[2], locs[2])) + for (int i = 0; i < o; ++i) + o_code.push_back(Instruction::POP); // pop additional items off stack for the previous item (final item's returns get left on). + } + if (compileLispFragment(d, e, _quiet, codes[2], locs[2]) != -1) return false; unsigned startLocation = (unsigned)o_code.size(); @@ -343,8 +361,15 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 { u256s codes; vector locs; - if (compileLispFragment(d, e, _quiet, codes, locs)) + outs = 0; + int o; + if ((o = compileLispFragment(d, e, _quiet, codes, locs)) > -1) + { + for (int i = 0; i < outs; ++i) + o_code.push_back(Instruction::POP); // pop additional items off stack for the previous item (final item's returns get left on). + outs = o; appendCode(o_code, o_locs, codes, locs); + } else break; } @@ -357,7 +382,12 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 { codes.resize(codes.size() + 1); locs.resize(locs.size() + 1); - if (!compileLispFragment(d, e, _quiet, codes.back(), locs.back())) + { + int o = compileLispFragment(d, e, _quiet, codes.back(), locs.back()); + if (o != 1) + return false; + } + if (compileLispFragment(d, e, _quiet, codes.back(), locs.back()) != -1) break; } @@ -408,8 +438,11 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 { codes.resize(codes.size() + 1); locs.resize(locs.size() + 1); - if (!compileLispFragment(d, e, _quiet, codes.back(), locs.back())) - break; + { + int o = compileLispFragment(d, e, _quiet, codes.back(), locs.back()); + if (o != 1) + return false; + } } // last one is empty. @@ -458,11 +491,26 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 if (exec) { vector>> codes(1); - while (d != e && compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second)) + int totalArgs = 0; + while (d != e) + { + int o = compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second); + if (o < 1) + break; codes.push_back(pair>()); + totalArgs += o; + } + int ea = c_instructionInfo.at(it->second).args; + if (totalArgs != ea || (ea < 0 && totalArgs < -ea)) + { + cwarn << "Expected " << (ea < 0 ? "at least" : "exactly") << abs(ea) << "arguments to binary operator" << t << "; got" << totalArgs << "."; + break; + } + for (auto it = codes.rbegin(); it != codes.rend(); ++it) appendCode(o_code, o_locs, it->first, it->second); o_code.push_back((u256)it->second); + outs = c_instructionInfo.at(it->second).ret; } else { @@ -480,15 +528,22 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 { u256s codes; vector locs; - if (compileLispFragment(d, e, _quiet, codes, locs)) + int o = compileLispFragment(d, e, _quiet, codes, locs); + if (o == -1) { - appendCode(o_code, o_locs, codes, locs); - if (i) - o_code.push_back((u256)it->second); - ++i; + if (!i) + cwarn << "Expected at least one argument to operation" << t; + break; } - else + if (o == 0) + { + cwarn << "null operation given to " << t; break; + } + appendCode(o_code, o_locs, codes, locs); + i += o; + for (; i > 1; --i) + o_code.push_back((u256)it->second); } } else @@ -497,15 +552,24 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 if (it != c_binary.end()) { vector>> codes(1); - while (d != e && compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second)) + int totalArgs = 0; + while (d != e) + { + int o = compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second); + if (o < 1) + break; codes.push_back(pair>()); + totalArgs += o; + } codes.pop_back(); - int i = (int)codes.size(); - if (i > 2) - cwarn << "Greater than two arguments given to binary operator" << t << "; using first two only."; +// int i = (int)codes.size(); + if (totalArgs != 2) + { + cwarn << "Expected two arguments to binary operator" << t << "; got" << totalArgs << "."; + break; + } for (auto it = codes.rbegin(); it != codes.rend(); ++it) - if (--i < 2) - appendCode(o_code, o_locs, it->first, it->second); + appendCode(o_code, o_locs, it->first, it->second); if (it->second == Instruction::NOT) o_code.push_back(Instruction::EQ); o_code.push_back((u256)it->second); @@ -516,15 +580,24 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 if (it != c_unary.end()) { vector>> codes(1); - while (d != e && compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second)) + int totalArgs = 0; + while (d != e) + { + int o = compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second); + if (o == -1) + break; + totalArgs += o; codes.push_back(pair>()); + } codes.pop_back(); - int i = (int)codes.size(); - if (i > 1) - cwarn << "Greater than one argument given to unary operator" << t << "; using first only."; +// int i = (int)codes.size(); + if (totalArgs != 1) + { + cwarn << "Expected one argument to unary operator" << t << "; got" << totalArgs << "."; + break; + } for (auto it = codes.rbegin(); it != codes.rend(); ++it) - if (--i < 1) - appendCode(o_code, o_locs, it->first, it->second); + appendCode(o_code, o_locs, it->first, it->second); o_code.push_back(it->second); } else if (!_quiet) @@ -536,11 +609,11 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 } if (!exec) - return true; + return outs; } } } - return false; + return -1; } u256s eth::compileLisp(std::string const& _code, bool _quiet) diff --git a/libethereum/Instruction.h b/libethereum/Instruction.h index cc37d0e79..fca0edc2d 100644 --- a/libethereum/Instruction.h +++ b/libethereum/Instruction.h @@ -126,10 +126,10 @@ static const std::map c_instructionInfo = { Instruction::BASEFEE, { "BASEFEE", 0, 0, 1 } }, { Instruction::SHA256, { "SHA256", 0, -1, 1 } }, { Instruction::RIPEMD160, { "RIPEMD160", 0, -1, 1 } }, - { Instruction::ECMUL, { "ECMUL", 0, 3, 1 } }, - { Instruction::ECADD, { "ECADD", 0, 4, 1 } }, - { Instruction::ECSIGN, { "ECSIGN", 0, 2, 1 } }, - { Instruction::ECRECOVER, { "ECRECOVER", 0, 4, 1 } }, + { Instruction::ECMUL, { "ECMUL", 0, 3, 2 } }, + { Instruction::ECADD, { "ECADD", 0, 4, 2 } }, + { Instruction::ECSIGN, { "ECSIGN", 0, 2, 3 } }, + { Instruction::ECRECOVER, { "ECRECOVER", 0, 4, 2 } }, { Instruction::ECVALID, { "ECVALID", 0, 2, 1 } }, { Instruction::SHA3, { "SHA3", 0, -1, 1 } }, { Instruction::PUSH, { "PUSH", 1, 0, 1 } },