CF87B Vasya and Types
题目描述
程序员 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,即返回与 $A$ 等价、带有所需数量 * 的 void\*\*...* 类型(数量可以为 0)。也就是说,若如上定义了 ptptvoid,则 typeof ptptvoid 会返回 void\*\*。
尝试对 void 类型进行解引用将导致错误,即返回特殊数据类型 errtype。对于 errtype,满足以下等式:errtype\* = &errtype = errtype。尝试使用未提前定义的数据类型同样会导致 errtype。
typedef 可以多次定义同一个类型,最后一次定义有效。但之前使用该类型定义出来的类型不会受影响。
还需注意,解引用操作的优先级低于指针操作,换句话说 $&T*$ 总是等于 $T$。
注意,所有运算符按给定顺序逐条依次执行。如果有 "typedef &void a" 和 "typedef a\* b" 这两条语句,则先让 a 变为 errtype,接着 b 变为 errtype\* = errtype,而不是 &void\* = void(见样例二)。
Vasya 还未能完全理解这种强大的技术,因此请你帮他编写一个分析这些运算符的程序。
输入格式
第一行包含整数 $n$($1 \leq n \leq 100$)——指令条数。接下来 $n$ 行,每行一个操作。每个操作为以下两种形式之一:"typedef $A$ $B$" 或 "typeof $A$"。在 typedef 语句中,$B$ 类型不同于 void 和 errtype,且 $B$ 不含 * 或 &。
所有类型名称皆为不超过 20 个小写英文字母的非空串。每个类型中星号或 & 符号的数量均不超过 10,但若类型化简为 void 加若干 *,这个 * 的数量可大于 10。
输出格式
对于每个 typeof 操作,输出一行该操作返回的类型。
说明/提示
让我们看下第二个样例。
在前两条指令执行后,b 类型等价于 void\*,c 等价于 void\*\*。
下一条 typedef 重新定义了 b——现在 b 等价于 &b = &void\* = void。此时 c 类型不变。
之后 c 被定义为 &&b\* = &&void\* = &void = errtype。它不会影响 b 类型,因此下一条 typedef 定义 c 为 &void\* = void。
接着 b 又被定义为 &void = errtype。
请注意,之后某次对于 c 的定义实际上为 errtype\*\*\*\*\*\*\* = errtype,而不是 &void\*\*\*\*\*\*\* = void\*\*\*\*\*\*\*。最后一次 typedef 同理。
由 ChatGPT 5 翻译