2014-10-28 3 views
0

Я застрял в точке, в преобразовании выражение, введенное пользователем в мой собственный тип данныхпреобразования типов данных без использования buildExpressionParser

Я сделал это с помощью biuldExpressionParser, но используя простой парсер и рекурсию я следующим

openBrace = char '(' 

closeBrace :: GenParser Char st Char 
closeBrace = char ')' 

bracketExpr = do 
      spaces >> openBrace 
      expr <- expressionParser 
      spaces >> closeBrace 
      return expr 

bracketExpr возвращает введенное выражение в моем собственном типе данных

, чтобы преобразовать его в мой тип данных я сделал для отрицания, если выражение является числом или переменной следующим образом:

expressionParser = negate1 
       <|> number 
       <|> variable 
       --<|> addition 
       <?> "simple expression" 

negate1 :: Parser Expr 
negate1 = do{ char '-' 
      ;ds <- number 
      ;return (ExprNeg (ds)) 
      } 
     <?> "negate" 

variable :: Parser Expr 
variable = do{ ds<- many1 (letter <|> digit) 
      ; return (ExprVar ds)} 
     <?> "variable" 

number :: Parser Expr 
number = do{ ds<- many1 digit 
      ; return (ExprNum (read ds))} 
      <?> "number" 

Чтобы сделать то же самое для addtion я попытался с помощью разделяющего выражения с помощью sepBy но я встретив несколько вопросов.

Если extered expreesion является 1+2 Тогда я должен получить ExprAdd (ExprNum 1) (ExprNum 2)

Я не могу дальше продолжить здесь .help было бы здорово.

спасибо.

+0

'sepBy' слишком наивен. Попробуйте искать факторинг слева. Также см. Http://stackoverflow.com/questions/26588019/how-to-build-parser-in-haskell/26588465#26588465, может быть, кто-то из вашего класса? – alternative

ответ

1

Если вы хотите писать парсер с комбинаторами парсера, вам нужно сначала подумать о правилах высокого уровня. Вот парсер парсера в Парсеке; это не 100% соответствует вашим потребностям, потому что все операторы имеют одинаковый приоритет и право-ассоциативный характер, тогда как вам, вероятно, нужны разные приоритеты и лево-ассоциативность. Тем не менее, это основной способ написать парсер:

import Text.Parsec 
import Text.Parsec.Char 
import Data.Char (isDigit) 

-- basic data type 
data Expr = Op Char Expr Expr | N Integer deriving (Show) 
type Parser x = Parsec String() x 

-- reverse-sequenced >>, used to implement `parenthesized` and `whitespaced` 
(<<) :: Monad m => m x -> m y -> m x 
mx << my = mx >>= \x -> my >> return x 
infixl 1 << 

parenthesized :: Parser e -> Parser e 
parenthesized e = char '(' >> e << char ')' 

whitespaced :: Parser e -> Parser e 
whitespaced e = spaces >> e << spaces 

number :: Parser Expr 
number = do 
    c <- oneOf "123456789" -- leading 0's can be reserved for octal/hexadecimal 
    cs <- many digit 
    return (N (read (c:cs))) 

operator :: Parser Expr 
operator = do 
    e1 <- expr_no_op 
    o <- whitespaced (oneOf "+*/-") 
    e2 <- expression 
    return (Op o e1 e2) 

expr_no_op :: Parser Expr 
expr_no_op = whitespaced (try number <|> parenthesized expression) 

expression :: Parser Expr 
expression = whitespaced (try operator <|> try number <|> parenthesized expression) 

Обратите внимание, что вы определяете маркеры (выше, просто «номер»), а затем объединить их с «попробовать это <|><|> попробовать, что в противном случае ...» синтаксис. Также обратите внимание, что у вас есть, чтобы остановить operator от принятия выражения в качестве первого аргумента, иначе вы получите цикл operator -> expression -> operator в разборе. Это называется «левый факторинг».

Смежные вопросы