package main import ( "errors" "fmt" "os" ) func run(code []int16) error { if len(code) != 100 { return errors.New("Code must be exactly 100 mailboxes long") } // for i, x := range code { // fmt.Printf("%d: %d\n", i, x) // } // fmt.Println() var accumulator int16 = 0 pc := 0 for pc >= 0 && pc < len(code) { i := code[pc] arg := i % 100 pc++ switch i - arg { case IHALT: return nil case IADD: accumulator += code[arg] case ISUBTRACT: accumulator -= code[arg] case ISTORE: code[arg] = accumulator case ILOAD: accumulator = code[arg] case IBRANCH: pc = int(i % 100) case IBRANCH_IF_ZERO: if accumulator == 0 { pc = int(arg) } case IBRANCH_IF_POSITIVE: if accumulator > 0 { pc = int(arg) } case IIO: switch arg { case IO_INPUT: fmt.Printf("Input: ") fmt.Scanf("%d\n", &accumulator) case IO_OUTPUT: fmt.Printf("Output: %d\n", accumulator) } default: e := fmt.Sprintf("Unsupported instruction %d at %d", i, pc) return errors.New(e) } } return errors.New("Program counter ran away") } func main() { if len(os.Args) != 2 { fmt.Printf("usage: %s file\n", os.Args[0]) } else if file, err := os.Open(os.Args[1]); err != nil { fmt.Printf("Cannot open file: %s\n", err) } else if code, err := Assemble(file); err != nil { fmt.Printf("Assembly failed: %s\n", err) } else if err = run(code); err != nil { fmt.Printf("Runtime error: %s\n", err) } else { os.Exit(0) } os.Exit(1) }