用java实现编译器-算术表达式及其语法解析器的实现

时间:2021-11-19 01:58:30

大家在参考本节时,请先阅读以下博文,进行预热:

http://blog.csdn.net/tyler_download/article/details/50708807

本节代码下载地址:

http://pan.baidu.com/s/1sjWiwPn

代码的理解和运行是吃透编译原理的关键,如果我们看的是爱情动作片,自然选择无码的好,但如果看得是计算机课程,则必须有码,无码的计算机理论都是耍流氓。

当前,java所实现的简易编译器目的是将一条或一组含有加号和乘号的算术表达式编译成类似汇编语言的伪码,因此必须给算术表达式设立一组语法规则,那么程序才能对输入的表达式进行分析。我们把一组带有分号的算术表达式称为statements, 例如:

1+2*3+4;

2+3*4+5;

3+4*5+6;

这三个表达式的集合称为statements.同时将一组表达式中的某一条带有分号的表达式称为expression, 这样statements 就是由一个或多个expression组成的:

用java实现编译器-算术表达式及其语法解析器的实现

因此statements的语法规则可以写成:

statements -> expression; | expression; statements

大家看到该语法定义跟我在上一篇文章中举的例子有所不同:

1.    在-> 右边有两组解析规则,他们用符号 | 分割开。

2.    -> 左边的被解析的对象居然在右边的解析规则中出现,形成了一种循环,也就是用自己来解释自己,这种情况在编译原理中称为左循环LR (Left recursive).

这里,大家可能会发现语法定义的一些问题:

1.    右边有两组解析规则,用右边替换左边时,到底选取哪一组?

2.    左边的符号(statements) 出现在右边的规则中,替换的话就会出现死循环:

statements(buffer) {

expression(buffer);

statements(buffer); //此处将导致循环调用

}

这些问题,在后面我们再加以解决,暂且先继续给出余下的语法规则:

Expression ->expression + term | term;

term -> term* factor | factor

factor ->NUMBER | (expression)

看到这,大家会不会有点恼火,为什么这组语法规则能够用来解析一组算术表达式? 你是根据什么办法给出这组规则的?我以前在读编译原理的相关书籍时也会有这些郁闷和困惑,都不知道作者是怎么想到的,书中解释有含糊不清,直到现在我才明白,在学习的早期,有些地方你必须先囫囵吞枣,带着疑惑看到后面,你自然就会明白,所以大家在此先无需理解我是怎么给出这组语法定义的,先记着,然后把代码跑一边,看看结果,有个感性认识,在后续文章中,我会慢慢解释,如何根据要编译的文本,给出相应的语法规则。

现在我们来解决前面提到的两个问题, ->右边有两组替换规则,在语法解析的时候,如何决定选取哪一组?在编译原理的实现技巧中,有一种方法叫look ahead, 举个例子,对规则:

statements ->expression; | expression; statements

替换时用“| “ 左边的 expression; 还是右边的expression; statements呢,办法是当我们在程序中,读到第一个分号”;” 时,再继续读入下一个符号,如果继续读入符号时,返回的是输入的结束标志(EOI) 那么我们就使用“|” 左边的规则来替换,如果继续读入的符号不是结束标志,那意味着分号后边还有需要解析的信息,那就使用“|” 右边的替换规则,这种技巧在语法解析中就叫look ahead.

如何解决语法规则中出现循环调用呢?我们需要对语法规则做一些更改,更改原理在以后的文章中再做进一步的解释,请大家再囫囵吞枣一次,我知道吃东西不消化会对胃不好,黄天在上,这里是最后一次这样,请大家原谅,修改后的语法规则如下:

1. statements -> ‘空‘ | expression; statements

2. expression-> term expression'

3. expression'-> +term expression' | ‘空‘

4. term -> factor  term'

5. term' -> * factor  term' | ‘空‘

6. factor -> number | (expression)

这组修改后的语法规则比修改前更加难以理解,但能确保,这组规则不会出现修改前那样导致解析死循环。语法规则中的’空’ 表示结束,什么都不做。例如如果我们输入一个空字符串””给语法解析器,那么规则1中就以”空”来解析输入的空字符串,其结果就是程序什么都不做,直接返回,在程序中”空” 相当于return语句。

我们用表达式:1 + 2 ; 看看语法规则形成的解析树是怎样的:

用java实现编译器-算术表达式及其语法解析器的实现

在下面给出的视频中,我将对代码实现进行详细的讲解,同时通过运行代码,让大家体会到执行的效果,以帮助大家对语法解析的原理和实现有深一步的认识,大家把代码下下来,对着视频中的步骤运行一次,便可得知一个语法解析器的“五脏六腑"是如何组合运行的。由于视频中会出现代码解析,如果画面分辨率过低,可能无法看清代码,请大家在观看视频时将分辨率设置成高清或1080P。

由于csdn无法插入视频,我将视频地址给出如下:

http://v.youku.com/v_show/id_XMTQ4MTI2NzgyMA==.html?firsttime=0&from=y1.4-2

用java实现编译器-算术表达式及其语法解析器的实现的更多相关文章

  1. 使用 java 实现一个简单的 markdown 语法解析器

    1. 什么是 markdown Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用.看到这里请不要被「标记」.「语言」所迷惑,Markdown 的 ...

  2. Boost学习之语法解析器--Spirit

    Boost.Spirit能使我们轻松地编写出一个简单脚本的语法解析器,它巧妙利用了元编程并重载了大量的C++操作符使得我们能够在C++里直接使用类似EBNF的语法构造出一个完整的语法解析器(同时也把C ...

  3. Anrlr4 生成C++版本的语法解析器

    一. 写在前面 我最早是在2005年,首次在实际开发中实现语法解析器,当时调研了Yacc&Lex,觉得风格不是太好,关键当时yacc对多线程也支持的不太好,接着就又学习了Bison&F ...

  4. 在.NET Core中使用Irony实现自己的查询语言语法解析器

    在之前<在ASP.NET Core中使用Apworks快速开发数据服务>一文的评论部分,.NET大神张善友为我提了个建议,可以使用Compile As a Service的Roslyn为语 ...

  5. 语法解析器续:case&period;&period;when&period;&period;语法解析计算

    之前写过一篇博客,是关于如何解析类似sql之类的解析器实现参考:https://www.cnblogs.com/yougewe/p/13774289.html 之前的解析器,更多的是是做语言的翻译转换 ...

  6. 手写token解析器、语法解析器、LLVM IR生成器(GO语言)

    最近开始尝试用go写点东西,正好在看LLVM的资料,就写了点相关的内容 - 前端解析器+中间代码生成(本地代码的汇编.执行则靠LLVM工具链完成) https://github.com/daibinh ...

  7. &lbrack;java&rsqb;输入一个算术表达式输出结果

    动手有益. 输入一个表达式,没有括号,数字小于0-9之间,输出计算结果,所有的中间结果化为整形.例如:  输入:3+8×2/9-2  输出:2 /** * input a calculate stri ...

  8. 【读书笔记】-【编程语言的实现模式】-【LL&lpar;1&rpar;递归下降的语法解析器】

    形如:[a,b,c] [a,[b,cd],f] 为 嵌套列表 其ANTLR文法表示: list :'[' elements ']'; // 匹配方括号 elements : elements (',' ...

  9. 利用栈实现算术表达式求值&lpar;Java语言描述&rpar;

    利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...

随机推荐

  1. golang print struct with key

    https://play.golang.org/p/YMfpuluzef 判断结构体是否为空 打印带attribute(key) 的结构体 package main import ( "fm ...

  2. echars3&period;0 柱状图大小设置

    { name:'百度', type:'bar', barWidth : 10, stack: '搜索引擎', data:[620, 732, 701, 734, 1090, 1130, 1120] } ...

  3. iOS NavigaitonController详解(code版)

    参考文章:http://blog.csdn.net/totogo2010/article/details/7681879,参考了这篇文章,写的超级好,自己他的基础上加上了自己的理解. 下面的图显示了导 ...

  4. 配置Nginx作为web server详解

    keepalived+nginx:实现高可用 corosync+ngin Nginx: 轻量级的反向代理 web服务器 处理静态文件,索引文件以及自动索引,打开文件描述缓存 使用缓存加速反向代理,简单 ...

  5. JAVA&lowbar;SE基础——64&period;StringBuffer类 ①

     字符串特点:字符串是常量:它们的值在创建之后不能更改 字符串的内容一旦发生了变化,那么马上会创建一个新的对象. 注意:字符串的内容不适宜频繁修改,因为一旦修改马上就会创建一个新的对象. publ ...

  6. ArcGIS JS Api 4&period;x修改三维球背景技巧

        通过修改scenceview.js中tileBackground和defaultTileBackground中的png的base64编码就可以达到要求. 4.8中通过修改scenceview. ...

  7. Introduction tp Operating System

    一.虚拟化 为了让用户告诉操作系统如何利用虚拟机功能,OS提供给应用程序一些接口——系统调用,也会说提供了一个标准库. CPU通过分时达到虚拟化. 内存物理模型只是一个字节数组,读写修改需要制定地址. ...

  8. SpringBoot 2&period;x 集成QQ邮箱、网易系邮箱、Gmail邮箱发送邮件

    在Spring中提供了非常好用的 JavaMailSender接口实现邮件发送,在SpringBoot的Starter模块中也为此提供了自动化配置. 项目源码已托管在Gitee-SpringBoot_ ...

  9. &lbrack;硬件&rsqb;Robot运动控制

    思考问题:机器人运动控制如何与图形界面交互? 不得不说,先锋机器人的软件做的真不怎么样.图形界面交互用户体验很差. 现在我遇到一个很现实的问题:SLAM需要采集激光数据和机器人的位姿,同时我还要再这个 ...

  10. ASP&period;NET Core 中间件 中间件(Middleware)和过滤器(Filter)的区别

    https://www.cnblogs.com/savorboard/p/5586229.html 前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的, ...