我完全同意上面提到的有关创建AST并在每次迭代中对其进行评估的所有答案。这是迄今为止做你想做的最好的(也是最正确的)方式。
但我写了编译器为生,我不禁建议另一个有趣的解决方案。当你说你想创建一个接受1个参数并返回结果的“函数”时,我提出了一个额头。
让我们试着做到这一点。
我们将开始为我们的“功能”分配一些内存。
现在让我们假设4k字节就足够了。 所以我们开始做
void* my_func = malloc(4k);
现在,这是我们需要使该地区执行真正的功能。这将取决于您的操作系统,您将不得不调用正确的系统调用。 您只需将执行权限授予此页面即可。
现在我们解析表示表达式的字符串。 我在这里假设WIN 64 fastcall调用约定。你可以使用你自己的。 所以参数t将在%rcx中,thr的结果将以%rax的形式返回。
现在,让我们的示例表达 - T * 2 + 5
因此,我们将有总成 -
imulq $2, %rcx, %rcx
addq $5, %rcx
movq %rcx, %rax
retq
现在我们组装成等效字节这在my_func,并将
所以你会有一些等效的 -
strcpy((char*)my_func, "\x48\x6B\xC9\x02\x48\x83\xC1\x05\x48\x89\C8\C3\0");
而不是一个字符串哟你将拥有建立在解析的缓冲区。 但你明白了。
如果需要更多内存,您可以分配两倍的大小并复制内容。
最后,所有你所要做的就是打电话给你的内循环“功能” -
typedef int (*func_type)(int);
for(t=0; t
s=(func_type)(my_func)(t);
虽然这是最不切实际,难以实现方法,我向你保证这会给你最好的性能(假设你生成有效的组装)。
这是一个有趣的练习不被重视。很高兴看到一个库为简单的表达式做这件事。
另外不要忘记释放你的记忆并移除执行标志。
编辑:一个半最佳,但容易产生策略将是使用堆栈的所有操作。基本上,一旦解析完成后构建AST,就会从堆栈中弹出每个节点的参数,然后使用寄存器计算结果并将其推回堆栈。最终值可以弹出到%rax中。这个策略对AST的任何运行时间评估都是有效的。 为您节省了所有的寄存器分配和指令调度的负担。