【问题标题】:How to implement the execution of a language that I am writing?如何实现我正在编写的语言的执行?
【发布时间】:2015-11-16 01:11:37
【问题描述】:

我使用 C# 编写自己的编程语言只是为了好玩。它被称为 SPL。它只有 12 个关键字/命令/指令,仅此而已。我确切地知道每个命令要做什么。这是类图:

这当然还没有结束。但我们的想法是,我们有一个运行时ISplRuntime。命令所做的所有事情都是在运行时完成的。例如,OutputCommand 将ISplRuntime.Current(这只是一个object)中的内容输出到ISplRuntime.Output(这是一个TextWriter)。

到目前为止一切顺利。但是我需要实现IGotoCommand,就像C#中的goto关键字一样。我要做三种goto。但我不知道如何改变程序的流程。

这是我尝试过的想法:

在ISplRuntime 中添加一个名为RunNextCommand() 的方法。在每个命令的Execute() 方法的最后,调用RunNextCommand。但是,如果用户编写了大量的 SPL 代码,堆栈跟踪会越来越大,并导致堆栈溢出。

将委托添加到ISplRuntime。每次命令完成执行时,Invoke() 代表。代理将寻找下一个要执行的命令并在该ICommand 上调用Execute()。但我不确定这是否也会导致堆栈溢出。 会导致堆栈溢出吗?

我仍然不太确定这是否是正确的方法。我只想要一个关于如何做这种事情的一般性答案,因为这是我第一次编写语言。另外请告诉我使用委托是否会导致堆栈溢出。

【问题讨论】:

  • 为什么不将goto操作插入到IL中?
  • 你的程序是一个指令列表。当您执行时,您将在执行每条指令时增加指令列表的索引。 goto 将导致索引跳转,而不是仅仅增加一。
  • 我会鼓励任何编写编程语言的人阅读“The Dragon Book”(en.wikipedia.org/wiki/…)。即使你不是在编写一个成熟的编译器,即使这本书是针对 C 程序员的,你也会通过阅读它学到很多东西。

标签: c# compiler-construction delegates stack-overflow


【解决方案1】:

我使用 C# 编写自己的编程语言只是为了好玩。

太棒了!

在 ISplRuntime 中添加一个名为 RunNextCommand() 的方法。在每个命令的 Execute() 方法结束时,调用 RunNextCommand。

即使在您意识到这样做是堆栈溢出之前,您也应该意识到您对RunNextCommand 的描述并没有像锡上所说的那样。您所描述的内容称为RunRemainderOfProgram。这表明这个设计有问题。

向 ISplRuntime 添加一个委托。每次命令完成执行时,Invoke() 委托。委托将查找下一个要执行的命令并在该 ICommand 上调用 Execute()。但我不确定这是否也会导致堆栈溢出。会不会导致栈溢出?

我不明白为什么会这样。所以这里的想法是 RunNextCommand 作为它的最后一个动作设置一个委托,当被调用时,它会执行下一个命令吗?

你在这里发明的东西叫做延续。指令的延续是“接下来会发生什么?”当前执行点的位置。

我仍然不太确定这是否是正确的方法。我只是想要一个关于如何做这种事情的一般性答案,因为这是我第一次编写语言。

有很多方法可以构建解释器,这基本上就是您在这里所做的。我会继续试验,看看哪些有效,哪些无效。

这可能有助于研究如何在虚拟机和实际机器中解决此问题。在这些机器中,每条指令都有一个与之相关的唯一编号; “goto”包含要运行的下一条指令的编号。有一个称为“指令指针”的特殊变量,它具有当前正在运行的指令的编号。如果当前指令是goto,则IP设置为goto指示的值;如果不是,IP 将递增到下一条指令,依此类推。然后主循环就是“在当前IP查找指令,执行,设置新IP,重复”。

另外请告诉我使用委托是否会导致堆栈溢出。

很难预测我们看不到而您还没有编写的程序的行为。试试看,你会很快发现你是否写了一个无限递归。

祝你好运!

【讨论】:

    【解决方案2】:

    通常,您只需执行一个循环;在循环内,在当前行执行命令,然后对于所有非流控制命令递增当前行。对于 goto,只需将当前行设置为参数。没有堆栈问题,因为流程不是递归的 - 一切都是从指令循环启动的(根据您的类图,它属于运行时)。

    【讨论】:

    • 让我解释一下你的意思,因为我不确定我是否完全理解。你想让我把 goto 命令的 Execute 方法留空。而当客户端代码实现 ISplRuntime 时,需要编写一个循环来执行命令。在循环中,需要检查当前命令是否为goto。如果是,则更改循环索引。我的解释正确吗?
    • 不完全。让我们试试这个:每个命令都有NextCommand 方法。命令分为FlowControlCommand和SimpleCommand。 SimpleCommand 的 NextCommand 将返回当前行 + 1。 goto 的 NextCommand 将返回 goto 指定的行。您的运行时有一个 while 循环,它执行 currentCommand.Execute,然后是 currentLine = currentCommand.NextCommand(currentLine)。我可能误解了您的ISplRuntime 的目的 - 基本上,客户可能在某个地方说myIsplProgram.Run() - 那就是你有一个循环的地方。
    • 好的,我现在明白了!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-15
    • 1970-01-01
    相关资源
    最近更新 更多