说起这次的语义分析,不得不说的是我的重大的改变。上一次的语法分析是利用了预测分析法来实现的,经过多方考证,发现用预测分析法的语法分析器基础来实现语义分析的困难重重,例如在语法指导翻译的时候那个栈的变化和各种属性的传递就已经让我头晕脑胀了。无奈之下,只好重写语法分析,用了递归下降来实现语法分析进而实现我的语义分析。

使用递归下降的最大好处就是思路特别清晰,一旦开始写了,就特别明确接下来要做什么。这就是我选择递归下降的原因。

简单的说一下,递归下降语法分析的思想。一个递归下降的语法分析程序由一堆的过程组成,每个非终结符号都有一个对应的过程。程序的执行从开始符号对应的过程开始,如果这个过程的过程体扫描了整个输入串,它就停止执行,并且语法分析结束。

而要在递归下降语法分析的过程中进行翻译:在语法分析中对应于每个非终结符A都有一个函数A,在函数A的函数体中,可以进行语法分析和处理继承属性和综合属性。

1.决定用哪一个产生式来展开A

2.当需要读入一个终结符号时,在输入中检查这些符号是否出现。

3.在局部变量中保存所有必要的属性值。这些属性可以用来计算产生式体中的非终结符号的继承属性,或产生式左部的非终结符号的综合属性。

4.调用对应于被选定产生式体中的非终结符号的函数,向他们提供正确的参数。

实现语义分析很关键的一点是语义动作的书写。我的语义动作都嵌入到了每个非终结符所对应的类中的某些方法来实现的。

例如在类Expression中有如下几个方法:

/**

* 返回一个可以成为某个三地址指令的右部

* @return 一个项

*/

public Expression gen() {

return this;

}

/**

* 把一个表达式规约成一个地址

* @return 一个地址

*/

public Expression reduce(){

return this;

}

/**

* 调用jumps()方法,生成跳转代码

* @param t true出口

* @param f false出口

*/

public void jumping(int t,int f){

jumps(toString(),t,f);

}

/**

* 生成跳转代码

* @param string

* @param t

* @param f

*/

public void jumps(String string,int t,int f){

if (t != 0 && f != 0){

emit("if " + string + " goto L" + t);

emit("goto L"+ f);

}else if(t != 0){

emit("if " + string + " goto L" + t);

}else if (f != 0){

emit("iffalse " + string + " goto L" + f);

}

}

在Expression的子类中通常会实现gen()方法和reduce()方法。

而在类Or中,也有jumps()方法与此相关,如下:

/**

* 为布尔表达式B = B1 || B2生成跳转代码

* 如果B1为真,那么B必然为真,所以B1的true出口是B的true出口

* 如果B1为假,那么B1的false出口则是B2的第一条指令

* B2的true出口和false出口与B的相同

*/

public void jumping(int t,int f) {

int label = t != 0 ? t : newLabel();

expression1.jumping(label, 0);

expression2.jumping(t, f);

if (t == 0){

label(label);

}

}

在类And中,也有也有jumps()方法与此相关,如下:

/**

* 为布尔表达式B = B1 & B2生成跳转代码

* 如果B1为假,那么B必然为假,所以B1的false出口是B的false出口

* 如果B1为真,那么B1的true出口则是B2的第一条指令

* B2的true出口和false出口与B的相同

*/

public void jumping(int t,int f) {

int label = f != 0 ? f : newLabel();

expression1.jumping(0,label);

expression2.jumping(t, f);

if (f == 0){

label(label);

}

}

还有一些方法,如label()和newLabel()方法也都与语义动作相关,newLabel()方法是用来生成一个新的标号,label()方法是用给接下来的一句三地址码标号。

关于符号表的处理:

我的符号表是一个HashMap,其定义是HashMap。其中key是变量名,value是一个ID类的对象。在ID类中,保存了变量的名字,类型,类型的长度,偏移量,入口地址等多个属性。如果变量是一个数组,则包含更加复杂的属性,如数组元素个数,数组元素的类型等等。

在变量声明阶段,程序每读到一个新的声明语句,都会将其加入到符号表中。当在赋值语句中使用这些变量的时候,首先从符号表中寻找是否已经存在这样一个已经被声明过的变量,否则不可使用。

我的测试程序如下:

根据这个测试程序,生成的符号表如下:

简要的说一下我的语义分析可识别的错误类型:

1.if或while的条件必须是布尔语句

2.变量必须要先声明后使用

3.相同变量名的变量不得重复声明

好像主要能识别的错误就是以上的三类了,其中还要说明的一点是,我的语义分析支持简单的类型转换,例如把float类型的值赋给int型变量是不会出错的。

总体来说,这次的语义分析实现的不大好。没有坚持用预测分析的方法来实现语义分析一直是我的一个遗憾,却转向较为简单递归下降的实现。并且在递归下降的实现中仍然有缺陷,例如不支持函数调用,符号表对于函数没有处理,指针运算的不支持,数组赋值只适用于a[i] = x这类的赋值,错误处理不完备等等。

最后,语义分析结果(仍然是针对上述测试程序)如下:

用c语言编译递归下降翻译器,Java实现C语言语义分析(递归下降)相关推荐

  1. java语言 编译原理_【Java学习】深入分析Java的编译原理

    在<Java代码的编译与反编译>中,有过关于Java语言的编译和反编译的介绍.我们可以通过javac命令将Java程序的源代码编译成Java字节码,即我们常说的class文件.这是我们通常 ...

  2. java调用c语言编辑器_如何用java调用c语言编译器实现在线编译c语言?

    要在java中调用c语言的库,需要使用Java提供了JNI. 举例说明 在c语言中定义一个 void sayHello()函数(打印Hello World);然后在Java中调用这个函数显示Hello ...

  3. c语言不会可以学好java吗_C语言一定要学好吗?

    编程语言其实是一个很初级的工具,但是你又必须熟练的掌握它,学懂一门编程语言就好像学会了写字,但是会写字的人不见得会写文章,而会写文章又不见的写得好.可是如果你不会写字,那就一定写不出文章来. 首先,在 ...

  4. java语言与其他语言的区别是_Java语言特点有哪些?Java区别其他语言特点详解

    Java语言特点有哪些?Java区别其他语言特点详解 Java是目前最流行的编程语言之一,那你知道为什么Java这么火吗?相比其他编程语言,Java的特点又有哪些呢?跟着小编一起来了解一下吧. 一.简 ...

  5. java跳出递归_在Java项目中如何跳出递归循环

    在Java项目中如何跳出递归循环 发布时间:2020-11-25 17:16:07 来源:亿速云 阅读:114 作者:Leah 今天就跟大家聊聊有关在Java项目中如何跳出递归循环,可能很多人都不太了 ...

  6. Scala语言编译之后生成的Java代码解读

    Created by Wang, Jerry on Oct 08, 2015 看个Scala的例子: package method /*** @author I042416*/ class boole ...

  7. c语言编译开头,#includestdio.h,为什么C语言代码开头都有这一行?

    作者 闫小林 白天搬砖,晚上做梦.我有故事,你有酒么? #include是在程序编译之前要进行处理的的内容,因此也称为预处理命令. 先介绍下include,include是一个计算机专业术语,指C/C ...

  8. 单片机c语言编译软件6,eUIDE下载-单片机c语言编译器 v1.07.32.23 官方版 - 安下载...

    eUIDE是一款专业的单片机c语言编译器,EM78系列集成开发环境是面向项目的ELAN EM78系列微控制器的开发工具,它包括UICE开发在线仿真器和eUIDE软件工具:eUIDE是基于PC端的UIC ...

  9. golang语言编译的二进制可执行文件为什么比 C 语言大(转载)

    最近一位朋友问我"为什么同样的hello world 入门程序"为什么golang编译出来的二进制文件,比 C 大,而且大很多.我做了个测试,来分析这个问题.C 语言的hello ...

最新文章

  1. Spring2.5注释驱动与基于注释的MVC
  2. 数据结构源码笔记(C语言):线性表的单链表示
  3. boost::geometry::ring_type用法的测试程序
  4. 【数据结构与算法】之深入解析“游乐园的迷宫”的求解思路与算法示例
  5. va_list和vsnprintf、getopt
  6. android显示网络图片控件,Android控件之ImageView(二)
  7. 网站登录JWT的实现
  8. VB.NET工作笔记005---用visual studio2017 编写WCF vb.net webservice
  9. PJzhang:经典子域名爆破工具subdomainsbrute
  10. SQLite连接C#笔记
  11. C# 未能加载文件或程序集“ Newtonsoft.Json” Json格式错误
  12. java通字乱码_Java解决通信过程的中文乱码的问题
  13. 对 Sea.js 进行配置 seajs.config
  14. 阿里P9谈程序员——程序员的青春饭
  15. 《结网》《人人都是产品经理》对比
  16. cygwin装linux系统,给cygwin安装命令package
  17. python爬取晋江文学城_晋江文学城[本站宗旨]
  18. SEO不能不知道的首页关键词策略
  19. 【一句日历】2019年9月
  20. python倒数切片_python切片

热门文章

  1. 端到端声源分离研究:现状、进展和未来
  2. IOS6旋转屏、锁定横屏的实现(兼容IOS5)
  3. jQuery修改CSS伪元素属性
  4. 8月19日星期一 恒指 美原油 美黄金 走势分析
  5. 猜一个1~100的数字
  6. Linux-USB鼠标驱动
  7. EGE示例程序——分形
  8. php rssi计算公式,rssi基本知识和计算
  9. 周集中报告 | 气候变暖如何影响微生物的多样性?(24号上午9:30)
  10. 【原创】系统设计之系统时序图表达