将数学表达式与控制流混合
Mixing mathematical expression with control flow
我想知道,当与控制流混合时,表达式是如何解析的。
让我们假设这样的语法:
case
when a == Method() + 1
then Something(1)
when a == Other() - 2
then 1
else 0
end
这里有两个条件表达式,Method() + 1
、Something(1)
和 0
。每个都可以通过 Shunting-yard algorithm
翻译成后缀,然后很容易翻译成 AST
。但是是否有可能扩展这个算法来处理控制流呢?或者是否有其他方法可以解决这种表达式和控制流的混合问题?
另一个例子:
a == b ? 1 : 2
还有我如何分类这样的表达式:a between b and c
,我可以说between
是三参数函数吗?或者这些表达式有什么特殊的名称吗?
Shunting-yard 算法适用于具有一元和二元运算符的表达式。你需要一些更强大的东西,比如 LL(1) 或 LALR(1) 来解析控制流语句,一旦你有了它,它也能处理表达式。根本不需要 Shunting-yard 算法。
您当然可以使用 operator-precedence 语法解析三元运算符。在
expr ? expr : expr
这里的二进制 "operator" 是 ? expr :
,它方便地以运算符标记(尽管不同)开始和结束。为了适应调车场,将 ? 的 right-precedence 和 : 的 left-precedence 分配给?:
运算符。 ? 的 left-precedence 和 : 的 right-precedence 是±∞,就像括号一样(实际上,他们是)。
由于 case
语句基本上是三元运算符的重复应用,对标记使用略有不同的拼写,并产生类似的解决方案。 (这里的case when
和end
是纯括号,而then
和其余的when
分别对应?
和:
。)
话虽如此,使用 LALR(1) 解析器生成器确实更简单,而且几乎可以肯定,无论您使用何种语言编写,都有一个可用的。
很明显,三元运算符和OP的case语句都是运算符文法:
三元运算符:
ternary-expr: non-ternary-expr
| non-ternary-expr '?' expr ':' ternary-expr
通常情况下,三元运算符的优先级低于任何其他运算符,并且关联到右侧,这就是上面的写法。在 C 和其他语言中,三元表达式与赋值表达式具有相同的优先级,添加起来很简单。这导致关系
X ·> ?
? <· X
? ·=· :
X ·> :
: <· X
案例陈述(许多可能的表述之一):
case_statement: 'case' case_body 'else' expr 'end'
case_body: 'when' expr 'then' expr
| case_body 'when' expr 'then' expr
以上语法的优先级关系如下:
case <· when
case ·=· else
when <· X
(见下文)
when ·=· then
then ·> when
then ·> else
else <· X
else ·=· end
X ·> then
X ·> when
X ·> end
上述关系中的X
指任意二元或一元运算符,任意值终结符,(
和)
.
很容易找到所有这些终端的 left- 和 right-precedence 函数;该模式将类似于标准代数语法中括号的模式。
我想知道,当与控制流混合时,表达式是如何解析的。
让我们假设这样的语法:
case
when a == Method() + 1
then Something(1)
when a == Other() - 2
then 1
else 0
end
这里有两个条件表达式,Method() + 1
、Something(1)
和 0
。每个都可以通过 Shunting-yard algorithm
翻译成后缀,然后很容易翻译成 AST
。但是是否有可能扩展这个算法来处理控制流呢?或者是否有其他方法可以解决这种表达式和控制流的混合问题?
另一个例子:
a == b ? 1 : 2
还有我如何分类这样的表达式:a between b and c
,我可以说between
是三参数函数吗?或者这些表达式有什么特殊的名称吗?
Shunting-yard 算法适用于具有一元和二元运算符的表达式。你需要一些更强大的东西,比如 LL(1) 或 LALR(1) 来解析控制流语句,一旦你有了它,它也能处理表达式。根本不需要 Shunting-yard 算法。
您当然可以使用 operator-precedence 语法解析三元运算符。在
expr ? expr : expr
这里的二进制 "operator" 是 ? expr :
,它方便地以运算符标记(尽管不同)开始和结束。为了适应调车场,将 ? 的 right-precedence 和 : 的 left-precedence 分配给?:
运算符。 ? 的 left-precedence 和 : 的 right-precedence 是±∞,就像括号一样(实际上,他们是)。
由于 case
语句基本上是三元运算符的重复应用,对标记使用略有不同的拼写,并产生类似的解决方案。 (这里的case when
和end
是纯括号,而then
和其余的when
分别对应?
和:
。)
话虽如此,使用 LALR(1) 解析器生成器确实更简单,而且几乎可以肯定,无论您使用何种语言编写,都有一个可用的。
很明显,三元运算符和OP的case语句都是运算符文法:
三元运算符:
ternary-expr: non-ternary-expr | non-ternary-expr '?' expr ':' ternary-expr
通常情况下,三元运算符的优先级低于任何其他运算符,并且关联到右侧,这就是上面的写法。在 C 和其他语言中,三元表达式与赋值表达式具有相同的优先级,添加起来很简单。这导致关系
X ·> ?
? <· X
? ·=· :
X ·> :
: <· X
案例陈述(许多可能的表述之一):
case_statement: 'case' case_body 'else' expr 'end' case_body: 'when' expr 'then' expr | case_body 'when' expr 'then' expr
以上语法的优先级关系如下:
case <· when
case ·=· else
when <· X
(见下文)when ·=· then
then ·> when
then ·> else
else <· X
else ·=· end
X ·> then
X ·> when
X ·> end
X
指任意二元或一元运算符,任意值终结符,(
和)
.很容易找到所有这些终端的 left- 和 right-precedence 函数;该模式将类似于标准代数语法中括号的模式。