一元减法搞乱解析

问题描述 投票:0回答:1

这里是要解析的语言ID的语法:

expr ::= val | const | (expr) | unop expr | expr binop expr
var ::= letter
const ::= {digit}+
unop ::= -
binop ::= /*+-

我正在使用haskell wiki中的示例。

这里没有显示语义和令牌解析器。

exprparser = buildExpressionParser table term <?> "expression"

table = [ [Prefix (m_reservedOp "-" >> return (Uno Oppo))] 
         ,[Infix (m_reservedOp "/"  >> return (Bino Quot)) AssocLeft
          ,Infix (m_reservedOp "*"  >> return (Bino Prod)) AssocLeft]
         ,[Infix (m_reservedOp "-"  >> return (Bino Diff)) AssocLeft
          ,Infix (m_reservedOp "+"  >> return (Bino Somm)) AssocLeft]
        ]

term = m_parens exprparser
       <|> fmap Var m_identifier
       <|> fmap Con m_natural

减号char出现两次,一次为一元,一次为二进制运算符。

在输入"1--2"上,解析器仅给出Con 1

而不是预期的"Bino Diff (Con 1) (Uno Oppo (Con 2))"

欢迎任何帮助。Full code here

parsing haskell parsec
1个回答
0
投票

reservedOp的目的是创建一个解析器(您将其命名为m_reservedOp),以解析给定的运算符符号字符串,同时确保它是较长的运算符符号字符串的前缀[[not 。您可以从源代码中的reservedOp的定义中看到这一点:

reservedOp name = lexeme $ try $ do{ _ <- string name ; notFollowedBy (opLetter languageDef) <?> ("end of " ++ show name) }
请注意,仅在提供的name后没有任何opLetter符号的情况下,才会对其进行解析。

在您的情况下,字符串"--2"不能由m_reservedOp "-"解析,因为即使它以有效的运算符"-"开头,该字符串也将作为更长的有效运算符"--"的前缀出现。] >

在使用单字符运算符的语言中,您可能根本不想使用reservedOp,除非您想在不插入空格的情况下禁止相邻的运算符。只需使用symbol "-",它就会始终解析"-",无论后面是什么(并消耗后面的空白,如果有的话)。同样,在具有

固定集

运算符(即,没有用户定义的运算符)的语言中,您可能不会使用operator解析器,因此将不需要opStart或[C0 ]。如果没有reservedOpNamesreservedOp,则不会使用operator解析器,因此也可以将其删除。这可能非常令人困惑,opLetter文档在解释“保留”机制应该如何工作方面做得很糟糕。这是入门书:

让我们从标识符开始,而不是运算符。在一种典型的语言中,它允许用户定义标识符(即,几乎所有语言,因为“变量”和“功能”具有用户定义的名称)并且还可能具有一些不允许用作标识符的保留字,相关设置在`GenLanguageDef中是:

Parsec

使用identStart       -- parser for first character of valid identifier
identLetter      -- second and following characters of valid identifier
reservedNames    -- list of reserved names not allowed as identifiers
对象创建的lexeme(吸收空白)解析器是:

    GenTokenParser-解析未知的用户定义标识符。它解析从identifier开始的字符,后跟零个或多个identStart,直到第一个非identLetter。 (它从不解析部分标识符,因此它永远不会在表上留下更多identLetter。)
  • 另外,它检查标识符是否不在列表identLetter中。
reservedNames-解析给定的字符串。如果字符串是保留字,则不会检查它是否不是较大有效标识符的一部分。因此,symbol会与symbol "for"的开头匹配,而这几乎是您想要的。请注意,foreground = "black"不使用symbolidentStartidentLetter
  • reservedNames-解析给定的字符串,然后确保其后没有reserved。因此,identLetter将解析m_reserved "for",但
  • not
  • 解析for (i=1; ...。通常,提供的字符串将是有效的标识符,但是对此不作任何检查,因此,如果需要,您可以编写foreground = "black"-用一种具有常见字母数字标识符的语言编写,只要它可以解析m_reserved "15"后面没有字母或其他数字。另外,也许有些令人惊讶,没有检查提供的字符串是否在"15"中。如果这对您有意义,那么操作员设置将遵循完全相同的模式。相关设置为:

    reservedNames

    和相关的解析器是:

      opStart -- parser for first character of valid operator opLetter -- valid second and following operator chars, for multichar operators reservedOpNames -- list of reserved operator names not allowed as user-defined operators -解析一个未知的,用户定义的运算符,从operator开始,然后是零个或多个opStart,直到第一个非opLetter。因此,应用于字符串opLetteroperator将始终占据整个运算符"--2",而不仅仅是前缀"--"。还要进行一次检查,确认所得的运算符不在"-"列表中。
    • reservedOpNames-完全与标识符相同。它解析没有检查或引用symbolopStartopLetter的字符串,因此reservedOpNames会很好地解析字符串symbol "-"的第一个字符,而将第二个"--"字符保留为稍后的解析器。
    • "-"-解析给定的字符串,确保其后没有reservedOp。因此,opLetter将解析m_reservedOp ":"的开头,但不解析“:+:y":lst"+, assumingopLettermatchesreservedOpNames`。
    © www.soinside.com 2019 - 2024. All rights reserved.