使用编程语言管理库和导入
我已经为 C++ 中的一种愚蠢的编程语言创建了一个解释器,并且整个核心结构已经完成(分词器、解析器、解释器,包括符号表、核心函数等)。
现在我在为这个解释器创建和管理函数库时遇到了问题(稍后我将解释我的意思)
所以目前我的核心函数处理程序是可怕:
// Simplified version
myLangResult SystemFunction( name, argc, argv )
{
if ( name == "print" )
{
if( argc < 1 )
{
Error('blah');
}
cout << argv[ 0 ];
} else if ( name == "input" ) {
if( argc < 1 )
{
Error('blah');
}
string res;
getline( cin, res );
SetVariable( argv[ 0 ], res );
} else if ( name == "exit ) {
exit( 0 );
}
现在想想其他的如果复杂度提高了10倍,系统功能增加了25个。无法维护,感觉很糟糕,太可怕了。
所以我想:如何创建某种包含所有函数的库,如果导入它们,则初始化它们自己并将它们的函数添加到正在运行的解释器的符号表中。
然而,这是我真的不知道如何继续下去的一点。
我想要实现的是,例如:我的语言有一个(外部?)字符串库,例如:字符串,并且它是从该语言的程序中导入的,例如:
import string
myString = "abcde"
print string.at( myString, 2 ) # output: c
我的问题:
- 如何将函数库与核心解释器并加载它们?
- 如何将它们的所有函数放入一个列表中,并在需要时将其添加到符号表中?
我想做的事情:
在解释器开始时,由于所有库都是用它编译的,每个函数都会调用类似 RegisterFunction( string namespace, myLangResult (*functionPtr) ); 的东西,它会添加自己到一个列表。当从语言内部调用 import X 时,使用 RegisterFunction 构建的列表将添加到符号表中。
想到的缺点是:
所有库都直接位于解释器核心中,大小会增加,肯定会减慢速度。
I've created an interpreter for a stupid programming language in C++ and the whole core structure is finished (Tokenizer, Parser, Interpreter including Symbol tables, core functions, etc.).
Now I have a problem with creating and managing the function libraries for this interpreter (I'll explain what I mean with that later)
So currently my core function handler is horrible:
// Simplified version
myLangResult SystemFunction( name, argc, argv )
{
if ( name == "print" )
{
if( argc < 1 )
{
Error('blah');
}
cout << argv[ 0 ];
} else if ( name == "input" ) {
if( argc < 1 )
{
Error('blah');
}
string res;
getline( cin, res );
SetVariable( argv[ 0 ], res );
} else if ( name == "exit ) {
exit( 0 );
}
And now think of each else if being 10 times more complicated and there being 25 more system functions. Unmaintainable, feels horrible, is horrible.
So I thought: How to create some sort of libraries that contain all the functions and if they are imported initialize themselves and add their functions to the symbol table of the running interpreter.
However this is the point where I don't really know how to go on.
What I wanted to achieve is that there is e.g.: an (extern?) string library for my language, e.g.: string, and it is imported from within a program in that language, example:
import string
myString = "abcde"
print string.at( myString, 2 ) # output: c
My problems:
- How to separate the function libs from the core interpreter and load them?
- How to get all their functions into a list and add it to the symbol table when needed?
What I was thinking to do:
At the start of the interpreter, as all libraries are compiled with it, every single function calls something like RegisterFunction( string namespace, myLangResult (*functionPtr) );
which adds itself to a list. When import X
is then called from within the language, the list built with RegisterFunction is then added to the symbol table.
Disadvantages that spring to mind:
All libraries are directly in the interpreter core, size grows and it will definitely slow it down.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果你的解释器是作为库实现的,那么它将从其他人的 C++ 代码中调用。他们必须从自己的代码中调用库中的函数才能将函数添加到解释器中,这并不是不合理的。这就是我自己的表情评估器所做的。用户代码中类似这样:
调用者必须提供指向实现函数的指针,以及函数参数的名称和数量。这对于非类型化设置非常有效 - 如果您进行严格类型化,当然还有很多工作要做。
If your interpreter is implemented as a library, it is going to be called from other people's C++ code. It's not unreasonable for them to have to call functions in your library from their own code to add function to the interpreter. That's hat my own expression evaluator does. something like this in user code:
where the caller must supply a pointer to the implementation function, and the name and number of parameters for the function. This works well with an untyped setup - if you do strict typing, there is of course a lot more work to do.
我认为您应该研究
Command
模式。然后,您可以将每个函数实现为Command
并拥有一个将函数名称映射到Command
对象的映射。这还将使您能够从外部库加载其他函数,方法是让每个库都有一个初始化函数,将其函数添加到映射中。
I think that you should look into the
Command
pattern. Then you can implement each function as aCommand
and have a map which map function names toCommand
objects.This will also enable you to load additional functions from an external library by letting each library have an initializer function which adds its functions to the map.
目前还不清楚你的目标是一个功能齐全的编程语言,还是一个玩具,所以我不知道你想在这上面投入多少时间。我怀疑动态库加载会比您需要的复杂得多。您可能需要一个库位置的 PATH 列表,或者您需要注册名称空间 - 这会让您回到现在所在的位置。
一种更简单的方法是保留一个全局符号表以及关联的处理程序。
使用 std::map (或 hash_map)可以比 if/else 构造更快地进行函数查找。让所有函数在符号表中注册自己。
存储在符号表中的“处理程序”可以是简单的对象(或函数指针),并且可以进行自己的参数检查。
我编写了一些代码来执行这个问题中的类的自注册,但这里不一定需要:
从文本存储访问 C++ 函数
It's unclear if you're aiming at a fully functional programming lang, or if this is a toy, so I don't know how much time you want to put into this. I suspect that dynamic library loading will be significantly more complicated than you need. You would likely need a PATH list of libraries locations, or you would need to register namespaces - which puts you back in the same place you are now.
A simpler approach is to keep a global symbol table, with associated handlers.
Use std::map (or hash_map) for a much faster function lookup than your if/else construct. Have all functions register themselves with the symbol table.
The "handlers" stored in the symbol table can be simple objects (or function pointers) and can do their own argument checking.
I wrote some code to perform self-registration for classes in this question, but it's not necessarily needed here:
Accessing C++ Functions From Text storage