-
Notifications
You must be signed in to change notification settings - Fork 5
/
cardinal.pir
384 lines (318 loc) · 8.68 KB
/
cardinal.pir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
=head1 NAME
cardinal -- A compiler for Ruby 1.8.4
=head1 SYNOPSIS
$ ./parrot languages/cardinal/cardinal.pir script.rb
=head1 DESCRIPTION
Ruby is a compiler for Ruby version 1.8, running on Parrot. Its parser is
a PGE grammar (a subclass of PGE::Grammar). The compilation is a series of
tree transformations using TGE: from match tree to abstract syntax tree
(AST), from AST to opcode syntax tree (OST), and finally from OST to
bytecode (actually to PIR, at first). For more on the ideas behind the
compiler, see:
=cut
#.HLL 'Ruby', ''
.HLL 'Ruby', 'ruby_group'
.include 'errors.pasm'
.include 'library/dumper.pir'
.sub _main :main
.param pmc args
errorson .PARROT_ERRORS_PARAM_COUNT_FLAG
load_bytecode 'PGE.pbc'
load_bytecode 'dumper.pbc'
load_bytecode 'PGE/Dumper.pbc'
load_bytecode 'PGE/Text.pbc'
load_bytecode 'Getopt/Obj.pbc'
load_bytecode 'languages/cardinal/src/PAST.pir'
load_bytecode 'languages/cardinal/src/POST.pir'
#load_bytecode 'languages/cardinal/src/CardinalGrammar.pir'
load_bytecode 'languages/cardinal/src/CardinalGrammar.pbc'
load_bytecode 'languages/cardinal/src/PGE2AST.pir'
load_bytecode 'languages/cardinal/src/AST2OST.pir'
load_bytecode 'languages/cardinal/src/OST2PIR.pir'
#needed to run compiled tests
load_bytecode 'languages/cardinal/src/builtins_gen.pir'
load_bytecode 'languages/cardinal/runtime/cardinallib.pbc'
.local pmc _dumper
.local pmc getopts
.local pmc opts
.local string arg0
_dumper = get_root_global [ 'parrot' ], '_dumper'
arg0 = shift args
getopts = new 'Getopt::Obj'
getopts.'notOptStop'(1)
push getopts, 'target=s'
push getopts, 'dump-optable'
push getopts, 'dump-source|s'
push getopts, 'dump-pge-parse|p'
push getopts, 'dump-tge-AST|a'
push getopts, 'dump-tge-OST|o'
push getopts, 'dump-tge-PIR|i'
push getopts, 'execute|e'
push getopts, 'dump-all|x'
push getopts, 'dump|d'
push getopts, 'help|h'
push getopts, 'trace|t'
opts = getopts.'get_options'(args)
$S0 = opts['dump-optable']
if $S0 goto dump_optable
$S0 = opts['help']
if $S0 goto usage
.local int stopafter
.local string dump
.local string target
.local int istrace
stopafter = 0
dump = opts['dump']
target = opts['target']
$S0 = opts['trace']
istrace = isne $S0, ''
.local int dump_pge
$S0 = opts['dump-pge-parse']
dump_pge = isne $S0, ''
unless $S0 goto a1
stopafter = 1
a1:
.local int dump_ast
$S0 = opts['dump-tge-AST']
dump_ast = isne $S0, ''
unless $S0 goto a2
stopafter = 2
a2:
.local int dump_ost
$S0 = opts['dump-tge-OST']
dump_ost = isne $S0, ''
unless $S0 goto a3
stopafter = 3
a3:
.local int dump_pir
$S0 = opts['dump-tge-PIR']
dump_pir = isne $S0, ''
unless $S0 goto a4
stopafter = 4
a4:
.local int dump_src
.local int dump_src_early
.local int execute_debug
$S0 = opts['dump-source']
dump_src = isne $S0, ''
dump_src_early = dump_src
$S0 = opts['execute']
execute_debug = isne $S0, ''
unless execute_debug goto a5
stopafter = 0
a5:
.local int istrace
$S0 = opts['dump-all']
if $S0 goto dump_all
$S0 = dump
unless $S0 goto after_dump_all
dump_all:
dump_pge = 1
dump_ast = 1
dump_ost = 1
dump_pir = 1
dump_src_early = 1
dump_src = 1
execute_debug = 1
stopafter = 0
after_dump_all:
.local pmc cardinal
.local string filename
cardinal = compreg 'Cardinal'
.local string source
$I0 = elements args
if $I0 > 0 goto file_arg
filename = "STDIN"
.local pmc stdin
stdin = getstdin
push stdin, 'utf8'
# enable interactive readline if possible
$I0 = stdin.'set_readline_interactive'(1)
stmt_loop:
.local string stmt
stmt = stdin.'readline'('cardinal> ')
unless stmt goto end
bsr cardinal_irb_eval
goto stmt_loop
file_arg:
filename = args[0]
source = _get_source(filename)
goto compile_it
cardinal_irb_eval:
$I0 = find_charset 'iso-8859-1' # XXX: Note 2006-04-14
trans_charset stmt, $I0
#$P0 = perl6(stmt, 'target' => target, 'dump' => dump)
null $P0
if target == 'PIR' goto dump_pir_output
if target goto dump_object
trace istrace
$P0()
trace 0
ret
dump_pir_output:
print $P0
ret
dump_object:
_dumper($P0, target)
ret
dump_optable:
#$P0 = get_hll_global [ 'Cardinal'; 'Grammar'], '$optable'
$P0 = get_root_global [ 'parrot'; 'Cardinal::Grammar'], '$optable'
_dumper($P0, "Cardinal::Grammar::optable")
goto end
usage:
print "usage: cardinal.pbc [--dump-optable] [--target=OUT] [file]\n"
end
compile_it:
# Match against the source
.local pmc match
.local pmc start_rule
unless dump_src_early goto after_src_dump_early
print "\n\nSource dump:\n"
print source
after_src_dump_early:
start_rule = get_root_global [ 'parrot'; 'Cardinal::Grammar'], 'program'
match = start_rule(source, 'grammar'=> 'Cardinal::Grammar')
# Verify the match
$I0 = match.__get_bool()
unless $I0 goto err_match_fail # if match fails stop
unless dump_pge goto after_pge_dump
print "parse succeeded\n"
print "Match tree dump:\n"
_dumper(match, "PGE Dump")
after_pge_dump:
eq stopafter, 1, end
# "Traverse" the parse tree
.local pmc grammar
grammar = new 'Cardinal::ASTGrammar'
# Construct the "AST"
.local pmc astbuilder
astbuilder = grammar.apply(match)
.local pmc ast
ast = astbuilder.get('result')
$I0 = defined ast
unless $I0 goto err_no_ast # if AST fails stop
unless dump_ast goto after_ast_dump
print "\n\nAST tree dump:\n"
'_dumper'(ast)
#ast.'dump'()
after_ast_dump:
eq stopafter, 2, end
# Compile the abstract syntax tree down to an opcode syntax tree
.local pmc ostgrammar
.local pmc ostbuilder
.local pmc ost
ostgrammar = new 'Cardinal::OSTGrammar'
ostbuilder = ostgrammar.apply(ast)
ost = ostbuilder.get('root')
$I0 = defined ost
unless $I0 goto err_no_ost # if OST fails stop
unless dump_ost goto after_ost_dump
print "\n\nOST tree dump:\n"
'_dumper'(ost)
#ost.'dump'()
after_ost_dump:
eq stopafter, 3, end
# Compile the OST down to PIR
.local pmc pirgrammar
.local pmc pirbuilder
.local pmc pir
pirgrammar = new 'Cardinal::PIRGrammar'
pirbuilder = pirgrammar.apply(ost)
pir = pirbuilder.get('root')
unless pir goto err_no_pir # if PIR not generated, stop
unless dump_src goto after_src_dump
print "\n\nSource dump:\n"
print source
after_src_dump:
unless dump_pir goto after_pir_dump
print "\n\nPIR dump:\n"
print pir
after_pir_dump:
eq stopafter, 4, end
# dump pir to file
$S0 = concat filename, ".pir.out"
_spew_file($S0, pir)
# Execute
unless execute_debug goto execute_only
print "\n\nExecution Result:\n"
execute_only:
cardinal_exec(pir)
end
err_match_fail:
print "Parse failed on "
print filename
print "\n"
exit -1
err_no_ast:
print "Unable to construct AST.\n"
exit -2
err_no_ost:
print "Unable to construct OST.\n"
exit -3
err_no_pir:
print "Unable to construct PIR.\n"
exit -4
end:
exit 0
.end
#.HLL 'Ruby', 'ruby_group'
.sub cardinal_exec
.param pmc code
.local pmc pir_compiler
.local pmc pir_compiled
pir_compiler = compreg "PIR"
pir_compiled = pir_compiler(code)
pir_compiled()
.end
#.HLL 'Ruby', ''
# Read in the source from a file
.sub _get_source
.param string filename
$S1 = _slurp_file(filename)
.return ($S1)
err_no_file:
print "You must supply a Ruby file to parse.\n"
end
.end
.sub _slurp_file
.param string filename
.local pmc filehandle
filehandle = open filename, "<"
unless filehandle goto err_no_file
$S1 = read filehandle, 65535
close filehandle
.return ($S1)
err_no_file:
print "Unable to open file "
print filename
print "\n"
end
.end
.sub _spew_file
.param string filename
.param string contents
.local pmc filehandle
filehandle = open filename, ">"
unless filehandle goto err_no_file
print filehandle, contents
close filehandle
.return ($S1)
err_no_file:
print "Unable to open file "
print filename
print "\n"
end
.end
=head1 LICENSE
Copyright (c) 2005 The Perl Foundation
This is free software; you may redistribute it and/or modify
it under the same terms as Parrot.
=head1 AUTHOR
Kevin Tew <kevintew@tewk.com>
=cut
# Local Variables:
# mode: pir
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4: