racc 1.4.6

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.
Files changed (109) hide show
  1. data/.gitattributes +2 -0
  2. data/.gitignore +7 -0
  3. data/COPYING +515 -0
  4. data/ChangeLog +846 -0
  5. data/DEPENDS +4 -0
  6. data/README.en.rdoc +86 -0
  7. data/README.ja.rdoc +96 -0
  8. data/Rakefile +15 -0
  9. data/TODO +5 -0
  10. data/bin/racc +308 -0
  11. data/bin/racc2y +195 -0
  12. data/bin/y2racc +339 -0
  13. data/doc/en/NEWS.en.rdoc +282 -0
  14. data/doc/en/command.en.html +78 -0
  15. data/doc/en/debug.en.rdoc +20 -0
  16. data/doc/en/grammar.en.rdoc +230 -0
  17. data/doc/en/index.en.html +10 -0
  18. data/doc/en/parser.en.rdoc +74 -0
  19. data/doc/en/usage.en.html +92 -0
  20. data/doc/ja/NEWS.ja.rdoc +307 -0
  21. data/doc/ja/command.ja.html +94 -0
  22. data/doc/ja/debug.ja.rdoc +36 -0
  23. data/doc/ja/grammar.ja.rdoc +348 -0
  24. data/doc/ja/index.ja.html +10 -0
  25. data/doc/ja/parser.ja.rdoc +125 -0
  26. data/doc/ja/usage.ja.html +414 -0
  27. data/ext/racc/cparse/MANIFEST +4 -0
  28. data/ext/racc/cparse/cparse.c +824 -0
  29. data/ext/racc/cparse/depend +1 -0
  30. data/ext/racc/cparse/extconf.rb +7 -0
  31. data/fastcache/extconf.rb +2 -0
  32. data/fastcache/fastcache.c +185 -0
  33. data/lib/racc.rb +6 -0
  34. data/lib/racc/compat.rb +40 -0
  35. data/lib/racc/debugflags.rb +59 -0
  36. data/lib/racc/exception.rb +15 -0
  37. data/lib/racc/grammar.rb +1115 -0
  38. data/lib/racc/grammarfileparser.rb +559 -0
  39. data/lib/racc/info.rb +16 -0
  40. data/lib/racc/iset.rb +91 -0
  41. data/lib/racc/logfilegenerator.rb +214 -0
  42. data/lib/racc/parser.rb +439 -0
  43. data/lib/racc/parserfilegenerator.rb +511 -0
  44. data/lib/racc/pre-setup +13 -0
  45. data/lib/racc/sourcetext.rb +34 -0
  46. data/lib/racc/state.rb +971 -0
  47. data/lib/racc/statetransitiontable.rb +316 -0
  48. data/lib/racc/static.rb +5 -0
  49. data/misc/dist.sh +31 -0
  50. data/sample/array.y +67 -0
  51. data/sample/array2.y +59 -0
  52. data/sample/calc-ja.y +66 -0
  53. data/sample/calc.y +65 -0
  54. data/sample/conflict.y +15 -0
  55. data/sample/hash.y +60 -0
  56. data/sample/lalr.y +17 -0
  57. data/sample/lists.y +57 -0
  58. data/sample/syntax.y +46 -0
  59. data/sample/yyerr.y +46 -0
  60. data/setup.rb +1587 -0
  61. data/tasks/doc.rb +12 -0
  62. data/tasks/email.rb +55 -0
  63. data/tasks/file.rb +37 -0
  64. data/tasks/gem.rb +37 -0
  65. data/tasks/test.rb +16 -0
  66. data/test/assets/chk.y +126 -0
  67. data/test/assets/conf.y +16 -0
  68. data/test/assets/digraph.y +29 -0
  69. data/test/assets/echk.y +118 -0
  70. data/test/assets/err.y +60 -0
  71. data/test/assets/expect.y +7 -0
  72. data/test/assets/firstline.y +4 -0
  73. data/test/assets/ichk.y +102 -0
  74. data/test/assets/intp.y +546 -0
  75. data/test/assets/mailp.y +437 -0
  76. data/test/assets/newsyn.y +25 -0
  77. data/test/assets/noend.y +4 -0
  78. data/test/assets/nonass.y +41 -0
  79. data/test/assets/normal.y +27 -0
  80. data/test/assets/norule.y +4 -0
  81. data/test/assets/nullbug1.y +25 -0
  82. data/test/assets/nullbug2.y +15 -0
  83. data/test/assets/opt.y +123 -0
  84. data/test/assets/percent.y +35 -0
  85. data/test/assets/recv.y +97 -0
  86. data/test/assets/rrconf.y +14 -0
  87. data/test/assets/scan.y +72 -0
  88. data/test/assets/syntax.y +50 -0
  89. data/test/assets/unterm.y +5 -0
  90. data/test/assets/useless.y +12 -0
  91. data/test/assets/yyerr.y +46 -0
  92. data/test/bench.y +36 -0
  93. data/test/helper.rb +88 -0
  94. data/test/infini.y +8 -0
  95. data/test/scandata/brace +7 -0
  96. data/test/scandata/gvar +1 -0
  97. data/test/scandata/normal +4 -0
  98. data/test/scandata/percent +18 -0
  99. data/test/scandata/slash +10 -0
  100. data/test/src.intp +34 -0
  101. data/test/start.y +20 -0
  102. data/test/test_chk_y.rb +51 -0
  103. data/test/test_grammar_file_parser.rb +15 -0
  104. data/test/test_racc_command.rb +155 -0
  105. data/test/test_scan_y.rb +51 -0
  106. data/test/testscanner.rb +51 -0
  107. data/web/racc.en.rhtml +42 -0
  108. data/web/racc.ja.rhtml +51 -0
  109. metadata +166 -0
@@ -0,0 +1,60 @@
1
+
2
+ class ErrTestp
3
+
4
+ rule
5
+
6
+ target: lines
7
+ ;
8
+
9
+ lines: line
10
+ | lines line
11
+ ;
12
+
13
+ line: A B C D E
14
+ | error E
15
+ ;
16
+
17
+ end
18
+
19
+ ---- inner
20
+
21
+ def initialize
22
+ @yydebug = false
23
+ @q = [
24
+ [:A, 'a'],
25
+ # [:B, 'b'],
26
+ [:C, 'c'],
27
+ [:D, 'd'],
28
+ [:E, 'e'],
29
+
30
+ [:A, 'a'],
31
+ [:B, 'b'],
32
+ [:C, 'c'],
33
+ [:D, 'd'],
34
+ [:E, 'e'],
35
+
36
+ [:A, 'a'],
37
+ [:B, 'b'],
38
+ # [:C, 'c'],
39
+ [:D, 'd'],
40
+ [:E, 'e'],
41
+ [false, nil]
42
+ ]
43
+ end
44
+
45
+ def next_token
46
+ @q.shift
47
+ end
48
+
49
+ def on_error( t, val, values )
50
+ $stderr.puts "error on token '#{val}'(#{t})"
51
+ end
52
+
53
+ def parse
54
+ do_parse
55
+ end
56
+
57
+ ---- footer
58
+
59
+ p = ErrTestp.new
60
+ p.parse
@@ -0,0 +1,7 @@
1
+ class E
2
+ expect 1
3
+ rule
4
+ list: inlist inlist
5
+ inlist:
6
+ | A
7
+ end
@@ -0,0 +1,4 @@
1
+ class T
2
+ rule
3
+ a: A B C
4
+ end
@@ -0,0 +1,102 @@
1
+ class Calculator
2
+
3
+ prechigh
4
+ left '*' '/'
5
+ left '+' '-'
6
+ preclow
7
+
8
+ convert
9
+ NUMBER 'Number'
10
+ end
11
+
12
+ rule
13
+
14
+ target : exp
15
+ | /* none */ { result = 0 }
16
+
17
+ exp : exp '+' exp { result += val[2]; a = 'plus' }
18
+ | exp '-' exp { result -= val[2]; a = "string test" }
19
+ | exp '*' exp { result *= val[2] }
20
+ | exp '/' exp { result /= val[2] }
21
+ | '(' { $emb = true } exp ')'
22
+ {
23
+ raise 'must not happen' unless $emb
24
+ result = val[2]
25
+ }
26
+ | '-' NUMBER { result = -val[1] }
27
+ | NUMBER
28
+
29
+ ----header
30
+
31
+ class Number
32
+ end
33
+
34
+ ----inner
35
+
36
+ def initialize
37
+ @racc_debug_out = $stdout
38
+ @yydebug = false
39
+ end
40
+
41
+ def validate(expected, src)
42
+ result = parse(src)
43
+ unless result == expected
44
+ raise "test #{@test_number} fail"
45
+ end
46
+ @test_number += 1
47
+ end
48
+
49
+ def parse(src)
50
+ @src = src
51
+ @test_number = 1
52
+ yyparse self, :scan
53
+ end
54
+
55
+ def scan(&block)
56
+ @src.each(&block)
57
+ end
58
+
59
+ ----footer
60
+
61
+ calc = Calculator.new
62
+
63
+ calc.validate(9, [[Number, 9], nil])
64
+
65
+ calc.validate(-3,
66
+ [[Number, 5],
67
+ ['*', '*'],
68
+ [Number, 1],
69
+ ['-', '*'],
70
+ [Number, 1],
71
+ ['*', '*'],
72
+ [Number, 8],
73
+ nil])
74
+
75
+ calc.validate(-1,
76
+ [[Number, 5],
77
+ ['+', '+'],
78
+ [Number, 2],
79
+ ['-', '-'],
80
+ [Number, 5],
81
+ ['+', '+'],
82
+ [Number, 2],
83
+ ['-', '-'],
84
+ [Number, 5],
85
+ nil])
86
+
87
+ calc.validate(-4,
88
+ [['-', 'UMINUS'],
89
+ [Number, 4],
90
+ nil])
91
+
92
+ calc.validate(40,
93
+ [[Number, 7],
94
+ ['*', '*'],
95
+ ['(', '('],
96
+ [Number, 4],
97
+ ['+', '+'],
98
+ [Number, 3],
99
+ [')', ')'],
100
+ ['-', '-'],
101
+ [Number, 9],
102
+ nil])
@@ -0,0 +1,546 @@
1
+ #
2
+ # intp
3
+ #
4
+
5
+ class Intp::Parser
6
+
7
+ prechigh
8
+ nonassoc UMINUS
9
+ left '*' '/'
10
+ left '+' '-'
11
+ nonassoc EQ
12
+ preclow
13
+
14
+ rule
15
+
16
+ program : stmt_list
17
+ {
18
+ result = RootNode.new( val[0] )
19
+ }
20
+
21
+ stmt_list :
22
+ {
23
+ result = []
24
+ }
25
+ | stmt_list stmt EOL
26
+ {
27
+ result.push val[1]
28
+ }
29
+ | stmt_list EOL
30
+
31
+ stmt : expr
32
+ | assign
33
+ | IDENT realprim
34
+ {
35
+ result = FuncallNode.new( @fname, val[0][0],
36
+ val[0][1], [val[1]] )
37
+ }
38
+ | if_stmt
39
+ | while_stmt
40
+ | defun
41
+
42
+ if_stmt : IF stmt THEN EOL stmt_list else_stmt END
43
+ {
44
+ result = IfNode.new( @fname, val[0][0],
45
+ val[1], val[4], val[5] )
46
+ }
47
+
48
+ else_stmt : ELSE EOL stmt_list
49
+ {
50
+ result = val[2]
51
+ }
52
+ |
53
+ {
54
+ result = nil
55
+ }
56
+
57
+ while_stmt: WHILE stmt DO EOL stmt_list END
58
+ {
59
+ result = WhileNode.new(@fname, val[0][0],
60
+ val[1], val[4])
61
+ }
62
+
63
+ defun : DEF IDENT param EOL stmt_list END
64
+ {
65
+ result = DefNode.new(@fname, val[0][0], val[1][1],
66
+ Function.new(@fname, val[0][0], val[2], val[4]))
67
+ }
68
+
69
+ param : '(' name_list ')'
70
+ {
71
+ result = val[1]
72
+ }
73
+ | '(' ')'
74
+ {
75
+ result = []
76
+ }
77
+ |
78
+ {
79
+ result = []
80
+ }
81
+
82
+ name_list : IDENT
83
+ {
84
+ result = [ val[0][1] ]
85
+ }
86
+ | name_list ',' IDENT
87
+ {
88
+ result.push val[2][1]
89
+ }
90
+
91
+ assign : IDENT '=' expr
92
+ {
93
+ result = AssignNode.new(@fname, val[0][0], val[0][1], val[2])
94
+ }
95
+
96
+ expr : expr '+' expr
97
+ {
98
+ result = FuncallNode.new(@fname, val[0].lineno, '+', [val[0], val[2]])
99
+ }
100
+ | expr '-' expr
101
+ {
102
+ result = FuncallNode.new(@fname, val[0].lineno, '-', [val[0], val[2]])
103
+ }
104
+ | expr '*' expr
105
+ {
106
+ result = FuncallNode.new(@fname, val[0].lineno, '*', [val[0], val[2]])
107
+ }
108
+ | expr '/' expr
109
+ {
110
+ result = FuncallNode.new(@fname, val[0].lineno,
111
+ '/', [val[0], val[2]])
112
+ }
113
+ | expr EQ expr
114
+ {
115
+ result = FuncallNode.new(@fname, val[0].lineno, '==', [val[0], val[2]])
116
+ }
117
+ | primary
118
+
119
+ primary : realprim
120
+ | '(' expr ')'
121
+ {
122
+ result = val[1]
123
+ }
124
+ | '-' expr =UMINUS
125
+ {
126
+ result = FuncallNode.new(@fname, val[0][0], '-@', [val[1]])
127
+ }
128
+
129
+ realprim : IDENT
130
+ {
131
+ result = VarRefNode.new(@fname, val[0][0],
132
+ val[0][1])
133
+ }
134
+ | NUMBER
135
+ {
136
+ result = LiteralNode.new(@fname, *val[0])
137
+ }
138
+ | STRING
139
+ {
140
+ result = StringNode.new(@fname, *val[0])
141
+ }
142
+ | TRUE
143
+ {
144
+ result = LiteralNode.new(@fname, *val[0])
145
+ }
146
+ | FALSE
147
+ {
148
+ result = LiteralNode.new(@fname, *val[0])
149
+ }
150
+ | NIL
151
+ {
152
+ result = LiteralNode.new(@fname, *val[0])
153
+ }
154
+ | funcall
155
+
156
+ funcall : IDENT '(' args ')'
157
+ {
158
+ result = FuncallNode.new(@fname, val[0][0], val[0][1], val[2])
159
+ }
160
+ | IDENT '(' ')'
161
+ {
162
+ result = FuncallNode.new(@fname, val[0][0], val[0][1], [])
163
+ }
164
+
165
+ args : expr
166
+ {
167
+ result = val
168
+ }
169
+ | args ',' expr
170
+ {
171
+ result.push val[2]
172
+ }
173
+
174
+ end
175
+
176
+ ---- header
177
+ #
178
+ # intp/parser.rb
179
+ #
180
+
181
+ ---- inner
182
+
183
+ def initialize
184
+ @scope = {}
185
+ end
186
+
187
+ RESERVED = {
188
+ 'if' => :IF,
189
+ 'else' => :ELSE,
190
+ 'while' => :WHILE,
191
+ 'then' => :THEN,
192
+ 'do' => :DO,
193
+ 'def' => :DEF,
194
+ 'true' => :TRUE,
195
+ 'false' => :FALSE,
196
+ 'nil' => :NIL,
197
+ 'end' => :END
198
+ }
199
+
200
+ RESERVED_V = {
201
+ 'true' => true,
202
+ 'false' => false,
203
+ 'nil' => nil
204
+ }
205
+
206
+ def parse(f, fname)
207
+ @q = []
208
+ @fname = fname
209
+ lineno = 1
210
+ f.each do |line|
211
+ line.strip!
212
+ until line.empty?
213
+ case line
214
+ when /\A\s+/, /\A\#.*/
215
+ ;
216
+ when /\A[a-zA-Z_]\w*/
217
+ word = $&
218
+ @q.push [(RESERVED[word] || :IDENT),
219
+ [lineno, RESERVED_V.key?(word) ? RESERVED_V[word] : word.intern]]
220
+ when /\A\d+/
221
+ @q.push [:NUMBER, [lineno, $&.to_i]]
222
+ when /\A"(?:[^"\\]+|\\.)*"/, /\A'(?:[^'\\]+|\\.)*'/
223
+ @q.push [:STRING, [lineno, eval($&)]]
224
+ when /\A==/
225
+ @q.push [:EQ, [lineno, '==']]
226
+ when /\A./
227
+ @q.push [$&, [lineno, $&]]
228
+ else
229
+ raise RuntimeError, 'must not happen'
230
+ end
231
+ line = $'
232
+ end
233
+ @q.push [:EOL, [lineno, nil]]
234
+ lineno += 1
235
+ end
236
+ @q.push [false, '$']
237
+ do_parse
238
+ end
239
+
240
+ def next_token
241
+ @q.shift
242
+ end
243
+
244
+ def on_error(t, v, values)
245
+ if v
246
+ line = v[0]
247
+ v = v[1]
248
+ else
249
+ line = 'last'
250
+ end
251
+ raise Racc::ParseError, "#{@fname}:#{line}: syntax error on #{v.inspect}"
252
+ end
253
+
254
+ ---- footer
255
+ # intp/node.rb
256
+
257
+ module Intp
258
+
259
+ class IntpError < StandardError; end
260
+ class IntpArgumentError < IntpError; end
261
+
262
+ class Core
263
+
264
+ def initialize
265
+ @ftab = {}
266
+ @obj = Object.new
267
+ @stack = []
268
+ @stack.push Frame.new '(toplevel)'
269
+ end
270
+
271
+ def frame
272
+ @stack[-1]
273
+ end
274
+
275
+ def define_function(fname, node)
276
+ raise IntpError, "function #{fname} defined twice" if @ftab.key?(fname)
277
+ @ftab[fname] = node
278
+ end
279
+
280
+ def call_function_or(fname, args)
281
+ call_intp_function_or(fname, args) {
282
+ call_ruby_toplevel_or(fname, args) {
283
+ yield
284
+ }
285
+ }
286
+ end
287
+
288
+ def call_intp_function_or(fname, args)
289
+ if func = @ftab[fname]
290
+ frame = Frame.new(fname)
291
+ @stack.push frame
292
+ func.call self, frame, args
293
+ @stack.pop
294
+ else
295
+ yield
296
+ end
297
+ end
298
+
299
+ def call_ruby_toplevel_or(fname, args)
300
+ if @obj.respond_to? fname, true
301
+ @obj.send fname, *args
302
+ else
303
+ yield
304
+ end
305
+ end
306
+
307
+ end
308
+
309
+ class Frame
310
+
311
+ def initialize(fname)
312
+ @fname = fname
313
+ @lvars = {}
314
+ end
315
+
316
+ attr :fname
317
+
318
+ def lvar?(name)
319
+ @lvars.key? name
320
+ end
321
+
322
+ def [](key)
323
+ @lvars[key]
324
+ end
325
+
326
+ def []=(key, val)
327
+ @lvars[key] = val
328
+ end
329
+
330
+ end
331
+
332
+
333
+ class Node
334
+
335
+ def initialize(fname, lineno)
336
+ @filename = fname
337
+ @lineno = lineno
338
+ end
339
+
340
+ attr_reader :filename
341
+ attr_reader :lineno
342
+
343
+ def exec_list(intp, nodes)
344
+ v = nil
345
+ nodes.each {|i| v = i.evaluate(intp) }
346
+ v
347
+ end
348
+
349
+ def intp_error!(msg)
350
+ raise IntpError, "in #{filename}:#{lineno}: #{msg}"
351
+ end
352
+
353
+ def inspect
354
+ "#{self.class.name}/#{lineno}"
355
+ end
356
+
357
+ end
358
+
359
+
360
+ class RootNode < Node
361
+
362
+ def initialize(tree)
363
+ super nil, nil
364
+ @tree = tree
365
+ end
366
+
367
+ def evaluate
368
+ exec_list Core.new, @tree
369
+ end
370
+
371
+ end
372
+
373
+
374
+ class DefNode < Node
375
+
376
+ def initialize(file, lineno, fname, func)
377
+ super file, lineno
378
+ @funcname = fname
379
+ @funcobj = func
380
+ end
381
+
382
+ def evaluate(intp)
383
+ intp.define_function @funcname, @funcobj
384
+ end
385
+
386
+ end
387
+
388
+ class FuncallNode < Node
389
+
390
+ def initialize(file, lineno, func, args)
391
+ super file, lineno
392
+ @funcname = func
393
+ @args = args
394
+ end
395
+
396
+ def evaluate(intp)
397
+ args = @args.map {|i| i.evaluate intp }
398
+ begin
399
+ intp.call_intp_function_or(@funcname, args) {
400
+ if args.empty? or not args[0].respond_to?(@funcname)
401
+ intp.call_ruby_toplevel_or(@funcname, args) {
402
+ intp_error! "undefined function #{@funcname.id2name}"
403
+ }
404
+ else
405
+ recv = args.shift
406
+ recv.send @funcname, *args
407
+ end
408
+ }
409
+ rescue IntpArgumentError, ArgumentError
410
+ intp_error! $!.message
411
+ end
412
+ end
413
+
414
+ end
415
+
416
+ class Function < Node
417
+
418
+ def initialize(file, lineno, params, body)
419
+ super file, lineno
420
+ @params = params
421
+ @body = body
422
+ end
423
+
424
+ def call(intp, frame, args)
425
+ unless args.size == @params.size
426
+ raise IntpArgumentError,
427
+ "wrong # of arg for #{frame.fname}() (#{args.size} for #{@params.size})"
428
+ end
429
+ args.each_with_index do |v,i|
430
+ frame[@params[i]] = v
431
+ end
432
+ exec_list intp, @body
433
+ end
434
+
435
+ end
436
+
437
+
438
+ class IfNode < Node
439
+
440
+ def initialize(fname, lineno, cond, tstmt, fstmt)
441
+ super fname, lineno
442
+ @condition = cond
443
+ @tstmt = tstmt
444
+ @fstmt = fstmt
445
+ end
446
+
447
+ def evaluate(intp)
448
+ if @condition.evaluate(intp)
449
+ exec_list intp, @tstmt
450
+ else
451
+ exec_list intp, @fstmt if @fstmt
452
+ end
453
+ end
454
+
455
+ end
456
+
457
+ class WhileNode < Node
458
+
459
+ def initialize(fname, lineno, cond, body)
460
+ super fname, lineno
461
+ @condition = cond
462
+ @body = body
463
+ end
464
+
465
+ def evaluate(intp)
466
+ while @condition.evaluate(intp)
467
+ exec_list intp, @body
468
+ end
469
+ end
470
+
471
+ end
472
+
473
+
474
+ class AssignNode < Node
475
+
476
+ def initialize(fname, lineno, vname, val)
477
+ super fname, lineno
478
+ @vname = vname
479
+ @val = val
480
+ end
481
+
482
+ def evaluate(intp)
483
+ intp.frame[@vname] = @val.evaluate(intp)
484
+ end
485
+
486
+ end
487
+
488
+ class VarRefNode < Node
489
+
490
+ def initialize(fname, lineno, vname)
491
+ super fname, lineno
492
+ @vname = vname
493
+ end
494
+
495
+ def evaluate(intp)
496
+ if intp.frame.lvar?(@vname)
497
+ intp.frame[@vname]
498
+ else
499
+ intp.call_function_or(@vname, []) {
500
+ intp_error! "unknown method or local variable #{@vname.id2name}"
501
+ }
502
+ end
503
+ end
504
+
505
+ end
506
+
507
+ class StringNode < Node
508
+
509
+ def initialize(fname, lineno, str)
510
+ super fname, lineno
511
+ @val = str
512
+ end
513
+
514
+ def evaluate(intp)
515
+ @val.dup
516
+ end
517
+
518
+ end
519
+
520
+ class LiteralNode < Node
521
+
522
+ def initialize(fname, lineno, val)
523
+ super fname, lineno
524
+ @val = val
525
+ end
526
+
527
+ def evaluate(intp)
528
+ @val
529
+ end
530
+
531
+ end
532
+
533
+ end # module Intp
534
+
535
+ begin
536
+ tree = nil
537
+ fname = 'src.intp'
538
+ File.open(fname) {|f|
539
+ tree = Intp::Parser.new.parse(f, fname)
540
+ }
541
+ tree.evaluate
542
+ rescue Racc::ParseError, Intp::IntpError, Errno::ENOENT
543
+ raise ####
544
+ $stderr.puts "#{File.basename $0}: #{$!}"
545
+ exit 1
546
+ end