> For the complete documentation index, see [llms.txt](https://mashplant.gitbook.io/decaf-doc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mashplant.gitbook.io/decaf-doc/pa1a/lalr1-shi-yong-zhi-dao/impl-kuai-de-ke-xuan-shu-xing.md).

# impl块的可选属性

除了`#[lalr1(Start)]`和`#[lex(TomlOfLexer)]`这两个必要的属性外，还可以添加几个额外的属性，目前支持的有以下几个：

1. `#[verbose(OutputPath)]`

   向`OutputPath`输出一些用于调试的信息。

   调试信息首先包括文法符号的编号及其对应的名字，产生式的编号及其对应的内容。这些内容对于本阶段的实现来说应该没有什么用，不过在调试pa1b的时候可能会用到。

   调试信息的剩余部分依据使用的文法而定。在lalr(1)模式中为action表，出现冲突警告的时候可以利用这个文件来帮助查找语法中的问题。action表中包含每个节点包含的产生式及点的位置(不包含向前看符号)，以及每个节点处遇到终结符时的移进/规约/接受动作。每个动作都会在后面加上一个表示冲突情况的符号，示例如下：

   ```
    A => Shift(1) (✓)
    A => Reduce(1) (-)
    B => Shift(2) (✓)
    B => Reduce(2) (✗)
   ```

   其中`(✓)`表示它最后被解析器采用，`(-)`表示它被利用优先级和结合性消除了，`(✗)`表示它被"强行"消除了，对应于一个冲突警告。详见后面的解决冲突一节。

   在ll(1)模式中为预测集合(predict set)，同样`(✗)`表示一个产生式被"强行"消除了，而因为ll(1)中没有利用优先级和结合性来消除冲突的机制，所以不存在`(-)`。

   此外，当这个属性存在的时候，会额外生成`show_token`和`show_prod`这两个函数，分别接受文法符号的编号和产生式的编号，返回表示对应的文法符号的名字和产生式内容的字符串(当然，越界会panic)。本质上这两个函数就是把上面提到的"文法符号的编号及其对应的名字，产生式的编号及其对应的内容"放到了rust代码中，也是为了方便大家调试。
2. `#[log_token]`

   每当新解析出一个非`_Eps`的终结符时，输出它的相关信息，也就是输出一个struct `Token`，包括名字，对应源代码，行号列号。
3. `#[log_reduce]`

   每当执行一次规约时，输出产生式。
4. `#[use_unsafe]`

   使用一些`unsafe`来减少运行时检查，以期提高性能。例如将不可达断言转化成不可达hint，取消下标越界检查等。

   如果你编写的parser是正确的，那么无论输入的程序是是什么，这些`unsafe`都不会导致真正不安全的结果(至少lalr1的目标是这个，至于是否真的达到了，目前暂且不能做出保证)。
5. `#[expand]`

   会在编译时输出生成的代码。之所以添加这个选项而不建议大家使用`cargo expand`来查看生成的代码，是因为后者把所有宏都展开了，不利于阅读或者调试，而且后者要求rustc的编译至少成功进行到了某个阶段(具体哪个阶段我还不清楚)才会输出，这对帮助解决编译错误可能是没有帮助的。

   由于lalr1生成的rust代码不包含位置信息，**所以parser中的编译错误和运行错误都无法得知具体在什么位置**，而如果使用`#[expand]`输出的代码来代替整个impl块，效果是完全等同的，这样可以方便调试或者看自己具体那里编译出错了。
6. `#[show_fsm(OutputPath)]`和`#[show_dfa(OutputPath)]`

   分别是把parser的lr fsm和lexer的dfa的图形以dot文件的形式输出到对应路径中。其实是没啥用的一个功能，因为这两个自动机都太大了，甚至dot文件都不一定能顺利地渲染成图片，更不用说靠人眼从中提取什么有用的信息了。这两个选项可以说纯属娱乐，如果电脑性能比较好的话不妨尝试一下看看自动机到底长啥样。

   不过这个功能也并不是完全没用的，re2dfa和lalr1中都提供了生成dot文件的接口，如果是一些简单一点的例子，的确是可以用来输出有意义的图片的\~\~(例如作业题什么的)\~\~。
