• Yacc用优先级和结合性解决冲突


    上一章,我们演示了一个已经写好的文法,带有优先级和结合性的。本章内容为如何利用Yacc写优先级和结合性。

    和上一章一样新建一个F#语言的xUnit测试项目,并安装依赖的NuGet包。

    然后,我们先输入设计好的文法,此时我们还不知道是否需要解决优先级:

    lines : lines expr "
    "
          | lines "
    "
          | /* empty */
          ;
    expr : expr "+" expr
         | expr "-" expr
         | expr "*" expr
         | expr "/" expr
         | "(" expr ")"
         | "-" expr
         | NUMBER
         ;
    

    如前所述,我们可以获取yacc输入文件的结构化表示:

        let path = Path.Combine(__SOURCE_DIRECTORY__, @"C4F59.yacc")
        let text = File.ReadAllText(path)
        let yaccFile = YaccFile.parse text
    

    上面代码最后的yaccFilemainRules,我们打印出来看:

    
    

    我们生成歧义表:

    let tbl = AmbiguousTable.create yaccFile.mainRules
    

    歧义表测试,首先,文法设计不能有产生式冲突,否则需要修改产生式:

        [<Fact>]
        member this.``there are not production conflicts``() =
            let pconflicts = ConflictFactory.productionConflict tbl.ambiguousTable
            Assert.True(pconflicts.IsEmpty)
    

    其次,文法设计尽量不要过度使用同一个符号,这只是警告,如果文法通过,可以无视:

        [<Fact>]
        member this.``show warning``() =
            let warning = ConflictFactory.overloadsWarning tbl
            Assert.True(warning.IsEmpty)
    

    当文法产生式完成,不再修改后,可以查看移动与归约的冲突:

        [<Fact>]
        member this.``resolve shift reduce conflicts``() =
            //优先级冲突
            let srconflicts = ConflictFactory.shiftReduceConflict tbl
            //show srconflicts
            let y = set [
                set [["expr";"-";"expr"];["expr";"expr";"*";"expr"]];
                set [["expr";"-";"expr"];["expr";"expr";"+";"expr"]];
                set [["expr";"-";"expr"];["expr";"expr";"-";"expr"]];
                set [["expr";"-";"expr"];["expr";"expr";"/";"expr"]];
                set [["expr";"expr";"*";"expr"]];
                set [["expr";"expr";"*";"expr"];["expr";"expr";"+";"expr"]];
                set [["expr";"expr";"*";"expr"];["expr";"expr";"-";"expr"]];
                set [["expr";"expr";"*";"expr"];["expr";"expr";"/";"expr"]];
                set [["expr";"expr";"+";"expr"]];
                set [["expr";"expr";"+";"expr"];["expr";"expr";"-";"expr"]];
                set [["expr";"expr";"+";"expr"];["expr";"expr";"/";"expr"]];
                set [["expr";"expr";"-";"expr"]];
                set [["expr";"expr";"-";"expr"];["expr";"expr";"/";"expr"]];
                set [["expr";"expr";"/";"expr"]]]
    
            Should.equal y srconflicts
    

    两个产生式的集合是第一个和第二个产生式冲突。一个产生式的集合,是自己和自己冲突。我们根据打印的冲突产生式很容易知道那些产生式需要指定优先级和结合性。注意连字号可以指向两个产生式。负号,和减号。需要在第一部分给产生式命名。使用%prec,别忘了文法产生式与优先级列表之间需要%%分隔。

    lines : lines expr "
    "
          | lines "
    "
          | /* empty */
          ;
    expr : expr "+" expr
         | expr "-" expr
         | expr "*" expr
         | expr "/" expr
         | "(" expr ")"
         | "-" expr %prec UMINUS
         | NUMBER
         ;
    
    %%
    
    %left "+" "-"
    %left "*" "/"
    %right UMINUS
    
  • 相关阅读:
    穿戴式眼镜显示屏方案
    centos8 shell脚本定时restart workerman问题
    cmake中文文档(一)-编译命令行工具
    Dear ImGui中文文档(一)
    PHP实现布隆过滤算法
    case when的记录
    前端的一些记录
    z-index 弹出元素被原本页面的元素遮挡住
    DevExpress 导出pdf中文不显示或者乱码问题
    DevExpress控件位置的微调
  • 原文地址:https://www.cnblogs.com/cuishengli/p/14373418.html
Copyright © 2020-2023  润新知