// Package lexmachine is a full lexical analysis framework for the Go // programming language. It supports a restricted but usable set of regular // expressions appropriate for writing lexers for complex programming // languages. The framework also supports sub-lexers and non-regular lexing // through an "escape hatch" which allows the users to consume any number of // further bytes after a match. So if you want to support nested C-style // comments or other paired structures you can do so at the lexical analysis // stage. // // For a tutorial see // http://hackthology.com/writing-a-lexer-in-go-with-lexmachine.html // // Example of defining a lexer // // // CreateLexer defines a lexer for the graphviz dot language. // func CreateLexer() (*lexmachine.Lexer, error) { // lexer := lexmachine.NewLexer() // // for _, lit := range Literals { // r := "\\" + strings.Join(strings.Split(lit, ""), "\\") // lexer.Add([]byte(r), token(lit)) // } // for _, name := range Keywords { // lexer.Add([]byte(strings.ToLower(name)), token(name)) // } // // lexer.Add([]byte(`//[^\n]*\n?`), token("COMMENT")) // lexer.Add([]byte(`/\*([^*]|\r|\n|(\*+([^*/]|\r|\n)))*\*+/`), token("COMMENT")) // lexer.Add([]byte(`([a-z]|[A-Z])([a-z]|[A-Z]|[0-9]|_)*`), token("ID")) // lexer.Add([]byte(`"([^\\"]|(\\.))*"`), token("ID")) // lexer.Add([]byte("( |\t|\n|\r)+"), skip) // lexer.Add([]byte(`\<`), // func(scan *lexmachine.Scanner, match *machines.Match) (interface{}, error) { // str := make([]byte, 0, 10) // str = append(str, match.Bytes...) // brackets := 1 // match.EndLine = match.StartLine // match.EndColumn = match.StartColumn // for tc := scan.TC; tc < len(scan.Text); tc++ { // str = append(str, scan.Text[tc]) // match.EndColumn += 1 // if scan.Text[tc] == '\n' { // match.EndLine += 1 // } // if scan.Text[tc] == '<' { // brackets += 1 // } else if scan.Text[tc] == '>' { // brackets -= 1 // } // if brackets == 0 { // match.TC = scan.TC // scan.TC = tc + 1 // match.Bytes = str // return token("ID")(scan, match) // } // } // return nil, // fmt.Errorf("unclosed HTML literal starting at %d, (%d, %d)", // match.TC, match.StartLine, match.StartColumn) // }, // ) // // err := lexer.Compile() // if err != nil { // return nil, err // } // return lexer, nil // } // // func token(name string) lex.Action { // return func(s *lex.Scanner, m *machines.Match) (interface{}, error) { // return s.Token(TokenIds[name], string(m.Bytes), m), nil // } // } // // Example of using a lexer // // func ExampleLex() error { // lexer, err := CreateLexer() // if err != nil { // return err // } // scanner, err := lexer.Scanner([]byte(`digraph { // rankdir=LR; // a [label="a" shape=box]; // c [