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 }