NS2入门教程——Tcl类

这里我们讲解一下~/ tclcl / tclcl.h中封装的OTcl解释器的实际实例,并提供了访问该解释器并与之通信的方法。

Tcl类提供了以下方法:

  1. 获得Tcl对象的引用
  2. 调用OTcl的函数,通过解释器
  3. 向解释器取值或者传值
  4. 报告错误情况并以统一的方式退出
  5. 存储并查找“TclObjects”。
  6. 获得对解释器的直接访问

在下面我们将对每一个方法进行详细讲解:

获得Tcl对象的引用

该类的单个实例在~tclcl / Tcl.cc中声明为静态成员变量;

我们必须获取对此实例的引用才能访问本节中描述的其他方法

访问此实例所需的语句是:

Tcl& tcl = Tcl::instance();

调用OTcl的函数,通过解释器

通过实例tcl调用OTcl命令有四种不同的方法。它们的参数基本不同。

每个函数都将一个字符串传递给解释器,然后在全局上下文中评估字符串的含义。

  • 如果解释器返回TCL_OK,这些方法将返回调用者。
  • 另一方面,如果解释器返回TCL_ERROR,则方法将报tkerror错误。用户可以重载此过程以选择性地忽略某些类型的错误。
void Tcl::evalc(const char* s)
{
    unsigned int n = strlen(s) + 1;
    if (n < sizeof(buffer_) - (bp_ - buffer_)) {
        char* const p = bp_;
        bp_ += n;
        strcpy(p, s);
        eval(p);
        bp_ = p;
    } else {
        char* p = new char[n + 1];
        strcpy(p, s);
        eval(p);
        delete[] p;
    }
}

void Tcl::eval(char* s)
{
    int st = Tcl_GlobalEval(tcl_, s);
    if (st != TCL_OK) {
        int n = strlen(application_) + strlen(s);
        if (n > MAX_CODE_TO_DUMP) {
            s = "\n[code omitted because of length]\n";
            n = strlen(application_) + strlen(s);
        };
        char* wrk = new char[n + 80];
        sprintf(wrk, "tkerror {%s: %s}", application_, s);
        if (Tcl_GlobalEval(tcl_, wrk) != TCL_OK) {
            fprintf(stderr, "%s: tcl error on eval of: %s\n",
                application_, s);
            exit(1);
        }
        delete[] wrk;
        //exit(1);
    }
}

void Tcl::eval()
{
    char* p = bp_;
    bp_ = p + strlen(p) + 1;
    /*XXX*/
    if (bp_ >= &buffer_[1024]) {
        fprintf(stderr, "bailing in Tcl::eval\n");
        assert(0);
        exit(1);
    }
    eval(p);
    bp_ = p;
}

/*
 *  按理说,应该是4个,还有一个evalf,但是在Tcl.cc中我没有找到,
 *  所以暂时作罢,等日后遇到,
 *  再做补充
 */

下面举一些例子来调用这些函数:

Tcl& tcl = Tcl::instance();
char wrk[128];
strcpy(wrk, "Simulator set NumberInterfaces_ 1");
tcl.eval(wrk);

sprintf(tcl.buffer(), "Agent/SRM set requestFunction_ %s", "Fixed");
tcl.eval();

tcl.evalc("puts stdout {hello world}");

tcl.evalf("%s request %d %d", name_, sender, msgid);

向解释器取值或者传值

当解释器调用C ++方法时,它会将结果返回到私有成员变量tcl_->result中。

有两种方法可用于设置此变量。(to)

void result(Tcl_Obj *pObj) { 
    Tcl_SetObjResult(tcl_, pObj); 
}

inline const char* result() const { 
    return (char *) Tcl_GetStringResult(tcl_); 
}

inline char* result() const {
    return (tcl_->result); 
}

inline void result(const char* p) { 
    tcl_->result = (char*)p; 
}

void resultf(const char* fmt, ...);

/*examples*/

if (strcmp(argv[1], "now") == 0) {
    tcl.resultf("%.17g", clock());
    return TCL_OK;
}
tcl.result("Invalid operation specified");
return TCL_ERROR;

同样,当C ++方法调用OTcl命令时,解释器会在tcl_->result中返回结果。(from)

tcl.evalc("Simulator set NumberInterfaces_");
char* ni = tcl.result();
if (atoi(ni) != 1)
    tcl.evalc("Simulator set NumberInterfaces_ 1");

报告错误情况并以统一的方式退出

此方法提供了一种统一的方法来报告编译代码中的错误。

void Tcl::error(const char* s)
{
    if (strlen(s) > MAX_CODE_TO_DUMP) {
        s = "\n[code omitted because of length]\n";
    };
    fprintf(stderr, "%s: \"%s\": %s\n", application_, s, tcl_->result);
    exit(1);
}
/* example */

tcl.resultf("cmd = %s", cmd);
tcl.error("invalid command specified");

注意:调用Tcl::result和Tcl::error有一些细微的区别,就是如果调用result出错,解释器会捕捉到异常,同时给你返回堆栈的追踪,供你调试改正错误,但是如果使用error,是不会返回堆栈的跟踪。

存储并查找TclObjects

NS2在哈希表中存储对编译层次结构中每个TclObject的引用;这允许快速访问对象。

哈希表是解释器的内部。NS2使用TclObject的名称作为键,以在哈希表中输入,查找或删除TclObject。

void Tcl::enter(TclObject* o)
{
    int nw;
    Tcl_HashEntry* he = Tcl_CreateHashEntry(&objs_, (char*)o->name(),
                        (int*)&nw);
    Tcl_SetHashValue(he, (char*)o);
}
/*
 *      insert a pointer to the TclObject into hashtable
 */

TclObject* Tcl::lookup(const char* name)
{
    /*XXX use tcl hash table */
    Tcl_HashEntry* he = Tcl_FindHashEntry(&objs_, (char*)name);
    if (he != 0)
        return ((TclObject*)Tcl_GetHashValue(he));
    return (0);
}
/*
 *      retrieve the TclObject with the name
 */

void Tcl::remove(TclObject* o)
{
    Tcl_HashEntry* he = Tcl_FindHashEntry(&objs_, (char*)o->name());
    if (he == 0)
        abort();

    Tcl_DeleteHashEntry(he);
}
/*
 *      delete references to the TclObject from the hash table
 */

这些函数由类TclObject和类TclClass在内部使用。

获得对解释器的直接访问

如果上面的方法不够,那么我们必须获取解释器的句柄,并编写我们自己的函数。

inline Tcl_Interp* interp() const { return (tcl_); }

/*
 *      returns the handle to the interpreter that is stored within the class Tcl.
 */

你可能感兴趣的:(NS2入门教程——Tcl类)