0
点赞
收藏
分享

微信扫一扫

ucc编译器(语义分析)

诗远 2022-11-23 阅读 59



 

    符合语法的代码,不一定符合语义。这句话听上去很拗口,我们不妨举个例子,假设我们定义了一个变量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语义分析的部分大同小异,主要就是把可能出现的问题罗列一遍,一般来说,如果没有问题的话,就会认为语句是没有问题的,可以进行后面二进制翻译工作了。

 

举报

相关推荐

0 条评论