217 lines
4.8 KiB
Go
217 lines
4.8 KiB
Go
// Code generated by gocc; DO NOT EDIT.
|
|
|
|
package parser
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
parseError "github.com/awalterschulze/gographviz/internal/errors"
|
|
"github.com/awalterschulze/gographviz/internal/token"
|
|
)
|
|
|
|
const (
|
|
numProductions = 60
|
|
numStates = 128
|
|
numSymbols = 36
|
|
)
|
|
|
|
// Stack
|
|
|
|
type stack struct {
|
|
state []int
|
|
attrib []Attrib
|
|
}
|
|
|
|
const iNITIAL_STACK_SIZE = 100
|
|
|
|
func newStack() *stack {
|
|
return &stack{
|
|
state: make([]int, 0, iNITIAL_STACK_SIZE),
|
|
attrib: make([]Attrib, 0, iNITIAL_STACK_SIZE),
|
|
}
|
|
}
|
|
|
|
func (s *stack) reset() {
|
|
s.state = s.state[:0]
|
|
s.attrib = s.attrib[:0]
|
|
}
|
|
|
|
func (s *stack) push(state int, a Attrib) {
|
|
s.state = append(s.state, state)
|
|
s.attrib = append(s.attrib, a)
|
|
}
|
|
|
|
func (s *stack) top() int {
|
|
return s.state[len(s.state)-1]
|
|
}
|
|
|
|
func (s *stack) peek(pos int) int {
|
|
return s.state[pos]
|
|
}
|
|
|
|
func (s *stack) topIndex() int {
|
|
return len(s.state) - 1
|
|
}
|
|
|
|
func (s *stack) popN(items int) []Attrib {
|
|
lo, hi := len(s.state)-items, len(s.state)
|
|
|
|
attrib := s.attrib[lo:hi]
|
|
|
|
s.state = s.state[:lo]
|
|
s.attrib = s.attrib[:lo]
|
|
|
|
return attrib
|
|
}
|
|
|
|
func (s *stack) String() string {
|
|
w := new(bytes.Buffer)
|
|
fmt.Fprintf(w, "stack:\n")
|
|
for i, st := range s.state {
|
|
fmt.Fprintf(w, "\t%d: %d , ", i, st)
|
|
if s.attrib[i] == nil {
|
|
fmt.Fprintf(w, "nil")
|
|
} else {
|
|
switch attr := s.attrib[i].(type) {
|
|
case *token.Token:
|
|
fmt.Fprintf(w, "%s", attr.Lit)
|
|
default:
|
|
fmt.Fprintf(w, "%v", attr)
|
|
}
|
|
}
|
|
fmt.Fprintf(w, "\n")
|
|
}
|
|
return w.String()
|
|
}
|
|
|
|
// Parser
|
|
|
|
type Parser struct {
|
|
stack *stack
|
|
nextToken *token.Token
|
|
pos int
|
|
}
|
|
|
|
type Scanner interface {
|
|
Scan() (tok *token.Token)
|
|
}
|
|
|
|
func NewParser() *Parser {
|
|
p := &Parser{stack: newStack()}
|
|
p.Reset()
|
|
return p
|
|
}
|
|
|
|
func (p *Parser) Reset() {
|
|
p.stack.reset()
|
|
p.stack.push(0, nil)
|
|
}
|
|
|
|
func (p *Parser) Error(err error, scanner Scanner) (recovered bool, errorAttrib *parseError.Error) {
|
|
errorAttrib = &parseError.Error{
|
|
Err: err,
|
|
ErrorToken: p.nextToken,
|
|
ErrorSymbols: p.popNonRecoveryStates(),
|
|
ExpectedTokens: make([]string, 0, 8),
|
|
}
|
|
for t, action := range actionTab[p.stack.top()].actions {
|
|
if action != nil {
|
|
errorAttrib.ExpectedTokens = append(errorAttrib.ExpectedTokens, token.TokMap.Id(token.Type(t)))
|
|
}
|
|
}
|
|
|
|
if action := actionTab[p.stack.top()].actions[token.TokMap.Type("error")]; action != nil {
|
|
p.stack.push(int(action.(shift)), errorAttrib) // action can only be shift
|
|
} else {
|
|
return
|
|
}
|
|
|
|
if action := actionTab[p.stack.top()].actions[p.nextToken.Type]; action != nil {
|
|
recovered = true
|
|
}
|
|
for !recovered && p.nextToken.Type != token.EOF {
|
|
p.nextToken = scanner.Scan()
|
|
if action := actionTab[p.stack.top()].actions[p.nextToken.Type]; action != nil {
|
|
recovered = true
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (p *Parser) popNonRecoveryStates() (removedAttribs []parseError.ErrorSymbol) {
|
|
if rs, ok := p.firstRecoveryState(); ok {
|
|
errorSymbols := p.stack.popN(p.stack.topIndex() - rs)
|
|
removedAttribs = make([]parseError.ErrorSymbol, len(errorSymbols))
|
|
for i, e := range errorSymbols {
|
|
removedAttribs[i] = e
|
|
}
|
|
} else {
|
|
removedAttribs = []parseError.ErrorSymbol{}
|
|
}
|
|
return
|
|
}
|
|
|
|
// recoveryState points to the highest state on the stack, which can recover
|
|
func (p *Parser) firstRecoveryState() (recoveryState int, canRecover bool) {
|
|
recoveryState, canRecover = p.stack.topIndex(), actionTab[p.stack.top()].canRecover
|
|
for recoveryState > 0 && !canRecover {
|
|
recoveryState--
|
|
canRecover = actionTab[p.stack.peek(recoveryState)].canRecover
|
|
}
|
|
return
|
|
}
|
|
|
|
func (p *Parser) newError(err error) error {
|
|
e := &parseError.Error{
|
|
Err: err,
|
|
StackTop: p.stack.top(),
|
|
ErrorToken: p.nextToken,
|
|
}
|
|
actRow := actionTab[p.stack.top()]
|
|
for i, t := range actRow.actions {
|
|
if t != nil {
|
|
e.ExpectedTokens = append(e.ExpectedTokens, token.TokMap.Id(token.Type(i)))
|
|
}
|
|
}
|
|
return e
|
|
}
|
|
|
|
func (p *Parser) Parse(scanner Scanner) (res interface{}, err error) {
|
|
p.Reset()
|
|
p.nextToken = scanner.Scan()
|
|
for acc := false; !acc; {
|
|
action := actionTab[p.stack.top()].actions[p.nextToken.Type]
|
|
if action == nil {
|
|
if recovered, errAttrib := p.Error(nil, scanner); !recovered {
|
|
p.nextToken = errAttrib.ErrorToken
|
|
return nil, p.newError(nil)
|
|
}
|
|
if action = actionTab[p.stack.top()].actions[p.nextToken.Type]; action == nil {
|
|
panic("Error recovery led to invalid action")
|
|
}
|
|
}
|
|
|
|
switch act := action.(type) {
|
|
case accept:
|
|
res = p.stack.popN(1)[0]
|
|
acc = true
|
|
case shift:
|
|
p.stack.push(int(act), p.nextToken)
|
|
p.nextToken = scanner.Scan()
|
|
case reduce:
|
|
prod := productionsTable[int(act)]
|
|
attrib, err := prod.ReduceFunc(p.stack.popN(prod.NumSymbols))
|
|
if err != nil {
|
|
return nil, p.newError(err)
|
|
} else {
|
|
p.stack.push(gotoTab[p.stack.top()][prod.NTType], attrib)
|
|
}
|
|
default:
|
|
panic("unknown action: " + action.String())
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|