diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index 9b9e8b316..1cdca6e3e 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -254,12 +254,20 @@ void parseLLL(string const& _s, sp::utree& o_out) string s; s.reserve(_s.size()); bool incomment = false; + bool instring = false; + bool insstring = false; for (auto i: _s) { - if (i == ';') + if (i == ';' && !instring && !insstring) incomment = true; else if (i == '\n') - incomment = false; + incomment = instring = insstring = false; + else if (i == '"' && !insstring) + instring = !instring; + else if (i == '\'') + insstring = true; + else if (i == ' ') + insstring = false; if (!incomment) s.push_back(i); } @@ -278,13 +286,14 @@ struct Macro { std::vector args; sp::utree code; + std::map env; }; struct CompilerState { std::map vars; - std::map defs; + std::map args; std::map macros; }; @@ -434,6 +443,15 @@ void debugOutAST(ostream& _out, sp::utree const& _this) CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) { + cdebug << "CodeFragment. Args:"; + for (auto const& i: _s.args) + cdebug << i.first << ":" << toHex(i.second.m_code); + cdebug << "Defs:"; + for (auto const& i: _s.defs) + cdebug << i.first << ":" << toHex(i.second.m_code); + debugOutAST(cout, _t); + cout.flush(); + switch (_t.which()) { case sp::utree_type::list_type: @@ -465,7 +483,9 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS m_code.push_back((byte)it->second); } } - if (_s.defs.count(s)) + if (_s.args.count(s)) + appendFragment(_s.args.at(s)); + else if (_s.defs.count(s)) appendFragment(_s.defs.at(s)); else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890") == string::npos) { @@ -503,6 +523,18 @@ void CodeFragment::appendPushDataLocation(bytes const& _data) m_deposit++; } +std::string CodeFragment::asPushedString() const +{ + string ret; + unsigned bc = m_code[0] - (byte)Instruction::PUSH1 + 1; + if (m_code[0] >= (byte)Instruction::PUSH1 && m_code[0] <= (byte)Instruction::PUSH32) + for (unsigned s = 0; s < bc && m_code[1 + s]; ++s) + ret.push_back(m_code[1 + s]); + else + error(); + return ret; +} + void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { if (_t.empty()) @@ -559,10 +591,22 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { if (ii == 1) { - if (i.tag() || i.which() != sp::utree_type::symbol_type) + if (i.tag()) error(); - auto sr = i.get, sp::utree_type::symbol_type>>(); - n = string(sr.begin(), sr.end()); + if (i.which() == sp::utree_type::string_type) + { + auto sr = i.get, sp::utree_type::string_type>>(); + n = string(sr.begin(), sr.end()); + } + else if (i.which() != sp::utree_type::string_type) + { + auto sr = i.get, sp::utree_type::symbol_type>>(); + n = string(sr.begin(), sr.end()); + if (_s.args.count(n)) + n = _s.args.at(n).asPushedString(); + else if (_s.defs.count(n)) + n = _s.defs.at(n).asPushedString(); + } } else if (ii == 2) if (_t.size() == 3) @@ -576,9 +620,13 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) _s.macros[n].args.push_back(string(sr.begin(), sr.end())); } else if (ii == 3) + { _s.macros[n].code = i; + _s.macros[n].env = _s.defs; + } ++ii; } + } else if (us == "LIT") { @@ -659,7 +707,25 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) auto requireMaxSize = [&](unsigned s) { if (code.size() > s) error(); }; auto requireDeposit = [&](unsigned i, int s) { if (code[i].m_deposit != s) error(); }; - if (c_instructions.count(us)) + if (_s.macros.count(s) && _s.macros.at(s).args.size() == code.size()) + { + Macro const& m = _s.macros.at(s); + CompilerState cs = _s; + for (unsigned i = 0; i < m.args.size(); ++i) + { + requireDeposit(i, 1); + cs.args[m.args[i]] = code[i]; + } + for (auto const& i: m.env) + if (!cs.args.count(i.first)) + cs.args.insert(i); + appendFragment(CodeFragment(m.code, cs)); + for (auto i: cs.defs) + _s.defs.insert(i); + for (auto i: cs.macros) + _s.macros.insert(i); + } + else if (c_instructions.count(us)) { auto it = c_instructions.find(us); int ea = c_instructionInfo.at(it->second).args; @@ -736,7 +802,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) else if (us == "WHILE") { requireSize(2); - requireDeposit(1, 1); + requireDeposit(0, 1); auto begin = CodeLocation(this); appendFragment(code[0], 1); appendInstruction(Instruction::NOT); @@ -829,18 +895,6 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) else appendFragment(i); } - else if (_s.macros.count(s)) - { - Macro const& m = _s.macros.at(s); - CompilerState cs = _s; - requireSize(m.args.size()); - for (unsigned i = 0; i < m.args.size(); ++i) - { - requireDeposit(i, 1); - cs.defs[m.args[i]] = code[i]; - } - appendFragment(CodeFragment(m.code, cs)); - } else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890") == string::npos) { auto it = _s.vars.find(s); diff --git a/libethereum/Instruction.h b/libethereum/Instruction.h index 284688484..5f80a3e69 100644 --- a/libethereum/Instruction.h +++ b/libethereum/Instruction.h @@ -162,6 +162,7 @@ class InvalidName: public CompilerException {}; class InvalidMacroArgs: public CompilerException {}; class InvalidLiteral: public CompilerException {}; class BareSymbol: public CompilerException {}; +class ExpectedLiteral: public CompilerException {}; bytes compileLLL(std::string const& _s, std::vector* _errors = nullptr); class CompilerState; @@ -216,18 +217,22 @@ public: CodeLocation appendJump(CodeLocation _l) { auto ret = appendPushLocation(_l.m_pos); appendInstruction(Instruction::JUMP); return ret; } CodeLocation appendJumpI(CodeLocation _l) { auto ret = appendPushLocation(_l.m_pos); appendInstruction(Instruction::JUMPI); return ret; } + std::string asPushedString() const; + void onePath() { assert(!m_totalDeposit && !m_baseDeposit); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } void ignored() { m_baseDeposit = m_deposit; } void endIgnored() { m_deposit = m_baseDeposit; m_baseDeposit = 0; } + bool operator==(CodeFragment const& _f) const { return _f.m_code == m_code && _f.m_data == m_data; } + bool operator!=(CodeFragment const& _f) const { return !operator==(_f); } unsigned size() const { return m_code.size(); } void consolidateData(); private: - template void error() { throw T(); } + template void error() const { throw T(); } void constructOperation(sp::utree const& _t, CompilerState& _s); void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) error(); }