zoukankan      html  css  js  c++  java
  • 编译原理笔记 2

    语法分析 (Syntactic Analysis / Parsing)

    识别程序语法结构,构造抽象语法树(Abstract Syntax Tree)

    1. 自顶向下

    • 递归下降算法(Recursive Descent Parsing)
      • 下降:语法分析的过程中,上级文法嵌套下级文法。
      • 递归:上下文无关文法。

    算术表达式在简单情况下,使用类似于词法分析用到的正则文法可以解析(如 "int a = 1")。
    但在复杂情况下("1+2*3""1*2+3" 等),难以穷尽各种组合,需要抽象出一种通用的规则:乘除法 看作 加减法 的子规则,生成 AST 时,乘除法节点就一定是加减法的子节点,从而达到排列优先级的效果。

    function add = multiply | (add + multiply)
    function multiply = numericLiteral | (multiply * numericLiteral)
    

    1.1 巴科斯范式

    实际应用中,上面的语法规则使用 巴科斯范式(BNF) 的形式,工具 Antlr 和 Yacc 也是用这种写法:

    add ::= mul | add + mul
    mul ::= pri | mul * pri
    pri ::= Id | num | (add)
    

    上面规则的优先级从低到高依次为:add, mul, pri。其中带括号的 (add) 实现了语法中常见的括号改变优先级

    1.2 解决左递归

    上面的定义方式转换为算法时,会出现 左递归 的情况(add 无限递归调用 add)
    将 add 交换到加号右侧:

    function add = multiply | (multiply + add)
    function multiply = numericLiteral | (numericLiteral * multiply)
    

    这样就能解决无限递归的问题了,但此时又会出现 "1+2+3" 优先计算了 2+3 的问题(从右向左计算,改变了加法的结合性)

    1.3 解决结合性问题

    还是把递归项放到左边:

    add -> mul | add + mul
    

    通过类似于 尾递归 的方式,将算法改写为循环语句可以解决左递归的问题,同时又保持结合性的正确:

    add -> mul (+ mul)*
    

    2. 自底向上

    递归下降算法在尝试一个规则(消耗 Token)不成功后,需要恢复到尝试之前的状态(不消耗 Token),即 回溯
    而自底向上的算法,回溯的次数较少。

  • 相关阅读:
    Unity The Method Signature Matching Rule
    Unity The Property Matching Rule
    Unity The Type Matching Rule
    Unity The Custom Attribute Matching Rule
    Unity The Member Name Matching Rule
    Unity No Policies
    Unity The Return Type Matching Rule
    Unity The Parameter Type Matching Rule
    Unity The Namespace Matching Rule
    关于TSQL递归查询的(转)
  • 原文地址:https://www.cnblogs.com/cdyang/p/compiler-theory-note-2.html
Copyright © 2011-2022 走看看