diff --git a/etc/init.shy b/etc/init.shy index 40ea1820..12a88102 100644 --- a/etc/init.shy +++ b/etc/init.shy @@ -1,58 +1,4 @@ -@lex lex ~cli - @lex lex ~aaa login root root - ~ssh dial chat.shylinux.com:9090 true - sleep 1 -~host1 - ~aaa login root root - ~web serve - ~nfs load usr/sess.txt - var sessid = $result - if -n $sessid - ~host1 remote context mpa register $sessid - else - ~host1 remote context mpa register terminal shhylinux term term term 1 - let sessid $result - end - - ~host1 cache sessid $sessid - ~host1 remote cache sessid $sessid - ~nfs save usr/sess.txt $sessid - ~nfs genqr usr/sess.png "terminal: " $sessid -return - return -return -# ~ssh dial chat.shylinux.com:9090 true -# ~cli -# remote slaver listen ":9393" tcp -# ~ssh -# listen :9191 -~tcp - listen :9393 - -# ~tcp dial ":9393" -# @debug on -# ~aaa -# login shy shy -# ~mdb -# open chat:chat@/chat mysql -# ~web listen -# @debug on -# ~nfs -# open hi.txt - - -@debug -~web spawn hi he ./ -route template /tpl ./usr/msg.tpl -route script /php ./usr/msg.php -route script /who who -~hi listen ./ ":9494" -master nice -return - -login shy shy - diff --git a/src/context/cli/cli.go b/src/context/cli/cli.go index b1b7d404..6cba078a 100644 --- a/src/context/cli/cli.go +++ b/src/context/cli/cli.go @@ -20,11 +20,12 @@ import ( // {{{ // }}} -type CLI struct { +type CLI struct { // {{{ out io.WriteCloser bio *bufio.Reader lines []string + yac *ctx.Message lex *ctx.Message target *ctx.Context alias map[string][]string @@ -32,6 +33,8 @@ type CLI struct { *ctx.Context } +// }}} + func (cli *CLI) print(str string, arg ...interface{}) bool { // {{{ if cli.out != nil { fmt.Fprintf(cli.out, str, arg...) @@ -45,18 +48,28 @@ func (cli *CLI) parse(m *ctx.Message) (cmd []string) { // {{{ line := m.Cap("next") if m.Cap("next", ""); line == "" { - if cli.bio == nil { - line = cli.lines[m.Capi("pos")] - m.Capi("pos", 1) + line = cli.lines[m.Capi("pos", 1)-1] } else { cli.print(m.Conf("PS1")) - l, e := cli.bio.ReadString('\n') - m.Assert(e) - line = l + if l, e := cli.bio.ReadString('\n'); m.Assert(e) { + line = l + } } } + if cli.yac != nil { + if line == "\n" && cli.out != nil { + line = m.Cap("back") + m.Cap("back", "") + } + + yac := m.Spawn(cli.yac.Target()) + yac.Cmd("parse", "line", "void", line+"\n") + + return nil + } + if line = strings.TrimSpace(line); len(line) == 0 && cli.out != nil { line = m.Cap("back") m.Cap("back", "") @@ -66,7 +79,18 @@ func (cli *CLI) parse(m *ctx.Message) (cmd []string) { // {{{ } ls := []string{} - if cli.lex == nil { + if cli.lex != nil { + rest := line + for len(rest) > 0 { + lex := m.Spawn(cli.lex.Target()) + lex.Cmd("split", rest, "word", "void") + if !lex.Gets("result") { + break + } + ls = append(ls, lex.Meta["result"][1]) + rest = lex.Meta["result"][2] + } + } else { ls = strings.Split(line, " ") cs := []string{} for i := 0; i < len(ls); i++ { @@ -79,10 +103,6 @@ func (cli *CLI) parse(m *ctx.Message) (cmd []string) { // {{{ cs = append(cs, ls[i]) } ls = cs - } else { - lex := m.Spawn(cli.lex.Target()) - m.Assert(lex.Cmd("split", line, "void")) - ls = lex.Meta["result"] } if !cli.Has("skip") || !cli.Pulse.Caps("skip") { @@ -277,7 +297,7 @@ func (cli *CLI) check(arg []string) bool { // {{{ // }}} -func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { +func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{ c.Caches = map[string]*ctx.Cache{} c.Configs = map[string]*ctx.Config{} c.Caches["skip"] = &ctx.Cache{Name: "跳过执行", Value: cli.Pulse.Cap("skip"), Help: "命令只解析不执行"} @@ -285,6 +305,7 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server s := new(CLI) s.Context = c s.lex = cli.lex + s.yac = cli.yac if m.Has("for") { s.lines = append(s.lines, cli.lines[cli.Pulse.Capi("pos")-1:]...) } else { @@ -293,7 +314,8 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server return s } -func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { +// }}} +func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ cli.Caches["target"] = &ctx.Cache{Name: "操作目标", Value: cli.Name, Help: "命令操作的目标"} cli.Caches["result"] = &ctx.Cache{Name: "执行结果", Value: "", Help: "前一条命令的执行结果"} cli.Caches["back"] = &ctx.Cache{Name: "前一条指令", Value: "", Help: "前一条指令"} @@ -314,11 +336,11 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { m.Assert(lex != nil, "词法解析模块不存在") if lex.Cap("status") != "start" { lex.Target().Start(lex) - m.Spawn(lex.Target()).Cmd("train", "'[^']*'") - m.Spawn(lex.Target()).Cmd("train", "\"[^\"]*\"") - m.Spawn(lex.Target()).Cmd("train", "[^ \t\n]+") - m.Spawn(lex.Target()).Cmd("train", "[ \n\t]+", "void", "void") - m.Spawn(lex.Target()).Cmd("train", "#[^\n]*\n", "void", "void") + m.Spawn(lex.Target()).Cmd("train", "'[^']*'", "word", "word") + m.Spawn(lex.Target()).Cmd("train", "\"[^\"]*\"", "word", "word") + m.Spawn(lex.Target()).Cmd("train", "[^\t \n]+", "word", "word") + m.Spawn(lex.Target()).Cmd("train", "[\t \n]+", "void", "void") + m.Spawn(lex.Target()).Cmd("train", "#[^\n]*\n", "help", "void") } cli.lex = lex return arg[0] @@ -326,6 +348,27 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { return x.Value // }}} }} + cli.Configs["yac"] = &ctx.Config{Name: "词法解析器", Value: "", Help: "命令行词法解析器", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { + if len(arg) > 0 && len(arg[0]) > 0 { // {{{ + cli, ok := m.Target().Server.(*CLI) + m.Assert(ok, "模块类型错误") + + yac := m.Find(arg[0], true) + m.Assert(yac != nil, "词法解析模块不存在") + if yac.Cap("status") != "start" { + yac.Target().Start(yac) + m.Spawn(yac.Target()).Cmd("train", "void", "void", "[\t ]+") + m.Spawn(yac.Target()).Cmd("train", "tran", "tran", "mul{", "@", "$", "}", "opt{", "[a-zA-Z0-9]+", "}") + m.Spawn(yac.Target()).Cmd("train", "word", "word", "rep{", "mul{", "~", "!", "tran", "\"[^\"]*\"", "'[^']*'", "[a-zA-Z0-9_/.]+", "}", "}") + m.Spawn(yac.Target()).Cmd("train", "tran", "tran", "$", "(", "word", ")") + m.Spawn(yac.Target()).Cmd("train", "line", "line", "opt{", "word", "}", "mul{", ";", "\n", "#[^\n]*\n", "}") + } + cli.yac = yac + return arg[0] + } + return x.Value + // }}} + }} cli.Configs["PS1"] = &ctx.Config{Name: "命令行提示符(target/detail)", Value: "target", Help: "命令行提示符,target:显示当前模块,detail:显示详细信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { if len(arg) > 0 { // {{{ return arg[0] @@ -383,7 +426,8 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { return cli } -func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { +// }}} +func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ cli.Caches["#"] = &ctx.Cache{Name: "参数个数", Value: fmt.Sprintf("%d", len(arg)), Help: "参数个数"} for i, v := range arg { cli.Caches[fmt.Sprintf("%d", i)] = &ctx.Cache{Name: "执行参数", Value: v, Help: "执行参数"} @@ -404,10 +448,11 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { m.Cap("init.shy", arg[0]) } - m.Cap("next", "source "+m.Cap("init.shy")) + m.Cap("next", fmt.Sprintf("source %s\n", m.Cap("init.shy"))) cli.bio = bufio.NewReader(os.Stdin) cli.out = os.Stdout - m.Conf("lex", "lex") + // m.Conf("lex", "lex") + m.Conf("yac", "yac") m.Cap("stream", "stdout") } else if stream, ok := m.Data["file"]; ok { if bio, ok := stream.(*bufio.Reader); ok { @@ -427,7 +472,8 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { go m.AssertOne(m, true, func(m *ctx.Message) { for !m.Caps("exit") { if cmd := cli.parse(m); cmd != nil { - m.Spawn(cli.target).Set("detail", cmd...).Post(cli.Context) + msg := m.Spawn(cli.target).Set("detail", cmd...) + msg.Post(cli.Context) } } }, func(m *ctx.Message) { @@ -443,7 +489,8 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { return !m.Caps("exit") } - if !msg.Has("result") && cli.Owner == ctx.Index.Owner { + if !msg.Hand && cli.Owner == ctx.Index.Owner { + msg.Hand = true msg.Log("system", nil, "%v", msg.Meta["detail"]) msg.Set("result").Set("append") @@ -468,11 +515,6 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { } } - result := strings.TrimRight(strings.Join(msg.Meta["result"], ""), "\n") - if m.Cap("result", result); len(result) > 0 { - cli.print(result + "\n") - } - if msg.Target().Context() != nil || msg.Target() == ctx.Index { cli.target = msg.Target() } @@ -489,7 +531,8 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { return !cli.Pulse.Has("save") } -func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { +// }}} +func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{ switch cli.Context { case m.Target(): if p, ok := cli.Context.Context().Server.(*CLI); ok { @@ -519,6 +562,8 @@ func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { return true } +// }}} + var Pulse *ctx.Message var Index = &ctx.Context{Name: "cli", Help: "管理中心", Caches: map[string]*ctx.Cache{ @@ -526,8 +571,57 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", }, Configs: map[string]*ctx.Config{}, Commands: map[string]*ctx.Command{ + "tran": &ctx.Command{Name: "tran word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if _, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + switch len(arg) { + case 2: + switch arg[0] { + case "$": + m.Echo(m.Cap(arg[1])) + case "@": + m.Echo(m.Conf(arg[1])) + } + default: + m.Set("result", arg[2:len(arg)-1]...) + } + } // }}} + }}, + "word": &ctx.Command{Name: "word word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + + msg := m.Spawn(cli.target) + if a, ok := cli.alias[arg[0]]; ok { + msg.Set("detail", a...) + msg.Meta["detail"] = append(msg.Meta["detail"], arg[1:]...) + } else { + msg.Set("detail", arg...) + } + + msg.Post(cli.Context) + if m.Hand = false; msg.Hand { + m.Hand = true + m.Meta["result"] = msg.Meta["result"] + } + } // }}} + }}, + "line": &ctx.Command{Name: "line word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + arg = arg[:len(arg)-1] + + result := strings.TrimRight(strings.Join(arg, ""), "\n") + if m.Cap("result", result); len(result) > 0 { + cli.print(result + "\n") + } + + if m.Cap("back", ""); cli.bio != nil { + cli.lines = append(cli.lines, strings.Join(arg, " ")) + m.Capi("nline", 1) + m.Capi("pos", 1) + } + } // }}} + }}, "alias": &ctx.Command{Name: "alias [short [long]]|[delete short]", Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ switch len(arg) { case 0: for k, v := range cli.alias { @@ -544,49 +638,49 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Echo("%s: %v\n", arg[0], cli.alias[arg[0]]) } } - } + } // }}} }}, "sleep": &ctx.Command{Name: "sleep time", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ if d, e := time.ParseDuration(arg[0]); m.Assert(e) { m.Log("info", nil, "sleep %v", d) time.Sleep(d) m.Log("info", nil, "sleep %v done", d) } - } + } // }}} }}, "var": &ctx.Command{Name: "var a [= exp]", Help: "定义变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ val := "" if len(arg) > 2 { val = cli.express(arg[2:]) } cli.Pulse.Cap(arg[0], arg[0], val, "临时变量") - } + } // }}} }}, "let": &ctx.Command{Name: "let a = exp", Help: "设置变量, a: 变量名, exp: 表达式(a {+|-|*|/|%} b)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ m.Echo(cli.Pulse.Cap(arg[0], cli.express(arg[2:]))) - } + } // }}} }}, "source": &ctx.Command{Name: "source file", Help: "运行脚本, file: 脚本文件名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ if f, e := os.Open(arg[0]); m.Assert(e) { m.Put("option", "file", f).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "脚本文件") <-m.Target().Exit Pulse.Capi("level", -1) } - } + } // }}} }}, "return": &ctx.Command{Name: "return result...", Help: "结束脚本, rusult: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ call := cli.Requests[len(cli.Requests)-1] call.Set("result", arg...) cli.Pulse.Caps("exit", true) - } + } // }}} }}, "if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ if m.Target(m.Source()); (cli.Has("skip") && cli.Pulse.Caps("skip")) || !cli.check(arg) { m.Add("option", "skip") } @@ -594,33 +688,33 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Put("option", "file", cli.bio).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "条件语句") <-m.Target().Exit Pulse.Capi("level", -1) - } + } // }}} }}, "elif": &ctx.Command{Name: "elif exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ if cli.Pulse.Caps("skip", !cli.Pulse.Caps("else")) { return } cli.Pulse.Caps("else", cli.Pulse.Caps("skip", !cli.check(arg))) - } + } // }}} }}, "else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ cli.Pulse.Caps("skip", !cli.Pulse.Caps("else")) - } + } // }}} }}, "end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ if cli.Pulse.Caps("exit", true); cli.Pulse.Has("for") && !cli.Pulse.Caps("skip") { cli.Pulse.Caps("exit", false) cli.Pulse.Cap("pos", "0") } cli.bio = nil - } + } // }}} }}, "for": &ctx.Command{Name: "for exp", Help: "循环语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ if cli.Pulse.Has("for") && cli.Pulse.Capi("pos") == 1 { cli.Pulse.Caps("skip", !cli.check(arg)) return @@ -632,10 +726,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Put("option", "file", cli.bio).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "循环语句") <-m.Target().Exit Pulse.Capi("level", -1) - } + } // }}} }}, "function": &ctx.Command{Name: "function name", Help: "函数定义, name: 函数名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ if _, ok := cli.Context.Context().Server.(*CLI); ok { m.Target(m.Source().Context()) } else { @@ -645,10 +739,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Add("option", "skip").Add("option", "save") m.Put("option", "file", cli.bio).Start(arg[0], "函数定义") <-m.Target().Exit - } + } // }}} }}, "call": &ctx.Command{Name: "call name arg...", Help: "函数调用, name: 函数名, arg: 参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - m.Target(m.Source()) + m.Target(m.Source()) // {{{ m.BackTrace(func(msg *ctx.Message) bool { if fun := msg.Find(arg[0], false); fun != nil { fun.Add("detail", arg[0], arg[1:]...).Target().Start(fun) @@ -657,7 +751,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", return false } return true - }) + }) // }}} }}, }, } diff --git a/src/context/ctx.go b/src/context/ctx.go index a27d7ad1..369c319c 100644 --- a/src/context/ctx.go +++ b/src/context/ctx.go @@ -443,6 +443,7 @@ func (c *Context) Del(arg ...string) { // {{{ type Message struct { code int time time.Time + Hand bool Recv chan bool Wait chan bool @@ -973,10 +974,8 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{ arg = m.Meta["args"] } + m.Hand = true x.Hand(m.Set("result").Set("append"), s, key, arg...) - if !m.Has("result") { - m.Meta["result"] = nil - } if x.Appends != nil { for _, v := range m.Meta["append"] { @@ -1112,7 +1111,7 @@ func (m *Message) Conf(key string, arg ...string) string { // {{{ } else { x.Value = arg[0] } - m.Log("conf", s, "%s %v", x.Name, x.Value) + // m.Log("conf", s, "%s %v", x.Name, x.Value) return x.Value case 0: if x.Hand != nil { @@ -1190,10 +1189,10 @@ func (m *Message) Cap(key string, arg ...string) string { // {{{ } else { x.Value = arg[0] } - m.Log("debug", s, "%s %s", x.Name, x.Value) + // m.Log("debug", s, "%s %s", x.Name, x.Value) return x.Value case 0: - m.Log("debug", s, "%s %s", x.Name, x.Value) + // m.Log("debug", s, "%s %s", x.Name, x.Value) if x.Hand != nil { return x.Hand(m, x) } diff --git a/src/context/lex/lex.go b/src/context/lex/lex.go index d8b3cf68..f0f6633b 100644 --- a/src/context/lex/lex.go +++ b/src/context/lex/lex.go @@ -1,23 +1,28 @@ -package lex - -import ( +package lex // {{{ +// }}} +import ( // {{{ "context" "fmt" + "strconv" ) -type State struct { - star bool - next int - hash int -} +// }}} -type Seed struct { +type Seed struct { // {{{ page int hash int word string } -type LEX struct { +// }}} +type State struct { // {{{ + star bool + next int + hash int +} + +// }}} +type LEX struct { // {{{ seed []*Seed page map[string]int hash map[string]int @@ -29,52 +34,71 @@ type LEX struct { *ctx.Context } -func (lex *LEX) train(seed []byte, arg ...string) { - cell, page, hash := 128, 1, 1 - if len(arg) > 0 { - if x, ok := lex.hash[arg[0]]; ok { - hash = x - } else { - hash = lex.Capi("nhash", 1) - lex.hash[arg[0]] = hash - } - } - if len(arg) > 1 { - if x, ok := lex.page[arg[1]]; ok { - page = x - } else { - lex.mat = append(lex.mat, make(map[byte]*State)) - page = lex.Capi("nline", 1) - lex.page[arg[1]] = page - lex.Capi("npage", 1) - } - } - lex.Log("debug", nil, "%d %d %v", page, hash, seed) - lex.seed = append(lex.seed, &Seed{page, hash, string(seed)}) - lex.Capi("nseed", 1) - lex.Cap("stream", fmt.Sprintf("%s,%s,%s", lex.Cap("nseed"), lex.Cap("npage"), lex.Cap("nhash"))) +// }}} +func (lex *LEX) index(hash string, h string) int { // {{{ + if x, e := strconv.Atoi(h); e == nil { + return x + } + + which := lex.page + switch hash { + case "npage": + which = lex.page + case "nhash": + which = lex.hash + } + + if x, ok := which[h]; ok { + return x + } + + x := lex.Capi(hash, 1) + which[h] = x + return x +} + +// }}} +func (lex *LEX) charset(c byte) []byte { // {{{ + switch c { + case 't': + return []byte{'\t'} + case 'n': + return []byte{'\n'} + case 's': + return []byte{'\t', ' ', '\n'} + case 'd': + return []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} + case 'x': + return []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'} + } + return []byte{c} +} + +// }}} +func (lex *LEX) train(page int, hash int, seed []byte) int { // {{{ + + cn := make([]bool, lex.Capi("ncell")) + c := make([]byte, 0, lex.Capi("ncell")) + sn := make([]bool, lex.Capi("nline")) s := []int{page} - c := make([]byte, 0, cell) - sn := make([]bool, len(lex.mat)) - cn := make([]bool, cell) - ends := make([]*State, 0, len(seed)) + ends := []*State{} + + for p, set := 0, true; p < len(seed); p++ { - for p := 0; p < len(seed); p++ { switch seed[p] { case '[': - p++ - set := true - if seed[p] == '^' { - set = false - p++ + if p++; seed[p] == '^' { + set, p = false, p+1 } for ; seed[p] != ']'; p++ { if seed[p] == '\\' { p++ - cn[seed[p]] = true + for _, s := range lex.charset(seed[p]) { + cn[s] = true + } continue } @@ -87,6 +111,7 @@ func (lex *LEX) train(seed []byte, arg ...string) { cn[i] = true } p += 2 + continue } cn[seed[p]] = true @@ -100,18 +125,21 @@ func (lex *LEX) train(seed []byte, arg ...string) { } case '.': - for i := 0; i < cell; i++ { + for i := 0; i < len(cn); i++ { c = append(c, byte(i)) } + case '\\': p++ - fallthrough + for _, s := range lex.charset(seed[p]) { + c = append(c, s) + } default: c = append(c, seed[p]) } - lex.Log("debug", nil, "page: \033[31m%v\033[0m", s) - lex.Log("debug", nil, "cell: \033[32m%v\033[0m", c) + lex.Log("debug", nil, "page: \033[31m%d %v\033[0m", len(s), s) + lex.Log("debug", nil, "cell: \033[32m%d %v\033[0m", len(c), c) flag := '\000' if p+1 < len(seed) { @@ -125,11 +153,11 @@ func (lex *LEX) train(seed []byte, arg ...string) { for i := 0; i < len(s); i++ { for line, j := 0, byte(0); int(j) < len(c); j++ { state := lex.mat[s[i]][c[j]] + lex.Log("debug", nil, "GET(%d,%d): %v", s[i], c[j], state) if state == nil { - state = new(State) + state = &State{} lex.Capi("nnode", 1) } - lex.Log("debug", nil, "GET(%d,%d): %v", s[i], c[j], state) switch flag { case '+': @@ -140,7 +168,7 @@ func (lex *LEX) train(seed []byte, arg ...string) { case '?': if sn[s[i]] = true; p == len(seed)-1 { for _, n := range ends { - if n.next == s[i] && n.hash == 0 { + if n.next == s[i] { lex.Log("debug", nil, "GET() state:%v", n) n.hash = hash lex.Log("debug", nil, "END() state:%v", n) @@ -153,25 +181,26 @@ func (lex *LEX) train(seed []byte, arg ...string) { state.hash = hash } else { if state.next == 0 { - if line == 0 { - line = len(lex.mat) - sn = append(sn, false) + if line == 0 || !lex.Caps("compact") { lex.mat = append(lex.mat, make(map[byte]*State)) - lex.Capi("nline", 1) + line = lex.Capi("nline", 1) - 1 + sn = append(sn, false) } state.next = line } sn[state.next] = true } - if s, ok := lex.state[*state]; ok { + if s, ok := lex.state[*state]; !ok { + lex.state[*state] = state + lex.Capi("nreal", 1) + } else { state = s } - lex.state[*state] = state lex.mat[s[i]][c[j]] = state - lex.Log("debug", nil, "SET(%d,%d): %v", s[i], c[j], state) + lex.Log("debug", nil, "SET(%d,%d): %v(%s,%s)", s[i], c[j], state, lex.Cap("nnode"), lex.Cap("nreal")) ends = append(ends, state) } } @@ -184,25 +213,20 @@ func (lex *LEX) train(seed []byte, arg ...string) { sn[i] = false } } + return hash } -func (lex *LEX) parse(line []byte, arg ...string) (word []byte, hash int, rest []byte) { - page, begin, end := 1, 0, 0 - if len(arg) > 0 { - if x, ok := lex.page[arg[0]]; ok { - page = x - } else { - return line, 0, nil - } - } +// }}} +func (lex *LEX) parse(page int, line []byte) (hash int, word []byte, rest []byte) { // {{{ - for star, s, i := 0, page, 0; s != 0 && i < len(line); i++ { + pos := 0 - c := line[i] - if c == '\\' && i < len(line)-1 { - c = 'a' - end++ - i++ + for star, s := 0, page; s != 0 && pos < len(line); pos++ { + + c := line[pos] + if c == '\\' && pos < len(line)-1 { + pos++ + c = lex.charset(line[pos])[0] } state := lex.mat[s][c] @@ -216,27 +240,31 @@ func (lex *LEX) parse(line []byte, arg ...string) (word []byte, hash int, rest [ break } - if state, ok := lex.mat[star][c]; star == 0 || !ok || state == nil || !state.star { + if state, ok := lex.mat[star][c]; !ok || state == nil || !state.star { star = 0 } - if end++; state.star { + if state.star { star = s } + + word = append(word, c) if s, hash = state.next, state.hash; s == 0 { s, star = star, 0 } } if hash == 0 { - begin, end = 0, 0 + pos, word = 0, word[:0] } + rest = line[pos:] - word, rest = line[begin:end], line[end:] lex.Log("debug", nil, "\033[31m[%v]\033[0m %d [%v]", string(word), hash, string(rest)) return } -func (lex *LEX) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { +// }}} + +func (lex *LEX) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{ c.Caches = map[string]*ctx.Cache{} c.Configs = map[string]*ctx.Config{} @@ -245,37 +273,42 @@ func (lex *LEX) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server return s } -func (lex *LEX) Begin(m *ctx.Message, arg ...string) ctx.Server { - lex.Message = m +// }}} +func (lex *LEX) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ + if lex.Context == Index { + Pulse = m + } + + lex.Caches["ncell"] = &ctx.Cache{Name: "字符上限", Value: "128", Help: "字符上限"} + lex.Caches["nlang"] = &ctx.Cache{Name: "集合上限", Value: "16", Help: "集合上限"} + lex.Caches["nseed"] = &ctx.Cache{Name: "种子数量", Value: "0", Help: "种子数量"} - lex.Caches["npage"] = &ctx.Cache{Name: "集合数量", Value: "1", Help: "集合数量"} - lex.Caches["nhash"] = &ctx.Cache{Name: "类型数量", Value: "1", Help: "类型数量"} + lex.Caches["npage"] = &ctx.Cache{Name: "集合数量", Value: "0", Help: "集合数量"} + lex.Caches["nhash"] = &ctx.Cache{Name: "类型数量", Value: "0", Help: "类型数量"} - lex.Caches["nline"] = &ctx.Cache{Name: "状态数量", Value: "1", Help: "状态数量"} + lex.Caches["nline"] = &ctx.Cache{Name: "状态数量", Value: "16", Help: "状态数量"} lex.Caches["nnode"] = &ctx.Cache{Name: "节点数量", Value: "0", Help: "节点数量"} - lex.Caches["npush"] = &ctx.Cache{Name: "节点数量", Value: "0", Help: "节点数量", Hand: func(m *ctx.Message, x *ctx.Cache, arg ...string) string { - return fmt.Sprintf("%d", len(m.Target().Server.(*LEX).state)) - }} + lex.Caches["nreal"] = &ctx.Cache{Name: "实点数量", Value: "0", Help: "实点数量"} + lex.Caches["compact"] = &ctx.Cache{Name: "紧凑模式", Value: "true", Help: "实点数量"} return lex } -func (lex *LEX) Start(m *ctx.Message, arg ...string) bool { - lex.seed = make([]*Seed, 0, 10) +// }}} +func (lex *LEX) Start(m *ctx.Message, arg ...string) bool { // {{{ + lex.Message = m + + lex.seed = make([]*Seed, 0, 9) lex.page = map[string]int{"nil": 0} lex.hash = map[string]int{"nil": 0} + lex.mat = make([]map[byte]*State, lex.Capi("nlang")) lex.state = make(map[State]*State) - lex.mat = make([]map[byte]*State, 2, 10) - for i := 0; i < len(lex.mat); i++ { - lex.mat[i] = make(map[byte]*State) - } - - lex.Message = m return false } -func (lex *LEX) Close(m *ctx.Message, arg ...string) bool { +// }}} +func (lex *LEX) Close(m *ctx.Message, arg ...string) bool { // {{{ switch lex.Context { case m.Target(): case m.Source(): @@ -283,77 +316,90 @@ func (lex *LEX) Close(m *ctx.Message, arg ...string) bool { return true } -var Index = &ctx.Context{Name: "lex", Help: "词法解析", +// }}} + +var Pulse *ctx.Message +var Index = &ctx.Context{Name: "lex", Help: "词法中心", Caches: map[string]*ctx.Cache{}, Configs: map[string]*ctx.Config{}, Commands: map[string]*ctx.Command{ "train": &ctx.Command{Name: "train seed [hash [page]", Help: "添加词法规则", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - lex, ok := m.Target().Server.(*LEX) - m.Assert(ok, "模块类型错误") - m.Assert(len(arg) > 0, "参数错误") + if lex, ok := m.Target().Server.(*LEX); m.Assert(ok) { // {{{ + page, hash := 1, 1 + if len(arg) > 2 { + page = lex.index("npage", arg[2]) + } + if len(arg) > 1 { + hash = lex.index("nhash", arg[1]) + } - lex.train([]byte(arg[0]), arg[1:]...) + if lex.mat[page] == nil { + lex.mat[page] = map[byte]*State{} + } + + lex.seed = append(lex.seed, &Seed{page, hash, string(arg[0])}) + lex.Log("info", nil, "%d %d %d %v", page, hash, lex.Capi("nseed", 1), arg[0]) + lex.Cap("stream", fmt.Sprintf("%s,%s,%s", lex.Cap("nseed"), lex.Cap("npage"), lex.Cap("nhash"))) + + m.Echo("%d", lex.train(page, hash, []byte(arg[0]))) + } // }}} }}, "parse": &ctx.Command{Name: "parse line [page]", Help: "解析单词", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - lex, ok := m.Target().Server.(*LEX) - m.Assert(ok, "模块类型错误") - m.Assert(len(arg) > 0, "参数错误") - - word, hash, rest := lex.parse([]byte(arg[0]), arg[1:]...) - m.Add("result", string(word), fmt.Sprintf("%d", hash), string(rest)) - }}, - "split": &ctx.Command{Name: "split line page1 [page2]", Help: "分割语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - lex, ok := m.Target().Server.(*LEX) - m.Assert(ok, "模块类型错误") - m.Assert(len(arg) > 1, "参数错误") - - for line := arg[0]; len(line) > 0; { - word, hash, rest := lex.parse([]byte(line), arg[1:]...) - line = string(rest) - word, hash, rest = lex.parse([]byte(line), arg[2:]...) - line = string(rest) - - if hash == 0 { - break + if lex, ok := m.Target().Server.(*LEX); m.Assert(ok) { // {{{ + page := 1 + if len(arg) > 1 { + page = lex.index("npage", arg[1]) } - if len(word) > 1 { - switch word[0] { - case '"', '\'': - word = word[1 : len(word)-1] + hash, word, rest := lex.parse(page, []byte(arg[0])) + m.Add("result", fmt.Sprintf("%d", hash), string(word), string(rest)) + } // }}} + }}, + "split": &ctx.Command{Name: "split line page void help", Help: "分割语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if lex, ok := m.Target().Server.(*LEX); m.Assert(ok) { // {{{ + page := 1 + if len(arg) > 1 { + page = lex.index("npage", arg[1]) + } + + void := 2 + if len(arg) > 2 { + void = lex.index("npage", arg[2]) + } + + help := 2 + if len(arg) > 3 { + help = lex.index("npage", arg[3]) + } + + rest := []byte(arg[0]) + _, _, rest = lex.parse(help, []byte(rest)) + _, _, rest = lex.parse(void, []byte(rest)) + hash, word, rest := lex.parse(page, []byte(rest)) + m.Add("result", fmt.Sprintf("%d", hash), string(word), string(rest)) + } // }}} + }}, + "info": &ctx.Command{Name: "info", Help: "显示缓存", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if lex, ok := m.Target().Server.(*LEX); m.Assert(ok) { // {{{ + for i, v := range lex.seed { + m.Echo("seed: %d %v\n", i, v) + } + for i, v := range lex.page { + m.Echo("page: %s %d\n", i, v) + } + for i, v := range lex.hash { + m.Echo("hash: %s %d\n", i, v) + } + for i, v := range lex.state { + m.Echo("node: %v %v\n", i, v) + } + for i, v := range lex.mat { + for k, v := range v { + m.Echo("node: %v %v %v\n", i, k, v) } } - - m.Add("result", string(word)) - } - + } // }}} }}, - "cache": &ctx.Command{Name: "cache", Help: "显示缓存", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - lex, ok := m.Target().Server.(*LEX) - m.Assert(ok, "模块类型错误") - for i, v := range lex.seed { - m.Echo("seed: %d %v\n", i, v) - } - for i, v := range lex.page { - m.Echo("page: %s %d\n", i, v) - } - for i, v := range lex.hash { - m.Echo("hash: %s %d\n", i, v) - } - for i, v := range lex.state { - m.Echo("node: %v %v\n", i, v) - } - for i, v := range lex.mat { - for k, v := range v { - m.Echo("node: %v %v %v\n", i, k, v) - } - } - }}, - }, - Index: map[string]*ctx.Context{ - "void": &ctx.Context{Name: "void", - Commands: map[string]*ctx.Command{"split": &ctx.Command{}}, - }, }, } diff --git a/src/context/yac/yac.go b/src/context/yac/yac.go new file mode 100644 index 00000000..4101aa0b --- /dev/null +++ b/src/context/yac/yac.go @@ -0,0 +1,371 @@ +package yac // {{{ +// }}} +import ( // {{{ + "context" + "fmt" + "strings" +) + +// }}} + +type Seed struct { // {{{ + page int + hash int + word []string +} + +// }}} +type State struct { // {{{ + star int + next int + hash int +} + +// }}} +type YAC struct { // {{{ + seed []*Seed + page map[string]int + hash map[string]int + hand map[int]string + + state map[State]*State + mat []map[byte]*State + + lex *ctx.Message + *ctx.Message + *ctx.Context +} + +// }}} + +func (yac *YAC) train(page, hash int, word []string) ([]*State, int) { // {{{ + + if yac.mat[page] == nil { + yac.mat[page] = map[byte]*State{} + for i := 0; i < yac.Capi("nlang"); i++ { + yac.mat[page][byte(i)] = nil + } + } + sn := make([]bool, yac.Capi("nline")) + ss := []int{page} + + begin := page + point := []*State{} + ends := []*State{} + state := []*State{} + mul := false + skip := len(word) + + for i, n := 0, 1; i < len(word); i += n { + if !mul { + if hash <= 0 && word[i] == "}" { + if skip = i + 2; hash == -1 { + hash = 0 + break + } + return ends, skip + } else { + ends = ends[:0] + } + } + + for _, s := range ss { + switch word[i] { + case "opt{": + sn[s] = true + state, n = yac.train(s, 0, word[i+1:]) + for _, x := range state { + for i := len(sn); i <= x.next; i++ { + sn = append(sn, false) + } + sn[x.next] = true + point = append(point, x) + } + case "rep{": + sn[s] = true + state, n = yac.train(s, -1, word[i+1:]) + for _, x := range state { + x.star = s + sn[x.next] = true + point = append(point, x) + yac.Pulse.Log("info", nil, "END: %v", x) + } + case "mul{": + mul, n = true, 1 + goto next + case "}": + if mul { + mul = false + goto next + } + default: + c := byte(0) + if x, ok := yac.page[word[i]]; !ok { + lex := yac.lex.Spawn(yac.lex.Target()) + lex.Cmd("parse", word[i], fmt.Sprintf("yac%d", s)) + if lex.Gets("result") { + x = lex.Geti("result") + } else { + x = len(yac.mat[s]) + lex = yac.lex.Spawn(yac.lex.Target()) + lex.Cmd("train", word[i], fmt.Sprintf("%d", x), fmt.Sprintf("yac%d", s)) + } + c = byte(x) + } else { + c = byte(x) + } + + state := yac.mat[s][c] + yac.Pulse.Log("info", nil, "GET(%d, %d): %v", s, c, state) + if state == nil { + state = &State{} + yac.Pulse.Capi("nnode", 1) + } + + if state.next == 0 { + yac.mat = append(yac.mat, map[byte]*State{}) + state.next = yac.Pulse.Capi("nline", 1) - 1 + for i := 0; i < yac.Capi("nlang"); i++ { + yac.mat[state.next][byte(i)] = nil + } + sn = append(sn, false) + } + sn[state.next] = true + + if x, ok := yac.state[*state]; !ok { + yac.Pulse.Capi("nreal", 1) + yac.state[*state] = state + } else { + yac.mat[s][c] = x + } + yac.mat[s][c] = state + + yac.Pulse.Log("info", nil, "SET(%d, %d): %v", s, c, state) + ends = append(ends, state) + point = append(point, state) + if s > begin { + begin = s + } + + } + } + + next: + if !mul { + ss = ss[:0] + for s, b := range sn { + if sn[s] = false; b { + ss = append(ss, s) + } + } + } + } + + for _, n := range ss { + if n < yac.Pulse.Capi("nlang") || n >= len(yac.mat) { + continue + } + + void := true + for _, x := range yac.mat[n] { + if x != nil { + void = false + break + } + } + if void { + yac.Pulse.Log("info", nil, "DEL: %d %d", yac.Pulse.Capi("nline"), n) + yac.Pulse.Capi("nline", 0, n) + yac.mat = yac.mat[:n] + } + } + + for _, n := range ss { + for _, s := range point { + if s.next == n { + yac.Pulse.Log("info", nil, "GET: %v", s) + if s.next >= len(yac.mat) { + s.next = 0 + } + if hash > 0 { + s.hash = hash + } + yac.Pulse.Log("info", nil, "SET: %v", s) + } + } + + } + + return ends, skip +} + +// }}} +func (yac *YAC) parse(m *ctx.Message, page, void int, line string) ([]string, string) { // {{{ + + level := m.Capi("level", 1) + m.Log("info", nil, ">>>%s%d", m.Cap("label")[0:level], level) + + hash, word := 0, []string{} + for star, s := 0, page; s != 0 && len(line) > 0; { + + lex := yac.lex.Spawn(yac.lex.Target()) + lex.Cmd("parse", line, fmt.Sprintf("yac%d", void)) + line = lex.Meta["result"][2] + + lex = yac.lex.Spawn(yac.lex.Target()) + lex.Cmd("parse", line, fmt.Sprintf("yac%d", s)) + line = lex.Meta["result"][2] + + c := byte(lex.Geti("result")) + state := yac.mat[s][c] + m.Log("info", nil, "get(%d,%d): %s %v", s, c, lex.Meta["result"][1], state) + if state == nil { + for i, x := range yac.mat[s] { + if int(i) >= m.Capi("nlang") || x == nil { + continue + } + m.Log("info", nil, "try(%d,%d): %v", s, i, x) + if w, l := yac.parse(m, int(i), void, line); l != line { + word = append(word, w...) + state = x + line = l + break + } + } + } else { + word = append(word, lex.Meta["result"][1]) + } + + if state == nil { + s, star = star, 0 + continue + } + + star, s, hash = state.star, state.next, state.hash + if s == 0 { + s, star = star, 0 + } + } + + if hash == 0 { + word = word[:0] + } else { + m.Log("info", nil, "%s(%d,%d): %d %v %v", yac.hand[page], page, hash, len(word), word, line) + msg := m.Spawn(m.Source()).Add("detail", yac.hand[page], word...) + if msg.Cmd(); msg.Hand { + word = msg.Meta["result"] + } + m.Log("info", nil, "end(%d,%d): %d %v %v", page, hash, len(word), word, line) + } + + m.Log("info", nil, "<<<%s%d", m.Cap("label")[0:level], level) + level = m.Capi("level", -1) + return word, line +} + +// }}} + +func (yac *YAC) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{ + c.Caches = map[string]*ctx.Cache{} + c.Configs = map[string]*ctx.Config{} + + s := new(YAC) + s.Context = c + return s +} + +// }}} +func (yac *YAC) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ + yac.Message = m + if yac.Context == Index { + Pulse = m + } + + yac.Caches["ncell"] = &ctx.Cache{Name: "单词上限", Value: "128", Help: "单词上限"} + yac.Caches["nlang"] = &ctx.Cache{Name: "集合上限", Value: "16", Help: "集合上限"} + + yac.Caches["nseed"] = &ctx.Cache{Name: "种子数量", Value: "0", Help: "种子数量"} + yac.Caches["npage"] = &ctx.Cache{Name: "集合数量", Value: "0", Help: "集合数量"} + yac.Caches["nhash"] = &ctx.Cache{Name: "类型数量", Value: "0", Help: "类型数量"} + + yac.Caches["nline"] = &ctx.Cache{Name: "状态数量", Value: "16", Help: "状态数量"} + yac.Caches["nnode"] = &ctx.Cache{Name: "节点数量", Value: "0", Help: "节点数量"} + yac.Caches["nreal"] = &ctx.Cache{Name: "实点数量", Value: "0", Help: "实点数量"} + + yac.Caches["level"] = &ctx.Cache{Name: "嵌套层级", Value: "0", Help: "嵌套层级"} + yac.Caches["label"] = &ctx.Cache{Name: "嵌套标记", Value: "####################", Help: "嵌套层级"} + + yac.page = map[string]int{"nil": 0} + yac.hash = map[string]int{"nil": 0} + yac.hand = map[int]string{0: "nil"} + + yac.mat = make([]map[byte]*State, m.Capi("nlang")) + yac.state = map[State]*State{} + return yac +} + +// }}} +func (yac *YAC) Start(m *ctx.Message, arg ...string) bool { // {{{ + yac.Message = m + return false +} + +// }}} +func (yac *YAC) Close(m *ctx.Message, arg ...string) bool { // {{{ + switch yac.Context { + case m.Target(): + case m.Source(): + } + return true +} + +// }}} + +var Pulse *ctx.Message +var Index = &ctx.Context{Name: "yac", Help: "语法中心", + Caches: map[string]*ctx.Cache{}, + Configs: map[string]*ctx.Config{}, + Commands: map[string]*ctx.Command{ + "train": &ctx.Command{Name: "train page hash word...", Help: "添加语法规则, page: 语法集合, hash: 语句类型, word: 语法模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) { // {{{ + page, ok := yac.page[arg[0]] + if !ok { + page = m.Capi("npage", 1) + yac.page[arg[0]] = page + } + + hash, ok := yac.hash[arg[1]] + if !ok { + hash = m.Capi("nhash", 1) + yac.hash[arg[0]] = hash + yac.hand[hash] = arg[0] + } + + if yac.lex == nil { + lex := m.Find("lex", true) + lex.Start("lyacc", "语法词法") + yac.lex = lex + } + yac.seed = append(yac.seed, &Seed{page, hash, arg[2:]}) + yac.Capi("nseed", 1) + yac.train(page, hash, arg[2:]) + } // }}} + }}, + "parse": &ctx.Command{Name: "parse page void word...", Help: "解析语句, page: 语法集合, void: 空白语法集合, word: 语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) { // {{{ + page, ok := yac.page[arg[0]] + m.Assert(ok) + void, ok := yac.page[arg[1]] + m.Assert(ok) + word, rest := yac.parse(m, page, void, strings.Join(arg[2:], " ")) + m.Add("result", rest, word...) + } // }}} + }}, + }, +} + +func init() { + yac := &YAC{} + yac.Context = Index + ctx.Index.Register(Index, yac) +} diff --git a/src/example/bench.go b/src/example/bench.go index 38e9ed1d..533f7327 100644 --- a/src/example/bench.go +++ b/src/example/bench.go @@ -12,6 +12,7 @@ import ( _ "context/web" _ "context/lex" + _ "context/yac" "os" )