Skip to content
Merged
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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ Increments:
- [X] Branching (if statements)
- [X] While Loops
- [X] Comparisons
- [ ] Blocks as statements
- [ ] Strings (WriteLn("Hello World"))
- [X] Blocks as statements
- [ ] For Loops
- [ ] Strings (WriteLn("Hello World"))
- [ ] Type Checking
- [ ] Procedures
- [ ] Functions
- [ ] Arrays
Expand Down
9 changes: 8 additions & 1 deletion src/HSPC/CodeGen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ generateStatement offsetMap (Halt ast) =
-- exit_group syscall, exit code is in rdi
++ [0xb8, 0x3c, 00, 00, 00] -- mov rax 60
++ [0x0f, 0x05] -- Syscall
generateStatement offsetMap (StatementBlock body) =
concatMap (generateStatement offsetMap) body
generateStatement offsetMap (Assignment name op) =
generateExpression offsetMap op
++ case Map.lookup name offsetMap of
Expand All @@ -114,6 +116,12 @@ generateExpression offsetMap (Identifier str) =
case Map.lookup str offsetMap of
Just offset -> [0x48, 0x8b, 0x85] ++ int32ToLE offset -- mov rax [rbp - n]
Nothing -> error $ "Variable " ++ str ++ " doesn't exist."
generateExpression offsetMap (Subtract op1 op2) =
generateExpression offsetMap op2
++ [0x50] -- push rax
++ generateExpression offsetMap op1
++ [0x48, 0x2b, 0x04, 0x24] -- sub rax, [rsp]
++ [0x48, 0x83, 0xc4, 0x08] -- add rsp, 8 (release stack space)
generateExpression offsetMap (Add op1 op2) =
generateExpression offsetMap op1
++ [0x50] -- push rax
Expand Down Expand Up @@ -158,4 +166,3 @@ generateExpression offsetMap (BoolAnd op1 op2) =
generateExpression offsetMap (BoolNot op) =
generateExpression offsetMap op
++ [0x48, 0x83, 0xf0, 0x01] -- xor rax, 0x1
generateExpression _ ast = error $ "CodeGen for " ++ show ast ++ " not implemented"
19 changes: 12 additions & 7 deletions src/HSPC/Parse.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ data Statement
| NOP
| Assignment String Expression
| Halt Expression
| StatementBlock [Statement]
| ExprStmt Expression
deriving (Show, Eq)

Expand Down Expand Up @@ -88,10 +89,10 @@ parse _ = Left MustStartWithProgramStatement
parseMainProgramBlock :: [HSPCToken] -> Either ParseError Block
parseMainProgramBlock (VarKeyWordTok : tocs) = do
(vars, rest) <- parseVariableDeclarations [] tocs
(res, _) <- parseStatements [] rest
(res, _) <- parseStatements ProgramEndKeyWordTok [] rest
return $ MainProgramBlock vars res
parseMainProgramBlock (BeginKeyWordTok : tocs) = do
(res, _) <- parseStatements [] tocs
(res, _) <- parseStatements ProgramEndKeyWordTok [] tocs
return $ MainProgramBlock [] res
parseMainProgramBlock _ = Left InvalidStartOfBlock

Expand Down Expand Up @@ -126,13 +127,14 @@ splitToMatchingBracket toks = go toks [] 0
go (x : xs) acc i = go xs (x : acc) i
go [] _ _ = Left UnmatchedBracket

parseStatements :: [Statement] -> [HSPCToken] -> Either ParseError ([Statement], [HSPCToken])
parseStatements acc (EndKeyWordTok : xs) = Right (reverse acc, xs)
parseStatements _ [] = Left ExpectedEndStatement
parseStatements acc xs = do
parseStatements :: HSPCToken -> [Statement] -> [HSPCToken] -> Either ParseError ([Statement], [HSPCToken])
parseStatements endTok acc (x : xs)
| x == endTok = Right (reverse acc, xs)
parseStatements _ _ [] = Left ExpectedEndStatement
parseStatements endTok acc xs = do
(expr, restWithSemiColon) <- parseStatement xs
rest <- removeLeadingSemiColon restWithSemiColon
parseStatements (expr : acc) rest
parseStatements endTok (expr : acc) rest

parseStatement :: [HSPCToken] -> Either ParseError (Statement, [HSPCToken])
parseStatement (IdentifierTok name : AssignmentTok : xs) = do
Expand All @@ -146,6 +148,9 @@ parseStatement
(internal, rest) <- splitToMatchingBracket xs
op <- parseExpression internal
return (Halt op, rest)
parseStatement (BeginKeyWordTok : xs) = do
(stmts, rest) <- parseStatements EndKeyWordTok [] xs
return (StatementBlock stmts, rest)

-- "IF cond THEN statement (; | ELSE elseStatement;)"
-- ELSE IF is simply an if statement where elseSatement
Expand Down
4 changes: 3 additions & 1 deletion src/HSPC/Tokenize.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ data HSPCToken
| VarKeyWordTok
| BeginKeyWordTok
| EndKeyWordTok
| ProgramEndKeyWordTok
| WhileKeyWordTok
| DoKeyWordTok
| IfKeyWordTok
Expand Down Expand Up @@ -54,7 +55,7 @@ tokenize ('{' : cs) = tokenize $ dropWhile (/= '}') cs
tokenize (c : cs)
| "//" `isPrefixOf` (c : cs) = tokenize $ dropWhile (/= '\n') cs
-- End includes this annoying '.'
| "END." `isPrefixOf` map toUpper (c : cs) = EndKeyWordTok : tokenize (drop 3 cs)
| "END." `isPrefixOf` map toUpper (c : cs) = ProgramEndKeyWordTok : tokenize (drop 3 cs)
| isSpace c = tokenize cs
| isDigit c =
let (num, rest) = span isDigit (c : cs)
Expand All @@ -73,6 +74,7 @@ tokenizeIdentifierOrKeyWord "IF" = IfKeyWordTok
tokenizeIdentifierOrKeyWord "ELSE" = ElseKeyWordTok
tokenizeIdentifierOrKeyWord "THEN" = ThenKeyWordTok
tokenizeIdentifierOrKeyWord "BEGIN" = BeginKeyWordTok
tokenizeIdentifierOrKeyWord "END" = EndKeyWordTok
tokenizeIdentifierOrKeyWord "HALT" = HaltBuiltInTok
tokenizeIdentifierOrKeyWord "DIV" = IntDivideTok
tokenizeIdentifierOrKeyWord "INTEGER" = IntegerTypeTok
Expand Down
3 changes: 3 additions & 0 deletions test/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ testSuite =
TestSpec "Exit code > 255" "ints_big_exit_code" 255,
TestSpec "Halt after Halt" "ints_halt_after_halt" 0,
TestSpec "Add literal ints" "operators_add_two_ints" 200,
TestSpec "Subtract literal ints" "operators_sub_two_ints" 90,
TestSpec "Multiply literal ints" "operators_multiply_two_ints" 40,
TestSpec "Divide(div) literal ints" "operators_divide_two_ints" 2,
TestSpec "Brackets with literal ints" "operators_brackets" 26,
Expand All @@ -44,9 +45,11 @@ testSuite =
TestSpec "IF ELSE" "if_else" 40,
TestSpec "IF ELSE IF" "if_else_if" 40,
TestSpec "IF with complex cond" "if_complex_cond" 40,
TestSpec "IF with block" "if_block" 15,
TestSpec "WHILE basic example" "while" 0,
TestSpec "WHILE not equal (<> 10)" "while_not_equal_10" 10,
TestSpec "WHILE less than (< 1000)" "while_less_than" 100,
TestSpec "WHILE with block" "while_block" 250,
TestSpec "Greater than (> and >=)" "comparison_greater_than" 40,
TestSpec "Less than (< and <=)" "comparison_less_than" 23,
TestSpec "Equality (= and <>)" "comparison_equality" 22
Expand Down
Empty file.
16 changes: 16 additions & 0 deletions test/sample_programs/if_block.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
program IfExample;

var
i : integer;
begin
i := 10;

if (True) then
begin
i := 10;
i := 20;
i := 15;
end;

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

begin
halt(100-10);
end.
Empty file.
18 changes: 18 additions & 0 deletions test/sample_programs/while_block.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
program WhileExample;

var
i : integer;
j : integer;
begin
i := 0;
j := 0;

while i < 25 do
begin
j := (j + 20) - 10;
i := i + 1;
end;


halt(j);
end.