编译器开发系列--Ocelot语言5.表达式的有效性检查
本篇将对“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.表达式的有效性检查的更多相关文章
- 编译器开发系列--Ocelot语言1.抽象语法树
从今天开始研究开发自己的编程语言Ocelot,从<自制编译器>出发,然后再自己不断完善功能并优化. 编译器前端简单,就不深入研究了,直接用现成的一款工具叫JavaCC,它可以生成抽象语法树 ...
- 编译器开发系列--Ocelot语言7.中间代码
Ocelot的中间代码是仿照国外编译器相关图书Modern Compiler Implementation 中所使用的名为Tree 的中间代码设计的.顾名思义,Tree 是一种树形结构,其特征是简单, ...
- 编译器开发系列--Ocelot语言6.静态类型检查
关于"静态类型检查",想必使用C 或Java 的各位应该非常熟悉了.在此过程中将检查表达式的类型,发现类型不正确的操作时就会报错.例如结构体之间无法用+ 进行加法运算,指针和数值之 ...
- 编译器开发系列--Ocelot语言2.变量引用的消解
"变量引用的消解"是指确定具体指向哪个变量.例如变量"i"可能是全局变量i,也可能是静态变量i,还可能是局部变量i.通过这个过程来消除这样的不确定性,确定所引用 ...
- 编译器开发系列--Ocelot语言3.类型名称的消解
"类型名称的消解"即类型的消解.类型名称由TypeRef 对象表示,类型由Type 对象表示.类型名称的消解就是将TypeRef 对象转换为Type 对象. TypeResolve ...
- 编译器开发系列--Ocelot语言4.类型定义的检查
这里主要介绍一下检查循环定义的结构体.联合体.是对成员中包含自己本身的结构体.联合体进行检查.所谓"成员中包含自己本身",举例来说,就是指下面这样的定义. struct point ...
- iOS开发系列--Swift语言
概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...
- iOS开发系列--C语言之基础知识
概览 当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: C语言 OC基础 IOS开发(iphone/ipad) Swift ...
- iOS开发系列--C语言之数组和字符串
概览 数组在C语言中有着特殊的地位,它有很多特性,例如它的存储是连续的,数组的名称就是数组的地址等.而在C语言中是没有String类型的,那么如果要表示一个字符串,就必须使用字符数组.今天主要就介绍如 ...
随机推荐
- 【疯狂造轮子-iOS】JSON转Model系列之二
[疯狂造轮子-iOS]JSON转Model系列之二 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇<[疯狂造轮子-iOS]JSON转Model系列之一> ...
- 加深一下BlockingQueue的认识
认识BlockingQueue BlockingQueue是一种可以阻塞线程的队列,java中对这种队列提供了方法抽象,BlockingQueue则是抽象的接口. add:添加元素到队列里,添加成功返 ...
- Summary of Critical and Exploitable iOS Vulnerabilities in 2016
Summary of Critical and Exploitable iOS Vulnerabilities in 2016 Author:Min (Spark) Zheng, Cererdlong ...
- hadoop 2.7.3本地环境运行官方wordcount
hadoop 2.7.3本地环境运行官方wordcount 基本环境: 系统:win7 虚机环境:virtualBox 虚机:centos 7 hadoop版本:2.7.3 本次先以独立模式(本地模式 ...
- JavaScript实现常用的排序算法
▓▓▓▓▓▓ 大致介绍 由于最近要考试复习,所以学习js的时间少了 -_-||,考试完还会继续的努力学习,这次用原生的JavaScript实现以前学习的常用的排序算法,有冒泡排序.快速排序.直接插入排 ...
- P2V之后的磁盘扩容新思路
背景: 原先的物理机环境多是若干块物理磁盘经过RAID卡进行了RAID5之后的虚拟磁盘组,这样我们在操作系统内看到的也就是一块完整的磁盘.我们会在上面进行分区,然后格式化后以便使用. Figure 1 ...
- 多线程条件通行工具——CountDownLatch
CountDownLatch的作用是,线程进入等待后,需要计数器达到0才能通行. CountDownLatch(int)构造方法,指定初始计数. await()等待计数减至0. await(long, ...
- 【Knockout.js 学习体验之旅】(3)模板绑定
本文是[Knockout.js 学习体验之旅]系列文章的第3篇,所有demo均基于目前knockout.js的最新版本(3.4.0).小茄才识有限,文中若有不当之处,还望大家指出. 目录: [Knoc ...
- Nova PhoneGap框架 第十章 开发环境
10.1 Visual Studio + ReSharper PhoneGap程序由HTML.CSS和JS编写而成,这3种语言的编写你都可以用记事本来完成,但显然效率比较低,出错的概率也比较大.一个强 ...
- 【css3笔记】---- 渐变的秘密
<CSS揭秘>这本书非常不错,充满了干货和惊喜.以下主要是关于使用渐变做出来的一些效果的笔记.请用最新的现代浏览器观看. 首先要回顾下一个css语句: linear-gradient([ ...