我正在为ECMAScript 5(作为玩具)编写解析器。标准规定了如何解析逻辑或表达式:
<LogicalORExpression> :
<LogicalANDExpression>
<LogicalORExpression> || <LogicalANDExpression>
基本上这相当于
<logicalOrExpression> = [<logicalOrExpression> ||] <LogicalAndExpression>
但是如何在不进入infite循环的情况下解析它?我当前的解析器显然会这样做:
logicalOrExpression :: Parser LogicalOrExpression
logicalOrExpression = do
orExpr <- optional $ do
e <- logicalOrExpression
_ <- symbol "||"
return e
andExpr <- logicalAndExpression
case orExpr of
Just e -> return $ LogicalOrExpression (e, andExpr)
Nothing -> return $ AndExpression andExpr
由于
答案 0 :(得分:2)
如果需要解析具有优先级和关联性的运算符语法,则应该使用megaparsec
's built-in tools。
expr = makeExprParser term table
where
term = literal <|> parenthesised expr
table = [[InfixL (string "&&" $> And)], [InfixL (string "||" $> Or)]]
对于literal
和parenthesised
的合适定义,这将解析由左关联中缀&&
和||
运算符组成的文字表达式的语法, &&
的优先级高于||
。 Megaparsec负责生成LL(k)解析器的繁琐工作,并生成正确的(在这种情况下为左关联)解析树。
当然,JavaScript的表达式语法比两个运算符大得多。此示例可以直接扩展为包括(例如)一元前缀运算符,如!
,后缀函数调用等。请参阅the module's documentation。
答案 1 :(得分:1)
该语法看起来相当于
<LogicalORExpression> :
<LogicalANDExpression>
<LogicalANDExpression> || <LogicalORExpression>
成为
<LogicalORExpression> :
<LogicalANDExpression> [|| <LogicalORExpression>]
通常,如果可能,您需要以(大致)LL(1)形式重写语法。
答案 2 :(得分:0)
空字符串匹配此解析器,我相信它会在Magaparsec中导致无限递归。我想你错过了一个&#34;术语&#34;或&#34;布尔&#34;在你的功能的某个地方。如果我写了True || False
什么会捕获第一个&#34; True&#34;
答案 3 :(得分:-1)
由于我希望在生成的AST方面保持真实,我决定切换到基于Earley的解析器而不是解析器组合器,因为Earley的算法可以处理左递归。
如果我可以将语法弄平,我会用Benjamin Hodgson的答案