1 1.1 alnsn /* 2 1.1 alnsn * Brainfuck interpreter with SLJIT 3 1.1 alnsn * 4 1.1 alnsn * Copyright 2015 Wen Xichang (wenxichang (at) 163.com). All rights reserved. 5 1.1 alnsn * 6 1.1 alnsn * Redistribution and use in source and binary forms, with or without modification, are 7 1.1 alnsn * permitted provided that the following conditions are met: 8 1.1 alnsn * 9 1.1 alnsn * 1. Redistributions of source code must retain the above copyright notice, this list of 10 1.1 alnsn * conditions and the following disclaimer. 11 1.1 alnsn * 12 1.1 alnsn * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 1.1 alnsn * of conditions and the following disclaimer in the documentation and/or other materials 14 1.1 alnsn * provided with the distribution. 15 1.1 alnsn * 16 1.1 alnsn * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 1.1 alnsn * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 alnsn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 1.1 alnsn * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 alnsn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 1.1 alnsn * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 1.1 alnsn * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 1.1 alnsn * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 1.1 alnsn * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 alnsn */ 26 1.1 alnsn 27 1.1 alnsn #include "sljitLir.h" 28 1.1 alnsn 29 1.1 alnsn #include <stdio.h> 30 1.1 alnsn #include <stdlib.h> 31 1.1 alnsn 32 1.1 alnsn #define BF_CELL_SIZE 3000 33 1.1 alnsn #define BF_LOOP_LEVEL 256 34 1.1 alnsn 35 1.1 alnsn static int readvalid(FILE *src) 36 1.1 alnsn { 37 1.1 alnsn int chr; 38 1.1 alnsn 39 1.1 alnsn while ((chr = fgetc(src)) != EOF) { 40 1.1 alnsn switch (chr) { 41 1.1 alnsn case '+': 42 1.1 alnsn case '-': 43 1.1 alnsn case '>': 44 1.1 alnsn case '<': 45 1.1 alnsn case '.': 46 1.1 alnsn case ',': 47 1.1 alnsn case '[': 48 1.1 alnsn case ']': 49 1.1 alnsn return chr; 50 1.1 alnsn } 51 1.1 alnsn } 52 1.1 alnsn 53 1.1 alnsn return chr; 54 1.1 alnsn } 55 1.1 alnsn 56 1.1 alnsn /* reading same instruction, and count, for optimization */ 57 1.1 alnsn /* ++++ -> '+', 4 */ 58 1.1 alnsn static int gettoken(FILE *src, int *ntok) 59 1.1 alnsn { 60 1.1 alnsn int chr = readvalid(src); 61 1.1 alnsn int chr2; 62 1.1 alnsn int cnt = 1; 63 1.1 alnsn 64 1.1 alnsn if (chr == EOF) 65 1.1 alnsn return EOF; 66 1.1 alnsn 67 1.1 alnsn if (chr == '.' || chr == ',' || chr == '[' || chr == ']') { 68 1.1 alnsn *ntok = 1; 69 1.1 alnsn return chr; 70 1.1 alnsn } 71 1.1 alnsn 72 1.1 alnsn while ((chr2 = readvalid(src)) == chr) 73 1.1 alnsn cnt++; 74 1.1 alnsn 75 1.1 alnsn if (chr2 != EOF) 76 1.1 alnsn ungetc(chr2, src); 77 1.1 alnsn 78 1.1 alnsn *ntok = cnt; 79 1.1 alnsn return chr; 80 1.1 alnsn } 81 1.1 alnsn 82 1.1 alnsn /* maintaining loop matched [] */ 83 1.1 alnsn struct loop_node_st { 84 1.1 alnsn struct sljit_label *loop_start; 85 1.1 alnsn struct sljit_jump *loop_end; 86 1.1 alnsn }; 87 1.1 alnsn 88 1.1 alnsn /* stack of loops */ 89 1.1 alnsn static struct loop_node_st loop_stack[BF_LOOP_LEVEL]; 90 1.1 alnsn static int loop_sp; 91 1.1 alnsn 92 1.1 alnsn static int loop_push(struct sljit_label *loop_start, struct sljit_jump *loop_end) 93 1.1 alnsn { 94 1.1 alnsn if (loop_sp >= BF_LOOP_LEVEL) 95 1.1 alnsn return -1; 96 1.1 alnsn 97 1.1 alnsn loop_stack[loop_sp].loop_start = loop_start; 98 1.1 alnsn loop_stack[loop_sp].loop_end = loop_end; 99 1.1 alnsn loop_sp++; 100 1.1 alnsn return 0; 101 1.1 alnsn } 102 1.1 alnsn 103 1.1 alnsn static int loop_pop(struct sljit_label **loop_start, struct sljit_jump **loop_end) 104 1.1 alnsn { 105 1.1 alnsn if (loop_sp <= 0) 106 1.1 alnsn return -1; 107 1.1 alnsn 108 1.1 alnsn loop_sp--; 109 1.1 alnsn *loop_start = loop_stack[loop_sp].loop_start; 110 1.1 alnsn *loop_end = loop_stack[loop_sp].loop_end; 111 1.1 alnsn return 0; 112 1.1 alnsn } 113 1.1 alnsn 114 1.1 alnsn static SLJIT_CALL void *my_alloc(long size, long n) 115 1.1 alnsn { 116 1.1 alnsn return calloc(size, n); 117 1.1 alnsn } 118 1.1 alnsn 119 1.1 alnsn static SLJIT_CALL void my_putchar(long c) 120 1.1 alnsn { 121 1.1 alnsn putchar(c); 122 1.1 alnsn } 123 1.1 alnsn 124 1.1 alnsn static SLJIT_CALL long my_getchar(void) 125 1.1 alnsn { 126 1.1 alnsn return getchar(); 127 1.1 alnsn } 128 1.1 alnsn 129 1.1 alnsn static SLJIT_CALL void my_free(void *mem) 130 1.1 alnsn { 131 1.1 alnsn free(mem); 132 1.1 alnsn } 133 1.1 alnsn 134 1.1 alnsn #define loop_empty() (loop_sp == 0) 135 1.1 alnsn 136 1.1 alnsn /* compile bf source to a void func() */ 137 1.1 alnsn static void *compile(FILE *src, unsigned long *lcode) 138 1.1 alnsn { 139 1.1 alnsn void *code = NULL; 140 1.1 alnsn int chr; 141 1.1 alnsn int nchr; 142 1.1 alnsn 143 1.1 alnsn struct sljit_compiler *C = sljit_create_compiler(); 144 1.1 alnsn struct sljit_jump *end; 145 1.1 alnsn struct sljit_label *loop_start; 146 1.1 alnsn struct sljit_jump *loop_end; 147 1.1 alnsn 148 1.1 alnsn int SP = SLJIT_S0; /* bf SP */ 149 1.1 alnsn int CELLS = SLJIT_S1; /* bf array */ 150 1.1 alnsn 151 1.1 alnsn sljit_emit_enter(C, 0, 0, 2, 2, 0, 0, 0); /* opt arg R S FR FS local_size */ 152 1.1 alnsn 153 1.1 alnsn sljit_emit_op2(C, SLJIT_XOR, SP, 0, SP, 0, SP, 0); /* SP = 0 */ 154 1.1 alnsn 155 1.1 alnsn sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, BF_CELL_SIZE); 156 1.1 alnsn sljit_emit_op1(C, SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, 1); 157 1.1 alnsn sljit_emit_ijump(C, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(my_alloc));/* calloc(BF_CELL_SIZE, 1) => R0 */ 158 1.1 alnsn 159 1.1 alnsn end = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0); /* R0 == 0 --> jump end */ 160 1.1 alnsn 161 1.1 alnsn sljit_emit_op1(C, SLJIT_MOV, CELLS, 0, SLJIT_R0, 0); /* CELLS = R0 */ 162 1.1 alnsn 163 1.1 alnsn while ((chr = gettoken(src, &nchr)) != EOF) { 164 1.1 alnsn switch (chr) { 165 1.1 alnsn case '+': 166 1.1 alnsn case '-': 167 1.1 alnsn sljit_emit_op1(C, SLJIT_MOV_UB, SLJIT_R0, 0, SLJIT_MEM2(CELLS, SP), 0); /* R0 = CELLS[SP] */ 168 1.1 alnsn sljit_emit_op2(C, chr == '+' ? SLJIT_ADD : SLJIT_SUB, 169 1.1 alnsn SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, nchr); /* R0 ?= nchr */ 170 1.1 alnsn sljit_emit_op1(C, SLJIT_MOV_UB, SLJIT_MEM2(CELLS, SP), 0, SLJIT_R0, 0); /* CELLS[SP] = R0 */ 171 1.1 alnsn break; 172 1.1 alnsn case '>': 173 1.1 alnsn case '<': 174 1.1 alnsn sljit_emit_op2(C, chr == '>' ? SLJIT_ADD : SLJIT_SUB, 175 1.1 alnsn SP, 0, SP, 0, SLJIT_IMM, nchr); /* SP ?= nchr */ 176 1.1 alnsn break; 177 1.1 alnsn case '.': 178 1.1 alnsn sljit_emit_op1(C, SLJIT_MOV_UB, SLJIT_R0, 0, SLJIT_MEM2(CELLS, SP), 0); /* R0 = CELLS[SP] */ 179 1.1 alnsn sljit_emit_ijump(C, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(my_putchar)); /* putchar(R0) */ 180 1.1 alnsn break; 181 1.1 alnsn case ',': 182 1.1 alnsn sljit_emit_ijump(C, SLJIT_CALL0, SLJIT_IMM, SLJIT_FUNC_OFFSET(my_getchar)); /* R0 = getchar() */ 183 1.1 alnsn sljit_emit_op1(C, SLJIT_MOV_UB, SLJIT_MEM2(CELLS, SP), 0, SLJIT_R0, 0); /* CELLS[SP] = R0 */ 184 1.1 alnsn break; 185 1.1 alnsn case '[': 186 1.1 alnsn loop_start = sljit_emit_label(C); /* loop_start: */ 187 1.1 alnsn sljit_emit_op1(C, SLJIT_MOV_UB, SLJIT_R0, 0, SLJIT_MEM2(CELLS, SP), 0); /* R0 = CELLS[SP] */ 188 1.1 alnsn loop_end = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0); /* IF R0 == 0 goto loop_end */ 189 1.1 alnsn 190 1.1 alnsn if (loop_push(loop_start, loop_end)) { 191 1.1 alnsn fprintf(stderr, "Too many loop level\n"); 192 1.1 alnsn goto compile_failed; 193 1.1 alnsn } 194 1.1 alnsn break; 195 1.1 alnsn case ']': 196 1.1 alnsn if (loop_pop(&loop_start, &loop_end)) { 197 1.1 alnsn fprintf(stderr, "Unmatch loop ]\n"); 198 1.1 alnsn goto compile_failed; 199 1.1 alnsn } 200 1.1 alnsn 201 1.1 alnsn sljit_set_label(sljit_emit_jump(C, SLJIT_JUMP), loop_start); /* goto loop_start */ 202 1.1 alnsn sljit_set_label(loop_end, sljit_emit_label(C)); /* loop_end: */ 203 1.1 alnsn break; 204 1.1 alnsn } 205 1.1 alnsn } 206 1.1 alnsn 207 1.1 alnsn if (!loop_empty()) { 208 1.1 alnsn fprintf(stderr, "Unmatch loop [\n"); 209 1.1 alnsn goto compile_failed; 210 1.1 alnsn } 211 1.1 alnsn 212 1.1 alnsn sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, CELLS, 0); 213 1.1 alnsn sljit_emit_ijump(C, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(my_free)); /* free(CELLS) */ 214 1.1 alnsn 215 1.1 alnsn sljit_set_label(end, sljit_emit_label(C)); 216 1.1 alnsn sljit_emit_return(C, SLJIT_UNUSED, 0, 0); 217 1.1 alnsn 218 1.1 alnsn code = sljit_generate_code(C); 219 1.1 alnsn if (lcode) 220 1.1 alnsn *lcode = sljit_get_generated_code_size(C); 221 1.1 alnsn 222 1.1 alnsn compile_failed: 223 1.1 alnsn sljit_free_compiler(C); 224 1.1 alnsn return code; 225 1.1 alnsn } 226 1.1 alnsn 227 1.1 alnsn /* function prototype of bf compiled code */ 228 1.1 alnsn typedef void (*bf_entry_t)(void); 229 1.1 alnsn 230 1.1 alnsn int main(int argc, char **argv) 231 1.1 alnsn { 232 1.1 alnsn void *code; 233 1.1 alnsn bf_entry_t entry; 234 1.1 alnsn FILE *fp; 235 1.1 alnsn 236 1.1 alnsn if (argc < 2) { 237 1.1 alnsn fprintf(stderr, "Usage: %s <brainfuck program>\n", argv[0]); 238 1.1 alnsn return -1; 239 1.1 alnsn } 240 1.1 alnsn 241 1.1 alnsn fp = fopen(argv[1], "rb"); 242 1.1 alnsn if (!fp) { 243 1.1 alnsn perror("open"); 244 1.1 alnsn return -1; 245 1.1 alnsn } 246 1.1 alnsn 247 1.1 alnsn code = compile(fp, NULL); 248 1.1 alnsn fclose(fp); 249 1.1 alnsn 250 1.1 alnsn if (!code) { 251 1.1 alnsn fprintf(stderr, "[Fatal]: Compile failed\n"); 252 1.1 alnsn return -1; 253 1.1 alnsn } 254 1.1 alnsn 255 1.1 alnsn entry = (bf_entry_t)code; 256 1.1 alnsn entry(); 257 1.1 alnsn 258 1.1 alnsn sljit_free_code(code); 259 1.1 alnsn return 0; 260 1.1 alnsn } 261