如何用C和C ++编写的解释器将标识符绑定到C(++)函数

时间:2010-03-30 18:50:27

标签: c++ interpreter

我在这里谈的是C和/或C ++,因为这是我所知道的唯一用于解释器的语言,其中以下可能是一个问题:

如果我们有一个解释型语言X,为它编写的库如何为该语言添加函数,然后可以从用该语言编写的程序中调用它?

PHP示例:

substr( $str, 5, 10 );
  • 如何将函数substr添加到PHP的“函数池”中,以便可以从脚本中调用它?

PHP很容易将所有已注册的函数名称存储在一个数组中,并在脚本中调用函数进行搜索。但是,由于C(++)中显然没有eval,那么如何调用该函数呢?我假设PHP没有100MB的代码,如:

if( identifier == "substr" )
{
   return PHP_SUBSTR(...);
} else if( ... ) {
   ...
}
哈哈,那会非常有趣。我希望你到目前为止理解我的问题。

  • 用C / C ++编写的口译员如何解决这个问题?
  • 如何为我自己用C ++编写的实验性玩具解释器解决这个问题?

4 个答案:

答案 0 :(得分:7)

实际上脚本语言会像你提到的那样做 它们包装函数,并将这些函数注册到解释器引擎。

Lua示例:

static int io_read (lua_State *L) {
  return g_read(L, getiofile(L, IO_INPUT), 1);
}


static int f_read (lua_State *L) {
  return g_read(L, tofile(L), 2);
}
...
static const luaL_Reg flib[] = {
  {"close", io_close},
  {"flush", f_flush},
  {"lines", f_lines},
  {"read", f_read},
  {"seek", f_seek},
  {"setvbuf", f_setvbuf},
  {"write", f_write},
  {"__gc", io_gc},
  {"__tostring", io_tostring},
  {NULL, NULL}
};
...
luaL_register(L, NULL, flib);  /* file methods */

答案 1 :(得分:2)

解释器可能只是将函数名称的哈希映射保存到函数定义中(其中包括参数信息,返回类型,函数位置/定义等)。这样,您只需在哈希映射上搜索函数名称(当你的口译员遇到一个)。如果存在,请使用哈希表中的函数info来评估它。

你显然需要为不同级别的范围等添加条款,但这就是它的要点。

答案 2 :(得分:1)

几乎所有编译器都有一个“符号表”,用于查找标识符所代表的内容。符号表将包含函数名称,变量名称,类型名称等...任何具有名称的东西都在符号表中,这基本上是编译器知道该名称的所有内容的名称映射(我在这里简化) )。然后,当编译器遇到标识符时,它会在符号表中查找它,并发现它是一个函数。如果您正在使用解释器,则符号表将包含有关在何处查找函数和继续解释的信息。如果这是一个编译器,则符号表将具有该函数在编译代码中的位置的地址(或稍后填充地址的占位符)。然后可以生成程序集,基本上说:将参数放在堆栈上,并在某个地址恢复执行。

所以,对于你的例子,翻译会查看

substr( $str, 5, 10 );

并在其符号表中找到“substr”:

symbolTableEntry entry = symbolTable["substr"];

从那里开始,它会收集$str510作为参数,并查看entry以查看参数对函数是否有效。然后它会查看entry以查找使用编组参数跳转到的位置。

答案 3 :(得分:0)

在C ++中你可能会使用与Nick D类似的机制,但是利用其OO功能:

typedef luaFunction boost::function<void(*)(lua_State&)>
std::map<std::string, luaFunction > symbolTable;
symbolTable["read"] = f_read;
symbolTable["close"] = f_close; // etc.
// ...
luaFunction& f = symbolTable[*symbolIterator++];
f(currentLuaState);