Draft_1 for compile assembly to a machine code
This commit is contained in:
parent
dbbfe450e5
commit
e5f4515cb1
|
@ -31,7 +31,7 @@ public class ToolBar extends JFrame {
|
|||
public ToolBar() throws HeadlessException {
|
||||
|
||||
introLogger.info("");
|
||||
introLogger.info("♢ EthereumJ [v0.5.1] ");
|
||||
introLogger.info("♢ EthereumJ [v0.5.1] by RomanJ");
|
||||
introLogger.info("♢ Code by Roman Mandeleil, (c) 2014.");
|
||||
introLogger.info("♢ Contribution: Nick Savers ");
|
||||
introLogger.info("♢ Based on a design by Vitalik Buterin.");
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
package org.ethereum.serpent;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.ethereum.util.ByteUtil;
|
||||
import org.ethereum.vm.OpCode;
|
||||
import org.spongycastle.util.BigIntegers;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
|
@ -20,4 +29,93 @@ public class SerpentCompiler {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static String compileAssemblyToMachine(String code){
|
||||
|
||||
StringBuffer assemblyCode = new StringBuffer();
|
||||
String[] lexaArr = code.split("\\s+");
|
||||
|
||||
List<String> lexaList = new ArrayList<String>();
|
||||
Collections.addAll(lexaList, lexaArr);
|
||||
|
||||
// Encode push_n numbers
|
||||
for (int i = 0; i < lexaList.size(); ++i){
|
||||
|
||||
String lexa = lexaList.get(i);
|
||||
|
||||
if (OpCode.contains(lexa) ||
|
||||
lexa.contains("REF_") ||
|
||||
lexa.contains("LABEL_")) continue;
|
||||
|
||||
int bytesNum = ByteUtil.numBytes( lexa );
|
||||
|
||||
String num = lexaList.remove(i);
|
||||
BigInteger bNum = new BigInteger(num);
|
||||
byte[] bytes = BigIntegers.asUnsignedByteArray(bNum);
|
||||
if (bytes.length == 0)bytes = new byte[]{0};
|
||||
|
||||
for (int j = bytes.length; j > 0 ; --j){
|
||||
|
||||
lexaList.add(i, (bytes[j-1] & 0xFF) +"");
|
||||
}
|
||||
|
||||
lexaList.add(i, "PUSH" + bytesNum);
|
||||
i = i + bytesNum;
|
||||
|
||||
}
|
||||
|
||||
// calc label pos & remove labels
|
||||
HashMap<String, Integer> labels = new HashMap<String, Integer>();
|
||||
for (int i = 0; i < lexaList.size(); ++i){
|
||||
|
||||
String lexa = lexaList.get(i);
|
||||
if (!lexa.contains("LABEL_")) continue;
|
||||
|
||||
String label = lexaList.remove(i);
|
||||
String labelNum = label.split("LABEL_")[1];
|
||||
|
||||
labels.put(labelNum, i);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
// encode all ref occurrence
|
||||
for (int i = 0; i < lexaList.size(); ++i){
|
||||
|
||||
String lexa = lexaList.get(i);
|
||||
if (!lexa.contains("REF_")) continue;
|
||||
|
||||
String ref = lexaList.remove(i);
|
||||
String labelNum = ref.split("REF_")[1];
|
||||
|
||||
Integer pos = labels.get(labelNum);
|
||||
int bytesNum = ByteUtil.numBytes( pos.toString() );
|
||||
|
||||
lexaList.add(i, pos.toString());
|
||||
|
||||
for (int j = 0; j < (4 - bytesNum) ; ++j)
|
||||
lexaList.add(i, "0");
|
||||
|
||||
lexaList.add(i, "PUSH4");
|
||||
++i;
|
||||
}
|
||||
|
||||
for (String lexa : lexaList){
|
||||
|
||||
if (OpCode.contains(lexa))
|
||||
assemblyCode.append( OpCode.byteVal(lexa) );
|
||||
else{
|
||||
|
||||
assemblyCode.append( lexa );
|
||||
}
|
||||
assemblyCode.append(" ");
|
||||
}
|
||||
|
||||
return assemblyCode.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -170,6 +170,8 @@ public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
|
|||
@Override
|
||||
public String visitInt_val(@NotNull SerpentParser.Int_valContext ctx) {
|
||||
|
||||
// todo: (!!!) ensure that not encode value more than 32 bytes (!!!)
|
||||
|
||||
if (ctx.OP_NOT() != null)
|
||||
return visitExpression(ctx.expression()) + " NOT";
|
||||
|
||||
|
|
|
@ -82,4 +82,28 @@ public class ByteUtil {
|
|||
return 0;
|
||||
return new BigInteger(1, b).intValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the number of bytes need
|
||||
* to encode the number
|
||||
*
|
||||
* @param val - number
|
||||
* @return number of min bytes used to encode the number
|
||||
*/
|
||||
public static int numBytes(String val){
|
||||
|
||||
BigInteger bInt = new BigInteger(val);
|
||||
int bytes = 0;
|
||||
|
||||
while(!bInt.equals(BigInteger.ZERO)){
|
||||
|
||||
bInt = bInt.shiftRight(8);
|
||||
++bytes;
|
||||
}
|
||||
|
||||
if (bytes == 0) ++bytes;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
package org.ethereum.vm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Instruction set for the Ethereum Virtual Machine
|
||||
*/
|
||||
public enum OpCode {
|
||||
|
||||
/**
|
||||
/**
|
||||
* Stop and Arithmetic Operations
|
||||
*/
|
||||
|
||||
|
@ -136,9 +135,13 @@ public enum OpCode {
|
|||
private byte opcode;
|
||||
|
||||
private static final Map<Byte, OpCode> intToTypeMap = new HashMap<Byte, OpCode>();
|
||||
private static final Map<String, Byte> stringToByteMap = new HashMap<String, Byte>();
|
||||
|
||||
|
||||
static {
|
||||
for (OpCode type : OpCode.values()) {
|
||||
intToTypeMap.put(type.opcode, type);
|
||||
stringToByteMap.put(type.name(), type.opcode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,4 +159,13 @@ public enum OpCode {
|
|||
public int asInt() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
public static boolean contains(String code){
|
||||
|
||||
return stringToByteMap.containsKey(code.trim());
|
||||
}
|
||||
|
||||
public static byte byteVal(String code){
|
||||
return stringToByteMap.get(code);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
|
||||
#***
|
||||
# Starting to gather some properties the system going to support
|
||||
#***
|
||||
client.name=EthereumJ [v0.5.1] by RomanJ
|
||||
|
||||
# if the system will work as a server also
|
||||
# accept for incoming connections [true/false]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.ethereum.serpent;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.ethereum.util.ByteUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -1211,23 +1212,34 @@ public class SerpentCompileTest {
|
|||
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
/*
|
||||
*
|
||||
a = msg.datasize
|
||||
b = msg.sender
|
||||
c = msg.value
|
||||
d = tx.gasprice
|
||||
e = tx.origin
|
||||
f = tx.gas
|
||||
g = contract.balance
|
||||
h = block.prevhash
|
||||
i = block.coinbase
|
||||
j = block.timestamp
|
||||
k = block.number
|
||||
l = block.difficulty
|
||||
m = block.gaslimit
|
||||
|
||||
*/
|
||||
|
||||
@Test // compile to machine code 1
|
||||
public void test42(){
|
||||
|
||||
String code = "x = 256 \n" +
|
||||
"while x > 1: \n" +
|
||||
" if (x % 2) == 0: \n" +
|
||||
" x = x / 2 \n" +
|
||||
" else: \n " +
|
||||
" x = 3 * x + 1 \n" ;
|
||||
|
||||
String expected = "97 1 0 96 0 84 96 1 96 0 83 11 12 13 99 0 0 0 53 89 96 0 96 2 96 0 83 6 12 13 99 0 0 0 39 89 96 2 96 0 83 4 96 0 84 99 0 0 0 51 88 96 1 96 0 83 96 3 2 1 96 0 84 99 0 0 0 6 88";
|
||||
|
||||
String asmResult = SerpentCompiler.compile(code);
|
||||
String machineCode = SerpentCompiler.compileAssemblyToMachine(asmResult);
|
||||
|
||||
Assert.assertEquals(expected, machineCode.trim());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test // todo delete this one
|
||||
public void testFoo(){
|
||||
|
||||
System.out.println(ByteUtil.numBytes("65536"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue