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编译器(语义分析)的主要内容,如果未能解决你的问题,请参考以下文章