github.com/phillinzzz/newBsc@v1.1.6/core/asm/lexer.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package asm
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"strings"
    23  	"unicode"
    24  	"unicode/utf8"
    25  
    26  	"github.com/phillinzzz/newBsc/common/gopool"
    27  )
    28  
    29  // stateFn is used through the lifetime of the
    30  // lexer to parse the different values at the
    31  // current state.
    32  type stateFn func(*lexer) stateFn
    33  
    34  // token is emitted when the lexer has discovered
    35  // a new parsable token. These are delivered over
    36  // the tokens channels of the lexer
    37  type token struct {
    38  	typ    tokenType
    39  	lineno int
    40  	text   string
    41  }
    42  
    43  // tokenType are the different types the lexer
    44  // is able to parse and return.
    45  type tokenType int
    46  
    47  const (
    48  	eof              tokenType = iota // end of file
    49  	lineStart                         // emitted when a line starts
    50  	lineEnd                           // emitted when a line ends
    51  	invalidStatement                  // any invalid statement
    52  	element                           // any element during element parsing
    53  	label                             // label is emitted when a label is found
    54  	labelDef                          // label definition is emitted when a new label is found
    55  	number                            // number is emitted when a number is found
    56  	stringValue                       // stringValue is emitted when a string has been found
    57  
    58  	Numbers            = "1234567890"                                           // characters representing any decimal number
    59  	HexadecimalNumbers = Numbers + "aAbBcCdDeEfF"                               // characters representing any hexadecimal
    60  	Alpha              = "abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ" // characters representing alphanumeric
    61  )
    62  
    63  // String implements stringer
    64  func (it tokenType) String() string {
    65  	if int(it) > len(stringtokenTypes) {
    66  		return "invalid"
    67  	}
    68  	return stringtokenTypes[it]
    69  }
    70  
    71  var stringtokenTypes = []string{
    72  	eof:              "EOF",
    73  	invalidStatement: "invalid statement",
    74  	element:          "element",
    75  	lineEnd:          "end of line",
    76  	lineStart:        "new line",
    77  	label:            "label",
    78  	labelDef:         "label definition",
    79  	number:           "number",
    80  	stringValue:      "string",
    81  }
    82  
    83  // lexer is the basic construct for parsing
    84  // source code and turning them in to tokens.
    85  // Tokens are interpreted by the compiler.
    86  type lexer struct {
    87  	input string // input contains the source code of the program
    88  
    89  	tokens chan token // tokens is used to deliver tokens to the listener
    90  	state  stateFn    // the current state function
    91  
    92  	lineno            int // current line number in the source file
    93  	start, pos, width int // positions for lexing and returning value
    94  
    95  	debug bool // flag for triggering debug output
    96  }
    97  
    98  // lex lexes the program by name with the given source. It returns a
    99  // channel on which the tokens are delivered.
   100  func Lex(source []byte, debug bool) <-chan token {
   101  	ch := make(chan token)
   102  	l := &lexer{
   103  		input:  string(source),
   104  		tokens: ch,
   105  		state:  lexLine,
   106  		debug:  debug,
   107  	}
   108  	gopool.Submit(func() {
   109  		l.emit(lineStart)
   110  		for l.state != nil {
   111  			l.state = l.state(l)
   112  		}
   113  		l.emit(eof)
   114  		close(l.tokens)
   115  	})
   116  
   117  	return ch
   118  }
   119  
   120  // next returns the next rune in the program's source.
   121  func (l *lexer) next() (rune rune) {
   122  	if l.pos >= len(l.input) {
   123  		l.width = 0
   124  		return 0
   125  	}
   126  	rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
   127  	l.pos += l.width
   128  	return rune
   129  }
   130  
   131  // backup backsup the last parsed element (multi-character)
   132  func (l *lexer) backup() {
   133  	l.pos -= l.width
   134  }
   135  
   136  // peek returns the next rune but does not advance the seeker
   137  func (l *lexer) peek() rune {
   138  	r := l.next()
   139  	l.backup()
   140  	return r
   141  }
   142  
   143  // ignore advances the seeker and ignores the value
   144  func (l *lexer) ignore() {
   145  	l.start = l.pos
   146  }
   147  
   148  // Accepts checks whether the given input matches the next rune
   149  func (l *lexer) accept(valid string) bool {
   150  	if strings.ContainsRune(valid, l.next()) {
   151  		return true
   152  	}
   153  
   154  	l.backup()
   155  
   156  	return false
   157  }
   158  
   159  // acceptRun will continue to advance the seeker until valid
   160  // can no longer be met.
   161  func (l *lexer) acceptRun(valid string) {
   162  	for strings.ContainsRune(valid, l.next()) {
   163  	}
   164  	l.backup()
   165  }
   166  
   167  // acceptRunUntil is the inverse of acceptRun and will continue
   168  // to advance the seeker until the rune has been found.
   169  func (l *lexer) acceptRunUntil(until rune) bool {
   170  	// Continues running until a rune is found
   171  	for i := l.next(); !strings.ContainsRune(string(until), i); i = l.next() {
   172  		if i == 0 {
   173  			return false
   174  		}
   175  	}
   176  
   177  	return true
   178  }
   179  
   180  // blob returns the current value
   181  func (l *lexer) blob() string {
   182  	return l.input[l.start:l.pos]
   183  }
   184  
   185  // Emits a new token on to token channel for processing
   186  func (l *lexer) emit(t tokenType) {
   187  	token := token{t, l.lineno, l.blob()}
   188  
   189  	if l.debug {
   190  		fmt.Fprintf(os.Stderr, "%04d: (%-20v) %s\n", token.lineno, token.typ, token.text)
   191  	}
   192  
   193  	l.tokens <- token
   194  	l.start = l.pos
   195  }
   196  
   197  // lexLine is state function for lexing lines
   198  func lexLine(l *lexer) stateFn {
   199  	for {
   200  		switch r := l.next(); {
   201  		case r == '\n':
   202  			l.emit(lineEnd)
   203  			l.ignore()
   204  			l.lineno++
   205  
   206  			l.emit(lineStart)
   207  		case r == ';' && l.peek() == ';':
   208  			return lexComment
   209  		case isSpace(r):
   210  			l.ignore()
   211  		case isLetter(r) || r == '_':
   212  			return lexElement
   213  		case isNumber(r):
   214  			return lexNumber
   215  		case r == '@':
   216  			l.ignore()
   217  			return lexLabel
   218  		case r == '"':
   219  			return lexInsideString
   220  		default:
   221  			return nil
   222  		}
   223  	}
   224  }
   225  
   226  // lexComment parses the current position until the end
   227  // of the line and discards the text.
   228  func lexComment(l *lexer) stateFn {
   229  	l.acceptRunUntil('\n')
   230  	l.ignore()
   231  
   232  	return lexLine
   233  }
   234  
   235  // lexLabel parses the current label, emits and returns
   236  // the lex text state function to advance the parsing
   237  // process.
   238  func lexLabel(l *lexer) stateFn {
   239  	l.acceptRun(Alpha + "_" + Numbers)
   240  
   241  	l.emit(label)
   242  
   243  	return lexLine
   244  }
   245  
   246  // lexInsideString lexes the inside of a string until
   247  // the state function finds the closing quote.
   248  // It returns the lex text state function.
   249  func lexInsideString(l *lexer) stateFn {
   250  	if l.acceptRunUntil('"') {
   251  		l.emit(stringValue)
   252  	}
   253  
   254  	return lexLine
   255  }
   256  
   257  func lexNumber(l *lexer) stateFn {
   258  	acceptance := Numbers
   259  	if l.accept("0") || l.accept("xX") {
   260  		acceptance = HexadecimalNumbers
   261  	}
   262  	l.acceptRun(acceptance)
   263  
   264  	l.emit(number)
   265  
   266  	return lexLine
   267  }
   268  
   269  func lexElement(l *lexer) stateFn {
   270  	l.acceptRun(Alpha + "_" + Numbers)
   271  
   272  	if l.peek() == ':' {
   273  		l.emit(labelDef)
   274  
   275  		l.accept(":")
   276  		l.ignore()
   277  	} else {
   278  		l.emit(element)
   279  	}
   280  	return lexLine
   281  }
   282  
   283  func isLetter(t rune) bool {
   284  	return unicode.IsLetter(t)
   285  }
   286  
   287  func isSpace(t rune) bool {
   288  	return unicode.IsSpace(t)
   289  }
   290  
   291  func isNumber(t rune) bool {
   292  	return unicode.IsNumber(t)
   293  }