编译器开发系列--Ocelot语言5.表达式的有效性检查
2016-12-21 19:39
232 查看
本篇将对“1=3”“&5”这样无法求值的不正确的表达式进行检查。
将检查如下这些问题。
●为无法赋值的表达式赋值(例:1 = 2 + 2)
●使用非法的函数名调用函数(例:"string"("%d\n", i))
●操作数非法的数组引用(例:1[0])
●操作数非法的成员引用(例:1.memb)
●操作数非法的指针间接引用(例:1->memb)
●对非指针的对象取值(例:*1)
●对非左值的表达式取地址
具体例子以及问题的检测方法如表10.1所示,其中包括了刚才列举的问题。
非指针类型取值操作的检查
获取非左值表达式地址的检查
隐式的指针生成
单个数组类型或函数类型的变量表示数组或函数的地址。例如,假设变量puts 的类型为函数类型(一般称为函数指针),那么puts 和&puts 得到的值是相同的。
puts 是指向函数的指针,因此它的取值运算*puts 的结果是函数类型,但这样又会隐式地转换为指向函数的指针。*puts 还是指向函数的指针,因此仍然可以进行取值运算,仍然会转换为指向函数的指针。像这样可以无限重复下去。所以C 语言中“&puts”“puts”“*puts”“**puts”“***puts”的值都是相同的。
将检查如下这些问题。
●为无法赋值的表达式赋值(例: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语言6.静态类型检查
- 编译器开发系列--Ocelot语言4.类型定义的检查
- 编译器开发系列--Ocelot语言2.变量引用的消解
- 编译器开发系列--Ocelot语言1.抽象语法树
- 编译器开发系列--Ocelot语言3.类型名称的消解
- 编译器开发系列--Ocelot语言7.中间代码
- 自己动手开发编译器(二)正则语言和正则表达式
- 开发自制语言Monkey编译器:实现复杂算术表达式的执行
- XPO 第三方控件学习(DevExpress Persistent Object )系列--- 其他(session,事务,有效性检查...
- SharePoint 2007 开发系列(20) SharePoint 多语言
- VSX开发之语言服务系列(8)——智能感知
- 自己动手开发编译器(六)上下文无关语言和文法
- 自己动手开发编译器(五)miniSharp语言的词法分析器
- cygwin跨平台移植开发系列1--在cygwin下使用VC编译器
- 谈谈程序设计语言、编译器和开发环境之间的关系
- VSX开发之语言服务系列(9)——插曲MPPG
- VSX开发之语言服务系列(6)——Lex和Yacc
- Spring3开发实战 之 第七章:Spring3的表达式语言
- VSX开发之语言服务系列(4)——从空Package开始构建语言服务框架
- VS2010开发体验系列之二 - 语言C#4.0