-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtable-row.go
127 lines (107 loc) · 3.19 KB
/
table-row.go
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package lr0
import (
"fmt"
"github.com/pkg/errors"
"github.com/vovan-ve/go-lr0-parser/internal/helpers"
)
//// Row is a single row of a Table
////
//// https://en.wikipedia.org/wiki/LR_parser#Table_construction
//type Row interface {
// // AcceptEof returns true if this state accepts EOF
// AcceptEof() bool
// // TerminalsSet returns all terminals possible in this state
// TerminalsSet() readonlyIdSet
// // TerminalAction returns next state index for the given terminal
// TerminalAction(id Id) (tableStateIndex, bool)
// // GotoAction returns next state index for the given non-terminal
// GotoAction(id Id) (tableStateIndex, bool)
// // ReduceRule returns a reduce rule if available or nil otherwise
// ReduceRule() Rule
// // IsReduceOnly returns true if this state can only be used for reduce
// IsReduceOnly() bool
//}
func newTableRow() *tableRow {
return &tableRow{
terminalsSet: newIdSet(),
terminals: make(stateActions),
gotos: make(stateActions),
}
}
type tableRow struct {
acceptEof bool
terminalsSet idSet
terminals stateActions
gotos stateActions
reduceRule Rule
}
func (r *tableRow) AcceptEof() bool { return r.acceptEof }
func (r *tableRow) SetAcceptEof() { r.acceptEof = true }
func (r *tableRow) ReduceRule() Rule { return r.reduceRule }
func (r *tableRow) SetReduceRule(v Rule) { r.reduceRule = v }
func (r *tableRow) TerminalsSet() readonlyIdSet { return r.terminalsSet }
func (r *tableRow) TerminalAction(id Id) (tableStateIndex, bool) {
idx, ok := r.terminals[id]
return idx, ok
}
func (r *tableRow) SetTerminalAction(id Id, idx tableStateIndex) {
// impossible to predict or check order of overlapping terminals here
// example is plus `+` and increment `++`
// a `+` can incorrectly match a part of increment `++` which is incorrect
if v, ok := r.terminals[id]; ok && v != idx {
panic(errors.Wrap(ErrInternal, "already was set to different index"))
}
r.terminalsSet.Add(id)
r.terminals[id] = idx
}
func (r *tableRow) GotoAction(id Id) (tableStateIndex, bool) {
idx, ok := r.gotos[id]
return idx, ok
}
func (r *tableRow) SetGoto(id Id, idx tableStateIndex) {
if v, ok := r.gotos[id]; ok && v != idx {
panic(errors.Wrap(ErrInternal, "already was set to different index"))
}
r.gotos[id] = idx
}
func (r *tableRow) IsReduceOnly() bool {
return !r.acceptEof &&
len(r.terminals) == 0 &&
len(r.gotos) == 0 &&
r.reduceRule != nil
}
func (r *tableRow) dump(indent string, reg SymbolRegistry) string {
res := indent + "EOF: "
if r.acceptEof {
res += "-"
} else {
res += "ACCEPT"
}
res += "\n" + indent + "terminals:"
if len(r.terminals) != 0 {
res += "\n" + r.terminals.dump(indent+"\t", reg)
} else {
res += " -\n"
}
res += indent + "goto:"
if len(r.gotos) != 0 {
res += "\n" + r.gotos.dump(indent+"\t", reg)
} else {
res += " -\n"
}
res += indent + "rule:"
if r.reduceRule != nil {
res += "\n" + indent + "\t" + r.ReduceRule().String() + "\n"
} else {
res += " -\n"
}
return res
}
type stateActions map[Id]tableStateIndex
func (s stateActions) dump(indent string, r SymbolRegistry) string {
res := ""
for _, p := range helpers.MapSortedInt(s) {
res += indent + fmt.Sprintf("%s -> %v\n", dumpId(p.K, r), p.V)
}
return res
}