获取在C ++中实例化的TCL-Interpreter中执行代码的行号

时间:2015-03-02 13:28:48

标签: c++ tcl

我使用CPPTCL在我的C ++代码中实例化TCL解释器的实例。然后,我可以使用" pTclInterpreter-> eval(script);"执行脚本。根据需要工作。我还将自己的TCL函数定义为C ++函数,并通过" pTclInterpreter-> def(" getValueCmd",getValueCmd);"使它们可用于TCL脚本。工作正常。

现在,对于我在C ++实现的TCL函数中的消息传递(信息/错误),我需要知道该函数被调用的脚本行。我找到了文章:Getting the line number of executing code in TCL,当我在一个独立的TCL shell中执行TCL-Script时,我按预期收到: 全球 28 proc A. 23 proc B. 18 proc C 13 proc D. 9

但是当我从C ++实例化的TCL解释器中执行相同的脚本时,我会收到: 全球 28 proc A. 3 proc B. 3 proc C 3 proc D. 3

全局调用在第28行是正确的。但对于函数调用,它总是" 3",这似乎是指被调用函数中的第三行 - 而不是完整脚本中的行

这给我留下了两个问题: 1.)如何检测哪些TCL脚本行称为我的C ++函数? 2.)如果TCL脚本的行为在这一点上有所不同 - 我还有什么地方可以期待差异?

在我的C ++代码中。

#include <systemc.h>
#include "cpptcl.h"

sc_event  go;

Tcl::interpreter *pTclInterpreter;

int MOD(std::string module, std::string cmd, int param1, int param2){
    /* 
        Function to simulate the execution of an IFS command.
    */

    /*
        Here we would have the code that creates the proper cmdObj
    */
    std::cout << sc_time_stamp() << ": creatingCmdObj(";
    std::cout << module;
    std::cout << ", " << cmd;
    std::cout << ", " << param1;
    std::cout << ", " << param2;
    std::cout << ")"  << std::endl;

//  pTclInterpreter->eval("puts [ dict get [info frame [info frame -1] ]  line ]");

    return 0;
}

int getValueCmd(){
    /*
        Function to simulate the execution of a getValue
    */
    std::cout << sc_time_stamp() << ": executing getValueCmd." << std::endl;
    std::cout << sc_time_stamp() << ": TCL waiting for all TBMs to catch up." << std::endl;
    wait(go);
    std::cout << sc_time_stamp() << ": TBMs in sync. TCL interpreter to continue." << std::endl;
    return 0;
}

int read_trace(const int& v, void *) {
  cout << "read trace triggered: wait(10, SC_NS)" << endl;
  wait(10, SC_NS);
  return v;
}

SC_MODULE (wait_example) {

  void tclInterpreter() {

    std::cout << sc_time_stamp() << ": Starting TCL interpreter!" << std::endl;

    // new TCL
    pTclInterpreter = new(Tcl::interpreter);

    // register the C++ function to be called from TCL
    pTclInterpreter->def("MOD", MOD);
    pTclInterpreter->def("getValueCmd", getValueCmd);
    // register read trace for variable
    pTclInterpreter->def_read_trace("tracedVar", "read", read_trace);

    // load the script
    // ifstream script("helloworld.tcl");
    ifstream script("test.tcl");

    // run the script with the given arguments
    pTclInterpreter->eval(script);

    cout << sc_time_stamp() << ": Terminating Simulation." << std::endl;
    sc_stop(); // sc_stop triggers end of simulation
  }

  void ifscontroller() {
    wait(100, SC_NS);
    go.notify();
  }

  SC_CTOR(wait_example) {
    SC_THREAD(tclInterpreter);
    SC_THREAD(ifscontroller);
  }
}; 

int sc_main (int argc, char* argv[]) {

  wait_example object("wait");

  sc_start(0, SC_NS); // First time called will init schedular
  sc_start();  // Run the simulation till sc_stop is encountered
  return 0;// Terminate simulation
}

这也使用了SystemC,我相信这里不再重要。如您所见,我创建了一个TCL解释器实例,并使用指针pTclInterpreter引用它。然后我使用&#34; pTclInterpreter-&gt; eval(script);&#34;从引用中执行脚本。但结果与在纯shell中执行此操作不同。

2 个答案:

答案 0 :(得分:0)

您的程序是由source文件创建的吗? (好吧,使用Tcl_EvalFile并且它的关系也可以。)如果没有,它们将没有全局行号,因为此时将没有合适的上下文。实际工作方式非常棘手,因此使用source(或它调用的C API)是迄今为止最简单的方法。

答案 1 :(得分:0)

更改以上行

pTclInterpreter->eval(script);

pTclInterpreter->eval("source test.tcl");

更新: 我根据需要完成了我的演示。我现在能够创建一个TCL解释器并定义可从TCL脚本调用的C ++函数。这些TCL-called-C ++函数现在能够访问TCL-interpreter实例,以确定命名文件调用它们的脚本行。 代码:

#include <systemc.h>
#include "cpptcl.h"

sc_event  go;
Tcl::interpreter *pTclInterpreter;

int MOD(std::string module, std::string cmd, int param1, int param2){
    /*
        Here we would have the code that creates the proper cmdObj and adds it to
        the IFS controller's list of cmdObj. From there the TBMs will receive it
        during their executeNextCommand loop.
    */

    pTclInterpreter->eval("set IFS_scriptLine [dict get [info frame [expr [info frame] -1] ] line]");
    pTclInterpreter->eval("set IFS_scriptName [dict get [info frame [expr [info frame] -1] ] file]");

    std::cout << sc_time_stamp() << "; " << pTclInterpreter->read_variable<std::string>("IFS_scriptName") << "(";
    std::cout << pTclInterpreter->read_variable<int>("IFS_scriptLine") << ")";
    std::cout << ": creatingCmdObj(";
    std::cout << module;
    std::cout << ", " << cmd;
    std::cout << ", " << param1;
    std::cout << ", " << param2;
    std::cout << ")"  << std::endl;

    return 0;
}

int getValueCmd(){

    pTclInterpreter->eval("set IFS_scriptLine [dict get [info frame [expr [info frame] -1] ] line]");
    pTclInterpreter->eval("set IFS_scriptName [dict get [info frame [expr [info frame] -1] ] file]");

    std::cout << sc_time_stamp() << "; " << pTclInterpreter->read_variable<std::string>("IFS_scriptName") << "(";
    std::cout << pTclInterpreter->read_variable<int>("IFS_scriptLine") << ")";
    std::cout << ": executing getValueCmd." << std::endl;
    std::cout << sc_time_stamp() << ": TCL waiting for all TBMs to catch up." << std::endl;
    wait(go);
    std::cout << sc_time_stamp() << ": TBMs in sync. TCL interpreter to continue." << std::endl;
    return 0;
}

int read_trace(const int& v, void *) {
  cout << "read trace triggered: wait(10, SC_NS)" << endl;
  wait(10, SC_NS);
  return v;
}

SC_MODULE (wait_example) {

  void tclInterpreter() {

    std::cout << sc_time_stamp() << ": Starting TCL interpreter!" << std::endl;

    // new TCL
    pTclInterpreter = new(Tcl::interpreter);


    // register the C++ function to be called from TCL
    pTclInterpreter->def("MOD", MOD);
    pTclInterpreter->def("getValueCmd", getValueCmd);
    // register read trace for variable
    pTclInterpreter->def_read_trace("tracedVar", "read", read_trace);

    // run the script with the given arguments
    pTclInterpreter->eval("source helloworld.tcl");

    cout << sc_time_stamp() << ": Terminating Simulation." << std::endl;
    sc_stop(); // sc_stop triggers end of simulation
  }

  void ifscontroller() {
    wait(100, SC_NS);
    go.notify();
  }

  SC_CTOR(wait_example) {
    SC_THREAD(tclInterpreter);
    SC_THREAD(ifscontroller);
  }
}; 

int sc_main (int argc, char* argv[]) {

  wait_example object("wait");

  sc_start(0, SC_NS); // First time called will init schedular
  sc_start();  // Run the simulation till sc_stop is encountered
  return 0;// Terminate simulation
}

执行后的结果:

0 s: Starting TCL interpreter!

             SystemC 2.3.0-ASI --- May 16 2014 17:16:28
        Copyright (c) 1996-2012 by all Contributors,
        ALL RIGHTS RESERVED

"Executing script and creating cmdObj."

0 s; myCppTcl/helloworld.tcl(5): creatingCmdObj(tbm1, userDefined1, 7, 12)
0 s; myCppTcl/helloworld.tcl(6): creatingCmdObj(tbm2, read, 9, 1)
0 s; myCppTcl/helloworld.tcl(8): creatingCmdObj(tbm2, write, 6, 6)
0 s; myCppTcl/helloworld.tcl(9): creatingCmdObj(tbm1, userDefined4, 2, 4)
0 s; myCppTcl/helloworld.tcl(14): executing getValueCmd.
0 s: TCL waiting for all TBMs to catch up.
100 ns: TBMs in sync. TCL interpreter to continue.
100 ns; myCppTcl/helloworld.tcl(19): creatingCmdObj(tbm1, read, 3, 0)
100 ns; myCppTcl/helloworld.tcl(19): creatingCmdObj(tbm1, read, 4, 1)
100 ns; myCppTcl/helloworld.tcl(19): creatingCmdObj(tbm1, read, 5, 2)
100 ns; myCppTcl/helloworld.tcl(19): creatingCmdObj(tbm1, read, 6, 3)
100 ns; myCppTcl/helloworld.tcl(19): creatingCmdObj(tbm1, read, 7, 4)
100 ns; myCppTcl/helloworld.tcl(19): creatingCmdObj(tbm1, read, 8, 5)
read trace triggered: wait(10, SC_NS)
10

read trace triggered: wait(10, SC_NS)
10

read trace triggered: wait(10, SC_NS)
10

read trace triggered: wait(10, SC_NS)
10

read trace triggered: wait(10, SC_NS)
10

read trace triggered: wait(10, SC_NS)
10

160 ns; myCppTcl/testSource.tcl(7): creatingCmdObj(tbm1, userDefined1, 7, 12)
160 ns; myCppTcl/testSource.tcl(4): creatingCmdObj(tbm1, userDefined1, 7, 12)
160 ns: Terminating Simulation.

Info: /OSCI/SystemC: Simulation stopped by user.

使用过的TCL脚本:

puts {"Executing script and creating cmdObj."}

# Regular IFS commands  to be put here.
# Each command creates individual cmdObj
MOD tbm1 userDefined1 [expr 3+4] [expr 4*3]
MOD tbm2 read [expr 3*3] 1
set myVar 6
MOD tbm2 write [expr 12-6] $myVar
MOD tbm1 userDefined4 [expr 20/10] 4

# Need to receive value from IFS. Cannot
# continue executing script.
# getValueCmd makes us wait for TBMs
getValueCmd

# Regular IFS commands  to be put here.
# Each command creates individual cmdObj
for { set i 0 } { $i <= 5 } { incr i } {
  MOD tbm1 read [expr 3+$i] $i
}

set tracedVar 10
# Assuming that tracedVar is an IFS-Signal type var, it is required
# to synchronize the IFS and it's testbench modules. For demonstration
# the read call back for the following command will wait 10 ns.
for { set i 0 } { $i <= 5 } { incr i } {
  puts $tracedVar
}

# Let us see what file name and line numbers are communicated when we use source
source testSource.tcl

下一步

#!/usr/bin/tclsh
proc testProc {} {
        # Execute an IFS command in a procedure to see what file and line info is communicated
        MOD tbm1 userDefined1 [expr 3+4] [expr 4*3]
}

MOD tbm1 userDefined1 [expr 3+4] [expr 4*3]