微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

e2 中 let e1 的明确语法

如何解决e2 中 let e1 的明确语法

我试图创建一个 let 语法,我的想法是这样的

start : let
let : "let" ID ("=" let)? in let | atom
atom : ANYTHING | "(" let ")"
ID : /[a-z]+/

这个想法是解析像 let A = B in Clet A in B 或两者混合 let f = let x in x + 1 in f(1) 这样的表达式。我也想支持括号来消除歧义,如 let A = (let b in b + 1) in A(1) + 1

我正在使用 Lark 和 LALR 解析器,但我在语法上苦苦挣扎,无法为此定义明确的语法

我试过了


from lark import Lark,Transformer as LarkTransformer


grammar = """
    start : expr
    expr : LET ID (EQUAL exprcont)? IN exprcont | exprcont
    exprcont : ANYTHING | LPAR expr RPAR | expr
    ANYTHING.0 : /.+/
    LET : "let"
    IN : "in"
    ID : /[a-z_][a-z0-9_]*/
    EQUAL : "="
    LPAR.10 : "("
    RPAR.10 : ")"

    %import common.WS
    %ignore WS
"""

let_parser = Lark(grammar,parser="lalr")

print(let_parser.parse("let a = 1 in let b = 2 in a + b").pretty())

但是我得到了很多减少减少错误

Traceback (most recent call last):
  File "/Users/gecko/code/lampycode/letparser.py",line 55,in <module>
    let_parser = Lark(grammar,parser="lalr")
  File "/Users/gecko/.pyenv/versions/lampy/lib/python3.9/site-packages/lark/lark.py",line 339,in __init__
    self.parser = self._build_parser()
  File "/Users/gecko/.pyenv/versions/lampy/lib/python3.9/site-packages/lark/lark.py",line 373,in _build_parser
    return self.parser_class(self.lexer_conf,parser_conf,options=self.options)
  File "/Users/gecko/.pyenv/versions/lampy/lib/python3.9/site-packages/lark/parser_frontends.py",line 145,in __init__
    self.parser = LALR_Parser(parser_conf,debug=debug)
  File "/Users/gecko/.pyenv/versions/lampy/lib/python3.9/site-packages/lark/parsers/lalr_parser.py",line 17,in __init__
    analysis.compute_lalr()
  File "/Users/gecko/.pyenv/versions/lampy/lib/python3.9/site-packages/lark/parsers/lalr_analysis.py",line 304,in compute_lalr
    self.compute_lalr1_states()
  File "/Users/gecko/.pyenv/versions/lampy/lib/python3.9/site-packages/lark/parsers/lalr_analysis.py",line 279,in compute_lalr1_states
    raise GrammarError('\n\n'.join(msgs))
lark.exceptions.GrammarError: Reduce/Reduce collision in Terminal('$END') between the following rules: 
    - <exprcont : expr>
    - <start : expr>

Reduce/Reduce collision in Terminal('IN') between the following rules: 
    - <expr : exprcont>
    - <expr : LET ID IN exprcont>

Reduce/Reduce collision in Terminal('RPAR') between the following rules: 
    - <expr : exprcont>
    - <expr : LET ID IN exprcont>

Reduce/Reduce collision in Terminal('$END') between the following rules: 
    - <expr : exprcont>
    - <expr : LET ID IN exprcont>

Reduce/Reduce collision in Terminal('IN') between the following rules: 
    - <expr : exprcont>
    - <expr : LET ID EQUAL exprcont IN exprcont>

Reduce/Reduce collision in Terminal('RPAR') between the following rules: 
    - <expr : exprcont>
    - <expr : LET ID EQUAL exprcont IN exprcont>

Reduce/Reduce collision in Terminal('$END') between the following rules: 
    - <expr : exprcont>

我不知道如何定义这个语法,这个想法很简单let : "let" ID ("=" let)? "in" let | atom有什么想法吗?

解决方法

我认为问题是

start : expr
    expr : ... | exprcont
    exprcont : ... | expr

这个循环意味着你的语法有歧义。

你能摆脱循环吗?

,

如果你想使用像 ANYTHING 这样的终端,不要使用 lalr。使用earley。 (即便如此,它仍然会产生问题)


但这实际上并不是造成这些错误的原因。问题在于 exprexprcont 中的相互递归。您可以删除 expr 中的 exprcont

exprcont : ANYTHING | LPAR expr RPAR

但这仍然行不通。 (除非您使用 parser='earley'lexer='dynamic_complete'。但这会很慢)。您必须重新设计语法以不包含 ANYTHING 终端。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。