我正在使用C#编写自己的编程语言,只是为了好玩。它被称为SPL。它只有12个关键字/命令/指令,仅此而已。我确切地知道每个命令将要做什么。这是类图:
当然没有完成。但我们的想法是,我们有一个运行时ISplRuntime
。命令所做的所有事情都是在运行时完成的。例如,OutputCommand
将ISplRuntime.Current
中的内容(仅object
)输出到ISplRuntime.Output
(这是TextWriter
)。
到目前为止一切顺利。但是我需要实现IGotoCommand
,就像C#中的goto
关键字一样。我将制作三种类型的东西。但我无法弄清楚如何改变程序的流程。
以下是我尝试的想法:
在RunNextCommand()
中添加名为ISplRuntime
的方法。在每个命令的Execute()
方法结束时,请致电RunNextCommand
。但是,如果用户编写了大量SPL代码,则堆栈跟踪将变得越来越大,从而导致堆栈溢出。
将代理人添加到ISplRuntime
。每次命令执行完毕,Invoke()
代表。代理将查找要执行的下一个命令,并在Execute()
上调用ICommand
。但我不确定这是否也会导致堆栈溢出。 是否会导致堆栈溢出?
我仍然不确定这是否是正确的方法。我只想要一个关于如何做这种事情的一般答案,因为这是我第一次写一种语言。另请告诉我使用委托是否会导致堆栈溢出。
答案 0 :(得分:7)
我正在使用C#编写自己的编程语言,只是为了好玩。
真棒!
在ISplRuntime中添加一个名为RunNextCommand()的方法。在每个命令的Execute()方法结束时,调用RunNextCommand。
即使在您意识到堆叠溢出之前,您应该意识到您对RunNextCommand
的描述不符合它所说的。您所描述的内容称为RunRemainderOfProgram
。这表明在这个设计中出现了一些问题。
向ISplRuntime添加委托。每次命令执行完毕后,调用()委托。委托将查找要执行的下一个命令,并在该ICommand上调用Execute()。但我不确定这是否也会导致堆栈溢出。它会导致堆栈溢出吗?
我不明白为什么会这样。所以这里的想法是RunNextCommand
作为最后一个动作设置一个委托,当被调用时,它会执行下一个命令吗?
您在此发明的内容称为延续。指令的延续是“接下来会发生什么?”目前的执行点。
我仍然不确定这是否是正确的方法。我只是想要一个关于如何做这种事情的一般答案,因为这是我第一次写一种语言。
有许多方法可以构建一个解释器,这基本上就是你在这里所做的。我会继续尝试,看看哪些有效,哪些无效。
研究如何在虚拟机和实际机器中解决此问题可能会有所帮助。在这些机器中,每个指令都有一个与之相关的唯一编号; “goto”包含要运行的下一条指令的编号。有一个称为“指令指针”的特殊变量,它具有当前运行指令的编号。如果当前指令是goto,则IP被设置为goto指示的值;如果不是,则IP递增到下一条指令,依此类推。然后主循环“查找当前IP的指令,执行它,设置新IP,重复”。
另请告诉我使用委托是否会导致堆栈溢出。
很难预测我们看不到的程序的行为,而你还没有写过。尝试一下,你会很快发现你是否写了一个无限的递归。
祝你好运!答案 1 :(得分:3)
通常,你只需做一个循环;在循环内,在当前行执行命令,然后对所有非流控制命令增加当前行。对于goto,只需将当前行设置为参数即可。没有堆栈问题,因为流不是递归的 - 一切都是从指令循环(在给定类图的情况下属于运行时)中启动的。