package main import "core:fmt" import "core:mem/virtual" import "core:os" import "core:strings" //MEMORY_SIZE :: 1 << 16 MEMORY_SIZE :: 1024 * 2 open_bf_file :: proc(filepath: string) -> (data: []byte) { ok: bool data, ok = os.read_entire_file(filepath) if !ok { fmt.eprintfln("ERROR: Cannot read file: %s", filepath) return } return data } build_bracket_matching_table :: proc( bracket_map: ^map[int]int, stack: ^[dynamic]int, data: []byte, ) { program := string(data) for index in 0 ..< len(program) { switch program[index] { case 91: // [ (start loop) append(stack, index) case 93: // ] (end loop) if len(stack) > 0 { start := pop(stack) bracket_map[start] = index bracket_map[index] = start } case: continue } } } run_bf_file :: proc( tape: ^[MEMORY_SIZE]byte, bracket_map: ^map[int]int, stack: ^[dynamic]int, data: []byte, ) { program := string(data) ptr: i64 for ip := 0; ip < len(program); ip += 1 { switch program[ip] { case 43: // + (increment cell value) tape[ptr] += 1 case 45: // - (decrement cell value) tape[ptr] -= 1 case 62: // > (move pointer right) ptr += 1 case 60: // < (move pointer left) ptr -= 1 case 46: // . (output cell value) output := fmt.tprintf("%c", tape[ptr]) fmt.print(output) case 44: // , (input to cell) case 91: // [ (start loop) if tape[ptr] == 0 { //jump forward to the matching ']' ip = bracket_map[ip] } case 93: // ] (end loop) if tape[ptr] != 0 { //jump back to the matching '[' ip = bracket_map[ip] } case: continue } } } main :: proc() { //Set up arena allocator arena: virtual.Arena arena_allocator := virtual.arena_allocator(&arena) defer virtual.arena_destroy(&arena) //handle args filename: string if len(os.args) < 2 { fmt.printfln("Usage:\n %s [file]", os.args[0]) return } filename = os.args[1] //check if the file is a valid bf file if !strings.has_suffix(filename, ".b") { fmt.eprintfln("ERROR: File %s does not have a valid b extention (.b)", filename) return } file := open_bf_file(filename) bracket_map := make(map[int]int, allocator = arena_allocator) stack := new([dynamic]int, allocator = arena_allocator) //returns a pointer tape := new([MEMORY_SIZE]byte, allocator = arena_allocator) build_bracket_matching_table(&bracket_map, stack, file) run_bf_file(tape, &bracket_map, stack, file) }