使用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
相关产品推荐
相关产品推荐

