如何在解释器中处理赋值和变量语法
How to handle assignment and variable syntax in an interpreter
大多数口译员让您在他们的控制台输入以下内容:
>> a = 2
>> a+3
5
>>
我的问题是通常使用什么机制来处理这种语法?解析器能够以某种方式区分赋值和表达式,即使它们都可以以数字或字母开头。只有当我们检索到第二个令牌时,您才知道您是否有任务。过去,我向前看两个标记,如果第二个标记不等于,我将标记推回到词法流中并假设它是一个表达式。我想人们可以将赋值视为一种表达,我认为某些语言会这样做。我想过使用左因式分解,但我看不到它起作用。
例如
assignment = variable A
A = '=' expression | empty
更新 我在 Whosebug 上发现了这个问题,它解决了同样的问题:
从您描述方法的方式来看 - 做一些前瞻性标记来决定如何处理事情 - 听起来您正在尝试按照 LL( 1) 或 LL(2) 解析器,并且您试图立即决定您正在解析的表达式是变量赋值还是算术表达式。有几种方法可以很自然地解析像这样的表达式,它们本质上涉及削弱这两个假设之一。
我们可以做到这一点的第一种方法是从使用像 LL(1) 或 LL(2) 解析器这样的自上而下的解析器切换到像 LR(0) 或 SLR(1) 解析器这样的其他东西.这些解析器通过在决定要查看的内容之前读取输入字符串的较大前缀来自下而上地工作。在您的情况下,自下而上的解析器可能会通过查看变量并思考 "okay, I'm either going to be reading an expression to print or an assignment statement, but with what I've seen so far I can't commit to either," 然后扫描更多标记以查看接下来会发生什么来工作。如果他们看到等号,那就太好了!这是一个赋值语句。如果他们看到别的东西,那就太好了!不是。这样做的好处是,如果您使用标准的自下而上的解析算法,如 LR(0)、SLR(1)、LALR(1) 或 LR(1),您可能会发现解析器通常会处理这些问题很好解决,不需要特殊的逻辑。
另一种选择是解析整个表达式,假设 = 像任何其他操作一样是合法的二元运算符,然后检查您解析的内容是否是合法的赋值语句。例如,如果使用 Dijkstra 的调车场算法进行解析,则可以为整个表达式恢复解析树,无论它是算术表达式还是赋值。然后你可以遍历解析树来问像
这样的问题
如果顶层操作是赋值,左边是单变量吗?
如果顶层操作不是赋值,这里是否有嵌套的赋值语句我们需要去掉?
换句话说,除了合法的语句之外,您还需要解析更广泛的 class 语句,然后执行后处理步骤以剔除任何无效的语句。
大多数口译员让您在他们的控制台输入以下内容:
>> a = 2
>> a+3
5
>>
我的问题是通常使用什么机制来处理这种语法?解析器能够以某种方式区分赋值和表达式,即使它们都可以以数字或字母开头。只有当我们检索到第二个令牌时,您才知道您是否有任务。过去,我向前看两个标记,如果第二个标记不等于,我将标记推回到词法流中并假设它是一个表达式。我想人们可以将赋值视为一种表达,我认为某些语言会这样做。我想过使用左因式分解,但我看不到它起作用。
例如
assignment = variable A
A = '=' expression | empty
更新 我在 Whosebug 上发现了这个问题,它解决了同样的问题:
从您描述方法的方式来看 - 做一些前瞻性标记来决定如何处理事情 - 听起来您正在尝试按照 LL( 1) 或 LL(2) 解析器,并且您试图立即决定您正在解析的表达式是变量赋值还是算术表达式。有几种方法可以很自然地解析像这样的表达式,它们本质上涉及削弱这两个假设之一。
我们可以做到这一点的第一种方法是从使用像 LL(1) 或 LL(2) 解析器这样的自上而下的解析器切换到像 LR(0) 或 SLR(1) 解析器这样的其他东西.这些解析器通过在决定要查看的内容之前读取输入字符串的较大前缀来自下而上地工作。在您的情况下,自下而上的解析器可能会通过查看变量并思考 "okay, I'm either going to be reading an expression to print or an assignment statement, but with what I've seen so far I can't commit to either," 然后扫描更多标记以查看接下来会发生什么来工作。如果他们看到等号,那就太好了!这是一个赋值语句。如果他们看到别的东西,那就太好了!不是。这样做的好处是,如果您使用标准的自下而上的解析算法,如 LR(0)、SLR(1)、LALR(1) 或 LR(1),您可能会发现解析器通常会处理这些问题很好解决,不需要特殊的逻辑。
另一种选择是解析整个表达式,假设 = 像任何其他操作一样是合法的二元运算符,然后检查您解析的内容是否是合法的赋值语句。例如,如果使用 Dijkstra 的调车场算法进行解析,则可以为整个表达式恢复解析树,无论它是算术表达式还是赋值。然后你可以遍历解析树来问像
这样的问题如果顶层操作是赋值,左边是单变量吗?
如果顶层操作不是赋值,这里是否有嵌套的赋值语句我们需要去掉?
换句话说,除了合法的语句之外,您还需要解析更广泛的 class 语句,然后执行后处理步骤以剔除任何无效的语句。