Go言語 - PEGで構文解析 - 字句解析
Go言語でPEGによる構文解析方法があることを知ったので、簡単な字句解析部分のみのプログラムを書いてみました。ruleの書き方はgoyaccよりも融通が利いて便利そうです。
参考サイト
入手先および構文の書き方
scan.peg
package main type Parser Peg { s Scan // parserが自動生成するフィールド変数と区別するために // 敢えて埋め込みを行っていない。 } root <- expression EOT / expression <.+> {p.s.Err(begin)} EOT / <.+> {p.s.Err(begin)} EOT EOT <- !. expression <- literal literal* literal <- <&'0' [0-9]+> { // p,begin,end,text を使用する場合はruleを<…>で囲む。 // '0'で始まる数字列 fmt.Printf("line %d(%d) KIND:ZeroNUMBER \"%s\"\n", p.s.line, begin - p.s.lineHead, text) } / <[0-9]+> { // 数字列 fmt.Printf("line %d(%d) KIND:NUMBER \"%s\"\n", p.s.line, begin - p.s.lineHead, text) } / <[[A-Z]]+> { // 大小英字列 fmt.Printf("line %d(%d) KIND:IDENT \"%s\"\n", p.s.line, begin - p.s.lineHead, text) } / ' '+ { } / <'\n'> { // 改行時処理 p.s.line++; p.s.lineHead = begin + 1 } / <[^0-9a-zA-Z \n]+> { // その他文字 fmt.Printf("line %d(%d) KIND:OTHER \"%s\"\n", p.s.line, begin - p.s.lineHead, text) }
scan.go
package main import ( "fmt" ) type Scan struct { line int lineHead int } func (self *Scan) Init() { self.line = 1 // 現在の行 self.lineHead = 0 // 行の先頭文字位置 } func (self *Scan) Err(s int) { fmt.Printf("\n!!error!!%d\n", s) } func main() { const s string = "line001\nint a = 10\n" // 解析対象文字列 parser := &Parser{Buffer: s} // 解析対象文字の設定 parser.Init() // parser初期化 parser.s.Init() // SCAN構造体初期化 err := parser.Parse() // 解析 if err != nil { fmt.Println(err) } else { parser.Execute() // アクション処理 } }
コンパイルおよび実行
peg scan.peg go run scan.go scan.peg.go
実行結果
line 1(0) KIND:IDENT "line" line 1(4) KIND:ZeroNUMBER "001" line 2(0) KIND:IDENT "int" line 2(4) KIND:IDENT "a" line 2(6) KIND:OTHER "=" line 2(8) KIND:NUMBER "10"