4 * Intermediate Code Compiler for Parrot.
6 * Copyright (C) 2002 Melvin Smith <melvin.smith@mindspring.com>
7 * Copyright (C) 2003-2008, The Perl Foundation.
33 #include "parrot/embed.h"
34 #include "parrot/longopt.h"
35 #include "parrot/imcc.h"
41 /* HEADERIZER HFILE: none */
43 /* HEADERIZER BEGIN: static */
44 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
46 static void compile_to_bytecode(PARROT_INTERP
,
47 ARGIN(const char * const sourcefile
),
48 ARGIN(const char * const output_file
))
49 __attribute__nonnull__(1)
50 __attribute__nonnull__(2)
51 __attribute__nonnull__(3);
53 static void determine_input_file_type(PARROT_INTERP
,
54 ARGIN(const char * const sourcefile
))
55 __attribute__nonnull__(1)
56 __attribute__nonnull__(2);
58 static void determine_output_file_type(PARROT_INTERP
,
59 ARGMOD(int *obj_file
),
60 ARGIN(const char *output_file
))
61 __attribute__nonnull__(1)
62 __attribute__nonnull__(2)
63 __attribute__nonnull__(3)
64 FUNC_MODIFIES(*obj_file
);
66 static void do_pre_process(PARROT_INTERP
)
67 __attribute__nonnull__(1);
69 static void help(void);
70 static void help_debug(void);
71 static void imcc_get_optimization_description(
74 ARGMOD(char *opt_desc
))
75 __attribute__nonnull__(3)
76 FUNC_MODIFIES(*opt_desc
);
78 static void imcc_run_pbc(PARROT_INTERP
,
80 ARGIN(const char *output_file
),
83 __attribute__nonnull__(1)
84 __attribute__nonnull__(3)
85 __attribute__nonnull__(5);
87 static void imcc_write_pbc(PARROT_INTERP
, ARGIN(const char *output_file
))
88 __attribute__nonnull__(1)
89 __attribute__nonnull__(2);
91 PARROT_WARN_UNUSED_RESULT
93 static int is_all_hex_digits(ARGIN(const char *s
))
94 __attribute__nonnull__(1);
96 static void Parrot_version(PARROT_INTERP
)
97 __attribute__nonnull__(1);
99 static void usage(ARGMOD(FILE* fp
))
100 __attribute__nonnull__(1)
103 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
104 /* HEADERIZER END: static */
107 static int load_pbc
, run_pbc
, write_pbc
, pre_process_only
, pasm_file
;
111 =item C<static void usage>
113 Outputs usage error message.
120 usage(ARGMOD(FILE* fp
))
123 "parrot -[abcCEfgGhjprStvVwy.] [-d [FLAGS]] [-D [FLAGS]]"
124 "[-O [level]] [-o FILE] <file>\n");
129 =item C<static void help_debug>
131 Print out list of debugging flag values.
140 /* split printf for C89 compliance on string length */
142 "--imcc-debug -d [Flags] ...\n"
147 " 0020 optimization 1\n"
148 " 0040 optimization 2\n"
151 " 2000 PBC constants\n"
155 "--parrot-debug -D [Flags] ...\n"
156 " 0001 memory statistics\n"
157 " 0002 print backtrace on exception\n"
158 " 0004 JIT debugging\n"
159 " 0008 interpreter startup\n"
160 " 0010 thread debugging\n"
161 " 0020 eval/compile\n"
162 " 0040 fill I, N registers with garbage\n"
163 " 0080 show when a context is destroyed\n"
165 "--trace -t [Flags] ...\n"
167 " 0002 find_method\n"
168 " 0004 function calls\n");
173 =item C<static void help>
175 Print out "help" list of options.
184 /* split printf for C89 compliance on string length */
186 "parrot [Options] <file>\n"
190 " -I add path to include search\n"
191 " -L add path to library search\n"
192 " <Run core options>\n"
193 " -R --runcore CORE\n"
194 " -b --bounds-checks|--slow-core\n"
197 " -g --computed-goto-core\n"
200 " -S --switched-core\n"
201 " -t --trace [flags]\n"
203 " -D --parrot-debug[=HEXFLAGS]\n"
209 " --leak-test|--destroy-at-end\n"
210 " -. --wait Read a keystroke before starting\n"
211 " --runtime-prefix\n"
212 " <Compiler options>\n"
213 " -d --imcc-debug[=HEXFLAGS]\n"
215 " -E --pre-process-only\n"
216 " -o --output=FILE\n"
218 " -O --optimize[=LEVEL]\n"
223 " <Language options>\n"
224 "see docs/running.pod for more\n");
230 =item C<static void Parrot_version>
232 Print out parrot version number.
239 Parrot_version(PARROT_INTERP
)
241 printf("This is parrot version " PARROT_VERSION
);
242 printf(" built for " PARROT_ARCHNAME
".\n");
243 printf("Copyright (C) 2001-2008, The Perl Foundation.\n\
245 This code is distributed under the terms of the Artistic License 2.0.\
247 For more details, see the full text of the license in the LICENSE file\
249 included in the Parrot source tree.\n\n");
251 Parrot_exit(interp
, 0);
254 #define SET_FLAG(flag) Parrot_set_flag(interp, (flag))
255 #define SET_DEBUG(flag) Parrot_set_debug(interp, (flag))
256 #define SET_TRACE(flag) Parrot_set_trace(interp, (flag))
257 #define SET_CORE(core) interp->run_core |= (core)
259 #define OPT_GC_DEBUG 128
260 #define OPT_DESTROY_FLAG 129
261 #define OPT_HELP_DEBUG 130
262 #define OPT_PBC_OUTPUT 131
263 #define OPT_RUNTIME_PREFIX 132
265 static struct longopt_opt_decl options
[] = {
266 { '.', '.', (OPTION_flags
)0, { "--wait" } },
267 { 'C', 'C', (OPTION_flags
)0, { "--CGP-core" } },
268 { 'D', 'D', OPTION_optional_FLAG
, { "--parrot-debug" } },
269 { 'E', 'E', (OPTION_flags
)0, { "--pre-process-only" } },
270 { 'G', 'G', (OPTION_flags
)0, { "--no-gc" } },
271 { 'I', 'I', OPTION_required_FLAG
, { NULL
} },
272 { 'L', 'L', OPTION_required_FLAG
, { NULL
} },
273 { 'O', 'O', OPTION_optional_FLAG
, { "--optimize" } },
274 { 'R', 'R', OPTION_required_FLAG
, { "--runcore" } },
275 { 'S', 'S', (OPTION_flags
)0, { "--switched-core" } },
276 { 'V', 'V', (OPTION_flags
)0, { "--version" } },
277 { '\0', OPT_DESTROY_FLAG
, (OPTION_flags
)0,
278 { "--leak-test", "--destroy-at-end" } },
279 { '\0', OPT_GC_DEBUG
, (OPTION_flags
)0, { "--gc-debug" } },
280 { 'a', 'a', (OPTION_flags
)0, { "--pasm" } },
281 { 'b', 'b', (OPTION_flags
)0, { "--bounds-checks", "--slow-core" } },
282 { 'c', 'c', (OPTION_flags
)0, { "--pbc" } },
283 { 'd', 'd', OPTION_optional_FLAG
, { "--imcc-debug" } },
284 { '\0', OPT_HELP_DEBUG
, (OPTION_flags
)0, { "--help-debug" } },
285 { 'f', 'f', (OPTION_flags
)0, { "--fast-core" } },
286 { 'g', 'g', (OPTION_flags
)0, { "--computed-goto-core" } },
287 { 'h', 'h', (OPTION_flags
)0, { "--help" } },
288 { 'j', 'j', (OPTION_flags
)0, { "--jit-core" } },
289 { 'o', 'o', OPTION_required_FLAG
, { "--output" } },
290 { '\0', OPT_PBC_OUTPUT
, (OPTION_flags
)0, { "--output-pbc" } },
291 { 'p', 'p', (OPTION_flags
)0, { "--profile" } },
292 { 'r', 'r', (OPTION_flags
)0, { "--run-pbc" } },
293 { '\0', OPT_RUNTIME_PREFIX
, (OPTION_flags
)0, { "--runtime-prefix" } },
294 { 't', 't', OPTION_optional_FLAG
, { "--trace" } },
295 { 'v', 'v', (OPTION_flags
)0, { "--verbose" } },
296 { 'w', 'w', (OPTION_flags
)0, { "--warnings" } },
297 { 'y', 'y', (OPTION_flags
)0, { "--yydebug" } },
298 { 0, 0, (OPTION_flags
)0, { NULL
} }
303 =item C<static int is_all_hex_digits>
305 Tests all characters in a string are hexadecimal digits.
306 Returns 1 if true, 0 as soon as a non-hex found
312 PARROT_WARN_UNUSED_RESULT
315 is_all_hex_digits(ARGIN(const char *s
))
325 =item C<const char * parseflags>
327 Parse Parrot's command line for options and set appropriate flags.
333 PARROT_WARN_UNUSED_RESULT
334 PARROT_CAN_RETURN_NULL
336 parseflags(PARROT_INTERP
, int *argc
, char **argv
[])
338 struct longopt_opt_info opt
= LONGOPT_OPT_INFO_INIT
;
346 while ((status
= longopt_get(interp
, *argc
, (const char **)*argv
, options
,
348 switch (opt
.opt_id
) {
350 if (STREQ(opt
.opt_arg
, "slow") || STREQ(opt
.opt_arg
, "bounds"))
351 SET_CORE(PARROT_SLOW_CORE
);
352 else if (STREQ(opt
.opt_arg
, "fast") || STREQ(opt
.opt_arg
, "function"))
353 SET_CORE(PARROT_FAST_CORE
);
354 else if (STREQ(opt
.opt_arg
, "switch"))
355 SET_CORE(PARROT_SWITCH_CORE
);
356 else if (STREQ(opt
.opt_arg
, "cgp"))
357 SET_CORE(PARROT_CGP_CORE
);
358 else if (STREQ(opt
.opt_arg
, "cgoto"))
359 SET_CORE(PARROT_CGOTO_CORE
);
360 else if (STREQ(opt
.opt_arg
, "jit"))
361 SET_CORE(PARROT_JIT_CORE
);
362 else if (STREQ(opt
.opt_arg
, "cgp-jit"))
363 SET_CORE(PARROT_CGP_JIT_CORE
);
364 else if (STREQ(opt
.opt_arg
, "switch-jit"))
365 SET_CORE(PARROT_SWITCH_JIT_CORE
);
366 else if (STREQ(opt
.opt_arg
, "exec"))
367 SET_CORE(PARROT_EXEC_CORE
);
368 else if (STREQ(opt
.opt_arg
, "trace")) {
369 SET_CORE(PARROT_SLOW_CORE
);
370 #ifdef HAVE_COMPUTED_GOTO
371 SET_CORE(PARROT_CGP_CORE
);
374 SET_CORE(PARROT_JIT_CORE
);
377 else if (STREQ(opt
.opt_arg
, "gcdebug"))
378 SET_CORE(PARROT_GC_DEBUG_CORE
);
380 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
381 "main: Unrecognized runcore '%s' specified."
382 "\n\nhelp: parrot -h\n", opt
.opt_arg
);
385 SET_FLAG(PARROT_BOUNDS_FLAG
);
388 SET_FLAG(PARROT_PROFILE_FLAG
);
391 if (opt
.opt_arg
&& is_all_hex_digits(opt
.opt_arg
))
392 SET_TRACE(strtoul(opt
.opt_arg
, 0, 16));
394 SET_TRACE(PARROT_TRACE_OPS_FLAG
);
397 SET_CORE(PARROT_JIT_CORE
);
400 SET_CORE(PARROT_SWITCH_CORE
);
403 SET_CORE(PARROT_CGP_CORE
);
406 SET_CORE(PARROT_FAST_CORE
);
409 SET_CORE(PARROT_CGOTO_CORE
);
412 if (opt
.opt_arg
&& is_all_hex_digits(opt
.opt_arg
)) {
413 IMCC_INFO(interp
)->debug
= strtoul(opt
.opt_arg
, 0, 16);
416 IMCC_INFO(interp
)->debug
++;
420 if (opt
.opt_arg
&& is_all_hex_digits(opt
.opt_arg
)) {
421 SET_DEBUG(strtoul(opt
.opt_arg
, 0, 16));
424 SET_DEBUG(PARROT_MEM_STAT_DEBUG_FLAG
);
427 Parrot_setwarnings(interp
, PARROT_WARNINGS_ALL_FLAG
);
428 IMCC_INFO(interp
)->imcc_warn
= 1;
431 IMCC_INFO(interp
)->gc_off
= 1;
433 case '.': /* Give Windows Parrot hackers an opportunity to
434 * attach a debuggger. */
448 case OPT_RUNTIME_PREFIX
:
450 char *prefix
= Parrot_get_runtime_prefix(interp
);
451 printf("%s\n", prefix
);
457 Parrot_version(interp
);
466 IMCC_INFO(interp
)->verbose
++;
472 pre_process_only
= 1;
476 interp
->output_file
= opt
.opt_arg
;
482 if (!interp
->output_file
)
483 interp
->output_file
= "-";
488 IMCC_INFO(interp
)->optimizer_level
|= OPT_PRE
;
491 if (strchr(opt
.opt_arg
, 'p'))
492 IMCC_INFO(interp
)->optimizer_level
|= OPT_PASM
;
493 if (strchr(opt
.opt_arg
, 'c'))
494 IMCC_INFO(interp
)->optimizer_level
|= OPT_SUB
;
496 IMCC_INFO(interp
)->allocator
= IMCC_GRAPH_ALLOCATOR
;
497 /* currently not ok due to different register allocation */
498 if (strchr(opt
.opt_arg
, 'j')) {
499 SET_CORE(PARROT_JIT_CORE
);
501 if (strchr(opt
.opt_arg
, '1')) {
502 IMCC_INFO(interp
)->optimizer_level
|= OPT_PRE
;
504 if (strchr(opt
.opt_arg
, '2')) {
505 IMCC_INFO(interp
)->optimizer_level
|= (OPT_PRE
| OPT_CFG
);
507 if (strchr(opt
.opt_arg
, 't')) {
508 SET_CORE(PARROT_SWITCH_CORE
);
509 #ifdef HAVE_COMPUTED_GOTO
510 SET_CORE(PARROT_CGP_CORE
);
513 SET_CORE(PARROT_JIT_CORE
);
520 Parrot_warn(interp
, PARROT_WARNINGS_ALL_FLAG
,
521 "PARROT_GC_DEBUG is set but the binary was "
522 "compiled with DISABLE_GC_DEBUG.");
524 SET_FLAG(PARROT_GC_DEBUG_FLAG
);
526 case OPT_DESTROY_FLAG
:
527 SET_FLAG(PARROT_DESTROY_FLAG
);
530 Parrot_add_library_path(interp
, opt
.opt_arg
,
531 PARROT_LIB_PATH_INCLUDE
);
534 Parrot_add_library_path(interp
, opt
.opt_arg
,
535 PARROT_LIB_PATH_LIBRARY
);
538 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
539 "main: Invalid flag '%s' used.\n\nhelp: parrot -h\n",
544 fprintf(stderr
, "%s\n", opt
.opt_error
);
548 /* reached the end of the option list and consumed all of argv */
549 if (*argc
== opt
.opt_index
) {
550 if (interp
->output_file
) {
551 fprintf(stderr
, "Missing program name or argument for -o\n");
554 /* We are not looking at an option, so it must be a program name */
555 fprintf(stderr
, "Missing program name\n");
560 *argc
-= opt
.opt_index
;
561 *argv
+= opt
.opt_index
;
568 =item C<static void do_pre_process>
570 Pre-processor step. Turn parser's output codes into Parrot instructions.
577 do_pre_process(PARROT_INTERP
)
582 const yyscan_t yyscanner
= IMCC_INFO(interp
)->yyscanner
;
584 IMCC_push_parser_state(interp
);
585 c
= yylex(&val
, yyscanner
, interp
); /* is reset at end of while loop */
588 case EMIT
: printf(".emit\n"); break;
589 case EOM
: printf(".eom\n"); break;
590 case LOCAL
: printf(".local "); break;
591 case ARG
: printf(".arg "); break;
592 case SUB
: printf(".sub "); break;
593 case ESUB
: printf(".end"); break;
594 case RESULT
: printf(".result "); break;
595 case RETURN
: printf(".return "); break;
596 case NAMESPACE
: printf(".namespace "); break;
597 case ENDNAMESPACE
: printf(".endnamespace"); break;
598 case CONST
: printf(".const "); break;
599 case PARAM
: printf(".param "); break;
600 /* RT#46147: print out more information about the macro */
601 /* case MACRO: yylex(&val, interp, yyscanner);
602 break; */ /* swallow nl */
603 case MACRO
: printf(".macro "); break;
605 case GOTO
: printf("goto ");break;
606 case IF
: printf("if ");break;
607 case UNLESS
: printf("unless ");break;
608 case INC
: printf("inc ");break;
609 case DEC
: printf("dec ");break;
610 case INTV
: printf("int ");break;
611 case FLOATV
: printf("float ");break;
612 case STRINGV
: printf("string ");break;
613 case PMCV
: printf("pmc ");break;
614 case NEW
: printf("new ");break;
615 case ADDR
: printf("addr ");break;
616 case GLOBAL
: printf("global ");break;
617 case SHIFT_LEFT
: printf(" << ");break;
618 case SHIFT_RIGHT
: printf(" >> ");break;
619 case SHIFT_RIGHT_U
: printf(" >>> ");break;
620 case LOG_AND
: printf(" && ");break;
621 case LOG_OR
: printf(" || ");break;
622 case LOG_XOR
: printf(" ~~ ");break;
623 case RELOP_LT
: printf(" < ");break;
624 case RELOP_LTE
: printf(" <= ");break;
625 case RELOP_GT
: printf(" > ");break;
626 case RELOP_GTE
: printf(" >= ");break;
627 case RELOP_EQ
: printf(" == ");break;
628 case RELOP_NE
: printf(" != ");break;
629 case POW
: printf(" ** ");break;
630 case COMMA
: printf(", ");break;
631 case LABEL
: printf("%s:\t", val
.s
); break;
632 case PCC_BEGIN
: printf(".begin_call "); break;
633 case PCC_END
: printf(".end_call"); break;
634 case PCC_SUB
: printf(".pccsub "); break;
635 case PCC_CALL
: printf(".call "); break;
636 case PCC_BEGIN_RETURN
: printf(".begin_return"); break;
637 case PCC_END_RETURN
: printf(".end_return"); break;
638 case PCC_BEGIN_YIELD
: printf(".begin_yield"); break;
639 case PCC_END_YIELD
: printf(".end_yield"); break;
640 case FILECOMMENT
: printf("setfile \"%s\"\n", val
.s
); break;
641 case LINECOMMENT
: printf("setline %d\n", val
.t
); break;
643 case PLUS_ASSIGN
: printf("+= ");break;
644 case MINUS_ASSIGN
: printf("-= ");break;
645 case MUL_ASSIGN
: printf("*= ");break;
646 case DIV_ASSIGN
: printf("/= ");break;
647 case MOD_ASSIGN
: printf("%%= ");break;
648 case FDIV_ASSIGN
: printf("//= ");break;
649 case BAND_ASSIGN
: printf("&= ");break;
650 case BOR_ASSIGN
: printf("|= ");break;
651 case BXOR_ASSIGN
: printf("~= ");break;
652 case SHR_ASSIGN
: printf(">>= ");break;
653 case SHL_ASSIGN
: printf("<<= ");break;
654 case SHR_U_ASSIGN
: printf(">>>= ");break;
655 case CONCAT_ASSIGN
: printf(".= ");break;
657 case MAIN
: printf(":main");break;
658 case LOAD
: printf(":load");break;
659 case INIT
: printf(":init");break;
660 case IMMEDIATE
: printf(":immediate");break;
661 case POSTCOMP
: printf(":postcomp");break;
662 case ANON
: printf(":anon");break;
663 case OUTER
: printf(":outer");break;
664 case NEED_LEX
: printf(":lex");break;
665 case METHOD
: printf(":method");break;
667 case UNIQUE_REG
: printf(":unique_reg");break;
668 case ADV_FLAT
: printf(":flat");break;
669 case ADV_SLURPY
: printf(":slurpy");break;
670 case ADV_OPTIONAL
: printf(":optional");break;
671 case ADV_OPT_FLAG
: printf(":opt_flag");break;
672 case ADV_NAMED
: printf(":named");break;
673 case ADV_ARROW
: printf("=>");break;
679 printf("%s ", val
.s
);
682 c
= yylex(&val
, yyscanner
, interp
);
692 =item C<static void imcc_get_optimization_description>
694 Create list (opt_desc[]) describing optimisation flags.
701 imcc_get_optimization_description(const PARROT_INTERP
, int opt_level
, ARGMOD(char *opt_desc
))
705 if (opt_level
& (OPT_PRE
| OPT_CFG
))
708 if (opt_level
& OPT_PRE
)
711 if (opt_level
& OPT_PASM
)
713 if (opt_level
& OPT_SUB
)
716 if (interp
->run_core
& PARROT_JIT_CORE
)
719 if (interp
->run_core
& PARROT_SWITCH_CORE
)
728 =item C<void imcc_initialize>
730 Initialise interpreter and set optimisation level.
737 imcc_initialize(PARROT_INTERP
)
739 yyscan_t yyscanner
= IMCC_INFO(interp
)->yyscanner
;
741 do_yylex_init(interp
, &yyscanner
);
743 Parrot_block_GC_mark(interp
);
744 Parrot_block_GC_sweep(interp
);
746 IMCC_INFO(interp
)->yyscanner
= yyscanner
;
747 IMCC_INFO(interp
)->allocator
= IMCC_VANILLA_ALLOCATOR
;
749 /* Default optimization level is zero; see optimizer.c, imc.h */
750 if (!IMCC_INFO(interp
)->optimizer_level
) {
752 IMCC_INFO(interp
)->optimizer_level
= 0;
754 /* won't even make with this: something with Data::Dumper and
756 IMCC_INFO(interp
)->optimizer_level
= OPT_PRE
;
763 =item C<static void imcc_run_pbc>
765 Write out or run Parrot bytecode.
766 RT#46149 no return value :-(
773 imcc_run_pbc(PARROT_INTERP
, int obj_file
, ARGIN(const char *output_file
),
774 int argc
, ARGIN(char **argv
))
776 if (IMCC_INFO(interp
)->imcc_warn
)
777 PARROT_WARNINGS_on(interp
, PARROT_WARNINGS_ALL_FLAG
);
779 PARROT_WARNINGS_off(interp
, PARROT_WARNINGS_ALL_FLAG
);
781 if (!IMCC_INFO(interp
)->gc_off
) {
782 Parrot_unblock_GC_mark(interp
);
783 Parrot_unblock_GC_sweep(interp
);
787 IMCC_info(interp
, 1, "Writing %s\n", output_file
);
789 IMCC_info(interp
, 1, "Running...\n");
791 /* runs :init functions */
792 PackFile_fixup_subs(interp
, PBC_MAIN
, NULL
);
794 /* RT#46149 no return value :-( */
795 Parrot_runcode(interp
, argc
, argv
);
800 =item C<static void imcc_write_pbc>
802 Output packed bytecode file.
809 imcc_write_pbc(PARROT_INTERP
, ARGIN(const char *output_file
))
815 IMCC_info(interp
, 1, "Writing %s\n", output_file
);
817 size
= PackFile_pack_size(interp
, interp
->code
->base
.pf
) *
819 IMCC_info(interp
, 1, "packed code %d bytes\n", size
);
820 packed
= (opcode_t
*) mem_sys_allocate(size
);
821 PackFile_pack(interp
, interp
->code
->base
.pf
, packed
);
822 if (STREQ(output_file
, "-"))
824 else if ((fp
= fopen(output_file
, "wb")) == 0)
825 IMCC_fatal_standalone(interp
, EXCEPTION_EXTERNAL_ERROR
,
826 "Couldn't open %s\n", output_file
);
828 if ((1 != fwrite(packed
, size
, 1, fp
)))
829 IMCC_fatal_standalone(interp
, EXCEPTION_EXTERNAL_ERROR
,
830 "Couldn't write %s\n", output_file
);
832 IMCC_info(interp
, 1, "%s written.\n", output_file
);
838 =item C<static void determine_input_file_type>
840 Read in the source and determine whether it's Parrot bytecode or PASM
847 determine_input_file_type(PARROT_INTERP
, ARGIN(const char * const sourcefile
))
849 yyscan_t yyscanner
= IMCC_INFO(interp
)->yyscanner
;
851 /* Read in the source and check the file extension for the input type;
852 a file extension .pbc means it's parrot bytecode;
853 a file extension .pasm means it's parrot assembly (PASM);
854 otherwise, it's assumed to be PIR.
856 if (STREQ(sourcefile
, "-")) {
857 imc_yyin_set(stdin
, yyscanner
);
860 const char * const ext
= strrchr(sourcefile
, '.');
862 if (ext
&& (STREQ(ext
, ".pbc"))) { /* a PBC file */
866 else if (!load_pbc
) {
867 if (!(imc_yyin_set(fopen(sourcefile
, "r"), yyscanner
))) {
868 IMCC_fatal_standalone(interp
, EXCEPTION_EXTERNAL_ERROR
,
869 "Error reading source file %s.\n",
872 if (ext
&& STREQ(ext
, ".pasm")) {
881 =item C<static void determine_output_file_type>
883 Decide what kind of file we are to output.
890 determine_output_file_type(PARROT_INTERP
,
891 ARGMOD(int *obj_file
), ARGIN(const char *output_file
))
893 const char * const ext
= strrchr(output_file
, '.');
896 if (STREQ(ext
, ".pbc")) {
899 else if (STREQ(ext
, PARROT_OBJ_EXT
)) {
905 Parrot_set_run_core(interp
, PARROT_EXEC_CORE
);
908 IMCC_fatal_standalone(interp
, 1, "main: can't produce object file");
916 =item C<static void compile_to_bytecode>
918 Compile source code into bytecode (or die trying).
925 compile_to_bytecode(PARROT_INTERP
,
926 ARGIN(const char * const sourcefile
),
927 ARGIN(const char * const output_file
))
929 yyscan_t yyscanner
= IMCC_INFO(interp
)->yyscanner
;
930 const int per_pbc
= (write_pbc
| run_pbc
) != 0;
931 const int opt_level
= IMCC_INFO(interp
)->optimizer_level
;
934 /* Shouldn't be more than five, but five extra is cheap */
937 imcc_get_optimization_description(interp
, opt_level
, opt_desc
);
939 IMCC_info(interp
, 1, "using optimization '-O%s' (%x) \n",
940 opt_desc
, opt_level
);
942 pf
= PackFile_new(interp
, 0);
943 Parrot_loadbc(interp
, pf
);
945 IMCC_push_parser_state(interp
);
946 IMCC_INFO(interp
)->state
->file
= sourcefile
;
948 emit_open(interp
, per_pbc
, per_pbc
? NULL
: (void*)output_file
);
950 IMCC_info(interp
, 1, "Starting parse...\n");
952 IMCC_INFO(interp
)->state
->pasm_file
= pasm_file
;
953 IMCC_TRY(IMCC_INFO(interp
)->jump_buf
,
954 IMCC_INFO(interp
)->error_code
) {
955 if (yyparse(yyscanner
, interp
))
958 imc_compile_all_units(interp
);
960 IMCC_CATCH(IMCC_FATAL_EXCEPTION
) {
961 char * const error_str
= string_to_cstring(interp
,
962 IMCC_INFO(interp
)->error_message
);
964 IMCC_INFO(interp
)->error_code
=IMCC_FATAL_EXCEPTION
;
965 fprintf(stderr
, "error:imcc:%s", error_str
);
966 IMCC_print_inc(interp
);
967 string_cstring_free(error_str
);
968 Parrot_exit(interp
, IMCC_FATAL_EXCEPTION
);
970 IMCC_CATCH(IMCC_FATALY_EXCEPTION
) {
971 char * const error_str
= string_to_cstring(interp
,
972 IMCC_INFO(interp
)->error_message
);
974 IMCC_INFO(interp
)->error_code
=IMCC_FATALY_EXCEPTION
;
975 fprintf(stderr
, "error:imcc:%s", error_str
);
976 IMCC_print_inc(interp
);
977 string_cstring_free(error_str
);
978 Parrot_exit(interp
, IMCC_FATALY_EXCEPTION
);
982 imc_cleanup(interp
, yyscanner
);
984 fclose(imc_yyin_get(yyscanner
));
986 IMCC_info(interp
, 1, "%ld lines compiled.\n", IMCC_INFO(interp
)->line
);
988 PackFile_fixup_subs(interp
, PBC_POSTCOMP
, NULL
);
993 =item C<int imcc_run>
995 Entry point of IMCC, as invoked by Parrot's main function.
996 Compile source code (if required), write bytecode file (if required)
997 and run. This function always returns 0.
1004 imcc_run(PARROT_INTERP
, ARGIN(const char *sourcefile
), int argc
,
1008 yyscan_t yyscanner
= IMCC_INFO(interp
)->yyscanner
;
1009 const char * const output_file
= interp
->output_file
;
1011 /* set the top of the stack so GC can trace it for GC-able pointers
1012 * see trace_system_areas() in src/cpu_dep.c */
1013 if (!interp
->lo_var_ptr
)
1014 interp
->lo_var_ptr
= (void *)&obj_file
;
1016 /* Figure out what kind of source file we have -- if we have one */
1017 if (!sourcefile
|| !*sourcefile
)
1018 IMCC_fatal_standalone(interp
, 1, "main: No source file specified.\n");
1020 determine_input_file_type(interp
, sourcefile
);
1022 if (pre_process_only
) {
1023 do_pre_process(interp
);
1024 Parrot_destroy(interp
);
1025 yylex_destroy(yyscanner
);
1026 IMCC_INFO(interp
)->yyscanner
= NULL
;
1031 /* Do we need to produce an output file? If so, what type? */
1034 determine_output_file_type(interp
, &obj_file
, output_file
);
1036 if (STREQ(sourcefile
, output_file
) && !STREQ(sourcefile
, "-"))
1037 IMCC_fatal_standalone(interp
, 1, "main: outputfile is sourcefile\n");
1040 IMCC_INFO(interp
)->write_pbc
= write_pbc
;
1042 if (IMCC_INFO(interp
)->verbose
) {
1043 IMCC_info(interp
, 1, "debug = 0x%x\n", IMCC_INFO(interp
)->debug
);
1044 IMCC_info(interp
, 1, "Reading %s\n",
1045 imc_yyin_get(yyscanner
) == stdin
? "stdin":sourcefile
);
1048 /* If the input file is Parrot bytecode, then we simply read it
1049 into a packfile, which Parrot then loads */
1051 PackFile
* const pf
= Parrot_readbc(interp
, sourcefile
);
1054 IMCC_fatal_standalone(interp
, 1, "main: Packfile loading failed\n");
1055 Parrot_loadbc(interp
, pf
);
1058 compile_to_bytecode(interp
, sourcefile
, output_file
);
1060 /* Produce a PBC output file, if one was requested */
1063 IMCC_fatal_standalone(interp
, 1,
1064 "main: NULL output_file when trying to write .pbc\n");
1066 imcc_write_pbc(interp
, output_file
);
1068 /* If necessary, load the file written above */
1069 if (run_pbc
== 2 && !STREQ(output_file
, "-")) {
1072 IMCC_info(interp
, 1, "Loading %s\n", output_file
);
1073 pf
= Parrot_readbc(interp
, output_file
);
1075 IMCC_fatal_standalone(interp
, 1, "Packfile loading failed\n");
1076 Parrot_loadbc(interp
, pf
);
1081 /* Run the bytecode */
1083 imcc_run_pbc(interp
, obj_file
, output_file
, argc
, argv
);
1085 yylex_destroy(yyscanner
);
1086 IMCC_INFO(interp
)->yyscanner
= NULL
;
1100 * c-file-style: "parrot"
1102 * vim: expandtab shiftwidth=4: