package main import ( "log" "strconv" "strings" "unicode/utf8" ) type item struct { typ int val string } type yyLex struct { input string start int pos int width int items chan item } func (y *yyLex) Error(s string) { log.Println(s) } func deneg(s string) string { return strings.Replace(s, "¯", "-", -1) } func dequote(s string) string { return strings.Replace(s, "''", "'", -1) } func (y *yyLex) Lex(lval *yySymType) int { item := <-y.items switch item.typ { case STRING: lval.sval = item.val case QUOTED: lval.sval = dequote(item.val) case INTEGER: v, err := strconv.ParseInt(deneg(item.val), 10, 64) if err != nil { y.Error(err.Error()) } lval.ival = v case FLOAT: v, err := strconv.ParseFloat(deneg(item.val), 64) if err != nil { y.Error(err.Error()) } lval.fval = v case COMPLEX: pos := strings.IndexAny(deneg(item.val), "jJ") if pos < 0 { y.Error("not a complex number") } r, err := strconv.ParseFloat(item.val[:pos], 64) if err != nil { y.Error(err.Error()) } i, err := strconv.ParseFloat(item.val[pos+1:], 64) if err != nil { y.Error(err.Error()) } lval.cval = complex(r, i) } return item.typ } func lex(input string) *yyLex { l := &yyLex{ input: input, items: make(chan item), } go l.run() return l } func (y *yyLex) run() { defer close(y.items) for { c := y.next() if t, ok := Tokens[c]; ok { switch t { case LAMP, EOF: return case BLANK: y.ignore() case QUOTE: y.lexQuoted() case DIGIT, NEG, DOT: if t == DOT && Tokens[y.peek()] != DIGIT { y.emit(t) } else { y.lexNumber() } case CHAR: y.lexString() default: y.emit(t) } } else { y.ignore() } } } func (y *yyLex) lexQuoted() { y.ignore() defer func() { y.emit(QUOTED) y.next() y.ignore() }() for { switch Tokens[y.next()] { case EOF: return case QUOTE: if !y.acceptToken(QUOTE) { y.backup() return } y.next() } } } func (y *yyLex) lexString() { defer y.emit(STRING) for { if Tokens[y.next()] != CHAR { y.backup() return } } } func (y *yyLex) lexNumber() { t := INTEGER y.backup() y.acceptToken(NEG) y.acceptDigits() if y.acceptToken(DOT) { t = FLOAT y.acceptDigits() } if y.acceptRunes('e', 'E') { t = FLOAT y.acceptToken(NEG) y.acceptDigits() } if y.acceptRunes('j', 'J') { t = COMPLEX y.acceptToken(NEG) y.acceptDigits() if y.acceptToken(DOT) { y.acceptDigits() } if y.acceptRunes('e', 'E') { y.acceptToken(NEG) y.acceptDigits() } } y.emit(t) } func (y *yyLex) acceptDigits() { for y.acceptToken(DIGIT) { } } func (y *yyLex) emit(t int) { y.items <- item{ typ: t, val: y.input[y.start:y.pos], } y.start = y.pos } func (y *yyLex) next() (r rune) { if y.pos >= len(y.input) { y.width = 0 return EOF } r, y.width = utf8.DecodeRuneInString(y.input[y.pos:]) y.pos += y.width return } func (y *yyLex) ignore() { y.start = y.pos } func (y *yyLex) backup() { y.pos -= y.width } func (y *yyLex) peek() rune { defer y.backup() return y.next() } func (y *yyLex) acceptRunes(valid ...rune) bool { for _, r := range valid { if y.next() == r { return true } y.backup() } return false } func (y *yyLex) acceptToken(valid int) bool { if t, ok := Tokens[y.next()]; ok && t == valid { return true } y.backup() return false }