Browse Source

Read binary program from file + tests init work

master
soupi 1 year ago
parent
commit
1c9fe1a920
5 changed files with 103 additions and 13 deletions
  1. +1
    -0
      .gitignore
  2. +5
    -0
      build.hs
  3. +26
    -7
      src/main.c
  4. +64
    -0
      tests/Tests.hs
  5. +7
    -6
      todo.org

+ 1
- 0
.gitignore View File

@@ -1,3 +1,4 @@
a.bin
_build
zig-cache



+ 5
- 0
build.hs View File

@@ -24,6 +24,11 @@ main = shakeArgs shakeOptions{shakeFiles="_build"} $ do
putInfo "Running _build/vm"
cmd_ "_build/vm" "_build/vm"

phony "test" $ do
need ["_build/vm" <.> exe]
putInfo "Testing vm"
cmd_ "tests/Tests.hs" ""

"_build/vm" <.> exe %> \out -> do
cs <- getDirectoryFiles "src" ["//*.c"]
let os = ["_build" </> "src" </> c -<.> "o" | c <- cs]


+ 26
- 7
src/main.c View File

@@ -1,6 +1,6 @@
#include <stdio.h>

#define DEBUG 1
#define DEBUG 0
#define DEBUG_PRINT(op) \
printf("(%d) %s | sp: %d | program[ip]: %d | stack: ", ip, (op), sp, program[ip]); \
print_array(sp + 1, stack);
@@ -8,12 +8,22 @@
int interpret(int* program);
void print_array(int size, int* array);

/*
int main(int argc, char* argv[]) {
if (argc != 2) {
puts("Expecting the first argument to be the input file.\n");
return 2;
}

FILE *fp = fopen(argv[argc], "r");
*/

int main(void) {
FILE *fp = fopen("a.bin", "r");
int program[255];
fread(program, sizeof(program), sizeof(int), fp);
fclose(fp);

// int program[] = { 1, 17, 2, 0 }; // print 17
// int program[] = { 1, 1, 1, 2, 3, 4, 5, 4, 5, 2, 0 }; // print (1 + 2)
// print (1 + (2 + (3 + (4 + 5)))))
int program[] = { 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 5, 3, 4, 3, 4, 5, 3, 4, 3, 4, 5, 3, 4, 3, 4, 5, 3, 4, 3, 4, 2, 0 };
return interpret(program);
}

@@ -38,6 +48,7 @@ int interpret(int* program) {
&&add
};

int temp;
int stack[1023] = { 0 };
int sp = -1;
int ip = 0;
@@ -73,9 +84,9 @@ int interpret(int* program) {
DEBUG_PRINT("swap");
#endif

int x = stack[sp];
temp = stack[sp];
stack[sp] = stack[sp - 1];
stack[sp - 1] = x;
stack[sp - 1] = temp;
goto *instructions[program[++ip]];

pop:
@@ -105,3 +116,11 @@ void print_array(int size, int* array) {
}
puts("\n");
}

// tests


// int program[] = { 1, 17, 2, 0 }; // print 17
// int program[] = { 1, 1, 1, 2, 3, 4, 5, 4, 5, 2, 0 }; // print (1 + 2)
// print (1 + (2 + (3 + (4 + 5)))))
//int program[] = { 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 5, 3, 4, 3, 4, 5, 3, 4, 3, 4, 5, 3, 4, 3, 4, 5, 3, 4, 3, 4, 2, 0 };

+ 64
- 0
tests/Tests.hs View File

@@ -0,0 +1,64 @@
#!/usr/bin/env stack
-- stack --resolver lts-15.7 script --package bytestring --package cereal --package hspec --package process

{-# LANGUAGE LambdaCase #-}

import Data.Int
import Data.Serialize
import qualified Data.ByteString as BS
import System.Process

import Test.Hspec

main :: IO ()
main = hspec $ do
describe "tests" $ do
it "prints 17" $ do
writeTestToFile "a.bin" . compile $ [ Lit 17, Print, Halt ]
callProcess "_build/vm" ["a.bin"]

it "print (1 + 2)" $ do
writeTestToFile "a.bin" . compile $ [ Lit 1, Lit 2, Add, Print, Halt ]
callProcess "_build/vm" ["a.bin"]

it "print (1 + (2 + (3 + (4 + 5))))" $ do
writeTestToFile "a.bin" . compile $ [ Lit 1, Lit 2, Lit 3, Lit 4, Lit 5, Add, Add, Add, Add, Print, Halt ]
callProcess "_build/vm" ["a.bin"]

it "print (swap 1 2)" $ do
writeTestToFile "a.bin" . compile $ [ Lit 1, Lit 2, Swap, Print, Halt ]
callProcess "_build/vm" ["a.bin"]

type Program = [Int32]
type Program' = [Stmt]

data Stmt
= Lit Int32
| Add
| Swap
| Print
| Halt
deriving (Show, Read)

halt_ = 0
load_ = 1
print_ = 2
swap_ = 3
pop_ = 4
add_ = 5

compileStmt :: Stmt -> Program
compileStmt = \case
Lit n -> [load_, n]
Add -> [add_, swap_, pop_, swap_, pop_]
Swap -> [swap_]
Print -> [print_]
Halt -> [halt_]

compile :: Program' -> Program
compile = concatMap compileStmt

writeTestToFile :: FilePath -> Program -> IO ()
writeTestToFile file =
BS.writeFile file . runPut . mapM_ putInt32le


+ 7
- 6
todo.org View File

@@ -5,22 +5,23 @@ I hope to work on this long enough to get to implementing closures, garbage coll
I'll be taking cues from OCaml and Chicken Scheme, along with other resources, combined with some experimentation.
I don't exactly know what I'm doing, but I have a rough idea. So please be patient with me!
** Tasks
*** Decide on bytecode scheme
*** DONE Decide on bytecode scheme
- load int, add, push, pop, print, halt
*** Add demo programs
*** DONE Add demo programs
| Program | Expected result |
|---------------------------------+-----------------|
| 1 print halt; | print 1 |
| 1 2 add 3 4 add add print halt; | print 10 |
*** Implement interpreter for demo programs
*** DONE Implement interpreter for demo programs
Should have a stack, stack pointer, instruction pointer

- Start with: just load int, print and halt
- Later add: push, pop, add
*** Write tests for the above in Haskell
*** Add strings
*** TODO Write tests for the above in Haskell
Need to actually test print output
*** TODO Add strings
- Heap allocated strings, int-to-str, concat, change print to only print strings
*** Add Automatic Memory Management for Heap Allocated Objects
*** TODO Add Automatic Memory Management for Heap Allocated Objects
*** Add bytearrays
*** Add Jumps and Conditional Jumps
*** Add Functions and Closures


Loading…
Cancel
Save