func (l *Lexer) Next() int {
	l.Prev = l.Last
	r := l.next()
	l.Last = l.lookahead
	return r
}
Next advances the scanner for one rune and returns the respective character
class of the new lookahead.  Typical usage in an .l file:

%yyn c = l.Next()
package lex
import (
	"bytes"
	"fmt"
	"go/token"
	"io"
	"os"
)
const (
	BOMError       = iota  
	BOMIgnoreFirst         
	BOMPassAll             
	BOMPassFirst           
)
const (
	NonASCII = 0x80  
	RuneEOF  = -1    
)
func DefaultRuneClass(r rune) int {
	if r >= 0 && r < 0x80 {
		return int(r)
	}
	return NonASCII
}
type Char struct {
	Rune rune
	pos  int32
}
func NewChar(pos token.Pos, r rune) Char { return Char{pos: int32(pos), Rune: r} }
func (c Char) IsValid() bool { return c.Pos().IsValid() }
func (c Char) Pos() token.Pos { return token.Pos(c.pos) }
type CharReader interface {
	ReadChar() (c Char, size int, err error)
}
type Lexer struct {
	File      *token.File              
	First     Char                     
	Last      Char                     
	Prev      Char                     
	bomMode   int                      
	bytesBuf  bytes.Buffer             
	charSrc   CharReader               
	classf    func(rune) int           
	errorf    func(token.Pos, string)  
	lookahead Char                     
	mark      int                      
	off       int                      
	src       io.RuneReader            
	tokenBuf  []Char                   
	ungetBuf  []Char                   
}
func New(file *token.File, src io.RuneReader, opts ...Option) (*Lexer, error) {
	r := &Lexer{
		File:    file,
		bomMode: BOMIgnoreFirst,
		classf:  DefaultRuneClass,
		src:     src,
	}
	if x, ok := src.(CharReader); ok {
		r.charSrc = x
	}
	r.errorf = r.defaultErrorf
	for _, o := range opts {
		if err := o(r); err != nil {
			return nil, err
		}
	}
	return r, nil
}
func (l *Lexer) Abort() (int, bool) {
	if l.mark >= 0 {
		if len(l.tokenBuf) > l.mark {
			l.Unget(l.lookahead)
			for i := len(l.tokenBuf) - 1; i >= l.mark; i-- {
				l.Unget(l.tokenBuf[i])
			}
		}
		l.tokenBuf = l.tokenBuf[:l.mark]
		return 0, false
	}
	switch n := len(l.tokenBuf); n {
	case 0:  
		c := l.lookahead
		l.Next()
		return int(c.Rune), true
	case 1:  
		return int(l.tokenBuf[0].Rune), true
	default:  
		c := l.tokenBuf[0]    
		l.Unget(l.lookahead)  
		for i := n - 1; i > 1; i-- {
			l.Unget(l.tokenBuf[i])  
		}
		l.lookahead = l.tokenBuf[1]  
		l.tokenBuf = l.tokenBuf[:1]
		return int(c.Rune), true
	}
}
func (l *Lexer) class() int { return l.classf(l.lookahead.Rune) }
func (l *Lexer) defaultErrorf(pos token.Pos, msg string) {
	l.Error(fmt.Sprintf("%v: %v", l.File.Position(pos), msg))
}
func (l *Lexer) Enter() int {
	if !l.lookahead.IsValid() {
		l.Next()
	}
	return l.class()
}
func (l *Lexer) Error(msg string) {
	fmt.Fprintf(os.Stderr, "%s\n", msg)
}
func (l *Lexer) Lookahead() Char {
	if !l.lookahead.IsValid() {
		l.Next()
	}
	return l.lookahead
}
func (l *Lexer) Mark() { l.mark = len(l.tokenBuf) }
func (l *Lexer) next() int {
	const bom = '\ufeff'
	if c := l.lookahead; c.IsValid() {
		l.tokenBuf = append(l.tokenBuf, c)
	}
	if n := len(l.ungetBuf); n != 0 {
		l.lookahead = l.ungetBuf[n-1]
		l.ungetBuf = l.ungetBuf[:n-1]
		return l.class()
	}
	if l.src == nil {
		return RuneEOF
	}
	var r rune
	var sz int
	var err error
	var pos token.Pos
	var c Char
again:
	off0 := l.off
	switch cs := l.charSrc; {
	case cs != nil:
		c, sz, err = cs.ReadChar()
		r = c.Rune
		pos = c.Pos()
	default:
		r, sz, err = l.src.ReadRune()
		pos = l.File.Pos(l.off)
	}
	l.off += sz
	if err != nil {
		l.src = nil
		r = RuneEOF
		if err != io.EOF {
			l.errorf(pos, err.Error())
		}
	}
	if r == bom {
		switch l.bomMode {
		default:
			fallthrough
		case BOMIgnoreFirst:
			if off0 != 0 {
				l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
			}
			goto again
		case BOMPassAll:
		case BOMPassFirst:
			if off0 != 0 {
				l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
				goto again
			}
		case BOMError:
			switch {
			case off0 == 0:
				l.errorf(pos, "unicode (UTF-8) BOM at beginnig of file")
			default:
				l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
			}
			goto again
		}
	}
	l.lookahead = NewChar(pos, r)
	if r == '\n' {
		l.File.AddLine(l.off)
	}
	return l.class()
}