/* * Copyright (c) 2007 The Akuma Project * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * $Id: main.c 133 2007-05-29 14:32:04Z asmodai $ */ /* Crown Copyright (c) 1997 This TenDRA(r) Computer Program is subject to Copyright owned by the United Kingdom Secretary of State for Defence acting through the Defence Evaluation and Research Agency (DERA). It is made available to Recipients with a royalty-free licence for its use, reproduction, transfer to other parties and amendment for any purpose not excluding product development provided that any such use et cetera shall be deemed to be acceptance of the following conditions:- (1) Its Recipients shall ensure that this Notice is reproduced upon any copies or amended versions of it; (2) Any amended version of it shall be clearly marked to show both the nature of and the organisation responsible for the relevant amendment or amendments; (3) Its onward transfer from a recipient to another party shall be deemed to be that party's acceptance of these conditions; (4) DERA gives no warranty or assurance as to its quality or suitability for any purpose and DERA accepts no liability whatsoever in relation to any use to which it may be put. */ /*** main.c --- SID program main routine. * ** Author: Steve Folkes * *** Commentary: * * This file implements the main function for SID. The main function just * deals with exception handling. It calls the ``main_init'' function to * initialise the error reporting routines and parse the command line * arguments, and the ``main_1'' function to parse the grammar. * * The initialisation stuff should be trivial. The ``main_1'' function first * parses the grammar and any language specific input files. The grammar * parser is defined in the file "parser/parser.sid". The language specific * file parsers are defined in the files "LANGUAGE-input/LANGUAGE-parser.sid". * * After reading in the grammar, and language specific information, it then * calls various functions to manipulate the grammar. These functions are * described in "transforms/grammar.[ch]". * * Finally, it calls an output function to output a program to recognise the * grammar. The output functions are described in the * "LANGUAGE-output/LANGUAGE-output.[ch]" files. * *** Change Log: * $Log: main.c,v $ * Revision 1.2 1998/02/06 17:05:44 release * Last minute pre-release polishing. * * Revision 1.1.1.1 1998/01/17 15:57:41 release * First version to be checked into rolling release. * * Revision 1.13 1996/07/01 13:29:41 smf * main.c: * - updated version number. * * Revision 1.12 1996/07/01 09:36:04 smf * main.c: * - updated version numer. * * Revision 1.11 1996/06/28 15:12:34 smf * main.c: * - added extra information to version string; * - added "build" mechanism for release system. * * Revision 1.10 1996/03/01 09:51:56 smf * main.c: * - updated version number. * * Revision 1.9 1996/02/29 09:53:26 smf * main.c: * - updated version number. * * Revision 1.8 1996/02/28 15:43:56 smf * Updated version number in main.c. * Modified build_sid to use new platform designation. * * Revision 1.7 1995/02/10 16:28:56 smf * Fixed bugs "CR95_111.sid-inline-no-var-check" and "CR95_112.sid-lre-var-call". * Updated version number. * * Revision 1.6 1994/12/23 09:44:18 smf * Fixing "CR94_227.sid-exception-optimisation-bug" - updated version number. * * Revision 1.5 1994/12/15 09:55:01 smf * Updated version to "1.9#4". * Brought into line with OSSG C Coding Standards Document, as per * "CR94_178.sid+tld-update". * * Revision 1.4 1994/11/11 11:35:40 smf * Updated version number for bug fix CR94_127.sid-tail-rec. * * Revision 1.3 1994/08/22 09:34:15 smf * Fixed bug DR114:ids-too-long. * * Revision 1.2 1994/08/18 13:42:35 smf * Fixed bug "DR115:SID-shadow-error". Also modified "build_sid" to make * parallel bug fixing simpler. * * Revision 1.1.1.1 1994/07/25 16:04:11 smf * Initial import of SID 1.8 non shared files. * **/ /****************************************************************************/ #include "os-interface.h" #include "arg-parse.h" #include "c-check.h" #include "c-lexer.h" #include "c-output.h" #include "c-parser.h" #include "cstring.h" #include "cstring-list.h" #include "dstring.h" #include "error.h" #include "error-file.h" #include "exception.h" #include "gen-errors.h" #include "grammar.h" #include "istream.h" #include "lexer.h" #include "ostream.h" #include "output.h" #include "parser.h" #include "rule.h" #include "syntax.h" /*--------------------------------------------------------------------------*/ #define USAGE "\ \tusage:[option ...]in-file ... out-file ...\n\ \twhere option is one of:" #ifndef VERSION #define VERSION "sid: version 1.10.0 (ansi-c, pre-ansi-c, test)" #endif /* !defined (VERSION) */ #ifndef BANNER #define BANNER "" #endif /* !defined (BANNER) */ /*--------------------------------------------------------------------------*/ typedef struct PhaseListT { CStringP phase; void (*proc)(BoolT); } PhaseListT, *PhaseListP; typedef struct LangListT { CStringP language; GenericP (*init_proc)(OutputInfoP, CStringListP); void (*input_proc)(GenericP, GrammarP); unsigned num_input_files; void (*output_proc)(GenericP, GrammarP); unsigned num_output_files; } LangListT, *LangListP; /*--------------------------------------------------------------------------*/ static void main_handle_phase_all(BoolT enable) { rule_set_inline_singles(enable); rule_set_inline_tail_calls(enable); rule_set_inline_all_basics(enable); rule_set_inline_non_tail_calls(enable); rule_set_multiple_inlining(enable); } /*--------------------------------------------------------------------------*/ static GenericP main_init_c(OutputInfoP out_info, CStringListP options, BoolT ansi) { COutputInfoP c_out_info = ALLOCATE(COutputInfoT); CStringListEntryP entry; c_out_info_init(c_out_info, out_info); if (ansi) { c_out_info_set_prototypes(c_out_info, TRUE); } for (entry = cstring_list_head(options); entry; entry = cstring_list_entry_deallocate(entry)) { CStringP option = cstring_list_entry_string(entry); if (cstring_equal(option, "prototypes") || cstring_equal(option, "proto")) { c_out_info_set_prototypes(c_out_info, TRUE); } else if (cstring_equal(option, "no-prototypes") || cstring_equal(option, "no-proto")) { c_out_info_set_prototypes(c_out_info, FALSE); } else if (cstring_equal(option, "split")) { c_out_info_set_split(c_out_info, (unsigned)5000); } else if (cstring_starts(option, "split=")) { unsigned limit; if (!cstring_to_unsigned(option + 6, &limit)) { E_bad_split_size(option + 6); UNREACHED; } c_out_info_set_split(c_out_info, limit); } else if (cstring_equal(option, "no-split")) { c_out_info_set_split(c_out_info, (unsigned)0); } else if (cstring_equal(option, "numeric-ids") || cstring_equal(option, "numeric")) { c_out_info_set_numeric_ids(c_out_info, TRUE); } else if (cstring_equal(option, "no-numeric-ids") || cstring_equal(option, "no-numeric")) { c_out_info_set_numeric_ids(c_out_info, FALSE); } else if (cstring_equal(option, "casts") || cstring_equal(option, "cast")) { c_out_info_set_casts(c_out_info, TRUE); } else if (cstring_equal(option, "no-casts") || cstring_equal(option, "no-cast")) { c_out_info_set_casts(c_out_info, FALSE); } else if (cstring_equal(option, "unreachable-macros") || cstring_equal(option, "unreachable-macro")) { c_out_info_set_unreachable(c_out_info, TRUE); } else if (cstring_equal(option, "unreachable-comments") || cstring_equal(option, "unreachable-comment")) { c_out_info_set_unreachable(c_out_info, FALSE); } else if (cstring_equal(option, "lines") || cstring_equal(option, "line")) { c_out_info_set_lines(c_out_info, TRUE); } else if (cstring_equal(option, "no-lines") || cstring_equal(option, "no-line")) { c_out_info_set_lines(c_out_info, FALSE); } else { CStringP lang; lang = (ansi ? "ansi-c" : "pre-ansi-c"); E_bad_language_option(lang, option); } } return((GenericP)c_out_info); } static GenericP main_init_ansi_c(OutputInfoP out_info, CStringListP options) { return(main_init_c(out_info, options, TRUE)); } static GenericP main_init_pre_ansi_c(OutputInfoP out_info, CStringListP options) { return(main_init_c(out_info, options, FALSE)); } static void main_input_c(GenericP gclosure, GrammarP grammar) { COutputInfoP c_out_info = (COutputInfoP)gclosure; OutputInfoP out_info = c_out_info_info(c_out_info); CLexerStreamT clstream; c_lexer_init(&clstream, out_info_get_istream(out_info, (unsigned)1)); c_current_stream = &clstream; c_current_out_info = c_out_info; c_current_table = grammar_table(grammar); c_parse_grammar(); c_lexer_close(&clstream); if (error_max_reported_severity() >= ERROR_SEVERITY_ERROR) { exit(EXIT_FAILURE); UNREACHED; } c_check_grammar(grammar); } static void main_output_c(GenericP gclosure, GrammarP grammar) { COutputInfoP c_out_info = (COutputInfoP)gclosure; grammar_compute_mutations(grammar); out_info_set_current_ostream(c_out_info_info(c_out_info), (unsigned)0); c_output_parser(c_out_info, grammar); out_info_set_current_ostream(c_out_info_info(c_out_info), (unsigned)1); c_output_header(c_out_info, grammar); } static GenericP main_init_test(OutputInfoP info, CStringListP options) { CStringListEntryP entry; UNUSED(info); for (entry = cstring_list_head(options); entry; entry = cstring_list_entry_deallocate(entry)) { CStringP option = cstring_list_entry_string(entry); E_bad_language_option("test", option); } return(NIL(GenericP)); } static void main_input_test(GenericP gclosure, GrammarP grammar) { UNUSED(gclosure); UNUSED(grammar); } static void main_output_test(GenericP gclosure, GrammarP grammar) { UNUSED(gclosure); UNUSED(grammar); } /*--------------------------------------------------------------------------*/ static BoolT main_did_one_off = FALSE; static BoolT main_did_other = FALSE; static OutputInfoP main_info_closure; static CStringListT main_language_options; static OStreamT dump_stream; static PhaseListT main_phase_list[] = { {"singles", rule_set_inline_singles}, {"tail", rule_set_inline_tail_calls}, {"basics", rule_set_inline_all_basics}, {"other", rule_set_inline_non_tail_calls}, {"multi", rule_set_multiple_inlining}, {"all", main_handle_phase_all}, {NIL(CStringP), NIL(void(*)(BoolT))} }; static LangListT main_language_list[] = { {"ansi-c", main_init_ansi_c, main_input_c, 2, main_output_c, 2}, {"pre-ansi-c", main_init_pre_ansi_c, main_input_c, 2, main_output_c, 2}, {"iso-c", main_init_ansi_c, main_input_c, 2, main_output_c, 2}, {"pre-iso-c", main_init_pre_ansi_c, main_input_c, 2, main_output_c, 2}, {"test", main_init_test, main_input_test, 1, main_output_test, 0}, {NIL(CStringP), NIL(GenericP(*)(OutputInfoP, CStringListP)), NIL(void(*)(GenericP, GrammarP)), 0, NIL(void(*)(GenericP, GrammarP)), 0} }; static LangListP main_language = &(main_language_list[0]); /*--------------------------------------------------------------------------*/ static void main_handle_dump_file(CStringP option, ArgUsageP usage, GenericP gclosure, CStringP dump_file) { UNUSED(option); UNUSED(usage); UNUSED(gclosure); main_did_other = TRUE; if (ostream_is_open(&dump_stream)) { E_multiple_dump_files(); UNREACHED; } else if (!ostream_open(&dump_stream, dump_file)) { E_cannot_open_dump_file(dump_file); UNREACHED; } } static void main_handle_help(CStringP option, ArgUsageP usage, GenericP gclosure) { UNUSED(option); UNUSED(gclosure); main_did_one_off = TRUE; write_arg_usage(ostream_error, usage); write_newline(ostream_error); ostream_flush(ostream_error); } static void main_handle_factor_limit(CStringP option, ArgUsageP usage, GenericP gclosure, CStringP limit_str) { unsigned limit; UNUSED(option); UNUSED(usage); UNUSED(gclosure); main_did_other = TRUE; if ((!cstring_to_unsigned(limit_str, &limit)) || (limit == 0)) { E_bad_factor_limit(limit_str); UNREACHED; } rule_set_factor_limit(limit); } static void main_handle_inlining(CStringP option, ArgUsageP usage, GenericP gclosure, CStringP inline_str) { UNUSED(option); UNUSED(usage); UNUSED(gclosure); main_did_other = TRUE; while (*inline_str) { BoolT enable = TRUE; DStringT dstring; CStringP phase; PhaseListP entry; if ((syntax_downcase(inline_str[0]) == 'n') && (syntax_downcase(inline_str[1]) == 'o')) { inline_str += 2; enable = FALSE; } dstring_init(&dstring); while ((*inline_str) && (*inline_str != ',')) { dstring_append_char(&dstring, syntax_downcase(*inline_str++)); } if (*inline_str == ',') { inline_str++; } phase = dstring_destroy_to_cstring(&dstring); for (entry = main_phase_list; entry->phase; entry++) { if (cstring_equal(phase, entry->phase)) { if (entry->proc) { (*(entry->proc))(enable); } goto next; } } E_bad_inlining_phase(phase); UNREACHED; next:; } } static void main_handle_language(CStringP option, ArgUsageP usage, GenericP gclosure, CStringP language_str) { LangListP entry; UNUSED(option); UNUSED(usage); UNUSED(gclosure); main_did_other = TRUE; for (entry = main_language_list; entry->language; entry++) { if (cstring_equal(language_str, entry->language)) { main_language = entry; return; } } E_bad_language(language_str); UNREACHED; } static void main_handle_show_errors(CStringP option, ArgUsageP usage, GenericP gclosure) { UNUSED(option); UNUSED(usage); UNUSED(gclosure); main_did_one_off = TRUE; write_error_file(ostream_output); ostream_flush(ostream_output); } static void main_handle_switch(CStringP option, ArgUsageP usage, GenericP gclosure, CStringP opt) { UNUSED(option); UNUSED(usage); UNUSED(gclosure); main_did_other = TRUE; cstring_list_append(&main_language_options, opt); } static void main_handle_tab_width(CStringP option, ArgUsageP usage, GenericP gclosure, CStringP width_str) { unsigned width; UNUSED(option); UNUSED(usage); UNUSED(gclosure); main_did_other = TRUE; if ((!cstring_to_unsigned(width_str, &width)) || (width == 0)) { E_bad_tab_width(width_str); UNREACHED; } out_info_set_tab_width(main_info_closure, width); } static void main_handle_version(CStringP option, ArgUsageP usage, GenericP gclosure) { UNUSED(option); UNUSED(usage); UNUSED(gclosure); main_did_one_off = TRUE; write_cstring(ostream_error, VERSION); write_cstring(ostream_error, ")"); write_cstring(ostream_error, BANNER); write_newline(ostream_error); ostream_flush(ostream_error); } /*--------------------------------------------------------------------------*/ static EStringDataT main_description_strings[] = { UB { "description of dump-file", " FILE\n\tCause intermediate grammars to be written to FILE." } UE, UB { "description of help", "\n\tDisplay an option summary for the current mode." } UE, UB { "description of factor-limit", " NUMBER\n\tSet the maximum number of rules to be generated during factorisation." } UE, UB { "description of inlining", " INLINES\n\tSet which classes of rule are inlined.\n\tShould be any of 'SINGLES', 'BASICS', 'TAIL', 'OTHER', 'MULTI', or 'ALL'." } UE, UB { "description of language", " LANGUAGE\n\tSet the language for the output parser." } UE, UB { "description of show-errors", "\n\tDisplay the current error table on the standard output." } UE, UB { "description of switch", " OPTION\n\tPass OPTION to language specific option parser." } UE, UB { "description of tab-width", " NUMBER\n\tSet the number of spaces in a tab character." } UE, UB { "description of version", "\n\tDisplay the version number on the standard error." } UE, ERROR_END_STRING_LIST }; #ifdef __TenDRA__ /* Some conversions to ArgProcP are slightly suspect */ #pragma TenDRA begin #pragma TenDRA conversion analysis (pointer-pointer) off #endif static ArgListT main_arglist[] = { { "dump-file", 'd', AT_FOLLOWING, (ArgProcP)main_handle_dump_file, NIL(GenericP), UB "description of dump-file" UE }, { "factor-limit", 'f', AT_FOLLOWING, (ArgProcP)main_handle_factor_limit, NIL(GenericP), UB "description of factor-limit" UE }, { "help", '?', AT_EMPTY, (ArgProcP)main_handle_help, NIL(GenericP), UB "description of help" UE }, { "inline", 'i', AT_FOLLOWING, (ArgProcP)main_handle_inlining, NIL(GenericP), UB "description of inlining" UE }, { "language", 'l', AT_FOLLOWING, (ArgProcP)main_handle_language, NIL(GenericP), UB "description of language" UE }, { "show-errors", 'e', AT_EMPTY, (ArgProcP)main_handle_show_errors, NIL(GenericP), UB "description of show-errors" UE }, { "switch", 's', AT_FOLLOWING, (ArgProcP)main_handle_switch, NIL(GenericP), UB "description of switch" UE }, { "tab-width", 't', AT_FOLLOWING, (ArgProcP)main_handle_tab_width, NIL(GenericP), UB "description of tab-width" UE }, { "version", 'v', AT_EMPTY, (ArgProcP)main_handle_version, NIL(GenericP), UB "description of version" UE }, ARG_PARSE_END_LIST }; #ifdef __TenDRA__ #pragma TenDRA end #endif /*--------------------------------------------------------------------------*/ static void main_init(int argc, char **argv, OutputInfoP out_info) { EStringP usage_estring = error_define_string("sid usage message", USAGE); ArgUsageT closure; CStringP error_file; int skip; unsigned i; unsigned num_infiles; unsigned num_outfiles; error_init(argv[0], gen_errors_init_errors); error_intern_strings(main_description_strings); if ((error_file = getenv("SID_ERROR_FILE")) != NIL(CStringP)) { error_file_parse(error_file, FALSE); } closure.usage = error_string_contents(usage_estring); closure.arg_list = main_arglist; main_info_closure = out_info; arg_parse_intern_descriptions(main_arglist); skip = arg_parse_arguments(main_arglist, usage_estring, --argc, ++argv); argc -= skip; argv += skip; if (main_did_one_off && (!main_did_other) && (argc == 0)) { exit(EXIT_SUCCESS); UNREACHED; } num_infiles = main_language->num_input_files; num_outfiles = main_language->num_output_files; if ((unsigned)argc != (num_infiles + num_outfiles)) { E_usage(main_language->language, num_infiles, num_outfiles, &closure); UNREACHED; } out_info_set_num_input_files(out_info, num_infiles); out_info_set_num_output_files(out_info, num_outfiles); for (i = 0; i < num_infiles; i++) { CStringP name = argv[i]; if (!istream_open(out_info_get_istream(out_info, i), name)) { E_cannot_open_input_file(name); UNREACHED; } out_info_set_infile_name(out_info, i, name); } for (i = 0; i < num_outfiles; i++) { CStringP name = argv[num_infiles + i]; if (!ostream_open(out_info_get_ostream(out_info, i), name)) { E_cannot_open_output_file(name); UNREACHED; } out_info_set_outfile_name(out_info, i, name); } } static void main_dump_grammar(OStreamP dstream, GrammarP grammar, CStringP mesg) { if (dstream) { write_cstring(dstream, mesg); write_newline(dstream); write_newline(dstream); write_grammar(dstream, grammar); } } static void main_abort_if_errored(void) { if (error_max_reported_severity() >= ERROR_SEVERITY_ERROR) { exit(EXIT_FAILURE); UNREACHED; } } static void main_1(OutputInfoP out_info, OStreamP dstream) { LexerStreamT lstream; GrammarT grammar; GenericP output_closure; output_closure = (*(main_language->init_proc))(out_info, &main_language_options); grammar_init(&grammar); lexer_init(&lstream, out_info_get_istream(out_info, (unsigned)0)); sid_current_stream = &lstream; sid_current_grammar = &grammar; sid_parse_grammar(); lexer_close(&lstream); main_abort_if_errored(); grammar_check_complete(&grammar); main_abort_if_errored(); (*(main_language->input_proc))(output_closure, &grammar); main_abort_if_errored(); main_dump_grammar(dstream, &grammar, "Original grammar:"); grammar_remove_left_recursion(&grammar); main_dump_grammar(dstream, &grammar, "After left recursion elimination:"); main_abort_if_errored(); grammar_compute_first_sets(&grammar); main_abort_if_errored(); grammar_factor(&grammar); main_dump_grammar(dstream, &grammar, "After factorisation:"); main_abort_if_errored(); grammar_simplify(&grammar); main_dump_grammar(dstream, &grammar, "After simplification:"); grammar_compute_inlining(&grammar); grammar_check_collisions(&grammar); main_dump_grammar(dstream, &grammar, "After everything:"); main_abort_if_errored(); grammar_recompute_alt_names(&grammar); if (dstream) { ostream_close(dstream); } (*(main_language->output_proc))(output_closure, &grammar); } /*--------------------------------------------------------------------------*/ int main(int argc, char **argv) { HANDLE { OutputInfoT out_info; istream_setup(); ostream_setup(); out_info_init(&out_info, argv[0]); ostream_init(&dump_stream); cstring_list_init(&main_language_options); main_init(argc, argv, &out_info); if (ostream_is_open(&dump_stream)) { main_1(&out_info, &dump_stream); } else { main_1(&out_info, NIL(OStreamP)); } } WITH { ExceptionP exception = EXCEPTION_EXCEPTION(); if (exception == XX_dalloc_no_memory) { E_no_memory(); UNREACHED; } else if (exception == XX_istream_read_error) { CStringP file = (CStringP)EXCEPTION_VALUE(); E_read_error(file); UNREACHED; } else if (exception == XX_ostream_write_error) { CStringP file = (CStringP)EXCEPTION_VALUE(); E_write_error(file); UNREACHED; } else { RETHROW(); UNREACHED; } } END_HANDLE exit(EXIT_SUCCESS); UNREACHED; } /* * Local variables(smf): * compile-command: "build_sid" * eval: (include::add-path-entry "os-interface" "library" "transforms") * eval: (include::add-path-entry "parser" "output" "c-output" "c-input") * eval: (include::add-path-entry "generated") * End: **/