本篇将对“1=3”“&5”这样无法求值的不正确的表达式进行检查。

将检查如下这些问题。
●为无法赋值的表达式赋值(例:1 = 2 + 2)
●使用非法的函数名调用函数(例:"string"("%d\n", i))
●操作数非法的数组引用(例:1[0])
●操作数非法的成员引用(例:1.memb)
●操作数非法的指针间接引用(例:1->memb)
●对非指针的对象取值(例:*1)
●对非左值的表达式取地址

具体例子以及问题的检测方法如表10.1所示,其中包括了刚才列举的问题。

非指针类型取值操作的检查

    /*非指针类型取值操作的检查
* 表示取值运算符(*)的DereferenceNode的处理。
* 该方法检查取值运算符的操作数的类型是否为指针。
*/
// #@@range/DereferenceNode{
public Void visit(DereferenceNode node) {
/*
* 首先,通过super.visit(node) 调用基类Visitor 的方法遍历操作数(node.expr())
(即检查操作数)。
*/
super.visit(node);
/*
* 接着,调用操作数node.expr() 的isPointer 方法,检查操作数的类型是否是指针,
即检查是否可以进行取值。如果无法取值,则调用undereferableError 方法输出编译错误。
*/
if (! node.expr().isPointer()) {
undereferableError(node.location());
}
/*
* 最后,调用handleImplicitAddress 方法对数组类型和函数类型进行特别处理。该处
理还和接下来AddressNode 的处理相关,
*/
handleImplicitAddress(node);
return null;
}

获取非左值表达式地址的检查

    /*获取非左值表达式地址的检查
* 检查操作数是否为左值。表示地址运算符的AddressNode 的处理
*/
// #@@range/AddressNode{
public Void visit(AddressNode node) {
super.visit(node);
/*
* 首先对node.expr() 调用isLvalue 方法,检查&expr 中的expr 是否是可以进行取
址操作的表达式。
ExprNode#isLvalue 是检查该节点的表达式是否能够获取地址的方法。
*/
if (! node.expr().isLvalue()) {
semanticError(node.location(), "invalid expression for &");
}
/*
* 剩余的语句用于确定AddressNode 的类型。通常node.expr().isLoadable() 会
返回true,即执行else 部分的处理。&expr 的类型是指向expr 类型的指针,因此指向
node.expr().type() 的指针类型可以作为节点整体的类型来使用。
*/
Type base = node.expr().type();
/*
* 在将puts 的类型设置为指向函数的指针的同时,还必须将&puts 的类型也设置为指向函
数的指针。
node.expr() 的类型是数组或函数的情况下进行特别处理,使得&puts 的类型
和puts 的类型相一致。
*/
if (! node.expr().isLoadable()) {
// node.expr.type is already pointer.
node.setType(base);
}
else {
node.setType(typeTable.pointerTo(base));
}
return null;
}

隐式的指针生成

单个数组类型或函数类型的变量表示数组或函数的地址。例如,假设变量puts 的类型为函数类型(一般称为函数指针),那么puts 和&puts 得到的值是相同的。

    /*
* handleImplicitAddress 方法将数组类型或函数类型转换为了指向
数组或函数类型的指针,即隐式地生成指针类型。
*/
private void handleImplicitAddress(LHSNode node) {
if (! node.isLoadable()) {
Type t = node.type();
if (t.isArray()) {
// int[4] ary; ary; should generate int*
node.setType(typeTable.pointerTo(t.baseType()));
}
else {
node.setType(typeTable.pointerTo(t));
}
}
}

puts 是指向函数的指针,因此它的取值运算*puts 的结果是函数类型,但这样又会隐式地转换为指向函数的指针。*puts 还是指向函数的指针,因此仍然可以进行取值运算,仍然会转换为指向函数的指针。像这样可以无限重复下去。所以C 语言中“&puts”“puts”“*puts”“**puts”“***puts”的值都是相同的。

编译器开发系列--Ocelot语言5.表达式的有效性检查的更多相关文章

  1. 编译器开发系列--Ocelot语言1.抽象语法树

    从今天开始研究开发自己的编程语言Ocelot,从<自制编译器>出发,然后再自己不断完善功能并优化. 编译器前端简单,就不深入研究了,直接用现成的一款工具叫JavaCC,它可以生成抽象语法树 ...

  2. 编译器开发系列--Ocelot语言7.中间代码

    Ocelot的中间代码是仿照国外编译器相关图书Modern Compiler Implementation 中所使用的名为Tree 的中间代码设计的.顾名思义,Tree 是一种树形结构,其特征是简单, ...

  3. 编译器开发系列--Ocelot语言6.静态类型检查

    关于"静态类型检查",想必使用C 或Java 的各位应该非常熟悉了.在此过程中将检查表达式的类型,发现类型不正确的操作时就会报错.例如结构体之间无法用+ 进行加法运算,指针和数值之 ...

  4. 编译器开发系列--Ocelot语言2.变量引用的消解

    "变量引用的消解"是指确定具体指向哪个变量.例如变量"i"可能是全局变量i,也可能是静态变量i,还可能是局部变量i.通过这个过程来消除这样的不确定性,确定所引用 ...

  5. 编译器开发系列--Ocelot语言3.类型名称的消解

    "类型名称的消解"即类型的消解.类型名称由TypeRef 对象表示,类型由Type 对象表示.类型名称的消解就是将TypeRef 对象转换为Type 对象. TypeResolve ...

  6. 编译器开发系列--Ocelot语言4.类型定义的检查

    这里主要介绍一下检查循环定义的结构体.联合体.是对成员中包含自己本身的结构体.联合体进行检查.所谓"成员中包含自己本身",举例来说,就是指下面这样的定义. struct point ...

  7. iOS开发系列--Swift语言

    概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...

  8. iOS开发系列--C语言之基础知识

    概览 当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: C语言 OC基础 IOS开发(iphone/ipad) Swift ...

  9. iOS开发系列--C语言之数组和字符串

    概览 数组在C语言中有着特殊的地位,它有很多特性,例如它的存储是连续的,数组的名称就是数组的地址等.而在C语言中是没有String类型的,那么如果要表示一个字符串,就必须使用字符数组.今天主要就介绍如 ...

随机推荐

  1. Cocos2d Android 环境搭建

    1.在开始之前,需要先准备好资源如下,如果安卓开发环境有了直接装第3.4. 1.JDK      点击下载 (1.6) 2.ADT(已经自带Android SDK)点击下载 3.NDK 点击下载 4. ...

  2. RestTemplate发送请求并携带header信息

    1.使用restTemplate的postForObject方法 注:目前没有发现发送携带header信息的getForObject方法. HttpHeaders headers = new Http ...

  3. 13、零配置Struts2开发

    Convention 插件 从 Struts 2.1 开始, Struts 可以使用 Convention 插件来支持零配置: Convention 插件完全抛弃配置信息, 不仅不需要使用 strut ...

  4. Java 为值传递而不是引用传递

    ——reference Java is Pass by Value and Not Pass by Reference 其实这个问题是一个非常初级的问题,相关的概念初学者早已掌握,但是时间长了还是容易 ...

  5. ADO.NET编程之美----数据访问方式(面向连接与面向无连接)

    最近,在学习ADO.NET时,其中提到了数据访问方式:面向连接与面向无连接.于是,百度了一下,发现并没有很好的资料,然而,在学校图书馆中发现一本好书(<ASP.NET MVC5 网站开发之美&g ...

  6. C# 数组的交集、差集、并集

    C# 数组的交集.差集.并集 工作中经常会用这方面的知识来检查那些字段是必须输入的,那些是禁止输入. using System; using System.Collections.Generic; u ...

  7. 【干货分享】流程DEMO-离职流程

    流程名: 离职申请   流程相关文件: 流程包.xml WebService业务服务.xml WebService.asmx WebService.cs   流程说明: 流程中集成了webservic ...

  8. 【干货分享】流程DEMO-补打卡

    流程名: 补打卡申请 业务描述: 当员工在该出勤的工作日出勤但漏打卡时,于一周内填写补打卡申请. 流程相关文件: 流程包.xml 流程说明: 直接导入流程包文件,即可使用本流程 表单:  流程: 图片 ...

  9. 全网独家MongoDB Certified DBA Associate考试认证视频

    该视频意在让所有学员一次通过考试,避免重复考试而承担的巨额考试费用! 目前MongDB发展迅猛,有赶超mysql,和oracle看齐的苗头.在这个时候MongoDB也适时的推出了官方的认证考试&quo ...

  10. MySQL数据库罕见的BUG——Can't get hostname for your address

    在连接mysql jdbc时候,抛出了 com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communicat ...