C++ 为C语言的一个子集实现基于堆栈的虚拟机

C++ 为C语言的一个子集实现基于堆栈的虚拟机,c++,interpreter,vm-implementation,C++,Interpreter,Vm Implementation,大家好,我目前正在实现一种简单的编程语言,以获得学习经验,但我需要一些建议。目前我正在设计我的解释器,我遇到了一个问题 我的语言是C语言的一个子集,关于堆栈解释器的实现,我遇到了一个问题。将使用以下语言编译: somefunc () { 1 + 2; } main () { somefunc (); } 现在这没问题,但是当计算“1+2”时,结果被推到堆栈上,然后函数返回,但是堆栈上仍然有一个数字,不应该有。我怎样才能避开这个问题 我考虑过在函数调用之前保存堆栈的“状态”,并

大家好,我目前正在实现一种简单的编程语言,以获得学习经验,但我需要一些建议。目前我正在设计我的解释器,我遇到了一个问题

我的语言是C语言的一个子集,关于堆栈解释器的实现,我遇到了一个问题。将使用以下语言编译:

somefunc ()
{
    1 + 2;
}

main ()
{
    somefunc ();
}
现在这没问题,但是当计算“1+2”时,结果被推到堆栈上,然后函数返回,但是堆栈上仍然有一个数字,不应该有。我怎样才能避开这个问题

我考虑过在函数调用之前保存堆栈的“状态”,并在函数调用之后恢复“状态”。例如,保存堆栈上的元素数量,然后执行函数代码,返回,然后从堆栈中弹出,直到元素数量与之前相同(或者如果函数返回了某些内容,则可能为+1)


有什么想法吗?谢谢你的提示

您需要一个更智能的解析器。当你看到一个表达式的值没有被使用时,你需要发出一个弹出声。

好问题!我的一个爱好是为玩具语言编写编译器,所以我很欣赏你出色的编程品味

表达式语句是语句中的代码仅为表达式的语句。这意味着任何形式的
,包括赋值和函数调用等内容,但不包括
if
s、
while
s或
return
s。任何表达式语句的末尾都会在堆栈上有一个剩余值,您应该放弃该值

1+2
是一个表达式语句,但它们也是:

  • x=5
    赋值表达式在堆栈上保留值5,因为赋值的结果是左侧操作数的值。语句完成后,弹出未使用的值5

  • printf(“你好,世界!\n”)
    printf()返回输出的字符数。您将在堆栈上保留此值,因此在语句结束时将其弹出


实际上,每个表达式语句都会在堆栈上留下一个值,除非表达式的类型是
void
。在这种情况下,您可以使用特殊的case
void
语句,然后不弹出任何内容,或者将一个假装的“void”值推到堆栈上,这样您就可以始终弹出一个值。

这是学习优化的一个重要机会。你有一个做数字但做整数运算的函数,整数运算结果甚至不以任何方式、形状或形式使用


让编译器优化函数会减少大量字节码的生成和执行

你好,谢谢你的回答。我仍处于编写编译器的初级阶段,我曾考虑过这样做优化,但未能找到一个可行的解决方案:(也许我会再试一次,再次感谢!!你的名字很有趣,因为在我的AST表示中,我有一个名为“ASTStmtExpr”的节点就为了这个!我想我开始明白了,有点…我不确定的是:由于这些评论回复的局限性,我必须粘贴一个snipplet:void编译器::visit(const ASTStmtExpr&expr_stmt,std::shared_ptr func){expr_stmt.expr()->accept(*this,func);}你是说我应该在这之后加一个OP_POP,对于像作业这样的事情,我会推一个虚拟的“Nil”对象,这样它就会弹出?对于赋值否,您不会推送一个伪值,因为赋值的结果已经在堆栈上。赋值只是一个使用
=
运算符的表达式,它与
+
-
没有什么不同,除了
=
具有赋值给变量的副作用可启用。否则它的行为与所有其他运算符一样。
void
表达式类似于调用返回
void
的函数。例如:
abort()
。但是,这可能只是一个学术上的考虑。您的示例代码没有列出函数返回类型,所以这对您来说可能不是问题。是的,这对我来说不是问题,因为我的语言没有类型,甚至原语在我的语言中都是“对象”,所以我认为这不会是问题。感谢您的回复!