zoukankan      html  css  js  c++  java
  • 关于语义分析的简单总结

    转自:https://blog.csdn.net/wyt734933289/article/details/53956151

    预备知识
    编译器的前端是由三个模块和两个核心数据结构(记号流,抽象语法树)组成的,
    编译器处于一个流水线的结构,阶段无关性(只考虑把每一个模块的输入输出)
    语义分析只依赖于前一阶段的抽象语法树
    语义分析也称为类型检查。上下文相关分析。负责检查程序(抽象语法树)的上下文相关的属性:
    变量在使用前先声明
    每个表达式都有何时的类型
    函数调用和函数的定义一致
    ………………
    举个例子
    void f(int *p)
    {
    X += 4:
    Cal(X);
    break;
    }
    1
    2
    3
    4
    5
    6
    编译器报出x,cal没有定义的错误,没有找到循环的错误,这就是所谓的上下文相关,不仅仅是检查当前

    所以语义分析要完成的工作就是针对给定的一段代码,去找出所有的语义错误,如果出错了,要给出清晰的诊断信息反馈给程序员,程序员根据出错信息改错

    语义分析器接受一个抽象语法树的输入,这棵树必然满足语法正确,还有一个输入,就是程序语言的合法规则(表明什么是合法的,什么是非法的),输出Yes或者NO,如果是Yes,那么就要产生中间代码(这个阶段过后,程序就不应包含任何语法和语义错误),如果是NO,就要给出错误信息

    如何定义程序语言的语义?
    传统上,大部分的程序设计语言都采用自然语言来表达程序语言的语义
    例如,对于“+”运算
    要求左右操作数都必须是整形数,如e1 + e2, 对于语法分析,+号两边操作数是不管的,而语义分析就要检查是否为整形数
    这个自然语言是我们学习一门语言的所需要的,比如一本编程书上

    但编译器的实现者必须对语言中的语义规定有全面的理解,比如加号两边可以是浮点数和整形数

    那么如何能够正确高效地实现?
    给出下面文法举个例子
    定义加法左右两边只能是整数

    E->N
    | true
    | false
    | E + E
    | E && E
    1
    2
    3
    4
    5
    类型合法的程序

    3 + 4
    False && true
    1
    2
    类型不合法的程序

    3 + true
    True + false
    1
    2
    对这个语言,语义分析的任务是:对给定一个表达式e,写一个函数check(e)
    返回一个表达式e的类型;若类型不合法,则报错
    如3 + 4这个表达式返回int, 3+true这个表达式就会出错

    下面对应抽象语法树的后序遍历的伪代码

    enum type {int, bool};
    enum type check (exp_t e)
    {
    switch(e->kind)
    case exp_int: return int;
    case exp_true: return true;
    case exp_false: return false;
    case exp_add: t1 = check(e->left);//左
    t2 = check(e->right);//右
    if(t1 != int || t2 != int) //根
    perror(“error”);
    else return int;
    case exp_and: t1 = check(e->left);
    t2 = check(e->right);
    if(t1 != bool || t2 != bool)
    perror(“error”);
    else return bool
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    符号表
    对于类型检查的有一个很重要的数据结构,符号表(key, value)
    符号表:
    用来存储程序中的变量相关信息
    类型
    作用域
    访问控制信息(如pubic ,private之类的,文件之间的访问)
    必须非常高效,因为程序中的变量规模会很大
    如int x, bool y
    table
    x:int …..
    y:bool ….

    符号表要有创建,插入,查找的接口功能,具体实现和所选择语言相关
    为了高效,可以使用哈希表等数据结构来实现呢符号表,
    为了节约空间,也可以使用红黑树等平衡树

    语义分析可能会出现的共性问题:
    类型相容性:
    类型检查问题往往归结为判断两个类型是否相等t1==t2? 在实际的语言中,这往往是个需要谨慎处理的复杂问题
    如:
    对采用名字相等的语言,可直接比较
    对采用结构相等的语言(如结构体),需要递归比较比较各个域
    面向对象的继承,需要维护类型间的继承关系
    错误诊断:编译器要报出语义错误,这些信息要很清晰地给出
    (1) 要给出极可能准确的错误信息
    (2) 要给出尽可能多的错误信息
    (3) 要给出尽可能准确的出错位置,程序代码的位置要从缱绻保留并传递归来(即词法分析的行号信息要传递到语义分析)
    代码翻译:生成中间表示(或目标代码),现代编译器中的语义分析模块,除了做语义分析外,还要负责生成中间代码或目标代码,代码生成的过程也同样是对树的某种遍历
    因此,语义分析往往是编译器中最庞大(代码量)最复杂(需要很多分析)的模块

  • 相关阅读:
    IplImage, CvMat, Mat 的关系
    neon memory copy
    基于v4l2的webcam应用, 本地预监
    makefile写法实例
    Ubuntu 12.04 使用Eclipse搭建C/C++编译环境
    xapp1167与TRD14.4 关系
    v3学院带你一次性认清UART、RS-232、RS-422、RS-485的区别
    v3学院教你学习-task和function的异同
    寒假参加V3
    FPGA培训学习心得
  • 原文地址:https://www.cnblogs.com/jacksplwxy/p/10217530.html
Copyright © 2011-2022 走看看