如何检查语句中的操作类型?

2024-05-29 04:02:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我希望能够检查返回值的类型是否与ANTLR中方法的类型相同。(即int processOperation()应返回类似于int的返回(3-1*4))

我的语法如下:https://github.com/RodrigoZea/Lab00DDC/blob/fda787998e5ed1cc5e5d94e6506ed6ca08dbd955/Decaf/Decaf.g4

我使用的是ANTLR4的python实现,但我不确定如何检查返回语句中的操作类型,例如(1+3*4)应该返回int。我使用的是侦听器,因此我的逻辑如下:

  1. 首先检查值是否为原语(即返回“random”,返回1)
  2. 检查该值是操作还是单个变量

对于单个变量,在符号表中搜索它就足够了,但是对于一个操作,我不确定如何接近它。我读过关于使用ParseTreeProperty的内容<&燃气轮机;但我不认为在Python版本的ANTLR4中有这样的实现,这似乎是我在ANTLR4权威参考中读到的最好的方法,因为它将保存节点(和操作子树)数据类型,我可以轻松检查其类型并将其与我的方法类型进行比较。我猜在输入运算符规则时需要进行检查,但我不确定如何处理这些数据,或者是否有办法在Python中实现ParseTreeProperty。谢谢


Tags: 方法httpsgithubcom类型语法int返回值
2条回答

ParseTreeProperty是将属性“附加”到解析树的节点的一种方便方法,也是跟踪树中每个节点的type的一种有用方法。但是,正如注释所提到的,您可以使用其他数据结构跟踪每个节点的类型并映射回它。(注意:如果您对侦听器使用这种方法,正如您的问题所暗示的那样,您需要在*Exit()方法中实现它,因为您希望所有子级都被“侦听”并分配了它们的类型,以便您可以确定父表达式的类型。)

使用侦听器,您也可以只拥有一个类型堆栈。当您退出每个表达式时,它会弹出其所有子表达式的类型,为自己计算表达式类型,并将该类型推送到堆栈上。当然,您必须注意正确地管理推送和弹出(注意异常),但它可以是一个相当干净的实现

还可以实现表达式类型验证访问者。使用这种方法,您可以编写一个返回其类型的表达式访问者。对于每个被重写的visit*(),您只需在每个子级上调用visit()即可获得它的类型,然后确定您希望得到的类型是什么(甚至可能是一个有效的表达式)。请注意,``visit``通过访问者返回一个结果,这是访问者和侦听器之间的关键区别之一(另一个区别是,对于访问者,您必须明确选择如何导航子节点)

就“如何处理这些数据”而言,在这一点上,您正在做出关于您希望您的语言如何运行、什么是有效的等的设计决策

例如:

7 * "string"

也许您决定7Int类型,“string”是String类型。在乘法表达式的侦听器/访问者中,由您决定这是否是一个错误(结果“type”可能是InvalidType),或者像Ruby一样,这是一种获取“stringstring”的可爱方式,在这种情况下,您将返回一种类型String。对于函数,您需要决定函数的返回类型。您是否要求明确定义它们?必须在引用它们之前定义它们(如果没有,则需要先解析树,创建要引用的函数和返回类型的符号表,然后才能导航树计算表达式类型)。也许,您有一种动态语言,在这种语言中,不同的输入类型(甚至值)可能会导致函数的不同返回类型

显然,这已经深入到了语言设计的选择中,语言对如何处理它们做出了许多不同的决定。ANTLR只是您的解析技术,并且(除了提供方便的类,如侦听器和访问者)对您如何做出这些决定或如何实现它们没有任何说明。而且,没有办法在语法中对它们进行编码,因为它们是语义问题,对解析或解析树的构造没有影响

所以,根据迈克和卡比的回答,我想出了一个解决办法。它非常简单,但功能非常强大。 在Python中复制ParseTreeProperty的最佳方法是创建一个字典,ctx对象将是键,值是手动设置的,这取决于您希望值是什么(Mike的答案就在这里)。要更新字典值,您将在*Exit()方法上执行此操作,正如Mike所说

例如,如果您正在退出int-literal、char-literal或任何东西(您可以将我的语法作为参考),则可以按如下方式向词典添加条目:

    def exitType_literal(self, ctx: DecafParser.Type_literalContext):
        self.nodeTypes[ctx] = 'type'

例如,如果我想将一个节点保存为int值,我会做如下操作

    def exitInt_literal(self, ctx: DecafParser.Int_literalContext):
        self.parseTreePropertyDictionary[ctx] = 'int'

但是,如果您想获得变量的值,则必须在符号表的实现中进行搜索。这就是我获取类型值的方法

因此,一旦每个节点都设置好,您就可以简单地设置希望如何处理操作。例如,如果希望“+”运算符与int一起使用,则需要检查字典中第一个和第二个运算符的类型,检查两者是否都是int,如果都是int,然后将其保存在字典中,作为处理“+”运算符的“int”类型节点

然后,要获取操作的类型,只需访问该节点上的字典,它将返回“int”或您设置的任何类型

相关问题 更多 >

    热门问题