编译器一日一练(DIY系列之语义分析)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

          代码地址:https://github.com/feixiaoxing/DIYCompiler

          语义分析一般是跟在语法分析后面进行的。语义分析的内容比较广。它的输入是语法树,并且在这过程当中会生成符号表,利用符号表的意义去检测语义是否正确。记录的符号表一般有全局变量、函数名、局部变量、参数名这些。此外,除了检测符号表之外,还会检测一些关键字的合理性,比如break外面是否有switch或者循环、continue是否外面有循环、goto是否真的有label与之匹配等等。总之,在中间代码生成前,所有的错误都要在这个阶段来被发现。

        如果大家读到这里,还是不能明白语义分析的话,接下来可以举几个例子来说明,分析下哪些语句是符合语法,但是不符合语义的,比如

        1)全局标识符重名;

        2)局部标识符重名;

        3)调用函数不存在;

        4)调用函数参数不匹配等等。

        当然,因为我们做的是四则运算,并且挑了一个除法来做运算。而除法里面最不能做的,就是除数不能等于0。基于这一点,我们就可以做一个简单的除法分析检测。

	public int check_value() {
	
		if(get_right_node() != null)
		{
			if( 0 == ((value_node)get_right_node()).get_value())
			{
				System.out.println("Div by Zero");
				return -1;
			}
		}
		
		if(get_left_node().get_node_type() == "/")
		{
			return ((div_node)(get_left_node())).check_value();
		}

		return 1;
	}

        因为检测的是一个除法运算,或者是连续除法运算,所以除数只能出现在右子树。检测的方法是自顶而下进行的。如check_value函数所示,首先检测右子树是否为空,如果不为空,并且发现除数为0,那么打印出来并且报警。接着继续检测左子树,判断左子树是否是递归语法树,如果是则继续检测递归语法树,反之则返回为1。整个流程还是比较清晰的。

        语义分析和语法分析基本是一一对应的,比如有一个if-statement的语法树,就会一个check_if_statement的语义分析。其他语法以此类推。

        说了这么多,大家还没有看到添加check_value后的效果是什么,我们可以编译测试下,

C:\Users\feixiaoxing\Desktop\DIYCompiler\day08>java Parse 1/0
Div by Zero
-1

C:\Users\feixiaoxing\Desktop\DIYCompiler\day08>java Parse 2/1/0
Div by Zero
-1

C:\Users\feixiaoxing\Desktop\DIYCompiler\day08>java Parse 2/0/1
Div by Zero
-1

C:\Users\feixiaoxing\Desktop\DIYCompiler\day08>java Parse 6/2/0/3/1
Div by Zero
-1

        从运行结果看,基本还是符合我们要求的。为了便于大家理解整个过程,这里给出完整的jj文件,可以实际操作动手做一下试验。

options {
    STATIC = false;
}
 
PARSER_BEGIN(Parse)
import java.io.*;

class node
{
	public node left;
	public node right;
	public String node_type;
	
	node() {this.left = this.right = null;}
	public void set_left_node(node left) { this.left = left;}
	public node get_left_node() { return this.left;}
	
	public void set_right_node(node right) { this.right = right;}
	public node get_right_node() {return this.right;}
	
	public void set_node_type(String node_type) {this.node_type = node_type;}
	public String get_node_type() {return this.node_type;}
}

class value_node extends node
{
	public int value;
	
	value_node() { set_node_type("value_node");}
	public int get_value() { return this.value;}
	public void set_value(int value) {this.value = value;}
}

class div_node extends node
{
	div_node() { set_node_type("/");}
	
	public int get_value() {
		int left = 0, right = 0;
		
		// get left node
		if(get_left_node().get_node_type() == "/")
		{
			left = ((div_node)get_left_node()).get_value();
		}
		else
		{
			left = ((value_node)get_left_node()).get_value();
		}

		// get right node
		if(get_right_node() == null)
		{
			return left;
		}
		else
		{
			right = ((value_node)get_right_node()).get_value();
			return left/right;
		}
	}

	// add semantic check
	public int check_value() {
	
		if(get_right_node() != null)
		{
			if( 0 == ((value_node)get_right_node()).get_value())
			{
				System.out.println("Div by Zero");
				return -1;
			}
		}
		
		if(get_left_node().get_node_type() == "/")
		{
			return ((div_node)(get_left_node())).check_value();
		}

		return 1;
	}
}

public class Parse {

    public static void main(String[] args) {
        for (String arg : args) {
            try {
                System.out.println(evaluate(arg).check_value());
            } catch (ParseException ex) {
                System.err.println(ex.getMessage());
            }
        }
    }
 
    public static div_node evaluate(String src) throws ParseException {
        Reader reader = new StringReader(src);
        return  new Parse(reader).expr();
    }
}
PARSER_END(Parse)
 
SKIP: { <[" ", "\t", "\r", "\n"]> }
TOKEN: {
    <INTEGER: (["0"-"9"])+>
}
 
div_node expr() throws NumberFormatException :
{
    Token a ;
    Token b ;
    div_node div;
}
{
	a = <INTEGER> 
	{ 
		value_node node_a = new value_node();
		node_a.set_value(Integer.parseInt( a.image ));
		
		div = new div_node();
		div.set_left_node(node_a);
		
	}
	
	(
	"/" b = <INTEGER>
	{
		value_node node_b = new value_node();
		node_b.set_value(Integer.parseInt( b.image ));

		// important code about node adding
		if(div.get_right_node() == null)
		{
			div.set_right_node(node_b);
		}
		else
		{
			div_node prev = div;
			div = new div_node();
			
			div.set_left_node(prev);
			div.set_right_node(node_b);
		}
	}
	)*
	
	<EOF>
	{ return div ; }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式-老费

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值