github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/core/asm/compiler.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2017 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package asm
    26  
    27  import (
    28  	"fmt"
    29  	"math/big"
    30  	"os"
    31  	"strings"
    32  
    33  	"github.com/ethereum/go-ethereum/common/math"
    34  	"github.com/ethereum/go-ethereum/core/vm"
    35  )
    36  
    37  //编译器包含有关已分析源的信息
    38  //并持有程序的令牌。
    39  type Compiler struct {
    40  	tokens []token
    41  	binary []interface{}
    42  
    43  	labels map[string]int
    44  
    45  	pc, pos int
    46  
    47  	debug bool
    48  }
    49  
    50  //NewCompiler返回新分配的编译器。
    51  func NewCompiler(debug bool) *Compiler {
    52  	return &Compiler{
    53  		labels: make(map[string]int),
    54  		debug:  debug,
    55  	}
    56  }
    57  
    58  //feed将令牌馈送到ch,并由
    59  //编译器。
    60  //
    61  //feed是编译阶段的第一个步骤,因为它
    62  //收集程序中使用的标签并保留
    63  //用于确定位置的程序计数器
    64  //跳跃的目的地。标签不能用于
    65  //第二阶段推标签并确定正确的
    66  //位置。
    67  func (c *Compiler) Feed(ch <-chan token) {
    68  	for i := range ch {
    69  		switch i.typ {
    70  		case number:
    71  			num := math.MustParseBig256(i.text).Bytes()
    72  			if len(num) == 0 {
    73  				num = []byte{0}
    74  			}
    75  			c.pc += len(num)
    76  		case stringValue:
    77  			c.pc += len(i.text) - 2
    78  		case element:
    79  			c.pc++
    80  		case labelDef:
    81  			c.labels[i.text] = c.pc
    82  			c.pc++
    83  		case label:
    84  			c.pc += 5
    85  		}
    86  
    87  		c.tokens = append(c.tokens, i)
    88  	}
    89  	if c.debug {
    90  		fmt.Fprintln(os.Stderr, "found", len(c.labels), "labels")
    91  	}
    92  }
    93  
    94  //编译编译当前令牌并返回一个
    95  //可由EVM解释的二进制字符串
    96  //如果失败了就会出错。
    97  //
    98  //编译是编译阶段的第二个阶段
    99  //
   100  func (c *Compiler) Compile() (string, []error) {
   101  	var errors []error
   102  //继续循环令牌,直到
   103  //
   104  	for c.pos < len(c.tokens) {
   105  		if err := c.compileLine(); err != nil {
   106  			errors = append(errors, err)
   107  		}
   108  	}
   109  
   110  //将二进制转换为十六进制
   111  	var bin string
   112  	for _, v := range c.binary {
   113  		switch v := v.(type) {
   114  		case vm.OpCode:
   115  			bin += fmt.Sprintf("%x", []byte{byte(v)})
   116  		case []byte:
   117  			bin += fmt.Sprintf("%x", v)
   118  		}
   119  	}
   120  	return bin, errors
   121  }
   122  
   123  //next返回下一个标记并递增
   124  //位置。
   125  func (c *Compiler) next() token {
   126  	token := c.tokens[c.pos]
   127  	c.pos++
   128  	return token
   129  }
   130  
   131  //compileline编译单行指令,例如
   132  //“push 1”,“jump@label”。
   133  func (c *Compiler) compileLine() error {
   134  	n := c.next()
   135  	if n.typ != lineStart {
   136  		return compileErr(n, n.typ.String(), lineStart.String())
   137  	}
   138  
   139  	lvalue := c.next()
   140  	switch lvalue.typ {
   141  	case eof:
   142  		return nil
   143  	case element:
   144  		if err := c.compileElement(lvalue); err != nil {
   145  			return err
   146  		}
   147  	case labelDef:
   148  		c.compileLabel()
   149  	case lineEnd:
   150  		return nil
   151  	default:
   152  		return compileErr(lvalue, lvalue.text, fmt.Sprintf("%v or %v", labelDef, element))
   153  	}
   154  
   155  	if n := c.next(); n.typ != lineEnd {
   156  		return compileErr(n, n.text, lineEnd.String())
   157  	}
   158  
   159  	return nil
   160  }
   161  
   162  //compileNumber将数字编译为字节
   163  func (c *Compiler) compileNumber(element token) (int, error) {
   164  	num := math.MustParseBig256(element.text).Bytes()
   165  	if len(num) == 0 {
   166  		num = []byte{0}
   167  	}
   168  	c.pushBin(num)
   169  	return len(num), nil
   170  }
   171  
   172  //compileElement编译元素(push&label或两者兼有)
   173  //以二进制表示,如果语句不正确,则可能出错。
   174  //喂的地方。
   175  func (c *Compiler) compileElement(element token) error {
   176  //检查是否有跳跃。必须读取和编译跳转
   177  //从右到左。
   178  	if isJump(element.text) {
   179  		rvalue := c.next()
   180  		switch rvalue.typ {
   181  		case number:
   182  //TODO了解如何正确返回错误
   183  			c.compileNumber(rvalue)
   184  		case stringValue:
   185  //字符串被引用,请删除它们。
   186  			c.pushBin(rvalue.text[1 : len(rvalue.text)-2])
   187  		case label:
   188  			c.pushBin(vm.PUSH4)
   189  			pos := big.NewInt(int64(c.labels[rvalue.text])).Bytes()
   190  			pos = append(make([]byte, 4-len(pos)), pos...)
   191  			c.pushBin(pos)
   192  		default:
   193  			return compileErr(rvalue, rvalue.text, "number, string or label")
   194  		}
   195  //推动操作
   196  		c.pushBin(toBinary(element.text))
   197  		return nil
   198  	} else if isPush(element.text) {
   199  //把手推。按从左到右读取。
   200  		var value []byte
   201  
   202  		rvalue := c.next()
   203  		switch rvalue.typ {
   204  		case number:
   205  			value = math.MustParseBig256(rvalue.text).Bytes()
   206  			if len(value) == 0 {
   207  				value = []byte{0}
   208  			}
   209  		case stringValue:
   210  			value = []byte(rvalue.text[1 : len(rvalue.text)-1])
   211  		case label:
   212  			value = make([]byte, 4)
   213  			copy(value, big.NewInt(int64(c.labels[rvalue.text])).Bytes())
   214  		default:
   215  			return compileErr(rvalue, rvalue.text, "number, string or label")
   216  		}
   217  
   218  		if len(value) > 32 {
   219  			return fmt.Errorf("%d type error: unsupported string or number with size > 32", rvalue.lineno)
   220  		}
   221  
   222  		c.pushBin(vm.OpCode(int(vm.PUSH1) - 1 + len(value)))
   223  		c.pushBin(value)
   224  	} else {
   225  		c.pushBin(toBinary(element.text))
   226  	}
   227  
   228  	return nil
   229  }
   230  
   231  //compileLabel将JumpDest推送到二进制切片。
   232  func (c *Compiler) compileLabel() {
   233  	c.pushBin(vm.JUMPDEST)
   234  }
   235  
   236  //推杆将值V推送到二进制堆栈。
   237  func (c *Compiler) pushBin(v interface{}) {
   238  	if c.debug {
   239  		fmt.Printf("%d: %v\n", len(c.binary), v)
   240  	}
   241  	c.binary = append(c.binary, v)
   242  }
   243  
   244  //
   245  //推(n)。
   246  func isPush(op string) bool {
   247  	return strings.ToUpper(op) == "PUSH"
   248  }
   249  
   250  //is jump返回字符串op是否为jump(i)
   251  func isJump(op string) bool {
   252  	return strings.ToUpper(op) == "JUMPI" || strings.ToUpper(op) == "JUMP"
   253  }
   254  
   255  //ToBinary将文本转换为vm.opcode
   256  func toBinary(text string) vm.OpCode {
   257  	return vm.StringToOp(strings.ToUpper(text))
   258  }
   259  
   260  type compileError struct {
   261  	got  string
   262  	want string
   263  
   264  	lineno int
   265  }
   266  
   267  func (err compileError) Error() string {
   268  	return fmt.Sprintf("%d syntax error: unexpected %v, expected %v", err.lineno, err.got, err.want)
   269  }
   270  
   271  func compileErr(c token, got, want string) error {
   272  	return compileError{
   273  		got:    got,
   274  		want:   want,
   275  		lineno: c.lineno,
   276  	}
   277  }