BUAA-SE-Compiling / miniplc0-handbook

miniplc0 指导书
https://mini.buaasecompiling.cn
22 stars 6 forks source link

add blank in grammer for both java and cpp #11

Closed HolmiumTS closed 3 years ago

HolmiumTS commented 3 years ago

修复了java和cpp指导书中文法部分没有对空白序列进行说明的问题 新增<空白序列>和<空白符>(空白符的定义copy自Readme.md对约定6的说明) 保证<空白序列>不会连续出现(没有二义性)

wtdcode commented 3 years ago

这是一个很好的问题,能提出来这个说明你跟我俩当年一样较真(笑)。这里先 @fazdzz,看看他怎么说。

这个问题我们内部早就讨论过了,我们也参考了一些语言的文法设计,这里放一个 Python 的 Grammar 和 Lua 的 Grammar 作为示例。可以看出在 Python 里有关空白符是被严格规定了的,原因不言而喻,然而作为对比 Lua 的语法就没管这些。我没研究过他们的实现,但是我猜测原因是:

BNF/EBNF 主要是为语法分析服务(回忆一下递归下降的实现方法),也就是说如果空白符不参与语法分析和之后的分析的话那么他们应该在词法分析就被解决,显然 Python 需要把空白符拿到语法分析但是 Lua 并不需要,所以他们的 BNF 在这里产生了分歧。

那么回到我们的实验,我们需要把空白符放进语法分析吗?实际上是不需要的。那么下一个问题,怎么在词法分析解决?在1621之前这个问题没有任何解答,在我们实施实验的时候 mini 我隐式的用 STL 解决了这个问题,见 这里,c0要麻烦一些,我们在这里规定了空白符而且我们期望大家在词法分析解决,总的来说我们没有把这个问题抛给学生,但是绝大多数学生应该都不会遇到这个问题(事实上来看当时应该也没人注意到这个)。

最后我有点忘了为什么这个问题就被提出来了(@fazdzz),但是本质原因应该跟 123abc 有异曲同工之妙,我个人的意见是没必要放在BNF里。

lynzrand commented 3 years ago

ouo

咱的意见是,不把空白符放进语法里,而是直接描述说

在词法分析的时候,采用最大吞噬(最长匹配)原则分析每一个 token。在分析时,遇到空白符时和遇到其他不在 token 中的字符时一样结束这个 token 的分析,在开始下一个 token 的分析时从当前位置之后的第一个非空白字符开始。

fazdzz commented 3 years ago

蟹腰,人刚下班,利益相关:初版文档编辑者(x)

因为 mini 和 C0 是同时进行设计的,最初考虑如何表示语法的时候就希望尽可能有一个统一的标准,我参考了下列资料:

JSON 语法 C0 reference 阅读体验良好版 or C0 reference C++ 的编译阶段 一些在野的 C++ 语法梳理,有些已经不存在了,比较有代表性的是 这个版本 ,它整理了 ISO/IEC 标准 中散落的 syntax 定义

个人观点,空白符当然是可接受的字符,最初设计语法时考虑过像 JSON 语法 一样显式地加入 ws 这样的非终结符代表空白符序列,这样当然是最严谨的。

但是在实际操作中发现,在每一条语法中都显式加入 ws 的话,会使语法肉眼可见地臃肿(而且很容易遗漏,你的 commit 里也如此)。对于 C0 这样比较复杂的语法,空白符几乎可以出现在每条规则的任何地方。正如 @wtdcode 所言,空白符对于 mini 和 C0 来说都是只有分隔意义的语法成分,我也认为突出语法的重点是必要的,不然 C++ 的语法恐怕会变得惨不忍睹吧(笑)。因此最终我没有把 ws 放入规则,这里其实理应是要补充说明空白符的处理规则的,但是刚才浏览了一下没有,应该是疏忽所致。

决策上,我支持 @01010101lzy 的说法:

不把空白符放进语法里,而是直接描述说

在词法分析的时候,采用最大吞噬(最长匹配)原则分析每一个 token。在分析时,遇到空白符时和遇到其他不在 token 中的字符时一样结束这个 token 的分析,在开始下一个 token 的分析时从当前位置之后的第一个非空白字符开始。

顺带一提,我个人倾向于把空白符序列作为词法分析的有效 token 导出,但是在语法分析取 token 时隐式地过滤。

fazdzz commented 3 years ago

补充:

空白符序列是否应当出现在语法,有一个我纠结过的点:个人认为不一定非要有长度(即,空串""也是空白符序列)。

比如你修改的规则:

<常量声明语句> ::= 'const'<空白序列><标识符><空白序列>'='<空白序列><常表达式>';'<空白序列>

这里 'const'<标识符> 中间一定要在语法层面体现必须有空格吗?

这里涉及到一个语法设计者期望在什么阶段发现语法错误的问题,这与 @wtdcode 提到的 123abc 是一个意思。

因为词法分析遵从最长匹配原则,如果存在 constabc=1; 这样的输入,那么词法分析时根本就分析不出来 'const',而是:

identifier(constabc)
operator(=)
integer(1)
operator(;)

无论使用哪一版的规则,都不能改变这里发现语法错误的时机。

对于 const abc=1;,得到:

keyword(const)
whitespaces
identifier(abc)
operator(=)
integer(1)
operator(;)

这里的空白符序列,即使不作为词法分析的结果导出,也不会影响语法分析的进行。

从精简语法的角度出发,这样的空白符真的有必要出现在语法吗?

lynzrand commented 3 years ago

那咱先把咱这版描述更新进去了

wtdcode commented 3 years ago

好活 (🖐️ 夸 好.jpg)

fazdzz commented 3 years ago

可以看出第一版实验方案充满了两个助教的个人主义色彩(

我还是希望它逐渐变得客观合理而完备的(大颗龙之泪.jpg

lynzrand commented 3 years ago

已更新。采用的实际描述是

在词法分析的时候,应采用最大吞噬(最长匹配)原则分析每一个 token。在分析中遇到空白符时,应和遇到其他不被 token 接受的字符时一样结束这个 token 的分析;在开始下一个 token 的分析时从当前位置之后的第一个非空白字符开始。


可以看出第一版实验方案充满了两个助教的个人主义色彩(

我还是希望它逐渐变得客观合理而完备的(大颗龙之泪.jpg

别骂了别骂了,马上就要成各届助教个人主义色彩的大杂烩了(

wtdcode commented 3 years ago

那看来可以先close咯。