Я программирую стандартную математическую нотацию ->DC POSIX-совместимый формат конвертер. Он берет входную строку, анализирует ее в промежуточный тип данных и затем превращает ее в выходную строку на show
.Как заставить функцию Parsec chainl1 следовать правилам приоритета операторов
Этот тип данных используется. У меня нет никаких проблем с типом данных -> Вывод строки преобразования, он работает безотказно:
data Expression = Expression :+ Expression
| Expression :- Expression
| Expression :* Expression
| Expression :/ Expression
| Expression :^ Expression
| Cons String
infixr 0 :+
infixr 0 :-
infixr 1 :*
infixr 1 :/
infixr 2 :^
instance Show Expression where
show (x :+ y) = unwords [show x, show y, "+"]
show (x :- y) = unwords [show x, show y, "-"]
show (x :* y) = unwords [show x, show y, "*"]
show (x :/ y) = unwords [show x, show y, "/"]
show (x :^ y) = unwords [show x, show y, "^"]
show (Cons y) = y
Парсек парсер часть, однако, отказывается соблюдать определенные правила старшинство операторов. Очевидно, из-за способом chainl1
используется в определении subexpression
парсера:
expression :: Parser Expression
expression = do
spaces
x <- subexpression
spaces >> eof >> return x
subexpression :: Parser Expression
subexpression = (
(bracketed subexpression) <|>
constant
) `chainl1` (
try addition <|>
try substraction <|>
try multiplication <|>
try division <|>
try exponentiation
)
addition = operator '+' (:+)
substraction = operator '-' (:-)
multiplication = operator '*' (:*)
division = operator '/' (:/)
exponentiation = operator '^' (:^)
operator :: Char -> (a -> a -> a) -> Parser (a -> a -> a)
operator c op = do
spaces >> char c >> spaces
return op
bracketed :: Parser a -> Parser a
bracketed parser = do
char '('
x <- parser
char ')'
return x
constant :: Parser Expression
constant = do
parity <- optionMaybe $ oneOf "-+"
constant <- many1 (digit <|> char '.')
return (if parity == Just '-'
then (Cons $ '_':constant)
else Cons constant)
Есть ли способ сделать синтаксический анализатор принимать во внимание правила оператора очередности без необходимости переписывать полноту моего кода?
спасибо. Это инкапсуляция парсера была именно тем, что мне нужно. До сих пор я работал только с регулярными выражениями, поэтому контекстно-зависимые возможности Parsec и тому подобное все еще заставляют мою голову немного вращаться. – Witiko
Вам придется немного переучиться, но писать парсеры намного проще, чем регулярные выражения для даже слегка сложных вещей, когда у вас будут ноги. –