/* * set up the compiler */ CTcMain::CTcMain(CResLoader *res_loader, const char *default_charset) { char csbuf[OSFNMAX]; /* * if the caller didn't provide a default character set, ask the OS * what we should use */ if (default_charset == 0) { /* * ask the OS what to use for file contents, since we use this * character set to translate the text we read from source files */ os_get_charmap(csbuf, OS_CHARMAP_FILECONTENTS); /* use our OS-provided character set */ default_charset = csbuf; } /* if there's no static console output character map, create one */ if (console_mapper_ == 0) { char mapname[32]; /* get the console character set name */ os_get_charmap(mapname, OS_CHARMAP_DISPLAY); /* create a resource loader for the console character map */ console_mapper_ = CCharmapToLocal::load(res_loader, mapname); /* if that failed, create an ASCII mapper */ if (console_mapper_ == 0) console_mapper_ = CCharmapToLocal::load(res_loader, "us-ascii"); } /* remember our resource loader */ res_loader_ = res_loader; /* * set default options - minimum verbosity, no numeric error codes, * show standard warnings but not pedantic warnings, not test mode */ err_options_ = TCMAIN_ERR_WARNINGS; /* we have no warning suppression list yet */ suppress_list_ = 0; suppress_cnt_ = 0; /* remember our default character set */ default_charset_ = lib_copy_str(default_charset); /* create the tokenizer */ G_tok = new CTcTokenizer(res_loader_, default_charset_); /* * Create the parser and node memory pool. Create the memory pool * first, because the parser allocates objects out of the pool. */ G_prsmem = new CTcPrsMem(); G_prs = new CTcParser(); /* create the generator data stream (for constant data) */ G_ds = new CTcDataStream(TCGEN_DATA_STREAM); /* create the primary generator code stream */ G_cs_main = new CTcCodeStream(TCGEN_CODE_STREAM); /* create the static initializer code stream */ G_cs_static = new CTcCodeStream(TCGEN_STATIC_CODE_STREAM); /* make the primary code stream active */ G_cs = G_cs_main; /* create the generator object data stream */ G_os = new CTcDataStream(TCGEN_OBJECT_STREAM); /* create the intrinsic class modifier object data stream */ G_icmod_stream = new CTcDataStream(TCGEN_ICMOD_STREAM); /* create the dictionary object data stream */ G_dict_stream = new CTcDataStream(TCGEN_DICT_STREAM); /* create the grammar-production object data stream */ G_gramprod_stream = new CTcDataStream(TCGEN_GRAMPROD_STREAM); /* create the BigNumber object data stream */ G_bignum_stream = new CTcDataStream(TCGEN_BIGNUM_STREAM); /* create the IntrinsicClass object data stream */ G_int_class_stream = new CTcDataStream(TCGEN_INTCLASS_STREAM); /* create the static initializer identifier stream */ G_static_init_id_stream = new CTcDataStream(TCGEN_STATIC_INIT_ID_STREAM); /* create the target-specific code generator */ G_cg = new CTcGenTarg(); /* initialize the parser */ G_prs->init(); /* no errors or warnings yet */ error_count_ = 0; warning_count_ = 0; first_error_ = 0; first_warning_ = 0; /* set a fairly liberal maximum error limit */ max_error_count_ = 100; /* there's no disassembly output stream yet */ G_disasm_out = 0; }
/* * Perform base initialization. This is an internal routine called only * by higher-level initialization routines; we perform all of the * generic, configuration-independent initialization. */ void vm_init_base(vm_globals **vmg, const vm_init_options *opts) { vm_globals *vmg__; char disp_mapname[32]; char filename_mapname[32]; char filecont_mapname[32]; CResLoader *map_loader; int disp_map_err; const char *charset = opts->charset; /* * Allocate globals according to build-time configuration, then * assign the global pointer to a local named vmg__. This will * ensure that the globals are accessible for all of the different * build-time configurations. */ vmg__ = *vmg = vmglob_alloc(); /* initialize the error stack */ err_init(VM_ERR_STACK_BYTES); /* get the character map loader from the host interface */ map_loader = opts->hostifc->get_cmap_res_loader(); /* if an external message set hasn't been loaded, try loading one */ if (!err_is_message_file_loaded() && map_loader != 0) { osfildef *fp; /* try finding a message file */ fp = map_loader->open_res_file(VM_ERR_MSG_FNAME, 0, VM_ERR_MSG_RESTYPE); if (fp != 0) { /* * try loading it - if that fails, we'll just be left with * the built-in messages, so we won't have lost anything for * trying */ err_load_vm_message_file(fp); /* we're done with the file */ osfcls(fp); } } /* remember the host interface */ G_host_ifc = opts->hostifc; /* initialize the system debug log file name */ char path[OSFNMAX]; opts->hostifc->get_special_file_path(path, sizeof(path), OS_GSP_LOGFILE); os_build_full_path(G_syslogfile, sizeof(G_syslogfile), path, "tadslog.txt"); /* we don't have a resource loader for program resources yet */ G_res_loader = 0; /* create the object table */ VM_IF_ALLOC_PRE_GLOBAL(G_obj_table = new CVmObjTable()); G_obj_table->init(vmg0_); /* * Create the memory manager. Empirically, our hybrid heap allocator * is faster than the standard C++ run-time library's allocator on many * platforms, so use it instead of hte basic 'malloc' allocator. */ G_varheap = new CVmVarHeapHybrid(G_obj_table); // G_varheap = new CVmVarHeapMalloc(); to use the system 'malloc' instead G_mem = new CVmMemory(vmg_ G_varheap); /* create the undo manager */ G_undo = new CVmUndo(VM_UNDO_MAX_RECORDS, VM_UNDO_MAX_SAVEPTS); /* create the metafile and function set tables */ G_meta_table = new CVmMetaTable(5); G_bif_table = new CVmBifTable(5); /* initialize the metaclass registration tables */ vm_register_metaclasses(); /* initialize the TadsObject class */ CVmObjTads::class_init(vmg0_); /* create the byte-code interpreter */ VM_IFELSE_ALLOC_PRE_GLOBAL( G_interpreter = new CVmRun(VM_STACK_SIZE, vm_init_stack_reserve()), G_interpreter->init()); /* presume we won't create debugger information */ G_debugger = 0; G_srcf_table = 0; /* presume we don't have a network configuration */ G_net_config = 0; /* initialize the debugger if present */ vm_init_debugger(vmg0_); /* create the source file table */ G_srcf_table = new CVmSrcfTable(); /* create the pre-defined object mapper */ VM_IFELSE_ALLOC_PRE_GLOBAL(G_predef = new CVmPredef, G_predef->reset()); /* presume we're in normal execution mode (not preinit) */ G_preinit_mode = FALSE; /* allocate the TADS intrinsic function set's globals */ G_bif_tads_globals = new CVmBifTADSGlobals(vmg0_); /* allocate the BigNumber register cache */ G_bignum_cache = new CVmBigNumCache(32); /* no image loader yet */ G_image_loader = 0; /* * If the caller explicitly specified a character set, use it. * Otherwise, ask the OS layer for the default character set we * should use. */ if (charset == 0) { /* the user did not specify a mapping - ask the OS for the default */ os_get_charmap(disp_mapname, OS_CHARMAP_DISPLAY); /* use the name we got from the OS */ charset = disp_mapname; /* there's no explicit global character set name setting to store */ G_disp_cset_name = 0; } else { /* save the global character set name */ G_disp_cset_name = lib_copy_str(charset); } /* create the display character maps */ G_cmap_from_ui = CCharmapToUni::load(map_loader, charset); G_cmap_to_ui = CCharmapToLocal::load(map_loader, charset); /* create the filename character maps */ os_get_charmap(filename_mapname, OS_CHARMAP_FILENAME); G_cmap_from_fname = CCharmapToUni::load(map_loader, filename_mapname); G_cmap_to_fname = CCharmapToLocal::load(map_loader, filename_mapname); /* create the file-contents character maps */ os_get_charmap(filecont_mapname, OS_CHARMAP_FILECONTENTS); G_cmap_from_file = CCharmapToUni::load(map_loader, filecont_mapname); G_cmap_to_file = CCharmapToLocal::load(map_loader, filecont_mapname); /* * If the caller specified a separate log-file character set, create * the mapping. Otherwise, just use the to-file mapper for log files. */ if (opts->log_charset != 0) { /* load the specified log file output mapping */ G_cmap_to_log = CCharmapToLocal::load(map_loader, opts->log_charset); } else { /* no log file mapping is specified, so use the generic file map */ if ((G_cmap_to_log = G_cmap_to_file) != 0) G_cmap_to_log->add_ref(); } /* make a note of whether we had any problems loading the maps */ disp_map_err = (G_cmap_from_ui == 0 || G_cmap_to_ui == 0); /* if we failed to create any of the maps, load defaults */ if (G_cmap_from_ui == 0) G_cmap_from_ui = CCharmapToUni::load(map_loader, "us-ascii"); if (G_cmap_to_ui == 0) G_cmap_to_ui = CCharmapToLocal::load(map_loader, "us-ascii"); if (G_cmap_from_fname == 0) G_cmap_from_fname = CCharmapToUni::load(map_loader, "us-ascii"); if (G_cmap_to_fname == 0) G_cmap_to_fname = CCharmapToLocal::load(map_loader, "us-ascii"); if (G_cmap_from_file == 0) G_cmap_from_file = CCharmapToUni::load(map_loader, "us-ascii"); if (G_cmap_to_file == 0) G_cmap_to_file = CCharmapToLocal::load(map_loader, "us-ascii"); if (G_cmap_to_log == 0) G_cmap_to_log = CCharmapToLocal::load(map_loader, "us-ascii"); /* create the primary console */ G_console = opts->clientifc->create_console(VMGLOB_ADDR); /* * if we had any trouble opening the display character mapping file, * make a note that we are using a default mapping */ if (disp_map_err) { const char *msg; char buf[256]; /* get the message */ msg = err_get_msg(vm_messages, vm_message_count, VMERR_NO_CHARMAP_FILE, TRUE); /* format it */ sprintf(buf, msg, charset); /* display it */ opts->clientifc->display_error(VMGLOB_ADDR, 0, buf, TRUE); } }