forked from simoneguidi94/gopapageno
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparser_stack.go
93 lines (73 loc) · 2.09 KB
/
parser_stack.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
package gopapageno
import (
"fmt"
)
// parserStack is the base data structure used by workers during parsing.
type parserStack struct {
*LOPS[Token]
firstTerminalStack *stack[*Token]
firstTerminalPos int
}
// newParserStack creates an empty parserStack.
func newParserStack(pool *Pool[stack[*Token]]) *parserStack {
return &parserStack{
LOPS: NewLOPS[Token](pool),
}
}
// Push pushes a token pointer in the ParserStack.
// It returns the pointer itself.
func (s *parserStack) Push(token *Token) *Token {
s.LOPS.Push(token)
//If the token is a terminal update the firstTerminal pointer
if token.Type.IsTerminal() {
s.firstTerminalStack = s.LOPS.cur
s.firstTerminalPos = s.LOPS.cur.Tos - 1
}
return token
}
// FirstTerminal returns a pointer to the first terminal token on the stack.
func (s *parserStack) FirstTerminal() *Token {
return s.firstTerminalStack.Data[s.firstTerminalPos]
}
// UpdateFirstTerminal should be used after a reduction in order to update the first terminal counter.
// In fact, in order to save some time, only the Push operation automatically updates the first terminal pointer,
// while the Pop operation does not.
func (s *parserStack) UpdateFirstTerminal() {
s.firstTerminalStack, s.firstTerminalPos = s.findFirstTerminal()
}
// findFirstTerminal computes the first terminal on the stacks.
// This function is for internal usage only.
func (s *parserStack) findFirstTerminal() (*stack[*Token], int) {
curStack := s.cur
pos := curStack.Tos - 1
for pos < s.headFirst {
pos = -1
if curStack.Prev == nil {
return nil, 0
}
s.headFirst = 0
curStack = curStack.Prev
pos = curStack.Tos - 1
}
for !curStack.Data[pos].Type.IsTerminal() {
pos--
for pos < s.headFirst {
pos = -1
if curStack.Prev == nil {
return nil, 0
}
s.headFirst = 0
curStack = curStack.Prev
pos = curStack.Tos - 1
}
}
return curStack, pos
}
func (s *parserStack) LastNonterminal() (*Token, error) {
for token := s.Pop(); token != nil; token = s.Pop() {
if !token.Type.IsTerminal() {
return token, nil
}
}
return nil, fmt.Errorf("no nonterminal found")
}