-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbison_parser.rby
167 lines (145 loc) · 3.25 KB
/
bison_parser.rby
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
%token IDENTIFIER
%token NUMBER
%token STRING
%token COLON
%token SEMICOLON
%token LBRACK
%token RBRACK
%token PIPE
%token HASH
%token DOUBLE_HASH
%token KW_TOKEN
%token KW_LEFT
%token KW_RIGHT
%token ACTIONS
%%
grammar_file :
token_list[tokens] DOUBLE_HASH grammar_rules[rules] optional_code[code]
{ self.result = Bison::GrammarFile.new(tokens, rules, code) }
;
optional_code :
{ nil }
|
DOUBLE_HASH ACTIONS[actions]
{ actions }
;
token_list :
{ [] }
|
token_list[list] token[token]
{ list << token }
;
token:
HASH KW_TOKEN IDENTIFIER[name]
{ Bison::Token.new(name) }
| assoc_token
| token[token] NUMBER[num]
{ token.tap{ |t| t.number = num } }
;
assoc_token:
HASH KW_LEFT IDENTIFIER[name]
{ Bison::Token.new(name, :left) }
|
HASH KW_RIGHT IDENTIFIER[name]
{ Bison::Token.new(name, :right) }
|
assoc_token[token] IDENTIFIER[name]
{ token.tap{ |t| t.names << name } }
;
grammar_rules:
{ [] }
|
grammar_rules[list] grammar_rule[rule]
{ list << rule }
;
grammar_rule:
IDENTIFIER[name] COLON components[components] SEMICOLON
{ Bison::Rule.new(name, components).tap{ |r| r.location = @name } }
;
components:
sequence[sequence]
{ [sequence] }
|
components[sequences] PIPE sequence[sequence]
{ sequences << sequence }
;
sequence:
{ Bison::Sequence.new }
| sequence[sequence] ACTIONS[code]
{ sequence << Bison::Action.new(code).tap{ |a| a.location = @code } }
|
sequence[sequence] IDENTIFIER[follower]
{ sequence << Bison::Nonterminal.new(follower).tap{ |x| x.location = @follower } }
|
sequence[sequence] IDENTIFIER[follower] LBRACK IDENTIFIER[tag] RBRACK
{ sequence << Bison::Nonterminal.new(follower, tag).tap{ |x| x.location = @follower } }
;
%%
class BisonParser
attr_accessor :section
def lex
self.section ||= 0
self.lex_value = nil
if section == 2
self.lex_value = io.read
self.section += 2
return Tokens::ACTIONS
end
c = read_over_whitespace(line_comment_prefix: '#')
return nil unless c
case c
when ':'
return Tokens::COLON
when ';'
return Tokens::SEMICOLON
when '|'
return Tokens::PIPE
when '%'
if self.peak == '%'
self.read
self.section += 1
return Tokens::DOUBLE_HASH
end
return Tokens::HASH
when '['
return Tokens::LBRACK
when ']'
return Tokens::RBRACK
when '{'
nesting = 1
action = ''
while (c = self.read) && nesting > 0
nesting += 1 if c == '{'
nesting -= 1 if c == '}'
action << c unless nesting.zero?
end
self.lex_value = action
return Tokens::ACTIONS
when '0'..'9'
number = c
while (c = self.peak) && ('0'..'9').include?(c)
number << self.read
end
self.lex_value = number.to_i
return Tokens::NUMBER
end
if c =~ /\w/
string = c
while (c = self.peak) && c =~ /\w/
self.read
string << c
end
if section.zero? && string == 'token'
return Tokens::KW_TOKEN
elsif section.zero? && string == 'left'
return Tokens::KW_LEFT
elsif section.zero? && string == 'right'
return Tokens::KW_RIGHT
else
self.lex_value = string
return Tokens::IDENTIFIER
end
end
return nil
end
end