Skip to content
Merged

If #10

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ Increments:
- [X] Unary Operators on Ints
- [X] Local Variables and Assignment
- [X] Booleans
- [ ] Branching (if statements)
- [ ] Comparisons
- [X] Branching (if statements)
- [ ] WriteLn("Hello World") (finally)
- [ ] Comparisons
- [ ] Loops
- [ ] Procedures
- [ ] Functions
Expand Down
12 changes: 12 additions & 0 deletions src/HSPC/CodeGen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ generateBlock (MainProgramBlock vars body) =
++ [0x5d] -- pop rbp

generateStatement :: OffsetMap -> Statement -> [Word8]
generateStatement _ NOP = []
generateStatement offsetMap (If cond statement elseStatement) =
let statementCode = generateStatement offsetMap statement
elseStatementCode = generateStatement offsetMap elseStatement
in generateExpression offsetMap cond
++ [0x48, 0x85, 0xc0] -- test rax rax
++ [0x0f, 0x84]
++ int32ToLE (fromIntegral $ length statementCode + 5) -- jz elseStatement
++ statementCode
++ [0xe9]
++ int32ToLE (fromIntegral $ length elseStatementCode) -- jz elseStatementCode
++ elseStatementCode
generateStatement offsetMap (Halt ast) =
generateExpression offsetMap ast
-- copy rax -> rdi but maxed out at 255
Expand Down
37 changes: 31 additions & 6 deletions src/HSPC/Parse.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ data Block

data Statement
= VarAssign String Expression
| -- if Expression then Statement else Statement;
If Expression Statement Statement
| NOP
| Assignment String Expression
| Halt Expression
| ExprStmt Expression
Expand Down Expand Up @@ -133,27 +136,47 @@ parseStatements :: Map.Map String HSPCDataType -> [Statement] -> [HSPCToken] ->
parseStatements _ acc (EndKeyWordTok : xs) = Right (reverse acc, xs)
parseStatements _ _ [] = Left ExpectedEndStatement
parseStatements vars acc xs = do
(expr, rest) <- parseStatement vars xs
(expr, restWithSemiColon) <- parseStatement vars xs
rest <- removeLeadingSemiColon restWithSemiColon
parseStatements vars (expr : acc) rest

parseStatement :: Map.Map String HSPCDataType -> [HSPCToken] -> Either ParseError (Statement, [HSPCToken])
parseStatement varMap (IdentifierTok name : AssignmentTok : xs) = do
let (rhs, rawRest) = break (== SemiColonTok) xs
rest <- removeLeadingSemiColon rawRest
let (rhs, rest) = break (`elem` [SemiColonTok, ElseKeyWordTok]) xs
op <- case Map.lookup name varMap of
Just dt -> parseOperand dt rhs
Nothing -> Left $ VariableNotDeclared name
return (Assignment name op, rest)
parseStatement
_
(HaltBuiltInTok : OpenBracketTok : CloseBracketTok : SemiColonTok : xs) = Right (Halt (IntLiteral 0), xs)
(HaltBuiltInTok : OpenBracketTok : CloseBracketTok : xs) = Right (Halt (IntLiteral 0), xs)
parseStatement
_
(HaltBuiltInTok : OpenBracketTok : xs) = do
(internal, rawRest) <- splitToMatchingBracket xs
rest <- removeLeadingSemiColon rawRest
(internal, rest) <- splitToMatchingBracket xs
op <- parseOperand IntegerType internal
return (Halt op, rest)

-- "IF cond THEN statement (; | ELSE elseStatement;)"
-- ELSE IF is simply an if statement where elseSatement
-- is another if statement.
parseStatement varMap (IfKeyWordTok : xs) = do
(cond, afterThen) <- parseCond xs
(statement, afterStatement) <- parseStatement varMap afterThen
case afterStatement of
(SemiColonTok : outsideOfStatement) ->
return (If cond statement NOP, SemiColonTok : outsideOfStatement)
(ElseKeyWordTok : afterElse) -> do
(elseStatement, afterElseStatement) <- parseStatement varMap afterElse
outsideOfStatement <- removeLeadingSemiColon afterElseStatement
return (If cond statement elseStatement, SemiColonTok : outsideOfStatement)
_ -> Left $ ExpectedToken SemiColonTok
where
parseCond :: [HSPCToken] -> Either ParseError (Expression, [HSPCToken])
parseCond tokens = do
let (condTokens, afterCond) = break (== ThenKeyWordTok) tokens
cond <- parseOperand BooleanType condTokens
return (cond, drop 1 afterCond)
parseStatement _ tok = Left $ NotImplemented "parseStatement" tok

parseOperand :: HSPCDataType -> [HSPCToken] -> Either ParseError Expression
Expand Down Expand Up @@ -199,6 +222,7 @@ parseIntOperand tokens = case breakLastOuter (`elem` [PlusTok, MinusTok]) tokens

parseFactor :: [HSPCToken] -> Either ParseError Expression
parseFactor [LiteralIntTok n] = Right $ IntLiteral n
-- TODO: check that this variable exists
parseFactor [IdentifierTok name] = Right $ Identifier name
parseFactor (PlusTok : xs) = do
operand <- parseFactor xs
Expand Down Expand Up @@ -246,6 +270,7 @@ parseBoolOperand tokens = case breakLastOuter (== OrTok) tokens of

parseBoolPrimary :: [HSPCToken] -> Either ParseError Expression
parseBoolPrimary [LiteralBoolTok bool] = Right $ BoolLiteral bool
parseBoolPrimary [IdentifierTok name] = Right $ Identifier name
parseBoolPrimary (OpenBracketTok : xs) = do
(inside, remaining) <- splitToMatchingBracket xs
case remaining of
Expand Down
6 changes: 6 additions & 0 deletions src/HSPC/Tokenize.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ data HSPCToken
| VarKeyWordTok
| BeginKeyWordTok
| EndKeyWordTok
| IfKeyWordTok
| ElseKeyWordTok
| ThenKeyWordTok
| HaltBuiltInTok
| OpenBracketTok
| CloseBracketTok
Expand Down Expand Up @@ -49,6 +52,9 @@ tokenize (c : cs)
tokenizeIdentifierOrKeyWord :: String -> HSPCToken
tokenizeIdentifierOrKeyWord "PROGRAM" = ProgramKeyWordTok
tokenizeIdentifierOrKeyWord "VAR" = VarKeyWordTok
tokenizeIdentifierOrKeyWord "IF" = IfKeyWordTok
tokenizeIdentifierOrKeyWord "ELSE" = ElseKeyWordTok
tokenizeIdentifierOrKeyWord "THEN" = ThenKeyWordTok
tokenizeIdentifierOrKeyWord "BEGIN" = BeginKeyWordTok
tokenizeIdentifierOrKeyWord "HALT" = HaltBuiltInTok
tokenizeIdentifierOrKeyWord "DIV" = IntDivideTok
Expand Down
6 changes: 5 additions & 1 deletion test/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ testSuite =
TestSpec "{} comments" "comments_curly_brace" 12,
TestSpec "// comments" "comments_single_line" 12,
TestSpec "Single variable" "variables_single_var" 10,
TestSpec "Boolean variable" "variables_bool" 0
TestSpec "Boolean variable" "variables_bool" 0,
TestSpec "IF" "if_no_else" 30,
TestSpec "IF ELSE" "if_else" 40,
TestSpec "IF ELSE IF" "if_else_if" 40,
TestSpec "IF with complex cond" "if_complex_cond" 40
]

main :: IO ()
Expand Down
Empty file.
16 changes: 16 additions & 0 deletions test/sample_programs/if_complex_cond.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
program IfExample;

var
i : integer;
b : boolean;
begin
i := 10;
b := false;

if (b or False) then
i := 30
else if (True and (not b)) then
i := 40;

halt(i);
end.
Empty file.
14 changes: 14 additions & 0 deletions test/sample_programs/if_else.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
program IfExample;

var
i : integer;
begin
i := 10;

if (False) then
i := 30
else
i := 40;

halt(i);
end.
Empty file.
14 changes: 14 additions & 0 deletions test/sample_programs/if_else_if.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
program IfExample;

var
i : integer;
begin
i := 10;

if (False) then
i := 30
else if (true) then
i := 40;

halt(i);
end.
Empty file.
12 changes: 12 additions & 0 deletions test/sample_programs/if_no_else.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
program IfExample;

var
i : integer;
begin
i := 10;

if (True) then
i := 30;

halt(i);
end.