如何在Go的文本/扫描仪中快退?

时间:2019-10-13 00:45:08

标签: parsing go rune

我正在使用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

上找到

1 个答案:

答案 0 :(得分:3)

通过查看text/scanner的API引用,我似乎找不到找到以所需方式倒带扫描仪的方法。

但是,Peek()方法可以在不推进扫描仪的情况下获得下一个符文。在“不”情况下,您可以使用它来预先查看是否匹配。