首页 > 其他分享 >5.4 Handling full expressions

5.4 Handling full expressions

时间:2025-01-05 11:10:58浏览次数:1  
标签:Handling 优先级 precedence Expr pub --- 5.4 expressions 表达式

Now we are ready to extend our calculator to cover the full range of arithmetic expressions (well, at least the ones you learned in elementary school). Here is the next calculator example, calculator3:

MST --- 现在我们准备扩展我们的计算器以涵盖所有算术表达式(嗯,至少是你在小学学过的那些)。这是下一个计算器示例 calculator3:

GPT --- 现在我们准备扩展我们的计算器,涵盖完整的算术表达式(好吧,至少是你在小学学到的那些)。下面是下一个计算器示例,calculator3

use std::str::FromStr;

grammar;

pub Expr: i32 = {
    <l:Expr> "+" <r:Factor> => l + r,
    <l:Expr> "-" <r:Factor> => l - r,
    Factor,
};

Factor: i32 = {
    <l:Factor> "*" <r:Term> => l * r,
    <l:Factor> "/" <r:Term> => l / r,
    Term,
};

Term: i32 = {
    Num,
    "(" <Expr> ")",
};

Num: i32 = {
    r"[0-9]+" => i32::from_str(<>).unwrap(),
};

Perhaps the most interesting thing about this example is the way it encodes precedence. The idea of precedence of course is that in an expression like 2+3*4, we want to do the multiplication first, and then the addition. It is pretty straightforward to express precedence in your grammar by structuring it in tiers -- for example, here we have the nonterminal Expr, which covers all expressions. It consists of a series of factors that are added or subtracted from one another. A Factor is then a series of terms that are multiplied or divided. Finally, a Term is either a single number or, using parenthesis, an entire expr.

MST --- 也许这个例子最有趣的地方是它对优先级进行编码的方式。当然,优先级的思想是,在像 2+3*4 这样的表达式中,我们想先做乘法,然后做加法。通过分层构建语法来表达语法中的优先级非常简单 —— 例如,这里我们有非终端 Expr,它涵盖了所有表达式。它由一系列相互添加或减去的因素组成。因子是一系列相乘或除以的项。最后,Term 可以是单个数字,也可以是整个 expr(使用括号)。

GPT --- 这个例子中最有趣的地方可能是它如何编码运算优先级。运算优先级的概念当然是,在像 2+3*4 这样的表达式中,我们希望先进行乘法运算,然后再进行加法运算。通过将文法结构分为多个层次来表示优先级是非常简单的——例如,在这里我们有一个非终结符 Expr,它表示所有的表达式。它由一系列可以相加或相减的因子组成。一个 Factor 由一系列可以相乘或相除的项组成。最后,Term 要么是一个单独的数字,要么是通过括号包围的整个 expr

Abstracting from this example, the typical pattern for encoding precedence is to have one nonterminal per precedence level, where you begin with the operators of lowest precedence (+, -), add in the next highest precedence level (*, /), and finish with the bare "atomic" expressions like Num. Finally, you add in a parenthesized version of your top-level as an atomic expression, which lets people reset.

MST --- 从此示例中抽象出,编码优先级的典型模式是每个优先级都有一个非终止符,其中以最低优先级的运算符 (+、-) 开头,加上下一个最高优先级 (*、/),并以裸露的“原子”表达式(如 Num)结束。最后,将 top-level 的括号版本添加为原子表达式,这样人们就可以重置。

GPT --- 从这个例子中抽象出来,编码优先级的典型模式是为每个优先级级别定义一个非终结符,从最低优先级的运算符(如 +-)开始,再添加下一个优先级级别的运算符(如 */),最后是像 Num 这样的基本“原子”表达式。最后,你为顶层表达式添加一个带括号的版本,作为一种原子表达式,这样用户就可以通过括号来重设优先级。

To see why this works, consider the two possible parse trees for something like 2+3*4:

MST --- 要了解为什么这样做,请考虑两种可能的解析树,例如 2+3*4:

GPT --- 为了理解为什么这种方式有效,考虑一下像 2+3*4 这样的表达式的两种可能的解析树:

2 + 3   *    4          2   +  3   *    4
| | |   |    |          |   |  |   |    |
| | +-Factor-+    OR    +-Expr-+   |    |
| |     |                   |      |    |
+-Expr -+                   +----Factor-+

In the first one, we give multiplication higher precedence, and in the second one, we (incorrectly) give addition higher precedence. If you look at the grammar now, you can see that the second one is impossible: a Factor cannot have an Expr as its left-hand side. This is the purpose of the tiers: to force the parser into the precedence you want.

MST --- 在第一个中,我们给乘法更高的优先级,而在第二个中,我们(错误地)给加法更高的优先级。如果你现在看一下语法,你可以看到第二个是不可能的: Factor 的左侧不能有 Expr。这就是 tiers 的用途:强制解析器达到您想要的优先级。

GPT --- 在第一个解析树中,我们给乘法更高的优先级,而在第二个解析树中,我们(错误地)给加法更高的优先级。如果你现在查看文法,你会发现第二种解析树是不可能的:一个 Factor 不能将一个 Expr 作为其左侧。层次结构的作用就是:强制解析器遵循你希望的优先级。

Tiered expressions can also be generated by Lalrpop using the precedence and assoc attribute macros. These macros generate the same thing as tiered expressions do, but they can reduce code complexity when working with many levels of precedence. The above Expr grammar can be rewritten to the following using them:

MST --- 分层表达式也可以由 Lalrpop 使用 precedence 和 assoc 属性宏生成。这些宏生成的内容与分层表达式相同,但在使用多个优先级时,它们可以降低代码复杂性。可以使用它们将上述 Expr 语法重写为以下内容:

GPT --- LALRPOP 还可以通过 precedenceassoc 属性宏生成分层表达式。这些宏生成的效果与分层表达式相同,但当处理多个优先级级别时,它们可以减少代码复杂性。上述的 Expr 文法可以通过这些宏重写为以下形式:

pub Expr: i32 = {
    #[precedence(level="0")] // Highest precedence
    Term,
    #[precedence(level="1")] #[assoc(side="left")]
    <l:Expr> "*" <r:Expr> => l * r,
    <l:Expr> "/" <r:Expr> => l / r,
    #[precedence(level="2")] #[assoc(side="left")]
    <l:Expr> "+" <r:Expr> => l + r,
    <l:Expr> "-" <r:Expr> => l - r,
};

The precedence level specifies the order of operations starting from zero. In this example it means that 13 + 7 * 3 would be evaluated as (13 + (7 * 3)) because multiplication has a lower precedence level than addition.

MST --- 优先级别指定从零开始的操作顺序。在此示例中,这意味着 13 + 7 * 3 的计算结果为 (13 + (7 * 3)),因为乘法的优先级低于加法的优先级。

GPT --- precedence 级别指定了从零开始的操作顺序。在这个例子中,它意味着 13 + 7 * 3 会被计算为 (13 + (7 * 3)),因为乘法的优先级低于加法。

By using assoc you can specify if the expression is left-associative or right-associative. This is required to make the grammar unambiguous, otherwise 1 + 2 + 3 could both be interpreted as (1 + (2 + 3)) and ((1 + 2) + 3).

MST --- 通过使用 assoc,您可以指定表达式是左关联还是右关联。这是使语法明确所必需的,否则 1 + 2 + 3 都可以解释为 (1 + (2 + 3)) 和 ((1 + 2) + 3)。

GPT --- 通过使用 assoc,你可以指定表达式是左结合还是右结合。这对于使文法无歧义是必需的,否则像 1 + 2 + 3 这样的表达式可能既可以解释为 (1 + (2 + 3)),也可以解释为 ((1 + 2) + 3)

Finally, note that we only write pub before the nonterminal we're interested in parsing (Expr) and not any of the helpers. Nonterminals marked pub have extra code generated, like the new() method used to access the parser from other modules. If you get a warning about an unused new() method on FooParser, drop the pub from nonterminal Foo.

MST --- 最后,请注意,我们只在我们感兴趣的非终端 (Expr) 之前编写 pub,而不编写任何帮助程序。标记为 pub 的非终端会生成额外的代码,例如用于从其他模块访问解析器的 new() 方法。如果您在 FooParser 上收到有关未使用的 new() 方法的警告,请从非终端 Foo 中删除 pub。

GPT --- 最后,注意我们只在我们感兴趣的非终结符(Expr)前写 pub,而不是任何辅助函数。标记为 pub 的非终结符会生成额外的代码,比如 new() 方法,用于从其他模块访问解析器。如果你收到关于 FooParser 的未使用 new() 方法的警告,可以去掉 Foo 非终结符的 pub 修饰符。

标签:Handling,优先级,precedence,Expr,pub,---,5.4,expressions,表达式
From: https://www.cnblogs.com/Tifahfyf/p/18653199

相关文章

  • 【CSS in Depth 2 精译_091】15.4:让 CSS 高度值过渡到自动高度 + 15.5:自定义属性的过
    当前内容所在位置(可进入专栏查看其他译好的章节内容)第五部分添加动效✔️【第15章过渡】✔️15.1状态间的由此及彼15.2定时函数15.2.1定制贝塞尔曲线15.2.2阶跃15.3非动画属性15.3.1不可添加动画效果的属性15.3.2淡入与淡出15.4过渡到自然......
  • 极狐GitLab 正式发布安全补丁版本 17.6.2、17.5.4、 17.4.6
    本分分享极狐GitLab补丁版本17.6.2,17.5.4,17.4.6的详细内容。这几个版本包含重要的缺陷和安全修复代码,我们强烈建议所有私有化部署用户应该立即升级到上述的某一个版本。对于极狐GitLabSaaS,技术团队已经进行了升级,无需用户采取任何措施。参考资料GitLab专业升级服务Gi......
  • SciTech-Logic:逻辑学-Introduction to Logic: Irvine - 5.4 质、量 与 周延性
    SciTech-Logic:逻辑学-IntroductiontoLogic:Irvine-5.2ClassandStatement类与直言命题A.质我们已经看到,每个标准直言命题或是肯定或是否定了某类关系。如果一个命题肯定了类与类之间的包含关系,不管是全部地还是部分地肯定,那么,它的质就是肯定的。因此,A命题(“所有S是P......
  • 报告!Elsevier旗下超强2区备选刊,IF=5.4,少量大牛“灌水”,随便写写也能投
    【SciencePub学术】今天给大家介绍的是一本计算机领域的SCI—《ControlEngineeringPractice》,影响因子5.4,目前位于中科院2区。是 Automatica 的姊妹刊,但是 Automatica 是控制领域公认的顶刊,对理论要求极高,若是大家想退而求其次,不妨考虑一下今天给大家推荐的这本期刊!期刊......
  • JMeter 5.4.1 if控制器使用(注册一个会员,判断注册成功过后登录)
    1、线程组结构2、参数化的形式,使用函数助手随机生成用户名和email3、正则表达式匹配注册响应结果(正则表达式提取器在请求里面的后置处理器中添加),可以添加一个debug,方便查看匹配到的内容4、if控制器的写法,然后在if控制器下面去添加满足条件后要执行的请求......
  • 802.15.4 WPAN协议-扫描、同步、入网和退网等消息流程
    802.15.4WPAN协议-扫描、同步、入网和退网等消息流程文章目录一、原语二、消息流程1.接收超帧和发送超帧的时序2.能量检测(ED)信道扫描3.主动扫描和被动扫描3.1主动扫描3.2被动扫描4.启动PAN网络5.重组PAN网络6.入网过程7.退网过程8.同步过程一、原......
  • 高等数学 5.4反常积分
    文章目录一、无穷限的反常积分二、无界函数的反常积分一、无穷限的反常积分设函数f(x)f(x)......
  • 5.4
    importnumpyasnpimportmathfromscipy.optimizeimportminimize,Boundsdeffunc(x):returnsum(math.sqrt(x[i])foriinrange(100))defcon(x):return1000-np.sum(x[i]*(101-i+1)foriinrange(100))con1={'type':'ineq',......
  • 解决 Maven 插件报错:The plugin org.codehaus.mojo:flatten-maven-plugin:1.5.0 requi
    检查Maven版本:首先,确认当前使用的Maven版本是否与插件要求的版本一致。可以通过在命令行中输入 mvn-v 来查看当前Maven的版本信息。升级或降级Maven版本:如果当前Maven版本过低,需要升级到插件要求的版本;如果过高,可能需要降级。升级或降级Maven可以参考Maven的官......
  • 5.4
    importnumpyasnpfromscipy.optimizeimportminimizedefobjective(x):return-np.sum(np.sqrt(x)*np.arange(1,101))defconstraint1(x):returnx[1]-10defconstraint2(x):return20-(x[1]+2x[2])defconstraint3(x):return30-(x[1]+2x[2]+3x[......