本项目的总体目标是要实现一个标准 (确定性、双向无限纸带) 图灵机的模拟器,并且能够在上面正确模拟运行符合特定语法的图灵机程序。
参考下文 Section 2 中的图灵机程序语法,实现一个标准图灵机程序解析器。要求:
- 以符合语法描述的图灵机程序作为解析器的输入;
- 该解析器能够正确解析读入的图灵机程序;
- 图灵机程序解析完成后,得到与之对应的一个图灵机模拟器 (见任务二)。
图灵机程序经过解析器解析后,得到一个对应的标准图灵机模拟器。模拟器读入一个字符串作为图灵机的输入。要求:
- 判断输入字符串的合法性 (也即判断所有字符是否均属于输入符号集,输入符号集的定义参见 语法描述 )。若字符串不合法,则不对其进行模拟运行,并按以下格式报告输入错误:
若字符串合法,按以下格式输出提示信息,并转 2:
Input: XXXXXXXXXXXX ==================== ERR ==================== The input "XXXXXXXXXXXX" is illegal ==================== END ====================
Input: XXXXXXXXXXXX ==================== RUN ====================
- 模拟器对合法的输入串进行模拟运行。对于图灵机上的每一次转移,按以下格式给出图灵机的一个瞬时描述:
Step : 0 Index : 0 1 2 3 4 5 6 Tape : 1 0 0 1 0 0 1 Head : ^ State : 0 --------------------------------------------- Step : 1 Index : 1 2 3 4 5 6 Tape : 0 0 1 0 0 1 Head : ^ State : li --------------------------------------------- Step : 2 Index : 1 2 3 4 5 6 Tape : 0 0 1 0 0 1 Head : ^ State : li --------------------------------------------- ...... ...... ...... --------------------------------------------- Step : 40 Index : 3 4 5 6 Tape : T r u e Head : ^ State : halt_accept ---------------------------------------------
注 1:
Index
中的0
表示初始时纸带上包含输入的最左单元的索引位置;注 2:读写头初始位置为初始输入的最左单元位置;
注 3:一般情况下,最前和最后的空格符号和对应索引都不需要打印,只需打印纸带上第一个非空格符号到最后一个非空格符号之间的符号及对应索引;
注 4:当读写头指向的位置为非空格符号外侧的空格符号时,需要打印必要的空格符号及对应索引,空格符号以
'_'
表示。示例:Step : 12 Index : 0 1 2 3 4 5 6 7 Tape : 1 1 1 0 0 0 0 _ Head : ^ State : s1 --------------------------------------------- Step : 14 Index : 5 Tape : _ Head : ^ State : s2 ---------------------------------------------
注 5:
Index
中相邻两项之间以一个空格为间隔,Tape
上的符号与Index
中对应的索引靠左对齐。示例:Step : 19 Index : 0 1 2 3 4 5 6 7 8 9 10 11 12 Tape : 1 1 1 0 0 0 0 0 1 1 1 0 0 Head : ^ State : s3 ---------------------------------------------
注 6:若需要向
0
索引左边的纸带单元中读写字符,请在Index
中按照"... 3 2 1 0 1 2 3 ..."
的格式 (即省略-3 -2 -1
等负索引的负号) 对索引进行描述。 - 模拟运行结束后,将纸带上的内容 (首尾分别为纸带上第一个和最后一个非空格符号) 作为最后的输出,对于上述格式描述中的示例,最后纸带上的内容为
True
。并按以下格式输出信息:其中Result: XXXX ==================== END ====================
XXXX
为模拟运行结束后纸带上的内容,对于上述示例即为True
。
使用下文 Section 2 中描述的图灵机程序语法,实现 Assignment 3 - Problem 2 中两个图灵机对应的图灵机程序。要求:
- 将图灵机实现为一个判定器,即判定一个输入串是否在图灵机描述的语言中;
- 使用你在 任务一 中实现的图灵机程序解析器对你实现的图灵机程序进行解析,得到对应的图灵机模拟器;
- 使用模拟器对合法的输入字符串进行模拟运行。对于符合图灵机语言要求的字符串,在纸带上打印
True
;对于不符合图灵机语言要求的字符串,在纸带上打印False
。要求在图灵机停止运行时,纸带上不出现True
和False
外的其他内容; - 请将你的图灵机设计思路以及每个状态表达的意义以注释的形式在图灵机程序文件中进行说明。
- Java 版本:
Java 8
; - 推荐使用 JetBrains 的 IntelliJ IDEA 来创建和开发 Java 项目 (你可以从 这里 (Student License) 获得 JetBrains 全部产品的免费使用权。此外,IntelliJ IDEA 也有 社区版 (Community) 可以直接免费使用)。
- 请确保能够在
Ubuntu 18.04 64-bit
上使用g++ 7.3.0
正常编译运行; - 请使用
Make
工具或其他构建工具对项目进行构建和管理,并在报告中进行说明。
图灵机的形式化描述如下:
下面定义的图灵机程序语法完整地刻画了上述七部分内容。
-
状态集
。以
#Q
开头。占据 (且仅占据) 图灵机程序的一行,即不包括回车换行,'#'
为该行的第一个字符 (以下2,3,4,5,6同)。各状态之间以英文逗号','
分隔。状态用一个或多个非空白字符 (字母a-z,A-Z
、数字0-9
和下划线_
) 表示,称为该状态的标签,如"10"
、"a"
、"state1"
等。语法格式为#Q = {q1,q2,...,qi}
。'='
两边各有一个空格' '
(以下2,3,4,5,6同)。示例:#Q = {0,1o,1i,2o,2i,3,4,accept,accept2,accept3,accept4,halt_accept,reject,reject2,reject3,reject4,reject5,halt_reject}
-
输入符号集
。以
#S
开头。各符号之间以英文逗号','
分隔。输入符号的可取值范围为除' '(space)
、','
、';'
、'*'
、'_'
外的所有 ASCII 可显示字符 (定义参见 维基百科 )。语法格式为#S = {s1,s2,...,sj}
。示例:#S = {0,1}
-
纸带符号集
。以
#T
开头。各符号之间以英文逗号','
分隔。纸带符号的可取值范围为除' '(space)
、','
、';'
、'*'
外的所有 ASCII 可显示字符,规定用'_'
表示空格符号。语法格式为#T = {t1,t2,...,tk}
。示例:#T = {0,1,_,T,r,u,e,F,a,l,s}
-
初始状态
。以
#q0
开头。语法格式为#q0 = q
。示例:#q0 = 0
-
空格符号
。以
#B
开头。语法格式为#B = b
。在本项目中,空格符号规定为'_'
。示例:#B = _
-
终结状态集
。以
#F
开头。各状态之间以英文逗号','
分隔。语法格式为#F = {f1,f2,...,fn}
。示例:#F = {halt_accept}
-
- 每个转移函数占用 (且仅占用) 图灵机程序的一行,行内容为一个五元组。五元组格式为:"旧状态 旧符号 新符号 方向 新状态",元组各部分之间以一个空格分隔。
- 示例:
0 0 _ r 1o ; 当前处于状态0,带头下符号为'0',将要写入的新符号为'_',下一步向右移动,下一个状态为1o
-
注释。只需处理行注释。行注释以英文分号
';'
开头,在解析程序时应当忽略注释。示例:; State 0: read the leftmost symbol 0 _ _ * accept ; Empty input
-
通配符
'*'
用于表示旧符号时,可匹配任意符号。示例:reject * _ l reject ; 表示无论当前读写头读到什么符号,都在纸带单元中写入空格符号,并向左移动
-
通配符
'*'
用于表示新符号时,表示没有变化。示例:1o * * r 1o ; 表示无论当前读写头读到什么符号,都不改变符号,并向右移动
通配符 '*'
的使用可能会破坏标准图灵机的“确定性”,示例:
1o _ _ l 2o
1o * * r 1o
在当前状态为 1o
,读写头下单元中为空格字符时,可以同时匹配上述两个转移函数。因此我们规定:
当可以同时匹配多个转移函数时,匹配更精确的转移函数。
也即对于上述示例,我们会匹配第一个转移函数 1o _ _ l 2o
。
完整的图灵机程序示例参见 palindrome_detector.tm。
- 任务一 & 任务二。我们会使用另外准备的图灵机程序以及对应的输入来对你实现的图灵机解析器和模拟器的正确性进行测试。每个图灵机程序的测试方案同下述 任务三 的测试方案。
- 任务三 测试方案:
- 输入为两个文件。第一个文件为你实现的图灵机程序文件
test.tm
,第二个为测试文件input.txt
。测试文件中每一行包含一个用于测试的输入字符串。实现时测试文件请自备,助教验收代码时会准备另外的测试文件。 - 输出也为两个文件。第一个文件是运行时信息输出文件
console.txt
,具体输出要求见 任务二 。第二个文件为结果文件result.txt
。结果文件中的每一行对应着输入文件中的每一行输入字符串对应的输出结果 (当输入字符串不合法时,在结果文件中输出一行Error
;当输入字符串合法且在图灵机描述的语言中时,在结果文件中输出一行True
;当输入字符串合法但不在图灵机描述的语言中时,在结果文件中输出一行False
)。 - 请将每个图灵机程序文件及对应的测试文件放在一个可执行文件同级目录的一个子目录下,并且生成的输出文件也放置在该子目录下。文档结构示例如下:
|—— turing.jar (Java) / turing (C++) // 可执行程序 |—— case1 // 测试子目录 |—— test.tm // 图灵机程序文件 |—— input.txt // 测试文件 |—— console.txt // 运行时信息输出文件 |—— result.txt // 结果文件 |—— case2 // 测试子目录 |—— test.tm // 图灵机程序文件 |—— input.txt // 测试文件 |—— console.txt // 运行时信息输出文件 |—— result.txt // 结果文件
- 输入为两个文件。第一个文件为你实现的图灵机程序文件
- 为方便我们进行测试,请确认以下事项:
- 若你使用 Java 实现。请将你的 Java 项目打包为一个可执行
jar
包,命名为turing.jar
,并确保能够正确运行以下命令 (参数case-directory
为测试子目录):java -jar turing.jar case-directory
- 若你使用 C++ 实现。请将你的 C++ 项目编译生成可执行文件,命名为
turing
,并确保能够正确运行以下命令 (参数case-directory
为测试子目录):./turing case-directory
case-directory
目录下生成两个文件console.txt
和result.txt
。注:
case-directory
中只包含目录名,不包含路径分隔符,如case1
; - 若你使用 Java 实现。请将你的 Java 项目打包为一个可执行
重要声明:为维护学术诚信,我们将对所有提交代码进行查重。请各位同学务必独立完成本项目。
- 实验源代码。请提交完整项目工程代码。
- 可执行
jar
包 (for Java) 或者可执行文件 (for C++)。 - 图灵机测试子目录。分别命名为
case1
、case2
。测试子目录下的图灵机程序文件名指定为test.tm
,输入文件名指定为input.txt
。 - 报告。报告格式为
pdf
,文件名为学号+'-'+姓名
。报告内容包括分析与设计思路、实验完成度、实验中遇到的问题及解决方案、编译运行说明 (for C++)、演示和总结感想,以及其他任何想写的内容 (如对课程和项目的意见与建议等)。 - 请将上述两部分内容打包为一个
zip
文件进行提交,文件名为学号+'-'+姓名
。文档结构示例如下:|—— 161220XXX-张三.zip (MG1833XXX-李四.zip) |—— turing.jar (Java) / turing (C++) |—— case1 |—— test.tm |—— input.txt // 请自备,验收测试时助教会另外统一输入文件 |—— case2 |—— test.tm |—— input.txt // 请自备,验收测试时助教会另外统一输入文件 |—— 161220XXX-张三.pdf (MG1833XXX-李四.pdf) |—— your-project
请登录 南京大学计算机系本科教学支撑平台,在本课程项目的对应作业提交位置进行提交。
注 1:支撑平台的初始账号和默认密码均为学号 (已使用过支撑平台的同学忽略本条说明);
注 2:研究生同学可以按相同方式登录该平台 (忽略本科教学支撑平台)。
2018-12-30 23:59:59