Home | History | Annotate | Line # | Download | only in tutorial
      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