• 谱写未来
    2019-08-21
    只有第一步用add,接下来都用add',后面不是都是add'了,还是左边那张图不是吗?

    作者回复: 是的。

    我们通过改写规则的方法,能够避免左递归,但无法同时照顾结合性。这是很多教科书都没有提到的一件事情。

    好在,这个事情比较简单,因为改写后的规则,是多了一个标准的“尾巴”。对,很多人都称呼它为尾巴。这个尾巴可以特别处理。

    也就是说,结合性的信息已经不是单纯通过上下文无关文法提供了,要辅助额外的信息。

    无独有偶,还有的作者用别的方法来解决算法优先级问题,比如LLVM的一个初学者教程,用的也是标注算符优先级的方法,也要在文法的基础上提供额外的信息给算法。

    http://llvm.org/docs/tutorial/MyFirstLanguageFrontend/index.html

    本课程讲究实践。在实践中才会看到这些教科书上讲不到的点,但在面对实际问题时必须要解决。

    
     10
  • Enzo
    2019-09-06
    老师 看不懂以下的公式
    add -> mul | add + mul
    mul -> pri | mul * pri
    pri -> Id | Num | (add)
    是需要找本书看看吗?

    作者回复: 我给你解释一下吧:
    以 add -> mul | add + mul 为例,
    -> 意思是推导出;
    | 意思是“或者”
    这个加号,我回头修改一下吧,可以用引号引起来,'+'只是匹配一个+号字符的意思,没有别的意思。
    所以,这个产生式的意思是:
    加法表达式,要么是一个乘法表达式,要么是一个加法表达式,后面跟个+号,然后再跟一个乘法表达式。

    参考书的话,看看这个链接:https://time.geekbang.org/column/article/125948

    
     8
  • 贾献华
    2019-08-20
    https://github.com/iOSDevLog/Logo
    Swift 版《编译原理之美》代码,可以在 iOS 上运行。

    作者回复: 厉害!点赞!

     1
     4
  • knull
    2019-08-28
    老师,我简单研究了下bnf,我觉得你写法最好修正下,不然不好看。比如:
    原来的写法:add -> mul (+ mul)*
    现在的写法:add -> mul ('+' mul)*
    '+'表示关键字;
    + 直接用,表示1个活多个;
    加单引号以示区分,看起来方便一点
    展开

    作者回复: 有道理!用EBNF的话,+号有特殊含义。
    我们修改一下文稿。
    谢谢你的建议,你很细心,并且自己去做研究了!

    
     3
  • pwlazy
    2019-08-21
    2+3+4+5生产的AST 是否是这样的?

    Programm Calculator
        
          AdditiveExp +
            AdditiveExp +
                AdditiveExp +
                    IntLiteral 2
                    IntLiteral 3
                IntLiteral 4
            IntLiteral 5
    展开

    作者回复: 是,没错。

     1
     3
  • 春去春又来
    2019-08-21
    老师 上一讲看懂了 这一讲在推导公式的时候迷糊了。可以加点推导过程的详细讲解嘛 而不是直接给一个推导的结果图

    作者回复: 好的,我对于公式推导过程再加个图。加完了在回复中告诉你。

    你指的是用:
    add -> mul add'
    add' -> + mul add' | ε

    来推导2+3+4的过程不清楚吗?

    
     3
  • Lafite
    2019-09-03
    请问宫老师
    add -> mul add'
    add' -> + mul add' | ε
    这两个产生式的推导过程应该是怎么样的,为什么可以转化为EBNF的写法呢。

    作者回复: 转化成EBNF:add ::= mul ( '+' mul)*
    一个表达式就解决了,更简洁。不需要add'了。

    推导过程,要看算法。每种算法采用的推导过程是不一样的。如果用递归下降算法,推导:2+3*5
    我们按照调用过程分成几层:
    第1层:采用 mul add',因为mul能完整的匹配2,不能再往后匹配了,所以第一个子节点建立完毕。接着用add'去建立第二个子节点。
    第2层:运用add'的第一个产生式,先匹配上了+号,之后去匹配mul,也就是3*5,也是成功的。然后再去匹配add'。
    第3层:这次用add'的时候,还是先尝试第一个产生式,失败。为什么呢?因为没有+号。回溯。尝试第二个产生式,即epsilon。也就是返回空。那么第3层就完成了。
    第3层成功后第2层,第2层也就成功完成了。
    同理,返回第1层,第1层也成功。
    这个过程是否听得清楚?
    可以换着不同的例子多推导几遍,就会变得很熟练了!

     2
     2
  • 许童童
    2019-08-21
    老师可以说一下生成出来的AST怎么使用吗?
    https://github.com/jamiebuilds/the-super-tiny-compiler
    这个编译器写得怎么样,老师可以说一下吗?

    作者回复: AST是对计算机语言的结构化表示,它是一切后续工作的基础,比如做语义分析,翻译成目标代码。

    看了一下你发的那个链接。是从类似lisp语言的函数调用翻译到C语言的格式。这属于语言翻译的范畴。

    我有两点点评:
    1.lisp语言很容易翻译,一个递归下降算法肯定搞定。因为它的语法结构很简单,所有的语法结构都是一层层括号的嵌套。
    2.翻译后得到AST,再生成C的格式,这就很简单了。基本上就是把括号位置改一下而已。

    感谢你经常参与讨论!

    
     2
  • nil
    2019-09-11
    老师你好,问个问题。最终通过循环来消除递归带来的二元预算符的结合性问题?能否直接在递归中消除结合性问题?

    作者回复: 理论上是可以的,但需要给算法提供额外的信息。
    采用递归下降算法的时候,我们在函数中标准的处理放肆,都是创建一个AST节点,并返回给调用者。调用者都是把返回的AST作为自己的子节点。
    如果要改变结合性,相当于要知道什么时候把返回的节点作为自己的父节点。
    Antlr里用属性标注的方法,来提供这个额外的信息。这种信息在标准的上下文无关文法中是无法提供的。

    
     1
  • 阿尔伯特
    2019-09-11
    https://github.com/albertabc/compiler
    继续攒代码。
    有了上节课的基础,这节相对比较容易理解。用文法的形式推导,最终消除了左递归的思路我觉得很有意思,用左右递归代表结合性,用文法上下级实现了优先级,这些可以作为解决问题的一个思路和方法,用比较平常的普通方法解决了这些问题。感觉比中缀后缀表达式容易掌握。

    作者回复: 嗯。编译且运行了一下。

    
     1
  • Enzo
    2019-09-06

    exp -> or | or = exp
    or -> and | or || and
    and -> equal | and && equal
    equal -> rel | equal == rel | equal != rel
    rel -> add | rel > add | rel < add | rel >= add | rel <= add
    add -> mul | add + mul | add - mul
    mul -> pri | mul * pri | mul / pri
     老师不懂这里的 + - >= 等符号的意思 能推荐本书 吗
    展开

    作者回复: 所有的操作符,你可以加上引号,也就是去匹配这样一个字符而已。没有太复杂的意思。
    add -> mul | add '+' mul | add '-' mul

    参考书籍的话,参见这篇攻略:https://time.geekbang.org/column/article/125948

    
     1
  • 半桶水
    2019-08-21
    是否可以给一些扩展资料的链接,有些概念,推导还是需要更多资料和练习才能掌握

    作者回复: 如果想练习语法规则的推导,那么随便买哪本教材都可以。一般也都会带些练习。

    其他的扩展资料,我后面有想到的,会提供链接。

    
     1
  • 简简酱
    2019-12-23
    学习这门课的时候 结合前后和留言问答 会好理解一些

    作者回复: 嗯。留言中别人遇到的问题,对自己也会有用。你如果有问题的话,也多提问!

    
    
  • 草戊
    2019-12-14
    antlr4能处理直接左递归了,表达式文法写起来直观很多

    作者回复: 是的。

    
    
  • ldd
    2019-12-04
    老师,我想问下,我之前的理解是把中缀表达式用栈改写成后缀表达式也可以生成AST树,老师推荐这种做法吗?
    
    
  • 慧强
    2019-12-01
    左递归可以通过改写语法规则来避免,而改写后的语法又可以表达成简洁的 EBNF 格式,从而启发我们用循环代替右递归。 是不是错了,,应该为 从而启发我们用循环代替左递归?
    
    
  • Geek_e986e3
    2019-11-15
    老师想问问

    add -> mul add'
    add' -> + mul add' | ε
    这个表达式是啥意思 为何和之前的语法不一样。
    还有 没看明白咋就变成了这个:add -> mul (+ mul)*
    能解释下吗?
    展开
    
    
  • knull
    2019-10-28
    add -> mul | add + mul 改成add-> pri |add + mul,是否可以

    作者回复: 这两个产生式应该是不等价的。
    你修改后的产生式,不能解析3*5这样的纯乘法表达式。

    
    
  • eviltion
    2019-10-19
    add -> mul add'
    add' -> + mul add' | ε
    这个是顺序匹配吗?就是先匹配mul然后返回的是2再匹配add'

    作者回复: 对的,递归下降算法都是先匹配完第一个元素,再匹配第二个,从左向右。

    
    
  • 郑家庄赶大车的老郑
    2019-10-07
    作为一个外行,最开始影响我理解的竟然是"推导"这样的术语,硬头皮看了,似乎是“可以展开为”的意思,不知道理解对了没有。

    作者回复: 非常对!
    1.就是要把这些看上去很难的概念,变成自己的直观理解。
    2.基础概念,比如啥叫推导,就是要重视。不要觉得不好意思。还是那个话,在别人提不出问题的地方提问,才叫厉害。基础概念,我们容易一模糊就过去了。但推敲一下呢,很有意思。

     1
    
我们在线,来聊聊吧