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.
|