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

时间:2016-10-06 17:35:32

标签: grammar bison yacc happy

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

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

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

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

但是这种修改包含许多减少 - 减少冲突。如何在没有逗号和paranthesis的情况下实现函数调用的解析?

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

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

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

    -- Lists
    | map Exp Exp                        { Map $2 $3 }

它会产生4个减少/减少冲突。删除任何规则也会导致冲突。如果您有兴趣,可以使用full grammar

1 个答案:

答案 0 :(得分:1)

问题是,由于函数应用程序中没有令牌,基于令牌的优先级冲突解决方案不能很好地工作 - 当它试图决定可能是函数应用程序的转移并减少其他一些表达式,前瞻标记是参数表达式的开头;没有可以使用的“空格”标记。

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

可能更好的替代方法是根本不使用优先级规则 - 而是使用针对每个优先级的不同规则消除语法歧义:

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