You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Parsec解析含中缀运算符的简易语言时测试失败求助

解决Parsec解析中缀运算符时的“意外空格”错误

Parsec解析中缀运算符时报“意外空格”,核心原因是没有显式处理运算符前后的空白字符——你的前缀表达式能正常工作,大概率是因为解析前缀符号或数字时已经处理了空格,但中缀运算符的解析逻辑遗漏了这一步。以下是具体的排查和修复方案:

1. 分离词法与语法解析(Parsec最佳实践)

先定义一个通用的空白跳过解析器,再用它包装所有需要忽略空格的基础解析单元:

import Text.Parsec
import Text.Parsec.Expr
import Text.Parsec.String (Parser)

-- 跳过任意数量的空格、制表符
skipSpaces :: Parser ()
skipSpaces = skipMany (space <|> tab)

-- 包装解析器,确保解析完目标后自动跳过后续空白
lexeme :: Parser a -> Parser a
lexeme p = p <* skipSpaces

2. 修正中缀运算符的定义

使用buildExpressionParser时,所有运算符的解析器必须用lexeme包装,确保运算符前后的空格被正确跳过:

data G = Low Int | Up Int | And G G | Or G G deriving (Show, Eq)

exprParser :: Parser G
exprParser = buildExpressionParser opTable term <* eof
  where
    opTable =
      [ -- 前缀运算符:<、>
        [ Prefix (lexeme (string "<") >> return Low)
        , Prefix (lexeme (string ">") >> return Up)
        ]
      , -- 中缀运算符:&&、||(左结合)
        [ Infix (lexeme (string "&&") >> return And) AssocLeft
        , Infix (lexeme (string "||") >> return Or) AssocLeft
        ]
      ]
    -- 基础项:整数(用lexeme包装,确保数字后空格被跳过)
    term = lexeme (fmap (Low . fromIntegral) integer)

3. 验证前缀解析的一致性

检查你之前的前缀表达式解析逻辑,确保和中缀的空格处理规则一致。比如不要单独在前缀符号后手动跳空格,统一用lexeme包装,避免规则不一致:

-- 错误示例:仅在符号后跳空格,规则不统一
badPrefix = string "<" >> skipSpaces >> (Low <$> integer)
-- 正确示例:用lexeme统一处理
goodPrefix = lexeme (string "<") >> (Low <$> lexeme integer)

4. 测试修复效果

修复后,测试>1 && <42、> 10 || < 20这类带空格的中缀表达式,应该能正常解析出对应的And/Or构造器结构。


内容的提问来源于stack exchange,提问作者GlinesMome

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 02:00:06