diff options
-rw-r--r-- | cli/cmd/compile.go | 27 | ||||
-rw-r--r-- | compiler/ast.go | 37 | ||||
-rw-r--r-- | compiler/compiler.go | 80 | ||||
-rw-r--r-- | compiler/parser_test.go | 38 |
4 files changed, 133 insertions, 49 deletions
diff --git a/cli/cmd/compile.go b/cli/cmd/compile.go index 23aa120..7815129 100644 --- a/cli/cmd/compile.go +++ b/cli/cmd/compile.go @@ -3,8 +3,10 @@ package cmd import ( "encoding/json" "fmt" + "io" "io/ioutil" "os" + "time" "github.com/nihei9/maleeni/compiler" "github.com/nihei9/maleeni/spec" @@ -22,7 +24,7 @@ func init() { rootCmd.AddCommand(cmd) } -func runCompile(cmd *cobra.Command, args []string) error { +func runCompile(cmd *cobra.Command, args []string) (retErr error) { var lspec *spec.LexSpec { data, err := ioutil.ReadAll(os.Stdin) @@ -35,7 +37,28 @@ func runCompile(cmd *cobra.Command, args []string) error { return err } } - clspec, err := compiler.Compile(lspec) + var w io.Writer + { + f, err := os.OpenFile("maleeni-compile.log", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return err + } + defer f.Close() + w = f + } + fmt.Fprintf(w, `maleeni compile starts. +Date time: %v +--- +`, time.Now().Format(time.RFC3339)) + defer func() { + fmt.Fprintf(w, "---\n") + if retErr != nil { + fmt.Fprintf(w, "maleeni compile failed: %v\n", retErr) + } else { + fmt.Fprintf(w, "maleeni compile succeeded.\n") + } + }() + clspec, err := compiler.Compile(lspec, compiler.EnableLogging(w)) if err != nil { return err } diff --git a/compiler/ast.go b/compiler/ast.go index 0b72f8d..e9c1b50 100644 --- a/compiler/ast.go +++ b/compiler/ast.go @@ -2,6 +2,7 @@ package compiler import ( "fmt" + "io" "sort" "strings" ) @@ -421,3 +422,39 @@ func positionSymbols(node astNode, n uint8) uint8 { } return p } + +func printAST(w io.Writer, ast astNode, ruledLine string, childRuledLinePrefix string, withAttrs bool) { + if ast == nil { + return + } + fmt.Fprintf(w, ruledLine) + fmt.Fprintf(w, "node: %v", ast) + if withAttrs { + fmt.Fprintf(w, ", nullable: %v, first: %v, last: %v", ast.nullable(), ast.first(), ast.last()) + } + fmt.Fprintf(w, "\n") + left, right := ast.children() + children := []astNode{} + if left != nil { + children = append(children, left) + } + if right != nil { + children = append(children, right) + } + num := len(children) + for i, child := range children { + line := "└─ " + if num > 1 { + if i == 0 { + line = "├─ " + } else if i < num-1 { + line = "│ " + } + } + prefix := "│ " + if i >= num-1 { + prefix = " " + } + printAST(w, child, childRuledLinePrefix+line, childRuledLinePrefix+prefix, withAttrs) + } +} diff --git a/compiler/compiler.go b/compiler/compiler.go index 3ae647e..02cda43 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1,8 +1,41 @@ package compiler -import "github.com/nihei9/maleeni/spec" +import ( + "io" + "strings" + + "github.com/nihei9/maleeni/log" + "github.com/nihei9/maleeni/spec" +) + +type compilerOption func(c *compilerConfig) error + +func EnableLogging(w io.Writer) compilerOption { + return func(c *compilerConfig) error { + logger, err := log.NewLogger(w) + if err != nil { + return err + } + c.logger = logger + return nil + } +} + +type compilerConfig struct { + logger log.Logger +} + +func Compile(lexspec *spec.LexSpec, opts ...compilerOption) (*spec.CompiledLexSpec, error) { + config := &compilerConfig{ + logger: log.NewNopLogger(), + } + for _, opt := range opts { + err := opt(config) + if err != nil { + return nil, err + } + } -func Compile(lexspec *spec.LexSpec) (*spec.CompiledLexSpec, error) { var kinds []string var patterns map[int][]byte { @@ -12,16 +45,45 @@ func Compile(lexspec *spec.LexSpec) (*spec.CompiledLexSpec, error) { kinds = append(kinds, e.Kind) patterns[i+1] = []byte(e.Pattern) } + + config.logger.Log("Patterns:") + for i, p := range patterns { + config.logger.Log(" #%v %v", i, string(p)) + } } - root, symTab, err := parse(patterns) - if err != nil { - return nil, err + + var root astNode + var symTab *symbolTable + { + var err error + root, symTab, err = parse(patterns) + if err != nil { + return nil, err + } + + var b strings.Builder + printAST(&b, root, "", "", false) + config.logger.Log("AST:\n%v", b.String()) } - dfa := genDFA(root, symTab) - tranTab, err := genTransitionTable(dfa) - if err != nil { - return nil, err + + var tranTab *spec.TransitionTable + { + dfa := genDFA(root, symTab) + var err error + tranTab, err = genTransitionTable(dfa) + if err != nil { + return nil, err + } + + config.logger.Log(`DFA: + States: %v states + Initial State: %v`, len(tranTab.Transition), tranTab.InitialState) + config.logger.Log(" Accepting States:") + for state, symbol := range tranTab.AcceptingStates { + config.logger.Log(" %v: %v", state, symbol) + } } + return &spec.CompiledLexSpec{ Kinds: kinds, DFA: tranTab, diff --git a/compiler/parser_test.go b/compiler/parser_test.go index 5c2d813..3bad222 100644 --- a/compiler/parser_test.go +++ b/compiler/parser_test.go @@ -1,49 +1,11 @@ package compiler import ( - "fmt" - "io" "os" "reflect" "testing" ) -func printAST(w io.Writer, ast astNode, ruledLine string, childRuledLinePrefix string, withAttrs bool) { - if ast == nil { - return - } - fmt.Fprintf(w, ruledLine) - fmt.Fprintf(w, "node: %v", ast) - if withAttrs { - fmt.Fprintf(w, ", nullable: %v, first: %v, last: %v", ast.nullable(), ast.first(), ast.last()) - } - fmt.Fprintf(w, "\n") - left, right := ast.children() - children := []astNode{} - if left != nil { - children = append(children, left) - } - if right != nil { - children = append(children, right) - } - num := len(children) - for i, child := range children { - line := "└─ " - if num > 1 { - if i == 0 { - line = "├─ " - } else if i < num-1 { - line = "│ " - } - } - prefix := "│ " - if i >= num-1 { - prefix = " " - } - printAST(w, child, childRuledLinePrefix+line, childRuledLinePrefix+prefix, withAttrs) - } -} - func TestParser(t *testing.T) { rune2Byte := func(char rune, index int) byte { return []byte(string(char))[index] |