2.2 语法分析

语法分析器(Grammar Parser)将对由扫描器产生的记号进行语法分析,从而产生语法树(Syntax Tree)。整个分析过程采用了上下文无关语法(Context-free Grammar)的分析手段。

由语法分析器生成的语法树就是以表达式(Expression)为节点的树。如下所示:

从图中可以知道,整个语句就是一个赋值表达式:赋值表达式的左边是一个数组表达式,右边是一个乘法表达式;数组表达式又由两个符号表达式组成,等等。符号和数字是最小的表达式,它们不是由其他表达式来组成,所以它们通常作为整个语法树的叶节点。

在语法分析的同时,很多运算符号的优先级和含义也被确定下来了。比如乘法表达式比加法表达式的优先级高。

另外有些符号具有多重含义,比如 * 在C语言中可以表示乘法表达式,也可以表示指针取内容的表达式,所以语法分析阶段必须对这些内容进行区分。如果出现了表达式不合法,比如各种括号不匹配、表达式中缺少操作符等,编译器就会报告语法分析阶段的错误。

语法分析工具使用 yacc(Yet Another Compiler Compiler),它像 lex 一样,可以根据用户给定的语法规则对输入的记号序列进行解析,从而构建出一棵语法树。

2.2.1 yacc 介绍

引用:https://blog.csdn.net/zdy0_2004/article/details/54918450

yacc(Yet Another Compiler Compiler),是Unix/Linux上一个用来生成编译器的编译器(编译器代码生成器).

使用巴克斯范式(BNF)定义语法,能处理上下文无关文法(context-free)。出现在每个产生式左边(left-hand side:lhs)的符号是非终端符号,出现在产生式右边(right-hand side:rhs)的符号有非终端符号和终端符号,但终端符号只出现在右端。

yacc是开发编译器的一个有用的工具,采用LR(1)(实际上是LALR(1))语法分析方法。

LR(k)分析方法是1965年Knuth提出的,括号中的k(k >=0)表示向右查看输入串符号的个数。LR分析法正视给出一种能根据当前分析栈中的符号串和向右顺序查看输入串的k个符号就可唯一确定分析器的动作是移进还是规约和用哪个产生式规约。

这种方法具有分析速度快,能准确,即使地指出出错的位置,它的主要缺点是对于一个使用语言文法的分析器的构造工作量相当大,k愈大构造愈复杂,实现比较困难。

  • 一个LR分析器有3个部分组成:
    • 总控程序,也可以称为驱动程序。
      • 对所有的LR分析器总控程序都是相同的。
    • 分析表或分析函数。
      • 不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表也不同,分析表又可分为动作(ACTION)表和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
    • 分析栈,包括文法符号栈和相应的状态栈。
      • 它们均是先进后出栈。 分析器的动作由栈顶状态和当前输入符号所决定(LR(0)分析器不需要向前查看输入符号)。
  • LR分析器工作过程如下 :
    • 其中SP为栈指针,S[i]为状态栈,X[i]为文法符号栈。状态转换表内容按关系GOTO[Si,X] = Sj确定,该关系式是指当栈顶状态为Si遇到当前文法符号为X时应转向状态Sj。X为终结符或非终结符。 ACTION[Si,a]规定了栈顶状态为Si是遇到输入符号a应执行的动作。
  • 执行的动作的分类:
    • 移进:当Sj = GOTO[Si,a]成立,则把Sj移入到状态栈,把a移入到文法符号栈。其中i,j表示状态号。
    • 规约:当在栈顶形成句柄为β时,则用β归约为相应的非终结符A,即当文法中有 A-->β的产生式,而β的长度为r(即|β| = r),则从状态栈和文法符号栈中自栈顶向下去掉r个符号,即栈指针SP减去r。并把A移入文法符号栈内,再把满足Sj = GOTO[Si,A]的状态移进状态栈,其中Si为修改指针后的栈顶状态。
    • 接受acc:当规约到文法符号栈只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。
    • 报错:当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入串不是该文法能接受的句子。

2.2.2 YACC 的文件格式

YACC 的文件格式分为三个部分:

  1. ...definitions...( % {} % )  
  2. % % 
  3. ...rules...
  4.  % % 
  5. ...subroutines...  
  • 定义部分:定义部分包括标志(token)定义和C代码(用"%{"和"%}"括起来)。
  • 规则部分:规则中目标或非终端符放在左边,后跟一个冒号(:),然后是产生式的右边,之后是对应的动作(用{}包含)
  • 第三部分:该部分是函数部分。当yacc解析出错时,会调用函数yyerror(),用户可自定义函数的实现。
    • 递归的处理:递归处理有左递归和右递归。
    • If-else 的冲突:当有两个IF一个ELSE时,该ELSE和哪个IF匹配是一个问题。有两种匹配方法:与第一个匹配和与第二匹配。现代程序语言都让ELSE与最近的IF匹配,这也是yacc的缺省行为。
    • 出错处理:当yacc解析出错时,缺省的行为是调用函数yyerror(),然后从yylex返回一个值。一个更友好的方法是忽略一段错误输入流,继续开始扫描。这里要涉及到YACC中错误保留字error的应用。

GCC编译器原理(三)------编译原理三:编译过程(2-2)---编译之语法分析的更多相关文章

  1. gcc编译器参数使用及解决

    gcc -c CStringAndPointer.c -o CStringAndPointer.o 执行时出现问题: ./CStringAndPointer.o bash: ./CStringAndP ...

  2. GCC编译器原理(三)------编译原理三:编译过程---预处理

    Gcc的编译流程分为了四个步骤: 预处理,生成预编译文件(.文件):gcc –E hello.c –o hello.i 编译,生成汇编代码(.s文件):gcc –S hello.i –o hello. ...

  3. 跟vczh看实例学编译原理——三:Tinymoe与无歧义语法分析

    文章中引用的代码均来自https://github.com/vczh/tinymoe.   看了前面的三篇文章,大家应该基本对Tinymoe的代码有一个初步的感觉了.在正确分析"print ...

  4. jQuery-1.9.1源码分析系列(三) Sizzle选择器引擎——编译原理

    这一节要分析的东东比较复杂,篇幅会比较大,也不知道我描述后能不能让人看明白.这部分的源码我第一次看的时候也比较吃力,现在重头看一遍,再分析一遍,看能否查缺补漏. 看这一部分的源码需要有一个完整的概念后 ...

  5. gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解

    摘自http://blog.csdn.net/elfprincexu/article/details/45043971 gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解 C和C+ ...

  6. 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——3 计算4个函数

    整个引擎代码在github上,地址为:https://github.com/sun2043430/RegularExpression_Engine.git nullable, firstpos, la ...

  7. GCC编译器原理(二)------编译原理一:ELF文件(2)

    四. ELF 文件格式分析 ELF文件(目标文件)格式主要四种: 可重定向文件: 文件保存着代码和适当的数据,用来和其他的目标文件一起来创建一个可执行文件或者是一个共享目标文件.(目标文件或者静态库文 ...

  8. 学了编译原理能否用 Java 写一个编译器或解释器?

    16 个回答 默认排序​ RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...

  9. 浅谈C++编译原理 ------ C++编译器与链接器工作原理

    原文:https://blog.csdn.net/zyh821351004/article/details/46425823 第一篇:      首先是预编译,这一步可以粗略的认为只做了一件事情,那就 ...

  10. Knowledge Point 20180303 对比编译器、解释器与Javac编译原理

    编译器与Javac编译原理 在前文我们知道了Java是一种编译语言和解释语言,它的源代码经过编译器Javac编译为能够被JVM识别的二进制语言,然后JVM将其解释为能够被平台识别的机器语言.那么什么是 ...

随机推荐

  1. hdu 2859 Phalanx (最大对称子矩阵)

    Problem Description Today is army day, but the servicemen are busy with the phalanx for the celebrat ...

  2. kvm虚拟化管理

    虚拟化 KVM (kernel-based virtual machine) 常见的一些虚拟化的软件xen kvm vmware esx openVZ Oracle VM VirtualBox vsp ...

  3. B1018. 锤子剪刀布

    大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图所示: 现给出两人的交锋记录,请统计双方的胜.平.负次数,并且给出双方分别出什么手势的胜算最大. 输入格式: 输入第1行给出正整数N( ...

  4. 将pandas的Dataframe对象读写Excel文件

    Dataframe对象生成Excel文件 需要xlrd库  命令  pip install xlrd #导入pandas import pandas as pd import numpy as np ...

  5. 每添加一张图片后,GDI对象 + 3 原因: ImageList_AddIcon(hIcon) 后没调用 DestroyIcon(hIcon)

    今天无意间在[任务管理器]中发现,每添加1张图片后,应用程序的 GDI对象 + 3,添加图片后,再把所有图片删除, GDI对象数量没减少! 排查原因,发现: GDI对象 + 3 的代码是: int o ...

  6. 有趣的js获取input标签中光标的索引

    先看动图如下,我们就可以很清楚的知道获取input标签中光标的索引的意思了. 由于IE支持document.selection,Firefox,Chrome,Safari以及Opera都有select ...

  7. Python之常用模块--collections模块

    认识模块 什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的 ...

  8. appium 切换native/ webview,findby,还有页面元素定位一直小于0的问题的解决

    之前一直有个bug没有解决. 今天,终于解决了. 疑问过程: app是混合应用,项目做了H5优化之后,以前的用例执行总会失败,体现在原来的一个元素点击无反馈 排查原因:1.项目做了H5优化,2.测试的 ...

  9. python爬虫获取图片

    import re import os import urllib #根据给定的网址来获取网页详细信息,得到的html就是网页的源代码 def getHtml(url): page = urllib. ...

  10. VMware for mac inside error solutions

    Terminal 下执行 sudo xattr -r -d com.apple.quarantine /Applications/VMware\ Fusion.app 之后就能正常打开镜像安装虚拟机了 ...