簡體   English   中英

使用Lark在BASIC語法中的“ END”和“ END IF”之間發生沖突

[英]Collision in between “END” and “END IF” in BASIC grammar, using Lark

我正在嘗試使用Lark為BASIC創建LALR解析器,並且很難解決“ END”語句和“ END IF”之類的語句之間的沖突。 這是語法的簡化版本:

%ignore /[ \t\f]+/

program: _nlopt _part_list

_part_list: (stmt | block) _nl _part_list
          |

_nlopt: _nl
      |

_nl: _NEWLINE _nl
   | _NEWLINE

block: if_block

stmt: print_stmt
    | end_stmt

end_stmt: END_KW

if_block: IF_KW expr THEN_KW _nl block_body endif_stmt

endif_stmt: END_KW IF_KW

block_body: _block_body_item block_body
          |

_block_body_item: stmt _nl

print_stmt: PRINT_KW expr

?expr: NUMERIC_LITERAL

_NEWLINE: "\n"
NUMERIC_LITERAL: /[\-+]?\d+(\.\d*)?[!#%&]?/

END_KW: "end"i
IF_KW: "if"i
PRINT_KW: "print"i
THEN_KW: "then"i

如果我用這樣的代碼嘗試這種語法:

parser = Lark(grammar, start='program', parser='lalr')

prog = r"""
if 1 then
   print 200
end if
"""
t = parser.parse(prog)
print(t.pretty())

這是我從雲雀身上得到的:

Traceback (most recent call last):
  File "test.py", line 230, in <module>
    t = parser.parse(prog)
  File "/home/user/.pyenv/versions/venv/lib/python3.6/site-packages/lark/lark.py", line 250, in parse
    return self.parser.parse(text)
  File "/home/user/.pyenv/versions/venv/lib/python3.6/site-packages/lark/parser_frontends.py", line 37, in parse
    return self.parser.parse(token_stream, *[sps] if sps is not NotImplemented else [])
  File "/home/user/.pyenv/versions/venv/lib/python3.6/site-packages/lark/parsers/lalr_parser.py", line 68, in parse
    for token in stream:
  File "/home/user/.pyenv/versions/venv/lib/python3.6/site-packages/lark/lexer.py", line 341, in lex
    for x in l.lex(stream, self.root_lexer.newline_types, self.root_lexer.ignore_types):
  File "/home/user/.pyenv/versions/venv/lib/python3.6/site-packages/lark/lexer.py", line 175, in lex
    raise UnexpectedCharacters(stream, line_ctr.char_pos, line_ctr.line, line_ctr.column, allowed=allowed, state=self.state)
lark.exceptions.UnexpectedCharacters: No terminal defined for 'i' at line 4 col 5

end if
    ^

Expecting: ['__IGNORE_0', '_NEWLINE']

如果刪除“ end_stmt”規則,則不會發生。 有沒有一種方法可以解決語法問題,從而避免這種情況發生?

默認情況下,Lark不會警告您有關語法中的移位減少的沖突,而是默默地解決它們,以支持移位。 通常,這會導致解析器無法解析您想要的內容-如此處的情況。 您可以通過將debug = True標志傳遞給Lark()來使百靈鳥對此類沖突發出警告。 這樣一來,即使在通過測試發現問題之前,您也會發現出了問題,甚至可能獲得有關問題所在的有用信息。

啟用debug選項后,您將收到一條警告,提示您存在移位減少沖突,其中END_KW可能意味着當前的block_body已結束,或者可能是end_stmt 這是一個問題,因為LALR(1)解析器只能向前看一個令牌,但是我們必須向前看第二個令牌,以查看在end之后是否有一個if來正確地決定采用哪個選項。

您可以通過將end if轉換為單個令牌(如下所示)來稍微修正一下:

ENDIF_KW: /end[ \t\f]+if/i

然后使用ENDIF_KW而不是END_KW IF_KW

PS:請注意,如果您使用Earley解析而不是LALR(1),則無需進行這些更改,語法就可以正常工作。

我的基本語法也有同樣的矛盾。 由於END WHILE,END IF等原因,基本語言是LALR(2)或LR(2)。如果您具有LR(2)解析器生成器,則可以解析基本語言。 LRSTAR解析器生成器可以創建LR(2)解析器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM