From 69287beabd8beb0616737a3bb000b9cee2ba1a6f Mon Sep 17 00:00:00 2001 From: huwenchao Date: Mon, 6 Jan 2020 20:52:20 +0800 Subject: [PATCH] feat: add brainfuck example written in class --- README.md | 5 +- examples/brainfuck_class/brainfuck.ts | 153 ++++++++++++++++++++++++++ examples/brainfuck_class/test.ts | 14 +++ 3 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 examples/brainfuck_class/brainfuck.ts create mode 100644 examples/brainfuck_class/test.ts diff --git a/README.md b/README.md index 9c13166..7df2516 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,9 @@ Then install minits: ``` $ git clone https://github.com/cryptape/minits -$ npm install -$ npm run build +$ cd minits +$ yarn +$ yarn run build ``` # Writing and Compiling a TypeScript Program diff --git a/examples/brainfuck_class/brainfuck.ts b/examples/brainfuck_class/brainfuck.ts new file mode 100644 index 0000000..a8f6991 --- /dev/null +++ b/examples/brainfuck_class/brainfuck.ts @@ -0,0 +1,153 @@ +// $ node build/main/index.js build examples/brainfuck_class/brainfuck.ts -o brainfuck.ll +// $ clang brainfuck.ll -o brainfuck +// +// $ ./brainfuck "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>." + +const enum Opcode { + SHR = '>', + SHL = '<', + ADD = '+', + SUB = '-', + PUTCHAR = '.', + GETCHAR = ',', + LB = '[', + RB = ']', +} + +export class BrainfuckInterpreter { + code: string; + pc: number; + ps: number; + + constructor(code: string) { + this.code = code; + this.pc = 0; + this.ps = 0; + } + + reset() { + this.pc = 0; + this.ps = 0; + } + + uint8(n: number): number { + if (n > 0xff) { + return this.uint8(n - 256); + } + if (n < 0x00) { + return this.uint8(n + 256); + } + return n + } + + run(): number { + this.reset(); + let stack = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + // run + for (; this.pc < this.code.length;) { + let op = this.code[this.pc]; + if (op === Opcode.SHR) { + this.ps += 1; + this.pc += 1; + continue + } + if (op === Opcode.SHL) { + this.ps -= 1; + this.pc += 1; + continue + } + if (op === Opcode.ADD) { + stack[this.ps] = this.uint8(stack[this.ps] + 1); + this.pc += 1; + continue + } + if (op === Opcode.SUB) { + stack[this.ps] = this.uint8(stack[this.ps] - 1); + this.pc += 1; + continue + } + if (op === Opcode.PUTCHAR) { + this.putchar(stack[this.ps]); + this.pc += 1; + continue + } + if (op === Opcode.GETCHAR) { + console.log('GETCHAR is disabled'); + return 1; + } + + + if (op === Opcode.LB) { + if (stack[this.ps] != 0x00) { + this.pc += 1; + continue + } + let n = 1; + for (; n !== 0;) { + this.pc += 1; + if (this.code[this.pc] === Opcode.LB) { + n += 1; + continue + } + if (this.code[this.pc] === Opcode.RB) { + n -= 1; + continue + } + } + this.pc += 1; + continue + } + if (op === Opcode.RB) { + if (stack[this.ps] === 0x00) { + this.pc += 1; + continue + } + let n = 1; + for (; n !== 0;) { + this.pc -= 1; + if (this.code[this.pc] === Opcode.RB) { + n += 1; + continue + } + if (this.code[this.pc] === Opcode.LB) { + n -= 1; + continue + } + } + this.pc += 1; + continue + } + } + return 0; + } + + putchar(n: number) { + console.log('%c', n); + } +} + +export function main(argc: number, argv: string[]): number { + if (argc !== 2) { + return 1; + } + let bfi = new BrainfuckInterpreter(argv[1]); + let status_code = bfi.run(); + return status_code; +} diff --git a/examples/brainfuck_class/test.ts b/examples/brainfuck_class/test.ts new file mode 100644 index 0000000..9a3399c --- /dev/null +++ b/examples/brainfuck_class/test.ts @@ -0,0 +1,14 @@ +// use ts-node to run the file directly for devlopment and test. +// ts-node examples/brainfuck_class/test.ts +import { BrainfuckInterpreter } from './brainfuck'; + +BrainfuckInterpreter.prototype.putchar = (n: number) => { + process.stdout.write(String.fromCharCode(n)); +} +let code = '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.'; +console.log(`code: ${code}`); +console.log('\n---------- start ----------'); +let bfi = new BrainfuckInterpreter(code); +let status_code = bfi.run(); +console.log('---------- end ----------\n'); +console.log(`status_code: ${status_code}`);