#include #include #include "main.h" #include "nmtbl.h" #include "token.h" #include "trnod.h" #include "util.h" extern int zzparse(); static void load_predefined() { b_ring::add_cur(nm_entry::add("integer", TKN_IDENT), symbol::s_type, &integer_type); b_ring::add_cur(nm_entry::add("real", TKN_IDENT), symbol::s_type, &real_type); b_ring::add_cur(nm_entry::add("boolean", TKN_IDENT), symbol::s_type, &bool_type); b_ring::add_cur(nm_entry::add("char", TKN_IDENT), symbol::s_type, &char_type); b_ring::add_cur(nm_entry::add("text", TKN_IDENT), symbol::s_type, &text_type); b_ring::add_cur(nm_entry::add("zero_terminated_string", TKN_IDENT), nm_entry::add("char*", TKN_IDENT), symbol::s_type, &string_type); b_ring::add_cur(nm_entry::add("true", TKN_IDENT), symbol::s_const, &bool_type); b_ring::add_cur(nm_entry::add("false", TKN_IDENT), symbol::s_const, &bool_type); b_ring::add_cur(nm_entry::add("nil", TKN_IDENT), symbol::s_const, &void_type); if (hp_pascal) { nm_entry::add("addr", TKN_ADDR); } if (turbo_pascal) { b_ring::add_cur(nm_entry::add("pointer", TKN_IDENT), symbol::s_type, &pointer_type); b_ring::add_cur(nm_entry::add("pchar", TKN_IDENT), symbol::s_type, &string_type); b_ring::add_cur(nm_entry::add("longint", TKN_IDENT), symbol::s_type, &longint_type); b_ring::add_cur(nm_entry::add("double", TKN_IDENT), symbol::s_type, &double_type); b_ring::add_cur(nm_entry::add("untyped_file", TKN_IDENT), symbol::s_type, &text_type); nested_comments = TRUE; } } static void load_keywords() { for (int tag = 0; tag < TKN_LAST; tag ++ ) { if (token::token_cat[tag] == CAT_ID || token::token_cat[tag] == CAT_KWD) { nm_entry::add(token::token_name[tag], tag); } } } #define MAX_NAME_LEN 1024 static void load_configuration(char* name) { FILE* cfg = fopen(name, "r"); if (cfg != NULL) { char buf[MAX_NAME_LEN]; while (fscanf(cfg, "%s", buf) == 1) { if (strcmp(buf, "#begin(reserved)") == 0) { while (fscanf(cfg, "%s", buf) == 1 && strcmp(buf, "#end(reserved)") != 0) { nm_entry::add(buf, TKN_RESERVED); } } else if(strcmp(buf, "#begin(macro)") == 0) { while (fscanf(cfg, "%s", buf) == 1 && strcmp(buf, "#end(macro)") != 0) { nm_entry::add(buf, TKN_IDENT)->flags |= nm_entry::macro; } } else if(strcmp(buf, "#begin(library)") == 0) { while (fscanf(cfg, "%s", buf) == 1 && strcmp(buf, "#end(library)") != 0) { b_ring::global_b_ring.add(nm_entry::add(buf, TKN_IDENT), symbol::s_dummy, NULL); } } else if(strcmp(buf, "#begin(rename)") == 0) { while (fscanf(cfg, "%s", buf) == 1 && strcmp(buf, "#end(rename)") != 0) { nm_entry* nm_old = nm_entry::add(buf, TKN_IDENT); fscanf(cfg, "%s", buf); nm_entry* nm_new = nm_entry::add(buf, TKN_IDENT); rename_item::add(nm_new, nm_old); } } } fclose(cfg); if (turbo_pascal) { // sizeof is builtin Pascal function nm_entry* nm_sizeof = nm_entry::find("sizeof"); if (nm_sizeof) { *nm_sizeof->text = 'S'; } } } else { fprintf(stderr, "Can't open configuration file '%s'\n", name); } } char *i_path; char *input_file; char *output_file; char *output_suf; char *prog_path; bool output_not_existed_hdr; bool no_array_assign_operator; bool language_c; bool compile_system_library; bool pio_init; bool use_call_graph; bool short_set; bool unsigned_comparison; bool small_enum; bool nological; bool turbo_pascal; bool use_c_strings; bool extern_vars; bool preserve_case; bool nested_comments; bool copy_array; bool comment_tags; bool use_namespaces; bool smart_union; bool no_index_decrement; bool ignore_preprocessor_directives; bool hp_pascal; bool do_not_use_enums; char* pascall; char path_sep; FILE *call_graph_file; static void scan_opt (int argc, char **argv) { int i; unsigned j; bool found; static struct opt_str { bool *flag; char **value; char *str; char *defval; char *comment; } opt[] = { // Add command options to this table: { NULL, &i_path, "-I", ".", #ifdef _WIN32 "Include path (semicolon separated directory list)" }, #else "Include path (colon separated directory list)" }, #endif { NULL, &input_file, "-in", NULL, "Input pascal file" }, { NULL, &output_file, "-out", NULL, "Output C/C++ file" }, { NULL, &output_suf, "-suf", ".cxx", "Output C/C++ file suffix" }, { &language_c, NULL, "-c", NULL, "Translate into ANSI C" }, { &no_array_assign_operator, NULL, "-assign", NULL, "Do not use assignment operators for array" }, { &use_call_graph, NULL, "-analyze", NULL, "Analyze call graph to find non-recursive functions" }, { &short_set, NULL, "-intset", NULL, "Use integer types for short sets of enumerations" }, { &pio_init, NULL, "-init", NULL, "Call pio_initialize() function from main()" }, { &small_enum, NULL, "-smallenum", NULL, "Use for enumerated types as small bytes as possible" }, { &unsigned_comparison, NULL, "-unsigned", NULL, "Generate correct code for sign/unsigned comparisons" }, { &output_not_existed_hdr, NULL, "-h", NULL, "Output only not existed header files" }, { &turbo_pascal, NULL, "-turbo", NULL, "Convert Turbo Pascal" }, { &hp_pascal, NULL, "-hp", NULL, "Convert HP64000 Pascal" }, { &use_c_strings, NULL, "-cstring", NULL, "Use char* type for string fields in records and arrays" }, { &nological, NULL, "-nological", NULL, "Use | and & instead of || and && for boolean operations" }, { &extern_vars, NULL, "-extern", NULL, "Declare all variables from included files as \"EXTERN\"" }, { &preserve_case, NULL, "-preserve", NULL, "Preserve case of identifiers" }, { &nested_comments, NULL, "-nested", NULL, "Nested comments: (* {} *)" }, { ©_array, NULL, "-copy", NULL, "Always make a copy of array passed by value" }, { &comment_tags, NULL, "-comment_tags", NULL, "Place in comments tags of Pascal variant records" }, { &smart_union, NULL, "-smartunion", NULL, "Convert variant records with empty fixed part to unions" }, { &use_namespaces, NULL, "-namespace", NULL, "Place Turbo Pascal units in separate namespaces" }, { &no_index_decrement, NULL, "-0based", NULL, "Assume all arrays are zero based" }, { &ignore_preprocessor_directives, NULL, "-ignore_directives", NULL, "Ignore all lines started with '$' character" }, { &do_not_use_enums, NULL, "-no_enums", NULL, "Do not use enums for integer constants" }, { NULL, &pascall, "-pascall", "", "Specify modifier (pascal,WINAPI...) for converted functions" } }; for (j = 0; j < (sizeof(opt)/sizeof(opt_str)); j++) { if (opt[j].value != NULL) { *opt[j].value = opt[j].defval; } if (opt[j].flag != NULL) { *(opt[j].flag) = FALSE; // Switch off flags } } for (i = 1; i < argc; i++) { // Skipping program name if (argv[i][0] != '-') { if (input_file != NULL) { fprintf(stderr, "Only one input file name is accepted\n"); goto Help; } input_file = argv[i]; continue; } found = FALSE; for (j = 0; j < (sizeof(opt)/sizeof(opt_str)); j++) { if (strcmp (opt[j].str, argv[i]) == 0) { if (opt[j].flag != NULL) { *(opt[j].flag) = TRUE; } if (opt[j].value != NULL) { i++; if (i >= argc) { fprintf(stderr, "Value for option '%s' is not specified\n", opt[j].str); goto Help; } *opt[j].value = argv[i]; } found = TRUE; break; } } if (!found) { Help: fprintf (stderr, "Pascal to C/C++ converter. Version "VERSION"\n" "Available options are:\n"); for (j = 0; j < (sizeof(opt)/sizeof(opt_str)); j++ ) { if (opt[j].defval != NULL) { char buf[256]; sprintf(buf, "%s [%s]", opt[j].str, opt[j].defval); fprintf(stderr, "\t%-12s", buf); } else { fprintf(stderr, "\t%-12s", opt[j].str); } fprintf(stderr, "%s\n", opt[j].comment); } exit (1); } pio_init = TRUE; } if (input_file == NULL) { goto Help; } #ifdef _WIN32 char* p = strrchr(argv[0], '\\'); prog_path = (p != NULL) ? dprintf("%.*s", p + 1 - argv[0], argv[0]) : (char*)""; path_sep = ';'; #else #ifdef __EMX__ char* p = strrchr(_fnslashify(argv[0]), '/'); prog_path = (p != NULL) ? dprintf("%.*s", p + 1 - argv[0], argv[0]) : (char*)""; #else char* p = strrchr(argv[0], '/'); prog_path = (p != NULL) ? dprintf("%.*s", p + 1 - argv[0], argv[0]) : (char*)""; #endif path_sep = ':'; #endif i_path = dprintf("%s%c%s", i_path, path_sep, prog_path); } int main(int argc, char* argv[]) { scan_opt (argc, argv); if (input_file == NULL) { fputs("Input file was not specified\n", stderr); exit(1); } if (output_file == NULL) { char* ext = strrchr(input_file, '.'); int file_name_len = ext ? ext - input_file : strlen(input_file); if (language_c) output_suf = ".c"; output_file = dprintf("%.*s%s", file_name_len, input_file, output_suf); } load_predefined(); load_keywords(); load_configuration(dprintf("%s%s", prog_path, CONFIG_FILE)); if (hp_pascal) { nested_comments = 1; ignore_preprocessor_directives = 1; } if (use_call_graph) { call_graph_file = fopen(CALL_GRAPH_FILE, "a"); FILE* f = fopen(RECURSIVE_PROC_FILE, "r"); if (f != NULL) { char name[256]; while (fscanf(f, "%s", name) == 1) { nm_entry::add(name, TKN_IDENT)->flags |= nm_entry::recursive; } fclose(f); } } compile_system_library = TRUE; #ifdef PREFIX token::input(turbo_pascal ? PREFIX "/share/ptoc/tptoc.pas" : PREFIX "/share/ptoc/ptoc.pas")); #else token::input(dprintf("%s%s", prog_path, turbo_pascal ? "tptoc.pas" : "ptoc.pas")); #endif zzparse(); compile_system_library = FALSE; token::reset(); token::input(input_file); zzparse(); token::output(output_file); if (call_graph_file) { fclose(call_graph_file); } return 0; }