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.
- checksums.yaml +7 -0
- data/.rubocop.yml +44 -0
- data/.simplecov +5 -0
- data/Gemfile +12 -0
- data/LICENSE.gpl +339 -0
- data/Manifest.txt +73 -0
- data/README.en +7 -21
- data/README.ja +19 -99
- data/Rakefile +31 -0
- data/bin/depager +7 -45
- data/examples/action_pl0d/pl0d.action.dr +421 -0
- data/examples/action_pl0d/test.pl0ds +48 -0
- data/examples/c89/c89.dr +493 -496
- data/examples/c89/test.c89 +10 -10
- data/examples/extension/astdf.rb +9 -0
- data/examples/extension/atree.dr +55 -0
- data/examples/{sample_calc → extension}/calc.atree.dr +42 -43
- data/examples/{sample_calc/calc.action.dr → extension/calc.simple_action.dr} +33 -33
- data/examples/extension/paction.dr +16 -15
- data/examples/extension/pactiontest.dr +14 -14
- data/examples/extension/simple_action.rb +46 -0
- data/examples/pl0d/pl0ds.dr +337 -334
- data/examples/pl0d/test.pl0ds +33 -33
- data/examples/rie_calc/calc.rie.dr +57 -0
- data/examples/rie_calc/test.calc +4 -0
- data/examples/rie_dcuse/dcuse.rie.dr +71 -0
- data/examples/rie_dcuse/test.dcuse +1 -0
- data/examples/rie_pl0/orig_ex/exerrdg.pl0 +44 -0
- data/examples/rie_pl0/orig_ex/exerrm.pl0 +19 -0
- data/examples/rie_pl0/orig_ex/exerrmre.pl0 +20 -0
- data/examples/rie_pl0/orig_ex/exerrtok.pl0 +18 -0
- data/examples/rie_pl0/orig_ex/exmdg.pl0 +40 -0
- data/examples/rie_pl0/orig_ex/exmdgwwl.pl0 +43 -0
- data/examples/rie_pl0/orig_ex/exmrw.pl0 +22 -0
- data/examples/rie_pl0/orig_ex/exmwwl.pl0 +18 -0
- data/examples/rie_pl0/orig_ex/exnorw.pl0 +17 -0
- data/examples/rie_pl0/pl0.rie.dr +450 -0
- data/examples/rie_pl0/test.pl0 +10 -0
- data/examples/slex_test/divreg.slex.dr +29 -29
- data/examples/slex_test/ljoin.slex.dr +36 -36
- data/examples/slex_test/test.divreg +1 -1
- data/examples/slex_test/test.ljoin +3 -3
- data/examples/{sample_calc/calc.nvaction.dr → tiny_calc/calc.action.dr} +33 -33
- data/examples/{sample_calc → tiny_calc}/calc.ast.action.dr +76 -66
- data/examples/{sample_calc → tiny_calc}/calc.ast.dr +67 -55
- data/examples/tiny_calc/calc.cst.dr +50 -0
- data/examples/{sample_calc → tiny_calc}/calc.dr +43 -43
- data/examples/{sample_calc → tiny_calc}/calc.lex.dr +29 -29
- data/examples/{sample_calc/calc_prec.nvaction.dr → tiny_calc/calc_prec.action.dr} +31 -31
- data/lib/depager/cli.rb +44 -0
- data/lib/depager/grammar.rb +253 -291
- data/lib/depager/lr.rb +589 -579
- data/lib/depager/parser.rb +269 -277
- data/lib/depager/plugins/_rie_debug.rb +63 -0
- data/lib/depager/plugins/action.rb +47 -0
- data/lib/depager/plugins/ast.dr +367 -0
- data/lib/depager/plugins/ast.rb +1329 -0
- data/lib/depager/{ruby/plugins → plugins}/cst.dr +174 -180
- data/lib/depager/plugins/cst.rb +591 -0
- data/lib/depager/{ruby/plugins → plugins}/lex.dr +85 -89
- data/lib/depager/plugins/lex.rb +313 -0
- data/lib/depager/plugins/rie.dr +725 -0
- data/lib/depager/plugins/rie.rb +1614 -0
- data/lib/depager/{ruby/plugins → plugins}/slex.dr +201 -200
- data/lib/depager/plugins/slex.rb +769 -0
- data/lib/depager/plugins/srp.rb +46 -0
- data/lib/depager/ruby/templates/extension_lalr_master.erb +40 -51
- data/lib/depager/ruby/templates/extension_lalr_slave.erb +113 -107
- data/lib/depager/ruby/templates/single_lalr_parser.erb +124 -117
- data/lib/depager/utils.rb +158 -318
- data/lib/depager/version.rb +3 -3
- data/lib/depager.rb +572 -670
- metadata +77 -80
- data/ChangeLog +0 -16
- data/data/depager/pre-setup.rb +0 -3
- data/examples/c89/c89.tab.rb +0 -7127
- data/examples/pl0d/pl0ds.tab.rb +0 -2698
- data/examples/sample_calc/calc.action.tab.rb +0 -457
- data/examples/sample_calc/calc.ast.action.tab.rb +0 -749
- data/examples/sample_calc/calc.ast.tab.rb +0 -665
- data/examples/sample_calc/calc.astdf.dr +0 -54
- data/examples/sample_calc/calc.astdf.tab.rb +0 -672
- data/examples/sample_calc/calc.atree.tab.rb +0 -451
- data/examples/sample_calc/calc.cst.dr +0 -45
- data/examples/sample_calc/calc.cst.tab.rb +0 -644
- data/examples/sample_calc/calc.lex.tab.rb +0 -374
- data/examples/sample_calc/calc.nvaction.tab.rb +0 -465
- data/examples/sample_calc/calc.tab.rb +0 -365
- data/examples/sample_calc/calc_prec.nvaction.tab.rb +0 -431
- data/examples/slex_test/divreg.slex.tab.rb +0 -303
- data/examples/slex_test/ljoin.slex.tab.rb +0 -370
- data/lib/depager/ruby/plugins/_ast_tmpl.rb +0 -73
- data/lib/depager/ruby/plugins/action.rb +0 -43
- data/lib/depager/ruby/plugins/ast.dr +0 -269
- data/lib/depager/ruby/plugins/ast.rb +0 -1308
- data/lib/depager/ruby/plugins/astdf.rb +0 -6
- data/lib/depager/ruby/plugins/atree.dr +0 -55
- data/lib/depager/ruby/plugins/atree.rb +0 -347
- data/lib/depager/ruby/plugins/cst.rb +0 -626
- data/lib/depager/ruby/plugins/lex.rb +0 -336
- data/lib/depager/ruby/plugins/nvaction.rb +0 -19
- data/lib/depager/ruby/plugins/slex.rb +0 -817
- data/lib/depager/ruby/plugins/srp.rb +0 -51
- data/lib/depager/ruby/templates/simple.erb +0 -23
- data/setup.rb +0 -1585
- /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
|
|
10
|
+
* Ruby 3.0
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
インストール方法(gem)
|
|
14
14
|
---------------------
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
���ޥ�ɥ饤��ǰʲ��Τ褦���Ǥ�����Ǥ���������
|
|
16
|
+
$ sudo gem install depager
|
|
18
17
|
|
|
19
|
-
# sudo gem install depager
|
|
20
18
|
|
|
19
|
+
簡単な使い方
|
|
20
|
+
------------
|
|
21
21
|
|
|
22
|
-
|
|
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
|
-
|
|
42
|
-
$ export RUBYLIB
|
|
24
|
+
例:
|
|
43
25
|
|
|
44
|
-
|
|
45
|
-
���ξ��� ruby setup.rb --help ��¹Ԥ��ƤߤƤ���������
|
|
26
|
+
$ depager -o calc.tab.rb calc.dr
|
|
46
27
|
|
|
47
|
-
|
|
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
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
Depager
|
|
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/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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.
|