我编写了一个实验函数赋值器,它允许我将简单函数绑定在一起,这样当变量发生变化时,所有依赖于这些变量的函数(以及依赖这些函数的函数等)都会同时更新.我这样做的方式是不是在输入时立即评估函数,而是存储函数.只有在请求输出值时才评估函数,并且每次请求输出值时都会对其进行评估.
例如:
pi = 3.14159 rad = 5 area = pi * rad * rad perim = 2 * pi * rad
我将'pi'和'rad'定义为变量(嗯,返回常量的函数),'area'和'perim'作为函数.无论何时'pi'或'rad'发生变化,我都希望'area'和'perim'的结果会有所改变.同样,如果有任何函数取决于'area'或'perim',那么这些函数的结果也会改变.
这一切都按预期工作.这里的问题是当用户引入递归时 - 无论是偶然的还是有意的.我的语法中没有逻辑 - 它只是一个评估者 - 所以我无法为用户提供一种"突破"递归的方法.我想要防止它发生,这意味着我需要一种方法来检测它并将有问题的输入声明为无效.
例如:
a = b b = c c = a
现在评估最后一行导致StackOverflowException(前两行评估为'0' - 未声明的变量/函数等于0).我想做的是检测循环逻辑情况并禁止用户输入这样的语句.无论循环逻辑隐藏得多深,我都希望这样做,但我不知道如何去做.
顺便提一下,在幕后,输入字符串通过简单的扫描仪转换为标记,然后通过手写的递归下降解析器转换为抽象语法树,然后评估AST.语言是C#,但我不是在寻找代码解决方案 - 仅逻辑就可以了.
注意:这是我用来了解解析器和编译器如何工作的个人项目,因此它不是关键任务 - 但是我从中获取的知识确实计划在某个时刻投入现实生活.你们可以提供的任何帮助都将受到极大的赞赏.=)
编辑:如果有人好奇,我的博客上的这篇文章描述了我为什么要学习这个,以及我从中得到的东西.
我过去也遇到过类似的问题.我的解决方案是将变量名称推送到堆栈,因为我通过表达式递归来检查语法,并在我退出递归级别时弹出它们.
在我将每个变量名称推送到堆栈之前,我会检查它是否已经存在.如果是,那么这是一个循环引用.我甚至能够在循环引用链中显示变量的名称(因为它们将在堆栈中,并且可以按顺序弹出,直到我到达有问题的名称).
编辑:当然,这是针对单个公式...对于您的问题,变量赋值的循环图将是更好的方法.