script.cpp

Example of creating a script interpreter.

// Copyright (C) 1995-1999 David Sugar, Tycho Softworks.
// Copyright (C) 1999-2005 Open Source Telecom Corp.
// Copyright (C) 2005-2010 David Sugar, Tycho Softworks.
//
// This file is part of GNU uCommon C++.
//
// GNU uCommon C++ is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// GNU uCommon C++ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GNU uCommon C++.  If not, see <http://www.gnu.org/licenses/>.

#include <config.h>
#include <ucommon/script.h>

using namespace UCOMMON_NAMESPACE;

static unsigned checks = 0;
static unsigned exchecks = 0;
static unsigned refchecks = 0;
static unsigned mainchecks = 0;
static unsigned debugcount = 0;
static unsigned printcount = 0;
static unsigned eventchecks = 0;
static unsigned loopingchecks = 0;
static unsigned manipchecks = 0;

class debug
{
public:
    debug();

    const char *flag;

    virtual void print(void);
};

class testing : public debug, public script::interp
{
public:
    bool scrCheck(void);
    bool scrCheckExit(void);
    bool scrCheckMain(void);
    bool scrCheckEvent(void);
    bool scrCheckLoop(void);
    bool scrCheckRefs(void);
    bool scrArgs(void);
    bool scrSleep(void);
    bool scrCheckManip(void);
};

debug::debug()
{
    ++debugcount;
    flag = NULL;
}

void debug::print(void)
{
    if(flag)
        printf("%s", flag);
    else
        ++printcount;
}

bool testing::scrCheckManip(void)
{
    ++manipchecks;
    skip();
    return true;
}

bool testing::scrCheckEvent(void)
{
    ++eventchecks;
    skip();
    return true;
}

bool testing::scrCheckRefs(void)
{
    ++refchecks;
    skip();
    return true;
}

bool testing::scrCheckMain(void)
{
    ++mainchecks;
    debug::print();
    if(scriptEvent("event"))
        return false;
    skip();
    return true;
}

bool testing::scrCheckLoop(void)
{
    ++loopingchecks;
    skip();
    return true;
}


bool testing::scrCheckExit(void)
{
    ++exchecks;
    skip();
    return true;
}

bool testing::scrCheck(void)
{
    ++checks;
    skip();
    return true;
}

bool testing::scrArgs(void)
{
    unsigned index = 0;
    script::line_t *line = stack[frame].line;

    while(index < line->argc) {
        const char *cp = getContent(line->argv[index]);
        printf(" ARG %d %s <%s>\n", index, line->argv[index], cp);
        ++index;
    }
    skip();
    return false;
}

bool testing::scrSleep(void)
{
    Thread::sleep(500);
    skip();
    return true;
}

int main(int argc, char **argv)
{
    testing interp;
    unsigned errors;

    static script::keyword_t keywords[] = {
        {"check", (script::method_t)&testing::scrCheck, &script::checks::chkNop},
        {"check.exit", (script::method_t)&testing::scrCheckExit, &script::checks::chkNop},
        {"check.main", (script::method_t)&testing::scrCheckMain, &script::checks::chkNop},
        {"check.event", (script::method_t)&testing::scrCheckEvent, &script::checks::chkNop},
        {"check.loop", (script::method_t)&testing::scrCheckLoop, &script::checks::chkNop},
        {"check.refs", (script::method_t)&testing::scrCheckRefs, &script::checks::chkNop},
        {"check.manip", (script::method_t)&testing::scrCheckManip, &script::checks::chkNop},
        {"ignore", (script::method_t)&script::methods::scrNop, &script::checks::chkIgnore}, 
        {"args", (script::method_t)&testing::scrArgs, &script::checks::chkIgnore},
        {"sleep", (script::method_t)&testing::scrSleep, &script::checks::chkNop},
        {NULL}};

    const char *filename = "testscript.scr";
    const char *mergename = "mergescript.scr";

    if(argc > 3) {
        fprintf(stderr, "use: testscript [scrname]\n");
        exit(-1);
    }

    if(argc == 2) {
        mergename = NULL;
        filename = argv[1];
    }

    script::init();
    script::assign(keywords);

    script *image;

    if(mergename) {
        image = script::compile(mergename);
        image = script::append(image, filename);
    }
    else
        image = script::compile(filename);

    if(!image) {
        fprintf(stderr, "*** failed to load %s\n", filename);
        exit(-1);
    }

    errors = image->getErrors();
    if(errors) {
        fprintf(stderr, "*** %d total errors in %s\n", errors, filename);
        linked_pointer<script::error> ep = image->getListing();
        while(is(ep)) {
            fprintf(stderr, "*** %s(%d): %s\n", image->getFilename(), ep->errline, ep->errmsg);
            ep.next();
        }
        delete image;
        exit(-1);
    }   

    interp.initialize();

    if(!interp.attach(image)) {
        fprintf(stderr, "*** no main section in %s\n", filename);
        exit(-1);
    } 
    while(interp.step()) {
        Thread::yield();
    }
    interp.detach();

    if(argc < 2) {
        // enter correct generic number of "checks"
        assert(checks == 3);

        // enter validation of defined call by ref
        assert(refchecks == 1);

        // @exit handler called, and only once...
        assert(exchecks == 1);

        // @main handler called
        assert(mainchecks == 1);

        // @main ^event handler called
        assert(eventchecks == 1);

        // check looping operation
        assert(loopingchecks == 3);

        // in multiple inheritence base class initialized successfully
        assert(debugcount == 1);

        // in  multiple inheritence, method call this* has combined class
        assert(printcount == 1);

        // check manipulations
        assert(manipchecks == 8);
    }

    exit(0);
}

Generated by  doxygen 1.6.2-20100208