depager 0.2.3 → 0.3.0.b20160729

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 (91) hide show
  1. checksums.yaml +7 -0
  2. data/README.en +4 -19
  3. data/README.ja +42 -79
  4. data/bin/depager +42 -45
  5. data/examples/action_pl0d/pl0d.action.dr +421 -0
  6. data/examples/action_pl0d/test.pl0ds +49 -0
  7. data/examples/c89/c89.dr +493 -496
  8. data/examples/c89/test.c89 +10 -10
  9. data/examples/extension/astdf.rb +10 -0
  10. data/examples/extension/atree.dr +55 -0
  11. data/examples/{sample_calc → extension}/calc.atree.dr +42 -43
  12. data/examples/extension/calc.simple_action.dr +33 -0
  13. data/examples/extension/paction.dr +16 -15
  14. data/examples/extension/pactiontest.dr +14 -14
  15. data/examples/extension/simple_action.rb +44 -0
  16. data/examples/pl0d/pl0ds.dr +337 -334
  17. data/examples/pl0d/test.pl0ds +33 -33
  18. data/examples/rie_calc/calc.rie.dr +57 -0
  19. data/examples/rie_calc/test.calc +4 -0
  20. data/examples/rie_dcuse/dcuse.rie.dr +71 -0
  21. data/examples/rie_dcuse/test.dcuse +1 -0
  22. data/examples/rie_pl0/orig_ex/exerrdg.pl0 +44 -0
  23. data/examples/rie_pl0/orig_ex/exerrm.pl0 +19 -0
  24. data/examples/rie_pl0/orig_ex/exerrmre.pl0 +20 -0
  25. data/examples/rie_pl0/orig_ex/exerrtok.pl0 +18 -0
  26. data/examples/rie_pl0/orig_ex/exmdg.pl0 +40 -0
  27. data/examples/rie_pl0/orig_ex/exmdgwwl.pl0 +43 -0
  28. data/examples/rie_pl0/orig_ex/exmrw.pl0 +22 -0
  29. data/examples/rie_pl0/orig_ex/exmwwl.pl0 +18 -0
  30. data/examples/rie_pl0/orig_ex/exnorw.pl0 +17 -0
  31. data/examples/rie_pl0/pl0.rie.dr +450 -0
  32. data/examples/rie_pl0/test.pl0 +10 -0
  33. data/examples/sample_calc/calc.action.dr +33 -33
  34. data/examples/sample_calc/calc.ast.action.dr +65 -66
  35. data/examples/sample_calc/calc.ast.dr +55 -55
  36. data/examples/sample_calc/calc.cst.dr +45 -45
  37. data/examples/sample_calc/calc.dr +43 -43
  38. data/examples/sample_calc/calc.lex.dr +29 -29
  39. data/examples/sample_calc/{calc_prec.nvaction.dr → calc_prec.action.dr} +31 -31
  40. data/examples/slex_test/divreg.slex.dr +29 -29
  41. data/examples/slex_test/ljoin.slex.dr +36 -36
  42. data/examples/slex_test/test.divreg +1 -1
  43. data/examples/slex_test/test.ljoin +3 -3
  44. data/lib/depager.rb +582 -670
  45. data/lib/depager/grammar.rb +256 -291
  46. data/lib/depager/lr.rb +574 -579
  47. data/lib/depager/parser.rb +282 -277
  48. data/lib/depager/ruby/plugins/_rie_debug.rb +35 -0
  49. data/lib/depager/ruby/plugins/action.rb +53 -43
  50. data/lib/depager/ruby/plugins/ast.dr +364 -269
  51. data/lib/depager/ruby/plugins/ast.rb +1367 -1308
  52. data/lib/depager/ruby/plugins/cst.dr +172 -180
  53. data/lib/depager/ruby/plugins/cst.rb +587 -626
  54. data/lib/depager/ruby/plugins/lex.dr +85 -89
  55. data/lib/depager/ruby/plugins/lex.rb +310 -336
  56. data/lib/depager/ruby/plugins/rie.dr +723 -0
  57. data/lib/depager/ruby/plugins/rie.rb +1653 -0
  58. data/lib/depager/ruby/plugins/slex.dr +202 -200
  59. data/lib/depager/ruby/plugins/slex.rb +780 -817
  60. data/lib/depager/ruby/plugins/srp.rb +56 -51
  61. data/lib/depager/ruby/templates/extension_lalr_master.erb +46 -51
  62. data/lib/depager/ruby/templates/extension_lalr_slave.erb +99 -107
  63. data/lib/depager/ruby/templates/single_lalr_parser.erb +115 -117
  64. data/lib/depager/utils.rb +148 -318
  65. data/lib/depager/version.rb +4 -3
  66. metadata +52 -60
  67. data/ChangeLog +0 -16
  68. data/data/depager/pre-setup.rb +0 -3
  69. data/examples/c89/c89.tab.rb +0 -7127
  70. data/examples/pl0d/pl0ds.tab.rb +0 -2698
  71. data/examples/sample_calc/calc.action.tab.rb +0 -457
  72. data/examples/sample_calc/calc.ast.action.tab.rb +0 -749
  73. data/examples/sample_calc/calc.ast.tab.rb +0 -665
  74. data/examples/sample_calc/calc.astdf.dr +0 -54
  75. data/examples/sample_calc/calc.astdf.tab.rb +0 -672
  76. data/examples/sample_calc/calc.atree.tab.rb +0 -451
  77. data/examples/sample_calc/calc.cst.tab.rb +0 -644
  78. data/examples/sample_calc/calc.lex.tab.rb +0 -374
  79. data/examples/sample_calc/calc.nvaction.dr +0 -33
  80. data/examples/sample_calc/calc.nvaction.tab.rb +0 -465
  81. data/examples/sample_calc/calc.tab.rb +0 -365
  82. data/examples/sample_calc/calc_prec.nvaction.tab.rb +0 -431
  83. data/examples/slex_test/divreg.slex.tab.rb +0 -303
  84. data/examples/slex_test/ljoin.slex.tab.rb +0 -370
  85. data/lib/depager/ruby/plugins/_ast_tmpl.rb +0 -73
  86. data/lib/depager/ruby/plugins/astdf.rb +0 -6
  87. data/lib/depager/ruby/plugins/atree.dr +0 -55
  88. data/lib/depager/ruby/plugins/atree.rb +0 -347
  89. data/lib/depager/ruby/plugins/nvaction.rb +0 -19
  90. data/lib/depager/ruby/templates/simple.erb +0 -23
  91. data/setup.rb +0 -1585
@@ -1,10 +1,10 @@
1
- /*
2
- comment
3
- */
4
- int fact(int n)
5
- {
6
- if (n == 1)
7
- return 1;
8
- else
9
- return n * fact(n - 1);
10
- }
1
+ /*
2
+ comment
3
+ */
4
+ int fact(int n)
5
+ {
6
+ if (n == 1)
7
+ return 1;
8
+ else
9
+ return n * fact(n - 1);
10
+ }
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'plugins/ast.rb'
3
+
4
+ module Examples ; end
5
+
6
+ class Examples::ASTBuilderDepthFirstExtension < Depager::ASTBuilderExtension #:nodoc:all
7
+ def gen_accept_code sym
8
+ " @#{sym}.accept(v)\n"
9
+ end
10
+ end
@@ -0,0 +1,55 @@
1
+ %defext Examples::ATreeBuilderExtension
2
+ %extend Depager::Action ('plugins/action.rb')
3
+ %extend Depager::Lexer ('plugins/lex.rb')
4
+ %decorate @Action
5
+ #%decorate Depager::LALR::ShiftReducePrinter ('plugins/srp.rb')
6
+ %expanded_code_delimiter DEPAGER_EXPANDED_CODE
7
+ %inner{
8
+ attr_accessor :action_code, :on_reduce
9
+ def init_extension
10
+ @action_code = ''
11
+ @on_reduce = []
12
+ end
13
+ def term_extension
14
+ g_parser.outer_code <<
15
+ generate_action_decorator_code(@on_reduce, @action_code)
16
+ end
17
+ %}
18
+ %hook post_rhs
19
+ %banner '=>...'
20
+ %%
21
+ %LEX{
22
+ /[ \t]+/ { }
23
+ /\r?\n/ { yield nil, nil }
24
+ /[a-zA-Z][a-zA-Z0-9_]*/ { yield token(:ID, $&) }
25
+ /'(.+)'/ { yield token(:STR, $1) }
26
+ /::/ { yield token(:CC, $&) }
27
+ /=>/ { yield token(:EG, $&) }
28
+ /./ { yield token($&, $&) }
29
+ %}
30
+
31
+ #begin-rule
32
+ start:
33
+ EG ast
34
+ {
35
+ n = g_parser.rules.size-1
36
+ master.action_code <<
37
+ master.expand_inline_code(_ast, _EG.lineno, :wrap => "def _atree_#{n} val")
38
+ master.on_reduce[n] = ":_atree_#{n}"
39
+ }
40
+ ;
41
+ ast:
42
+ ID '(' ')' { "[:#{_ID.value}]" }
43
+ | ID '(' fact_list ')' { "[:#{_ID.value}, #{_fact_list.join(',')}]" }
44
+ | ID { "val[#{g_parser.name_to_rhs_index(_ID.value)}]" }
45
+ ;
46
+ fact_list:
47
+ fact { [ _fact ] }
48
+ | fact_list ',' fact { _fact_list.push _fact }
49
+ ;
50
+ fact:
51
+ ID { "val[#{g_parser.name_to_rhs_index(_ID.value)}]" }
52
+ | STR { "'#{_STR.value}'" }
53
+ ;
54
+ #end-rule
55
+ %%
@@ -1,43 +1,42 @@
1
- %class TinyCalc
2
- %extend Lexer ('plugins/lex.rb')
3
- %extend ATreeBuilder ('plugins/atree.rb')
4
- %decorate @ATreeBuilder
5
- #%decorate ShiftReducePrinter ('plugins/srp.rb')
6
- %mixin Depager
7
- %%
8
-
9
- %LEX{
10
- /\s+/, /\#.*/ { }
11
- /[1-9][0-9]*/ { yield token(:NUM, $&.to_i) }
12
- /./ { yield token($&, $&) }
13
- %}
14
-
15
- #begin-rule
16
- expr :
17
- expr '+' term
18
- => add(expr, term)
19
- | expr '-' term
20
- => sub(expr, term)
21
- | term
22
- => term
23
- ;
24
- term :
25
- term '*' fact
26
- => mul(term, fact)
27
- | term '/' fact
28
- => div(term, fact)
29
- | fact
30
- => fact
31
- ;
32
- fact :
33
- NUM
34
- => literal(NUM)
35
- | '(' expr ')'
36
- => expr
37
- ;
38
- #end-rule
39
- %%
40
- require 'pp'
41
- parser = createDecoratedTinyCalc
42
- r, = parser.parse(STDIN)
43
- pp r
1
+ %class TinyCalc::Parser
2
+ %extend Depager::Lexer ('plugins/lex.rb')
3
+ %extend Examples::ATreeBuilder ('./atree.rb')
4
+ %decorate @ATreeBuilder
5
+ #%decorate Depager::LALR::ShiftReducePrinter ('plugins/srp.rb')
6
+ %%
7
+
8
+ %LEX{
9
+ /\s+/, /\#.*/ { }
10
+ /[1-9][0-9]*/ { yield token(:NUM, $&.to_i) }
11
+ /./ { yield token($&, $&) }
12
+ %}
13
+
14
+ #begin-rule
15
+ expr :
16
+ expr '+' term
17
+ => add(expr, term)
18
+ | expr '-' term
19
+ => sub(expr, term)
20
+ | term
21
+ => term
22
+ ;
23
+ term :
24
+ term '*' fact
25
+ => mul(term, fact)
26
+ | term '/' fact
27
+ => div(term, fact)
28
+ | fact
29
+ => fact
30
+ ;
31
+ fact :
32
+ NUM
33
+ => literal(NUM)
34
+ | '(' expr ')'
35
+ => expr
36
+ ;
37
+ #end-rule
38
+ %%
39
+ require 'pp'
40
+ parser = TinyCalc.create_decorated_parser()
41
+ t, = parser.parse(STDIN)
42
+ pp t
@@ -0,0 +1,33 @@
1
+ %class TinyCalc::Parser
2
+ %extend Depager::Lexer ('plugins/lex.rb')
3
+ %extend Examples::SimpleAction ('./simple_action.rb')
4
+ %decorate @SimpleAction
5
+ #%decorate Depager::LALR::ShiftReducePrinter ('plugins/srp.rb')
6
+ %%
7
+
8
+ %LEX{
9
+ /\s+/, /\#.*/ { }
10
+ /[1-9][0-9]*/ { yield token(:NUM, $&.to_i) }
11
+ /./ { yield token($&, $&) }
12
+ %}
13
+
14
+ #begin-rule
15
+ expr :
16
+ expr '+' term { val[0] + val[2] }
17
+ | expr '-' term { val[0] - val[2] }
18
+ | term { val[0] }
19
+ ;
20
+ term :
21
+ term '*' fact { val[0] * val[2] }
22
+ | term '/' fact { val[0] / val[2] }
23
+ | fact { val[0] }
24
+ ;
25
+ fact :
26
+ NUM { val[0].value }
27
+ | '(' expr ')' { val[1] }
28
+ ;
29
+ #end-rule
30
+ %%
31
+ parser = TinyCalc.create_decorated_parser
32
+ r, = parser.parse(STDIN)
33
+ puts r
@@ -1,15 +1,16 @@
1
- %defext PseudoActionExtension
2
- %extend Lexer ('plugins/lex.rb')
3
- %extend Action ('plugins/action.rb')
4
- %decorate @Action
5
- #%decorate ShiftReducePrinter ('plugins/srp.rb')
6
- %hook postrhs
7
- %%
8
- %LEX{
9
- /\s/ { }
10
- /./ { yield $&, $&, @lineno }
11
- %}
12
- start:
13
- '{' '}' { warn 'HIT' }
14
- ;
15
- %%
1
+ %defext Examples::PseudoActionExtension
2
+ %extend Depager::Lexer ('plugins/lex.rb')
3
+ %extend Depager::Action ('plugins/action.rb')
4
+ %decorate @Action
5
+ #%decorate Depager::LALR::ShiftReducePrinter ('plugins/srp.rb')
6
+ %hook post_rhs
7
+ %%
8
+ %LEX{
9
+ /\s+/ { }
10
+ /\{/ { yield $&, $&, @lineno }
11
+ /\}/ { yield $&, $&, @lineno ; yield nil, nil }
12
+ %}
13
+ start:
14
+ '{' '}' { warn 'HIT' }
15
+ ;
16
+ %%
@@ -1,14 +1,14 @@
1
- %class PseudoActionTest
2
- %extend PseudoAction ('paction.rb')
3
- %%
4
- #begin-rule
5
- expr:
6
- expr '+' fact { }
7
- ;
8
- fact:
9
- ID { }
10
- ;
11
- #end-rule
12
- %%
13
- p = PseudoActionTest.new()
14
- #p.parse(STDIN)
1
+ %class PseudoActionTest::Parser
2
+ %extend Examples::PseudoAction ('./paction.rb')
3
+ %%
4
+ #begin-rule
5
+ expr:
6
+ expr '+' fact { }
7
+ ;
8
+ fact:
9
+ ID { }
10
+ ;
11
+ #end-rule
12
+ %%
13
+ p = PseudoActionTest.new()
14
+ #p.parse(STDIN)
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'depager/parser.rb'
3
+
4
+ module Examples ; end
5
+
6
+ class Examples::SimpleActionExtension < Depager::Extension #:nodoc:all
7
+ def init_extension
8
+ @line0 = @line = @oldline = ''
9
+ @action_code = ''
10
+ @on_reduce = []
11
+ end
12
+
13
+ def term_extension
14
+ g_parser.outer_code <<
15
+ generate_action_decorator_code(@on_reduce, @action_code)
16
+ end
17
+
18
+ def modify_action_code code
19
+ return code, 0
20
+ end
21
+
22
+ def pre_rule_list
23
+ if g_parser.original_line =~ /^%ACTION\{\s*$/
24
+ while line = file.gets
25
+ break if line =~ /^%\}\s*$/
26
+ @action_code << line
27
+ end
28
+ g_parser.update_context ''
29
+ end
30
+ end
31
+
32
+ def post_rhs
33
+ if g_parser.line =~ /\s*\{/
34
+ @original_line, @line = g_parser.original_line, g_parser.line
35
+ lineno = g_parser.file.lineno
36
+ code, d = parse_block, 1
37
+ n = g_parser.rules.size - 1
38
+ @action_code <<
39
+ expand_inline_code(code, lineno, :wrap => "def _act_#{n} val", :delta => d)
40
+ g_parser.update_context @line
41
+ @on_reduce[n] = ":_act_#{n}"
42
+ end
43
+ end
44
+ end
@@ -1,334 +1,337 @@
1
- %class PL0d
2
- %extend Lexer ('plugins/lex.rb')
3
- %extend ASTBuilder ('plugins/ast.rb')
4
- %decorate @ASTBuilder
5
- #%decorate ShiftReducePrinter ('plugins/srp.rb')
6
- %%
7
- %LEX{
8
- /\s+/ { }
9
- ':=' { yield token(:COLOEQ, $&) }
10
- '<>' { yield token(:NOTEQ, $&) }
11
- '<=' { yield token(:LE, $&) }
12
- '>=' { yield token(:GE, $&) }
13
- '=' { yield token(:EQ, $&) }
14
- '<' { yield token(:LT, $&) }
15
- '>' { yield token(:GT, $&) }
16
- 'const' { yield token(:CONST, $&) }
17
- 'var' { yield token(:VAR, $&) }
18
- 'function'{ yield token(:FUNCTION, $&) }
19
- 'begin' { yield token(:BEGINN, $&) }
20
- 'end' { yield token(:END, $&) }
21
- 'if' { yield token(:IF, $&) }
22
- 'then' { yield token(:THEN, $&) }
23
- 'while' { yield token(:WHILE, $&) }
24
- 'do' { yield token(:DO, $&) }
25
- 'return' { yield token(:RETURN, $&) }
26
- 'writeln' { yield token(:WRITELN, $&) }
27
- 'write' { yield token(:WRITE, $&) }
28
- 'odd' { yield token(:ODD, $&) }
29
- /[a-zA-Z][a-zA-Z0-9_]*/
30
- { yield token(:IDENT, $&) }
31
- /[0-9]+/ { yield token(:NUMBER, $&.to_i) }
32
- /./ { yield token($&, $&) }
33
- %}
34
-
35
- %AST{
36
- Node [value] { @value = nil }
37
- Visitor
38
- {
39
- STEntry = Struct.new(:kind, :narg, :value)
40
- def initialize
41
- @global = {
42
- '+' => STEntry.new(:FUNC, 2, proc{|a| a[0] + a[1] }),
43
- '-' => STEntry.new(:FUNC, 2, proc{|a| a[0] - a[1] }),
44
- '*' => STEntry.new(:FUNC, 2, proc{|a| a[0] * a[1] }),
45
- '/' => STEntry.new(:FUNC, 2, proc{|a| a[0] / a[1] }),
46
- '=' => STEntry.new(:FUNC, 2, proc{|a| a[0] == a[1] ? 1 : 0}),
47
- '<>' => STEntry.new(:FUNC, 2, proc{|a| a[0] != a[1] ? 1 : 0}),
48
- '<' => STEntry.new(:FUNC, 2, proc{|a| a[0] < a[1] ? 1 : 0}),
49
- '>' => STEntry.new(:FUNC, 2, proc{|a| a[0] > a[1] ? 1 : 0}),
50
- '<=' => STEntry.new(:FUNC, 2, proc{|a| a[0] <= a[1] ? 1 : 0}),
51
- '>=' => STEntry.new(:FUNC, 2, proc{|a| a[0] >= a[1] ? 1 : 0}),
52
- 'odd'=> STEntry.new(:FUNC, 1, proc{|a| a[0] & 1 }),
53
-
54
- 'write' => STEntry.new(:FUNC, 1, proc{|a| print "#{a[0]} "; 1}),
55
- 'writeln' => STEntry.new(:FUNC, 0, proc{|a| puts ''; 1}),
56
- }
57
- @env = [@global]
58
- end
59
- def lookup name
60
- @env.reverse_each{|s| return s[name] if s[name]}
61
- return nil
62
- end
63
- def dump_env n = 2
64
- n = @env.size if n > @env.size
65
- e = @env[n..-1].map{|i| Hash[* i.map{|k, v| [k, v.value]}.flatten ] }
66
- warn e.pretty_inspect
67
- end
68
- }
69
- program(block)
70
- {
71
- visit($.block)
72
- }
73
- block(decls, stmt)
74
- {
75
- @env.push({})
76
- visit($.decls)
77
- visit($.stmt)
78
- @env.pop
79
- }
80
- var_decl(-idents)
81
- {
82
- $.idents.to_a.each do |ident|
83
- if @env.last[ident.value]
84
- warn "'#{ident.value}' already exist."; exit
85
- else
86
- @env.last[ident.value] = STEntry.new(:VAR, 0, 0)
87
- end
88
- end
89
- }
90
- const_decl(const_inits)
91
- {
92
- visit($.const_inits)
93
- }
94
- const_init(-ident, -number)
95
- {
96
- if @env.last[$.ident.value]
97
- warn "'#{$.ident.value}' already exist."; exit
98
- else
99
- @env.last[$.ident.value] = STEntry.new(:CONST, 0, $.number.value)
100
- end
101
- }
102
- func_decl(-ident, -params, -block)
103
- {
104
- if @env[0][$.ident.value]
105
- warn "'#{$.ident.value}' already exist."; exit
106
- end
107
- body = proc do |args|
108
- value = 0
109
- n = @env.size
110
- @env.push({})
111
- value = catch(:return) do
112
- @env.last['return'] = STEntry.new(:VAR, 0, :return)
113
- $.params.to_a.each_with_index do |a, x|
114
- @env.last[a.value] = STEntry.new(:VAR, 0, args[x])
115
- end
116
- visit($.block)
117
- end
118
- @env = @env[0, n]
119
- value
120
- end
121
- @env.last[$.ident.value] = STEntry.new(:FUNC, $.params.size, body)
122
- }
123
- nop_stmt(-nop)
124
- {
125
- }
126
- assign_stmt(-ident, expr)
127
- {
128
- if ent = lookup($.ident.value)
129
- unless ent.kind == :VAR
130
- warn "'#{$.ident.value}' not var."; exit
131
- end
132
- ent.value = visit($.expr).value
133
- else
134
- warn @env.pretty_inspect
135
- warn "'#{$.ident.value}' not found."; exit
136
- end
137
- }
138
- begin_stmt(stmt, stmts)
139
- {
140
- visit($.stmt)
141
- visit($.stmts)
142
- }
143
- if_stmt(cond, stmt)
144
- {
145
- if visit($.cond).value != 0
146
- visit($.stmt)
147
- end
148
- }
149
- while_stmt(cond, stmt)
150
- {
151
- while visit($.cond).value != 0
152
- visit($.stmt)
153
- end
154
- }
155
- return_stmt(expr)
156
- {
157
- ent = nil
158
- @env.reverse_each{|s| break if ent = s['return'] }
159
- unless ent
160
- warn "'return' not in func."; exit
161
- end
162
- throw :return, visit($.expr).value
163
- }
164
- apply(-ident, -args)
165
- {
166
- ent = nil
167
- @env.reverse_each{|s| break if ent = s[$.ident.value] }
168
- unless ent
169
- warn "'#{$.ident.value}' not found."; exit
170
- end
171
- unless ent.kind == :FUNC
172
- warn "'#{$.ident.value}' not func."; exit
173
- end
174
-
175
- args = $.args.to_a.map{|a| visit(a).value }
176
- # warn "#{' '*(@env.size-2)}|#{$.ident.value} : #{args.inspect}"
177
- unless ent.narg == args.size
178
- warn "#{ent.narg} #{args.size} #{args.inspect}"
179
- warn "'#{$.ident.value}' unmatch args."; exit
180
- end
181
- $.value = ent.value.call(args)
182
- # warn "#{' '*(@env.size-2)}|-> #{$.value} @ #{$.ident.value}"
183
- }
184
- refv(-ident)
185
- {
186
- unless ent = lookup($.ident.value)
187
- warn "'#{$.ident.value}' not found."; exit
188
- end
189
- if ent.kind == :VAR || ent.kind == :CONST
190
- $.value = ent.value
191
- else
192
- warn "'#{$.ident.value}' not var."; exit
193
- end
194
- }
195
- number(-n)
196
- {
197
- $.value = $.n.value
198
- }
199
- %}
200
- #begin-rule
201
- program:
202
- block '.'
203
- => program(block)
204
- ;
205
-
206
- block:
207
- opt_decl_list statement
208
- => block(opt_decl_list, statement)
209
- ;
210
-
211
- opt_decl_list:
212
- => []
213
- | opt_decl_list decl
214
- => opt_decl_list << decl
215
- ;
216
-
217
- decl:
218
- CONST const_init_list ';'
219
- => const_decl(const_init_list)
220
- | VAR ident_list ';'
221
- => var_decl(ident_list)
222
- | FUNCTION IDENT '(' ')' block ';'
223
- => func_decl(IDENT, [], block)
224
- | FUNCTION IDENT '(' ident_list ')' block ';'
225
- => func_decl(IDENT, ident_list, block)
226
- ;
227
-
228
- const_init_list:
229
- const_init
230
- => [ const_init ]
231
- | const_init_list ',' const_init
232
- => const_init_list << const_init
233
- ;
234
-
235
- const_init:
236
- IDENT EQ NUMBER
237
- => const_init(IDENT, NUMBER)
238
- ;
239
-
240
- ident_list:
241
- IDENT
242
- => [ IDENT ]
243
- | ident_list ',' IDENT
244
- => ident_list << IDENT
245
- ;
246
-
247
- statement:
248
- => nop_stmt([])
249
- | IDENT COLOEQ expression
250
- => assign_stmt(IDENT, expression)
251
- | BEGINN statement opt_state_list END
252
- => begin_stmt(statement, opt_state_list)
253
- | IF condition THEN statement
254
- => if_stmt(condition, statement)
255
- | WHILE condition DO statement
256
- => while_stmt(condition, statement)
257
- | RETURN expression
258
- => return_stmt(expression)
259
- | WRITE expression
260
- => apply('write', [expression])
261
- | WRITELN
262
- => apply('writeln', [])
263
- ;
264
-
265
- opt_state_list:
266
- => []
267
- | opt_state_list ';' statement
268
- => opt_state_list << statement
269
- ;
270
-
271
- condition:
272
- ODD expression
273
- => apply('odd', [expression])
274
- | expression-e0 EQ expression-e1
275
- => apply('=', [e0, e1])
276
- | expression-e0 NOTEQ expression-e1
277
- => apply('<>', [e0, e1])
278
- | expression-e0 LT expression-e1
279
- => apply('<', [e0, e1])
280
- | expression-e0 GT expression-e1
281
- => apply('>', [e0, e1])
282
- | expression-e0 LE expression-e1
283
- => apply('<=', [e0, e1])
284
- | expression-e0 GE expression-e1
285
- => apply('>=', [e0, e1])
286
- ;
287
-
288
- expression:
289
- expression '+' term
290
- => apply('+', [expression, term])
291
- | expression '-' term
292
- => apply('-', [expression, term])
293
- | term
294
- => term
295
- | '-' term
296
- => apply('UMINUS', [term])
297
- ;
298
-
299
- term:
300
- term '*' factor
301
- => apply('*', [term, factor])
302
- | term '/' factor
303
- => apply('/', [term, factor])
304
- | factor
305
- => factor
306
- ;
307
-
308
- factor:
309
- IDENT
310
- => refv(IDENT)
311
- | NUMBER
312
- => number(NUMBER)
313
- | IDENT '(' ')'
314
- => apply(IDENT, [])
315
- | IDENT '(' exp_list ')'
316
- => apply(IDENT, exp_list)
317
- | '(' expression ')'
318
- => expression
319
- ;
320
-
321
- exp_list:
322
- expression
323
- => [ expression ]
324
- | exp_list ',' expression
325
- => exp_list << expression
326
- ;
327
- #end-rule
328
- %%
329
- require 'pp'
330
- psr = createDecoratedPL0d
331
- t, = psr.parse(STDIN)
332
- # pp t
333
- v = Visitor.new
334
- t.accept(v)
1
+ %class PL0d::Parser
2
+ %extend Depager::Lexer ('plugins/lex.rb')
3
+ %extend Depager::ASTBuilder ('plugins/ast.rb')
4
+ %decorate @ASTBuilder
5
+ #%decorate Depager::LALR::ShiftReducePrinter ('plugins/srp.rb')
6
+ %inner{
7
+ KEYWORDS = {
8
+ 'const' => :CONST,
9
+ 'var' => :VAR,
10
+ 'function' => :FUNCTION,
11
+ 'begin' => :BEGINN,
12
+ 'end' => :END,
13
+ 'if' => :IF,
14
+ 'then' => :THEN,
15
+ 'while' => :WHILE,
16
+ 'do' => :DO,
17
+ 'return' => :RETURN,
18
+ 'writeln' => :WRITELN,
19
+ 'write' => :WRITE,
20
+ 'odd' => :ODD,
21
+ }
22
+ %}
23
+ %%
24
+ %LEX{
25
+ /\s+/ { }
26
+ ':=' { yield token(:COLOEQ, $&) }
27
+ '<>' { yield token(:NOTEQ, $&) }
28
+ '<=' { yield token(:LE, $&) }
29
+ '>=' { yield token(:GE, $&) }
30
+ '=' { yield token(:EQ, $&) }
31
+ '<' { yield token(:LT, $&) }
32
+ '>' { yield token(:GT, $&) }
33
+ /[a-zA-Z][a-zA-Z0-9_]*/ { yield token(KEYWORDS[$&] || :IDENT, $&) }
34
+ /[0-9]+/ { yield token(:NUMBER, $&.to_i) }
35
+ /./ { yield token($&, $&) }
36
+ %}
37
+
38
+ %AST{
39
+ Node [value] { @value = nil }
40
+ Visitor
41
+ {
42
+ STEntry = Struct.new(:kind, :narg, :value)
43
+ def initialize
44
+ @global = {
45
+ '+' => STEntry.new(:FUNC, 2, proc{|a| a[0] + a[1] }),
46
+ '-' => STEntry.new(:FUNC, 2, proc{|a| a[0] - a[1] }),
47
+ '*' => STEntry.new(:FUNC, 2, proc{|a| a[0] * a[1] }),
48
+ '/' => STEntry.new(:FUNC, 2, proc{|a| a[0] / a[1] }),
49
+ '=' => STEntry.new(:FUNC, 2, proc{|a| a[0] == a[1] ? 1 : 0}),
50
+ '<>' => STEntry.new(:FUNC, 2, proc{|a| a[0] != a[1] ? 1 : 0}),
51
+ '<' => STEntry.new(:FUNC, 2, proc{|a| a[0] < a[1] ? 1 : 0}),
52
+ '>' => STEntry.new(:FUNC, 2, proc{|a| a[0] > a[1] ? 1 : 0}),
53
+ '<=' => STEntry.new(:FUNC, 2, proc{|a| a[0] <= a[1] ? 1 : 0}),
54
+ '>=' => STEntry.new(:FUNC, 2, proc{|a| a[0] >= a[1] ? 1 : 0}),
55
+ 'odd'=> STEntry.new(:FUNC, 1, proc{|a| a[0] & 1 }),
56
+
57
+ 'write' => STEntry.new(:FUNC, 1, proc{|a| print "#{a[0]} "; 1}),
58
+ 'writeln' => STEntry.new(:FUNC, 0, proc{|a| puts ''; 1}),
59
+ }
60
+ @env = [@global]
61
+ end
62
+ def lookup name
63
+ @env.reverse_each{|s| return s[name] if s[name]}
64
+ return nil
65
+ end
66
+ def dump_env n = 2
67
+ n = @env.size if n > @env.size
68
+ e = @env[n..-1].map{|i| Hash[* i.map{|k, v| [k, v.value]}.flatten ] }
69
+ warn e.pretty_inspect
70
+ end
71
+ }
72
+ program(block)
73
+ {
74
+ visit($.block)
75
+ }
76
+ block(decls, stmt)
77
+ {
78
+ @env.push({})
79
+ visit($.decls)
80
+ visit($.stmt)
81
+ @env.pop
82
+ }
83
+ var_decl(-idents)
84
+ {
85
+ $.idents.to_a.each do |ident|
86
+ if @env.last[ident.value]
87
+ warn "'#{ident.value}' already exist."; exit
88
+ else
89
+ @env.last[ident.value] = STEntry.new(:VAR, 0, 0)
90
+ end
91
+ end
92
+ }
93
+ const_decl(const_inits)
94
+ {
95
+ visit($.const_inits)
96
+ }
97
+ const_init(-ident, -number)
98
+ {
99
+ if @env.last[$.ident.value]
100
+ warn "'#{$.ident.value}' already exist."; exit
101
+ else
102
+ @env.last[$.ident.value] = STEntry.new(:CONST, 0, $.number.value)
103
+ end
104
+ }
105
+ func_decl(-ident, -params, -block)
106
+ {
107
+ if @env[0][$.ident.value]
108
+ warn "'#{$.ident.value}' already exist."; exit
109
+ end
110
+ body = proc do |args|
111
+ value = 0
112
+ n = @env.size
113
+ @env.push({})
114
+ value = catch(:return) do
115
+ @env.last['return'] = STEntry.new(:VAR, 0, :return)
116
+ $.params.to_a.each_with_index do |a, x|
117
+ @env.last[a.value] = STEntry.new(:VAR, 0, args[x])
118
+ end
119
+ visit($.block)
120
+ end
121
+ @env = @env[0, n]
122
+ value
123
+ end
124
+ @env.last[$.ident.value] = STEntry.new(:FUNC, $.params.size, body)
125
+ }
126
+ nop_stmt(-nop)
127
+ {
128
+ }
129
+ assign_stmt(-ident, expr)
130
+ {
131
+ if ent = lookup($.ident.value)
132
+ unless ent.kind == :VAR
133
+ warn "'#{$.ident.value}' not var."; exit
134
+ end
135
+ ent.value = visit($.expr).value
136
+ else
137
+ warn @env.pretty_inspect
138
+ warn "'#{$.ident.value}' not found."; exit
139
+ end
140
+ }
141
+ begin_stmt(stmt, stmts)
142
+ {
143
+ visit($.stmt)
144
+ visit($.stmts)
145
+ }
146
+ if_stmt(cond, stmt)
147
+ {
148
+ if visit($.cond).value != 0
149
+ visit($.stmt)
150
+ end
151
+ }
152
+ while_stmt(cond, stmt)
153
+ {
154
+ while visit($.cond).value != 0
155
+ visit($.stmt)
156
+ end
157
+ }
158
+ return_stmt(expr)
159
+ {
160
+ ent = nil
161
+ @env.reverse_each{|s| break if ent = s['return'] }
162
+ unless ent
163
+ warn "'return' not in func."; exit
164
+ end
165
+ throw :return, visit($.expr).value
166
+ }
167
+ apply(-ident, -args)
168
+ {
169
+ ent = nil
170
+ @env.reverse_each{|s| break if ent = s[$.ident.value] }
171
+ unless ent
172
+ warn "'#{$.ident.value}' not found."; exit
173
+ end
174
+ unless ent.kind == :FUNC
175
+ warn "'#{$.ident.value}' not func."; exit
176
+ end
177
+
178
+ args = $.args.to_a.map{|a| visit(a).value }
179
+ # warn "#{' '*(@env.size-2)}|#{$.ident.value} : #{args.inspect}"
180
+ unless ent.narg == args.size
181
+ warn "#{ent.narg} #{args.size} #{args.inspect}"
182
+ warn "'#{$.ident.value}' unmatch args."; exit
183
+ end
184
+ $.value = ent.value.call(args)
185
+ # warn "#{' '*(@env.size-2)}|-> #{$.value} @ #{$.ident.value}"
186
+ }
187
+ refv(-ident)
188
+ {
189
+ unless ent = lookup($.ident.value)
190
+ warn "'#{$.ident.value}' not found."; exit
191
+ end
192
+ if ent.kind == :VAR || ent.kind == :CONST
193
+ $.value = ent.value
194
+ else
195
+ warn "'#{$.ident.value}' not var."; exit
196
+ end
197
+ }
198
+ number(-n)
199
+ {
200
+ $.value = $.n.value
201
+ }
202
+ %}
203
+ #begin-rule
204
+ program:
205
+ block '.'
206
+ => program(block)
207
+ ;
208
+
209
+ block:
210
+ opt_decl_list statement
211
+ => block(opt_decl_list, statement)
212
+ ;
213
+
214
+ opt_decl_list:
215
+ => []
216
+ | opt_decl_list decl
217
+ => opt_decl_list << decl
218
+ ;
219
+
220
+ decl:
221
+ CONST const_init_list ';'
222
+ => const_decl(const_init_list)
223
+ | VAR ident_list ';'
224
+ => var_decl(ident_list)
225
+ | FUNCTION IDENT '(' ')' block ';'
226
+ => func_decl(IDENT, [], block)
227
+ | FUNCTION IDENT '(' ident_list ')' block ';'
228
+ => func_decl(IDENT, ident_list, block)
229
+ ;
230
+
231
+ const_init_list:
232
+ const_init
233
+ => [ const_init ]
234
+ | const_init_list ',' const_init
235
+ => const_init_list << const_init
236
+ ;
237
+
238
+ const_init:
239
+ IDENT EQ NUMBER
240
+ => const_init(IDENT, NUMBER)
241
+ ;
242
+
243
+ ident_list:
244
+ IDENT
245
+ => [ IDENT ]
246
+ | ident_list ',' IDENT
247
+ => ident_list << IDENT
248
+ ;
249
+
250
+ statement:
251
+ => nop_stmt([])
252
+ | IDENT COLOEQ expression
253
+ => assign_stmt(IDENT, expression)
254
+ | BEGINN statement opt_state_list END
255
+ => begin_stmt(statement, opt_state_list)
256
+ | IF condition THEN statement
257
+ => if_stmt(condition, statement)
258
+ | WHILE condition DO statement
259
+ => while_stmt(condition, statement)
260
+ | RETURN expression
261
+ => return_stmt(expression)
262
+ | WRITE expression
263
+ => apply('write', [expression])
264
+ | WRITELN
265
+ => apply('writeln', [])
266
+ ;
267
+
268
+ opt_state_list:
269
+ => []
270
+ | opt_state_list ';' statement
271
+ => opt_state_list << statement
272
+ ;
273
+
274
+ condition:
275
+ ODD expression
276
+ => apply('odd', [expression])
277
+ | expression-e0 EQ expression-e1
278
+ => apply('=', [e0, e1])
279
+ | expression-e0 NOTEQ expression-e1
280
+ => apply('<>', [e0, e1])
281
+ | expression-e0 LT expression-e1
282
+ => apply('<', [e0, e1])
283
+ | expression-e0 GT expression-e1
284
+ => apply('>', [e0, e1])
285
+ | expression-e0 LE expression-e1
286
+ => apply('<=', [e0, e1])
287
+ | expression-e0 GE expression-e1
288
+ => apply('>=', [e0, e1])
289
+ ;
290
+
291
+ expression:
292
+ expression '+' term
293
+ => apply('+', [expression, term])
294
+ | expression '-' term
295
+ => apply('-', [expression, term])
296
+ | term
297
+ => term
298
+ | '-' term
299
+ => apply('UMINUS', [term])
300
+ ;
301
+
302
+ term:
303
+ term '*' factor
304
+ => apply('*', [term, factor])
305
+ | term '/' factor
306
+ => apply('/', [term, factor])
307
+ | factor
308
+ => factor
309
+ ;
310
+
311
+ factor:
312
+ IDENT
313
+ => refv(IDENT)
314
+ | NUMBER
315
+ => number(NUMBER)
316
+ | IDENT '(' ')'
317
+ => apply(IDENT, [])
318
+ | IDENT '(' exp_list ')'
319
+ => apply(IDENT, exp_list)
320
+ | '(' expression ')'
321
+ => expression
322
+ ;
323
+
324
+ exp_list:
325
+ expression
326
+ => [ expression ]
327
+ | exp_list ',' expression
328
+ => exp_list << expression
329
+ ;
330
+ #end-rule
331
+ %%
332
+ require 'pp'
333
+ psr = PL0d.create_decorated_parser
334
+ t, = psr.parse(STDIN)
335
+ # pp t
336
+ v = PL0d::Visitor.new
337
+ t.accept(v)