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

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

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

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

  1. /*非指针类型取值操作的检查
  2. * 表示取值运算符(*)的DereferenceNode的处理。
  3. * 该方法检查取值运算符的操作数的类型是否为指针。
  4. */
  5. // #@@range/DereferenceNode{
  6. public Void visit(DereferenceNode node) {
  7. /*
  8. * 首先,通过super.visit(node) 调用基类Visitor 的方法遍历操作数(node.expr())
  9. (即检查操作数)。
  10. */
  11. super.visit(node);
  12. /*
  13. * 接着,调用操作数node.expr() 的isPointer 方法,检查操作数的类型是否是指针,
  14. 即检查是否可以进行取值。如果无法取值,则调用undereferableError 方法输出编译错误。
  15. */
  16. if (! node.expr().isPointer()) {
  17. undereferableError(node.location());
  18. }
  19. /*
  20. * 最后,调用handleImplicitAddress 方法对数组类型和函数类型进行特别处理。该处
  21. 理还和接下来AddressNode 的处理相关,
  22. */
  23. handleImplicitAddress(node);
  24. return null;
  25. }

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

  1. /*获取非左值表达式地址的检查
  2. * 检查操作数是否为左值。表示地址运算符的AddressNode 的处理
  3. */
  4. // #@@range/AddressNode{
  5. public Void visit(AddressNode node) {
  6. super.visit(node);
  7. /*
  8. * 首先对node.expr() 调用isLvalue 方法,检查&expr 中的expr 是否是可以进行取
  9. 址操作的表达式。
  10. ExprNode#isLvalue 是检查该节点的表达式是否能够获取地址的方法。
  11. */
  12. if (! node.expr().isLvalue()) {
  13. semanticError(node.location(), "invalid expression for &");
  14. }
  15. /*
  16. * 剩余的语句用于确定AddressNode 的类型。通常node.expr().isLoadable() 会
  17. 返回true,即执行else 部分的处理。&expr 的类型是指向expr 类型的指针,因此指向
  18. node.expr().type() 的指针类型可以作为节点整体的类型来使用。
  19. */
  20. Type base = node.expr().type();
  21. /*
  22. * 在将puts 的类型设置为指向函数的指针的同时,还必须将&puts 的类型也设置为指向函
  23. 数的指针。
  24. node.expr() 的类型是数组或函数的情况下进行特别处理,使得&puts 的类型
  25. 和puts 的类型相一致。
  26. */
  27. if (! node.expr().isLoadable()) {
  28. // node.expr.type is already pointer.
  29. node.setType(base);
  30. }
  31. else {
  32. node.setType(typeTable.pointerTo(base));
  33. }
  34. return null;
  35. }

隐式的指针生成

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

  1. /*
  2. * handleImplicitAddress 方法将数组类型或函数类型转换为了指向
  3. 数组或函数类型的指针,即隐式地生成指针类型。
  4. */
  5. private void handleImplicitAddress(LHSNode node) {
  6. if (! node.isLoadable()) {
  7. Type t = node.type();
  8. if (t.isArray()) {
  9. // int[4] ary; ary; should generate int*
  10. node.setType(typeTable.pointerTo(t.baseType()));
  11. }
  12. else {
  13. node.setType(typeTable.pointerTo(t));
  14. }
  15. }
  16. }

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. Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数

    上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...

  2. Jexus 5.8.2 正式发布为Asp.Net Core进入生产环境提供平台支持

    Jexus 是一款运行于 Linux 平台,以支持  ASP.NET.PHP 为特色的集高安全性和高性能为一体的 WEB 服务器和反向代理服务器.最新版 5.8.2 已经发布,有如下更新: 1,现在大 ...

  3. ExtJS 4.2 组件介绍

    目录 1. 介绍 1.1 说明 1.2 组件分类 1.3 组件名称 1.4 组件结构 2. 组件的创建方式 2.1 Ext.create()创建 2.2 xtype创建 1. 介绍 1.1 说明 Ex ...

  4. JQuery easyUI DataGrid 创建复杂列表头(译)

    » Create column groups in DataGrid The easyui DataGrid has ability to group columns, as the followin ...

  5. 【NLP】蓦然回首:谈谈学习模型的评估系列文章(一)

    统计角度窥视模型概念 作者:白宁超 2016年7月18日17:18:43 摘要:写本文的初衷源于基于HMM模型序列标注的一个实验,实验完成之后,迫切想知道采用的序列标注模型的好坏,有哪些指标可以度量. ...

  6. Linux平台 Oracle 10gR2(10.2.0.5)RAC安装 Part2:clusterware安装和升级

    Linux平台 Oracle 10gR2(10.2.0.5)RAC安装 Part2:clusterware安装和升级 环境:OEL 5.7 + Oracle 10.2.0.5 RAC 3.安装Clus ...

  7. 【开源毕设】一款精美的家校互动APP分享——爱吖校推 [你关注的,我们才推](持续开源更新3)附高效动态压缩Bitmap

    一.写在前面 爱吖校推如同它的名字一样,是一款校园类信息推送交流平台,这么多的家校互动类软件,你选择了我,这是我的幸运.从第一次在博客园上写博客到现在,我一次一次地提高博文的质量和代码的可读性,都是为 ...

  8. 使用RequireJS并实现一个自己的模块加载器 (一)

    RequireJS & SeaJS 在 模块化开发 开发以前,都是直接在页面上引入 script 标签来引用脚本的,当项目变得比较复杂,就会带来很多问题. JS项目中的依赖只有通过引入JS的顺 ...

  9. UVa 122 Trees on the level

    题目的意思: 输入很多个节点,包括路径和数值,但是不一定这些全部可以构成一棵树,问题就是判断所给的能否构成一棵树,且没有多余. 网上其他大神已经给出了题目意思:比如我一直很喜欢的小白菜又菜的博客 说一 ...

  10. [Django]用户权限学习系列之Permission权限基本操作指令

    若需建立py文件进行测试,则在文件开始加入以下代码即可 #coding:utf-8 import os os.environ.setdefault("DJANGO_SETTINGS_MODU ...