/
pipp.pir
executable file
·439 lines (337 loc) · 10.9 KB
/
pipp.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
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
# $Id$
=head1 NAME
pipp.pir - driver program for Pipp, PCT and PHC variants
=head1 SYNOPSIS
cd languages/pipp
make pipp
./pipp t/in_php/01_sea_only.t
./pipp --variant=pct t/in_php/01_sea_only.t
./pipp --variant=phc t/in_php/01_sea_only.t
./pipp --run-nqp t.nqp
=head1 DESCRIPTION
pipp.pbc is the driver for Pipp.
=head1 Variants
=head2 Pipp pct
Parse PHP with the Parrot compiler toolkit. This is the default variant.
=head2 Pipp phc
Take XML from phc and transform it with XSLT to PIR setting up PAST.
Run the PAST with the help of PCT.
=head1 SEE ALSO
L<http://pipp.org>
=head1 AUTHOR
Bernhard Schmalhofer - L<Bernhard.Schmalhofer@gmx.de>
=cut
.HLL 'pipp'
.sub '' :anon :load :init
# Pipp uses the Parrot Compiler Toolkit
load_bytecode 'PCT.pbc'
# Export namespaces to the appropriate HLL ns
.local pmc parrotns, phpns, exports
parrotns = get_root_namespace ['parrot']
phpns = get_hll_namespace
exports = split ' ', 'PAST PCT PGE'
parrotns.'export_to'(phpns, exports)
.end
.include 'src/pct/gen_grammar.pir'
.include 'src/pct/gen_actions.pir'
.include 'src/pct/quote_expression.pir'
.HLL '_pipp'
.const string VERSION = "0.0.1"
.sub '__onload' :anon :load :init
# %valflags specifies when PAST::Val nodes are allowed to
# be used as a constant. The 'e' flag indicates that the
# value must be quoted+escaped in PIR code.
.local pmc valflags
valflags = get_root_global ['parrot';'PAST';'Compiler'], '%valflags'
valflags['PhpString'] = 's~*e'
# for accessing config info
load_bytecode 'config.pbc'
load_bytecode 'P6object.pbc'
# determine location of libs from the Parrot config
.local pmc cfg
$P0 = get_root_global ['parrot'], '_config'
cfg = $P0()
.local string lib_dir, pbc_fn
lib_dir = cfg['build_dir']
lib_dir .= '/languages/pipp'
pbc_fn = concat lib_dir, '/pipplib.pbc'
load_bytecode pbc_fn
pbc_fn = concat lib_dir, '/php_ctype.pbc'
load_bytecode pbc_fn
pbc_fn = concat lib_dir, '/php_gmp.pbc'
load_bytecode pbc_fn
pbc_fn = concat lib_dir, '/php_pcre.pbc'
load_bytecode pbc_fn
load_bytecode 'CGI/QueryHash.pbc'
load_bytecode 'dumper.pbc'
load_bytecode 'Getopt/Obj.pbc'
# import PGE::Util::die into Pipp::Grammar
$P0 = get_root_global ['parrot';'PGE';'Util'], 'die'
set_hll_global ['Pipp'; 'Grammar'], 'die', $P0
set_hll_global ['Pipp'], 'die', $P0
# Initialize the stack @?BLOCK
$P0 = new 'ResizablePMCArray'
set_root_global ['pipp';'Pipp';'Grammar';'Actions'], '@?BLOCK', $P0
# register and set up the the HLLCompiler
$P1 = new ['PCT';'HLLCompiler']
$P1.'language'('Pipp')
$P0 = get_root_namespace ['pipp';'Pipp';'Grammar']
$P1.'parsegrammar'($P0)
$P0 = get_root_namespace ['pipp';'Pipp';'Grammar';'Actions']
$P1.'parseactions'($P0)
.end
.sub 'pipp' :main
.param pmc argv
.local string prog, php_source_fn
.local pmc opt
(prog, opt, php_source_fn) = parse_arguments(argv)
if php_source_fn goto GOT_PHP_SOURCE_FN
# XXX: should do REPL or read from stdin
printerr "No input file specified.\n"
exit -1
GOT_PHP_SOURCE_FN:
# config stuff
.local pmc cfg
$P0 = get_root_global ['parrot'], '_config'
cfg = $P0()
.local string build_dir
build_dir = cfg['build_dir']
.local pmc pipp_ini
pipp_ini = opt['d']
set_ini( pipp_ini )
set_predefined_variables()
set_superglobals()
# target of compilation
.local string target
target = opt['target']
# output file
.local string output
output = opt['output']
# look at commandline and decide what to do
.local string cmd, err_msg, variant
.local int ret
# run the NQP-code when called with --run-nqp
$I0 = defined opt['run-nqp']
if $I0 goto RUN_NQP
# check for the variant from the commandline or from the environment
$I0 = defined opt['variant']
unless $I0 goto GET_VARIANT_FROM_ENV
variant = opt['variant']
goto GOT_VARIANT
GET_VARIANT_FROM_ENV:
.local pmc env
env = new 'Env'
$I0 = exists env['PIPP_VARIANT']
unless $I0 goto USE_DEFAULT_VARIANT
variant = env['PIPP_VARIANT']
goto GOT_VARIANT
USE_DEFAULT_VARIANT:
variant = 'pct'
goto GOT_VARIANT
GOT_VARIANT:
if variant == 'pct' goto VARIANT_PCT
if variant == 'PCT' goto VARIANT_PCT
if variant == 'phc' goto VARIANT_PHC
if variant == 'PHC' goto VARIANT_PHC
err_msg = "Unknown pipp variant: '"
err_msg .= variant
err_msg .= "'."
goto ERROR
VARIANT_PCT:
# use the Parrot Compiler Toolkit by default
.local pmc pipp_compiler
pipp_compiler = compreg 'Pipp'
.local pmc args
args = new 'ResizableStringArray'
push args, prog
push args, php_source_fn
# $P0 = get_root_global ['parrot'], '_dumper'
# $P0( args )
.tailcall pipp_compiler.'command_line'( args, 'target' => target, 'output' => output )
VARIANT_PHC:
.local string phc_src_dir
phc_src_dir = concat build_dir, '/languages/pipp/src/phc'
# work with the XML generated by PHC, the PHP Compiler
err_msg = 'Creating XML-AST with phc failed'
cmd = 'phc --dump-ast-xml=ast '
cmd .= php_source_fn
cmd .= '> pipp_phc_ast.xml'
ret = spawnw cmd
if ret goto ERROR
err_msg = 'Creating XML-PAST with xsltproc failed'
cmd = 'xsltproc '
cmd .= phc_src_dir
cmd .= '/phc_xml_to_past_xml.xsl pipp_phc_ast.xml > pipp_phc_past.xml'
ret = spawnw cmd
if ret goto ERROR
err_msg = 'Creating NQP with xsltproc failed'
cmd = 'xsltproc '
cmd .= phc_src_dir
cmd .= '/past_xml_to_past_nqp.xsl pipp_phc_past.xml > pipp_phc_past.nqp'
ret = spawnw cmd
if ret goto ERROR
.tailcall run_nqp( 'pipp_phc_past.nqp', target )
RUN_NQP:
.tailcall run_nqp( php_source_fn, target )
ERROR:
printerr err_msg
printerr "\n"
exit ret
.end
# currently not used
.sub run_nqp
.param string nqp_source_fn
.param string target
# config stuff
.local pmc cfg
$P0 = get_root_global ['parrot'], '_config'
cfg = $P0()
.local string build_dir
build_dir = cfg['build_dir']
# compile NQP to PIR
.local string pir_fn, cmd
.local int ret
pir_fn = build_dir
pir_fn .= '/languages/pipp/'
pir_fn .= nqp_source_fn
substr pir_fn, -3, 3, 'pir' # change extension from '.nqp' to '.pir'
cmd = build_dir
cmd .= '/parrot '
cmd .= build_dir
cmd .= '/compilers/nqp/nqp.pbc --target=pir --output='
cmd .= pir_fn
cmd .= ' '
cmd .= nqp_source_fn
ret = spawnw cmd
# load the generated PIR
load_bytecode pir_fn
.local pmc stmts
( stmts ) = php_entry() # stmts contains the PAST
if target != 'past' goto NO_PAST_DUMP
$P0 = get_root_global ['parrot'], '_dumper'
$P0( stmts )
.return ()
NO_PAST_DUMP:
# compile and evaluate the PAST returned from scheme_entry()
.local pmc past_compiler
past_compiler = new [ 'PCT';'HLLCompiler' ]
$P0 = split ' ', 'post pir evalpmc'
past_compiler.'stages'( $P0 )
past_compiler.'eval'(stmts)
.return ()
.end
# get commandline options
.sub parse_arguments
.param pmc argv
# name of the called program
.local string prog
prog = shift argv
.local pmc getopts
getopts = new 'Getopt::Obj'
# Pipp specific command line options
push getopts, 'f=s' # source file
push getopts, 'variant=s' # switch between variants
push getopts, 'target=s' # compilation target, used during development
push getopts, 'run-nqp' # run PAST set up in NQP
push getopts, 'output|o=s'
# standard PHP options
push getopts, 'version'
push getopts, 'help'
push getopts, 'd=%'
# options used by the PHP 5.3 test suit, not yet used
push getopts, 'C'
.local pmc opt
opt = getopts."get_options"(argv)
$I0 = defined opt['version']
unless $I0 goto n_ver
print prog
print " "
print VERSION
print "\n"
end
n_ver:
$I0 = defined opt['help']
unless $I0 goto n_help
print "usage: "
print prog
print " [options...] [file]\n"
print "see\n\tperldoc -F "
print prog
print "\nfor more\n"
end
n_help:
# Find the name of the input file
.local int argc
.local string php_source_fn
argc = elements argv
if argc < 1 goto NO_PHP_SCRIPT_NAME
dec argc
php_source_fn = argv[argc]
goto GOT_PHP_SOURCE_FN
NO_PHP_SCRIPT_NAME:
$I0 = defined opt['f']
unless $I0 goto GOT_NO_F_OPTION
php_source_fn = opt['f']
GOT_NO_F_OPTION:
GOT_PHP_SOURCE_FN:
.return (prog, opt, php_source_fn)
.end
# keep arguments from the command line and from ini-file
.sub set_ini
.param pmc pipp_ini
set_root_global ['pipp'], 'pipp_ini', pipp_ini
.end
# there is a distinction between predefined variables and superglobals
.sub set_predefined_variables
# TODO: these should probably be lexicals
.local pmc php_errormsg
php_errormsg = new 'PhpString'
php_errormsg = ''
set_root_global ['pipp'], '$php_errormsg', php_errormsg
.local pmc included_files
included_files = new 'PhpArray'
set_root_global ['pipp'], '$INC', included_files
.local string default_include_path
$P0 = get_root_global ['pipp'], 'constant'
default_include_path = $P0('DEFAULT_INCLUDE_PATH')
$P0 = split ':', default_include_path
set_root_global ['pipp'], '$INCLUDE_PATH', $P0
.end
# Most of the superglobals are not initialized yet
# When adding superglobals, please alse add them to @?SUPER_GLOBALS in actions.pm
.sub set_superglobals
# the superglobals _GET and _POST need to be set up
.local pmc parse_get
parse_get = get_root_global ['parrot';'CGI'; 'QueryHash'], 'parse_get'
$P0 = parse_get()
$P1 = new 'PhpArray'
assign $P1, $P0
set_root_global ['pipp'], '$_GET', $P1
.local pmc parse_post
parse_post = get_root_global ['parrot';'CGI';'QueryHash'], 'parse_post'
$P0 = parse_post()
$P1 = new 'PhpArray'
assign $P1, $P0
set_root_global ['pipp'], '$_POST', $P1
$P0 = new 'PhpArray'
set_root_global ['pipp'], '$_SERVER', $P0
$P0 = new 'PhpArray'
set_root_global ['pipp'], '$_GLOBALS', $P0
$P0 = new 'PhpArray'
set_root_global ['pipp'], '$_FILES', $P0
$P0 = new 'PhpArray'
set_root_global ['pipp'], '$_COOKIE', $P0
$P0 = new 'PhpArray'
$P0['name'] = '$_SESSION' # dummy content
set_root_global ['pipp'], '$_SESSION', $P0
$P0 = new 'PhpArray'
$P0['name'] = '$_REQUEST' # dummy content
set_root_global ['pipp'], '$_REQUEST', $P0
$P0 = new 'PhpArray'
set_root_global ['pipp'], '$_ENV', $P0
.end
# Local Variables:
# mode: pir
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4 ft=pir: