ed-precompiled_racc 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/BSDL +22 -0
- data/COPYING +56 -0
- data/ChangeLog +846 -0
- data/README.ja.rdoc +58 -0
- data/README.rdoc +60 -0
- data/TODO +5 -0
- data/bin/racc +320 -0
- data/doc/en/grammar.en.rdoc +218 -0
- data/doc/en/grammar2.en.rdoc +219 -0
- data/doc/ja/command.ja.html +99 -0
- data/doc/ja/debug.ja.rdoc +36 -0
- data/doc/ja/grammar.ja.rdoc +348 -0
- data/doc/ja/index.ja.html +10 -0
- data/doc/ja/parser.ja.rdoc +125 -0
- data/doc/ja/usage.ja.html +414 -0
- data/ext/racc/cparse/cparse.c +840 -0
- data/ext/racc/cparse/extconf.rb +8 -0
- data/lib/racc/compat.rb +33 -0
- data/lib/racc/debugflags.rb +60 -0
- data/lib/racc/exception.rb +16 -0
- data/lib/racc/grammar.rb +1191 -0
- data/lib/racc/grammarfileparser.rb +667 -0
- data/lib/racc/info.rb +18 -0
- data/lib/racc/iset.rb +92 -0
- data/lib/racc/logfilegenerator.rb +212 -0
- data/lib/racc/parser-text.rb +496 -0
- data/lib/racc/parser.rb +650 -0
- data/lib/racc/parserfilegenerator.rb +473 -0
- data/lib/racc/sourcetext.rb +35 -0
- data/lib/racc/state.rb +976 -0
- data/lib/racc/statetransitiontable.rb +311 -0
- data/lib/racc/static.rb +5 -0
- data/lib/racc.rb +6 -0
- metadata +92 -0
data/README.ja.rdoc
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
= Racc
|
2
|
+
|
3
|
+
* https://github.com/ruby/racc
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Racc は LALR(1) パーサジェネレータです。
|
8
|
+
yacc の Ruby 版に相当します。
|
9
|
+
|
10
|
+
== 必要環境
|
11
|
+
|
12
|
+
* Ruby 2.5 以降
|
13
|
+
|
14
|
+
== インストール
|
15
|
+
|
16
|
+
gem インストール:
|
17
|
+
|
18
|
+
$ gem install racc
|
19
|
+
|
20
|
+
== テスト
|
21
|
+
|
22
|
+
sample/ 以下にいくつか Racc の文法ファイルのサンプルが用意
|
23
|
+
してあります。動くのも動かないのもありますが、少なくとも
|
24
|
+
calc-ja.y は動くのでこれを処理してみましょう。Racc をインス
|
25
|
+
トールしたあと
|
26
|
+
|
27
|
+
$ racc -ocalc.rb calc-ja.y
|
28
|
+
|
29
|
+
として下さい。処理は一瞬から数秒で終わるので、
|
30
|
+
|
31
|
+
$ ruby calc.rb
|
32
|
+
|
33
|
+
を実行してください。ちゃんと動いてますか?
|
34
|
+
|
35
|
+
Racc の文法など詳しいことは doc.ja/ ディレクトリ以下の HTML を
|
36
|
+
見てください。
|
37
|
+
|
38
|
+
|
39
|
+
== ライセンス
|
40
|
+
|
41
|
+
このパッケージに付属するファイルの著作権は青木峰郎が保持します。
|
42
|
+
ライセンスは Ruby ライセンスです。ただしユーザが書いた規則
|
43
|
+
ファイルや、Racc がそこから生成した Ruby スクリプトはその対象
|
44
|
+
外です。好きなライセンスで配布してください。
|
45
|
+
|
46
|
+
|
47
|
+
== バグなど
|
48
|
+
|
49
|
+
Racc を使っていてバグらしき現象に遭遇したら、下記のアドレスまで
|
50
|
+
メールをください。作者にはバグを修正する義務はありませんがその
|
51
|
+
意思はあります。また、そのときはできるだけバグを再現できる文法
|
52
|
+
ファイルを付けてください。
|
53
|
+
|
54
|
+
|
55
|
+
青木峰郎(あおきみねろう)
|
56
|
+
aamine@loveruby.net
|
57
|
+
http://i.loveruby.net
|
58
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
= Racc
|
2
|
+
|
3
|
+
* https://github.com/ruby/racc
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Racc is an LALR(1) parser generator.
|
8
|
+
It is written in Ruby itself, and generates Ruby program.
|
9
|
+
|
10
|
+
== Requirement
|
11
|
+
|
12
|
+
* Ruby 2.5 or later.
|
13
|
+
|
14
|
+
== Installation
|
15
|
+
|
16
|
+
gem install:
|
17
|
+
|
18
|
+
$ gem install racc
|
19
|
+
|
20
|
+
== Testing Racc
|
21
|
+
|
22
|
+
Racc comes with simple calculator. To compile this, on shell:
|
23
|
+
|
24
|
+
$ racc -o calc calc.y
|
25
|
+
|
26
|
+
This process costs few seconds (or less). Then type:
|
27
|
+
|
28
|
+
$ ruby calc
|
29
|
+
|
30
|
+
... Does it work?
|
31
|
+
For details of Racc, see HTML documents placed under 'doc/en/'
|
32
|
+
and sample grammar files under 'sample/'.
|
33
|
+
|
34
|
+
== Release flow
|
35
|
+
|
36
|
+
* Update VERSION number of these files
|
37
|
+
* <code>RACC_VERSION</code> in "ext/racc/com/headius/racc/Cparse.java"
|
38
|
+
* <code>VERSION</code> in "lib/racc/info.rb"
|
39
|
+
* Release as a gem by <code>rake release</code> with CRuby and JRuby because Racc gem provides 2 packages
|
40
|
+
* Create new release on {GitHub}[https://github.com/ruby/racc/releases]
|
41
|
+
|
42
|
+
== License
|
43
|
+
|
44
|
+
Racc is distributed under the same terms of ruby.
|
45
|
+
(see the file COPYING). Note that you do NOT need to follow
|
46
|
+
ruby license for your own parser (racc outputs).
|
47
|
+
You can distribute those files under any licenses you want.
|
48
|
+
|
49
|
+
|
50
|
+
== Bug Reports
|
51
|
+
|
52
|
+
Any kind of bug report is welcome.
|
53
|
+
If you find a bug of Racc, please report an issue at
|
54
|
+
https://github.com/ruby/racc/issues. Your grammar file,
|
55
|
+
debug output generated by "racc -t", are helpful.
|
56
|
+
|
57
|
+
|
58
|
+
Minero Aoki
|
59
|
+
aamine@loveruby.net
|
60
|
+
http://i.loveruby.net
|
data/TODO
ADDED
data/bin/racc
ADDED
@@ -0,0 +1,320 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# Copyright (c) 1999-2006 Minero Aoki
|
6
|
+
#
|
7
|
+
# This program is free software.
|
8
|
+
# You can distribute/modify this program under the same terms of ruby.
|
9
|
+
# see the file "COPYING".
|
10
|
+
|
11
|
+
require 'racc/static'
|
12
|
+
require 'optparse'
|
13
|
+
|
14
|
+
def main
|
15
|
+
output = nil
|
16
|
+
debug_parser = false
|
17
|
+
make_logfile = false
|
18
|
+
logfilename = nil
|
19
|
+
make_executable = false
|
20
|
+
rubypath = nil
|
21
|
+
embed_runtime = false
|
22
|
+
frozen_strings = false
|
23
|
+
debug_flags = Racc::DebugFlags.new
|
24
|
+
line_convert = true
|
25
|
+
line_convert_all = false
|
26
|
+
omit_action_call = true
|
27
|
+
superclass = nil
|
28
|
+
check_only = false
|
29
|
+
verbose = false
|
30
|
+
profiler = RaccProfiler.new(false)
|
31
|
+
|
32
|
+
parser = OptionParser.new
|
33
|
+
parser.banner = "Usage: #{File.basename($0)} [options] [input]"
|
34
|
+
parser.on('-o', '--output-file=PATH',
|
35
|
+
'output file name [<input>.tab.rb]') {|name|
|
36
|
+
output = name
|
37
|
+
}
|
38
|
+
parser.on('-t', '--debug', 'Outputs debugging parser.') {|fl|
|
39
|
+
debug_parser = fl
|
40
|
+
}
|
41
|
+
parser.on('-g', 'Equivalent to -t (obsolete).') {|fl|
|
42
|
+
$stderr.puts "racc -g is obsolete. Use racc -t instead." if $VERBOSE
|
43
|
+
debug_parser = fl
|
44
|
+
}
|
45
|
+
parser.on('-v', '--verbose',
|
46
|
+
'Creates <filename>.output log file.') {|fl|
|
47
|
+
make_logfile = fl
|
48
|
+
}
|
49
|
+
parser.on('-O', '--log-file=PATH',
|
50
|
+
'Log file name [<input>.output]') {|path|
|
51
|
+
make_logfile = true
|
52
|
+
logfilename = path
|
53
|
+
}
|
54
|
+
parser.on('-e', '--executable [RUBYPATH]', 'Makes executable parser.') {|path|
|
55
|
+
make_executable = true
|
56
|
+
rubypath = (path == 'ruby' ? nil : path)
|
57
|
+
}
|
58
|
+
parser.on('-E', '--embedded', "Embeds Racc runtime in output.") {
|
59
|
+
embed_runtime = true
|
60
|
+
}
|
61
|
+
parser.on('-F', '--frozen', "Add frozen_string_literals: true.") {
|
62
|
+
frozen_strings = true
|
63
|
+
}
|
64
|
+
parser.on('--line-convert-all', 'Converts line numbers of user codes.') {
|
65
|
+
line_convert_all = true
|
66
|
+
}
|
67
|
+
parser.on('-l', '--no-line-convert', 'Never convert line numbers.') {
|
68
|
+
line_convert = false
|
69
|
+
line_convert_all = false
|
70
|
+
}
|
71
|
+
parser.on('-a', '--no-omit-actions', 'Never omit actions.') {
|
72
|
+
omit_action_call = false
|
73
|
+
}
|
74
|
+
parser.on('--superclass=CLASSNAME',
|
75
|
+
'Uses CLASSNAME instead of Racc::Parser.') {|name|
|
76
|
+
superclass = name
|
77
|
+
}
|
78
|
+
parser.on('-C', '--check-only', 'Checks syntax and quit immediately.') {|fl|
|
79
|
+
check_only = fl
|
80
|
+
}
|
81
|
+
parser.on('-S', '--output-status', 'Outputs internal status time to time.') {
|
82
|
+
verbose = true
|
83
|
+
}
|
84
|
+
parser.on('-P', 'Enables generator profile') {
|
85
|
+
profiler = RaccProfiler.new(true)
|
86
|
+
}
|
87
|
+
parser.on('-D flags', "Flags for Racc debugging (do not use).") {|flags|
|
88
|
+
debug_flags = Racc::DebugFlags.parse_option_string(flags)
|
89
|
+
}
|
90
|
+
#parser.on('--no-extensions', 'Run Racc without any Ruby extension.') {
|
91
|
+
# Racc.const_set :Racc_No_Extensions, true
|
92
|
+
#}
|
93
|
+
parser.on('--version', 'Prints version and quit.') {
|
94
|
+
puts "racc version #{Racc::Version}"
|
95
|
+
exit
|
96
|
+
}
|
97
|
+
parser.on('--runtime-version', 'Prints runtime version and quit.') {
|
98
|
+
printf "racc runtime version %s; %s core version %s\n",
|
99
|
+
Racc::Parser::Racc_Runtime_Version,
|
100
|
+
Racc::Parser.racc_runtime_type,
|
101
|
+
if Racc::Parser.racc_runtime_type == 'ruby'
|
102
|
+
Racc::Parser::Racc_Runtime_Core_Version_R
|
103
|
+
else
|
104
|
+
Racc::Parser::Racc_Runtime_Core_Version_C
|
105
|
+
end
|
106
|
+
exit
|
107
|
+
}
|
108
|
+
parser.on('--copyright', 'Prints copyright and quit.') {
|
109
|
+
puts Racc::Copyright
|
110
|
+
exit
|
111
|
+
}
|
112
|
+
parser.on('--help', 'Prints this message and quit.') {
|
113
|
+
puts parser.help
|
114
|
+
exit
|
115
|
+
}
|
116
|
+
begin
|
117
|
+
parser.parse!
|
118
|
+
rescue OptionParser::ParseError => err
|
119
|
+
abort [err.message, parser.help].join("\n")
|
120
|
+
end
|
121
|
+
if ARGV.size > 1
|
122
|
+
abort 'too many input'
|
123
|
+
end
|
124
|
+
|
125
|
+
input = ARGV[0] || "stdin"
|
126
|
+
|
127
|
+
if input == "stdin" && !output then
|
128
|
+
abort 'You must specify a path to read or use -o <path> for output.'
|
129
|
+
end
|
130
|
+
|
131
|
+
begin
|
132
|
+
$stderr.puts 'Parsing grammar file...' if verbose
|
133
|
+
result = profiler.section('parse') {
|
134
|
+
parser = Racc::GrammarFileParser.new(debug_flags)
|
135
|
+
content = input == "stdin" ? ARGF.read : File.read(input)
|
136
|
+
parser.parse(content, File.basename(input))
|
137
|
+
}
|
138
|
+
if check_only
|
139
|
+
$stderr.puts 'syntax ok'
|
140
|
+
exit
|
141
|
+
end
|
142
|
+
|
143
|
+
$stderr.puts 'Generating LALR states...' if verbose
|
144
|
+
states = profiler.section('nfa') {
|
145
|
+
Racc::States.new(result.grammar).nfa
|
146
|
+
}
|
147
|
+
|
148
|
+
$stderr.puts "Resolving #{states.size} states..." if verbose
|
149
|
+
profiler.section('dfa') {
|
150
|
+
states.dfa
|
151
|
+
}
|
152
|
+
|
153
|
+
$stderr.puts 'Creating parser file...' if verbose
|
154
|
+
params = result.params.dup
|
155
|
+
params.filename = File.basename(input)
|
156
|
+
# Overwrites parameters given by a grammar file with command line options.
|
157
|
+
params.superclass = superclass if superclass
|
158
|
+
params.omit_action_call = true if omit_action_call
|
159
|
+
# From command line option
|
160
|
+
if make_executable
|
161
|
+
params.make_executable = true
|
162
|
+
params.interpreter = rubypath
|
163
|
+
end
|
164
|
+
params.debug_parser = debug_parser
|
165
|
+
params.convert_line = line_convert
|
166
|
+
params.convert_line_all = line_convert_all
|
167
|
+
params.embed_runtime = embed_runtime
|
168
|
+
params.frozen_strings = frozen_strings
|
169
|
+
profiler.section('generation') {
|
170
|
+
generator = Racc::ParserFileGenerator.new(states, params)
|
171
|
+
generator.generate_parser_file(output || make_filename(input, '.tab.rb'))
|
172
|
+
}
|
173
|
+
|
174
|
+
if make_logfile
|
175
|
+
profiler.section('logging') {
|
176
|
+
$stderr.puts 'Creating log file...' if verbose
|
177
|
+
logfilename ||= make_filename(output || File.basename(input), '.output')
|
178
|
+
File.open(logfilename, 'w') {|f|
|
179
|
+
Racc::LogFileGenerator.new(states, debug_flags).output f
|
180
|
+
}
|
181
|
+
}
|
182
|
+
end
|
183
|
+
if debug_flags.status_logging
|
184
|
+
log_useless states.grammar
|
185
|
+
log_conflict states
|
186
|
+
else
|
187
|
+
has_useless = report_useless states.grammar
|
188
|
+
has_conflicts = report_conflict states
|
189
|
+
if has_useless || has_conflicts
|
190
|
+
preamble = make_logfile ? 'C' : 'Turn on logging with "-v" and c'
|
191
|
+
$stderr.puts %Q{#{preamble}heck ".output" file for details}
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
profiler.report
|
196
|
+
if states.should_error_on_expect_mismatch?
|
197
|
+
raise Racc::CompileError, "#{states.grammar.n_expected_srconflicts} shift/reduce conflicts are expected but #{states.n_srconflicts} shift/reduce conflicts exist"
|
198
|
+
end
|
199
|
+
rescue Racc::Error, Errno::ENOENT, Errno::EPERM => err
|
200
|
+
raise if $DEBUG or debug_flags.any?
|
201
|
+
lineno = err.message.slice(/\A\d+:/).to_s
|
202
|
+
abort "#{File.basename $0}: #{input}:#{lineno} #{err.message.strip}"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def make_filename(path, suffix)
|
207
|
+
path.sub(/(?:\..*?)?\z/, suffix)
|
208
|
+
end
|
209
|
+
|
210
|
+
LIST_LIMIT = 10
|
211
|
+
def report_list(enum, label)
|
212
|
+
c = enum.count
|
213
|
+
if c > 0
|
214
|
+
$stderr.puts "#{c} #{label}:"
|
215
|
+
enum.first(LIST_LIMIT).each do |item|
|
216
|
+
$stderr.puts " #{yield item}"
|
217
|
+
end
|
218
|
+
$stderr.puts " ..." if c > LIST_LIMIT
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# @return [Boolean] if anything was reported
|
223
|
+
def report_conflict(states)
|
224
|
+
if states.should_report_srconflict?
|
225
|
+
reported = true
|
226
|
+
$stderr.puts "#{states.n_srconflicts} shift/reduce conflicts"
|
227
|
+
end
|
228
|
+
if states.rrconflict_exist?
|
229
|
+
reported = true
|
230
|
+
$stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts"
|
231
|
+
end
|
232
|
+
reported
|
233
|
+
end
|
234
|
+
|
235
|
+
def log_conflict(states)
|
236
|
+
logging('w') {|f|
|
237
|
+
f.puts "ex#{states.grammar.n_expected_srconflicts}"
|
238
|
+
if states.should_report_srconflict?
|
239
|
+
f.puts "sr#{states.n_srconflicts}"
|
240
|
+
end
|
241
|
+
if states.rrconflict_exist?
|
242
|
+
f.puts "rr#{states.n_rrconflicts}"
|
243
|
+
end
|
244
|
+
}
|
245
|
+
end
|
246
|
+
|
247
|
+
# @return [Boolean] if anything was reported
|
248
|
+
def report_useless(grammar)
|
249
|
+
reported = report_list(grammar.each_useless_nonterminal, 'useless nonterminals', &:to_s)
|
250
|
+
|
251
|
+
reported ||= report_list(grammar.each_useless_rule, 'useless rules') { |r| "##{r.ident} (#{r.target})" }
|
252
|
+
|
253
|
+
if grammar.start.useless?
|
254
|
+
$stderr.puts 'fatal: start symbol does not derive any sentence'
|
255
|
+
reported = true
|
256
|
+
end
|
257
|
+
reported
|
258
|
+
end
|
259
|
+
|
260
|
+
def log_useless(grammar)
|
261
|
+
logging('a') {|f|
|
262
|
+
if grammar.useless_nonterminal_exist?
|
263
|
+
f.puts "un#{grammar.n_useless_nonterminals}"
|
264
|
+
end
|
265
|
+
if grammar.useless_rule_exist?
|
266
|
+
f.puts "ur#{grammar.n_useless_rules}"
|
267
|
+
end
|
268
|
+
}
|
269
|
+
end
|
270
|
+
|
271
|
+
def logging(mode, &block)
|
272
|
+
File.open("log/#{File.basename(ARGV[0])}", mode, &block)
|
273
|
+
end
|
274
|
+
|
275
|
+
class RaccProfiler
|
276
|
+
def initialize(really)
|
277
|
+
@really = really
|
278
|
+
@log = []
|
279
|
+
end
|
280
|
+
|
281
|
+
def section(name)
|
282
|
+
if @really
|
283
|
+
t1 = ::Process.times.utime
|
284
|
+
result = yield
|
285
|
+
t2 = ::Process.times.utime
|
286
|
+
@log.push [name, t2 - t1]
|
287
|
+
result
|
288
|
+
else
|
289
|
+
yield
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def report
|
294
|
+
return unless @really
|
295
|
+
f = $stderr
|
296
|
+
total = cumulative_time()
|
297
|
+
f.puts '--task-----------+--sec------+---%-'
|
298
|
+
@log.each do |name, time|
|
299
|
+
f.printf "%-19s %s %3d%%\n", name, pjust(time,4,4), (time/total*100).to_i
|
300
|
+
end
|
301
|
+
f.puts '-----------------+-----------+-----'
|
302
|
+
f.printf "%-20s%s\n", 'total', pjust(total,4,4)
|
303
|
+
end
|
304
|
+
|
305
|
+
private
|
306
|
+
|
307
|
+
def cumulative_time
|
308
|
+
t = @log.inject(0) {|sum, (name, time)| sum + time }
|
309
|
+
t == 0 ? 0.01 : t
|
310
|
+
end
|
311
|
+
|
312
|
+
def pjust(num, i, j)
|
313
|
+
m = /(\d+)(\.\d+)?/.match(num.to_s)
|
314
|
+
str = m[1].rjust(i)
|
315
|
+
str.concat m[2].ljust(j+1)[0,j+1] if m[2]
|
316
|
+
str
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
main
|
@@ -0,0 +1,218 @@
|
|
1
|
+
= Racc Grammar File Reference
|
2
|
+
|
3
|
+
== Global Structure
|
4
|
+
|
5
|
+
== Class Block and User Code Block
|
6
|
+
|
7
|
+
There are two top-level blocks: the 'class' block, and the 'user code'
|
8
|
+
block. The 'user code' block MUST be after the 'class' block.
|
9
|
+
|
10
|
+
== Comment
|
11
|
+
|
12
|
+
Comments can be added about everywhere. Two comment styles are
|
13
|
+
supported: Ruby style (`# ...`) and C style (`/* ... */`).
|
14
|
+
|
15
|
+
== Class Block
|
16
|
+
|
17
|
+
The class block is formed like this:
|
18
|
+
|
19
|
+
class CLASS_NAME
|
20
|
+
[precedence table]
|
21
|
+
[token declarations]
|
22
|
+
[expected number of S/R conflict]
|
23
|
+
[options]
|
24
|
+
[semantic value conversion]
|
25
|
+
[start rule]
|
26
|
+
rule
|
27
|
+
GRAMMARS
|
28
|
+
|
29
|
+
CLASS_NAME is a name of parser class.
|
30
|
+
This is the name of generating parser class.
|
31
|
+
|
32
|
+
If CLASS_NAME includes '::', Racc outputs module clause.
|
33
|
+
For example, writing "class M::C" causes creating the code below:
|
34
|
+
|
35
|
+
module M
|
36
|
+
class C
|
37
|
+
:
|
38
|
+
:
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
== Grammar Block
|
43
|
+
|
44
|
+
The grammar block describes the grammar
|
45
|
+
to be understood by parser. Syntax is:
|
46
|
+
|
47
|
+
(token): (token) (token) (token).... (action)
|
48
|
+
|
49
|
+
(token): (token) (token) (token).... (action)
|
50
|
+
| (token) (token) (token).... (action)
|
51
|
+
| (token) (token) (token).... (action)
|
52
|
+
|
53
|
+
(action) is an action which is executed when its (token)s are found.
|
54
|
+
(action) is a ruby code block, which is surrounded by braces:
|
55
|
+
|
56
|
+
{ print val[0]
|
57
|
+
puts val[1] }
|
58
|
+
|
59
|
+
Note that you cannot use '%' string, here document, '%r' regexp in action.
|
60
|
+
|
61
|
+
Actions can be omitted.
|
62
|
+
When it is omitted, '' (empty string) is used.
|
63
|
+
|
64
|
+
A return value of action is a value of left side value ($$).
|
65
|
+
It is value of result, or returned value by "return" statement.
|
66
|
+
|
67
|
+
Here is an example of whole grammar block.
|
68
|
+
|
69
|
+
rule
|
70
|
+
goal: definition rules source { result = val }
|
71
|
+
|
72
|
+
definition: /* none */ { result = [] }
|
73
|
+
| definition startdesig { result[0] = val[1] }
|
74
|
+
| definition
|
75
|
+
precrule # this line continue from upper line
|
76
|
+
{
|
77
|
+
result[1] = val[1]
|
78
|
+
}
|
79
|
+
|
80
|
+
startdesig: START TOKEN
|
81
|
+
|
82
|
+
You can use following special local variables in action.
|
83
|
+
|
84
|
+
* result ($$)
|
85
|
+
|
86
|
+
The value of left-hand side (lhs). A default value is val[0].
|
87
|
+
|
88
|
+
* val ($1,$2,$3...)
|
89
|
+
|
90
|
+
An array of value of right-hand side (rhs).
|
91
|
+
|
92
|
+
* _values (...$-2,$-1,$0)
|
93
|
+
|
94
|
+
A stack of values.
|
95
|
+
DO NOT MODIFY this stack unless you know what you are doing.
|
96
|
+
|
97
|
+
== Operator Precedence
|
98
|
+
|
99
|
+
This function is equal to '%prec' in yacc.
|
100
|
+
To designate this block:
|
101
|
+
|
102
|
+
prechigh
|
103
|
+
nonassoc '++'
|
104
|
+
left '*' '/'
|
105
|
+
left '+' '-'
|
106
|
+
right '='
|
107
|
+
preclow
|
108
|
+
|
109
|
+
`right' is yacc's %right, `left' is yacc's %left.
|
110
|
+
|
111
|
+
`=' + (symbol) means yacc's %prec:
|
112
|
+
|
113
|
+
prechigh
|
114
|
+
nonassoc UMINUS
|
115
|
+
left '*' '/'
|
116
|
+
left '+' '-'
|
117
|
+
preclow
|
118
|
+
|
119
|
+
rule
|
120
|
+
exp: exp '*' exp
|
121
|
+
| exp '-' exp
|
122
|
+
| '-' exp =UMINUS # equals to "%prec UMINUS"
|
123
|
+
:
|
124
|
+
:
|
125
|
+
|
126
|
+
== expect
|
127
|
+
|
128
|
+
Racc supports Bison's "expect" directive to declare the expected
|
129
|
+
number of shift/reduce conflicts.
|
130
|
+
|
131
|
+
class MyParser
|
132
|
+
expect 3
|
133
|
+
rule
|
134
|
+
:
|
135
|
+
:
|
136
|
+
|
137
|
+
Then warnings are issued only when the effective number of conflicts differs.
|
138
|
+
|
139
|
+
== Declaring Tokens
|
140
|
+
|
141
|
+
Declaring tokens avoids many bugs.
|
142
|
+
|
143
|
+
Racc outputs warnings for declared tokens that do not exist, or existing tokens not declared.
|
144
|
+
The syntax is:
|
145
|
+
|
146
|
+
token TOKEN_NAME AND_IS_THIS
|
147
|
+
ALSO_THIS_IS AGAIN_AND_AGAIN THIS_IS_LAST
|
148
|
+
|
149
|
+
== Options
|
150
|
+
|
151
|
+
You can write options for racc command in your racc file.
|
152
|
+
|
153
|
+
options OPTION OPTION ...
|
154
|
+
|
155
|
+
Options are:
|
156
|
+
|
157
|
+
* omit_action_call
|
158
|
+
|
159
|
+
omit empty action call or not.
|
160
|
+
|
161
|
+
* result_var
|
162
|
+
|
163
|
+
use/does not use local variable "result"
|
164
|
+
|
165
|
+
You can use 'no_' prefix to invert its meanings.
|
166
|
+
|
167
|
+
== Converting Token Symbol
|
168
|
+
|
169
|
+
Token symbols are, as default,
|
170
|
+
|
171
|
+
* naked token strings in racc file (TOK, XFILE, this_is_token, ...)
|
172
|
+
--> symbol (:TOK, :XFILE, :this_is_token, ...)
|
173
|
+
* quoted strings (':', '.', '(', ...)
|
174
|
+
--> same string (':', '.', '(', ...)
|
175
|
+
|
176
|
+
You can change this default using a "convert" block.
|
177
|
+
Here is an example:
|
178
|
+
|
179
|
+
convert
|
180
|
+
PLUS 'PlusClass' # We use PlusClass for symbol of `PLUS'
|
181
|
+
MIN 'MinusClass' # We use MinusClass for symbol of `MIN'
|
182
|
+
end
|
183
|
+
|
184
|
+
We can use almost all ruby value can be used by token symbol,
|
185
|
+
except 'false' and 'nil'. These are causes unexpected parse error.
|
186
|
+
|
187
|
+
If you want to use String as token symbol, special care is required.
|
188
|
+
For example:
|
189
|
+
|
190
|
+
convert
|
191
|
+
class '"cls"' # in code, "cls"
|
192
|
+
PLUS '"plus\n"' # in code, "plus\n"
|
193
|
+
MIN "\"minus#{val}\"" # in code, \"minus#{val}\"
|
194
|
+
end
|
195
|
+
|
196
|
+
== Start Rule
|
197
|
+
|
198
|
+
'%start' in yacc. This changes the start symbol.
|
199
|
+
|
200
|
+
start real_target
|
201
|
+
|
202
|
+
== User Code Block
|
203
|
+
|
204
|
+
A "User Code Block" is a piece of Ruby source code copied in the output.
|
205
|
+
There are three user code blocks, "header" "inner" and "footer".
|
206
|
+
|
207
|
+
User code blocks are introduced by four '-' at the beginning of a line,
|
208
|
+
followed by a single-word name:
|
209
|
+
|
210
|
+
---- header
|
211
|
+
ruby statement
|
212
|
+
ruby statement
|
213
|
+
ruby statement
|
214
|
+
|
215
|
+
---- inner
|
216
|
+
ruby statement
|
217
|
+
:
|
218
|
+
:
|