aboutsummaryrefslogtreecommitdiff
path: root/grammar/slr1.go
blob: b11a66f48558e2a8cb751e8beb0309b4be980be1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package grammar

import "fmt"

type slr1Automaton struct {
	*lr0Automaton
}

func genSLR1Automaton(lr0 *lr0Automaton, prods *productionSet, follow *followSet) (*slr1Automaton, error) {
	for _, state := range lr0.states {
		for prodID := range state.reducible {
			prod, ok := prods.findByID(prodID)
			if !ok {
				return nil, fmt.Errorf("reducible production not found: %v", prodID)
			}

			flw, err := follow.find(prod.lhs)
			if err != nil {
				return nil, err
			}

			var reducibleItem *lrItem
			for _, item := range state.items {
				if item.prod != prodID {
					continue
				}

				reducibleItem = item
				break
			}
			if reducibleItem == nil {
				for _, item := range state.emptyProdItems {
					if item.prod != prodID {
						continue
					}

					reducibleItem = item
					break
				}
				if reducibleItem == nil {
					return nil, fmt.Errorf("reducible item not found; state: %v, production: %v", state.num, prodID)
				}
			}

			if reducibleItem.lookAhead.symbols == nil {
				reducibleItem.lookAhead.symbols = map[symbol]struct{}{}
			}

			for sym := range flw.symbols {
				reducibleItem.lookAhead.symbols[sym] = struct{}{}
			}
			if flw.eof {
				reducibleItem.lookAhead.symbols[symbolEOF] = struct{}{}
			}
		}
	}

	return &slr1Automaton{
		lr0Automaton: lr0,
	}, nil
}