maximum line length in a pod (pdd) is 78 characters
[parrot.git] / src / main.c
blobf718131565f8c70cfb30085b34145a9f4645174e
1 /*
2 Copyright (C) 2007-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/main.c - the Entry Point to Parrot Programs
9 =head1 DESCRIPTION
11 Start Parrot
13 =head2 Functions
15 =over 4
17 =cut
21 #include <stdio.h>
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
41 PARROT_PURE_FUNCTION
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,
48 ARGMOD(int *argc),
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)
57 FUNC_MODIFIES(*argc)
58 FUNC_MODIFIES(*argv[])
59 FUNC_MODIFIES(*core)
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)
68 FUNC_MODIFIES(*fp);
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 = (\
73 PARROT_ASSERT_ARG(s))
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.
95 =cut
99 int
100 main(int argc, char * argv[])
102 int stacktop;
103 const char *sourcefile;
104 const char *execname;
105 Interp *interp;
106 int status;
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
122 available. */
123 execname = argv[0];
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);
144 /* Parse flags */
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);
152 UNUSED(status);
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
209 =cut
213 PARROT_WARN_UNUSED_RESULT
214 PARROT_PURE_FUNCTION
215 static int
216 is_all_hex_digits(ARGIN(const char *s))
218 ASSERT_ARGS(is_all_hex_digits)
219 for (; *s; s++)
220 if (!isxdigit(*s))
221 return 0;
222 return 1;
227 =item C<static void usage(FILE *fp)>
229 Outputs usage error message.
231 =cut
235 static void
236 usage(ARGMOD(FILE *fp))
238 ASSERT_ARGS(usage)
239 fprintf(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.
250 =cut
254 static void
255 help_debug(void)
257 ASSERT_ARGS(help_debug)
258 /* split printf for C89 compliance on string length */
259 printf(
260 "--imcc-debug -d [Flags] ...\n"
261 " 0002 lexer\n"
262 " 0004 parser\n"
263 " 0008 imc\n"
264 " 0010 CFG\n"
265 " 0020 optimization 1\n"
266 " 0040 optimization 2\n"
267 " 0100 AST\n"
268 " 1000 PBC\n"
269 " 2000 PBC constants\n"
270 " 4000 PBC fixups\n"
271 "\n");
272 printf(
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"
282 "\n"
283 "--trace -t [Flags] ...\n"
284 " 0001 opcodes\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.
295 =cut
299 static void
300 help(void)
302 ASSERT_ARGS(help)
303 /* split printf for C89 compliance on string length */
304 printf(
305 "parrot [Options] <file>\n"
306 " Options:\n"
307 " -h --help\n"
308 " -V --version\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"
317 " <VM options>\n"
318 " -D --parrot-debug[=HEXFLAGS]\n"
319 " --help-debug\n");
320 printf(
321 " -w --warnings\n"
322 " -G --no-gc\n"
323 " --gc-debug\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"
330 " -v --verbose\n"
331 " -E --pre-process-only\n"
332 " -o --output=FILE\n"
333 " --output-pbc\n"
334 " -O --optimize[=LEVEL]\n"
335 " -a --pasm\n"
336 " -c --pbc\n"
337 " -r --run-pbc\n"
338 " -y --yydebug\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.
350 =cut
354 static void
355 Parrot_version(void)
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");
368 exit(EXIT_SUCCESS);
373 =item C<static void parseflags_minimal(PARROT_INTERP, int argc, char *argv[])>
375 Parse minimal subset of args required for initializing interpreter.
377 =cut
380 static void
381 parseflags_minimal(PARROT_INTERP, int argc, ARGIN(char *argv[]))
383 ASSERT_ARGS(parseflags_minimal)
385 int pos = 0;
387 while (pos < argc) {
388 const char *arg = argv[pos];
390 if (STREQ(arg, "--gc")) {
391 ++pos;
392 if (pos == argc) {
393 fprintf(stderr,
394 "main: No GC specified."
395 "\n\nhelp: parrot -h\n");
396 exit(EXIT_FAILURE);
398 arg = argv[pos];
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;
403 else {
404 fprintf(stderr,
405 "main: Unrecognized GC '%s' specified."
406 "\n\nhelp: parrot -h\n", arg);
407 exit(EXIT_FAILURE);
409 break;
411 else if (!strncmp(arg, "--hash-seed", 11)) {
413 arg = strrchr(arg, '=')+1;
414 if (!arg) {
415 ++pos;
416 arg = argv[pos];
418 if (is_all_hex_digits(arg)) {
419 interp->hash_seed = strtoul(arg, NULL, 16);
421 else {
422 fprintf(stderr, "error: invalid hash seed specified:"
423 "'%s'\n", arg);
424 exit(EXIT_FAILURE);
426 ++pos;
427 arg = argv[pos];
429 ++pos;
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.
440 =cut
444 PARROT_CAN_RETURN_NULL
445 static const char *
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;
452 int status;
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);
459 if (*argc == 1) {
460 usage(stderr);
461 exit(EXIT_SUCCESS);
464 imcc_start_handling_flags(interp);
466 while ((status = longopt_get(interp, *argc, _tempargv, options, &opt)) > 0) {
467 switch (opt.opt_id) {
468 case 'R':
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;
493 else {
494 fprintf(stderr,
495 "main: Unrecognized runcore '%s' specified."
496 "\n\nhelp: parrot -h\n", opt.opt_arg);
497 exit(EXIT_FAILURE);
499 break;
500 case 'g':
501 /* Handled in parseflags_minimal */
502 break;
503 case 't':
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;
507 *trace = _temp_flag;
509 else
510 *trace = PARROT_TRACE_OPS_FLAG;
511 break;
512 case 'D':
513 if (opt.opt_arg && is_all_hex_digits(opt.opt_arg)) {
514 SET_DEBUG(strtoul(opt.opt_arg, NULL, 16));
516 else
517 SET_DEBUG(PARROT_MEM_STAT_DEBUG_FLAG);
518 break;
520 case '.': /* Give Windows Parrot hackers an opportunity to
521 * attach a debuggger. */
522 fgetc(stdin);
523 break;
524 case 'h':
525 help();
526 exit(EXIT_FAILURE);
527 break;
528 case OPT_HASH_SEED:
529 /* handled in parseflags_minimal */
530 break;
531 case OPT_HELP_DEBUG:
532 help_debug();
533 exit(EXIT_FAILURE);
534 break;
535 case OPT_RUNTIME_PREFIX:
536 Parrot_io_printf(interp, "%Ss\n",
537 Parrot_get_runtime_path(interp));
538 exit(EXIT_SUCCESS);
539 case 'V':
540 Parrot_version();
541 break;
543 case OPT_GC_DEBUG:
544 #if DISABLE_GC_DEBUG
545 Parrot_warn(interp, PARROT_WARNINGS_ALL_FLAG,
546 "PARROT_GC_DEBUG is set but the binary was compiled "
547 "with DISABLE_GC_DEBUG.");
548 #endif
549 SET_FLAG(PARROT_GC_DEBUG_FLAG);
550 break;
551 case OPT_DESTROY_FLAG:
552 SET_FLAG(PARROT_DESTROY_FLAG);
553 break;
554 case 'I':
555 Parrot_lib_add_path_from_cstring(interp, opt.opt_arg,
556 PARROT_LIB_PATH_INCLUDE);
557 break;
558 case 'L':
559 Parrot_lib_add_path_from_cstring(interp, opt.opt_arg,
560 PARROT_LIB_PATH_LIBRARY);
561 break;
562 case 'X':
563 Parrot_lib_add_path_from_cstring(interp, opt.opt_arg,
564 PARROT_LIB_PATH_DYNEXT);
565 break;
566 default:
567 /* Delegate handling of IMCC flags to IMCC */
568 if (imcc_handle_flag(interp, &opt, core))
569 break;
571 /* PIRC flags handling goes here */
572 fprintf(stderr,
573 "main: Invalid flag '%s' used.\n\nhelp: parrot -h\n",
574 (*argv)[0]);
575 exit(EXIT_FAILURE);
579 if (status == -1) {
580 fprintf(stderr, "%s\n", opt.opt_error);
581 usage(stderr);
582 exit(EXIT_FAILURE);
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");
590 else {
591 /* We are not looking at an option, so it must be a program name */
592 fprintf(stderr, "Missing program name\n");
594 usage(stderr);
595 exit(EXIT_FAILURE);
598 *argc -= opt.opt_index;
599 *argv += opt.opt_index;
601 return (*argv)[0];
605 =back
607 =head1 SEE ALSO
609 F<compilers/imcc/main.c>, unfortunately.
611 =cut
616 * Local variables:
617 * c-file-style: "parrot"
618 * End:
619 * vim: expandtab shiftwidth=4: