aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGav Wood <i@gavwood.com>2014-05-26 17:22:19 +0800
committerGav Wood <i@gavwood.com>2014-05-26 17:22:19 +0800
commita4e46e665aac0aa26afa37a22eaf44941d856d9f (patch)
tree12f5c1ee10b87694756a96115e9723ca18a2f05b
downloaddexon-solidity-a4e46e665aac0aa26afa37a22eaf44941d856d9f.tar
dexon-solidity-a4e46e665aac0aa26afa37a22eaf44941d856d9f.tar.gz
dexon-solidity-a4e46e665aac0aa26afa37a22eaf44941d856d9f.tar.bz2
dexon-solidity-a4e46e665aac0aa26afa37a22eaf44941d856d9f.tar.lz
dexon-solidity-a4e46e665aac0aa26afa37a22eaf44941d856d9f.tar.xz
dexon-solidity-a4e46e665aac0aa26afa37a22eaf44941d856d9f.tar.zst
dexon-solidity-a4e46e665aac0aa26afa37a22eaf44941d856d9f.zip
Major reorganisation.
New libs (libethsupport, libevm, liblll). New LLLC binary.
-rw-r--r--Assembly.cpp0
-rw-r--r--Assembly.h0
-rw-r--r--CMakeLists.txt70
-rw-r--r--CodeFragment.cpp701
-rw-r--r--CodeFragment.h157
-rw-r--r--Compiler.cpp61
-rw-r--r--Compiler.h35
-rw-r--r--CompilerState.cpp37
-rw-r--r--CompilerState.h49
-rw-r--r--Parser.cpp91
-rw-r--r--Parser.h38
11 files changed, 1239 insertions, 0 deletions
diff --git a/Assembly.cpp b/Assembly.cpp
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/Assembly.cpp
diff --git a/Assembly.h b/Assembly.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/Assembly.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..dc5fc222
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,70 @@
+cmake_policy(SET CMP0015 NEW)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
+
+aux_source_directory(. SRC_LIST)
+
+set(EXECUTABLE lll)
+
+if(APPLE)
+ # set(CMAKE_INSTALL_PREFIX ../lib)
+ add_library(${EXECUTABLE} SHARED ${SRC_LIST})
+else()
+ add_library(${EXECUTABLE} ${SRC_LIST})
+endif()
+if (UNIX)
+ FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework locale)
+endif()
+file(GLOB HEADERS "*.h")
+
+include_directories(..)
+include_directories(${MINIUPNPC_ID})
+include_directories(${LEVELDB_ID})
+
+target_link_libraries(${EXECUTABLE} ethcore)
+target_link_libraries(${EXECUTABLE} ethsupport)
+target_link_libraries(${EXECUTABLE} secp256k1)
+target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
+target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
+target_link_libraries(${EXECUTABLE} gmp)
+
+
+if(${TARGET_PLATFORM} STREQUAL "w64")
+ include_directories(/usr/x86_64-w64-mingw32/include/cryptopp)
+ target_link_libraries(${EXECUTABLE} cryptopp)
+ target_link_libraries(${EXECUTABLE} boost_system-mt-s)
+ target_link_libraries(${EXECUTABLE} boost_filesystem-mt-s)
+ target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
+ target_link_libraries(${EXECUTABLE} iphlpapi)
+ target_link_libraries(${EXECUTABLE} ws2_32)
+ target_link_libraries(${EXECUTABLE} mswsock)
+ target_link_libraries(${EXECUTABLE} shlwapi)
+elseif (APPLE)
+ # Latest mavericks boost libraries only come with -mt
+ target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES})
+ target_link_libraries(${EXECUTABLE} boost_system-mt)
+ target_link_libraries(${EXECUTABLE} boost_filesystem-mt)
+ target_link_libraries(${EXECUTABLE} boost_thread-mt)
+ find_package(Threads REQUIRED)
+ target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
+elseif (UNIX)
+ target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES})
+ target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARY})
+ target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARY})
+ target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY})
+ target_link_libraries(${EXECUTABLE} ${Boost_DATE_TIME_LIBRARY})
+ target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
+else ()
+ target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES})
+ target_link_libraries(${EXECUTABLE} boost_system)
+ target_link_libraries(${EXECUTABLE} boost_filesystem)
+ target_link_libraries(${EXECUTABLE} boost_thread)
+ find_package(Threads REQUIRED)
+ target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
+endif ()
+
+message("Installation path: ${CMAKE_INSTALL_PREFIX}")
+
+install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
+install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )
+
diff --git a/CodeFragment.cpp b/CodeFragment.cpp
new file mode 100644
index 00000000..854a27c4
--- /dev/null
+++ b/CodeFragment.cpp
@@ -0,0 +1,701 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file CodeFragment.cpp
+ * @author Gav Wood <i@gavwood.com>
+ * @date 2014
+ */
+
+#include "Parser.h"
+#include "CodeFragment.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/spirit/include/support_utree.hpp>
+#include <libethsupport/Log.h>
+#include <libethcore/Instruction.h>
+#include <libethcore/CommonEth.h>
+#include "CompilerState.h"
+using namespace std;
+using namespace eth;
+namespace qi = boost::spirit::qi;
+namespace px = boost::phoenix;
+namespace sp = boost::spirit;
+
+void eth::debugOutAST(ostream& _out, sp::utree const& _this)
+{
+ switch (_this.which())
+ {
+ case sp::utree_type::list_type:
+ switch (_this.tag())
+ {
+ case 0: _out << "( "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << ")"; break;
+ case 1: _out << "@ "; debugOutAST(_out, _this.front()); break;
+ case 2: _out << "@@ "; debugOutAST(_out, _this.front()); break;
+ case 3: _out << "[ "; debugOutAST(_out, _this.front()); _out << " ] "; debugOutAST(_out, _this.back()); break;
+ case 4: _out << "[[ "; debugOutAST(_out, _this.front()); _out << " ]] "; debugOutAST(_out, _this.back()); break;
+ case 5: _out << "{ "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << "}"; break;
+ default:;
+ }
+
+ break;
+ case sp::utree_type::int_type: _out << _this.get<int>(); break;
+ case sp::utree_type::string_type: _out << "\"" << _this.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>() << "\""; break;
+ case sp::utree_type::symbol_type: _out << _this.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>(); break;
+ case sp::utree_type::any_type: _out << *_this.get<bigint*>(); break;
+ default: _out << "nil";
+ }
+}
+
+CodeLocation::CodeLocation(CodeFragment* _f)
+{
+ m_f = _f;
+ m_pos = _f->m_code.size();
+}
+
+unsigned CodeLocation::get() const
+{
+ assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4);
+ bytesConstRef r(&m_f->m_code[m_pos], 4);
+ cdebug << toHex(r);
+ return fromBigEndian<uint32_t>(r);
+}
+
+void CodeLocation::set(unsigned _val)
+{
+ assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4);
+ assert(!get());
+ bytesRef r(&m_f->m_code[m_pos], 4);
+ toBigEndian(_val, r);
+}
+
+void CodeLocation::anchor()
+{
+ set(m_f->m_code.size());
+}
+
+void CodeLocation::increase(unsigned _val)
+{
+ assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4);
+ bytesRef r(&m_f->m_code[m_pos], 4);
+ toBigEndian(get() + _val, r);
+}
+
+void CodeFragment::appendFragment(CodeFragment const& _f)
+{
+ m_locs.reserve(m_locs.size() + _f.m_locs.size());
+ m_code.reserve(m_code.size() + _f.m_code.size());
+
+ unsigned os = m_code.size();
+
+ for (auto i: _f.m_code)
+ m_code.push_back(i);
+
+ for (auto i: _f.m_locs)
+ {
+ CodeLocation(this, i + os).increase(os);
+ m_locs.push_back(i + os);
+ }
+
+ for (auto i: _f.m_data)
+ m_data.insert(make_pair(i.first, i.second + os));
+
+ m_deposit += _f.m_deposit;
+}
+
+CodeFragment CodeFragment::compile(string const& _src, CompilerState& _s)
+{
+ CodeFragment ret;
+ sp::utree o;
+ parseTreeLLL(_src, o);
+ if (!o.empty())
+ ret = CodeFragment(o, _s);
+ _s.treesToKill.push_back(o);
+ return ret;
+}
+
+void CodeFragment::consolidateData()
+{
+ m_code.push_back(0);
+ bytes ld;
+ for (auto const& i: m_data)
+ {
+ if (ld != i.first)
+ {
+ ld = i.first;
+ for (auto j: ld)
+ m_code.push_back(j);
+ }
+ CodeLocation(this, i.second).set(m_code.size() - ld.size());
+ }
+ m_data.clear();
+}
+
+void CodeFragment::appendFragment(CodeFragment const& _f, unsigned _deposit)
+{
+ if ((int)_deposit > _f.m_deposit)
+ error<InvalidDeposit>();
+ else
+ {
+ appendFragment(_f);
+ while (_deposit++ < (unsigned)_f.m_deposit)
+ appendInstruction(Instruction::POP);
+ }
+}
+
+CodeLocation CodeFragment::appendPushLocation(unsigned _locationValue)
+{
+ m_code.push_back((byte)Instruction::PUSH4);
+ CodeLocation ret(this, m_code.size());
+ m_locs.push_back(m_code.size());
+ m_code.resize(m_code.size() + 4);
+ bytesRef r(&m_code[m_code.size() - 4], 4);
+ toBigEndian(_locationValue, r);
+ m_deposit++;
+ return ret;
+}
+
+unsigned CodeFragment::appendPush(u256 _literalValue)
+{
+ unsigned br = max<unsigned>(1, bytesRequired(_literalValue));
+ m_code.push_back((byte)Instruction::PUSH1 + br - 1);
+ m_code.resize(m_code.size() + br);
+ for (unsigned i = 0; i < br; ++i)
+ {
+ m_code[m_code.size() - 1 - i] = (byte)(_literalValue & 0xff);
+ _literalValue >>= 8;
+ }
+ m_deposit++;
+ return br + 1;
+}
+
+void CodeFragment::appendInstruction(Instruction _i)
+{
+ m_code.push_back((byte)_i);
+ m_deposit += c_instructionInfo.at(_i).ret - c_instructionInfo.at(_i).args;
+}
+
+CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM)
+{
+/* cdebug << "CodeFragment. Locals:";
+ for (auto const& i: _s.defs)
+ cdebug << i.first << ":" << toHex(i.second.m_code);
+ cdebug << "Args:";
+ for (auto const& i: _s.args)
+ cdebug << i.first << ":" << toHex(i.second.m_code);
+ cdebug << "Outers:";
+ for (auto const& i: _s.outers)
+ cdebug << i.first << ":" << toHex(i.second.m_code);
+ debugOutAST(cout, _t);
+ cout << endl << flush;
+*/
+ switch (_t.which())
+ {
+ case sp::utree_type::list_type:
+ constructOperation(_t, _s);
+ break;
+ case sp::utree_type::string_type:
+ {
+ auto sr = _t.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>();
+ string s(sr.begin(), sr.end());
+ if (s.size() > 32)
+ error<StringTooLong>();
+ h256 valHash;
+ memcpy(valHash.data(), s.data(), s.size());
+ memset(valHash.data() + s.size(), 0, 32 - s.size());
+ appendPush(valHash);
+ break;
+ }
+ case sp::utree_type::symbol_type:
+ {
+ auto sr = _t.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>();
+ string s(sr.begin(), sr.end());
+ string us = boost::algorithm::to_upper_copy(s);
+ if (_allowASM)
+ {
+ if (c_instructions.count(us))
+ {
+ auto it = c_instructions.find(us);
+ m_deposit = c_instructionInfo.at(it->second).ret - c_instructionInfo.at(it->second).args;
+ m_code.push_back((byte)it->second);
+ }
+ }
+ if (_s.defs.count(s))
+ appendFragment(_s.defs.at(s));
+ else if (_s.args.count(s))
+ appendFragment(_s.args.at(s));
+ else if (_s.outers.count(s))
+ appendFragment(_s.outers.at(s));
+ else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos)
+ {
+ auto it = _s.vars.find(s);
+ if (it == _s.vars.end())
+ {
+ bool ok;
+ tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32));
+ }
+ appendPush(it->second);
+ }
+ else
+ error<BareSymbol>();
+
+ break;
+ }
+ case sp::utree_type::any_type:
+ {
+ bigint i = *_t.get<bigint*>();
+ if (i < 0 || i > bigint(u256(0) - 1))
+ error<IntegerOutOfRange>();
+ appendPush((u256)i);
+ break;
+ }
+ default: break;
+ }
+}
+
+void CodeFragment::appendPushDataLocation(bytes const& _data)
+{
+ m_code.push_back((byte)Instruction::PUSH4);
+ m_data.insert(make_pair(_data, m_code.size()));
+ m_code.resize(m_code.size() + 4);
+ memset(&m_code.back() - 3, 0, 4);
+ m_deposit++;
+}
+
+std::string CodeFragment::asPushedString() const
+{
+ string ret;
+ if (m_code.size())
+ {
+ 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]);
+ return ret;
+ }
+ }
+ error<ExpectedLiteral>();
+ return ret;
+}
+
+void CodeFragment::optimise()
+{
+// map<string, function<bytes(vector<u256> const&)>> pattern = { { "PUSH,PUSH,ADD", [](vector<u256> const& v) { return CodeFragment(appendPush(v[0] + v[1])); } } };
+}
+
+void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
+{
+ if (_t.empty())
+ error<EmptyList>();
+ else if (_t.tag() == 0 && _t.front().which() != sp::utree_type::symbol_type)
+ error<DataNotExecutable>();
+ else
+ {
+ string s;
+ string us;
+ switch (_t.tag())
+ {
+ case 0:
+ {
+ auto sr = _t.front().get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>();
+ s = string(sr.begin(), sr.end());
+ us = boost::algorithm::to_upper_copy(s);
+ break;
+ }
+ case 1:
+ us = "MLOAD";
+ break;
+ case 2:
+ us = "SLOAD";
+ break;
+ case 3:
+ us = "MSTORE";
+ break;
+ case 4:
+ us = "SSTORE";
+ break;
+ case 5:
+ us = "SEQ";
+ break;
+ default:;
+ }
+
+ // Operations who args are not standard stack-pushers.
+ bool nonStandard = true;
+ if (us == "ASM")
+ {
+ int c = 0;
+ for (auto const& i: _t)
+ if (c++)
+ appendFragment(CodeFragment(i, _s, true));
+ }
+ else if (us == "INCLUDE")
+ {
+ if (_t.size() != 2)
+ error<IncorrectParameterCount>();
+ string n;
+ auto i = *++_t.begin();
+ if (i.tag())
+ error<InvalidName>();
+ if (i.which() == sp::utree_type::string_type)
+ {
+ auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>();
+ n = string(sr.begin(), sr.end());
+ }
+ else if (i.which() == sp::utree_type::symbol_type)
+ {
+ auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>();
+ n = _s.getDef(string(sr.begin(), sr.end())).asPushedString();
+ }
+ appendFragment(CodeFragment::compile(asString(contents(n)), _s));
+ }
+ else if (us == "DEF")
+ {
+ string n;
+ unsigned ii = 0;
+ if (_t.size() != 3 && _t.size() != 4)
+ error<IncorrectParameterCount>();
+ for (auto const& i: _t)
+ {
+ if (ii == 1)
+ {
+ if (i.tag())
+ error<InvalidName>();
+ if (i.which() == sp::utree_type::string_type)
+ {
+ auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>();
+ n = string(sr.begin(), sr.end());
+ }
+ else if (i.which() == sp::utree_type::symbol_type)
+ {
+ auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>();
+ n = _s.getDef(string(sr.begin(), sr.end())).asPushedString();
+ }
+ }
+ else if (ii == 2)
+ if (_t.size() == 3)
+ _s.defs[n] = CodeFragment(i, _s);
+ else
+ for (auto const& j: i)
+ {
+ if (j.tag() || j.which() != sp::utree_type::symbol_type)
+ error<InvalidMacroArgs>();
+ auto sr = j.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>();
+ _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.outers;
+ for (auto const& i: _s.args)
+ _s.macros[n].env[i.first] = i.second;
+ for (auto const& i: _s.defs)
+ _s.macros[n].env[i.first] = i.second;
+ }
+ ++ii;
+ }
+
+ }
+ else if (us == "LIT")
+ {
+ if (_t.size() < 3)
+ error<IncorrectParameterCount>();
+ unsigned ii = 0;
+ CodeFragment pos;
+ bytes data;
+ for (auto const& i: _t)
+ {
+ if (ii == 1)
+ {
+ pos = CodeFragment(i, _s);
+ if (pos.m_deposit != 1)
+ error<InvalidDeposit>();
+ }
+ else if (ii == 2 && !i.tag() && i.which() == sp::utree_type::string_type)
+ {
+ auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>();
+ data = bytes((byte const*)sr.begin(), (byte const*)sr.end());
+ }
+ else if (ii >= 2 && !i.tag() && i.which() == sp::utree_type::any_type)
+ {
+ bigint bi = *i.get<bigint*>();
+ if (bi < 0)
+ error<IntegerOutOfRange>();
+ else if (bi > bigint(u256(0) - 1))
+ {
+ if (ii == 2 && _t.size() == 3)
+ {
+ // One big int - allow it as hex.
+ data.resize(bytesRequired(bi));
+ toBigEndian(bi, data);
+ }
+ else
+ error<IntegerOutOfRange>();
+ }
+ else
+ {
+ data.resize(data.size() + 32);
+ *(h256*)(&data.back() - 31) = (u256)bi;
+ }
+ }
+ else if (ii)
+ error<InvalidLiteral>();
+ ++ii;
+ }
+ appendPush(data.size());
+ appendInstruction(Instruction::DUP);
+ appendPushDataLocation(data);
+ appendFragment(pos, 1);
+ appendInstruction(Instruction::CODECOPY);
+ }
+ else
+ nonStandard = false;
+
+ if (nonStandard)
+ return;
+
+ std::map<std::string, Instruction> const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD }, { "&", Instruction::AND }, { "|", Instruction::OR }, { "^", Instruction::XOR } };
+ std::map<std::string, pair<Instruction, bool>> const c_binary = { { "<", { Instruction::LT, false } }, { "<=", { Instruction::GT, true } }, { ">", { Instruction::GT, false } }, { ">=", { Instruction::LT, true } }, { "S<", { Instruction::SLT, false } }, { "S<=", { Instruction::SGT, true } }, { "S>", { Instruction::SGT, false } }, { "S>=", { Instruction::SLT, true } }, { "=", { Instruction::EQ, false } }, { "!=", { Instruction::EQ, true } } };
+ std::map<std::string, Instruction> const c_unary = { { "!", Instruction::NOT } };
+
+ vector<CodeFragment> code;
+ CompilerState ns = _s;
+ ns.vars.clear();
+ int c = _t.tag() ? 1 : 0;
+ for (auto const& i: _t)
+ if (c++)
+ {
+ if (us == "LLL" && c == 1)
+ code.push_back(CodeFragment(i, ns));
+ else
+ code.push_back(CodeFragment(i, _s));
+ }
+ auto requireSize = [&](unsigned s) { if (code.size() != s) error<IncorrectParameterCount>(); };
+ auto requireMinSize = [&](unsigned s) { if (code.size() < s) error<IncorrectParameterCount>(); };
+ auto requireMaxSize = [&](unsigned s) { if (code.size() > s) error<IncorrectParameterCount>(); };
+ auto requireDeposit = [&](unsigned i, int s) { if (code[i].m_deposit != s) error<InvalidDeposit>(); };
+
+ if (_s.macros.count(s) && _s.macros.at(s).args.size() == code.size())
+ {
+ Macro const& m = _s.macros.at(s);
+ CompilerState cs = _s;
+ for (auto const& i: m.env)
+ cs.outers[i.first] = i.second;
+ for (auto const& i: cs.defs)
+ cs.outers[i.first] = i.second;
+ cs.defs.clear();
+ for (unsigned i = 0; i < m.args.size(); ++i)
+ {
+ requireDeposit(i, 1);
+ cs.args[m.args[i]] = code[i];
+ }
+ appendFragment(CodeFragment(m.code, cs));
+ for (auto const& i: cs.defs)
+ _s.defs[i.first] = i.second;
+ for (auto const& 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;
+ if (ea >= 0)
+ requireSize(ea);
+ else
+ requireMinSize(-ea);
+
+ for (unsigned i = code.size(); i; --i)
+ appendFragment(code[i - 1], 1);
+ appendInstruction(it->second);
+ }
+ else if (c_arith.count(us))
+ {
+ auto it = c_arith.find(us);
+ requireMinSize(1);
+ for (unsigned i = code.size(); i; --i)
+ {
+ requireDeposit(i - 1, 1);
+ appendFragment(code[i - 1], 1);
+ }
+ for (unsigned i = 1; i < code.size(); ++i)
+ appendInstruction(it->second);
+ }
+ else if (c_binary.count(us))
+ {
+ auto it = c_binary.find(us);
+ requireSize(2);
+ requireDeposit(0, 1);
+ requireDeposit(1, 1);
+ appendFragment(code[1], 1);
+ appendFragment(code[0], 1);
+ appendInstruction(it->second.first);
+ if (it->second.second)
+ appendInstruction(Instruction::NOT);
+ }
+ else if (c_unary.count(us))
+ {
+ auto it = c_unary.find(us);
+ requireSize(1);
+ requireDeposit(0, 1);
+ appendFragment(code[0], 1);
+ appendInstruction(it->second);
+ }
+ else if (us == "IF")
+ {
+ requireSize(3);
+ requireDeposit(0, 1);
+ appendFragment(code[0]);
+ auto pos = appendJumpI();
+ onePath();
+ appendFragment(code[2]);
+ auto end = appendJump();
+ otherPath();
+ pos.anchor();
+ appendFragment(code[1]);
+ donePaths();
+ end.anchor();
+ }
+ else if (us == "WHEN" || us == "UNLESS")
+ {
+ requireSize(2);
+ requireDeposit(0, 1);
+ appendFragment(code[0]);
+ if (us == "WHEN")
+ appendInstruction(Instruction::NOT);
+ auto end = appendJumpI();
+ onePath();
+ otherPath();
+ appendFragment(code[1], 0);
+ donePaths();
+ end.anchor();
+ }
+ else if (us == "WHILE")
+ {
+ requireSize(2);
+ requireDeposit(0, 1);
+ auto begin = CodeLocation(this);
+ appendFragment(code[0], 1);
+ appendInstruction(Instruction::NOT);
+ auto end = appendJumpI();
+ appendFragment(code[1], 0);
+ appendJump(begin);
+ end.anchor();
+ }
+ else if (us == "FOR")
+ {
+ requireSize(4);
+ requireDeposit(1, 1);
+ appendFragment(code[0], 0);
+ auto begin = CodeLocation(this);
+ appendFragment(code[1], 1);
+ appendInstruction(Instruction::NOT);
+ auto end = appendJumpI();
+ appendFragment(code[3], 0);
+ appendFragment(code[2], 0);
+ appendJump(begin);
+ end.anchor();
+ }
+ else if (us == "LLL")
+ {
+ requireMinSize(2);
+ requireMaxSize(3);
+ requireDeposit(1, 1);
+
+ CodeLocation codeloc(this, m_code.size() + 6);
+ bytes const& subcode = code[0].code();
+ appendPush(subcode.size());
+ appendInstruction(Instruction::DUP);
+ if (code.size() == 3)
+ {
+ requireDeposit(2, 1);
+ appendFragment(code[2], 1);
+ appendInstruction(Instruction::LT);
+ appendInstruction(Instruction::NOT);
+ appendInstruction(Instruction::MUL);
+ appendInstruction(Instruction::DUP);
+ }
+ appendPushDataLocation(subcode);
+ appendFragment(code[1], 1);
+ appendInstruction(Instruction::CODECOPY);
+ }
+ else if (us == "&&" || us == "||")
+ {
+ requireMinSize(1);
+ for (unsigned i = 0; i < code.size(); ++i)
+ requireDeposit(i, 1);
+
+ vector<CodeLocation> ends;
+ if (code.size() > 1)
+ {
+ appendPush(us == "||" ? 1 : 0);
+ for (unsigned i = 1; i < code.size(); ++i)
+ {
+ // Check if true - predicate
+ appendFragment(code[i - 1], 1);
+ if (us == "&&")
+ appendInstruction(Instruction::NOT);
+ ends.push_back(appendJumpI());
+ }
+ appendInstruction(Instruction::POP);
+ }
+
+ // Check if true - predicate
+ appendFragment(code.back(), 1);
+
+ // At end now.
+ for (auto& i: ends)
+ i.anchor();
+ }
+ else if (us == "~")
+ {
+ requireSize(1);
+ requireDeposit(0, 1);
+ appendFragment(code[0], 1);
+ appendPush(1);
+ appendPush(0);
+ appendInstruction(Instruction::SUB);
+ appendInstruction(Instruction::SUB);
+ }
+ else if (us == "SEQ")
+ {
+ unsigned ii = 0;
+ for (auto const& i: code)
+ if (++ii < code.size())
+ appendFragment(i, 0);
+ else
+ appendFragment(i);
+ }
+ else if (us == "RAW")
+ {
+ for (auto const& i: code)
+ appendFragment(i);
+ while (m_deposit > 1)
+ appendInstruction(Instruction::POP);
+ }
+ else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos)
+ {
+ auto it = _s.vars.find(s);
+ if (it == _s.vars.end())
+ {
+ bool ok;
+ tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32));
+ }
+ appendPush(it->second);
+ }
+ else
+ error<InvalidOperation>();
+ }
+}
diff --git a/CodeFragment.h b/CodeFragment.h
new file mode 100644
index 00000000..82630dbe
--- /dev/null
+++ b/CodeFragment.h
@@ -0,0 +1,157 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file CodeFragment.h
+ * @author Gav Wood <i@gavwood.com>
+ * @date 2014
+ */
+
+#pragma once
+
+#include <libethsupport/Common.h>
+#include <libethcore/Instruction.h>
+#include "Exceptions.h"
+
+namespace boost { namespace spirit { class utree; } }
+namespace sp = boost::spirit;
+
+namespace eth
+{
+
+class CompilerState;
+class CodeFragment;
+
+void debugOutAST(std::ostream& _out, sp::utree const& _this);
+
+class CodeLocation
+{
+ friend class CodeFragment;
+
+public:
+ CodeLocation(CodeFragment* _f);
+ CodeLocation(CodeFragment* _f, unsigned _p): m_f(_f), m_pos(_p) {}
+
+ unsigned get() const;
+ void increase(unsigned _val);
+ void set(unsigned _val);
+ void set(CodeLocation _loc) { assert(_loc.m_f == m_f); set(_loc.m_pos); }
+ void anchor();
+
+ CodeLocation operator+(unsigned _i) const { return CodeLocation(m_f, m_pos + _i); }
+
+private:
+ CodeFragment* m_f;
+ unsigned m_pos;
+};
+
+class CompilerState;
+
+enum AssemblyItemType { Operation, Push, PushString, PushTag, Tag, PushData };
+
+class AssemblyItem
+{
+public:
+ AssemblyItem(u256 _push): m_type(Push), m_data(_push) {}
+ AssemblyItem(std::string const& _push): m_type(PushString), m_pushString(_push) {}
+ AssemblyItem(AssemblyItemType _type, AssemblyItem const& _tag): m_type(_type), m_data(_tag.m_data) { assert(_type == PushTag); assert(_tag.m_type == Tag); }
+ AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {}
+ AssemblyItem(AssemblyItemType _type, u256 _data): m_type(_type), m_data(_data) {}
+
+ AssemblyItemType type() const { return m_type; }
+ u256 data() const { return m_data; }
+ std::string const& pushString() const { return m_pushString; }
+
+private:
+ AssemblyItemType m_type;
+ u256 m_data;
+ std::string m_pushString;
+};
+
+class Assembly
+{
+public:
+ AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); }
+ AssemblyItem newData(bytes const& _data) { auto h = sha3(_data); m_data[h] = _data; return AssemblyItem(PushData, h); }
+ bytes assemble() const;
+ void append(Assembly const& _a);
+
+private:
+ u256 m_usedTags = 0;
+ std::vector<AssemblyItem> m_items;
+ std::map<h256, bytes> m_data;
+};
+
+class CodeFragment
+{
+ friend class CodeLocation;
+
+public:
+ CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM = false);
+ CodeFragment(bytes const& _c = bytes()): m_code(_c) {}
+
+ static CodeFragment compile(std::string const& _src, CompilerState& _s);
+
+ /// Consolidates data and returns code.
+ bytes const& code() { optimise(); consolidateData(); return m_code; }
+
+ unsigned appendPush(u256 _l);
+ void appendFragment(CodeFragment const& _f);
+ void appendFragment(CodeFragment const& _f, unsigned _i);
+ void appendInstruction(Instruction _i);
+
+ CodeLocation appendPushLocation(unsigned _l = 0);
+ void appendPushLocation(CodeLocation _l) { assert(_l.m_f == this); appendPushLocation(_l.m_pos); }
+ void appendPushDataLocation(bytes const& _data);
+
+ CodeLocation appendJump() { auto ret = appendPushLocation(0); appendInstruction(Instruction::JUMP); return ret; }
+ CodeLocation appendJumpI() { auto ret = appendPushLocation(0); appendInstruction(Instruction::JUMPI); return ret; }
+ 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; }
+
+ void appendFile(std::string const& _fn);
+
+ 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();
+ void optimise();
+
+private:
+ template <class T> 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<InvalidDeposit>(); }
+
+ int m_deposit = 0;
+ int m_baseDeposit = 0;
+ int m_totalDeposit = 0;
+ bytes m_code;
+ std::vector<unsigned> m_locs;
+ std::multimap<bytes, unsigned> m_data;
+};
+
+static const CodeFragment NullCodeFragment;
+
+}
diff --git a/Compiler.cpp b/Compiler.cpp
new file mode 100644
index 00000000..afe84eb4
--- /dev/null
+++ b/Compiler.cpp
@@ -0,0 +1,61 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file Compiler.cpp
+ * @author Gav Wood <i@gavwood.com>
+ * @date 2014
+ */
+
+#include "Compiler.h"
+#include "Parser.h"
+#include "CompilerState.h"
+#include "CodeFragment.h"
+
+using namespace std;
+using namespace eth;
+
+bytes eth::compileLLL(string const& _s, vector<string>* _errors)
+{
+ try
+ {
+ CompilerState cs;
+ bytes ret = CodeFragment::compile(_s, cs).code();
+ for (auto i: cs.treesToKill)
+ killBigints(i);
+ return ret;
+ }
+ catch (Exception const& _e)
+ {
+ if (_errors)
+ _errors->push_back(_e.description());
+ }
+ catch (std::exception)
+ {
+ if (_errors)
+ _errors->push_back("Parse error.");
+ }
+ return bytes();
+}
+
+string eth::parseLLL(string const& _src)
+{
+ sp::utree o;
+ parseTreeLLL(_src, o);
+ ostringstream ret;
+ debugOutAST(ret, o);
+ killBigints(o);
+ return ret.str();
+}
diff --git a/Compiler.h b/Compiler.h
new file mode 100644
index 00000000..e58e12ba
--- /dev/null
+++ b/Compiler.h
@@ -0,0 +1,35 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file Compiler.h
+ * @author Gav Wood <i@gavwood.com>
+ * @date 2014
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <libethsupport/Common.h>
+
+namespace eth
+{
+
+std::string parseLLL(std::string const& _src);
+bytes compileLLL(std::string const& _s, std::vector<std::string>* _errors = nullptr);
+
+}
+
diff --git a/CompilerState.cpp b/CompilerState.cpp
new file mode 100644
index 00000000..d2894475
--- /dev/null
+++ b/CompilerState.cpp
@@ -0,0 +1,37 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file CompilerState.cpp
+ * @author Gav Wood <i@gavwood.com>
+ * @date 2014
+ */
+
+#include "CompilerState.h"
+
+using namespace std;
+using namespace eth;
+
+CodeFragment const& CompilerState::getDef(std::string const& _s)
+{
+ if (defs.count(_s))
+ return defs.at(_s);
+ else if (args.count(_s))
+ return args.at(_s);
+ else if (outers.count(_s))
+ return outers.at(_s);
+ else
+ return NullCodeFragment;
+}
diff --git a/CompilerState.h b/CompilerState.h
new file mode 100644
index 00000000..d53c2bcd
--- /dev/null
+++ b/CompilerState.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file CompilerState.h
+ * @author Gav Wood <i@gavwood.com>
+ * @date 2014
+ */
+
+#pragma once
+
+#include <boost/spirit/include/support_utree.hpp>
+#include "CodeFragment.h"
+
+namespace eth
+{
+
+struct Macro
+{
+ std::vector<std::string> args;
+ boost::spirit::utree code;
+ std::map<std::string, CodeFragment> env;
+};
+
+struct CompilerState
+{
+ CodeFragment const& getDef(std::string const& _s);
+
+ std::map<std::string, unsigned> vars;
+ std::map<std::string, CodeFragment> defs;
+ std::map<std::string, CodeFragment> args;
+ std::map<std::string, CodeFragment> outers;
+ std::map<std::string, Macro> macros;
+ std::vector<boost::spirit::utree> treesToKill;
+};
+
+}
diff --git a/Parser.cpp b/Parser.cpp
new file mode 100644
index 00000000..2a0146a6
--- /dev/null
+++ b/Parser.cpp
@@ -0,0 +1,91 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file Parser.cpp
+ * @author Gav Wood <i@gavwood.com>
+ * @date 2014
+ */
+
+#include "Parser.h"
+
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/phoenix.hpp>
+#include <boost/spirit/include/support_utree.hpp>
+#include <libethcore/CommonEth.h>
+
+using namespace std;
+using namespace eth;
+namespace qi = boost::spirit::qi;
+namespace px = boost::phoenix;
+namespace sp = boost::spirit;
+
+void eth::killBigints(sp::utree const& _this)
+{
+ switch (_this.which())
+ {
+ case sp::utree_type::list_type: for (auto const& i: _this) killBigints(i); break;
+ case sp::utree_type::any_type: delete _this.get<bigint*>(); break;
+ default:;
+ }
+}
+
+void eth::parseTreeLLL(string const& _s, sp::utree& o_out)
+{
+ using qi::ascii::space;
+ typedef sp::basic_string<std::string, sp::utree_type::symbol_type> symbol_type;
+ typedef string::const_iterator it;
+
+ qi::rule<it, qi::ascii::space_type, sp::utree()> element;
+ qi::rule<it, string()> str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"';
+ qi::rule<it, string()> strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;())") + '\0'))];
+ qi::rule<it, symbol_type()> symbol = qi::lexeme[+(~qi::char_(std::string(" @[]{}:();\"\x01-\x1f\x7f") + '\0'))];
+ qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]];
+ qi::rule<it, bigint()> integer = intstr;
+ qi::rule<it, bigint()> multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether];
+ qi::rule<it, qi::ascii::space_type, bigint()> quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1];
+ qi::rule<it, qi::ascii::space_type, sp::utree()> atom = quantity[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
+ qi::rule<it, qi::ascii::space_type, sp::utree::list_type()> seq = '{' > *element > '}';
+ qi::rule<it, qi::ascii::space_type, sp::utree::list_type()> mload = '@' > element;
+ qi::rule<it, qi::ascii::space_type, sp::utree::list_type()> sload = qi::lit("@@") > element;
+ qi::rule<it, qi::ascii::space_type, sp::utree::list_type()> mstore = '[' > element > ']' > -qi::lit(":") > element;
+ qi::rule<it, qi::ascii::space_type, sp::utree::list_type()> sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element;
+ qi::rule<it, qi::ascii::space_type, sp::utree()> extra = sload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 2)] | mload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 1)] | sstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 4)] | mstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 3)] | seq[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 5)];
+ qi::rule<it, qi::ascii::space_type, sp::utree::list_type()> list = '(' > *element > ')';
+ element = atom | list | extra;
+
+ string s;
+ s.reserve(_s.size());
+ bool incomment = false;
+ bool instring = false;
+ bool insstring = false;
+ for (auto i: _s)
+ {
+ if (i == ';' && !instring && !insstring)
+ incomment = true;
+ else if (i == '\n')
+ 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);
+ }
+ qi::phrase_parse(s.cbegin(), s.cend(), element, space, o_out);
+}
+
diff --git a/Parser.h b/Parser.h
new file mode 100644
index 00000000..3b275657
--- /dev/null
+++ b/Parser.h
@@ -0,0 +1,38 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file Parser.h
+ * @author Gav Wood <i@gavwood.com>
+ * @date 2014
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <libethsupport/Common.h>
+
+namespace boost { namespace spirit { class utree; } }
+namespace sp = boost::spirit;
+
+namespace eth
+{
+
+void killBigints(sp::utree const& _this);
+void parseTreeLLL(std::string const& _s, sp::utree& o_out);
+
+}
+