HNU 编译系统 语义分析练习题(ChatGPT出题)

题目1

考虑以下简化的程序代码,该代码使用类似C语言的语法:

P -> D E
D -> T id; D 
   | ε
T -> int 
   | bool
E -> n 
   | id 
   | true 
   | false 
   | E+E 
   | E&&E

代码片段:

int x; 
bool y; 
x = 5; 
y = true; 
if (x + y) {     
	int z;     
	z = x * 2; 
} else {     
	bool z;     
	z = false; 
} 
z = 10;

代码中包含变量声明、表达式和使用,但可能存在语义错误。请基于语义分析的知识点回答下列问题。

  1. 类型检查:代码中哪些表达式存在类型错误?请具体指出并结合语义分析的伪代码解释原因。
  2. 变量声明与作用域:代码中变量z的使用是否存在语义错误?请结合符号表的作用域管理解释。
  3. 符号表模拟:如果使用符号表栈来处理作用域,请描述解析到第11行时符号表栈的状态。

  1. x + y存在类型错误。
    原因:语义分析的伪代码中,
enum Type check_E(E e){
	switch(e->kind)
		...
		case E_INT : 
			return INT; 
			break;
		case TRUE : 
			return BOOL; 
			break;
		case FALSE : 
			return BOOL; 
			break;
		case ADD : 
			e1 = check_E(e->left);
			e2 = check_E(e->right);
			if (e1 == INT && e2 == INT) {
				return INT; 
				break;
			}
			else emit("runtime_error");
}

对于int x;,返回x.Type = INT;对于float y;,返回y.Type = FLOAT。此时x + y属于ADD分支,会出现e1.Type != e2.Type报错runtime_error
2. 变量z的使用存在语义错误。
将整体作用域设为0,进入if (x + y)分支时,进入作用域1,符号表加入

键\值typescope
zINT1

结束if分支时,符号表将上面的条目删除;
进入else分支时,进入作用域2,符号表加入

键\值typescope
zFLOAT2

结束else分支时,符号表将上面的条目删除。
此时走到z = 10,发现符号表中没有z的定义,报错runtime_error
3.
第1行:

键\值typescope
xINT0
第2-4行:
键\值typescope
xINT0
yBOOL0
第5行:
键\值typescope
xINT1
yBOOL1
键\值typescope
xINT0
yBOOL0
第6-7行:
键\值typescope
xINT1
yBOOL1
zINT1
键\值typescope
xINT0
yBOOL0
第8行:
键\值typescope
xINT2
yBOOL2
键\值typescope
xINT0
yBOOL0
第9-10行:
键\值typescope
xINT2
yBOOL2
zBOOL2
键\值typescope
xINT0
yBOOL0
第11行:
键\值typescope
xINT0
yBOOL0

题目2

考虑描述表达式规则的文法CFG,其非终结符集合为{E},终结符集合为{num, true, false}。文法产生式如下:

E -> num 
E -> true 
E -> false 
E -> E + E
E -> E && E
E -> E > E 

假设其语义规则为:每个表达式E都有一个类型(整型)。具体地:

  • E + E 类型的表达式中两个子表达式都必须是整型(即num),结果类型为整型。
  • E && E 类型的表达式中两个子表达式都必须是布尔型(即truefalse),结果类型为布尔型。
  • E > E 类型的表达式中两个子表达式都必须是整型,结果类型为布尔型。
    回答以下问题:
    (1)给出一段伪代码,能完成上述语言的语义分析,当输入表达式语义错误时报错,否则返回输入表达式的类型(假设抽象语法树已经建立好,词法分析已完成);
    (2)用语法制导翻译SDD的方法描述上述语义分析的语义动作,并指出该SDD中的属性哪些是综合属性、哪些是继承属性。
    (3)如果将E -> E + E 改为两个子表达式可以是整型或布尔型,结果类型为整型,那么对应的语义分析伪代码和语法制导翻译SDD要如何改变?

(1)语义分析伪代码:

enum Type check_E(E e){
	switch(e->kind)
		case NUM:
			return INT;
			break;
		case TRUE || FALSE:
			return BOOL;
			break;
		case ADD:
			e1 = check_E(e->left);
			e2 = check_E(e->right);
			if (e1 == INT && e2 == INT) {
				return INT; 
				break;
			}
			else emit("runtime_error");
		case AND:
			e1 = check_E(e->left);
			e2 = check_E(e->right);
			if (e1 == BOOL && e2 == BOOL) {
				return BOOL; 
				break;
			}
			else emit("runtime_error");
		case larger:
			e1 = check_E(e->left);
			e2 = check_E(e->right);
			if (e1 == INT && e2 == INT) {
				return BOOL; 
				break;
			}
			else emit("runtime_error");
}

(2)SDD如下:

1. E -> num        {E.Type = INT;}
2. E -> true       {E.Type = BOOL;}
3. E -> false      {E.Type = BOOL;}
4. E -> E1 + E1    {if (E1.Type == INT && E2.Type == INT) E.Type = INT;
					else emit("runtime_error");}
5. E -> E1 && E1   {if (E1.Type == IBOOL && E2.Type == BOOL) E.Type = BOOL;
					else emit("runtime_error");}
6. E -> E1 > E1    {if (E1.Type == INT && E2.Type == INT) E.Type = BOOL;
					else emit("runtime_error");}

(3)改后的语义分析伪代码:

		case AND:
			return INT; 
			break;

改后的SDD:

E -> E1 + E1    {E.Type = INT;}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值