func (p *Parser) errorRecovery(lex lexer.Lexer, tok lexer.Token, stateStack []ItemSetID, dataStack []interface{}) (lexer.Token, []ItemSetID, []interface{}, error) { parseErr := ParseError{ Invalid: []lexer.Token{tok}, Location: lex.Location(), } topState := stateStack[len(stateStack)-1] for expectedTok := range p.parsetable[topState] { parseErr.Expected = append(parseErr.Expected, p.Syms.Get(expectedTok)) } // rewind the state stack searching for an error rule action, found := p.parsetable[topState][syms.ERROR] for !(found && action.actiontype == Shift) { stateStack = stateStack[:len(stateStack)-1] if len(stateStack) == 0 { break } topState = stateStack[len(stateStack)-1] action, found = p.parsetable[topState][syms.ERROR] } parseErr.Valid = append(parseErr.Valid, dataStack[len(stateStack):]...) dataStack = dataStack[:len(stateStack)] if len(stateStack) == 0 { err := UnexpectedTerminalParseError("parse error; could not find a suitable error rule") dataStack = append(dataStack, parseErr) if p.debug { fmt.Println("\nParse error, no error recovery possible", p.fmtStacks(stateStack, dataStack)) } return tok, stateStack, dataStack, err } stateStack = append(stateStack, action.state) // now search for next action by discarding unfitting tokens actionMap := p.parsetable[action.state] action, found = actionMap[tok.ID] parseErr.Invalid = nil for !found { parseErr.Invalid = append(parseErr.Invalid, tok) if tok.ID == syms.EOF { err := UnexpectedTerminalParseError("parse error; could not find a suitable error rule before EOF") dataStack = append(dataStack, parseErr) if p.debug { fmt.Println("\nParse error, EOF while recovering", "\nRecovery state expected one of:", p.symNames(actionMap), p.fmtStacks(stateStack, dataStack)) } return tok, stateStack, dataStack, err } var err error tok, err = p.nextToken(lex) if err != nil { dataStack = append(dataStack, parseErr) return tok, stateStack, dataStack, err } action, found = actionMap[tok.ID] } dataStack = append(dataStack, parseErr) if p.debug { fmt.Println("\nParse error, stack unwinded", p.fmtStacks(stateStack, dataStack)) } return tok, stateStack, dataStack, nil }