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