如何从函数调用中删除逗号和括号

How to remove commas and parenthesis from function calls

在使用 happy parser 编写的函数式语言编译器中,这与 yacc/bison 非常相似,我实现了列表并使用列表一些核心函数 mapconcatfilter,使用以下规则:

Exp:
...
| concat '(' Exp ',' Exp ')'         { Concat   }
| map '(' Exp ',' Exp ')'            { Map   }
| filter '(' Exp ',' Exp ')'         { Filter   }

这很好用,但在大多数函数式语言中没有括号或逗号,所以我宁愿写 map myfun [1,2,3] 而不是 map(myfun, [1,2,3])。语法中明显的修改如下:

Exp:
...
| concat Exp Exp         { Concat   }
| map Exp Exp            { Map   }
| filter Exp Exp         { Filter   }

但是这个修改包含了很多reduce-reduce冲突。如何在没有逗号和括号的情况下实现函数调用的解析?

我能提取的最小冲突语法是这样的:

Exp :
    -- Math
     Exp '+' Exp                         { Op  Add  }
    | Exp '-' Exp                        { Op  Sub  }

    -- Literals
    | num                                { Num  }
    | '-' num %prec NEGATIVE             { Num (-) }

    -- Lists
    | map Exp Exp                        { Map   }

它产生了 4 个 reduce/reduce 冲突。删除任何规则也会导致冲突。如果你有兴趣,这里是full grammar

问题在于,由于函数应用程序中没有令牌,因此基于令牌的优先级冲突解决方案效果不佳——当它试图决定可能是函数应用程序的转变并减少一些其他表达式,先行标记是参数表达式开头的任何内容;没有可以使用的 'blank space' 令牌。

要解决该问题并使其正常工作,您需要将可能是表达式的每个标记(FIRST(Exp) 中的每个标记)的优先级设置为函数应用程序的优先级。如果这些标记中的任何一个需要一些其他优先级(例如,任何可能是中缀或前缀的标记),这会变得更加棘手并且可能无法工作。

一个可能更好的替代方法是根本不使用优先规则——相反,为每个优先级别使用不同的规则来消除语法歧义:

Exp: Term | Exp '+' Term
Term: Factor | Term '*' Factor
Factor: Primary | Factor Primary
Primary: num | id | '(' Exp ')'