From a7547dd670d2c03d1bae49de150cbeca7941a67d Mon Sep 17 00:00:00 2001 From: sudoer777 Date: Sat, 7 Oct 2023 22:46:37 -0500 Subject: [PATCH 1/8] Parse expressions into different types --- README.md | 1 + really-bad-compiler-in-haskell.cabal | 2 +- src/Main/LLVMGen.hs | 53 ++++++++++++++++------------ src/Main/Parser/Megaparsec.hs | 53 ++++++++++++---------------- src/Main/Type.hs | 30 ---------------- src/Main/Types.hs | 33 +++++++++++++++++ 6 files changed, 88 insertions(+), 84 deletions(-) delete mode 100644 src/Main/Type.hs create mode 100644 src/Main/Types.hs diff --git a/README.md b/README.md index 3f59fd2..17ef438 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ I recommend using VSCodium, which is preconfigured to have syntax highlighting a - https://gh.sudoer.ch/danieljharvey/mimsa/blob/trunk/llvm-calc/src/Calc/Compile/ToLLVM.hs (source code for above resource) - https://9to5tutorial.com/homebrew-compiler-made-with-haskell-llvm-configuration (for help using llvm-hs-pure) - https://blog.ocharles.org.uk/blog/posts/2012-12-17-24-days-of-hackage-optparse-applicative.html (for help parsing command line arguments with optparse-applicative) +- http://learnyouahaskell.com/making-our-own-types-and-typeclasses (for help defining types) ### Tools diff --git a/really-bad-compiler-in-haskell.cabal b/really-bad-compiler-in-haskell.cabal index 0b1bace..18fcdd1 100644 --- a/really-bad-compiler-in-haskell.cabal +++ b/really-bad-compiler-in-haskell.cabal @@ -18,7 +18,7 @@ executable really-bad-compiler-in-haskell other-modules: Main.LLVMGen Main.Parser.Megaparsec - Main.Type + Main.Types Paths_really_bad_compiler_in_haskell hs-source-dirs: src diff --git a/src/Main/LLVMGen.hs b/src/Main/LLVMGen.hs index 620e168..57b8ed8 100644 --- a/src/Main/LLVMGen.hs +++ b/src/Main/LLVMGen.hs @@ -22,7 +22,7 @@ import LLVM.IRBuilder.Constant import LLVM.IRBuilder.Instruction import LLVM.IRBuilder.Module import LLVM.IRBuilder.Monad -import Main.Type as Expr +import Main.Types qualified as T data Env = Env { operands :: M.Map Text Operand, @@ -56,8 +56,8 @@ getString str = do modify $ \env -> env {strings = M.insert str operand (strings env)} return operand -getLLVM :: [Expr] -> Module -getLLVM expr = +getLLVM :: [T.Statement] -> Module +getLLVM statement = flip evalState (Env {operands = M.empty, strings = M.empty}) $ buildModuleT "program" $ mdo -- TODO: better module name @@ -66,7 +66,7 @@ getLLVM expr = function "main" [] i32 $ \_ -> mdo printNumStr <- globalStringPtr "%d\n" (mkName "str") lift $ registerString "%d\n" $ ConstantOperand printNumStr - _ <- forM_ expr exprToLLVM + _ <- forM_ statement statementToLLVM ret $ int32 0 -- @@ -74,42 +74,49 @@ getLLVM expr = -- _ <- call (FunctionType i32 [ptr] True) printf [(ConstantOperand numFormatStr, []), (ourExpression, [])] -- ret $ int32 0 -exprToLLVM :: +statementToLLVM :: ( MonadIRBuilder m, MonadModuleBuilder m, MonadState Env m ) => - Expr -> + T.Statement -> m Operand -exprToLLVM (Lit prim) = pure $ primToLLVM prim -exprToLLVM (Paren e) = exprToLLVM e -exprToLLVM (Print e) = mdo - val <- exprToLLVM e +statementToLLVM (T.Print e) = mdo + val <- intExprToLLVM e printf <- getOperand "printf" formatStr <- getString "%d\n" _ <- call (FunctionType i32 [ptr] True) printf [(formatStr, []), (val, [])] pure val -exprToLLVM (Expr.Add a b) = mdo - lhs <- exprToLLVM a - rhs <- exprToLLVM b + +intExprToLLVM :: + ( MonadIRBuilder m, + MonadModuleBuilder m, + MonadState Env m + ) => + T.Int -> + m Operand +intExprToLLVM (T.Int prim) = pure $ primToLLVM prim +intExprToLLVM (T.IntArith T.Add a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b add lhs rhs -exprToLLVM (Expr.Sub a b) = mdo - lhs <- exprToLLVM a - rhs <- exprToLLVM b +intExprToLLVM (T.IntArith T.Sub a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b sub lhs rhs -exprToLLVM (Expr.Mul a b) = mdo - lhs <- exprToLLVM a - rhs <- exprToLLVM b +intExprToLLVM (T.IntArith T.Mul a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b mul lhs rhs -exprToLLVM (Expr.Div a b) = mdo - lhs <- exprToLLVM a - rhs <- exprToLLVM b +intExprToLLVM (T.IntArith T.Div a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b sdiv lhs rhs primToLLVM :: Int -> Operand primToLLVM i = int32 $ fromIntegral i -llvmGen :: [Expr] -> IO ByteString +llvmGen :: [T.Statement] -> IO ByteString llvmGen expr = do let l = getLLVM expr withContext $ \c -> withModuleFromAST c l moduleLLVMAssembly \ No newline at end of file diff --git a/src/Main/Parser/Megaparsec.hs b/src/Main/Parser/Megaparsec.hs index aa1ea72..ec90c9f 100644 --- a/src/Main/Parser/Megaparsec.hs +++ b/src/Main/Parser/Megaparsec.hs @@ -8,7 +8,7 @@ import Control.Monad.Combinators.Expr import Data.Functor.Identity qualified import Data.Text import Data.Void (Void) -import Main.Type +import Main.Types qualified as M import Text.Megaparsec as MP hiding (parse) import Text.Megaparsec qualified as MP import Text.Megaparsec.Char qualified as C @@ -31,48 +31,41 @@ string = C.string container :: Text -> Text -> Parser a -> Parser a container b e = between (symbol b) (symbol e) -term :: Parser Expr -term = +parens :: Parser a -> Parser a +parens = container "(" ")" + +intExprTerm :: ParsecT Void Text Data.Functor.Identity.Identity M.Int +intExprTerm = choice - [ Lit <$> int, - container "(" ")" expr + [ M.Int <$> int, + parens intExpr ] -table :: [[Operator Parser Expr]] -table = - [ [methodOp "print" Print], - [ binaryOp "*" Mul, - binaryOp "/" Div +intExprTable :: [[Operator Parser M.Int]] +intExprTable = + [ [ binaryOp "*" (M.IntArith M.Mul), + binaryOp "/" (M.IntArith M.Div) ], - [ binaryOp "+" Add, - binaryOp "-" Sub + [ binaryOp "+" (M.IntArith M.Add), + binaryOp "-" (M.IntArith M.Sub) ] ] +intExpr :: Parser M.Int +intExpr = makeExprParser intExprTerm intExprTable + binaryOp :: Text -> (a -> a -> a) -> Operator (ParsecT Void Text Data.Functor.Identity.Identity) a binaryOp name f = InfixL $ f <$ symbol name --- prefixOp :: Text -> (a -> a) -> Operator (ParsecT Void Text Data.Functor.Identity.Identity) a --- prefixOp name f = Prefix (f <$ symbol name) +statement :: Parser M.Statement +statement = string "print" *> (M.Print <$> parens intExpr) <* symbol ";" -methodOp :: Text -> (a -> a) -> Operator (ParsecT Void Text Data.Functor.Identity.Identity) a -methodOp name f = Prefix $ f <$ (string name <* C.space) +parseStatements :: Text -> Either (ParseErrorBundle Text Void) [M.Statement] +parseStatements = MP.parse (C.space *> many statement <* eof) "" --- postfixOp :: Text -> (a -> a) -> Operator (ParsecT Void Text Data.Functor.Identity.Identity) a --- postfixOp name f = Postfix (f <$ symbol name) - -expr :: Parser Expr -expr = makeExprParser term table - -statement :: Parser Expr -statement = expr <* symbol ";" - -parseExpr :: Text -> Either (ParseErrorBundle Text Void) [Expr] -parseExpr = MP.parse (C.space *> many statement <* eof) "" - -parse :: Text -> [Expr] +parse :: Text -> [M.Statement] parse t = - case parseExpr t of + case parseStatements t of Right r -> r -- TODO: add error handling \ No newline at end of file diff --git a/src/Main/Type.hs b/src/Main/Type.hs deleted file mode 100644 index 23178b8..0000000 --- a/src/Main/Type.hs +++ /dev/null @@ -1,30 +0,0 @@ -module Main.Type - ( Expr (..), - -- AST (..) - ) -where - -import Data.Graph (Tree (Node)) - -data Expr - = Lit Int - | Paren Expr - | Add Expr Expr - | Sub Expr Expr - | Mul Expr Expr - | Div Expr Expr - | Print Expr - deriving - ( Show - ) - --- data AST = AST Node - --- data Node --- = Reg --- { cur :: Expr, --- next :: Node --- } --- | End --- { cur :: Expr --- } \ No newline at end of file diff --git a/src/Main/Types.hs b/src/Main/Types.hs new file mode 100644 index 0000000..81a33d4 --- /dev/null +++ b/src/Main/Types.hs @@ -0,0 +1,33 @@ +module Main.Types + ( ArithOp (..), + EqOp (..), + OrdCmpOp (..), + -- BinExpr (..), + Int (..), + Bool (..), + Statement (..), + ) +where + +import qualified Prelude as P + +data ArithOp = Add | Sub | Mul | Div + +data EqOp = Eq | Neq + +data OrdCmpOp = GT | GTE | LT | LTE + +-- newtype BinExpr op i o = BinExpr (op -> i -> i -> o) + +data Int + = Int P.Int + | IntArith ArithOp Int Int -- (BinExpr ArithOp Int Int) + +data Bool + = Bool P.Bool + | IntEq EqOp Int Int -- (BinExpr EqOp Int Bool) + | IntOrdCmp OrdCmpOp Int Int -- (BinExpr OrdCmpOp Int Bool) + | BoolEq EqOp Bool Bool -- (BinExpr EqOp Bool Bool) + +data Statement + = Print Int \ No newline at end of file -- 2.40.1 From d64ad9aedac4314ef1df016f3883b1bac70cc494 Mon Sep 17 00:00:00 2001 From: sudoer777 Date: Sun, 8 Oct 2023 00:23:13 -0500 Subject: [PATCH 2/8] Parse printInt instead of print --- example/1.hear | 2 +- src/Main/LLVMGen.hs | 2 +- src/Main/Parser/Megaparsec.hs | 31 +++++++++++++++++++++++++++++-- src/Main/Types.hs | 3 ++- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/example/1.hear b/example/1.hear index 62b1f81..a948a80 100644 --- a/example/1.hear +++ b/example/1.hear @@ -1 +1 @@ -print(5*(3-2)+-4-4); \ No newline at end of file +printInt(5*(3-2)+-4-4); \ No newline at end of file diff --git a/src/Main/LLVMGen.hs b/src/Main/LLVMGen.hs index 57b8ed8..65306f2 100644 --- a/src/Main/LLVMGen.hs +++ b/src/Main/LLVMGen.hs @@ -81,7 +81,7 @@ statementToLLVM :: ) => T.Statement -> m Operand -statementToLLVM (T.Print e) = mdo +statementToLLVM (T.PrintInt e) = mdo val <- intExprToLLVM e printf <- getOperand "printf" formatStr <- getString "%d\n" diff --git a/src/Main/Parser/Megaparsec.hs b/src/Main/Parser/Megaparsec.hs index ec90c9f..dc49b3d 100644 --- a/src/Main/Parser/Megaparsec.hs +++ b/src/Main/Parser/Megaparsec.hs @@ -54,11 +54,38 @@ intExprTable = intExpr :: Parser M.Int intExpr = makeExprParser intExprTerm intExprTable -binaryOp :: Text -> (a -> a -> a) -> Operator (ParsecT Void Text Data.Functor.Identity.Identity) a +-- boolExprTerm :: ParsecT Void Text Data.Functor.Identity.Identity M.Bool +-- boolExprTerm = +-- choice +-- [ M.Bool True <$ string "true", +-- M.Bool False <$ string "false", +-- parens boolExpr +-- ] + +-- boolExprTable :: [[Operator Parser (Either M.Bool M.Int)]] +-- boolExprTable = +-- [ [ binaryOp "<" (M.IntOrdCmp M.LT), +-- binaryOp "<=" (M.IntOrdCmp M.LTE), +-- binaryOp ">" (M.IntOrdCmp M.GT), +-- binaryOp ">=" (M.IntOrdCmp M.GTE) +-- ], +-- [ binaryOp "==" (M.IntOrdCmp M.Eq), +-- binaryOp "!=" (M.IntOrdCmp M.Neq) +-- ] +-- ] + +-- boolExpr :: Parser M.Bool +-- boolExpr = makeExprParser boolExprTerm boolExprTable + binaryOp name f = InfixL $ f <$ symbol name statement :: Parser M.Statement -statement = string "print" *> (M.Print <$> parens intExpr) <* symbol ";" +statement = + choice + [ string "printInt" *> (M.PrintInt <$> parens intExpr) + -- ,string "printBool" *> (M.PrintBool <$> parens boolExpr) + ] + <* symbol ";" parseStatements :: Text -> Either (ParseErrorBundle Text Void) [M.Statement] parseStatements = MP.parse (C.space *> many statement <* eof) "" diff --git a/src/Main/Types.hs b/src/Main/Types.hs index 81a33d4..182b0db 100644 --- a/src/Main/Types.hs +++ b/src/Main/Types.hs @@ -30,4 +30,5 @@ data Bool | BoolEq EqOp Bool Bool -- (BinExpr EqOp Bool Bool) data Statement - = Print Int \ No newline at end of file + = PrintInt Int + | PrintBool Bool \ No newline at end of file -- 2.40.1 From 6e2031f71508afe96ecfce9830f1c217d85de6bc Mon Sep 17 00:00:00 2001 From: sudoer777 Date: Sat, 14 Oct 2023 18:01:01 -0500 Subject: [PATCH 3/8] Parse int comparisons as boolean expression --- README.md | 2 +- src/Main/Parser/Megaparsec.hs | 39 ++++++++++++++++++++++++++--------- src/Main/Types.hs | 11 ++++++---- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 17ef438..170d18f 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ I recommend using VSCodium, which is preconfigured to have syntax highlighting a ## File structure -- `app` - contains the compiler program +- `src` - contains the compiler program - `example` - contains example programs that can be compiled ## Credits diff --git a/src/Main/Parser/Megaparsec.hs b/src/Main/Parser/Megaparsec.hs index dc49b3d..3f2c922 100644 --- a/src/Main/Parser/Megaparsec.hs +++ b/src/Main/Parser/Megaparsec.hs @@ -54,15 +54,34 @@ intExprTable = intExpr :: Parser M.Int intExpr = makeExprParser intExprTerm intExprTable --- boolExprTerm :: ParsecT Void Text Data.Functor.Identity.Identity M.Bool --- boolExprTerm = --- choice --- [ M.Bool True <$ string "true", --- M.Bool False <$ string "false", --- parens boolExpr --- ] +intOrdCmpExpr :: ParsecT Void Text Data.Functor.Identity.Identity (M.OrdCmpOp, M.Int, M.Int) +intOrdCmpExpr = do + b <- intExpr + a <- + choice + [ M.GT <$ symbol ">", + M.GTE <$ symbol ">=", + -- M.Eq <$ string "==", + -- M.Neq <$ string "!=", + M.LTE <$ symbol "<=", + M.LT <$ symbol "<" + ] + c <- intExpr + return (a, b, c) --- boolExprTable :: [[Operator Parser (Either M.Bool M.Int)]] +uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d +uncurry3 f (x, y, z) = f x y z + +boolExprTerm :: ParsecT Void Text Data.Functor.Identity.Identity M.Bool +boolExprTerm = + choice + [ uncurry3 M.IntOrdCmp <$> intOrdCmpExpr, + M.Bool True <$ string "true", + M.Bool False <$ string "false", + parens boolExprTerm + ] + +-- boolExprTable :: [[Operator Parser M.Bool]] -- boolExprTable = -- [ [ binaryOp "<" (M.IntOrdCmp M.LT), -- binaryOp "<=" (M.IntOrdCmp M.LTE), @@ -82,8 +101,8 @@ binaryOp name f = InfixL $ f <$ symbol name statement :: Parser M.Statement statement = choice - [ string "printInt" *> (M.PrintInt <$> parens intExpr) - -- ,string "printBool" *> (M.PrintBool <$> parens boolExpr) + [ string "printInt" *> (M.PrintInt <$> parens intExpr), + string "printBool" *> (M.PrintBool <$> parens boolExprTerm) ] <* symbol ";" diff --git a/src/Main/Types.hs b/src/Main/Types.hs index 182b0db..c9cc000 100644 --- a/src/Main/Types.hs +++ b/src/Main/Types.hs @@ -11,24 +11,27 @@ where import qualified Prelude as P -data ArithOp = Add | Sub | Mul | Div +data ArithOp = Add | Sub | Mul | Div deriving (P.Show) -data EqOp = Eq | Neq +data EqOp = Eq | Neq deriving (P.Show) -data OrdCmpOp = GT | GTE | LT | LTE +data OrdCmpOp = GT | GTE | LT | LTE deriving (P.Show) -- newtype BinExpr op i o = BinExpr (op -> i -> i -> o) data Int = Int P.Int | IntArith ArithOp Int Int -- (BinExpr ArithOp Int Int) + deriving (P.Show) data Bool = Bool P.Bool | IntEq EqOp Int Int -- (BinExpr EqOp Int Bool) | IntOrdCmp OrdCmpOp Int Int -- (BinExpr OrdCmpOp Int Bool) | BoolEq EqOp Bool Bool -- (BinExpr EqOp Bool Bool) + deriving (P.Show) data Statement = PrintInt Int - | PrintBool Bool \ No newline at end of file + | PrintBool Bool + deriving (P.Show) \ No newline at end of file -- 2.40.1 From a75b0df9bc9c2cce0f7f29341d792861fd0e971c Mon Sep 17 00:00:00 2001 From: sudoer777 Date: Sat, 14 Oct 2023 20:45:48 -0500 Subject: [PATCH 4/8] Add greater than and less than for integers --- README.md | 2 ++ example/1.hear | 6 +++++- src/Main/LLVMGen.hs | 38 +++++++++++++++++++++++++++++++++++--- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 170d18f..36b09d7 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ I recommend using VSCodium, which is preconfigured to have syntax highlighting a - https://9to5tutorial.com/homebrew-compiler-made-with-haskell-llvm-configuration (for help using llvm-hs-pure) - https://blog.ocharles.org.uk/blog/posts/2012-12-17-24-days-of-hackage-optparse-applicative.html (for help parsing command line arguments with optparse-applicative) - http://learnyouahaskell.com/making-our-own-types-and-typeclasses (for help defining types) +- https://llvm.org/docs/LangRef.html (LLVM documentation) +- https://hackage.haskell.org/package/llvm-hs-pure-9.0.0/docs/ (llvm-hs documentation) ### Tools diff --git a/example/1.hear b/example/1.hear index a948a80..44fe560 100644 --- a/example/1.hear +++ b/example/1.hear @@ -1 +1,5 @@ -printInt(5*(3-2)+-4-4); \ No newline at end of file +printInt(5*(3-2)+-4-4); +printBool(true); +printBool(false); +printBool(5 * 3 > 5 + 9); +printBool(5*(3-2)+-4-4 < -3); \ No newline at end of file diff --git a/src/Main/LLVMGen.hs b/src/Main/LLVMGen.hs index 65306f2..ecb8d65 100644 --- a/src/Main/LLVMGen.hs +++ b/src/Main/LLVMGen.hs @@ -16,7 +16,9 @@ import Data.String.Conversions import Data.Text import LLVM (moduleLLVMAssembly, withModuleFromAST) import LLVM.AST hiding (function) +import LLVM.AST.IntegerPredicate (IntegerPredicate (SGE, SGT, SLE, SLT)) import LLVM.AST.Type +import LLVM.AST.Type qualified as AST import LLVM.Context import LLVM.IRBuilder.Constant import LLVM.IRBuilder.Instruction @@ -87,6 +89,13 @@ statementToLLVM (T.PrintInt e) = mdo formatStr <- getString "%d\n" _ <- call (FunctionType i32 [ptr] True) printf [(formatStr, []), (val, [])] pure val +statementToLLVM (T.PrintBool e) = mdo + val <- boolExprToLLVM e + val32 <- zext val i32 + printf <- getOperand "printf" + formatStr <- getString "%d\n" + _ <- call (FunctionType i32 [ptr] True) printf [(formatStr, []), (val32, [])] + pure val intExprToLLVM :: ( MonadIRBuilder m, @@ -95,7 +104,7 @@ intExprToLLVM :: ) => T.Int -> m Operand -intExprToLLVM (T.Int prim) = pure $ primToLLVM prim +intExprToLLVM (T.Int prim) = pure $ int32 $ fromIntegral prim intExprToLLVM (T.IntArith T.Add a b) = mdo lhs <- intExprToLLVM a rhs <- intExprToLLVM b @@ -113,8 +122,31 @@ intExprToLLVM (T.IntArith T.Div a b) = mdo rhs <- intExprToLLVM b sdiv lhs rhs -primToLLVM :: Int -> Operand -primToLLVM i = int32 $ fromIntegral i +boolExprToLLVM :: + ( MonadIRBuilder m, + MonadModuleBuilder m, + MonadState Env m + ) => + T.Bool -> + m Operand +boolExprToLLVM (T.Bool prim) = + if prim then pure $ bit 1 else pure $ bit 0 +boolExprToLLVM (T.IntOrdCmp T.GT a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b + icmp SGT lhs rhs +boolExprToLLVM (T.IntOrdCmp T.GTE a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b + icmp SGE lhs rhs +boolExprToLLVM (T.IntOrdCmp T.LT a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b + icmp SLT lhs rhs +boolExprToLLVM (T.IntOrdCmp T.LTE a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b + icmp SLE lhs rhs llvmGen :: [T.Statement] -> IO ByteString llvmGen expr = do -- 2.40.1 From f436c6bc715aeefa4550a5f01a7ff394b1072828 Mon Sep 17 00:00:00 2001 From: sudoer777 Date: Sat, 14 Oct 2023 20:54:59 -0500 Subject: [PATCH 5/8] Fix GTE and LTE not parsing --- example/1.hear | 2 +- src/Main/Parser/Megaparsec.hs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/1.hear b/example/1.hear index 44fe560..265a993 100644 --- a/example/1.hear +++ b/example/1.hear @@ -1,5 +1,5 @@ printInt(5*(3-2)+-4-4); printBool(true); printBool(false); -printBool(5 * 3 > 5 + 9); +printBool(5 * 3 >= 5 + 9); printBool(5*(3-2)+-4-4 < -3); \ No newline at end of file diff --git a/src/Main/Parser/Megaparsec.hs b/src/Main/Parser/Megaparsec.hs index 3f2c922..3281b77 100644 --- a/src/Main/Parser/Megaparsec.hs +++ b/src/Main/Parser/Megaparsec.hs @@ -59,12 +59,12 @@ intOrdCmpExpr = do b <- intExpr a <- choice - [ M.GT <$ symbol ">", - M.GTE <$ symbol ">=", + [ M.GTE <$ string ">=" <* C.space, + M.LTE <$ string "<=" <* C.space, + M.GT <$ string ">" <* C.space, -- M.Eq <$ string "==", -- M.Neq <$ string "!=", - M.LTE <$ symbol "<=", - M.LT <$ symbol "<" + M.LT <$ string "<" <* C.space ] c <- intExpr return (a, b, c) -- 2.40.1 From 20c20b58b79d03feb571058288a7cc012bf39e53 Mon Sep 17 00:00:00 2001 From: sudoer777 Date: Sat, 14 Oct 2023 21:23:37 -0500 Subject: [PATCH 6/8] Fix EQ and NE not parsing --- example/1.hear | 5 ++++- src/Main/LLVMGen.hs | 10 +++++++++- src/Main/Parser/Megaparsec.hs | 31 +++++++++++++------------------ src/Main/Types.hs | 2 +- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/example/1.hear b/example/1.hear index 265a993..98aa9bf 100644 --- a/example/1.hear +++ b/example/1.hear @@ -2,4 +2,7 @@ printInt(5*(3-2)+-4-4); printBool(true); printBool(false); printBool(5 * 3 >= 5 + 9); -printBool(5*(3-2)+-4-4 < -3); \ No newline at end of file +printBool(5*(3-2)+-4-4 < -3); +printBool(5 == 5); +printBool(5 == 6); +printBool(5 != 5); \ No newline at end of file diff --git a/src/Main/LLVMGen.hs b/src/Main/LLVMGen.hs index ecb8d65..9a0bbcf 100644 --- a/src/Main/LLVMGen.hs +++ b/src/Main/LLVMGen.hs @@ -16,7 +16,7 @@ import Data.String.Conversions import Data.Text import LLVM (moduleLLVMAssembly, withModuleFromAST) import LLVM.AST hiding (function) -import LLVM.AST.IntegerPredicate (IntegerPredicate (SGE, SGT, SLE, SLT)) +import LLVM.AST.IntegerPredicate import LLVM.AST.Type import LLVM.AST.Type qualified as AST import LLVM.Context @@ -147,6 +147,14 @@ boolExprToLLVM (T.IntOrdCmp T.LTE a b) = mdo lhs <- intExprToLLVM a rhs <- intExprToLLVM b icmp SLE lhs rhs +boolExprToLLVM (T.IntEq T.EQ a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b + icmp LLVM.AST.IntegerPredicate.EQ lhs rhs +boolExprToLLVM (T.IntEq T.NE a b) = mdo + lhs <- intExprToLLVM a + rhs <- intExprToLLVM b + icmp LLVM.AST.IntegerPredicate.NE lhs rhs llvmGen :: [T.Statement] -> IO ByteString llvmGen expr = do diff --git a/src/Main/Parser/Megaparsec.hs b/src/Main/Parser/Megaparsec.hs index 3281b77..64f9712 100644 --- a/src/Main/Parser/Megaparsec.hs +++ b/src/Main/Parser/Megaparsec.hs @@ -62,40 +62,35 @@ intOrdCmpExpr = do [ M.GTE <$ string ">=" <* C.space, M.LTE <$ string "<=" <* C.space, M.GT <$ string ">" <* C.space, - -- M.Eq <$ string "==", - -- M.Neq <$ string "!=", M.LT <$ string "<" <* C.space ] c <- intExpr return (a, b, c) +intEqExpr :: ParsecT Void Text Data.Functor.Identity.Identity (M.EqOp, M.Int, M.Int) +intEqExpr = do + b <- intExpr + a <- + choice + [ M.EQ <$ string "==" <* C.space, + M.NE <$ string "!=" <* C.space + ] + c <- intExpr + return (a, b, c) + uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d uncurry3 f (x, y, z) = f x y z boolExprTerm :: ParsecT Void Text Data.Functor.Identity.Identity M.Bool boolExprTerm = choice - [ uncurry3 M.IntOrdCmp <$> intOrdCmpExpr, + [ try (uncurry3 M.IntOrdCmp <$> intOrdCmpExpr), + uncurry3 M.IntEq <$> intEqExpr, M.Bool True <$ string "true", M.Bool False <$ string "false", parens boolExprTerm ] --- boolExprTable :: [[Operator Parser M.Bool]] --- boolExprTable = --- [ [ binaryOp "<" (M.IntOrdCmp M.LT), --- binaryOp "<=" (M.IntOrdCmp M.LTE), --- binaryOp ">" (M.IntOrdCmp M.GT), --- binaryOp ">=" (M.IntOrdCmp M.GTE) --- ], --- [ binaryOp "==" (M.IntOrdCmp M.Eq), --- binaryOp "!=" (M.IntOrdCmp M.Neq) --- ] --- ] - --- boolExpr :: Parser M.Bool --- boolExpr = makeExprParser boolExprTerm boolExprTable - binaryOp name f = InfixL $ f <$ symbol name statement :: Parser M.Statement diff --git a/src/Main/Types.hs b/src/Main/Types.hs index c9cc000..aa504a8 100644 --- a/src/Main/Types.hs +++ b/src/Main/Types.hs @@ -13,7 +13,7 @@ import qualified Prelude as P data ArithOp = Add | Sub | Mul | Div deriving (P.Show) -data EqOp = Eq | Neq deriving (P.Show) +data EqOp = EQ | NE deriving (P.Show) data OrdCmpOp = GT | GTE | LT | LTE deriving (P.Show) -- 2.40.1 From b1d2f6599259674736a3bbab1f86f9517dbd4069 Mon Sep 17 00:00:00 2001 From: sudoer777 Date: Mon, 23 Oct 2023 12:20:37 -0500 Subject: [PATCH 7/8] Add boolean logic operators --- example/1.hear | 7 +++++- src/Main.hs | 14 +++++++---- src/Main/LLVMGen.hs | 19 ++++++++++++++ src/Main/Parser/Megaparsec.hs | 47 +++++++++++++++++++++++++++++------ src/Main/Types.hs | 5 ++++ 5 files changed, 79 insertions(+), 13 deletions(-) diff --git a/example/1.hear b/example/1.hear index 98aa9bf..8c60c2a 100644 --- a/example/1.hear +++ b/example/1.hear @@ -5,4 +5,9 @@ printBool(5 * 3 >= 5 + 9); printBool(5*(3-2)+-4-4 < -3); printBool(5 == 5); printBool(5 == 6); -printBool(5 != 5); \ No newline at end of file +printBool(5 != 5); +printBool(true == true); +printBool(true && true); +printBool(true && false); +printBool(!true); +printBool(!(5 == 5)); \ No newline at end of file diff --git a/src/Main.hs b/src/Main.hs index dee11e3..3030c5d 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -22,11 +22,15 @@ run opts = do let fileName = filePath opts contents <- T.readFile fileName T.putStrLn "- Generating LLVM to './a.out.ll'..." - result <- (llvmGen . parse) contents - B.writeFile "a.out.ll" result - T.putStrLn "- Compiling to executable './a.out'..." - callCommand "clang a.out.ll" - T.putStrLn "- Done." + let parseResult = parse contents + case parseResult of + Right r -> do + result <- llvmGen r + B.writeFile "a.out.ll" result + T.putStrLn "- Compiling to executable './a.out'..." + callCommand "clang a.out.ll" + T.putStrLn "- Done." + Left l -> putStrLn l main :: IO () main = execParser opts >>= run diff --git a/src/Main/LLVMGen.hs b/src/Main/LLVMGen.hs index 9a0bbcf..c4f00e2 100644 --- a/src/Main/LLVMGen.hs +++ b/src/Main/LLVMGen.hs @@ -155,6 +155,25 @@ boolExprToLLVM (T.IntEq T.NE a b) = mdo lhs <- intExprToLLVM a rhs <- intExprToLLVM b icmp LLVM.AST.IntegerPredicate.NE lhs rhs +boolExprToLLVM (T.BoolEq T.EQ a b) = mdo + lhs <- boolExprToLLVM a + rhs <- boolExprToLLVM b + icmp LLVM.AST.IntegerPredicate.EQ lhs rhs +boolExprToLLVM (T.BoolEq T.NE a b) = mdo + lhs <- boolExprToLLVM a + rhs <- boolExprToLLVM b + icmp LLVM.AST.IntegerPredicate.NE lhs rhs +boolExprToLLVM (T.BoolLogic T.AND a b) = mdo + lhs <- boolExprToLLVM a + rhs <- boolExprToLLVM b + LLVM.IRBuilder.Instruction.and lhs rhs +boolExprToLLVM (T.BoolLogic T.OR a b) = mdo + lhs <- boolExprToLLVM a + rhs <- boolExprToLLVM b + LLVM.IRBuilder.Instruction.or lhs rhs +boolExprToLLVM (T.BoolNeg a) = mdo + l <- boolExprToLLVM a + LLVM.IRBuilder.Instruction.xor l $ bit 1 llvmGen :: [T.Statement] -> IO ByteString llvmGen expr = do diff --git a/src/Main/Parser/Megaparsec.hs b/src/Main/Parser/Megaparsec.hs index 64f9712..ee82942 100644 --- a/src/Main/Parser/Megaparsec.hs +++ b/src/Main/Parser/Megaparsec.hs @@ -78,6 +78,31 @@ intEqExpr = do c <- intExpr return (a, b, c) +boolExprTable :: [[Operator Parser M.Bool]] +boolExprTable = + [ [ binaryOp "==" (M.BoolEq M.EQ), + binaryOp "!=" (M.BoolEq M.NE) + ], + [prefixOp "!" M.BoolNeg], + [binaryOp "&&" (M.BoolLogic M.AND)], + [binaryOp "||" (M.BoolLogic M.OR)] + ] + +-- boolEqExpr :: ParsecT Void Text Data.Functor.Identity.Identity (M.EqOp, M.Bool, M.Bool) +-- boolEqExpr = do +-- b <- +-- choice +-- [ + +-- ] +-- a <- +-- choice +-- [ M.EQ <$ string "==" <* C.space, +-- M.NE <$ string "!=" <* C.space +-- ] +-- c <- intExpr +-- return (a, b, c) + uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d uncurry3 f (x, y, z) = f x y z @@ -86,27 +111,35 @@ boolExprTerm = choice [ try (uncurry3 M.IntOrdCmp <$> intOrdCmpExpr), uncurry3 M.IntEq <$> intEqExpr, - M.Bool True <$ string "true", - M.Bool False <$ string "false", - parens boolExprTerm + M.Bool True <$ string "true" <* C.space, + M.Bool False <$ string "false" <* C.space, + parens boolExpr ] -binaryOp name f = InfixL $ f <$ symbol name +boolExpr :: ParsecT Void Text Data.Functor.Identity.Identity M.Bool +boolExpr = makeExprParser boolExprTerm boolExprTable + +binaryOp :: Text -> (a -> a -> a) -> Operator (ParsecT Void Text Data.Functor.Identity.Identity) a +binaryOp name f = InfixL $ f <$ string name <* C.space + +prefixOp :: Text -> (a -> a) -> Operator (ParsecT Void Text Data.Functor.Identity.Identity) a +prefixOp name f = Prefix $ f <$ symbol name statement :: Parser M.Statement statement = choice [ string "printInt" *> (M.PrintInt <$> parens intExpr), - string "printBool" *> (M.PrintBool <$> parens boolExprTerm) + string "printBool" *> (M.PrintBool <$> parens boolExpr) ] <* symbol ";" parseStatements :: Text -> Either (ParseErrorBundle Text Void) [M.Statement] parseStatements = MP.parse (C.space *> many statement <* eof) "" -parse :: Text -> [M.Statement] +parse :: Text -> Either String [M.Statement] parse t = case parseStatements t of - Right r -> r + Right r -> Right r + Left e -> Left (errorBundlePretty e) -- TODO: add error handling \ No newline at end of file diff --git a/src/Main/Types.hs b/src/Main/Types.hs index aa504a8..3061817 100644 --- a/src/Main/Types.hs +++ b/src/Main/Types.hs @@ -2,6 +2,7 @@ module Main.Types ( ArithOp (..), EqOp (..), OrdCmpOp (..), + LogicOp (..), -- BinExpr (..), Int (..), Bool (..), @@ -17,6 +18,8 @@ data EqOp = EQ | NE deriving (P.Show) data OrdCmpOp = GT | GTE | LT | LTE deriving (P.Show) +data LogicOp = AND | OR deriving (P.Show) + -- newtype BinExpr op i o = BinExpr (op -> i -> i -> o) data Int @@ -26,9 +29,11 @@ data Int data Bool = Bool P.Bool + | BoolNeg Bool | IntEq EqOp Int Int -- (BinExpr EqOp Int Bool) | IntOrdCmp OrdCmpOp Int Int -- (BinExpr OrdCmpOp Int Bool) | BoolEq EqOp Bool Bool -- (BinExpr EqOp Bool Bool) + | BoolLogic LogicOp Bool Bool deriving (P.Show) data Statement -- 2.40.1 From 1fbacda21bf890bd8876ca9b7108614be6d828e5 Mon Sep 17 00:00:00 2001 From: sudoer777 Date: Mon, 23 Oct 2023 12:28:38 -0500 Subject: [PATCH 8/8] Fix boolean parenthesis bug --- src/Main/Parser/Megaparsec.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Main/Parser/Megaparsec.hs b/src/Main/Parser/Megaparsec.hs index ee82942..17c7117 100644 --- a/src/Main/Parser/Megaparsec.hs +++ b/src/Main/Parser/Megaparsec.hs @@ -110,10 +110,10 @@ boolExprTerm :: ParsecT Void Text Data.Functor.Identity.Identity M.Bool boolExprTerm = choice [ try (uncurry3 M.IntOrdCmp <$> intOrdCmpExpr), + parens boolExpr, uncurry3 M.IntEq <$> intEqExpr, M.Bool True <$ string "true" <* C.space, - M.Bool False <$ string "false" <* C.space, - parens boolExpr + M.Bool False <$ string "false" <* C.space ] boolExpr :: ParsecT Void Text Data.Functor.Identity.Identity M.Bool -- 2.40.1