ucc编译器(语义分析)

Posted 费晓行

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ucc编译器(语义分析)相关的知识,希望对你有一定的参考价值。

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

 

    符合语法的代码,不一定符合语义。这句话听上去很拗口,我们不妨举个例子,假设我们定义了一个变量int a;,这个时候我们不能再定义一个int a吧。这个是关于变量的例子。

 

    我们还可以举一个函数的例子,假设一个函数没有返回值,但是在实现的时候,出现了一个return true的语句,这个是不是也不合理。

 

    因为语法树本身已经创建好了,这个时候只要按照语法树的结构往下层层递进就可以了,基本处理方法类似于二叉树的后序遍历。

 

1、语义解析的入口

void CheckTranslationUnit(AstTranslationUnit transUnit)

 

2、每一个语法解析的地方都有一个语义解析的文件

declchk.c

https://github.com/sheisc/ucc162.3/blob/master/ucc/ucl/declchk.c

 

exprchk.c

https://github.com/sheisc/ucc162.3/blob/master/ucc/ucl/exprchk.c

 

stmtchk.c

https://github.com/sheisc/ucc162.3/blob/master/ucc/ucl/stmtchk.c

 

3、symbol.c

语义解析关键的一个文件

https://github.com/sheisc/ucc162.3/blob/master/ucc/ucl/symbol.c

变量存不存在、函数存不存在、类型对不对,这些都和symbol.c息息相关。

symbol.c中的addTag和addFunction就会出现在不同的语义检查文件中。

 

4、type.c

兼容性判断的重要文件

https://github.com/sheisc/ucc162.3/blob/a92719fff0ab7eb5b0c45768acedabb3cd70ca05/ucc/ucl/type.c

 

5、不失一般性,我们分析一下stmtchk.c

5.1 入口函数

static AstStatement CheckStatement(AstStatement stmt)
{
	return (* StmtCheckers[stmt->kind - NK_ExpressionStatement])(stmt);
}

 

5.2 检查case-statement

/**
	case-statement:
					case  constant-expression :	statement
	 Constraints 
		A case or default label shall appear only in a switch statement.
	 Further constraints on such labels are discussed under the switch
	 statement.
	 Even the following code is legal:
	 	int a = 5;
		switch(a){
			printf("123.\\n");	---------- these are dead-code.
			break;
		case 3:
			printf("3.\\n");
			printf("this printf is not part of case-statment from syntactic view.\\n");
		case 2:
			printf("2.\\n");
		}
 */
static AstStatement CheckCaseStatement(AstStatement stmt)
{
	AstCaseStatement caseStmt = AsCase(stmt);
	AstSwitchStatement swtchStmt;
	// We have pushed the current switch statement in CheckSwitchStatement(...)
	swtchStmt = (AstSwitchStatement)TopStatement(CURRENTF->swtches);
	if (swtchStmt == NULL)
	{
		Error(&stmt->coord, "A case label shall appear in a switch statement.");
		return stmt;
	}

	caseStmt->expr = CheckConstantExpression(caseStmt->expr);
	if (caseStmt->expr == NULL)
	{
		Error(&stmt->coord, "The case value must be integer constant.");
		return stmt;
	}

	caseStmt->stmt = CheckStatement(caseStmt->stmt);
	caseStmt->expr = FoldCast(swtchStmt->expr->ty, caseStmt->expr);
	AddCase(swtchStmt, caseStmt);

	return stmt;
}

    case-statement最容易出现的问题,一个是外面没有switch语句,一个是value数值不是整数。

 

5.3 检查loop-statement

/**
	 iteration-statement:
			 while (  expression )	statement
			 do  statement while (	expression ) ;
 */
static AstStatement CheckLoopStatement(AstStatement stmt)
{
	AstLoopStatement loopStmt = AsLoop(stmt);

	PushStatement(CURRENTF->loops,    stmt);
	PushStatement(CURRENTF->breakable, stmt);
	// Adjust expr's type to Pointer(...)  when its type is FUNCTION/ARRAY
	loopStmt->expr = Adjust(CheckExpression(loopStmt->expr), 1);
	if (! IsScalarType(loopStmt->expr->ty))
	{
		Error(&stmt->coord, "The expression in do or while statement shall be scalar type.");
	}
	loopStmt->stmt = CheckStatement(loopStmt->stmt);
	
	PopStatement(CURRENTF->loops);
	PopStatement(CURRENTF->breakable);

	return stmt;
}

    循环语句的问题主要就是判断expression是不是标量。

 

5.4 检查break-statement

// break;
static AstStatement CheckBreakStatement(AstStatement stmt)
{
	AstBreakStatement brkStmt = AsBreak(stmt);

	brkStmt->target = TopStatement(CURRENTF->breakable);
	if (brkStmt->target == NULL)
	{
		Error(&stmt->coord, "The break shall appear in a switch or loop");
	}

	return stmt;
}

    break语句主要是判断在不在循环或者switch里面。

 

5.5 检查default-statement

/**
	default-statement
			default :  statement
 */
static AstStatement CheckDefaultStatement(AstStatement stmt)
{
	AstDefaultStatement defStmt = AsDef(stmt);
	AstSwitchStatement swtchStmt;

	swtchStmt = (AstSwitchStatement)TopStatement(CURRENTF->swtches);
	if (swtchStmt == NULL)
	{
		Error(&stmt->coord, "A default label shall appear in a switch statement.");
		return stmt;
	}
	if (swtchStmt->defStmt != NULL)
	{
		Error(&stmt->coord, "There shall be only one default label in a switch statement.");
		return stmt;
	}

	defStmt->stmt = CheckStatement(defStmt->stmt);
	swtchStmt->defStmt = defStmt;

	return stmt;
}

    default语句主要有两个问题,一个是判断在不在switch语句内,一个是判断是不是只有一个default statement。

 

5.6 总结

    statement语义分析的部分大同小异,主要就是把可能出现的问题罗列一遍,一般来说,如果没有问题的话,就会认为语句是没有问题的,可以进行后面二进制翻译工作了。

 

以上是关于ucc编译器(语义分析)的主要内容,如果未能解决你的问题,请参考以下文章

ucc编译器(语法解析)

ucc编译器(中间代码生成)

ucc编译器(汇编生成)

ucc编译器(优化)

ucc编译器(优化)

编译原理系列 实验四语义分析与中间代码生成