/* LookupTable::for_each callback */ static void cb(VMG_ const vm_val_t *key, const vm_val_t *val, void *ctx) { /* the context is our 'this' pointer */ metatab_saver *self = (metatab_saver *)ctx; CVmFile *fp = self->fp; /* both the key and value must be strings for us to save them */ const char *keystr = key->get_as_string(vmg0_); const char *valstr = val->get_as_string(vmg0_); if (keystr != 0 && valstr != 0) { size_t len; /* save the key string */ fp->write_uint2(len = vmb_get_len(keystr)); fp->write_bytes(keystr + VMB_LEN, len); /* save the value string */ fp->write_uint2(len = vmb_get_len(valstr)); fp->write_bytes(valstr + VMB_LEN, len); /* count the pair */ self->cnt += 1; } }
int main(int argc, char **argv) { CResLoader *res_loader; CTcHostIfc *hostifc; int curarg; int fatal_error_count = 0; osfildef *fpout = 0; int next_local = 0; CVmFile *imgfile = 0; CVmFile *objfile = 0; const char *imgfname; int success; char pathbuf[OSFNMAX]; static const char tool_data[4] = { 't', 's', 't', 'L' }; /* initialize for testing */ test_init(); /* create the host interface object */ hostifc = new CTcHostIfcStdio(); /* create a resource loader */ os_get_special_path(pathbuf, sizeof(pathbuf), argv[0], OS_GSP_T3_RES); res_loader = new CResLoader(pathbuf); /* initialize the compiler */ CTcMain::init(hostifc, res_loader, 0); err_try { /* scan arguments */ for (curarg = 1 ; curarg < argc ; ++curarg) { char *p; /* get the argument string for easy reference */ p = argv[curarg]; /* if it's not an option, we're done */ if (*p != '-') break; if (*(p + 1) == 'v') { /* set verbose mode */ G_tcmain->set_verbosity(TRUE); } else { /* * invalid usage - consume all the arguments and fall * through to the usage checker */ curarg = argc; break; } } /* check arguments */ if (curarg + 2 > argc) { /* terminate the compiler */ CTcMain::terminate(); /* delete our objects */ delete res_loader; /* exit with an error */ errexit("usage: test_link [options] obj-file [obj-file [...]] " "image-file\n" "options:\n" " -v - verbose error messages"); } /* set up an output file */ imgfname = argv[argc - 1]; fpout = osfopwb(imgfname, OSFTT3IMG); if (fpout == 0) errexit("unable to open image file"); imgfile = new CVmFile(); imgfile->set_file(fpout, 0); /* read the object files */ for ( ; curarg < argc - 1 ; ++curarg) { osfildef *fpobj; /* open this object file */ fpobj = osfoprb(argv[curarg], OSFTT3OBJ); if (fpobj == 0) { printf("unable to open object file \"%s\"\n", argv[curarg]); goto done; } /* note the loading */ printf("loading %s\n", argv[curarg]); /* set up the CVmFile object for it */ objfile = new CVmFile(); objfile->set_file(fpobj, 0); /* read the object file */ G_cg->load_object_file(objfile, argv[curarg]); /* done with the object file */ delete objfile; objfile = 0; } /* check for unresolved externals */ if (G_prs->check_unresolved_externs()) goto done; /* write the image file */ G_cg->write_to_image(imgfile, 0, tool_data); done: ; } err_catch(exc) { /* * if it's not a general internal or fatal error, log it; don't * log general errors, since these will have been logged as * specific internal errors before being thrown */ if (exc->get_error_code() != TCERR_INTERNAL_ERROR && exc->get_error_code() != TCERR_FATAL_ERROR) G_tok->log_error(TC_SEV_FATAL, exc->get_error_code()); /* count the fatal error */ ++fatal_error_count; } err_end; /* report errors */ fprintf(stderr, "Warnings: %d\n" "Errors: %d\n" "Longest string: %d, longest list: %d\n", G_tcmain->get_warning_count(), G_tcmain->get_error_count() + fatal_error_count, G_cg->get_max_str_len(), G_cg->get_max_list_cnt()); /* * note whether or not the compilation was successful - it succeeded * if we had no errors or fatal errors */ success = (G_tcmain->get_error_count() + fatal_error_count == 0); /* delete the object file object (this closes the file) */ delete imgfile; /* if we have an open object file, close it */ if (objfile != 0) delete objfile; /* * if any errors occurred, delete the object file in the external * file system - this prevents us from leaving around an incomplete * or corrupted image file when compilation fails, and helps * 'make'-type tools realize that they must generate the image file * target again on the next build, even if source files didn't * change */ if (!success) osfdel(imgfname); /* shut down the compiler */ CTcMain::terminate(); /* done with the res loader */ delete res_loader; /* delete the host interface */ delete hostifc; /* show any unfreed memory */ t3_list_memory_blocks(0); /* * terminate - exit with a success indication if we had no errors * (other than warnings); exit with an error indication otherwise */ return (success ? OSEXSUCC : OSEXFAIL); }
/* * Execute an image file. If an exception occurs, we'll display a * message on the console, and we'll return the error code; we'll return * zero on success. If an error occurs, we'll fill in 'errbuf' with a * message describing the problem. */ int vm_run_image(CVmMainClientIfc *clientifc, const char *image_file_name, class CVmHostIfc *hostifc, const char *const *prog_argv, int prog_argc, const char *script_file, int script_quiet, const char *log_file, const char *cmd_log_file, int load_from_exe, int show_banner, const char *charset, const char *log_charset, const char *saved_state, const char *res_dir) { CVmFile *fp = 0; CVmImageLoader *volatile loader = 0; CVmImageFile *volatile imagefp = 0; unsigned long image_file_base = 0; int retval; vm_globals *vmg__; /* presume we will return success */ retval = 0; /* create the file object */ fp = new CVmFile(); /* initialize the VM */ vm_init_options opts(hostifc, clientifc, charset, log_charset); vm_initialize(&vmg__, &opts); /* tell the client system to initialize */ clientifc->client_init(VMGLOB_ADDR, script_file, script_quiet, log_file, cmd_log_file, show_banner ? T3VM_BANNER_STRING : 0); /* catch any errors that occur during loading and running */ err_try { /* remember the name of the byte-code file */ strncpy(G_os_gamename, image_file_name, sizeof(G_os_gamename)); G_os_gamename[sizeof(G_os_gamename) - 1] = '\0'; if (load_from_exe) { osfildef *exe_fp; /* find the image within the executable */ exe_fp = os_exeseek(image_file_name, "TGAM"); if (exe_fp == 0) err_throw(VMERR_NO_IMAGE_IN_EXE); /* * set up to read from the executable at the location of the * embedded image file that we just found */ image_file_base = osfpos(exe_fp); fp->set_file(exe_fp, image_file_base); } else { /* reading from a normal file - open the file */ fp->open_read(image_file_name, OSFTT3IMG); } /* create the loader */ imagefp = new CVmImageFileExt(fp); loader = new CVmImageLoader(imagefp, image_file_name, image_file_base); /* load the image */ loader->load(vmg0_); /* if we have a resource root path, tell the host interface */ if (res_dir != 0) hostifc->set_res_dir(res_dir); /* let the client prepare for execution */ clientifc->pre_exec(VMGLOB_ADDR); /* run the program from the main entrypoint */ loader->run(vmg_ prog_argv, prog_argc, 0, saved_state); /* tell the client we're done with execution */ clientifc->post_exec(VMGLOB_ADDR); } err_catch(exc) { char errbuf[512]; /* tell the client execution failed due to an error */ clientifc->post_exec_err(VMGLOB_ADDR); /* note the error code for returning to the caller */ retval = exc->get_error_code(); /* get the message for the error */ CVmRun::get_exc_message(vmg_ exc, errbuf, sizeof(errbuf), TRUE); /* display the message */ clientifc->display_error(VMGLOB_ADDR, errbuf, FALSE); } err_end; /* unload the image */ if (loader != 0) loader->unload(vmg0_); /* delete the loader and the image file object */ if (loader != 0) delete loader; if (imagefp != 0) delete imagefp; /* notify the client */ clientifc->client_terminate(VMGLOB_ADDR); /* terminate the VM */ vm_terminate(vmg__, clientifc); /* delete the file */ if (fp != 0) delete fp; /* return the status code */ return retval; }
int main(int argc, char **argv) { CVmFile *fp = 0; CVmImageWriter *volatile iw = 0; /* initialize for testing */ test_init(); /* initialize error stack */ err_init(1024); /* check arguments */ if (argc != 2) errexit("usage: test_write <output-file>"); /* open the file */ fp = new CVmFile(); err_try { static const char *meta[] = { "tads-object" }; static const char *bif[] = { "tads/030000" }; static const unsigned char code0[] = { /* * method header */ 0x00, /* parameter count */ 0x00, /* reserved */ 0x02, 0x00, /* local variable count */ 0x20, 0x00, /* maximum stack usage */ 0x00, 0x00, /* exception table offset */ 0x00, 0x00, /* debugging records offset */ 0x00, 0x00, 0x00, 0x00, /* defining object */ /* * code */ // local i; // -> local #0 // local j; // -> local #1 // // say('hello, world!\n'); 0x05, 0x00, 0x00, 0x00, 0x00, // pushstr 0x00000000 0xB1, 0x00, 0x01, // builtin_a 0 // for (i := 1 ; i < 100 ; ++i) // { 0xDA, 0x00, // onelcl1 0 // $1: 0x80, 0x00, // getlcl1 0 0x03, 0x64, // pushint8 100 0x96, 0x29, 0x00, // jgt $2 ; +41 // j := i*3; 0x80, 0x00, // getlcl1 0 0x03, 0x03, // pushint8 3 0x24, // mul 0xE0, 0x01, // setlcl1 1 // say('i = ' + i + ', j = ' + j + '\n'); 0x05, 0x10, 0x00, 0x00, 0x00, // pushstr 0x00000010 0x80, 0x00, // getlcl1 0 0x22, // add 0x05, 0x16, 0x00, 0x00, 0x00, // pushstr 0x00000016 0x22, // add 0x80, 0x01, // getlcl1 1 0x22, // add 0x05, 0x1E, 0x00, 0x00, 0x00, // pushstr 0x0000001E 0x22, // add 0xB1, 0x00, 0x01, // builtin_a 0 // } // end of for 0xD0, 0x00, 0x00, // inclcl 0 0x91, 0xD4, 0xFF, // jmp $1 ; -44 // $2: // END OF FUNCTION 0x51 // retnil }; static const unsigned char const0[] = { /* 0 = 0x0000 */ /* string "hello, world!\n" */ 0x0E, 0x00, // length = 14 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', 0x0A, /* 16 = 0x0010 */ /* string "i = " */ 0x04, 0x00, // length = 4 'i', ' ', '=', ' ', /* 22 = 0x0016 */ /* string ", j = " */ 0x06, 0x00, // length = 6 ',', ' ', 'j', ' ', '=', ' ', /* 30 = 0x001E */ /* string "\n" */ 0x01, 0x00, // length = 1 0x0A }; static const char tool_data[4] = { 't', 'e', 's', 't' }; /* open the output file */ fp->open_write(argv[1], OSFTT3IMG); /* create an image writer */ iw = new CVmImageWriter(fp); /* start the file */ iw->prepare(1, tool_data); /* write the entrypoint - enter at code offset zero */ iw->write_entrypt(0, 14, 10, 10, 2, 6, 4, 1); /* write an empty function set dependency table */ iw->write_func_dep(bif, sizeof(bif)/sizeof(bif[0])); /* write our metaclass dependency table */ iw->write_meta_dep(meta, sizeof(meta)/sizeof(meta[0])); /* write our code pool definition and pages */ iw->write_pool_def(1, 1, 4096, TRUE); iw->write_pool_page(1, 0, (const char *)code0, sizeof(code0), TRUE, 0); /* write the constant pool definition and pages */ iw->write_pool_def(2, 1, 4096, TRUE); iw->write_pool_page(2, 0, (const char *)const0, sizeof(const0), TRUE, 0); /* finish the image file data */ iw->finish(); } err_catch(exc) { printf("exception caught: %d\n", exc->get_error_code()); } err_end; /* delete the image writer */ if (iw != 0) delete iw; /* release our file object */ if (fp != 0) delete fp; /* delete the error context */ err_terminate(); /* done */ return 0; }
int main(int argc, char **argv) { CResLoader *res_loader; CTcHostIfc *hostifc; int curarg; int fatal_error_count = 0; osfildef *fpout = 0; CVmFile *imgfile = 0; CTcUnasSrcCodeStr *unas_in; CTcUnasOutStdio unas_out; CTPNStmProg *node; const char *image_fname; int success; int unasm = FALSE; uchar xor_mask = 0; char pathbuf[OSFNMAX]; /* initialize for testing */ test_init(); /* create the host interface object */ hostifc = new CTcHostIfcStdio(); /* create a resource loader */ os_get_special_path(pathbuf, sizeof(pathbuf), argv[0], OS_GSP_T3_RES); res_loader = new CResLoader(pathbuf); /* initialize the compiler */ CTcMain::init(hostifc, res_loader, "us-ascii"); /* use test reporting mode */ G_tok->set_test_report_mode(TRUE); G_tcmain->set_test_report_mode(TRUE); /* create the disassembler input stream */ unas_in = new CTcUnasSrcCodeStr(G_cs); err_try { static const char tool_data[4] = { 't', 's', 't', 'P' }; /* scan options */ for (curarg = 1 ; curarg < argc ; ++curarg) { char *p; /* get the argument string for easy reference */ p = argv[curarg]; /* if it's not an option, we're done */ if (*p != '-') break; /* if it's a -I argument, use it */ if (*(p + 1) == 'I') { char *path; /* * if it's with this argument, read it, otherwise move * on to the next argument */ if (*(p + 2) == '\0') path = argv[++curarg]; else path = p + 2; /* add the directory to the include path list */ G_tok->add_inc_path(path); } else if (*(p + 1) == 'v') { /* set verbose mode */ G_tcmain->set_verbosity(TRUE); } else if (*(p + 1) == 'u') { /* note unassembly mode */ unasm = TRUE; } else { /* * invalid usage - consume all the arguments and fall * through to the usage checker */ curarg = argc; break; } } /* check arguments */ if (curarg + 2 != argc) { /* terminate the compiler */ CTcMain::terminate(); /* delete our objects */ delete res_loader; /* exit with an error */ errexit("usage: test_prs [options] <source-file> <image-file>\n" "options:\n" " -Idir - add dir to include path\n" " -v - verbose error messages"); } /* add the default system include directory to the include path */ os_get_special_path(pathbuf, sizeof(pathbuf), argv[0], OS_GSP_T3_INC); G_tok->add_inc_path(pathbuf); /* set up the tokenizer with the main input file */ if (G_tok->set_source(argv[curarg], argv[curarg])) errexit("unable to open source file"); /* set up an output file */ image_fname = argv[curarg+1]; fpout = osfopwb(image_fname, OSFTT3IMG); if (fpout == 0) errexit("unable to open image file"); imgfile = new CVmFile(); imgfile->set_file(fpout, 0); /* read the first token */ G_tok->next(); /* parse at the top level */ node = G_prs->parse_top(); /* if errors occurred during parsing, stop here */ if (G_tcmain->get_error_count() != 0 || node == 0) goto done; /* fold symbolic constants for all nodes */ node->fold_constants(G_prs->get_global_symtab()); /* if errors occurred during constant folding, stop now */ if (G_tcmain->get_error_count() != 0) goto done; /* generate code and write the image file */ node->build_image(imgfile, xor_mask, tool_data); /* if errors occurred during code generation, stop now */ if (G_tcmain->get_error_count() != 0) goto done; /* disassemble the result if desired */ if (unasm) CTcT3Unasm::disasm(unas_in, &unas_out); done: ; } err_catch(exc) { /* * if it's not a general internal or fatal error, log it; don't * log general errors, since these will have been logged as * specific internal errors before being thrown */ if (exc->get_error_code() != TCERR_INTERNAL_ERROR && exc->get_error_code() != TCERR_FATAL_ERROR) G_tok->log_error(TC_SEV_FATAL, exc->get_error_code()); /* count the fatal error */ ++fatal_error_count; } err_end; /* report errors */ fprintf(stderr, "Warnings: %d\n" "Errors: %d\n" "Longest string: %d, longest list: %d\n", G_tcmain->get_warning_count(), G_tcmain->get_error_count() + fatal_error_count, G_cg->get_max_str_len(), G_cg->get_max_list_cnt()); /* * note whether or not the compilation was successful - it succeeded * if we had no errors or fatal errors */ success = (G_tcmain->get_error_count() + fatal_error_count == 0); /* delete the image file object (this closes the file) */ delete imgfile; /* * if any errors occurred, delete the image file in the external * file system - this prevents us from leaving around an incomplete * or corrupted image file when compilation fails, and helps * 'make'-type tools realize that they must generate the image file * target again on the next build, even if source files didn't * change */ if (!success) osfdel(image_fname); /* delete the disassembler input object */ delete unas_in; /* shut down the compiler */ CTcMain::terminate(); /* done with the res loader */ delete res_loader; /* delete the host interface */ delete hostifc; /* show any unfreed memory */ t3_list_memory_blocks(0); /* * terminate - exit with a success indication if we had no errors * (other than warnings); exit with an error indication otherwise */ return (success ? OSEXSUCC : OSEXFAIL); }
int main(int argc, char **argv) { CResLoader *res_loader; CTcHostIfc *hostifc; int curarg; int fatal_error_count = 0; node_entry *node_head = 0; node_entry *node_tail = 0; osfildef *fpout = 0; CVmFile *imgfile = 0; ulong next_obj_id = 1; uint next_prop_id = 1; int next_local = 0; CTcTokFileDesc *desc; long linenum; CTcUnasSrcCodeStr *unas_in; CTcUnasOutStdio unas_out; char pathbuf[OSFNMAX]; /* initialize for testing */ test_init(); /* create the host interface object */ hostifc = new CTcHostIfcStdio(); /* create a resource loader */ os_get_special_path(pathbuf, sizeof(pathbuf), argv[0], OS_GSP_T3_RES); res_loader = new CResLoader(pathbuf); /* initialize the compiler */ CTcMain::init(hostifc, res_loader, 0); /* create the disassembler input stream */ unas_in = new CTcUnasSrcCodeStr(G_cs); err_try { /* scan -I arguments */ for (curarg = 1 ; curarg < argc ; ++curarg) { char *p; /* get the argument string for easy reference */ p = argv[curarg]; /* if it's not an option, we're done */ if (*p != '-') break; /* if it's a -I argument, use it */ if (*(p + 1) == 'I') { char *path; /* * if it's with this argument, read it, otherwise move * on to the next argument */ if (*(p + 2) == '\0') path = argv[++curarg]; else path = p + 2; /* add the directory to the include path list */ G_tok->add_inc_path(path); } else if (*(p + 1) == 'v') { /* set verbose mode */ G_tcmain->set_verbosity(TRUE); } else { /* * invalid usage - consume all the arguments and fall * through to the usage checker */ curarg = argc; break; } } /* check arguments */ if (curarg + 2 != argc) { /* terminate the compiler */ CTcMain::terminate(); /* delete our objects */ delete res_loader; /* exit with an error */ errexit("usage: test_prs [options] <source-file> <image-file>\n" "options:\n" " -Idir - add dir to include path\n" " -v - verbose error messages"); } /* set up the tokenizer with the main input file */ if (G_tok->set_source(argv[curarg], argv[curarg])) errexit("unable to open source file"); /* set up an output file */ fpout = osfopwb(argv[curarg+1], OSFTT3IMG); if (fpout == 0) errexit("unable to open image file"); imgfile = new CVmFile(); imgfile->set_file(fpout, 0); /* read the first token */ G_tok->next(); /* parse expressions */ for (;;) { CTcPrsNode *result; CTcSymbol *entry; /* if we're at end of file, we're done */ if (G_tok->getcur()->gettyp() == TOKT_EOF) break; /* check for our fake declarations */ switch(G_tok->getcur()->gettyp()) { case TOKT_OBJECT: /* add an object symbol */ G_tok->next(); entry = new CTcSymObj(G_tok->getcur()->get_text(), G_tok->getcur()->get_text_len(), FALSE, next_obj_id++, FALSE, TC_META_TADSOBJ, 0); G_prs->get_global_symtab()->add_entry(entry); /* skip the object name */ G_tok->next(); break; case TOKT_FUNCTION: /* add a function symbol */ G_tok->next(); entry = new CTcSymFunc(G_tok->getcur()->get_text(), G_tok->getcur()->get_text_len(), FALSE, 0, 0, FALSE, TRUE, FALSE, FALSE, FALSE); G_prs->get_global_symtab()->add_entry(entry); /* skip the function name */ G_tok->next(); break; case TOKT_LOCAL: /* add a local variable symbol */ G_tok->next(); entry = new CTcSymLocal(G_tok->getcur()->get_text(), G_tok->getcur()->get_text_len(), FALSE, FALSE, next_local++); G_prs->get_global_symtab()->add_entry(entry); /* skip the function name */ G_tok->next(); break; default: /* note the starting line */ desc = G_tok->get_last_desc(); linenum = G_tok->get_last_linenum(); /* parse an expression */ result = G_prs->parse_expr(); /* add it to our list */ if (result != 0) { node_entry *cur; /* create a new list entry */ cur = new node_entry(result, desc, linenum); /* link it at the end of our list */ cur->nxt = 0; if (node_tail != 0) node_tail->nxt = cur; else node_head = cur; node_tail = cur; } } /* parse a semicolon */ if (G_prs->parse_req_sem()) break; } /* * if there were no parse errors, run through our node list and * generate code */ if (G_tcmain->get_error_count() == 0) { /* * loop through our node list; generate code and then delete * each list entry */ while (node_head != 0) { node_entry *nxt; /* remember the next entry */ nxt = node_head->nxt; /* * set this line's descriptor as current, for error * reporting purposes */ G_tok->set_line_info(node_head->desc, node_head->linenum); /* fold symbolic constants */ node_head->node = node_head->node ->fold_constants(G_prs->get_global_symtab()); /* if it's a constant value, display it */ show_const(0, node_head->node); /* * generate code; for testing purposes, don't discard * anything, to ensure we perform all generation */ node_head->node->gen_code(FALSE, FALSE); /* disassemble this much */ unas_out.print("// line %lu\n", node_head->linenum); CTcT3Unasm::disasm(unas_in, &unas_out); /* delete this entry */ delete node_head; /* move on to the next entry */ node_head = nxt; } } } err_catch(exc) { /* * if it's not a general internal or fatal error, log it; don't * log general errors, since these will have been logged as * specific internal errors before being thrown */ if (exc->get_error_code() != TCERR_INTERNAL_ERROR && exc->get_error_code() != TCERR_FATAL_ERROR) G_tok->log_error(TC_SEV_FATAL, exc->get_error_code()); /* count the fatal error */ ++fatal_error_count; } err_end; /* report errors */ fprintf(stderr, "Warnings: %d\n" "Errors: %d\n" "Longest string: %d, longest list: %d\n", G_tcmain->get_warning_count(), G_tcmain->get_error_count() + fatal_error_count, G_cg->get_max_str_len(), G_cg->get_max_list_cnt()); /* delete the disassembler input object */ delete unas_in; /* shut down the compiler */ CTcMain::terminate(); /* done with the res loader */ delete res_loader; /* delete the image file */ delete imgfile; /* delete the host interface */ delete hostifc; /* show any unfreed memory */ t3_list_memory_blocks(0); /* success */ return 0; }