depager 0.2.3 → 0.3.0.b20250423

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 (106) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +44 -0
  3. data/.simplecov +5 -0
  4. data/Gemfile +12 -0
  5. data/LICENSE.gpl +339 -0
  6. data/Manifest.txt +73 -0
  7. data/README.en +7 -21
  8. data/README.ja +19 -99
  9. data/Rakefile +31 -0
  10. data/bin/depager +7 -45
  11. data/examples/action_pl0d/pl0d.action.dr +421 -0
  12. data/examples/action_pl0d/test.pl0ds +48 -0
  13. data/examples/c89/c89.dr +493 -496
  14. data/examples/c89/test.c89 +10 -10
  15. data/examples/extension/astdf.rb +9 -0
  16. data/examples/extension/atree.dr +55 -0
  17. data/examples/{sample_calc → extension}/calc.atree.dr +42 -43
  18. data/examples/{sample_calc/calc.action.dr → extension/calc.simple_action.dr} +33 -33
  19. data/examples/extension/paction.dr +16 -15
  20. data/examples/extension/pactiontest.dr +14 -14
  21. data/examples/extension/simple_action.rb +46 -0
  22. data/examples/pl0d/pl0ds.dr +337 -334
  23. data/examples/pl0d/test.pl0ds +33 -33
  24. data/examples/rie_calc/calc.rie.dr +57 -0
  25. data/examples/rie_calc/test.calc +4 -0
  26. data/examples/rie_dcuse/dcuse.rie.dr +71 -0
  27. data/examples/rie_dcuse/test.dcuse +1 -0
  28. data/examples/rie_pl0/orig_ex/exerrdg.pl0 +44 -0
  29. data/examples/rie_pl0/orig_ex/exerrm.pl0 +19 -0
  30. data/examples/rie_pl0/orig_ex/exerrmre.pl0 +20 -0
  31. data/examples/rie_pl0/orig_ex/exerrtok.pl0 +18 -0
  32. data/examples/rie_pl0/orig_ex/exmdg.pl0 +40 -0
  33. data/examples/rie_pl0/orig_ex/exmdgwwl.pl0 +43 -0
  34. data/examples/rie_pl0/orig_ex/exmrw.pl0 +22 -0
  35. data/examples/rie_pl0/orig_ex/exmwwl.pl0 +18 -0
  36. data/examples/rie_pl0/orig_ex/exnorw.pl0 +17 -0
  37. data/examples/rie_pl0/pl0.rie.dr +450 -0
  38. data/examples/rie_pl0/test.pl0 +10 -0
  39. data/examples/slex_test/divreg.slex.dr +29 -29
  40. data/examples/slex_test/ljoin.slex.dr +36 -36
  41. data/examples/slex_test/test.divreg +1 -1
  42. data/examples/slex_test/test.ljoin +3 -3
  43. data/examples/{sample_calc/calc.nvaction.dr → tiny_calc/calc.action.dr} +33 -33
  44. data/examples/{sample_calc → tiny_calc}/calc.ast.action.dr +76 -66
  45. data/examples/{sample_calc → tiny_calc}/calc.ast.dr +67 -55
  46. data/examples/tiny_calc/calc.cst.dr +50 -0
  47. data/examples/{sample_calc → tiny_calc}/calc.dr +43 -43
  48. data/examples/{sample_calc → tiny_calc}/calc.lex.dr +29 -29
  49. data/examples/{sample_calc/calc_prec.nvaction.dr → tiny_calc/calc_prec.action.dr} +31 -31
  50. data/lib/depager/cli.rb +44 -0
  51. data/lib/depager/grammar.rb +253 -291
  52. data/lib/depager/lr.rb +589 -579
  53. data/lib/depager/parser.rb +269 -277
  54. data/lib/depager/plugins/_rie_debug.rb +63 -0
  55. data/lib/depager/plugins/action.rb +47 -0
  56. data/lib/depager/plugins/ast.dr +367 -0
  57. data/lib/depager/plugins/ast.rb +1329 -0
  58. data/lib/depager/{ruby/plugins → plugins}/cst.dr +174 -180
  59. data/lib/depager/plugins/cst.rb +591 -0
  60. data/lib/depager/{ruby/plugins → plugins}/lex.dr +85 -89
  61. data/lib/depager/plugins/lex.rb +313 -0
  62. data/lib/depager/plugins/rie.dr +725 -0
  63. data/lib/depager/plugins/rie.rb +1614 -0
  64. data/lib/depager/{ruby/plugins → plugins}/slex.dr +201 -200
  65. data/lib/depager/plugins/slex.rb +769 -0
  66. data/lib/depager/plugins/srp.rb +46 -0
  67. data/lib/depager/ruby/templates/extension_lalr_master.erb +40 -51
  68. data/lib/depager/ruby/templates/extension_lalr_slave.erb +113 -107
  69. data/lib/depager/ruby/templates/single_lalr_parser.erb +124 -117
  70. data/lib/depager/utils.rb +158 -318
  71. data/lib/depager/version.rb +3 -3
  72. data/lib/depager.rb +572 -670
  73. metadata +77 -80
  74. data/ChangeLog +0 -16
  75. data/data/depager/pre-setup.rb +0 -3
  76. data/examples/c89/c89.tab.rb +0 -7127
  77. data/examples/pl0d/pl0ds.tab.rb +0 -2698
  78. data/examples/sample_calc/calc.action.tab.rb +0 -457
  79. data/examples/sample_calc/calc.ast.action.tab.rb +0 -749
  80. data/examples/sample_calc/calc.ast.tab.rb +0 -665
  81. data/examples/sample_calc/calc.astdf.dr +0 -54
  82. data/examples/sample_calc/calc.astdf.tab.rb +0 -672
  83. data/examples/sample_calc/calc.atree.tab.rb +0 -451
  84. data/examples/sample_calc/calc.cst.dr +0 -45
  85. data/examples/sample_calc/calc.cst.tab.rb +0 -644
  86. data/examples/sample_calc/calc.lex.tab.rb +0 -374
  87. data/examples/sample_calc/calc.nvaction.tab.rb +0 -465
  88. data/examples/sample_calc/calc.tab.rb +0 -365
  89. data/examples/sample_calc/calc_prec.nvaction.tab.rb +0 -431
  90. data/examples/slex_test/divreg.slex.tab.rb +0 -303
  91. data/examples/slex_test/ljoin.slex.tab.rb +0 -370
  92. data/lib/depager/ruby/plugins/_ast_tmpl.rb +0 -73
  93. data/lib/depager/ruby/plugins/action.rb +0 -43
  94. data/lib/depager/ruby/plugins/ast.dr +0 -269
  95. data/lib/depager/ruby/plugins/ast.rb +0 -1308
  96. data/lib/depager/ruby/plugins/astdf.rb +0 -6
  97. data/lib/depager/ruby/plugins/atree.dr +0 -55
  98. data/lib/depager/ruby/plugins/atree.rb +0 -347
  99. data/lib/depager/ruby/plugins/cst.rb +0 -626
  100. data/lib/depager/ruby/plugins/lex.rb +0 -336
  101. data/lib/depager/ruby/plugins/nvaction.rb +0 -19
  102. data/lib/depager/ruby/plugins/slex.rb +0 -817
  103. data/lib/depager/ruby/plugins/srp.rb +0 -51
  104. data/lib/depager/ruby/templates/simple.erb +0 -23
  105. data/setup.rb +0 -1585
  106. /data/examples/{sample_calc → tiny_calc}/test.calc +0 -0
data/README.ja CHANGED
@@ -1,127 +1,47 @@
1
1
  Depager README
2
2
  ==============
3
3
 
4
- Deager�ϼ��ʳ�ĥ��ǽ�ʹ�ʸ���ϴ������ϤǤ���
4
+ Deagerは自己拡張可能な構文解析器生成系です。
5
5
 
6
6
 
7
- ɬ�״Ķ�
7
+ 必要環境
8
8
  --------
9
9
 
10
- * Ruby 1.8
10
+ * Ruby 3.0
11
11
 
12
12
 
13
- ���󥹥ȡ�����ˡ(gem)
13
+ インストール方法(gem)
14
14
  ---------------------
15
15
 
16
- gem��depager�򤪻Ȥ��Υ����ƥ�˥��󥹥ȡ��뤹���硢
17
- ���ޥ�ɥ饤��ǰʲ��Τ褦���Ǥ�����Ǥ���������
16
+ $ sudo gem install depager
18
17
 
19
- # sudo gem install depager
20
18
 
19
+ 簡単な使い方
20
+ ------------
21
21
 
22
- ���󥹥ȡ�����ˡ(tgz)
23
- ---------------------
24
-
25
- tgz��depager�򤪻Ȥ��Υ����ƥ�˥��󥹥ȡ��뤹���硢
26
- ���ޥ�ɥ饤��ǰʲ��Τ褦���Ǥ�����Ǥ���������
27
- UNIX �� OS �ǤϤ����餯 root ���¤�ɬ�פˤʤ�ޤ���
28
-
29
- ($ su)
30
- # ruby setup.rb
31
-
32
- �ĿͤΥۡ���ǥ��쥯�ȥ�ʲ��˥��󥹥ȡ��뤹���硢
33
- ���ޥ�ɥ饤��ǰʲ��Τ褦���Ǥ�����Ǥ���������
34
-
35
- # ruby setup.rb all --installdirs=home
36
-
37
- �ĿͤΥۡ���ǥ��쥯�ȥ�ʲ��˥��󥹥ȡ��뤷����硢
38
- �Ķ��ѿ�RUBYLIB�˥ǥ��쥯�ȥ���ɲä��Ƥ���������
39
- (�����餯 $HOME/lib/ruby �Ǥ�)
22
+ $ depager -o 出力ファイル 入力ファイル
40
23
 
41
- $ RUBYLIB=$RUBYLIB:$HOME/lib/ruby
42
- $ export RUBYLIB
24
+ 例:
43
25
 
44
- ���󥹥ȡ�������ѹ������ꤹ�뤳�Ȥ�Ǥ��ޤ���
45
- ���ξ��� ruby setup.rb --help ��¹Ԥ��ƤߤƤ���������
26
+ $ depager -o calc.tab.rb calc.dr
46
27
 
47
- ����˾ܤ���setup.rb�λȤ����ˤĤ��Ƥϡ�
48
- setup.rb ( LoveRubyNet )
49
- http://i.loveruby.net/ja/projects/setup/
50
- �򻲾Ȥ��Ƥ���������
28
+ 詳しくは -h オプションをご利用ください。
51
29
 
52
30
 
53
- ��ñ�ʻȤ���
54
- ------------
55
-
56
- # depager -o ���ϥե����� ���ϥե�����
57
-
58
- ��.
59
-
60
- # depager -o calc.tab.rb calc.dr
61
-
62
- �ܤ����� -h ���ץ��������Ѥ���������
63
-
64
-
65
- �ե�����δ�ñ������
66
- --------------------
67
-
68
- /bin
69
- depager �¹���
70
- /lib
71
- depager.rb �����ϥᥤ��
72
- /depager
73
- lr.rb LRɽ������
74
- grammar.rb ���ϼ�ˡ���
75
- utils.rb ����⥸�塼�뷲
76
- version.rb ����������
77
- parser.rb ��󥿥���饤�֥��
78
- /ruby
79
- /plugins
80
- action.rb ����������ĥ
81
- ast.rb AST��ĥ
82
- astdf.rb ����ͥ��õ��AST��ĥ
83
- atree.rb ����ˤ���ڹ��۳�ĥ
84
- cst.rb CST��ĥ
85
- lex.rb ������ϳ�ĥ
86
- nvaction.rb ̾���ե���������ĥ
87
- srp.rb �����å�ɽ���ǥ��졼��
88
- slex.rb �����ջ�����ϳ�ĥ
89
- /templetes
90
- extension_lalr_master.erb
91
- ��ĥ�ޥ����ƥ�ץ졼��
92
- extension_lalr_slave.erb
93
- ��ĥ���졼�֥ƥ�ץ졼��
94
- simple.rb
95
- ����ץ�ƥ�ץ졼��
96
- single_lalr_parser.erb
97
- ɸ��LR�ѡ����ƥ�ץ졼��
98
- /data
99
- /depager
100
- /misc
101
- depager-mode.el Emacs��depager-mode
102
- /examples
103
- /c89 c89�ѡ���
104
- /pl0d PL0���󥿥ץ꥿
105
- /extension ��ĥ����ץ�
106
- /samlpe_calc ���������������ץ�
107
- /slextest �����ջ�����ϳ�ĥ����ץ�
108
-
109
-
110
- �饤����
31
+ ライセンス
111
32
  ----------
112
33
 
113
- GPL�˽��ä����ۤ��ޤ���
34
+ GNU GPL Version 2 に従って配布します。
114
35
 
115
36
 
116
- ����¾
37
+ その他
117
38
  ------
118
39
 
119
- Depager�������δ��ĤΤ�ȡ�maita��������
120
- ���漼�ˤ�äƳ�ȯ����ޤ�����
121
-
122
- Depager�δ�Ȥʤä�Depage��Ʊ���漼�κ����ϻ�ˤ�ä�
123
- ��ȯ����ޤ�����
40
+ Depagerは中井央の監督のもと、maitaおよび中井
41
+ 研究室によって開発されました。
42
+
43
+ Depagerの基となったDepageは同研究室の佐竹力氏によって
44
+ 開発されました。
124
45
 
125
46
 
126
47
  maita <maita@fujiyama.slis.tsukuba.ac.jp>
127
- ��渦�漼 http://nakai2.slis.tsukuba.ac.jp/hiki/
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
5
+ require "minitest/test_task"
6
+
7
+ RuboCop::RakeTask.new
8
+
9
+ Minitest::TestTask.create(:test) do |t|
10
+ t.test_prelude = "require \"simplecov\""
11
+ end
12
+
13
+ desc "Build plugins"
14
+ task :build_plugins do
15
+ plugins = %w[lex ast cst rie slex]
16
+ plugins.each do |i|
17
+ input_path = "lib/depager/plugins/#{i}.dr"
18
+ output_path = "lib/depager/plugins/#{i}.rb"
19
+ ruby "bin/depager", "-o", output_path, input_path
20
+ end
21
+ end
22
+
23
+ desc "Update Manifest.txt"
24
+ task :update_manifest do
25
+ files = `git ls-files -z`.split("\x0").reject do |f|
26
+ f.end_with?(".gemspec") || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
27
+ end
28
+ File.open("Manifest.txt", "w") { |f| f.puts(files.sort.join("\n")) }
29
+ end
30
+
31
+ task default: :test
data/bin/depager CHANGED
@@ -1,45 +1,7 @@
1
- #!/usr/local/bin/ruby
2
- require 'depager'
3
- require 'optparse'
4
-
5
- include Depager
6
- begin
7
- $MP_VERBOSE = nil
8
- $MP_DEBUG = nil
9
- dp = nil
10
- output_file_name = nil
11
- ARGV.options do |opt|
12
- opt.on('-v') { $MP_VERBOSE = true }
13
- opt.on('-g[FLAGS]') {|flags| $MP_DEBUG = flags || 'sgc' }
14
- opt.on('-o OUTPUT') {|ofn| output_file_name = ofn }
15
- opt.parse!
16
- end
17
-
18
- f = ARGV[0] ? File.open(ARGV[0]) : STDIN
19
- begin
20
- dp = DeclParser.new
21
- res = dp.parse(f, ARGV[0])
22
- if output_file_name
23
- File.open(output_file_name, "w"){|o| o.write res }
24
- else
25
- print res
26
- end
27
- rescue Exception
28
- lineno = dp.files.lineno rescue '?'
29
- raise
30
- end
31
- rescue SystemExit
32
- raise
33
- rescue Exception
34
- warn "#{File.basename $0}: fatal error."
35
- warn "| #{$!}"
36
- warn "| - #{dp.files.path}:#{lineno}" if dp
37
- $@[0].match(/^(.+):(\d+)(:.+)?$/)
38
- warn "| ( #{File.basename $1}:#{$2} )"
39
- if $MP_DEBUG
40
- warn "#{File.basename $0}: #{$@.unshift($!).join("\n")}"
41
- else
42
- warn "Try -g option if you want to see more error infomation."
43
- end
44
- exit 1
45
- end
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
4
+
5
+ require "depager/cli"
6
+
7
+ exit Depager::CLI.new.run(ARGV.dup)
@@ -0,0 +1,421 @@
1
+ %class Pl0d::Parser
2
+ %extend Depager::Lexer ('depager/plugins/lex.rb')
3
+ %extend Depager::Action ('depager/plugins/action.rb')
4
+ %decorate @Action
5
+ #%decorate Depager::LALR::ShiftReducePrinter ('depager/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
+ #begin-rule
39
+ program:
40
+ block '.'
41
+ {
42
+ debug{ warn _block.pretty_inspect }
43
+ execute(linearize_codes(_block))
44
+ }
45
+ ;
46
+
47
+ block:
48
+ opt_decl_list statement
49
+ {
50
+ func = env.lookup('#FUNC#')
51
+ [
52
+ [ :O_JMP, 0, func.value ],
53
+ _opt_decl_list,
54
+ [ :O_LAB, 0, func.value ],
55
+ [ :O_INT, 0, env.max_addr-2 ],
56
+ _statement,
57
+ [ :O_RET, 0, func.argc ]
58
+ ]
59
+ }
60
+ ;
61
+
62
+ opt_decl_list:
63
+ { [] }
64
+ | opt_decl_list decl
65
+ { _opt_decl_list.concat _decl }
66
+ ;
67
+
68
+ decl:
69
+ CONST const_init_list ';'
70
+ { [ ] }
71
+ | VAR ident_list ';'
72
+ {
73
+ _ident_list.each do |ident|
74
+ not env.lookup( ident, 1 ) or
75
+ error_exit "redeclaration of variable '%s'", ident
76
+ env.install :VARIABLE, ident, nil
77
+ end
78
+ [ ]
79
+ }
80
+ | func_head block ';'
81
+ { env.leave ; _block }
82
+ ;
83
+
84
+ func_head:
85
+ FUNCTION IDENT '(' opt_ident_list ')'
86
+ {
87
+ argc = _opt_ident_list.size
88
+ lab = env.genlab
89
+ not env.lookup( _IDENT.value, 1 ) or
90
+ error_exit "redeclaration of function '%s'", _IDENT.value
91
+ env.install :FUNCTION, _IDENT.value, lab, argc
92
+ env.enter
93
+ env.install :INFO, '#FUNC#', lab, argc
94
+ _opt_ident_list.each_with_index do |ident, x|
95
+ env.install :VARIABLE, ident, x-argc
96
+ end
97
+ }
98
+ ;
99
+
100
+ const_init_list:
101
+ const_init
102
+ { }
103
+ | const_init_list ',' const_init
104
+ { }
105
+ ;
106
+
107
+ const_init:
108
+ IDENT EQ NUMBER
109
+ {
110
+ not env.lookup( _IDENT.value, 1 ) or
111
+ error_exit "redeclaration of constant '%s'", _IDENT.value
112
+ env.install :CONSTANT, _IDENT.value, _NUMBER.value
113
+ }
114
+ ;
115
+
116
+ opt_ident_list:
117
+ { [] }
118
+ | ident_list
119
+ { _ident_list }
120
+ ;
121
+
122
+ ident_list:
123
+ IDENT
124
+ { [ _IDENT.value ] }
125
+ | ident_list ',' IDENT
126
+ { _ident_list << _IDENT.value }
127
+ ;
128
+
129
+ statement:
130
+ { [] }
131
+ | IDENT COLOEQ expression
132
+ {
133
+ entry = env.lookup( _IDENT.value )
134
+ entry or
135
+ error_exit "undeclared identifier %s", _IDENT.value
136
+ entry.kind == :VARIABLE or
137
+ error_exit "assignment to constant/procedure is not allowed"
138
+ [
139
+ _expression,
140
+ [ :O_STO, env.level - entry.level, entry.value ]
141
+ ]
142
+ }
143
+ | BEGINN state_list END
144
+ {
145
+ _state_list
146
+ }
147
+ | IF condition THEN statement
148
+ {
149
+ lab = env.genlab();
150
+ [
151
+ _condition,
152
+ [ :O_JPC, 0, lab ],
153
+ _statement,
154
+ [ :O_LAB, 0, lab ]
155
+ ]
156
+ }
157
+ | WHILE condition DO statement
158
+ {
159
+ lab1 = env.genlab()
160
+ lab2 = env.genlab()
161
+ [
162
+ [ :O_LAB, 0, lab1 ],
163
+ _condition,
164
+ [ :O_JPC, 0, lab2 ],
165
+ _statement,
166
+ [ :O_JMP, 0, lab1 ],
167
+ [ :O_LAB, 0, lab2 ]
168
+ ]
169
+ }
170
+ | RETURN expression
171
+ {
172
+ [
173
+ _expression,
174
+ [ :O_RET, 0, env.lookup('#FUNC#').argc ]
175
+ ]
176
+ }
177
+ | WRITE expression
178
+ {
179
+ [
180
+ _expression,
181
+ [ :O_OPR, 0, :P_WRI ]
182
+ ]
183
+ }
184
+ | WRITELN
185
+ { [ [ :O_OPR, 0, :P_WRL ] ] }
186
+ ;
187
+
188
+ state_list:
189
+ statement
190
+ { [ _statement ] }
191
+ | state_list ';' statement
192
+ { _state_list << _statement }
193
+ ;
194
+
195
+ condition:
196
+ ODD expression
197
+ { [ _expression, [ :O_OPR, 0, :P_ODD ] ] }
198
+ | expression-e0 EQ expression-e1
199
+ { [ _e0, _e1, [ :O_OPR, 0, :P_EQ ] ] }
200
+ | expression-e0 NOTEQ expression-e1
201
+ { [ _e0, _e1, [ :O_OPR, 0, :P_NE ] ] }
202
+ | expression-e0 LT expression-e1
203
+ { [ _e0, _e1, [ :O_OPR, 0, :P_LT ] ] }
204
+ | expression-e0 GT expression-e1
205
+ { [ _e0, _e1, [ :O_OPR, 0, :P_GT ] ] }
206
+ | expression-e0 LE expression-e1
207
+ { [ _e0, _e1, [ :O_OPR, 0, :P_LE ] ] }
208
+ | expression-e0 GE expression-e1
209
+ { [ _e0, _e1, [ :O_OPR, 0, :P_GE ] ] }
210
+ ;
211
+
212
+ expression:
213
+ expression '+' term
214
+ { [ _expression, _term, [ :O_OPR, 0, :P_ADD ] ] }
215
+ | expression '-' term
216
+ { [ _expression, _term, [ :O_OPR, 0, :P_SUB ] ] }
217
+ | term
218
+ { _term }
219
+ | '-' term
220
+ { [ _term, [ :O_OPR, 0, :P_NEG ] ] }
221
+ ;
222
+
223
+ term:
224
+ term '*' factor
225
+ { [ _term, _factor, [ :O_OPR, 0, :P_MUL ] ] }
226
+ | term '/' factor
227
+ { [ _term, _factor, [ :O_OPR, 0, :P_DIV ] ] }
228
+ | factor
229
+ { _factor }
230
+ ;
231
+
232
+ factor:
233
+ IDENT
234
+ {
235
+ entry = env.lookup( _IDENT.value )
236
+ entry or
237
+ error_exit "undeclared identifier %s", _IDENT.value
238
+ entry.kind != :FUNCTION or
239
+ error_exit "expression must not contain a procedure identifier"
240
+ entry.kind == :CONSTANT ?
241
+ [ :O_LIT, 0, entry.value ] :
242
+ [ :O_LOD, env.level - entry.level, entry.value ]
243
+ }
244
+ | NUMBER
245
+ { [ :O_LIT, 0, _NUMBER.value ] }
246
+ | IDENT '(' opt_exp_list ')'
247
+ {
248
+ entry = env.lookup( _IDENT.value )
249
+ entry or
250
+ error_exit "undeclared identifier %s", _IDENT.value
251
+ entry.kind == :FUNCTION or
252
+ error_exit "call of a constant or a variable is meaningless"
253
+ entry.argc == _opt_exp_list.size or
254
+ error_exit "wrong number of arguments %i for %i", _opt_exp_list.size, entry.argc
255
+ [
256
+ _opt_exp_list,
257
+ [ :O_CAL, env.level - entry.level, entry.value ]
258
+ ]
259
+ }
260
+ | '(' expression ')'
261
+ { _expression }
262
+ ;
263
+
264
+ opt_exp_list:
265
+ { [] }
266
+ | exp_list
267
+ { _exp_list }
268
+ ;
269
+
270
+ exp_list:
271
+ expression
272
+ { [ _expression ] }
273
+ | exp_list ',' expression
274
+ { _exp_list << _expression }
275
+ ;
276
+ #end-rule
277
+ %%
278
+
279
+ class Pl0d::Action
280
+ class Entry
281
+ attr_accessor :kind, :name, :value, :argc, :level
282
+
283
+ def initialize k, n, v, c, l
284
+ @kind, @name, @value, @argc, @level = k, n, v, c, l
285
+ end
286
+ def inspect
287
+ "(#{@name}.#{@level}:#{@kind.to_s[0,1]}[#{@argc}]/#{@value})"
288
+ end
289
+ end
290
+
291
+ class Env
292
+ def initialize
293
+ @stack, @label = [], 0
294
+ end
295
+ def enter
296
+ @stack.push({})
297
+ end
298
+ def leave
299
+ @stack.pop
300
+ end
301
+ def level
302
+ @stack.size-1
303
+ end
304
+ def install k, n, v, c = 0
305
+ v ||= max_addr+1
306
+ @stack.last[n] = Entry.new(k, n, v, c, level)
307
+ end
308
+ def lookup name, n = nil
309
+ return nil if @stack.empty?
310
+ n ||= @stack.size
311
+ (1 .. n).each do |x|
312
+ result = @stack[-x][name] and
313
+ return result
314
+ end
315
+ return nil
316
+ end
317
+ def max_addr
318
+ # 3 local variables are reserved(BP+0,BP+1,BP+2).
319
+ max = @stack.last.select{|k,v| v.kind==:VARIABLE }.map{|k,v| v.value}.max.to_i
320
+ max < 2 ? 2 : max
321
+ end
322
+ def genlab
323
+ @label += 1
324
+ end
325
+ def inspect
326
+ result = "LEVEL:#{level}\n"
327
+ @stack.reverse.each_with_index do |i,x|
328
+ result << "(#{level-x}):#{i.inspect}\n"
329
+ end
330
+ result
331
+ end
332
+ end
333
+
334
+ attr_reader :env
335
+ def initialize inside
336
+ super
337
+ @env = Env.new
338
+ env.enter ; env.install :CONSTANT, "#FUNC#", env.genlab, 0
339
+ end
340
+ def error_exit *args
341
+ print("#{basis.file.lineno}:")
342
+ printf(*args); print "\n"; exit
343
+ end
344
+ def debug
345
+ yield if $DEBUG
346
+ end
347
+ def linearize_codes codes, res=[], labs={}
348
+ codes.each do |i|
349
+ i.is_a? Array or
350
+ raise "invalid code"
351
+ case i[0]
352
+ when :O_LAB
353
+ lab, addr = i[2], res.size
354
+ debug{ warn "LABEL: L#{lab}->##{addr} BACKPATCH: #{labs[lab].inspect}" }
355
+ labs[lab] and labs[lab].each{|i| res[i][2] = addr }
356
+ labs[lab] = res.size
357
+ when :O_JMP, :O_JPC, :O_CAL
358
+ lab, addr = i[2], labs[i[2]]
359
+ if addr.is_a? Integer
360
+ i[2] = addr
361
+ else
362
+ labs[lab] ||= []
363
+ labs[lab] << res.size
364
+ end
365
+ res << i
366
+ when Symbol
367
+ res << i
368
+ else
369
+ linearize_codes i, res, labs
370
+ end
371
+ end ; res
372
+ end
373
+ # *STACK* :-3(BP) :-2 :-1
374
+ # {...args...}[lexical base][old BP][old PC]{...vars...}
375
+ def execute codes
376
+ debug{
377
+ warn "\n** CODES **"
378
+ codes.each_with_index{|i,x| warn "#{'% 4i'%x} #{i.inspect}"}
379
+ warn "\n** EXEC **"
380
+ }
381
+ pc, bp, s = 0, 1, [0, 0, 0, 0]
382
+ begin
383
+ pc < codes.size or
384
+ raise "ADDRESS ERROR(PC:#{pc})."
385
+ op, l, a = codes[pc] ; pc += 1
386
+ debug{ warn " #{s.inspect}\nPC:#{pc-1} BP:#{bp} CODE:[#{op}, #{l}, #{a}]" }
387
+ case op
388
+ when :O_LIT; s.push a
389
+ when :O_OPR;
390
+ case a
391
+ when :P_NEG; s.push(-s.pop)
392
+ when :P_ODD; s.push s.pop % 2
393
+ when :P_ADD; r=s.pop; s.push s.pop + r
394
+ when :P_SUB; r=s.pop; s.push s.pop - r
395
+ when :P_MUL; r=s.pop; s.push s.pop * r
396
+ when :P_DIV; r=s.pop; s.push s.pop / r
397
+ when :P_EQ ; r=s.pop; s.push( s.pop == r ? 1 : 0 )
398
+ when :P_NE ; r=s.pop; s.push( s.pop != r ? 1 : 0 )
399
+ when :P_LT ; r=s.pop; s.push( s.pop < r ? 1 : 0 )
400
+ when :P_GE ; r=s.pop; s.push( s.pop >= r ? 1 : 0 )
401
+ when :P_GT ; r=s.pop; s.push( s.pop > r ? 1 : 0 )
402
+ when :P_LE ; r=s.pop; s.push( s.pop <= r ? 1 : 0 )
403
+ when :P_RDI; print "?"; s.push Integer(STDIN.gets)
404
+ when :P_WRI; printf( "\t%10d", s.pop )
405
+ when :P_WRL; puts ""
406
+ end
407
+ when :O_INT; s.fill(0, s.size, a)
408
+ when :O_LOD; x=bp;l.times{x=s[x]}; s.push s[x+a];
409
+ when :O_STO; x=bp;l.times{x=s[x]}; s[x+a] = s.pop;
410
+ when :O_CAL; x=bp;l.times{x=s[x]}; s.push x, bp, pc; bp, pc = s.size-3, a;
411
+ when :O_RET; r=s.pop; _, bp, pc, = s.slice!(bp..-1); s.slice!(-a, a) ; s.push r
412
+ when :O_JMP; pc = a
413
+ when :O_JPC; pc = a if s.pop == 0
414
+ end
415
+ end while pc != 0
416
+ end
417
+ end
418
+
419
+ require 'pp'
420
+ parser = Pl0d.create_decorated_parser
421
+ r, = parser.parse(ARGF)
@@ -0,0 +1,48 @@
1
+ const m = 7, n = 85;
2
+ var x,y;
3
+
4
+ function puts_ntimes(x, n)
5
+ var i;
6
+ begin
7
+ i := 0;
8
+ while i < n do
9
+ begin
10
+ write x; writeln;
11
+ i := i + 1;
12
+ end;
13
+ return i
14
+ end;
15
+
16
+ function fact(x)
17
+ begin
18
+ write x; writeln;
19
+ if x = 0 then return 1;
20
+ return x * fact(x - 1)
21
+ end;
22
+
23
+ function outer(x, z)
24
+ function inner(x)
25
+ begin
26
+ write x; write y; write z; writeln;
27
+ return outer(x + 1, z - 1)
28
+ end;
29
+ begin
30
+ if z = 0 then return 0;
31
+ return inner(x)
32
+ end;
33
+
34
+
35
+ begin
36
+ x := m; y := n;
37
+ write x; write y; writeln;
38
+ x := 84; y := 36;
39
+ write x; write y; writeln;
40
+
41
+ y := puts_ntimes(5, 10);
42
+ write y; writeln;
43
+
44
+ y := fact(5);
45
+ write y; writeln;
46
+
47
+ y := outer(5, 5);
48
+ end.