Добавление инфиксного оператора в анализатор выражений - PullRequest
1 голос
/ 02 февраля 2020

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

import qualified Text.Parsec.Expr as Expr
import qualified Text.Parsec.Token as Tokens
import Text.ParserCombinators.Parsec
import Text.Parsec

data Expr = Number Integer
          | Op Expr Expr
          | Boolean Bool

instance Show Expr where
  show (Op l r) = "(+ " ++ (show l) ++ " " ++ (show r) ++ ")"
  show (Number r) = show r
  show (Boolean b) = show b

parens = Tokens.parens haskell
reserved = Tokens.reservedOp haskell

infix_ operator func =
  Expr.Infix (spaces >> reserved operator >> spaces >> return func) Expr.AssocLeft

infixOp =
  Expr.buildExpressionParser table parser
  where
    table = [[infix_ "+" Op]]

number :: Parser Expr
number = 
  do num <- many1 digit
     return $ Number $ read num

bool :: Parser Expr
bool = (string "true" >> return (Boolean True)) <|> (string "false" >> return (Boolean False))

parser = parens infixOp <|> number <|> bool

run = Text.Parsec.runParser parser () ""

Этот синтаксический анализатор может анализировать выражения типа 1, false, (1 + 2), (1 + false), но не 1 + 2 (он анализируется как 1). Если я попытаюсь изменить синтаксический анализатор на parens infixOp <|> infixOp <|> number <|> bool, он застрянет.

Что я должен изменить, чтобы разобрать выражения вроде 1 + 2 без скобок?

1 Ответ

1 голос
/ 02 февраля 2020

Вы должны запустить синтаксический анализатор infixOp на верхнем уровне следующим образом:

run = Text.Parsec.runParser infixOp () ""

В противном случае ваши выражения инфикса могут быть проанализированы только в скобках.

Попытка использовать parens infixOp <|> infixOp <|> number <|> bool, скорее всего, застревает из-за циклов: parser пытается выполнить синтаксический анализ с использованием infixOp, который пытается выполнить синтаксический анализ с использованием parse и т. Д. *

Этот учебник может помочь вам начать с разбора c (они сделали для меня):

https://wiki.haskell.org/Parsing_a_simple_imperative_language

http://dev.stephendiehl.com/fun/002_parsers.html

...