Created
September 14, 2019 10:00
-
-
Save prednaz/2c7508245fc07a84c734fc2830d1eea2 to your computer and use it in GitHub Desktop.
Zentraluebung zu Parsen von Herr Jost
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Prelude hiding (lex) | |
import Data.Char | |
import Data.Maybe | |
import Data.Semigroup | |
{- Vorlesung "Programmierung und Modellierung" | |
LMU München, Sommersemester 2019 | |
Steffen Jost | |
Code zu Folien 7.23ff | |
live gecoded von Dr Steffen Jost, Lehrstuhl TCS, LMU München | |
in der 3. Zentralübung zur Programmierung und Modellierung | |
19. Juni 2019 | |
Erklärungen/Gedankengänge: siehe Videoaufzeichung! | |
-} | |
-- Code von Folie 7.29: | |
data Expr = Const Integer | |
| Plus Expr Expr | |
| Times Expr Expr | |
deriving (Eq) | |
-- Beispiel: | |
a2 = Times (Plus (Const 5) (Const 3)) (Const 2) | |
-- (5+3) * 2 | |
eval :: Expr -> Integer | |
eval (Const n) = n | |
eval (Plus l r) = eval l + eval r | |
eval (Times l r) = eval l * eval r | |
-- Ein paar nützliche Instanzen für die Übung: | |
instance Show Expr where | |
show (Const i) = show i | |
show (Plus e1 e2) = "("++ show e1 ++ "+" ++ show e2 ++")" | |
show (Times e1 e2) = "("++ show e1 ++ "*" ++ show e2 ++")" | |
instance Read Expr where | |
readsPrec _ s = let (e,t) = parseExpr $ lex s in [(e,concatMap show t)] | |
-- Code Folie 7.30:-- | |
data Token | |
= CONST Integer | LPAREN | RPAREN | PLUS | TIMES | |
deriving Show | |
{- | |
instance Show Token where | |
show (CONST i) = show i | |
show LPAREN = "(" | |
show RPAREN = ")" | |
show PLUS = "+" | |
show TIMES = "*" | |
-} | |
s1str = " 3 * (8+3)+ 5 *4" | |
s1 = [CONST 3, TIMES, LPAREN, CONST 8, PLUS, CONST 3, RPAREN, PLUS, CONST 5, TIMES, CONST 4] | |
-- Lexikalische Analyse | |
lex :: String -> [Token] | |
lex "" = [] | |
lex (' ':s) = lex s | |
lex ('(':s) = LPAREN : lex s | |
lex (')':s) = RPAREN : lex s | |
lex ('[':s) = LPAREN : lex s | |
lex (']':s) = RPAREN : lex s | |
lex ('+':s) = PLUS : lex s | |
lex ('*':s) = TIMES : lex s | |
lex s = case lexInt s of | |
Just (i, rest) -> CONST i : lex rest | |
Nothing -> error $ "Unbekanntes Zeichen: " <> s | |
lexInt :: String -> Maybe (Integer, String) | |
lexInt (' ':s) = lexInt s | |
lexInt ('-':s) = negFst <$> lexPos s | |
where negFst (i,r) = (negate i,r) | |
lexInt s = lexPos s | |
lexPos :: String -> Maybe (Integer, String) | |
lexPos (c:s) | isSpace c = lexPos s | |
lexPos s | null num = Nothing | |
| otherwise = Just (read num, rest) | |
where | |
(num,rest) = span (`elem` ['0'..'9']) s | |
-- Alternative Variante von lexInt: | |
lexInt1 :: String -> Maybe (Integer, String) | |
lexInt1 = listToMaybe . reads | |
-- Natürlich könnte man das auch komplett zu Fuss implementieren: | |
-- lexInt2 ('0':s) = ... | |
-- lexInt2 ('1':s) = ... | |
-- ... | |
-- Syntaxanalyse, Folie 7.31ff. | |
parseExpr :: [Token] -> (Expr,[Token]) | |
parseProd :: [Token] -> (Expr,[Token]) | |
parseFactor :: [Token] -> (Expr,[Token]) | |
parseExpr l = case parseProd l of | |
(prod, PLUS:rest1) -> | |
let (expr,rest2) = parseExpr rest1 | |
in (Plus prod expr, rest2) | |
-- (prod, rest) -> (prod, rest) | |
-- erg@(prod, rest) -> erg | |
erg -> erg | |
parseProd l | (TIMES:rest2) <- rest1 = let (prod,rest3) = parseFactor rest2 | |
in (Times factor prod, rest3) | |
| otherwise = (factor,rest1) | |
where | |
(factor,rest1) = parseFactor l | |
parseFactor ((CONST i):rest) = (Const i, rest) | |
parseFactor (LPAREN:rest) = case parseExpr rest of | |
(expr, RPAREN:rest2) -> (expr, rest2) | |
_ -> error "Klammer zu machen, es zieht!" | |
parseFactor _ = error "Syntaxfehler! Konstante oder Klammer auf erwartet!" | |
test :: Expr -- query GHCI for "test" to test your solution | |
test = read "1 * (2 + 3 * 4) + 5 * 6 + 7 + 8 * 9" | |
parse :: String -> Expr | |
parse str = case parseExpr (lex str) of | |
(expr, []) -> expr | |
(_,bad) -> error $ "Unnötiger Ballast am Ende: " ++ show bad | |
{- | |
> lex "(1 +2 * 3 + 4 )" | |
[LPAREN,CONST 1,PLUS,CONST 2,TIMES,CONST 3,PLUS,CONST 4,RPAREN] | |
> parse "(1 +2 * 3 + 4 )" | |
+ | |
/ \ | |
1 + | |
/ \ | |
* 4 | |
/ \ | |
2 3 | |
> eval $ parse "(1 +2 * 3 + 4 )" | |
11 | |
-} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment