Example #1
0
/*
 *   Main program entrypoint 
 */
int main(int argc, char **argv)
{
    int stat;
    MyClientIfc clientifc;
    CVmHostIfc *hostifc = new CVmHostIfcStdio(argv[0]);

    /* initialize for testing */
    test_init();

    /* 
     *   Initialize the OS layer.  Since this is a command-line-only
     *   implementation, there's no need to ask the OS layer to try to get
     *   us a filename to run, so pass in null for the prompt and filename
     *   buffer.  
     */
    os_init(&argc, argv, 0, 0, 0);

    /* run the image */
    stat = vm_run_image_main(&clientifc, "test_exec", argc, argv,
                             TRUE, TRUE, hostifc);

    /* uninitialize the OS layer */
    os_uninit();

    /* done with the host interface */
    delete hostifc;

    /* show any unfreed memory */
    t3_list_memory_blocks(0);

    /* done */
    return stat;
}
Example #2
0
/*
 *   Invoke the T3 VM with the given command-line arguments
 */
static int main_t3(int argc, char **argv)
{
    CVmMainClientConsole clientifc;
    int stat;
    CVmHostIfc *hostifc = new CVmHostIfcStdio(argv[0]);

#ifdef GARGLK
    garglk_set_program_name("TADS " T3VM_VSN_STRING);
    char *s;
    s = strrchr(argv[1], '/');
    if (!s) s = strrchr(argv[1], '\\');
    garglk_set_story_name(s ? s + 1 : argv[1]);
#endif

    /* 
     *   Initialize the OS layer.  Since this is a command-line-only
     *   implementation, there's no need to ask the OS layer to try to get
     *   us a filename to run, so pass in null for the prompt and filename
     *   buffer.  
     */
    os_init(&argc, argv, 0, 0, 0);

    /* invoke the basic entrypoint */
    stat = vm_run_image_main(&clientifc, "t3run", argc, argv,
                             TRUE, FALSE, hostifc);

    /* uninitialize the OS layer */
    os_uninit();

    /* done with the host interface */
    delete hostifc;

    /* show any unfreed memory */
    t3_list_memory_blocks(0);

    /* exit with status code */
    os_term(stat);

    /* we shouldn't get here, but in case os_term doesn't really exit... */
    return stat;
}
/*
 *   Invoke the T3 VM with the given command-line arguments
 */
static int main_t3(int argc, char **argv)
{
    CVmMainClientConsole clientifc;
    int stat;
    CVmHostIfc *hostifc = new CVmHostIfcStdio(argv[0]);

    /* check for a "-plain" option */
    check_plain_option(argc, argv);

    /* 
     *   Initialize the OS layer.  Since this is a command-line-only
     *   implementation, there's no need to ask the OS layer to try to get
     *   us a filename to run, so pass in null for the prompt and filename
     *   buffer.  
     */
    os_init(&argc, argv, 0, 0, 0);

    /* invoke the basic entrypoint */
    stat = vm_run_image_main(&clientifc, "t3run", argc, argv,
                             TRUE, FALSE, hostifc);

    /* uninitialize the OS layer */
    os_uninit();

    /* done with the host interface */
    delete hostifc;

    /* show any unfreed memory */
    t3_list_memory_blocks(0);

    /* exit with status code */
    os_term(stat);

    /* we shouldn't get here, but in case os_term doesn't really exit... */
    return stat;
}
Example #4
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);
}
Example #5
0
int main(int argc, char **argv)
{
    CResLoader *res_loader;
    CTcHostIfc *hostifc;
    int curarg;
    CTcTokFileDesc *desc;
    long linenum;
    int pp_mode = FALSE;
    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");

    /* set test reporting mode */
    G_tok->set_test_report_mode(TRUE);
    G_tcmain->set_test_report_mode(TRUE);

    err_try
    {
        /* add some pre-defined symbols for testing */
        G_tok->add_define("_MSC_VER", "1100");
        G_tok->add_define("_WIN32", "1");
        G_tok->add_define("_M_IX86", "500");
        G_tok->add_define("__STDC__", "0");
        G_tok->add_define("_INTEGRAL_MAX_BITS", "64");
        G_tok->add_define("__cplusplus", "1");
        
        /* 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) == 'P')
            {
                /* set preprocess-only mode */
                G_tok->set_mode_pp_only(TRUE);
                pp_mode = TRUE;
            }
            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 + 1 != argc)
        {
            /* terminate the compiler */
            CTcMain::terminate();
            
            /* delete our objects */
            delete res_loader;
            
            /* exit with an error */
            errexit("usage: test_tok [options] <source-file>\n"
                    "options:\n"
                    "   -Idir   - add dir to include path\n"
                    "   -P      - preprocess to standard output\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");
        
        /* start out with no stream */
        desc = 0;
        linenum = 0;
        
        /* read lines of input */
        for (;;)
        {
            /* read the next line, and stop if we've reached end of file */
            if (G_tok->read_line_pp())
                break;
            
            /* 
             *   If we're in a different stream than for the last line, or
             *   the new line number is more than the last line number plus
             *   1, add a #line directive to the output stream.
             *   
             *   In order to make test log output independent of local path
             *   naming conventions and the local directory structure, use
             *   only the root filename in the #line directive.  
             */
            if (pp_mode
                && (G_tok->get_last_desc() != desc
                    || G_tok->get_last_linenum() != linenum + 1))
                printf("#line %ld %s\n", G_tok->get_last_linenum(),
                       G_tok->get_last_desc()->get_dquoted_rootname());
            
            /* remember the last line we read */
            desc = G_tok->get_last_desc();
            linenum = G_tok->get_last_linenum();
            
            /* show this line */
            printf("%s\n", G_tok->get_cur_line());
        }
        
        /* dump the hash table, to see what it looks like */
        G_tok->get_defines_table()->debug_dump();
    }
    err_catch(exc)
    {
        /* 
         *   if it's not the general internal error, log it; don't log
         *   general internal errors, since these will have been logged as
         *   specific internal errors before being thrown 
         */
        if (exc->get_error_code() != TCERR_INTERNAL_ERROR)
            printf("exception caught: %d\n", exc->get_error_code());
    }
    err_end;

    /* shut down the compiler */
    CTcMain::terminate();

    /* done with the res loader */
    delete res_loader;

    /* delete host interface */
    delete hostifc;

    /* show any unfreed memory */
    t3_list_memory_blocks(0);

    /* success */
    return 0;
}
Example #6
0
/*
 *   Main entrypoint 
 */
int main(int argc, char **argv)
{
    int stat;
    int i;
    CVmHostIfc *hostifc;
    CVmMainClientConsole clientifc;

    /* 
     *   Check for a "-plain" option; if it's there, set the terminal to
     *   plain text mode.  We must make this check before doing anything
     *   else, because os_plain() must be called prior to os_init() if
     *   it's going to be called at all.  
     */
    for (i = 1 ; i < argc ; ++i)
    {
        if (strcmp(argv[i], "-plain") == 0)
        {
            /* set plain text mode in the OS layer */
            os_plain();

            /* we've found what we're looking for - no need to look further */
            break;
        }
    }

    /* 
     *   Initialize the OS layer.  Since this is a command-line-only
     *   implementation, there's no need to ask the OS layer to try to get us
     *   a filename to run, so pass in null for the prompt and filename
     *   buffer.  
     */
    os_init(&argc, argv, 0, 0, 0);

    /* install the OS break handler while we're running */
    os_instbrk(1);

    /* create the host interface */
    hostifc = new CVmHostIfcStdio(argv[0]);

    /* invoke the basic entrypoint */
    stat = vm_run_image_main(&clientifc, "t3run", argc, argv,
                             TRUE, FALSE, hostifc);

#ifdef TADSNET
    /* 
     *   Disconnect the Web UI, if applicable.  Leave any final UI window
     *   state displayed until the user manually closes it, so that the user
     *   can read any final messages displayed when the game program
     *   terminated. 
     */
    osnet_disconnect_webui(FALSE);

    /* shut down the network layer, if applicable */
    os_net_cleanup();
#endif

    /* remove the OS break handler */
    os_instbrk(0);

    /* uninitialize the OS layer */
    os_uninit();

    /* delete the host interface object */
    delete hostifc;

    /* show any unfreed memory */
    t3_list_memory_blocks(0);

    /* exit with status code */
    os_term(stat);

    /* we shouldn't get here, but in case os_term doesn't really exit... */
    AFTER_OS_TERM(return stat;)
}
Example #7
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);
}
Example #8
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;
}
int main(int argc, char **argv)
{
    osfildef *fpin;
    osfildef *fpout;
    CVmFile *file_in;
    CVmFile *file_out;
    int status;
    CVmHostIfc *hostifc;
    CVmMainClientConsole clientifc;
    int curarg;

    /* initialize for testing */
    test_init();

    /* initialize the error stack */
    err_init(1024);
    
    /* start at the first argument */
    curarg = 1;

    /* check usage */
    if (curarg + 2 > argc)
    {
        printf("usage: t3pre <original-image> <new-image> [program-args]\n"
               "\n"
               "Runs preinitialization on the image file, writing a new "
               "image file\n"
               "with the state of the program after preinitialization.\n");
        return OSEXFAIL;
    }

    /* open the files */
    if ((fpin = osfoprb(argv[curarg], OSFTT3IMG)) == 0)
    {
        printf("Error opening original image file \"%s\"\n", argv[1]);
        return OSEXFAIL;
    }

    if ((fpout = osfopwb(argv[curarg + 1], OSFTT3IMG)) == 0)
    {
        printf("Error opening new image file \"%s\"\n", argv[2]);
        return OSEXFAIL;
    }

    /* create the CVmFile objects */
    file_in = new CVmFile();
    file_in->set_file(fpin, 0);
    file_out = new CVmFile();
    file_out->set_file(fpout, 0);

    /* create our host interface */
    hostifc = new CVmHostIfcStdio(argv[0]);

    /* run preinit and write the new image file */
    err_try
    {
        /* load, run, and write */
        vm_run_preinit(file_in, argv[1], file_out, hostifc, &clientifc,
                       argv + curarg + 1, argc - curarg - 1, 0);
        
        /* note the success status */
        status = OSEXSUCC;
    }
    err_catch(exc)
    {
        const char *msg;
        char buf[128];

        /* look up the message */
        msg = err_get_msg(vm_messages, vm_message_count,
                          exc->get_error_code(), FALSE);

        /* if that failed, just show the error number */
        if (msg == 0)
        {
            sprintf(buf, "[no message: code %d]", exc->get_error_code());
            msg = buf;
        }

        /* show the message */
        printf("VM Error: %s\n", msg);

        /* note the failure status */
        status = OSEXFAIL;
    }
    err_end;

    /* delete the file objects, which will close the files */
    delete file_in;
    delete file_out;

    /* terminate the error mechanism */
    err_terminate();

    /* delete our host interface object */
    delete hostifc;

    /* log any memory leaks */
    t3_list_memory_blocks(0);

    /* exit with appropriate results */
    return status;
}
Example #10
0
/*
 *   Main program entrypoint.  This is meant to be replaced by the actual
 *   host application.
 *
 *   Don't worry if you're using an OS that uses something other than the
 *   standard Unix-style "main()" as its entrypoint - you're going to remove
 *   this entire file anyway and replace it with your own, so you can use
 *   whatever style of OS entrypoint is appropriate.  The only reason this
 *   is here is to serve as an example of how you invoke the T3 VM to get
 *   your compiled T3 program running in the first place.
 *
 *   Note also that you don't have to call the VM directly from your
 *   entrypoint function.  We call the VM from main() only because we have
 *   nothing else useful to do.  You can do as much as you want to set up
 *   your program or even run interactively for a while before calling the
 *   VM to run the T3 program.
 */
int main(int argc, char **argv)
{
    int stat;
    int load_from_exe;
    const char *image_file_name;

    /*
     *   For our purposes, we will assume that our argument vector contains
     *   only one argument, which is the name of the program to run.  If the
     *   arguments don't look right, terminate with an error.
     */
    if (argc != 2)
    {
        printf("usage: t3core <program-name>\n");
        exit(1);
    }

    /*
     *   The image (.t3) file's name is given by the first argument.
     *
     *   Some applications might want to bind the .t3 file directly into the
     *   application's executable file (the .exe file on Windows, for
     *   example) rather than loading a separate .t3 file.  Fortunately,
     *   this is easy.  Two steps are required.
     *
     *   1.  After building the application executable and compiling the T3
     *   program to yield a .t3 file, use the appropriate OS-specific TADS
     *   tool to bind two together into a single executable file.  On
     *   DOS/Windows, this tool is 'maketrx32' - simply specify the name of
     *   your application executable, the name of your .t3 file, and the
     *   name of a new executable, and the tool will generate a new
     *   executable that has both files bound together.
     *
     *   2.  In our call to vm_run_image(), rather than passing the name of
     *   a .t3 file to laod, we'd pass the name of the application
     *   executable file itself (this is simply argv[0] with our unix-style
     *   main(), but on other systems we might have to obtain this
     *   information some other way), and we'd pass TRUE for the
     *   'load_from_exe' argument to vm_run_image().  This will make the VM
     *   look for the .t3 file bound into the application executable using
     *   an appropriate OS-specific mechanism.
     */
    image_file_name = argv[1];
    load_from_exe = FALSE;

    /*
     *   Create the "host interface."  For our purposes, we use the simple
     *   "stdio" host interface implementation, which the T3 source code
     *   provides for convenience.  The host interface lets the main
     *   application (the "host") communicate certain information about the
     *   execution environment to the VM, and carries out certain tasks on
     *   behalf of the VM; the purpose of this is to allow the VM adapt more
     *   easily to different application environments by deferring certain
     *   operations to the host application, so that the VM doesn't have to
     *   make assumptions about the host environment that might not always
     *   be true.
     *
     *   Most real applications will not want to use the simple "stdio" host
     *   interface implementation, because this standard implementation does
     *   make lots of assumptions about the host environment that might not
     *   always be true.  That's why we have to create the object here - the
     *   VM can't create it, because it can't know what kind of object we'd
     *   want to use.
     *
     *   If you do want to customize the host interface, you'll need to
     *   implement a C++ class as a subclass of CVmHostIfc - see vmhost.h.
     *   You'll need to provide an implementation for each method defined in
     *   CVmHostIfc.
     *
     *   Note that we use "new" to allocate this object, rather than
     *   allocating it on the stack, because of a logistical detail:
     *   CVmHostIfcStdio actually allocates some memory upon creating an
     *   instance, which it frees when the CVmHostIfcStdio instance itself
     *   is destroyed.  If we allocated this instance on the stack, the
     *   instance wouldn't be destroyed until this function returns.
     *   However, we want to run a memory leak test (by calling
     *   t3_list_memory_blocks(), below) before we return from the function.
     *   If we allocated this object on the stack, it wouldn't be deleted
     *   until after we return, and so the memory it allocates won't be
     *   deleted until after we return, so our memory test would show those
     *   blocks still allocated and warn of a memory leak.  We deal with
     *   this by explicitly allocating it with 'new' here so that we can
     *   explicitly destroy it with 'delete' before running the memory
     *   check.
     */
    CVmHostIfc *hostifc = new CVmHostIfcStdio(argv[0]);

    /*
     *   Create the "client interface" object.  This is similar in purpose
     *   to the host interface; this is defined as a separate interface
     *   because it provides functionality that is somewhat orthogonal to
     *   the host interface, so in some cases we might want to mix and match
     *   different pairs of client and host interface implementations.  For
     *   example, HTML TADS uses its own custom host interface, and most
     *   character-mode TADS interpreters use the "stdio" host interface,
     *   but both types of interpreters use the same "console" client
     *   interface implementation.
     *
     *   There's only one standard system client interface implementation,
     *   which is based on the system "console."  The console is the TADS
     *   output formatter subsystem.  We do NOT use this standard
     *   implementation, because we don't want to depend on the console
     *   layer: the whole point of this core VM configuration is to provide
     *   a version of the VM without any UI dependencies, and including the
     *   console formatter introduces all kinds of dependencies.
     *
     *   So, we define our own custom implementation of the client
     *   interface.  See the definition earlier in the file.
     */
    MyClientIfc clientifc;

    /*
     *   Load and run the image file.  This is how we run the T3 program:
     *   this loads the program, sets everything up in the VM, and executes
     *   the program.  This call doesn't return until the program terminates.
     *
     *   If your application runs on an event-oriented operating system,
     *   such as Windows or Macintosh, you might be wondering at this point
     *   exactly where you're supposed to put your message loop if the T3
     *   program is going to hog the CPU from now until the program
     *   terminates.  There are several approaches you can use:
     *
     *   1.  You can use a separate thread to run the T3 program, and run
     *   the UI event loop in the main thread.  To do this, rather than
     *   calling the VM directly here, you'd intead spawn another thread,
     *   and let that thread call the VM.  So, the VM would run in that new
     *   thread, leaving the main thread free to proces UI events.  This
     *   would require proper synchronization any time one of your intrinsic
     *   functions needs to access UI features, but otherwise it would be
     *   pretty simple, because the VM is otherwise fairly self-contained.
     *
     *   2.  You can write the event loop in the T3 program itself (i.e., in
     *   the interpreted code running under the VM).  You would have to
     *   write an intrinsic function to retrieve and dispatch events.  This
     *   approach would probably be a lot of work, because it would mean
     *   that you'd have to provide access to a fair chunk of your OS's GUI
     *   API in your intrinsic function set or sets.  In all likelihood,
     *   you've already implemented most or all of your UI in the C++ part
     *   of your application, and you won't have any desire to provide broad
     *   access to the low-level OS GUI API directly to the T3 program, so
     *   this option is probably not suitable in most cases.
     *
     *   3.  You can do what HTML TADS does, which is run everything in one
     *   thread, and run *recursive* event loops in the intrinsic functions.
     *   In HTML TADS, the T3 program runs happily along, oblivious to the
     *   UI, until it wants to read some text from the keyboard or display
     *   some text on the console, at which point it has to call an
     *   intrinsic function.  The intrinsic makes the appropriate OS-level
     *   API calls to display the text or whatever.  If the intrinsic's
     *   purpose is to read some input from the user, HTML TADS runs a
     *   recursive event loop to allow the user to interact with the
     *   program.  The recursive event loop monitors a flag, controlled by
     *   the intrinsic, that indicates when the recursive loop is done.  For
     *   example, if the intrinsic's purpose is to wait for a keystroke from
     *   the user, the intrinsic tells the main window that it's waiting for
     *   a key, then calls the recursive event loop; the event loop simply
     *   reads and dispatches events as long as the "done" flag is false;
     *   and the main window, when it receives a keystroke event, notices
     *   that it's waiting for a key, so it stashes the keystroke for
     *   retrieval by the intrinsic and sets the "done" flag to true; the
     *   recursive event loop notices this and returns to the intrinsic,
     *   which finds the keystroke it wanted stashed away, and returns.
     */
    stat = vm_run_image(&clientifc, image_file_name, hostifc, 0, 0,
                        0, FALSE, 0, 0, load_from_exe, FALSE, 0, 0, 0, 0);

    /* we're done with the host interface object, so delete it */
    delete hostifc;

    /*
     *   Show any unfreed memory.  This is purely for debugging purposes
     *   during development of T3 itself; most real applications that link
     *   in T3 won't want to bother with this, unless they're suspicious
     *   that T3 is leaking memory on them and want to check it.
     */
    t3_list_memory_blocks(0);

    /* terminate with the status code from the VM */
    exit(stat);
}
Example #11
0
/*
 *   Main program entrypoint 
 */
int main(int argc, char **argv)
{
    int curarg;
    int create;
    int recurse = TRUE;
    const char *image_fname;
    CRcResList *res_list = 0;
    rcmain_res_op_mode_t op_mode;
    int exit_stat;
    int err;
    MyHostIfc hostifc;
    char image_buf[OSFNMAX];

    /* assume we will operate on an existing file */
    create = FALSE;

    /* start out in add-recursive mode */
    op_mode = RCMAIN_RES_OP_MODE_ADD;

    /* scan options */
    for (curarg = 1 ; curarg < argc && argv[curarg][0] == '-' ; ++curarg)
    {
        switch(argv[curarg][1])
        {
        case 'c':
            if (strcmp(argv[curarg], "-create") == 0)
                create = TRUE;
            else
                goto bad_option;
            break;
            
        default:
        bad_option:
            /* invalid option - skip all arguments so we go to usage */
            curarg = argc;
            break;
        }
    }

    /* if there's nothing left, show usage */
    if (curarg >= argc)
    {
    show_usage:
        /* display usage */
        printf("usage: t3res [options] <image-file> [operations]\n"
               "Options:\n"
               "  -create      - create a new resource file\n"
               "Operations:\n"
               "  -add         - add the following resource files (default)\n"
               "  -recurse     - recursive - include files in "
               "subdirectories (default)\n"
               "  -norecurse   - do not include files in subdirectories\n"
               "  <file>       - add the file\n"
               "  <dir>        - add files in the directory\n"
               "  <file>=<res> - add file, using <res> as resource name\n"
               "\n"
               "-add is assumed if no conflicting option is specified.\n"
               "If no resource name is explicitly provided for a file, "
               "the resource is named\n"
               "by converting the filename to a URL-style resource name.\n");

        /* give up */
        exit_stat = OSEXFAIL;
        goto done;
    }

    /* get the image filename */
    image_fname = argv[curarg];

    /* create our resource list */
    res_list = new CRcResList();

    /* parse the operations list */
    for (++curarg ; curarg < argc ; ++curarg)
    {
        /* check for an option */
        if (argv[curarg][0] == '-')
        {
            /* see what we have */
            if (strcmp(argv[curarg], "-add"))
            {
                /* set 'add' mode */
                op_mode = RCMAIN_RES_OP_MODE_ADD;
            }
            else if (strcmp(argv[curarg], "-recurse"))
            {
                /* set recursive mode */
                recurse = TRUE;
            }
            else if (strcmp(argv[curarg], "-norecurse"))
            {
                /* set non-recursive mode */
                recurse = FALSE;
            }
            else
            {
                /* invalid option */
                goto show_usage;
            }
        }
        else
        {
            char *p;
            char *alias;
            
            /* check for an alias */
            for (p = argv[curarg] ; *p != '\0' && *p != '=' ; ++p) ;
            if (*p == '=')
            {
                /* 
                 *   overwrite the '=' with a null byte so that the
                 *   filename ends here 
                 */
                *p = '\0';

                /* the alias starts after the '=' */
                alias = p + 1;
            }
            else
            {
                /* there's no alias */
                alias = 0;
            }
            
            /* it's a file - add the file to the operations list */
            res_list->add_file(argv[curarg], alias, recurse);
        }
    }

    /* 
     *   if we're not creating, and the image doesn't exist, try adding
     *   the default image file extension 
     */
    if (!create && osfacc(image_fname))
    {
        strcpy(image_buf, image_fname);
        os_defext(image_buf, "t3");                       /* formerly "t3x" */
        image_fname = image_buf;
    }

    /* we've parsed the arguments - go apply the operations list */
    err = CResCompMain::add_resources(image_fname, res_list,
                                      &hostifc, create, OSFTT3IMG, FALSE);

    /* set the appropriate exit status */
    exit_stat = (err ? OSEXFAIL : OSEXSUCC);

done:
    /* delete the resource list if we created one */
    if (res_list != 0)
        delete res_list;
    
    /* show any unfreed memory (if we're in a debug build) */
    t3_list_memory_blocks(0);

    /* exit with current status */
    return exit_stat;
}