代码之家  ›  专栏  ›  技术社区  ›  Erik Forbes

如何在自定义表达式计算器中检测循环逻辑或递归?

  •  3
  • Erik Forbes  · 技术社区  · 17 年前

    我已经编写了一个实验函数计算器,它允许我将简单函数绑定在一起,这样当变量发生变化时,依赖这些变量的所有函数(以及依赖这些函数的函数等)都会同时更新。我这样做的方式不是在输入函数时立即计算它,而是存储函数。只有当请求输出值时,我才对函数进行求值,每次请求输出值时,我都会对函数进行求值。

    例如:

    pi = 3.14159
    rad = 5
    area = pi * rad * rad
    perim = 2 * pi * rad
    

    我将'pi'和'rad'定义为变量(返回常数的函数),将'area'和'perim'定义为函数。无论何时‘pi’或‘rad’发生变化,我都希望‘area’和‘perim’的结果会发生同样的变化。同样,如果有任何函数依赖于“区域”或“perim”,那么这些函数的结果也会发生变化。

    例如:

    a = b
    b = c
    c = a
    

    现在计算最后一行会导致StackOverflowException(前两行计算为“0”-未声明的变量/函数等于0)。我想做的是检测循环逻辑情况,并禁止用户输入这样的语句。不管循环逻辑隐藏得有多深,我都想这样做,但我不知道如何去做。

    注意:这是一个我用来学习解析器和编译器如何工作的个人项目,所以它不是任务关键型的-但是我从中获得的知识我确实计划在某个时候投入到实际生活中。如果你们能提供任何帮助,我们将不胜感激。=)

    this post on my blog 描述了我为什么要学习这一点,以及我从中学到了什么。

    3 回复  |  直到 17 年前
        1
  •  6
  •   Andrew Rollings Andrew Rollings    17 年前

    我过去也有过类似的问题。

    在我将每个变量名推到堆栈上之前,我会检查它是否已经存在。 如果是,那么这是一个循环引用。 我甚至能够在循环引用链中显示变量的名称(因为它们将在堆栈上,并且可以按顺序弹出,直到我找到不合适的名称)。

    编辑:当然,这是针对单一公式。。。对于您的问题,变量赋值的循环图是更好的方法。

        2
  •  2
  •   Mankarse    14 年前

    一个解决方案(可能不是最好的)是创建依赖关系图。

    每次添加或更改函数时,都会检查依赖关系图中是否存在循环。

    这是可以缩短的。每次添加或更改函数时,都要对其进行标记。如果评估结果导致调用被标记的函数,则有一个循环。

    例子:

    a = b

    • 评估b(未找到)

    b = c

    • 评估c(未找到)

    c = a

    • c旗
    • 评估a
    • 评估c(已标记)->循环,放弃对c的更改!
    • 解渣c
        3
  •  0
  •   Andrew Rollings    17 年前

    答复对答复二的评论:

    (很抱歉,我的openid创建工作搞砸了,所以我以后必须把旧的东西链接起来……)

    使用堆栈的唯一优点是,无论深度如何,都可以轻松地提供有关循环的详细信息。(对错误消息有用:))

    安得烈