4065: 瓦夏和类型

内存限制:256 MB 时间限制:2 S
题面:传统 评测方式:文本比较 上传者:
提交:4 通过:3

题目描述

程序员Vasya正在研究一种新的编程语言&K*。&K*语言在语法上类似于C家族的语言。然而,它更强大,这就是为什么实际的类c语言的规则不适用于它的原因。要完全理解这个语句,请仔细阅读下面的语言描述,并遵循它,而不是实际编程语言中的类似规则。
在&K*上有一个非常强大的指针系统,您可以在现有类型X的右侧添加一个星号,这将导致新的类型X*。这被称为指针定义操作。此外,还有一种相反的操作——对任何类型的X(指针),你可以添加一个&号——这将导致类型&X,指向X,这被称为解引用操作。
&K*语言只有两种基本数据类型:void和errtype。此外,该语言还有操作符typedef和typeof。
操作符“typedef A B”定义了一个新的数据类型B,它相当于A。A可以有星号和&号,而B不能有它们。例如,操作符typedef void** ptptvoid将创建一个新的类型ptptvoid,可以用作void**。
操作符"typeof A"返回类型为A的void,即返回类型为void**…*,相当于它与必要的星号数量(数字可以是零)。也就是说,如上所示,定义了ptptvoid类型后,typeof ptptvoid操作符将返回void**。
试图取消对void类型的引用将导致错误:指向一个特殊的数据类型errtype。对于errtype,以下公式成立:errtype*=&errtype=errtype。尝试使用之前未定义的数据类型也会导致错误类型。
使用typedef,我们可以多次定义一个类型。所有的定义中只有最后一个是有效的。但是,之前使用该类型定义的所有类型都不会更改。
我们还要注意到,解引用操作的优先级比指针操作低,换句话说,&T*总是等于T。
注意,操作符是一个接一个连续执行的。如果我们有两个操作符“typedef &void a”和“typedef a* b”,那么首先a变成errtype,然后b变成errtype* = errtype,而不是&void* = void(见示例2)。
瓦斯亚还没有完全理解这种强大的技术,所以他才让你帮他。写一个程序来分析这些运算符。

输入格式

第一行为整数n(1≤n≤100)−操作符个数。然后在n行后面加上运算符。每个操作符都是两种类型之一:“typedef A B”或“typeof A”。在第一种情况下,B类型不同于void和errtype类型,此外,没有任何星号和&号。
所有数据类型名称都是不超过20个小写拉丁字母的非空行。在任何运算符中,一种类型中星号和和号的数量都不超过10个,但是如果我们用几个星号使某些类型无效,它们的数量可能超过10个。

输出格式

输出对于每个typeof操作符,在单行上打印该操作符的答案-给定操作符返回的类型。

输入样例 复制

17
typedef void* b
typedef b* c
typeof b
typeof c
typedef &b b
typeof b
typeof c
typedef &&b* c
typeof c
typedef &b* c
typeof c
typedef &void b
typeof b
typedef b******* c
typeof c
typedef &&b* c
typeof c

输出样例 复制

void*
void**
void
void**
errtype
void
errtype
errtype
errtype

数据范围与提示

让我们看一下第二个样本。
在前两个查询之后,typedef 的 b 类型等同于 void*,而 c 类型等同于 void**。
接下来的查询中,typedef 重新定义了 b —— 现在它等于 &b = &void* = void。同时,c 类型没有变化。
之后,c 类型被定义为 &&b* = &&void* = &void = errtype。这不会影响 b 类型,因此接下来的 typedef 将 c 定义为 &void* = void。
然后,b 类型再次被重新定义为 &void = errtype。
请注意,在下一个查询中,c 类型被定义为 errtype******* = errtype,而不是 &void******* = void******。最后一个 typedef 中也发生了相同的情况。