Ejemplo n.º 1
0
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))
			}
		}
	}
}