2 Copyright (C) 2007-2010, Parrot Foundation.
7 src/main.c - the Entry Point to Parrot Programs
23 #include "parrot/parrot.h"
24 #include "parrot/embed.h"
25 #include "parrot/imcc.h"
26 #include "parrot/longopt.h"
27 #include "parrot/runcore_api.h"
28 #include "pmc/pmc_callcontext.h"
30 /* For gc_sys_type_enum */
31 #include "gc/gc_private.h"
33 /* HEADERIZER HFILE: none */
35 /* HEADERIZER BEGIN: static */
36 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
38 static void help(void);
39 static void help_debug(void);
40 PARROT_WARN_UNUSED_RESULT
42 static int is_all_hex_digits(ARGIN(const char *s
))
43 __attribute__nonnull__(1);
45 static void Parrot_version(void);
46 PARROT_CAN_RETURN_NULL
47 static const char * parseflags(PARROT_INTERP
,
49 ARGMOD(char **argv
[]),
50 ARGMOD(Parrot_Run_core_t
*core
),
51 ARGMOD(Parrot_trace_flags
*trace
))
52 __attribute__nonnull__(1)
53 __attribute__nonnull__(2)
54 __attribute__nonnull__(3)
55 __attribute__nonnull__(4)
56 __attribute__nonnull__(5)
58 FUNC_MODIFIES(*argv
[])
60 FUNC_MODIFIES(*trace
);
62 static void parseflags_minimal(PARROT_INTERP
, int argc
, ARGIN(char *argv
[]))
63 __attribute__nonnull__(1)
64 __attribute__nonnull__(3);
66 static void usage(ARGMOD(FILE *fp
))
67 __attribute__nonnull__(1)
70 #define ASSERT_ARGS_help __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
71 #define ASSERT_ARGS_help_debug __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
72 #define ASSERT_ARGS_is_all_hex_digits __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
74 #define ASSERT_ARGS_Parrot_version __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
75 #define ASSERT_ARGS_parseflags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
76 PARROT_ASSERT_ARG(interp) \
77 , PARROT_ASSERT_ARG(argc) \
78 , PARROT_ASSERT_ARG(argv) \
79 , PARROT_ASSERT_ARG(core) \
80 , PARROT_ASSERT_ARG(trace))
81 #define ASSERT_ARGS_parseflags_minimal __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
82 PARROT_ASSERT_ARG(interp) \
83 , PARROT_ASSERT_ARG(argv))
84 #define ASSERT_ARGS_usage __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
85 PARROT_ASSERT_ARG(fp))
86 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
87 /* HEADERIZER END: static */
91 =item C<int main(int argc, char * argv[])>
93 The entry point from the command line into Parrot.
100 main(int argc
, char * argv
[])
103 const char *sourcefile
;
104 const char *execname
;
108 Parrot_Run_core_t core
= PARROT_SLOW_CORE
;
109 Parrot_trace_flags trace
= PARROT_NO_TRACE
;
111 /* internationalization setup */
112 /* setlocale(LC_ALL, ""); */
113 PARROT_BINDTEXTDOMAIN(PACKAGE
, LOCALEDIR
);
114 PARROT_TEXTDOMAIN(PACKAGE
);
116 Parrot_set_config_hash();
118 interp
= allocate_interpreter(NULL
, PARROT_NO_FLAGS
);
120 /* We parse the arguments, but first store away the name of the Parrot
121 executable, since parsing destroys that and we want to make it
125 /* Parse minimal subset of flags */
126 parseflags_minimal(interp
, argc
, argv
);
128 /* Now initialize interpreter */
129 initialize_interpreter(interp
, (void*)&stacktop
);
130 imcc_initialize(interp
);
132 { /* EXPERIMENTAL: add library and include paths from environment */
133 PMC
*env
= Parrot_pmc_new(interp
, enum_class_Env
);
134 STRING
*path
= VTABLE_get_string_keyed_str(interp
, env
,
135 Parrot_str_new_constant(interp
, "PARROT_LIBRARY"));
136 if (!Parrot_str_is_null(interp
, path
) && Parrot_str_length(interp
, path
) > 0)
137 Parrot_lib_add_path(interp
, path
, PARROT_LIB_PATH_LIBRARY
);
138 path
= VTABLE_get_string_keyed_str(interp
, env
,
139 Parrot_str_new_constant(interp
, "PARROT_INCLUDE"));
140 if (!Parrot_str_is_null(interp
, path
) && Parrot_str_length(interp
, path
) > 0)
141 Parrot_lib_add_path(interp
, path
, PARROT_LIB_PATH_INCLUDE
);
145 sourcefile
= parseflags(interp
, &argc
, &argv
, &core
, &trace
);
147 Parrot_set_trace(interp
, trace
);
148 Parrot_set_run_core(interp
, (Parrot_Run_core_t
) core
);
149 Parrot_set_executable_name(interp
, Parrot_str_new(interp
, execname
, 0));
151 status
= imcc_run(interp
, sourcefile
, argc
, argv
);
154 /* Clean-up after ourselves */
155 Parrot_destroy(interp
);
156 Parrot_exit(interp
, 0);
159 #define OPT_GC_DEBUG 128
160 #define OPT_DESTROY_FLAG 129
161 #define OPT_HELP_DEBUG 130
162 #define OPT_PBC_OUTPUT 131
163 #define OPT_RUNTIME_PREFIX 132
164 #define OPT_HASH_SEED 133
166 #define SET_FLAG(flag) Parrot_set_flag(interp, (flag))
167 #define SET_DEBUG(flag) Parrot_set_debug(interp, (flag))
168 #define SET_TRACE(flag) Parrot_set_trace(interp, (flag))
170 static struct longopt_opt_decl options
[] = {
171 { '.', '.', (OPTION_flags
)0, { "--wait" } },
172 { 'D', 'D', OPTION_optional_FLAG
, { "--parrot-debug" } },
173 { 'E', 'E', (OPTION_flags
)0, { "--pre-process-only" } },
174 { 'G', 'G', (OPTION_flags
)0, { "--no-gc" } },
175 { '\0', OPT_HASH_SEED
, OPTION_required_FLAG
, { "--hash-seed" } },
176 { 'I', 'I', OPTION_required_FLAG
, { "--include" } },
177 { 'L', 'L', OPTION_required_FLAG
, { "--library" } },
178 { 'O', 'O', OPTION_optional_FLAG
, { "--optimize" } },
179 { 'R', 'R', OPTION_required_FLAG
, { "--runcore" } },
180 { 'g', 'g', OPTION_required_FLAG
, { "--gc" } },
181 { 'V', 'V', (OPTION_flags
)0, { "--version" } },
182 { 'X', 'X', OPTION_required_FLAG
, { "--dynext" } },
183 { '\0', OPT_DESTROY_FLAG
, (OPTION_flags
)0,
184 { "--leak-test", "--destroy-at-end" } },
185 { '\0', OPT_GC_DEBUG
, (OPTION_flags
)0, { "--gc-debug" } },
186 { 'a', 'a', (OPTION_flags
)0, { "--pasm" } },
187 { 'c', 'c', (OPTION_flags
)0, { "--pbc" } },
188 { 'd', 'd', OPTION_optional_FLAG
, { "--imcc-debug" } },
189 { '\0', OPT_HELP_DEBUG
, (OPTION_flags
)0, { "--help-debug" } },
190 { 'h', 'h', (OPTION_flags
)0, { "--help" } },
191 { 'o', 'o', OPTION_required_FLAG
, { "--output" } },
192 { '\0', OPT_PBC_OUTPUT
, (OPTION_flags
)0, { "--output-pbc" } },
193 { 'r', 'r', (OPTION_flags
)0, { "--run-pbc" } },
194 { '\0', OPT_RUNTIME_PREFIX
, (OPTION_flags
)0, { "--runtime-prefix" } },
195 { 't', 't', OPTION_optional_FLAG
, { "--trace" } },
196 { 'v', 'v', (OPTION_flags
)0, { "--verbose" } },
197 { 'w', 'w', (OPTION_flags
)0, { "--warnings" } },
198 { 'y', 'y', (OPTION_flags
)0, { "--yydebug" } },
199 { 0, 0, (OPTION_flags
)0, { NULL
} }
204 =item C<static int is_all_hex_digits(const char *s)>
206 Tests all characters in a string are hexadecimal digits.
207 Returns 1 if true, 0 as soon as a non-hex found
213 PARROT_WARN_UNUSED_RESULT
216 is_all_hex_digits(ARGIN(const char *s
))
218 ASSERT_ARGS(is_all_hex_digits
)
227 =item C<static void usage(FILE *fp)>
229 Outputs usage error message.
236 usage(ARGMOD(FILE *fp
))
240 "parrot -[acEGhprtvVwy.] [-d [FLAGS]] [-D [FLAGS]]"
241 "[-O [level]] [-R runcore] [-o FILE] <file>\n");
246 =item C<static void help_debug(void)>
248 Print out list of debugging flag values.
257 ASSERT_ARGS(help_debug
)
258 /* split printf for C89 compliance on string length */
260 "--imcc-debug -d [Flags] ...\n"
265 " 0020 optimization 1\n"
266 " 0040 optimization 2\n"
269 " 2000 PBC constants\n"
273 "--parrot-debug -D [Flags] ...\n"
274 " 0001 memory statistics\n"
275 " 0002 print backtrace on exception\n"
276 " 0004 JIT debugging\n"
277 " 0008 interpreter startup\n"
278 " 0010 thread debugging\n"
279 " 0020 eval/compile\n"
280 " 0040 fill I, N registers with garbage\n"
281 " 0080 show when a context is destroyed\n"
283 "--trace -t [Flags] ...\n"
285 " 0002 find_method\n"
286 " 0004 function calls\n");
291 =item C<static void help(void)>
293 Print out "help" list of options.
303 /* split printf for C89 compliance on string length */
305 "parrot [Options] <file>\n"
309 " -I --include add path to include search\n"
310 " -L --library add path to library search\n"
311 " --hash-seed F00F specify hex value to use as hash seed\n"
312 " -X --dynext add path to dynamic extension search\n"
313 " <Run core options>\n"
314 " -R --runcore slow|bounds|fast|cgoto|cgp\n"
315 " -R --runcore switch|trace|profiling|gcdebug\n"
316 " -t --trace [flags]\n"
318 " -D --parrot-debug[=HEXFLAGS]\n"
324 " --leak-test|--destroy-at-end\n"
325 " -g --gc ms|inf set GC type\n"
326 " -. --wait Read a keystroke before starting\n"
327 " --runtime-prefix\n"
328 " <Compiler options>\n"
329 " -d --imcc-debug[=HEXFLAGS]\n"
331 " -E --pre-process-only\n"
332 " -o --output=FILE\n"
334 " -O --optimize[=LEVEL]\n"
339 " <Language options>\n"
340 "see docs/running.pod for more\n");
346 =item C<static void Parrot_version(void)>
348 Print out parrot version number.
357 ASSERT_ARGS(Parrot_version
)
358 printf("This is Parrot version " PARROT_VERSION
);
359 printf(" built for " PARROT_ARCHNAME
".\n");
360 printf("Copyright (C) 2001-2010, Parrot Foundation.\n\
362 This code is distributed under the terms of the Artistic License 2.0.\
364 For more details, see the full text of the license in the LICENSE file\
366 included in the Parrot source tree.\n\n");
373 =item C<static void parseflags_minimal(PARROT_INTERP, int argc, char *argv[])>
375 Parse minimal subset of args required for initializing interpreter.
381 parseflags_minimal(PARROT_INTERP
, int argc
, ARGIN(char *argv
[]))
383 ASSERT_ARGS(parseflags_minimal
)
388 const char *arg
= argv
[pos
];
390 if (STREQ(arg
, "--gc")) {
394 "main: No GC specified."
395 "\n\nhelp: parrot -h\n");
399 if (STREQ(arg
, "ms"))
400 interp
->gc_sys
->sys_type
= MS
;
401 else if (STREQ(arg
, "inf"))
402 interp
->gc_sys
->sys_type
= INF
;
405 "main: Unrecognized GC '%s' specified."
406 "\n\nhelp: parrot -h\n", arg
);
411 else if (!strncmp(arg
, "--hash-seed", 11)) {
413 arg
= strrchr(arg
, '=')+1;
418 if (is_all_hex_digits(arg
)) {
419 interp
->hash_seed
= strtoul(arg
, NULL
, 16);
422 fprintf(stderr
, "error: invalid hash seed specified:"
435 =item C<static const char * parseflags(PARROT_INTERP, int *argc, char **argv[],
436 Parrot_Run_core_t *core, Parrot_trace_flags *trace)>
438 Parse Parrot's command line for options and set appropriate flags.
444 PARROT_CAN_RETURN_NULL
446 parseflags(PARROT_INTERP
,
447 ARGMOD(int *argc
), ARGMOD(char **argv
[]),
448 ARGMOD(Parrot_Run_core_t
*core
), ARGMOD(Parrot_trace_flags
*trace
))
450 ASSERT_ARGS(parseflags
)
451 struct longopt_opt_info opt
= LONGOPT_OPT_INFO_INIT
;
453 /* g++ complains if we cast char** to const char** directly. However, nobody
454 ever complains if you const to void* first. Sure we lose a certain
455 amount of compiler-enforced type safety, but this is a rare occasion
456 with a very long explanatory comment. */
457 const char ** const _tempargv
= (const char **)((void *)*argv
);
464 imcc_start_handling_flags(interp
);
466 while ((status
= longopt_get(interp
, *argc
, _tempargv
, options
, &opt
)) > 0) {
467 switch (opt
.opt_id
) {
469 if (STREQ(opt
.opt_arg
, "slow") || STREQ(opt
.opt_arg
, "bounds"))
470 *core
= PARROT_SLOW_CORE
;
471 else if (STREQ(opt
.opt_arg
, "fast") || STREQ(opt
.opt_arg
, "function"))
472 *core
= PARROT_FAST_CORE
;
473 else if (STREQ(opt
.opt_arg
, "switch"))
474 *core
= PARROT_SWITCH_CORE
;
475 else if (STREQ(opt
.opt_arg
, "cgp"))
476 *core
= PARROT_CGP_CORE
;
477 else if (STREQ(opt
.opt_arg
, "cgoto"))
478 *core
= PARROT_CGOTO_CORE
;
479 else if (STREQ(opt
.opt_arg
, "jit"))
480 *core
= PARROT_FAST_CORE
;
481 else if (STREQ(opt
.opt_arg
, "cgp-jit"))
482 *core
= PARROT_CGP_CORE
;
483 else if (STREQ(opt
.opt_arg
, "switch-jit"))
484 *core
= PARROT_SWITCH_CORE
;
485 else if (STREQ(opt
.opt_arg
, "exec"))
486 *core
= PARROT_EXEC_CORE
;
487 else if (STREQ(opt
.opt_arg
, "trace"))
488 *core
= PARROT_SLOW_CORE
;
489 else if (STREQ(opt
.opt_arg
, "profiling"))
490 *core
= PARROT_PROFILING_CORE
;
491 else if (STREQ(opt
.opt_arg
, "gcdebug"))
492 *core
= PARROT_GC_DEBUG_CORE
;
495 "main: Unrecognized runcore '%s' specified."
496 "\n\nhelp: parrot -h\n", opt
.opt_arg
);
501 /* Handled in parseflags_minimal */
504 if (opt
.opt_arg
&& is_all_hex_digits(opt
.opt_arg
)) {
505 const unsigned long _temp
= strtoul(opt
.opt_arg
, NULL
, 16);
506 const Parrot_trace_flags _temp_flag
= (Parrot_trace_flags
)_temp
;
510 *trace
= PARROT_TRACE_OPS_FLAG
;
513 if (opt
.opt_arg
&& is_all_hex_digits(opt
.opt_arg
)) {
514 SET_DEBUG(strtoul(opt
.opt_arg
, NULL
, 16));
517 SET_DEBUG(PARROT_MEM_STAT_DEBUG_FLAG
);
520 case '.': /* Give Windows Parrot hackers an opportunity to
521 * attach a debuggger. */
529 /* handled in parseflags_minimal */
535 case OPT_RUNTIME_PREFIX
:
536 Parrot_io_printf(interp
, "%Ss\n",
537 Parrot_get_runtime_path(interp
));
545 Parrot_warn(interp
, PARROT_WARNINGS_ALL_FLAG
,
546 "PARROT_GC_DEBUG is set but the binary was compiled "
547 "with DISABLE_GC_DEBUG.");
549 SET_FLAG(PARROT_GC_DEBUG_FLAG
);
551 case OPT_DESTROY_FLAG
:
552 SET_FLAG(PARROT_DESTROY_FLAG
);
555 Parrot_lib_add_path_from_cstring(interp
, opt
.opt_arg
,
556 PARROT_LIB_PATH_INCLUDE
);
559 Parrot_lib_add_path_from_cstring(interp
, opt
.opt_arg
,
560 PARROT_LIB_PATH_LIBRARY
);
563 Parrot_lib_add_path_from_cstring(interp
, opt
.opt_arg
,
564 PARROT_LIB_PATH_DYNEXT
);
567 /* Delegate handling of IMCC flags to IMCC */
568 if (imcc_handle_flag(interp
, &opt
, core
))
571 /* PIRC flags handling goes here */
573 "main: Invalid flag '%s' used.\n\nhelp: parrot -h\n",
580 fprintf(stderr
, "%s\n", opt
.opt_error
);
585 /* reached the end of the option list and consumed all of argv */
586 if (*argc
== opt
.opt_index
) {
587 if (interp
->output_file
) {
588 fprintf(stderr
, "Missing program name or argument for -o\n");
591 /* We are not looking at an option, so it must be a program name */
592 fprintf(stderr
, "Missing program name\n");
598 *argc
-= opt
.opt_index
;
599 *argv
+= opt
.opt_index
;
609 F<compilers/imcc/main.c>, unfortunately.
617 * c-file-style: "parrot"
619 * vim: expandtab shiftwidth=4: