热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

编译原理与javacc初探[转]

2019独角兽企业重金招聘Python工程师标准1、前序真是书到用时方恨少啊,在大学的时候,虽然学过编译原理,但当时真是不懂啊&#x

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

1、前序

          真是书到用时方恨少啊,在大学的时候,虽然学过编译原理,但当时真是不懂啊,只是为了应付考试,死记硬背了一点点。现在呢,由于工作上的需要,不得不弥补一下啊。 这两天把编译原理的书又看了一遍,其实也就是主要看了文法,词法分析,语法分析而已,为了备忘,赶紧先记一下吧。

2、定义

      词法分析,就是把源码中的一行行代码按照事先规定好的格式分隔成一个个单词符号(token),比如数字,变量名称,函数等等。
      语法分析呢,主要就是分析词法分析后的一个个token,是否能够拼装,组成事先规定好的语法中的一个。
      文法呢,就是对上面语法的规定的集合(程序里面用到的主要是上下文无关文法)。

3、实现

 3.1词法分析

        主要用到的技术有正则表达式,状态转换图,DFA(确定有限自动机),NFA(非确定有限自动机)以及超前搜索。

3.2语法分析

     主要分自上而下分析和子下而上分析。

3.2.1自上而下分析

主要面临的问题有左递归和左因子。

3.2.1.1左递归的消除

可以参考一下公式
  P->Pα|β可以转换成一下语句
  P->βP'
  P'->αP'|ε   (ε为空子)

 

3.2.1.2消除回溯,提取公因子

可以参考一下公式
  A->δβ1|δβ2|δβ3|γ1|γ2|γ3
  转换成
  A->δA'|γ1|γ2|γ3
  A'->β1|β2|β3

3.2.1.3 LL(1)文法

意思就是从左向右扫描输入串,最左推导,每一步只需向前看一个符号。

3.2.1.4实现方法

      当一个文法满足 LL(1)文法条件时,我们就可以为它构造一个不带回溯的自上而下分析程序,这个分析程序是由一组递归过程组成的,每个过程对应文法的一个非终结符。这样的一个分析程序称为递归下降分析器。
      另外一种实现方法为预测分析程序。就是使用一张分析表和一个栈进行联合控制。

3.2.2自下而上分析

      从输入串开始,逐步进行规约,直至规约到文法的开始符号。
      由于与我下文说的javacc没有关系,因此我就不再叙述了。

4、javacc概述

    JavaCC是一个词法分析器和语法分析器的生成器,用于Java领域,根据指定格式的输入文件生成java源码的词法、语法分析程序(比lex和yacc要人性化)。
    是一个免费的开源的工具,可以从网上下载。
    javacc采用的是自顶向下的分析方法,而且没有回溯功能,因此如何解决冲突的问题,是程序员的责任。


      必须要解决两个问题:左递归和公因子
      关于左递归的问题,一般采用经典的修改文法的方法解决。
      关于公因子的问题,可以改写算法(提取公因子),也可以通过展望(look ahead)更多符号的方法来解决。 但是因为javacc扩展了经典的BNF,因此它面临更多的问题。总之,当在编译时碰到冲突问题时,就说到了一个choice point。


 可以将javacc中choice point归结为以下几类:
 l . 由选择算子 | 引入的冲突,
 2. 由可省略算子 [] 或 ?引入的冲突
 3. 由重复算子 * 引入的冲突
 4. 由重复算子 + 引入的冲突


当在javacc中碰到冲突时,可以采用下面的方法之一解决问题
 1.修改语法,使之成为LL(1)语法。
 2.只要将LOOKAHEAD=k写到Options块中即可,javacc产生的分析器就可以分析LL(K)语法生成的语言
 
 采用第一种方法的好处是效率非常高,易于维护。采用第二种方法的好处是语法更加直观,但是却不易维护。有时候采用第一种方法是无法解决冲突的,第二种方法是唯一的选择。

 

5、javacc入门

            首先先从官网上面下载相应的javacc文件,我这里下载的是javacc-5.0.zip。里面包含一些入门文档(英文)和例子。

addr.jj

expression: Start->NUMBER(PLUS Primary)*

[java] view plain copy

 print?在CODE上查看代码片派生到我的代码片

相信能够看懂怎么使用吧。

6、javacc与eclipse整合

   从网上下载easy-javacc-1.5.7-eclipse plugin.exe,并安装到eclipse的安装目录里面。然后重启eclipse,看下图。

 

编译adder.jj,生成java源文件(词法语法分析程序)

7、扩展语法分析器

 在上面的例子中的start函数中,我们仅仅通过语法分析器来判断输入的语句是否正确
我们可以扩展BNF表达式,加入Java代码,使得经过语法分析后,得到我们想要的结果或者对象。
我们将start函数改写为:

注意:t.kind表示单词的类别,t.image表示单词值。

8、javacc实例一(计算器)

expression:

[java] view plain copy

 print?在CODE上查看代码片派生到我的代码片

  1. Start -> ( Expression EOL )*   
  2. Expression -> Term(PLUS Term|MINUS Term)*  
  3. Term -> Primary(TIMES Primary | DIVIDE Primary)*  
  4. Primary -> NUMBER  


Calculator.jj

[java] view plain copy

 print?在CODE上查看代码片派生到我的代码片

  1. options  
  2. {  
  3.   static = false;  
  4. }  
  5.   
  6. PARSER_BEGIN(Calculator)  
  7. import java.io.PrintStream ;  
  8. public class Calculator {  
  9.     double previousValue = 0.0 ;  
  10.     public static void main( String[] args )throws ParseException, TokenMgrError, NumberFormatException {  
  11.         Calculator parser = new Calculator( System.in ) ;  
  12.         parser.Start( System.out ) ;  
  13.     }  
  14. }  
  15. PARSER_END(Calculator)  
  16.   
  17. SKIP:{ " " }  
  18.   
  19. TOKEN:{< EOL : "\n"|"\r"|"\r\n" >}  
  20. TOKEN:{< PLUS : "&#43;">}  
  21. TOKEN :{ < MINUS : "-" > }  
  22. TOKEN:{< TIMES : "*" > }  
  23. TOKEN:{< DIVIDE : "/" > }  
  24. TOKEN:{< NUMBER : "."  | "."|"."  >}  
  25. TOKEN : {< #DIGITS : (["0"-"9"])&#43; >}  
  26.   
  27. void Start(PrintStream printStream) throws NumberFormatException :  
  28. {}  
  29. {  
  30.     (  
  31.         previousValue &#61; Expression()  
  32.           
  33.         { printStream.println(previousValue); }  
  34.     )*  
  35.       
  36. }  
  37.   
  38. double Expression() throws NumberFormatException :  
  39. {  
  40.     double i;  
  41.     double value;  
  42. }  
  43. {  
  44.     value &#61; Term()  
  45.     (  
  46.           
  47.         i &#61; Term()  
  48.         { value &#43;&#61; i;}  
  49.         |  
  50.           
  51.         i &#61; Term()  
  52.         { value -&#61; i; }  
  53.     )*  
  54.     { return value; }  
  55. }   
  56.   
  57. double Term() throws NumberFormatException :  
  58. {  
  59.     double i;  
  60.     double value;  
  61. }  
  62. {  
  63.     value &#61; Primary()  
  64.     (  
  65.           
  66.         i &#61; Primary ()  
  67.         { value *&#61; i;}  
  68.         |  
  69.           
  70.         i &#61; Primary ()  
  71.         { value /&#61; i; }  
  72.     )*  
  73.     { return value; }  
  74. }  
  75.   
  76. double Primary() throws NumberFormatException :  
  77. {  
  78.     Token t;  
  79.     double d;  
  80. }  
  81. {  
  82.     t &#61;   
  83.     { return Double.parseDouble( t.image ); }  
  84. }  

9、javacc实例一&#xff08;计算器扩展&#xff09;

   在8的基础上&#xff0c;增加括号支持和负数计算

expression&#xff1a;

[java] view plain copy

 print?在CODE上查看代码片派生到我的代码片

  1. Start -> ( Expression EOL )*   
  2. Expression -> Term(PLUS Term|MINUS Term)*  
  3. Term -> Primary(TIMES Primary | DIVIDE Primary)*  
  4. Primary -> NUMBER | PREVIOUS | MINUS Primary | OPEN_PAR Expression CLOSE_PAR  


Calculator.jj

 

[java] view plain copy

 print?在CODE上查看代码片派生到我的代码片

  1. options  
  2. {  
  3.   static &#61; false;  
  4. }  
  5.   
  6. PARSER_BEGIN(Calculator)  
  7. import java.io.PrintStream ;  
  8. public class Calculator {  
  9.     double previousValue &#61; 0.0 ;  
  10.     public static void main( String[] args )throws ParseException, TokenMgrError, NumberFormatException {  
  11.         Calculator parser &#61; new Calculator( System.in ) ;  
  12.         parser.Start( System.out ) ;  
  13.     }  
  14. }  
  15. PARSER_END(Calculator)  
  16.   
  17. SKIP:{ " " }  
  18.   
  19. TOKEN:{< EOL : "\n"|"\r"|"\r\n" >}  
  20. TOKEN:{< PLUS : "&#43;">}  
  21. TOKEN :{ < MINUS : "-" > }  
  22. TOKEN:{< TIMES : "*" > }  
  23. TOKEN:{< DIVIDE : "/" > }  
  24. TOKEN:{< OPEN_PAR : "(" > }  
  25. TOKEN:{< CLOSE_PAR : ")" > }  
  26. TOKEN:{< PREVIOUS : "$" > }  
  27. TOKEN:{< NUMBER : "."  | "."|"."  >}  
  28. TOKEN : {< #DIGITS : (["0"-"9"])&#43; >}  
  29.   
  30. void Start(PrintStream printStream) throws NumberFormatException :  
  31. {}  
  32. {  
  33.     (  
  34.         previousValue &#61; Expression()  
  35.           
  36.         { printStream.println(previousValue); }  
  37.     )*  
  38.       
  39. }  
  40.   
  41. double Expression() throws NumberFormatException :  
  42. {  
  43.     double i;  
  44.     double value;  
  45. }  
  46. {  
  47.     value &#61; Term()  
  48.     (  
  49.           
  50.         i &#61; Term()  
  51.         { value &#43;&#61; i;}  
  52.         |  
  53.           
  54.         i &#61; Term()  
  55.         { value -&#61; i; }  
  56.     )*  
  57.     { return value; }  
  58. }   
  59.   
  60. double Term() throws NumberFormatException :  
  61. {  
  62.     double i;  
  63.     double value;  
  64. }  
  65. {  
  66.     value &#61; Primary()  
  67.     (  
  68.           
  69.         i &#61; Primary ()  
  70.         { value *&#61; i;}  
  71.         |  
  72.           
  73.         i &#61; Primary ()  
  74.         { value /&#61; i; }  
  75.     )*  
  76.     { return value; }  
  77. }  
  78.   
  79. double Primary() throws NumberFormatException :  
  80. {  
  81.     Token t;  
  82.     double d;  
  83. }  
  84. {  
  85.     t &#61;   
  86.     { return Double.parseDouble( t.image ); }  
  87.     |  
  88.           
  89.     { return previousValue; }     
  90.     |     
  91.      d &#61; Expression()    
  92.     { return d; }     
  93.     |     
  94.      d &#61; Primary()   
  95.     { return -d; }  
  96. }  

转:https://my.oschina.net/qiangzigege/blog/862120



推荐阅读
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 本文介绍了如何使用python从列表中删除所有的零,并将结果以列表形式输出,同时提供了示例格式。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 深度学习中的Vision Transformer (ViT)详解
    本文详细介绍了深度学习中的Vision Transformer (ViT)方法。首先介绍了相关工作和ViT的基本原理,包括图像块嵌入、可学习的嵌入、位置嵌入和Transformer编码器等。接着讨论了ViT的张量维度变化、归纳偏置与混合架构、微调及更高分辨率等方面。最后给出了实验结果和相关代码的链接。本文的研究表明,对于CV任务,直接应用纯Transformer架构于图像块序列是可行的,无需依赖于卷积网络。 ... [详细]
author-avatar
黄于諭春琪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有