去除代码中的注释(三) 实现 下

上一篇博文介绍了对输入字符流的预处理,将字符流转化为Token流。经过这一步转化后,就可以使用上下文无关文法进行分析了。本文介绍对Token流的分析过程。


我们使用递归下降法来实现语法的解析。递归下降法的特点是,为每一个非终结符定义一个函数,在这个函数里需要定义所有以该非终结符为左部的产生式。


我们定义了下面的非终结符。

  • <prog>表示整个源代码段,它是文法定义中的初始非终结符。
  • <line_comment>表示代码段中的行注释片断。
  • <block_comment>表示代码段中的块注释片断。
  • <quote>表示代码段中的引用字符串,即C语言中的字符串常量。
  • <norm_block>表示代码段中非注释,非引用的片段


下面将对这些非终结符逐一分析。


1. prog


void prog(BufferedReader & reader)
{
	while(true)
	{
		Token t = reader.readToken();
		if(t.type == Token::END_OF_FILE)break;

		reader.pushToken(t);
		if(t.type == Token::BLCOK_COMMENT_START)blockComment(reader);
		else if(t.type == Token::LINE_COMMENT_START)lineComment(reader);
		else if(t.type == Token::DOUBLE_QUOTE_MARK)quote(reader);
		else normBlock(reader);
	}
}


根据产生式的定义,prog其实是由一列的blockComment, lineComment, quote和normBlock构成。那么我们如何知道,当前的的token序列是归约为这4个字符的哪一个呢?其实很简单,我们只需要看第一个token序列即可。

  • 如果第一个token为/*,则属于blockComment(代码第9行)
  • 如果第一个token为//,则属于lineComment(代码第10行)
  • 如果第一个token为双引号",则属于quote(代码第11行)
  • 否则,属于normBlock(代码第12行)

这种只需要看一个终结符就能够判断用哪个非终结符或者产生式归约的文法特性称为1向前看特性。需要注意的是一般的上下文无关文法不具备这种特性。所以在解析一般的上下文无关文法时可能需要回溯。而为了实现高效编译,一般的程序设计语言都满足1向前看的特性。


2. quote


void quote(BufferedReader & reader)
{
	reader.readToken().print();
	while(true)
	{
		Token t = reader.readToken();
		if(t.type == Token::END_OF_FILE)break;
		t.print();
		if(t.type == Token::DOUBLE_QUOTE_MARK)break;
	}
}

代码第3行首先将第1个双引号读入并输出。之后的循环依次读入字符,直到出现引号结束。


注意:

  • 如果在引用字符串中出现引号”,需要写成转义字符\",对应token的type为CONVERT_CHAR。
  • 在引用中可能会出现行注释和块注释的开始记号,我们将它看做是能够在引用中出现的合法token,并没有什么妨碍。


3. lineComment


void lineComment(BufferedReader & reader)
{
	reader.in_comment = true;
	while(true)
	{
		Token t = reader.readToken();
		if(t.type == Token::END_OF_FILE || t.type == Token::ENTER)break;
	}
	reader.in_comment = false;
}

在处理注释要注意下面几点。

  • 设置reader对象的in_comment标记,告诉reader现在正在处理注释,这样reader对象就会把'\'当做是普通的字符。
  • 处理注释时,不要输出token,这样就达到了删除注释的目的。


4. blockComment与lineComment解析相似,故略。


5. normBlock


void normBlock(BufferedReader & reader)
{
	while(true)
	{
		Token t = reader.readToken();
		if(t.type == Token::END_OF_FILE)break;
		if(t.type != Token::NORM_CHAR && t.type != Token::ENTER && t.type != Token::CONVERT_CHAR)
		{
			reader.pushToken(t);
			break;
		}
		t.print();
	}
}

normBlock与blockComment,lineComment,quote不同。blockComment,lineComment和quote有明显的起始和结束token,可是normBlock没有。因此在解析normBlock时,总是看当前token是否是normBlock定义的合法token。如果合法,则将该token接收进来。否则,normBlcok的解析结束。这种解析策略涉及到上下文无关文法的空串产生式,下一篇博文将详细讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值