我正在使用text/scanner
包来解析一些任意表达式。我目前正在尝试实现一个not in
选项,即如果当前标识符是not
,而下一个是in
,则使用 function 解析它notin(left, right)
,否则我们将其解析为negate(right)
。
我基本上已经获得了管理这些情况的代码,但是,如果下一个令牌不是,我无法倒带扫描仪in
。我已经尝试通过记录位置然后重新分配它,但无济于事并且无法找到不同的解决方案。
func readToken(stream *scanner.Scanner) {
switch stream.Scan() {
case scanner.Ident:
switch stream.TokenText() {
case "in":
in(left, right)
case "not":
oldPosition := stream.Position
nextToken := stream.Scan()
if nextToken == scanner.Ident {
switch stream.TokenText() {
case "in":
fmt.Println("notin")
default:
// how do we rewind the scanner?
stream.Position = oldPosition
fmt.Println("negate default")
}
} else {
fmt.Println("negate no-ident")
}
}
}
}
找不到有效标识符时,如何倒带扫描仪?
编辑,我也尝试Peek()
如下使用,但这仍然会将状态更改为我需要倒带的点。
// other code
case "not":
nextIdent, err := getNextIdent(stream)
if err != nil {
fmt.Println("negate no-ident")
} else {
switch nextIdent {
case "in":
fmt.Println("notin")
default:
fmt.Println("negate default")
}
}
// other code
func getNextIdent(s *scanner.Scanner) (string, error) {
var nextIdent string
ch := s.Peek()
// skip white space
for s.Whitespace&(1<<uint(ch)) != 0 {
ch = s.Next()
}
if isIdentRune(ch, 0) {
nextIdent = string(ch)
ch = s.Next()
nextIdent += string(ch)
for i := 1; isIdentRune(ch, i); i++ {
ch = s.Next()
if s.Whitespace&(1<<uint(ch)) != 0 {
break
}
nextIdent += string(ch)
}
return nextIdent, nil
}
return "",errors.New("not a ident")
}
请注意,我得到的代码是来自Knetic/govaluate的分叉,以及来自 GH 用户generikvault的PR和其他一些分叉。完整代码可以在我的Github 个人资料中找到