Parsing 如何在解释器中处理赋值和变量语法

Parsing 如何在解释器中处理赋值和变量语法,parsing,context-free-grammar,Parsing,Context Free Grammar,大多数口译员允许您在其控制台上键入以下内容: >> a = 2 >> a+3 5 >> 我的问题是,通常使用什么机制来处理这种语法?无论如何,解析器能够区分赋值和表达式,即使它们都可以以数字或字母开头。只有当我们检索第二个令牌时,您才知道是否有分配。在过去,我向前看了两个标记,如果第二个标记不是等号,我将标记推回到词汇流中,并假设它是一个表达式。我想人们可以把作业当作一种表达,我想有些语言就是这样做的。我曾想过使用左因子分解,但我看不出它起作用 乙二醇 更新

大多数口译员允许您在其控制台上键入以下内容:

>> a = 2
>> a+3
5
>>
我的问题是,通常使用什么机制来处理这种语法?无论如何,解析器能够区分赋值和表达式,即使它们都可以以数字或字母开头。只有当我们检索第二个令牌时,您才知道是否有分配。在过去,我向前看了两个标记,如果第二个标记不是等号,我将标记推回到词汇流中,并假设它是一个表达式。我想人们可以把作业当作一种表达,我想有些语言就是这样做的。我曾想过使用左因子分解,但我看不出它起作用

乙二醇


更新我在StackOverflow上发现了这个问题,它解决了同样的问题:

从你如何描述你的方法-做一些前瞻性的标记来决定如何处理事情-听起来像是你试图按照LL(1)或LL(2)解析器的思路编写某种自顶向下的解析器,您试图立即确定要解析的表达式是变量赋值还是算术表达式。有几种方法可以很自然地解析这样的表达式,它们本质上涉及到削弱这两个假设中的一个

第一种方法是从使用自顶向下的解析器(如LL(1)或LL(2)解析器)切换到其他解析器(如LR(0)或SLR(1)解析器)。这些解析器是自下而上工作的,在决定要查看什么之前,先读取输入字符串的较大前缀。在您的例子中,自下而上的解析器可能通过看到变量并思考“好的,我要么要读取要打印的表达式,要么要读取赋值语句,但到目前为止我所看到的,我都无法提交”,然后扫描更多的标记以查看接下来会发生什么。如果他们看到等号,太好了!这是一份作业说明。如果他们看到别的东西,太好了!不是。这方面的好处在于,如果您使用标准的自底向上解析算法,如LR(0)、SLR(1)、LALR(1)或LR(1),您可能会发现解析器通常能够很好地处理此类问题,并且不需要特殊的大小写逻辑

另一个选项是解析整个表达式,假设=与任何其他操作一样是合法的二进制运算符,然后检查解析的内容是否是合法的赋值语句。例如,如果使用Dijkstra的调车场算法进行解析,则可以恢复整个表达式的解析树,而不管它是算术表达式还是赋值。然后,您可以遍历解析树,提出如下问题

  • 如果顶级操作是一个赋值,那么左边是一个变量吗

  • 如果顶级操作不是赋值,这里是否隐藏了嵌套的赋值语句,我们需要去掉它们


换言之,你可以分析比合法的更广泛的语句类,然后做一个后处理步骤,扔掉任何无效的东西。

从你如何描述你的方法-做一些前瞻性的标记来决定如何处理事情-听起来像是你试图按照LL(1)或LL(2)解析器的思路编写某种自上而下的解析器,您试图立即确定要解析的表达式是变量赋值还是算术表达式。有几种方法可以很自然地解析这样的表达式,它们本质上涉及到削弱这两个假设中的一个

第一种方法是从使用自顶向下的解析器(如LL(1)或LL(2)解析器)切换到其他解析器(如LR(0)或SLR(1)解析器)。这些解析器是自下而上工作的,在决定要查看什么之前,先读取输入字符串的较大前缀。在您的例子中,自下而上的解析器可能通过看到变量并思考“好的,我要么要读取要打印的表达式,要么要读取赋值语句,但到目前为止我所看到的,我都无法提交”,然后扫描更多的标记以查看接下来会发生什么。如果他们看到等号,太好了!这是一份作业说明。如果他们看到别的东西,太好了!不是。这方面的好处在于,如果您使用标准的自底向上解析算法,如LR(0)、SLR(1)、LALR(1)或LR(1),您可能会发现解析器通常能够很好地处理此类问题,并且不需要特殊的大小写逻辑

另一个选项是解析整个表达式,假设=与任何其他操作一样是合法的二进制运算符,然后检查解析的内容是否是合法的赋值语句。例如,如果使用Dijkstra的调车场算法进行解析,则可以恢复整个表达式的解析树,而不管它是算术表达式还是赋值。然后,您可以遍历解析树,提出如下问题

  • 如果顶级操作是一个赋值,那么左边是一个变量吗

  • 如果顶级操作不是赋值,这里是否隐藏了嵌套的赋值语句,我们需要去掉它们


换言之,你需要解析比合法语句更广泛的语句类,然后进行后处理,剔除任何无效的语句。

我确实在编写一个解析器,更多的是为了更好地理解理论。我现在想继续使用LL(k)类型的解析器,因为这就是我想要学习的。我过去使用过像yacc(LALR)这样的工具,但我想手工写一些东西。不过,我认为您可以回答我的问题,或者使用更灵活的其他解析系统,或者使用LL()和treat equals a
assignment = variable A
A = '=' expression | empty