zoukankan      html  css  js  c++  java
  • 编译器设计-自下而上分析器-误差恢复-语义分析

    编译器设计-自下而上分析器-误差恢复-语义分析

    Compiler Design - Bottom-Up Parser

    Compiler Design - Error Recovery

    Compiler Design - Semantic Analysis

    一.Compiler Design - Bottom-Up Parser

    自底向上的解析从树的叶节点开始,向上工作直到到达根节点。在这里,我们从一个句子开始,然后以相反的方式应用产生式规则,以达到开始符号。下面给出的图像描述了可用的自下而上的解析器。

     移位减少分析             

    Shift-reduce解析使用两个独特的步骤进行自底向上的解析。这些步骤称为移位步骤和减少步骤。             

    移位步骤:移位步骤是指输入指针向前移动到下一个输入符号,称为移位符号。这个符号被推到堆栈上。移位的符号被视为解析树的单个节点。             

    Reduce step:当解析器找到一个完整的语法规则(RHS)并将其替换为(LHS)时,称为reducestep。当堆栈顶部包含句柄时发生这种情况。为了减少,在堆栈上执行POP函数,该函数从句柄弹出,并用LHS非终端符号替换它。

    LR分析器             

    LR解析器是一个非递归、移位减少、自底向上的解析器。它使用了大量的上下文无关语法,这使得它成为最有效的语法分析技术。L R解析器也称为LR(k)解析器,其中L表示从左到右扫描输入流;R表示反向构造最右边的派生,k表示要做出决策的先行符号的数量。             

    有三种广泛使用的算法可用于构造LR解析器:

    • SLR(1) – Simple LR Parser:
      • Works on smallest class of grammar
      • Few number of states, hence very small table
      • Simple and fast construction
    • LR(1) – LR Parser:
      • Works on complete set of LR(1) Grammar
      • Generates large table and large number of states
      • Slow construction
    • LALR(1) – Look-Ahead LR Parser:
      • Works on intermediate size of grammar
      • Number of states are same as in SLR(1)

    LR解析算法             

    这里我们描述一个LR解析器的骨架算法:

    token = next_token()

    repeat forever

       s = top of stack

      

       if action[s, token] = “shift si” then

          PUSH token

          PUSH si

          token = next_token()   

       else if action[s, token] = “reduce A::= β“ then

          POP 2 * |β| symbols

          s = top of stack

          PUSH A

          PUSH goto[s,A]   

       else if action[s, token] = “accept” then

          return

       else

          error()

    LL vs. LR

    二.Compiler Design - Error Recovery

    解析器应该能够检测并报告程序中的任何错误。当遇到错误时,解析器应该能够处理它并继续解析其余的输入。大多数情况下,解析器需要检查错误,但在编译过程的各个阶段可能会遇到错误。一个程序在不同阶段可能有以下几种错误:             

    词法:某个标识符的名称键入不正确             

    语法:缺少分号或括号不平衡             

    语义:不兼容的值赋值             

    逻辑:代码不可访问,无限循环             

    可以在解析器中实现四种常见的错误恢复策略来处理代码中的错误。             

    紧急模式             

    当解析器在语句中的任何地方遇到错误时,它将忽略语句的其余部分,不处理从错误输入到分隔符(如分号)的输入。这是最简单的错误恢复方法,而且还可以防止解析器开发无限循环。

    语句模式             

    当解析器遇到错误时,它会尝试采取纠正措施,以便语句的其余输入允许解析器提前解析。例如,插入一个缺少的分号,用分号替换逗号等等。解析器设计者在这里必须小心,因为一个错误的更正可能导致无限循环。             

    错误产品             

    编译器设计器知道代码中可能出现的一些常见错误。此外,设计人员可以创建要使用的扩充语法,作为在遇到错误时生成错误构造的产品。             

    整体校正             

    解析器将手边的程序视为一个整体,并试图找出程序的意图,并试图找出与之最接近的匹配项,这是无错误的。当错误的输入(语句)X被馈送时,它会为某个最接近的无错误语句Y创建一个解析树。这可能允许解析器对源代码进行最小的更改,但由于此策略的复杂性(时间和空间),它尚未在实践中实现。

    抽象语法树             

    解析树表示不容易被编译器解析,因为它们包含的细节比实际需要的多。以下面的解析树为例:

    如果仔细观察,我们会发现大多数叶节点都是父节点的单个子节点。在将信息传送到下一阶段之前,可以消除这些信息。通过隐藏额外信息,我们可以获得如下所示的树:

    Abstract tree can be represented as:

    ASTs是编译器中重要的数据结构,具有最少的不必要信息。ASTs比解析树更紧凑,编译器可以很容易地使用它。

    三.Compiler Design - Semantic Analysis

    在语法分析阶段,我们学习了解析器如何构造解析树。在那个阶段构造的纯解析树通常对编译器没有用处,因为它不携带任何关于如何计算树的信息。上下文无关语法的产生,决定了语言的规则,不适应如何解释它们。

    For example

    E  E + T

    上面的CFG产品没有与之相关联的语义规则,它无法帮助理解产品。             

    语义学             

    语言的语义为其结构提供了意义,如标记和语法结构。语义有助于解释符号、它们的类型以及它们之间

    CFG + semantic rules = Syntax Directed Definitions

    For example:

    int a = value”;

    不应在词汇和语法分析阶段出现错误,因为它在词汇和结构上都是正确的,但应在赋值类型不同时产生语义错误。这些规则由语言的语法设定,并在语义分析中进行评估。语义分析应完成以下任务:             

    范围分辨率             

    类型检查             

    数组绑定检查

    语义错误             

    我们已经提到了一些语义分析器需要识别的语义错误:             

    类型不匹配             

    未声明的变量             

    保留标识符误用。             

    作用域中变量的多重声明。             

    访问范围外变量。             

    实际参数与形式参数不匹配。

    属性语法             

    属性语法是上下文无关语法的一种特殊形式,它将一些附加信息(属性)附加到一个或多个非终端,以提供上下文敏感信息。每个属性都有定义良好的值域,如integer、float、character、string和expressions。             

    属性语法是为上下文无关语法提供语义的一种媒介,它可以帮助指定编程语言的语法和语义。属性语法(当被视为解析树时)可以在树的节点之间传递值或信息。

    Example:

    E  E + T { E.value = E.value + T.value }

    CFG的右边部分包含语义规则,这些规则指定如何解释语法。这里,将非终端E和T的值相加,结果被复制到非终端E。             

    语义属性可以在解析时从其域中分配给其值,并在分配或条件时进行计算。根据属性获取值的方式,它们可以大致分为两类:合成属性和继承属性。             

    综合属性             

    这些属性从其子节点的属性值中获取值。为了说明这一点,假设以下产品:

    S  ABC

    如果S从它的子节点(A、B、C)中获取值,则它被称为合成属性,因为ABC的值被合成为S。              

    如前一个示例(E→E+T)所示,父节点E从其子节点获取其值。合成属性从不从其父节点或任何同级节点获取值。             

    继承的属性             

    与合成属性不同,继承属性可以从父属性和/或兄弟属性中获取值。在接下来的制作中,

    S  ABC

    A可以从S、B和C中获取值。B可以从S、A和C中获取值。同样,C可以从S、A和B中获取值。             

    扩展:根据语法规则将非终端扩展为终端时

    归约:根据语法规则将一个终端归约为其对应的非终端。语法树从上到下和从左到右进行分析。每当进行约简时,我们都会应用相应的语义规则(动作)。             

    语义分析使用语法导向的翻译来执行上述任务。             

    语义分析器从其前一阶段(语法分析)接收AST(抽象语法树)。             

    语义分析器将属性信息附加到AST中,称为属性AST。             

    属性是两个元组值,<attribute name,attribute value>

    For example:

    int value  = 5;
    <type, integer”>
    <presentvalue, 5”>

    对于每个产品,我们都附加一个语义规则。             

    S属性SDT             

    如果SDT只使用合成属性,则称为S属性SDT。这些属性使用S属性的SDTs进行评估,这些sdt在产品(右侧)之后编写语义操作。

    如上所述,S属性的sdt中的属性在自下而上的解析中求值,因为父节点的值依赖于子节点的值。             

    L属性SDTs             

    这种形式的SDTs既使用合成属性,也使用继承属性,并且限制不从正确的兄弟节点获取值。             

    L属性的SDTs中,非终端可以从其父节点、子节点和同级节点获取值。在下面的生产中

    S  ABC

    S可以取A、B和C(合成)的值。A只能从S获取值。B可以从S获取值,A可以从S、A和B获取值。任何非终端都不能从其右边的同级中获取值。             

    L属性SDT中的属性是通过深度优先和从左到右的解析方式计算的。

    我们可以得出结论,如果一个定义是S属性的,那么它也是L属性的,因为L属性的定义包含S属性的定义。

     

  • 相关阅读:
    Mysql5.5安装
    JVM内存管理
    jquery, js轮播图插件Swiper3
    Redis基本结构
    ArcGIS10.1发布WFS-T服务
    ArcGIS10.1如何将数据库注册到ARCSERVER服务器
    转:Oracle密码过期,取消密码180天限制
    oracle数据库导入导出命令
    转载:oracle11G 已开启监听,但远程连接依旧无监听解决过程
    Xcode group
  • 原文地址:https://www.cnblogs.com/wujianming-110117/p/13183938.html
Copyright © 2011-2022 走看看