-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.go
147 lines (122 loc) · 3.1 KB
/
parser.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package merak
import (
"errors"
"fmt"
"github.com/Orlion/merak/container"
"github.com/Orlion/merak/first_set"
"github.com/Orlion/merak/item"
"github.com/Orlion/merak/lexer"
"github.com/Orlion/merak/lr"
"github.com/Orlion/merak/symbol"
)
var (
SyntaxErr = errors.New("syntax error")
)
func newSyntaxErr(unexpected lexer.Token) error {
return fmt.Errorf("%s:%d:%d: %w: unexpected %s", unexpected.Filename(), unexpected.Line(), unexpected.Col(), SyntaxErr, unexpected.ToString())
}
type Parser struct {
at *lr.ActionTable
itm *item.Manager
fsb *first_set.Builder
}
func NewParser() *Parser {
return &Parser{
itm: item.NewManager(),
fsb: first_set.NewBuilder(),
}
}
// Register production to this parser
func (parser *Parser) RegProduction(result symbol.Symbol, params []symbol.Symbol, callback item.Callback) (err error) {
if result.IsTerminal() {
err = errors.New("result cannot be a terminator")
return
}
parser.itm.Reg(result, params, callback)
parser.fsb.Reg(result, params)
return
}
func (parser *Parser) buildActionTable(goal symbol.Symbol, eoi symbol.Symbol) (err error) {
if parser.at != nil {
return
}
// build first set
fs, err := parser.fsb.Build()
if err != nil {
return
}
// build action table
parser.at, err = lr.NewActionTableBuilder(parser.itm, fs).Build(goal, eoi)
if err != nil {
return
}
return
}
// Parse Input
func (parser *Parser) Parse(goal symbol.Symbol, eoi symbol.Symbol, l lexer.Lexer) (result symbol.Value, err error) {
var (
state int
action *lr.Action
args []symbol.Value
currentSymbolValue symbol.Value
currentSymbol symbol.Symbol
)
err = parser.buildActionTable(goal, eoi)
if err != nil {
return
}
lexerDelegator := lexer.NewLexerDelegator(l)
token, err := lexerDelegator.Next()
if err != nil {
return
}
currentSymbolValue = token.ToSymbol()
currentSymbol = currentSymbolValue.Symbol()
stateStack := container.NewStack()
valueStack := container.NewStack()
symbolStack := container.NewStack()
stateStack.Push(0)
Loop:
for {
state = stateStack.Top().(int)
if state == 0 && currentSymbol == goal {
break Loop
}
action, err = parser.at.Action(state, currentSymbol)
if err != nil {
err = newSyntaxErr(token)
break Loop
}
switch action.Type() {
case lr.ActionReduce:
args = []symbol.Value{}
paramsNum := action.ParamsNum()
for i := paramsNum; i > 0; i-- {
stateStack.Pop()
symbolStack.Pop()
args = append(args, valueStack.Pop().(symbol.Value))
}
for j := 0; j < paramsNum/2; j++ {
temp := args[j]
args[j] = args[paramsNum-1-j]
args[paramsNum-1-j] = temp
}
result = action.Reduce(args...)
currentSymbol = result.Symbol()
symbolStack.Push(currentSymbol)
valueStack.Push(result)
case lr.ActionShift:
stateStack.Push(action.State())
symbolStack.Push(currentSymbol)
if currentSymbol.IsTerminal() {
valueStack.Push(currentSymbolValue)
if token, err = lexerDelegator.Next(); err != nil {
break Loop
}
}
currentSymbolValue = token.ToSymbol()
currentSymbol = currentSymbolValue.Symbol()
}
}
return
}