func (p *Parser) Parse(lex lexer.Lexer) (interface{}, error) { defer tlog.FuncLog(tlog.Func("Parse")) stateStack := []ItemSetID{ItemSetID(0)} dataStack := make([]interface{}, 1, 1) // first is nil tok, err := p.nextToken(lex) if err != nil { return tok, err } if p.debug { fmt.Println("\nInitial token", tok.String(p.Syms), p.fmtStacks(stateStack, dataStack)) } for { topState := stateStack[len(stateStack)-1] action, found := p.parsetable[topState][tok.ID] if !found { action, found = p.parsetable[topState][syms.EMPTY] if found { lex.Unread() tok = lexer.Token{ID: syms.EMPTY, Str: ""} } } if !found { // parsing error tok, stateStack, dataStack, err = p.errorRecovery(lex, tok, stateStack, dataStack) _ = "breakpoint" if err != nil { return dataStack, err } topState = stateStack[len(stateStack)-1] action, found = p.parsetable[topState][tok.ID] } if action.actiontype == Shift { stateStack = append(stateStack, action.state) dataStack = append(dataStack, tok) if p.debug { fmt.Println("\nShifted token", tok.String(p.Syms), p.fmtStacks(stateStack, dataStack)) } tok, err = p.nextToken(lex) if err != nil { dataStack = append(dataStack, tok) return dataStack, err } } else if action.actiontype == Reduce { rule := p.Rules.Get(action.ruleID) cutoff := len(stateStack) - len(rule.RHS) if cutoff < 0 { tlog.Panic("should reduce, but not enough elements on stack.", "\nReduce before token ", tok.String(p.Syms), "\nRule: ", rule.String(*p.Syms, -1), p.fmtStacks(stateStack, dataStack)) } userFn := rule.UserFn if userFn == nil { userFn = grammar.NilUserFn } newdata, err := userFn(p.Grammar, rule, dataStack[cutoff:]) if err != nil { return newdata, UserCallbackParseError( fmt.Sprint("user callback error on reduce. ", "\nReduce before token ", tok.String(p.Syms), "\nRule: ", rule.String(*p.Syms, -1), p.fmtStacks(stateStack, dataStack))) } dataStack = dataStack[:cutoff] dataStack = append(dataStack, newdata) stateStack = stateStack[:cutoff] topState = stateStack[len(stateStack)-1] if topState == 0 && len(stateStack) == 1 && tok.ID == syms.EOF { if p.debug { fmt.Println( "\nFinal Reduce, before token ", tok.String(p.Syms), "\nRule: ", rule.String(*p.Syms, -1), "\nReduced to state:", topState, p.fmtStacks(stateStack, dataStack)) } return newdata, nil } action2, found := p.parsetable[topState][rule.LHS] if !found { tlog.Panic("internal parser error, no goto state. ", "\nAfter Reduce, before token ", tok.String(p.Syms), "\nRule: ", rule.String(*p.Syms, -1), p.fmtStacks(stateStack, dataStack)) } if action2.actiontype != Goto { tlog.Panic("internal parser error, expected goto action, instead got: ", action2, "\nAfter Reduce, before token ", tok.String(p.Syms), "\nRule: ", rule.String(*p.Syms, -1), p.fmtStacks(stateStack, dataStack)) } stateStack = append(stateStack, action2.state) // a reduce does not consume the terminal if p.debug { fmt.Println( "\nAfter Reduce, before token: ", tok.String(p.Syms), "\nRule: ", rule.String(*p.Syms, -1), "\nReduced to state:", topState, "and GOTO state", action2.state, p.fmtStacks(stateStack, dataStack)) } } } }