Exemple #1
0
    /* 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;
        }
    }
Exemple #2
0
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);
}
Exemple #3
0
/*
 *   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;
}
Exemple #4
0
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;
}
Exemple #5
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);
}
Exemple #6
0
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;
}