-
Notifications
You must be signed in to change notification settings - Fork 2
/
parse.go
148 lines (138 loc) · 3.27 KB
/
parse.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
148
package main
import (
"fmt"
"os"
"container/vector"
)
func parseHeader() {
for word, err := nextWord(); err == nil && word.text != "%%"; word, err = nextWord() {
if word.ttype == newline {
continue
}
switch {
case word.text == "%dev":
dev = true
case word.text == "%package":
word, err = nextWord()
packageName = word.text
case word.text == "%union":
word, err = nextWord() // {
word, err = nextWord() // newline
parseUnionEntries()
case word.text == "%import":
for word, err := nextWord(); err == nil && word.ttype != newline; word, err = nextWord() {
imports.Push(word.text)
}
case len(word.text) > 6 && word.text[0:5] == "%type":
parseTypedEntries(word.text[6 : len(word.text)-1])
case len(word.text) > 7 && word.text[0:6] == "%token":
parseTypedEntries(word.text[7 : len(word.text)-1])
case word.text == "%defaultcode":
memorizeTerms = true
code, _ := nextWord()
defaultcode = code.text
memorizeTerms = false
default:
fmt.Println("Unrecognized header entry:", word.text)
}
}
memorizeTerms = true
}
func parseTypedEntries(etype string) {
for name, err := nextWord(); err == nil && name.ttype != newline; name, err = nextWord() {
typedEntries[name.text] = etype
}
}
func parseUnionEntries() {
for name, err := nextWord(); err == nil && name.text != "}"; name, err = nextWord() {
etype := ""
for typespec, err := nextWord(); err == nil && typespec.ttype != newline; typespec, err = nextWord() {
etype += typespec.text
}
unionEntries[name.text] = etype
}
}
func parseProductions() {
for word, err := nextWord(); err == nil && word.text != "%%"; word, err = nextWord() {
if word.ttype == newline {
continue
}
if word.ttype != nonterm {
fmt.Println("Expected non-terminal but got", word.text)
return
}
prod := new(production)
prod.name = word.text
prods.Push(prod)
word, err = nextWord()
if word.ttype != begindef {
fmt.Println("Expected ':' but got", word.text)
return
}
parseProduction(prod)
}
for _, p := range prods {
prod := p.(*production)
if len(prod.code) == 0 {
prod.code = defaultcode
}
}
memorizeTerms = false
terms["%%"] = 0, false
}
func parseProduction(prod *production) {
for word, err := nextWord(); err == nil && word.ttype != enddef; word, err = nextWord() {
HandleProductionToken:
switch word.ttype {
case code:
prod.code = word.text
case newline:
word, err = nextWord()
goto HandleProductionToken
case alternate:
prod = &production{prod.name, vector.Vector{}, ""}
prods.Push(prod)
case enddef:
return
default:
prod.seq.Push(word)
}
}
}
func nextWord() (word tok, err os.Error) {
word, err = s.nextWord()
if word.text == "#" {
for true {
word, err = s.nextWord()
if word.ttype == newline {
break
}
}
}
if memorizeTerms {
switch word.ttype {
case term:
if _, ok := terms[word.text]; !ok {
terms[word.text] = len(terms)
}
case nonterm:
if _, ok := nonterms[word.text]; !ok {
nonterms[word.text] = len(nonterms)
}
}
}
return
}
func firstsFor(name string) (output *set) {
output = &set{}
for i, p := range prods {
prod := p.(*production)
if prod.name == name {
output.Union(firsts[i])
}
}
return
}
func followsFor(name string) *set {
return follows[nonterms[name]]
}