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

7

我在这里谈论的是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++编写的实验性玩具解释器的这个问题?

你是在询问通用解释器使用的策略吗?特别是C/C++解释器如何做到这一点?还是当C/C++编译时如何实现这一点? - MtnViewMark
  • 解释器如何解决这个问题?
  • 我如何为自己的实验性玩具解释器解决这个问题?
- sub
4个回答

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 */

这很尴尬,但我不知道您可以将函数存储在数组中,这当然改变了一切;D - sub
1
一个注意事项:很多语言并不会为每个调用执行这个操作。通常,它们会在解析期间进行查找,并立即将所有函数名转换为函数指针。有些甚至会在运行时生成CALL汇编指令,这意味着它们的函数可以像任何其他本地函数一样被调用,并且只调用库例程。 - uliwitness
@uliwitness,说得好。是的,一般来说,编程语言会执行像你提到的那些优化。 - Nick Dandoulakis

2

解释器可能只是将函数名称与函数定义(包括参数信息、返回类型、函数位置/定义等)的哈希表保持一致。这样,当解释器遇到一个函数名称时,可以在哈希表中搜索该函数。如果存在,则使用哈希表中的函数信息来评估它。

显然,您需要添加不同级别范围的规定等,但这就是要点。


1
几乎所有编译器都有一个“符号表”,用于查找标识符表示的内容。符号表将保存函数名称、变量名称、类型名称等等...任何具有名称的东西都会放入符号表中,这基本上是一个名称映射到编译器了解该名称的所有内容的地图(我在这里简化了一下)。然后,当编译器遇到标识符时,它会在符号表中查找,并发现它是一个函数。如果您正在使用解释器,则符号表将包含有关如何查找函数并继续解释的信息。如果这是一个编译器,则符号表将具有该函数在编译代码中的地址(或填充地址的占位符)。然后可以生成汇编代码,其实就是说:将参数放在堆栈上,并在某个地址处恢复执行。
因此,对于您的示例,解释器将查看
substr( $str, 5, 10 );

在它的符号表中查找"substr":
symbolTableEntry entry = symbolTable["substr"];

接下来,它将收集$str510作为参数,并查看entry以确定这些参数是否有效。然后,它将在entry中查找跳转到哪个位置,并传递打包好的参数。


0
在C++中,您可能会使用与Nick D类似的机制,但利用其面向对象的能力:
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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接