/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#define MEMORY_SIZE 30000
#define MAX_PROGRAM_SIZE 4096
#define STACK_SIZE 512
#define STACK_PUSH(x) (stack[sp++] = x)
#define STACK_POP() (sp--)
#define STACK_EMPTY() (sp == 0)
#define STACK_FULL() (sp == STACK_SIZE)
#define STACK_PEEK() (stack[sp-1])
void die(const char *msg) { perror(msg); exit(EXIT_FAILURE); }
void usage (char *argv[]) { printf("usage: %s script\n", argv[0]); exit(EXIT_SUCCESS); }
uint8_t memory[MEMORY_SIZE] = {0};
uint8_t program[MAX_PROGRAM_SIZE] = {0};
uint32_t stack[STACK_SIZE] = {0};
uint32_t sp = 0; // stack pointer
char *bf_file;
int bf_fd;
void
load(void)
{
size_t i = 0;
char c;
while ((read(bf_fd, &c, 1)) > 0)
{
switch (c)
{
case '>':
case '<':
case '+':
case '-':
case '.':
case ',':
case '[':
case ']':
program[i] = c;
i++;
break;
default: break;
}
}
}
ssize_t
find_closing_bracket(size_t pos)
{
/*
* find closing ] for opening [ at location pos in program, return its position
* -1 on not found
*
* count each opening [ and closing ] until the numbers match, that will be our closing bracket
*/
ssize_t close_pos = -1;
size_t open_count = 0;
size_t close_count = 0;
if (pos > MAX_PROGRAM_SIZE)
{
return -1;
}
if (program[pos] != '[')
{
fprintf(stderr, "instruction not [ at %zu\n", pos);
exit(EXIT_FAILURE);
}
uint8_t c;
while ((c = program[pos]) != 0)
{
switch (c)
{
case '[':
open_count++;
break;
case ']':
close_count++;
break;
default: break;
}
if (open_count == close_count)
{
close_pos = pos;
break;
}
pos++;
if (pos > MAX_PROGRAM_SIZE)
break;
}
assert(close_pos != -1);
return close_pos;
}
void
run(void)
{
int pc = 0; // program counter
size_t datap = 0; // data pointer into memory
uint8_t i; // current instruction
while ((i = program[pc]) != 0)
{
/*
size_t in;
int x = 0;
printf("PC = %d\n", pc);
while ((in = program[x]) != 0)
{
if (x == pc)
putchar('A');
putchar(in);
if (x == pc)
putchar('A');
x++;
}
getchar();
*/
switch (i)
{
case '>':
datap++;
pc++;
break;
case '<':
datap--;
pc++;
break;
case '+':
memory[datap]++;
pc++;
break;
case '-':memory[datap]--;
pc++;
break;
case '.':
putchar(memory[datap]);
fflush(stdout);
pc++;
break;
case ',':
memory[datap] = (char)getchar();
pc++;
break;
case '[':
{
if (memory[datap] == 0)
{
uint32_t end = find_closing_bracket(pc);
pc = end+1;
}
else
{
STACK_PUSH(pc+1);
pc++;
}
break;
}
case ']':
if (memory[datap] != 0)
{
pc = STACK_PEEK();
}
else
{
STACK_POP();
pc++;
}
break;
default: die("unknown instruction"); break;
}
}
}
int
main(int argc, char *argv[])
{
if (argc < 2)
usage(argv);
bf_file = argv[1];
if ((bf_fd = open(bf_file, O_RDONLY)) < 0)
die("open");
load();
run();
close(bf_fd);
return EXIT_SUCCESS;
}