作者回复: 是的。它会自动处理。
Antlr这个工具做了大量的工作,让开发者编写语法的时候,可以效率更高。
这样的工具,也不是采用固化的LL(1)或LL(2)算法,而是有能力根据语法去决定解析策略。实在不行了还可以回溯。你会发现:1.生产中使用的编译器,会综合采用多种技术,而不仅仅是单纯的采用某个算法。
2.如果要写符合LL(1)算法的语法,其实语法很啰嗦。这是在编译技术发展的早期,计算能力有限,大家更重视执行的效率。而现在,计算能力很强,可以更加照顾开发者效率,而不是计算效率。所有Antlr的语法很友好,很人性化。从表达式的语法就可见一斑。
作者回复: 你看得很细。上下两个图没配起来,两张图用的语法规则是不同的,插图的时候插错了,而且推导过程跳了步骤,我修改一下!
多谢你帮我发现!
作者回复: 没错,mul展开成mul*pri。笔误了。多谢指出!
作者回复: 因为这些孩子节点是父节点最右边的。那么父节点后面会跟什么终结符,这些子节点也会跟这些终结符。
如果一个非终结符位于上一级产生式的最右边,比如:A->abcdB中的B,(我们用大小写区分终结符和非终结符)那么找到可能出现在它右边的终结符,实际上不是那么好找。要看看A后面都可能跟啥,比如:C->abcAb,那么A的Follow集合中有b,B的Follow集合中也要有b。
实际上,我觉得自己的这个实现比较笨拙,受限于我采用的GrammarNode这样的数据结构。后面有时间的话,我再写个更加简洁的算法给大家参考。
作者回复: 这句看不懂?我抽空多加点注释。
作者回复: 把箭头指在线上这种画法确实不大好,会有歧义。我回头更新一版图,让箭头指向每个存储位置的格子上。