**《Rust 实现 Logo 语言解释器作业指南》**
**一、Logo 语言简介**
– Logo 是一种从 Lisp 和其他编程语言衍生而来的语言。许多老程序员的第一次编程经历就是使用 Logo。其主要特点是有一个“海龟”绘图机制,它可以像一支无形的笔,通过抬笔、落笔以及移动来绘制图形。
– Logo 程序由文本行组成,这些行被拆分为令牌(由空格分隔的字符串)。以“//”开头的行或空行被视为注释而忽略。令牌分为三种类型:
– 程序:类似于函数,可由解释器提供或在 Logo 文件中实现。例如,MAKE 程序用于设置变量的值。一些程序需要参数,一些则不需要。在作业的后续阶段,还会有返回值的程序。
– 变量:以“:”开头的令牌,表示应查找具有该名称的变量。例如,“:MYVARIABLE”可能具有值“42”。
– 值:以“””开头,表示原始字符串。Logo 中的所有值都存储为字符串。
**二、Unsvg 介绍**
– 在这个作业中,将使用`unsvg` crate 来生成 SVG 或 PNG 图像。该 crate 有两个有用的功能:
– `unsvg::Image`:表示图像,具有像`draw_simple_line`这样的方法,可以让你绘制图像。注意,`draw_simple_line`会返回线的终点坐标,无需进行数学计算来确定线的终点。
– `unsvg::get_end_coordinates`:返回从给定的点开始绘制一条线的终点坐标。
**三、程序工作方式**
– 要创建一个名为`rslogo`的程序,它始终接受四个参数:
– 一个 Logo 程序文件(通常以.lg 结尾)。
– 输出 SVG 或 PNG 文件的路径(必须以.svg 或.png 结尾)。
– 读取 Logo 程序。
– 逐行解析并执行程序。
– 如果有问题,打印错误并以非零返回码退出。
– 如果没有问题,使用`unsvg` crate 编写 SVG 或 PNG 文件。
**四、卓越设计**
– 为了在作业中获得满分,代码需要在“设计卓越”方面有突出表现:
– 使错误美丽:错误信息应具有描述性,包括有问题的行的文本,并在可行的情况下提供可能错误的提示,还可以彩色显示以突出问题。可以考虑使用一些诊断报告 crate,如`miette`、`ariadne`、`chumsky`、`annotate-snippets`、`codespan-reporting`等。
– 达到 80%测试覆盖率:可以使用像`tarpaulin`这样的库来计算测试覆盖率,采用测试驱动开发风格可能有助于实现这一目标。
– 使用解析器组合库构建解析器:例如`nom`、`winnow`、`chumsky`等。
– 创建程序员添加语言扩展的设施:只需要更改一两行代码并添加一个有用的命令,同时应记录所有对程序员可用的公共接口。
– 构建接近零拷贝的程序:这需要考虑如何编写高性能的程序并避免分配内存。
– 为`unsvg`库做出有意义的贡献:可以是文档、新功能或错误修复,在进行之前应提交一个问题并在论坛上请求批准。
– 构建转译器:将`rslogo`代码转换为另一种语言(如 Python、JavaScript、C、Rust)以运行它,这虽然不一定是设计卓越,但会带来有趣的设计挑战。
**五、任务完成部分**
1. **第一部分:海龟控制(20%)**
– 控制“海龟”,它就像一支可以在图像上绘制的无形笔。海龟有两种状态:“抬笔”(不绘制)和“落笔”(移动时绘制线条)。笔的颜色初始为白色,海龟开始时在屏幕中心,面朝上。
– 需要解析以下命令:
– `PENUP`(抬笔)和`PENDOWN`(落笔)。
– `FORWARD [numpixels:f32]`(向前移动指定像素数)、`BACK [numpixels:f32]`(向后移动)、`LEFT [numpixels:f32]`(左转指定角度对应的像素数)、`RIGHT [numpixels:f32]`(右转)。其中,左转是在当前朝向基础上加 270 度,右转是加 90 度,后退是加 180 度。如果海龟“落笔”,这些命令应绘制线条,且像素数可以为负数,表示反向移动。
– `SETPENCOLOR [colorcode:f32]`(设置笔的颜色),颜色可以是`unsvg`的 COLORS 数组中的 16 种选项之一,若不是整数则报错。
– `TURN [degrees:f32]`和`SETHEADING [degrees:f32]`(转弯或设置朝向),以整数角度为参数,若不是整数报错。内部不应该对朝向进行归一化处理。
– `SETX [location:f32]`和`SETY [location:f32]`(设置海龟的 X 和 Y 坐标),参数为浮点数,即使海龟“落笔”,这些命令也不应绘制任何东西。
2. **第二部分:变量和查询(20%)**
– 实现`MAKE`命令用于创建和赋值变量,例如`MAKE “x “10`将变量 x 赋值为 10。还需实现`ADDASSIGN`命令,相当于其他语言中的“+=”,它需要一个现有变量名和一个要添加的值,如果变量不存在或任一参数不是数字则报错。变量没有作用域限制,可以被覆盖。
– 支持“查询”,即一些返回值的过程,它们类似于变量但不用“:”开头且由程序自动设置,包括`XCOR`(返回当前 X 坐标)、`YCOR`(返回当前 Y 坐标)、`HEADING`(返回当前朝向)、`COLOR`(返回笔的颜色编号)。
3. **第三部分:条件判断和循环(20%)**
– 实现`IF EQ`和`WHILE EQ`命令进行条件执行和循环。`IF EQ
4. **第四部分:使用栈实现数学运算和比较(20%)**
– 实现波兰表示法的各种运算符,包括`EQ`(等于)、`NE`(不等于)、`GT`(大于)、`LT`(小于)、`AND`(与)、`OR`(或)、`+`(加)、`-`(减)、`*`(乘)、`/`(除)。例如,在 Logo 中,`+ “3 “4`相当于 Rust 中的 3 + 4。如果参数不符合要求(如不是数字、布尔值或单词等情况)应报错,除法时若除数为零也应报错。需要在`IF`和`WHILE`中实现栈操作。
5. **第五部分:Logo 自定义过程(20%)**
– Logo 允许通过过程来分解代码,类似于其他语言中的函数。语法是以“TO”开头,接着是过程名和参数列表,最后以“END”结束。例如`TO DoSquare “arg1 FORWARD :arg1 LEFT :arg1 BACK :arg1 RIGHT :arg1 END`。过程在使用前必须在其上方定义,不能递归、不能在条件语句中定义、也不能在其他过程中定义,且过程名不能重复。过程执行结束后,其参数不应被更改或删除。
**六、常见问题**
1. **设计方法**:有两种主要方法,一是逐行执行,在执行过程中存储更多数据和状态以支持条件语句;二是先将文本转换为抽象语法树,然后读取和理解这个树来执行程序。
2. **规划建议**:这是一个大型程序,可以先思考采用哪种方法并通读作业,但不要花费超过 30 分钟进行规划,因为从实践中能学到更多。
3. **使用 AI**:在这个作业中可以使用 AI,例如用于帮助回忆概念、进行模式匹配、生成代码骨架和编写测试等。
**七、其他信息**
1. **提交要求**:按照页面底部的说明进行提交,截止日期为第 7 周周三 17:00:00。
2. **使用其他 crate 的条件**:可以使用在 crates.io 上发布的 crate,但必须满足三个条件:不是课程中其他人编写的 crate、有至少 1000 次下载(不包括最近 30 天)、不要求共享自己的代码。
3. **评分标准**:根据机械风格(10%)、功能正确性(40%乘以完成作业的百分比)、习惯用法设计(50%乘以完成作业的百分比)进行评分。机械风格要求代码编译无警告和错误、通过 cargo clippy 检查、使用 rustfmt 格式化且测试通过。习惯用法设计从代码的可读性、函数参数合理性、避免重复代码、类型使用、错误处理等多个方面进行评估。
**八、正式要求**
– 这是一个个人作业,不允许联合工作或共享代码。可以使用代码合成工具,但要谨慎,因为可能会引入设计缺陷,你需要对代码负责。不允许向除教学人员以外的任何人请求帮助,也不允许在课程论坛上发布作业代码或在完成课程后分享作业。违反这些条件可能导致学术诚信调查,最高可处以 COMP6991 课程成绩为 0 分并被新南威尔士大学开除的处罚。