我正在使用text/scanner
包来解析一些任意表达式。我当前正在尝试实现一个not in
选项,也就是说,如果当前标识符是not
,下一个是in
,请使用函数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派生的,并结合了PR from GH user generikvault和其他一些分支。完整的代码可以在我的Github profile
上找到答案 0 :(得分:3)
通过查看text/scanner
的API引用,我似乎找不到找到以所需方式倒带扫描仪的方法。
但是,Peek()
方法可以在不推进扫描仪的情况下获得下一个符文。在“不”情况下,您可以使用它来预先查看是否匹配。