编译原理——CMM语义分析

这篇博客介绍了CMM语义分析的主要任务,包括确定类型、类型检查、识别含义和静态语义检查。通过遍历抽象语法树,实现了语义分析、生成符号表和输出结果。文章详细阐述了语法规则,如变量默认类型、类型转换、运算符处理等,并提供了代码实现,包括声明变量、赋值、条件语句、循环语句等关键步骤。
摘要由CSDN通过智能技术生成

一、语义分析要解决的问题
确定类型:确定标识符所关联的数据对象的数据类型。
类型检查:按照语言的类型规则,对运算及运算分量进行类型检查,必要时做出相应类型转换。
识别含义:根据程序设计语言的语义定义,确定各个构造部分组合后的含义,做出相应处理(生成中间代码或者目标代码)。
态语义检查:比如控制流检查,嵌套层数检查。

二、总体思路说明 

之前在语义分析阶段生成了抽象语法树,抽象语法树本身就是一种中间代码,因此现在将语义分析和解释执行结合在一起,对抽象语法树进行一次遍历,完成语义分析、生成符号表并输出最后结果。抽象语法树的遍历类似于属性文法树的遍历。

文法规定:

所有变量声明是默认为int类型,int类型默认值为0,double为0.0。

除了数组变量外,其余变量在声明是都可与赋值

在声明数组时,可以生成多维数组,维数没有限制,声明数组的形式为int[m][n] a; m和n都为常数

数组在声明后,默认每个值都为0或者0.0

赋值时,int类型可以自动转成double,double类型不能转换为int,true转换为int和double是默认为0或0.0,false默认为1或者1.0。

整数和实数都支持16进制类型数 如-0x14ae.123;

If和while语句中,如果类型为true或者值不为0.0或者0都视为满足条件

Break跳出最近的循环

Read语句用于从命令读取数值赋值给变量

Write语句用于输出expr的值,可以是变量、常数或者和表达式

三、实现代码(代码比较长为了不破坏结构将代码部分字体放小,可以放大看)

1、之前代码完善

之前在声明变量时,如果用int a,b,c;声明语句时,生成语法树的顺序会发生改变,对语义分析会产生影响,因此对varDeclare部分进行修改,使顺序正确。

2、主要类型说明

在实现过程中,新建了三个类:

Record类:记录着声明的变量的信息

symbolTable类:符号表,里面有两个表,一个是table表,记录所有的声明的变量,一个是arrayTable,记录所有数组的声明。符号表中存储着Record。符号表的结构是arrarList,而每个内容是record,record里面有一个next属性指向同名的前一个record,内层的声明的变量会取代外层声明的,类似于杂凑表结构。


Value类:返回表达式计算的结果,包括值和类型

类结构如下

public class Record implements Cloneable {
    public static final int intType=0;//数据类型
    
public static final int doubleType=1;
    Token name;//变量名,记录为tokem便于以后报错
    
ArrayList<Integer> arrayNum;//数组类型变量的维度大小
    
private int type;
    private int intValue;
    private double doubleValue;
    private int level;//变量的层数
    
private Record next;//链表指针

public class SymbolTable {
    private ArrayList<Record> table;//普通变量
    
private ArrayList<Record> arraytable;//数组变量

public class Value {
    public static final int intType=0;
    public static final int doubleType=1;
    public static final int trueType=2;
    public static final int falseType=3;
    private int type;//类型
    
private int intValue;//int型值
    
private double doubleValue;//double型值

3、program节点

创建executeProgram函数,初始化level,遍历指向每一个子树,对其调用executeStmt,执行完毕后清除level为0的符号表,并删除整个符号表

//执行executeProgram节点
public void executeProgram(TreeNode program)throws UnexpectedException{
    int level=0;//运算的层数
    
for(TreeNode node :program.getChildren()){
        executeStmt(node,level);
    }
    //倒着删除声明的数目的变量
    
symbolTable.deleteRecord(level);
    //删除整个table
    
symbolTable.clearTable();
}

4、stmt节点

创建executeStmt,根据treeNode的不同,调用不同的执行函数

//根据treeNode的不同,调用不同的执行函数
public void executeStmt(TreeNode stmtNode,int level)throws UnexpectedException{
    switch ( stmtNode.getType()) {
        case TreeNode.DECLARENODE:
            executeDeclare(stmtNode, level);
            break;
        case TreeNode.ASSIGNNODE:
            executeAssign(stmtNode, level);
            break;
        case TreeNode.IFNODE:
            executeIf(stmtNode,level);
            break;
        case TreeNode.WHILENODE:
            executeWhile(stmtNode,level);
            break;
        case TreeNode.STMTBLOCKNODE:
            executeStmtBlock(stmtNode, level);
            break;
        case TreeNode.WRITENODE:
            executeWrite(stmtNode, level);
            break;
        case TreeNode.READNODE:
            executeRead(stmtNode,level);
            break;
        case TreeNode.BREAKNODE:
            //是program的break,什么都不做
            
break;
    }
}

5、stmtBlock节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值