Parsec зависает при использовании buildExpressionParser

Я пытаюсь создать базовый синтаксический анализатор для математических уравнений с использованием Parsec, и у меня возникли некоторые проблемы с использованием buildExpressionParser функция.

Я создал parsecParse функция, но она просто навсегда зависает, когда я вызываю ее в ghci: parse parsecParse "" "200*6", Я не могу понять, почему. Есть идеи?

module Equation where

import Control.Applicative hiding (many, (<|>))

import Text.Parsec.Char (char, digit)
import Text.Parsec.Combinator (many1, option)
import Text.Parsec.Expr (Assoc (..), Operator (..), buildExpressionParser)
import Text.Parsec.Prim ((<|>), try)
import Text.Parsec.String (Parser)

data Equation = Leaf Double | Tree Op Equation Equation deriving (Show)
data Op = Plus | Minus | Multiply | Divide deriving (Show)

parsecParse :: Parser Equation
parsecParse = try parseOperator <|> parseDouble

parseDouble :: Parser Equation
parseDouble = fmap (Leaf . read) $ (++) <$> integer <*> fraction
    where integer  = many1 digit
          fraction = option "" $ (:) <$> char '.' <*> many1 digit

parseOperator :: Parser Equation
parseOperator = buildExpressionParser table parsecParse
    where table     = [[ getOp '*' Multiply, getOp '/' Divide ],
                       [ getOp '+' Plus,     getOp '-' Minus ]]
          getOp c o = Infix (char c >> return (Tree o)) AssocLeft

1 ответ

Решение

Вы получаете проблемы, потому что parseOperator возвращает себя в крайнее левое положение, то, что Parsec не может обработать напрямую, и которое дает бесконечную рекурсию.

Последний аргумент buildExpressionParser должен быть синтаксический анализатор, который анализирует более "основные" элементы.

Это нормально для косвенного рекурсии на parseOperatorНапример, для обработки элементов в скобках, но не так, чтобы они оказались в крайнем левом положении.

Другие вопросы по тегам