Skip to content

Commit 70170b7

Browse files
committed
v 0.2 :D
1 parent c8740eb commit 70170b7

12 files changed

+350
-305
lines changed

kisscomp.c

+128-122
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#include <kissfuck.h>
2+
#include <stddef.h>
23
#include <stdlib.h>
4+
#include <assert.h>
35

46
/*
5-
* KISS brainfuck iterpreter.
7+
* KISS brainfuck iterpreter. Compiler to the bytecode.
68
* Copyright (C) UtoECat 2023. All rights reserved.
79
* GNU GPL License. No any warranty.
810
*
@@ -13,6 +15,7 @@
1315
* Context allocation
1416
*/
1517

18+
1619
struct kissfuck* makectx() {
1720
void *p = calloc(sizeof(struct kissfuck), 1);
1821
if (!p) {
@@ -30,44 +33,98 @@ void freectx (struct kissfuck* x) {
3033
* COMPILING
3134
*/
3235

33-
static void compiler_message(struct kissfuck* x, const char* s) {
34-
fprintf(stderr, "[compiler] : %s (at line %i)\n", s, x->line);
35-
}
36-
37-
#define INDEX_LONG_BC(x, pos) *((uint16_t*)(x->bytecode + (pos)))
36+
struct compstate {
37+
uint8_t* bytecode;
38+
uint16_t instp; // instruction pointer
39+
uint16_t jmptbl[65536][2];
40+
uint16_t jmptblpos;
41+
enum bytecode currcode;
42+
int codedata;
43+
int line;
44+
};
3845

39-
static int finallize_jumppair(struct kissfuck* x, uint16_t first, uint16_t second) {
40-
// some assertions first
41-
if (x->bytecode[first] != BC_JPZ) {
42-
return ERR_ERR;
43-
}
44-
if (x->bytecode[second] != BC_JPNZ) {
45-
return ERR_ERR;
46-
}
47-
uint16_t start = first + sizeof(uint16_t) + 1;
48-
uint16_t end = second + sizeof(uint16_t) + 1;
49-
// set jump destinations :D
50-
INDEX_LONG_BC(x, first + 1) = end;
51-
INDEX_LONG_BC(x, second + 1) = start;
52-
return ERR_OK;
53-
}
46+
#define NEXT_CHAR() ch = getc(f);
5447

55-
static int checkchar(FILE* f, char ch) {
56-
return (!feof(f)) && ch;
48+
static void compiler_message(struct compstate* x, const char* s) {
49+
fprintf(stderr, "[compiler] : %s (at line %i)\n", s, x->line);
5750
}
5851

59-
static inline void pushbc1(struct kissfuck* x, enum bytecode b, uint8_t v) {
52+
// sets instruction with short argument (8 bits)
53+
static inline void pushbc1(struct compstate* x, enum bytecode b, uint8_t v) {
6054
x->bytecode[x->instp++] = b;
6155
x->bytecode[x->instp++] = v; // constant value
6256
};
6357

64-
static inline void pushbc2(struct kissfuck* x, enum bytecode b, uint16_t v) {
58+
// sets instruction with long argument (16 bits, 1 byte alligment)
59+
static inline void pushbc2(struct compstate* x, enum bytecode b, uint16_t v) {
6560
x->bytecode[x->instp++] = b;
6661
*(uint16_t*)(x->bytecode + x->instp) = v; // constant value
6762
x->instp += 2;
6863
};
6964

70-
static inline void closecode(struct kissfuck* x, enum bytecode b, int v) {
65+
// links jumps instructions to each other (on instruction below each other)
66+
static int finallize_jumppair(struct compstate* x, uint16_t f, uint16_t s) {
67+
// next instructions after JPZ and JPNZ instructions
68+
uint16_t start = f + sizeof(uint16_t) + 1;
69+
uint16_t end = s + sizeof(uint16_t) + 1;
70+
// set jump distanations
71+
*(uint16_t*)(x->bytecode + f + 1) = end;
72+
*(uint16_t*)(x->bytecode + s + 1) = start;
73+
return ERR_OK;
74+
}
75+
76+
// tries to finnalize jumppair (returns 1 on success)
77+
static int trytofinnalize(struct compstate* x) {
78+
uint16_t* start = &x->jmptbl[x->jmptblpos][1];
79+
uint16_t* end = &x->jmptbl[x->jmptblpos][0];
80+
81+
if (*start && *end) {
82+
// table can be finnalized!
83+
assert(finallize_jumppair(x, *start, *end) == ERR_OK);
84+
*start = 0;
85+
*end = 0;
86+
return 1;
87+
}
88+
return 0;
89+
}
90+
91+
static void addjumpstart(struct compstate* x) {
92+
// if jump table is busy
93+
if (x->jmptbl[x->jmptblpos][0]) x->jmptblpos++;
94+
// add start of the loop to the jumptable
95+
x->jmptbl[x->jmptblpos][0] = x->instp;
96+
97+
// instruction will be rewrited later
98+
pushbc2(x, BC_JPZ, 0);
99+
100+
if (trytofinnalize(x)) {
101+
// move forward if next jumpfield is not empity
102+
uint16_t npos = x->jmptblpos + 1;
103+
if (x->jmptbl[npos][0] || x->jmptbl[npos][1]) x->jmptblpos = npos;
104+
}
105+
}
106+
107+
static void addjumpend(struct compstate* x) {
108+
// if jump table is busy
109+
if (x->jmptbl[x->jmptblpos][1]) x->jmptblpos--;
110+
// add start of the loop to the jumptable
111+
x->jmptbl[x->jmptblpos][1] = x->instp;
112+
113+
// instruction data will be rewrited later
114+
pushbc2(x, BC_JPNZ, 0);
115+
116+
if (trytofinnalize(x)) {
117+
// move backward if next jumpfield is not empity
118+
uint16_t npos = x->jmptblpos - 1;
119+
if (x->jmptbl[npos][0] || x->jmptbl[npos][1]) x->jmptblpos = npos;
120+
}
121+
}
122+
123+
// finnaly adds instruction to bytecode
124+
static void newcode(struct compstate* x, enum bytecode n) {
125+
enum bytecode b = x->currcode;
126+
int v = x->codedata;
127+
71128
if (b == BC_ADD || b == BC_SET) {
72129
if (v == 0) {return;}
73130
else if (v > 0) pushbc1(x, b, v);
@@ -83,156 +140,105 @@ static inline void closecode(struct kissfuck* x, enum bytecode b, int v) {
83140
pushbc2(x, b, (uint16_t)(UINT16_MAX - v + 1));
84141
}
85142
} else if (b == BC_IN || b == BC_OUT) {
86-
if (v <= 0) {
87-
fprintf(stderr, "Value is below zero or equal; for normal operands :/\n");
88-
exit(-1);
89-
}
143+
assert(v > 0 && "Value is belowequal zero");
90144
pushbc1(x, b, v);
91145
} else if (b == BC_HALT) {
92146
pushbc1(x, b, 0);
93147
}
148+
149+
x->currcode = n;
150+
x->codedata = 0;
94151
}
95152

96-
int loadcode(struct kissfuck* x, const char* filename) {
97-
if (x == ERR_ERR) return ERR_ERR;
153+
/*
154+
* Compilation functions :p
155+
*/
156+
int loadcode(struct kissfuck* kf, const char* filename) {
157+
if (kf == ERR_ERR) return ERR_ERR;
158+
int status = ERR_OK;
159+
char ch;
160+
161+
struct compstate state = {0};
162+
state.currcode = 128;
163+
struct compstate* x = &state;
164+
x->bytecode = kf->bytecode;
98165

99166
// init
100-
x->line = 0;
101-
x->instp = 0;
102-
x->cellp = 0;
167+
stopcode(kf);
103168

104169
FILE *f = fopen(filename, "r");
105170
if (!f) {
106-
compiler_message(x, "Can't open file!");
171+
fprintf(stderr, "[compiler] : can't open file %s!\n", filename);
107172
return ERR_ERR;
108173
}
109174

110-
int status = ERR_OK;
111-
enum bytecode oldcode = 90;
112-
int codedata = 0;
113-
uint16_t jmptbl[65536][2] = {0}; // holy shit
114-
uint16_t jmptblpos = 0;
115-
116-
char ch = getc(f);
117-
#define NEXT_CHAR() ch = getc(f);
118-
while (checkchar(f, ch)) {
175+
while ((ch = getc(f)) && !feof(f)) {
119176

120177
if (CHAR_COMM(ch)) { // comment
121178
while (getc(f) != '\n') {};
122-
x->line++; NEXT_CHAR();
179+
x->line++;
123180
} else if (VALID_TOKEN(ch)) {
124-
int val= 0;
181+
int val = 0;
125182
switch (ch) {
126183
// + and -
127184
case TOKEN_INC :
128-
val = 2;
129-
// falltrough
185+
val = 2;
186+
_fallthrough()
130187
case TOKEN_DEC :
131188
val--;
132-
if (oldcode != BC_ADD && oldcode != BC_SET) {
133-
closecode(x, oldcode, codedata);
134-
oldcode = BC_ADD;
135-
codedata = 0;
136-
}
137-
codedata += val;
189+
if (x->currcode != BC_ADD && x->currcode != BC_SET) newcode(x, BC_ADD);
190+
x->codedata += val;
138191
break;
139192
// ,
140193
case TOKEN_IN :
141-
if (oldcode != BC_IN) {
142-
closecode(x, oldcode, codedata);
143-
oldcode = BC_IN;
144-
codedata = 0;
145-
}
146-
codedata += 1;
194+
if (x->currcode != BC_IN) newcode(x, BC_IN);
195+
x->codedata += 1;
147196
break;
148197
// .
149198
case TOKEN_OUT :
150-
if (oldcode != BC_OUT) {
151-
closecode(x, oldcode, codedata);
152-
oldcode = BC_OUT;
153-
codedata = 0;
154-
}
155-
codedata += 1;
199+
if (x->currcode != BC_OUT) newcode(x, BC_OUT);
200+
x->codedata += 1;
156201
break;
157-
/*
158-
* TODO: GOOCLE TRANSLATE HELP ME :(
159-
* NEXT and PREV operations are взаимоисключающие like addition and substraction
160-
*/
202+
// NEXT and PREV operations are mutually exclusive
203+
// operations like addition and substraction
161204
// > and <
162205
case TOKEN_NEXT :
163206
val = 2;
207+
_fallthrough()
164208
case TOKEN_PREV :
165209
val--;
166-
if (oldcode != BC_NEXT) {
167-
closecode(x, oldcode, codedata);
168-
oldcode = BC_NEXT;
169-
codedata = 0;
170-
}
171-
codedata += val;
210+
if (x->currcode != BC_NEXT) newcode(x, BC_NEXT);
211+
x->codedata += val;
172212
break;
173-
/*
174-
* Loops a bit harder to make ;p
175-
* We need to use jumptable for this
176-
*/
213+
// Loops a bit harder to make ;p
214+
// We need to use jumptable for this
177215
// [
178216
case TOKEN_LOOP :
179-
// close other bytecodes
180-
closecode(x, oldcode, codedata);
181-
oldcode = BC_JPZ;
182-
codedata = 0;
183-
// jump calculations
184-
if (jmptbl[jmptblpos][0]) jmptblpos++;
185-
jmptbl[jmptblpos][0] = x->instp; // add start of the loop to the jumptable
186-
// instruction body will be rewrited later...
187-
pushbc2(x, BC_JPZ, 0);
188-
189-
if (jmptbl[jmptblpos][1]) { // finalized pair
190-
if (finallize_jumppair(x, jmptbl[jmptblpos][0], jmptbl[jmptblpos][1]) != ERR_OK) {
191-
compiler_message(x, "Can't finnalize jump pair! Internal error!");
192-
status = ERR_ERR; goto end_it;
193-
}
194-
jmptbl[jmptblpos][0] = 0; jmptbl[jmptblpos][1] = 0; // cleanup :p
195-
uint16_t npos = jmptblpos + 1;
196-
if (jmptbl[npos][0] || jmptbl[npos][1]) jmptblpos = npos; // important
197-
}
217+
newcode(x, BC_JPZ); // close other bytecodes
218+
addjumpstart(x); // save code position to the jump table
198219
break;
199220
// ]
200221
case TOKEN_POOL :
201-
// close other bytecodes
202-
closecode(x, oldcode, codedata);
203-
oldcode = BC_JPNZ;
204-
codedata = 0;
205-
// jump calculations
206-
if (jmptbl[jmptblpos][1]) jmptblpos--;
207-
jmptbl[jmptblpos][1] = x->instp; // add end of the loop to the jumptable
222+
newcode(x, BC_JPNZ); // close other bytecodes
223+
addjumpend(x); // save code position to the jumptable
208224
// instruction body will be rewrited later...
209225
pushbc2(x, BC_JPNZ, 0);
210226

211-
if (jmptbl[jmptblpos][0]) { // finalized pair
212-
if (finallize_jumppair(x, jmptbl[jmptblpos][0], jmptbl[jmptblpos][1]) != ERR_OK) {
213-
compiler_message(x, "Can't finnalize jump pair! Internal error!");
214-
status = ERR_ERR; goto end_it;
215-
}
216-
jmptbl[jmptblpos][0] = 0; jmptbl[jmptblpos][1] = 0; // cleanup :p
217-
uint16_t npos = jmptblpos - 1;
218-
if (jmptbl[npos][0] || jmptbl[npos][1]) jmptblpos = npos; // important
219-
}
220227
break;
221228
default:
222229
compiler_message(x, "impossible!");
223230
status = ERR_ERR;
224231
goto end_it;
225232
break;
226-
};NEXT_CHAR();} else if (ch == '\n' || ch == '\r') {
227-
NEXT_CHAR();
233+
}} else if (ch == '\n' || ch == '\r') {
228234
x->line++;
229-
} else NEXT_CHAR();
235+
};
230236
};
231-
closecode(x, oldcode, codedata);
237+
newcode(x, 128);
232238

233-
if (jmptblpos != 0) {
239+
if (x->jmptblpos != 0) {
234240
compiler_message(x, "Code is not balanced!");
235-
fprintf(stderr, "[compiler] : unused branches count %i!\n", jmptblpos);
241+
fprintf(stderr, "[compiler] : unused branches count %i!\n", x->jmptblpos);
236242
status = ERR_ERR;
237243
goto end_it;
238244
}

0 commit comments

Comments
 (0)