2016-11-23 6 views
2

Mein Ziel ist es, einen Rechner in Haskell mit Text.ParserCombinators.ReadP, die +, -, *, /, ^, sowie Negation implementiert, und folgt PEMDAS. Zuerst muss ich eine String-Eingabe für einen mathematischen Ausdruck analysieren (MathExp). Ein Teil des Code, den ich habe, ist wie folgt:Lesen Klammern und Negation

import Control.Applicative hiding (many) 
import Control.Monad 
import Data.Char 
import Data.List 
import Data.Ord 
import Text.ParserCombinators.Readp 
type Name = String 
type Number = Int  

data MathExp 
    = Number Number 
    | Neg MathExp 
    | Plus MathExp MathExp 
    | Minus MathExp MathExp 
    | Mult MathExp MathExp 
    | Div MathExp MathExp 
    | Pow MathExp MathExp 
    | Var String 
    deriving (Eq, Show) 

parseNumber :: ReadP MathExp 
parseNumber = do 
    skipSpaces 
    x <- munch1 isDigit 
    return (Number (read x :: Int)) 

parsePlus :: ReadP (MathExp -> MathExp -> MathExp) 
parsePlus = do 
    x <- char '+' 
    return Plus 

parseMinus :: ReadP (MathExp -> MathExp -> MathExp) 
parseMinus = do 
    skipSpaces 
    x <- char '-' 
    return Minus 

parsePlusMinus = choice [parsePlus, parseMinus] --parse both-- 

parseMult :: ReadP (MathExp -> MathExp -> MathExp) 
parseMult = do 
    x <- char '*' 
    return Mult 

parseDiv :: ReadP (MathExp -> MathExp -> MathExp) 
parseDiv = do 
    x <- char '/' 
    return Div 

parseMultDiv = choice [parseMult, parseDiv] --parse both M,D-- 
parsePow :: ReadP (MathExp -> MathExp -> MathExp) 
parsePow = do 
    x <- char '^' 
    return Pow 

parseNeg :: ReadP MathExp 
parseNeg = undefined 
parseParens = undefined 

Ich habe kein Problem, die Parser kombiniert ich derzeit habe, mit chainl1 und chainr1, Assoziativität und Vorrang in der richtigen Reihenfolge zu implementieren, aber ich habe keine Ahnung, wie man Negation und Klammern richtig implementieren.

Was ich weiß, wenn diese Negation auch ein - Zeichen ist, und es kann entweder vor einer Ganzzahl, Klammern oder einer Variablen (Buchstabenfolge) stehen. Die Variablen sind ein weiterer Teil des Rechners (ich habe keine Probleme mit). Darüber hinaus kann eine Negation einen Leerraum enthalten; zum Beispiel 1+2* - 3 ist ein gültiger String-Eingang für diesen Rechner.

+0

"PEMDAS" ist kein richtiges Wort. Meinst du "die Reihenfolge der Operationen"? – dfeuer

+0

Ja, Reihenfolge der Operationen. – Harambe17

+0

Hallo CS 161 Schüler, die diese Seite gefunden haben, indem Sie suchen, 1. Hausaufgaben nicht online posten. 2. Verlassen Sie sich nicht auf SO-Mitarbeiter, um Ihre Hausaufgaben für Sie zu machen. Wenn Sie Probleme haben, schreiben Sie auf der Piazza. Deshalb benutzen wir es. Und machen Sie sich mit der Kollaborationspolitik vertraut: http://cmsc-16100.cs.uchicago.edu/2017/policies.php Wir werden jede Lösung erwarten, die Sie einreichen, um die ursprüngliche Interaktion mit der Aufgabe zu demonstrieren. Mailen Sie uns, wenn Sie Fragen haben. Peace, Your Instructors –

Antwort

3

Sie können wie folgt tun:

import Control.Applicative 
import Data.Char 
import Text.ParserCombinators.ReadP 

type Name = String 
type Number = Int 

data MathExp 
    = Number Number 
    | Neg MathExp 
    | Plus MathExp MathExp 
    | Minus MathExp MathExp 
    | Mult MathExp MathExp 
    | Div MathExp MathExp 
    | Pow MathExp MathExp 
    | Var Name 
    deriving (Eq, Show) 

runParser :: ReadP a -> String -> Maybe a 
runParser p s = 
    case readP_to_S p s of 
     [(x, [])] -> Just x 
     _   -> Nothing 

mathExp = mathExp' <* skipSpaces <* eof 
mathExp' = term `chainl1` addop 
term  = factor `chainl1` mulop 
factor = expo `chainr1` expop 
expo  = number <|> var <|> parens mathExp' <|> neg expo 

number = skipSpaces *> (Number . read <$> munch1 isDigit) 
var = skipSpaces *> (Var <$> munch1 isAlpha) 
addop = skipSpaces *> (Plus <$ char '+' <|> Minus <$ char '-') 
mulop = skipSpaces *> (Mult <$ char '*' <|> Div <$ char '/') 
expop = skipSpaces *> (Pow <$ char '^') 
neg p = skipSpaces *> (Neg <$> (char '-' *> p)) 

parens = between (skipSpaces *> char '(') (skipSpaces *> char ')') 

main = print $ runParser mathExp "1+2* - 3" 

Ausgang wird sein:

Just (Plus (Number 1) (Mult (Number 2) (Neg (Number 3)))) 
+0

Noch eine Frage: Wenn ich auch einen Parser implementieren wollte, der folgende Zeichenfolge lesen könnte: "put (x, y, zee) = (1,2,3) für x + y * zee" mit der Die Wörter "put" und "for" geben an, dass ich Variablen deklariere/verwende, und ich möchte, dass sie nach '[" x "," y "," zee "] [Nummer 1, Nummer 2, Nummer 3] (Plus (Var "x) (Mult (Var" y) (Var "zee"))) "Wie würde ich das machen? – Harambe17

+0

Zuerst müssen Sie Abstract Syntax Tree (AST) für Ihre Aufgabe in Bezug auf Ihre Syntax entwerfen. Dann können Sie über AST nachdenken. Ich verstehe Syntax und Semantik Ihres Beispiels nicht, deshalb kann ich Ihnen nicht mehr helfen. – freestyle