minimal syntax checker and simulator for IOTM (brainfuck-like language)
#ifndef _H_BRAINFUCK
#define _H_BRAINFUCK
#define MEMORY_SIZE 4096
#define CODE_LEN_LIMIT 65536
#endif // _H_BRAINFUCK
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "brainfuck.h"
#define eprintf(format, ...) \
fprintf(stderr, "%s: " format, __func__,## __VA_ARGS__)
// expand our syntax sugar (similar to run-length encoding) to traditional
// brainfuck program; return NULL if the code exceeds the limit
//
// in order to know how long it will be, the expansion will be done in two
// passes: decide the length the first pass, allocate a space to be filled,
// and fill it in the second pass.
char* bfexpand(char* code) {
char* p = code;
int count = 0;
// first pass
int actlen = 0;
while (*p) {
if (isdigit(*p)) {
if (count == 0 && *p == '0') {
eprintf("expected positive integer, got 0\n");
return NULL;
}
count = count * 10 + *p - '0';
} else {
if (count != 0) {
actlen += count;
count = 0;
} else actlen++;
}
p++;
}
// reject
if (count != 0) {
eprintf("stray number after code\n");
return NULL;
}
printf("expanded len = %d\n", actlen);
if (actlen > CODE_LEN_LIMIT) {
eprintf("code too long\n");
return NULL;
}
// second pass
p = code;
char* ret = (char*) malloc(actlen + 1);
int filled = 0;
while (*p) {
if (isdigit(*p)) {
count = count * 10 + *p - '0';
} else {
if (count != 0) {
while (--count) {
ret[filled++] = *p;
}
}
ret[filled++] = *p;
}
p++;
}
ret[actlen] = '\0';
return ret;
}
// run on some brainfuck code
// return 0 if success,
// 1 if runtime error,
// 2 if tick limit exceeded
int brainfuck(char* code, const char* input, char** output,
size_t* output_sz, size_t* tick_lim) {
char memory[MEMORY_SIZE] = {};
int memptr = 0;
int stack[32]; // XXX: what is the stack size?
int stsize = 0;
int jmptable[CODE_LEN_LIMIT]; // XXX: can be improved by using map
size_t tick_cnt = 0;
int do_tick_check = tick_lim && *tick_lim > 0;
// syntax checking; build jump table
int pos = 0;
while (code[pos]) {
if (code[pos] == '[') {
stack[stsize++] = pos;
} else if (code[pos] == ']') {
if (stsize == 0) {
// stack underflow owo
eprintf("unexpected ] at position %d\n", pos + 1);
return 1;
}
// fill it to jump table; bi-directional
stsize--;
jmptable[pos] = stack[stsize];
jmptable[stack[stsize]] = pos;
} else if (strchr(".,<>+-", code[pos]) == NULL) {
// the character is not in allowing list of characters
eprintf("unallowed character '%c' at position %d\n",
code[pos], pos + 1);
return 1;
}
pos++;
}
if (stsize > 0) {
printf("expected ] at end\n");
return 1;
}
// syntax checked; start execution
int len = pos;
size_t output_len = 0;
pos = 0;
while (pos != len) {
char c = code[pos];
switch (c) {
case '<': // move left
if (memptr == 0) {
eprintf("attempting to move left at the left end of memory"
" at position %d\n", pos + 1);
}
memptr--;
break;
case '>': // move right
if (memptr == MEMORY_SIZE - 1) {
eprintf("attempting to move right at the right end of memory"
" at position %d\n", pos + 1);
}
memptr++;
break;
case '+': // increment
memory[memptr]++; tick_cnt++; break;
case '-': // decrement
memory[memptr]--; tick_cnt++; break;
case ',': // read from input; no-op if exhausted
if (*input) {
memory[memptr] = *input;
input++;
}
tick_cnt++; break;
case '.': // write to output
if (memory[memptr] == 0) {
eprintf("attempting to print zero character to output"
" at position %d\n", pos + 1);
}
(*output)[output_len++] = memory[memptr];
// if output is longer than expected, the space is relocated
if (output_len == *output_sz) {
*output_sz *= 2;
// printf("relocating memory to expand output to"
// " size %zd\n", *output_sz);
*output = (char*) realloc(*output, *output_sz);
}
tick_cnt++; break;
case '[': // loop construct left
if (memory[memptr] == 0) {
pos = jmptable[pos];
}
tick_cnt++; break;
case ']': // loop construct right
if (memory[memptr] != 0) {
pos = jmptable[pos];
}
tick_cnt++; break;
}
// check tick limit
if (do_tick_check && tick_cnt >= *tick_lim) {
eprintf("tick limit exceeded\n");
return 2;
}
pos++;
}
// zero-terminate the output string
(*output)[output_len] = '\0';
if (tick_lim) {
*tick_lim = tick_cnt;
}
return 0;
}
int main() {
char* line = NULL;
size_t n = 0;
ssize_t len = 0;
while ((len = getline(&line, &n, stdin)) >= 0) {
if (len > 0 && line[len - 1] == '\n')
line[len - 1] = '\0';
printf("code: '%s'\n", line);
char* expanded = bfexpand(line);
if (!expanded) {
printf("syntax error\n");
} else {
printf("expanded: '%s'\n", expanded);
}
if (!expanded) continue;
const char* input = "100 ";
size_t output_sz = 4096;
size_t tick = 0;
char* output_ptr = (char*) malloc(output_sz);
int result = brainfuck(expanded, input,
&output_ptr, &output_sz, &tick);
if (result == 0) {
printf("success\n");
printf("output buffer len = %zd\n", output_sz);
printf("output: [%s]\n", output_ptr);
printf("tick used: [%zd]\n", tick);
} else if (result == 1) {
printf("runtime error\n");
} else if (result == 2) {
printf("tick limit (%zd) exceeded\n", tick);
}
free(output_ptr);
free(expanded);
}
free(line);
}
#include <stdio.h>
#include <string.h>
int main() {
char c;
while ((c = getchar()) > 0) {
if (strchr("<>[],.+-", c) != NULL)
putchar(c);
}
}
#include <stdio.h>
int main() {
char c, prev = '\0';
int count = 1;
while (c = getchar(), c > 0) {
if (c == prev) {
count++;
} else if (prev) {
if (count == 1) {
putchar(prev);
} else {
printf("%d%c", count, prev);
}
count = 1;
}
if (c == '\n') {
puts("");
prev = '\0';
continue;
}
prev = c;
}
}
ECHO = /bin/echo -e
CC = gcc
CSRCS = $(wildcard *.c)
%: %.c
@$(ECHO) "compiling $< -> $@"
@$(CC) -std=c99 -O2 -o $@ $<
all: bfcomp bfconcat brainfuck
clean:
rm -f bfcomp bfconcat brainfuck
>++++++++[<++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++.[-]>++++++++++[<++++++++++>-]<+++++++++.[-]>++++++++++[<++++++++++>-]<+.[-]>++++++++++[<++++++++++>-]<+++++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++.[-]>+++++++[<+++++++>-]<+++++++++.[-]>+++++[<+++++>-]<+++++++.[-]+[->,--------------------------------[<+>---------------->[>+>+<<-]>>[<<+>>-]<>>>+++++++++[<<<[>+>+<<-]>>[<<+>>-]<[<<+>>-]>>-]<<<[-]<<[>+<-]]<]>>[<<+>>-]<<>+<-[>+[>+>+<<-]>>[<<+>>-]<>+<-->>>>>>>>+<<<<<<<<[>+<-<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<>[>>+>+<<<-]>>>[<<<+>>>-]<<<<>>>[>+>+<<-]>>[<<+>>-]<<<[>>>>>+<<<[>+>+<<-]>>[<<+>>-]<[>>[-]<<-]>>[<<<<[>+>+<<-]>>[<<+>>-]<>>>-]<<<-<<-]+>>[<<[-]>>-]<<>[-]<[>>>>>>[-]<<<<<<-]<<>>[-]>[-]<<<]>>>>>>>>[-<<<<<<<[-]<<[>>+>+<<<-]>>>[<<<+>>>-]<<<>>[>+<-]>[[>+>+<<-]>>[<<+>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>-]<<-<-]+++++++++>[<->-]<[>+<-]<[>+<-]<[>+<-]>>>[<<<+>>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]>>>>[<<<<+>>>>-]<<<<>[-]<<+>]<[[>+<-]+++++++[<+++++++>-]<-><.[-]>>[<<+>>-]<<-]>++++[<++++++++>-]<.[-]>>>>>>>]<<<<<<<<>[-]<[-]<<-]
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.