Files
BrainFuck/interpreter.c
2024-09-12 16:48:58 +02:00

220 lines
5.2 KiB
C

/*
* Created by Lionel Sambuc on 03.dec.2009.
* Copyright 2009-2010. All rights reserved.
*
*/
/**************************************************************************
* Brainfuck and derivatives interpreter *
**************************************************************************/
#include <stdio.h>
#include "bf.h"
#include "Heu.h"
#include "interpreter.h"
/* Program Input */
static char *bfi_program;
static int bfi_token_start;
static size_t bfi_length;
/* Program tokenizer functions */
static int (*bfi_read_previous_token)(char const *program, int *token_start, size_t length);
static int (*bfi_read_next_token)(char const *program, int *token_start, size_t length);
static void (*bfi_lexer_init)(void);
/* Machine hardware */
static char bfi_memory[NB_MEMORY_WORDS];
/* Reading/Writing Head, which points to a memory word */
static char *bfi_head;
/**************************************************************************
* PRIVATE INTERFACE *
**************************************************************************/
/**
* Prints the error message and dump the interpreter memory before returning
* the given error code.
*/
static int bfi_execution_error(char* reason, int code)
{
int i;
printf( COLOR_RST "\n" COLOR_ERR "%s" COLOR_MSG "\n", reason);
printf( COLOR_RST "At position : %s" COLOR_MSG "\n", (bfi_program + bfi_token_start));
for(i = 0; i < MEMORY_DUMP_SIZE; i++)
printf("%s%02x", i%4==0? (i%16==0?"\n": "::"): " ", bfi_memory[i]);
printf(COLOR_RST "\n");
return code;
}
/**
* Jump to the associated closing bracket and returns the next instruction
* to be executed.
* Hypotheses: bfi_token_start points just after the opening bracket.
*/
static void bfi_skip_forward(void)
{
int context = 0;
int next = -1;
while((next = bfi_read_next_token(bfi_program, &bfi_token_start, bfi_length)) != EOT)
{
switch(next)
{ /* Opening bracket */
case JZF: context++;
break;
/* Closing bracket */
case JNB: context--;
if(context == 0)
return;
break;
/* End of the program or unknown instruction. */
case EOT:
case SOT:
case UKW:
return;
}
}
}
/**
* Jump to the associated opening bracket and returns the next instruction
* to be executed.
* Hypotheses: bfi_token_start points just before the closing bracket.
*/
static void bfi_skip_backward(void)
{
int context = 0;
int prev = -1;
while((prev = bfi_read_previous_token(bfi_program, &bfi_token_start, bfi_length)) != SOT)
{
switch(prev)
{ /* Opening bracket */
case JZF: context--;
if(context == 0)
return;
break;
/* Closing bracket */
case JNB: context++;
break;
/* End of the program or unknown instruction. */
case EOT:
case SOT:
case UKW:
return;
}
}
}
/**
* This function initializes the lexer associated to the given brainfuck
* dialect. It also zero the whole memory band and reset the head to the
* first word.
* it returns 0 on success or -1 if the dialect is unknown.
*/
static int bfi_initialize(enum bfi_dialects dialect)
{
int i;
/* Reset memory state. */
for(i = 0; i < NB_MEMORY_WORDS; i++)
bfi_memory[i] = 0;
bfi_head = bfi_memory;
/* Initialize the parser functions. */
switch(dialect)
{
case BRAINFUCK:
bfi_lexer_init = brainfuck_lexer_init;
bfi_read_previous_token = brainfuck_read_previous_token;
bfi_read_next_token = brainfuck_read_next_token;
break;
case HEU:
bfi_lexer_init = heu_lexer_init;
bfi_read_previous_token = heu_read_previous_token;
bfi_read_next_token = heu_read_next_token;
break;
default:
return -1;
break;
}
/* Initialize the chosen lexer. */
bfi_lexer_init();
return 0;
}
/**************************************************************************
* PUBLIC INTERFACE *
**************************************************************************/
int bfi_execute(char* program, size_t length, enum bfi_dialects dialect, char print_num)
{
int next = EOT;
bfi_program = program;
bfi_length = length;
if(bfi_initialize(dialect) != 0)
return -UNKNOWN_DIALECT;
while((next = bfi_read_next_token(bfi_program, &bfi_token_start, bfi_length)) != EOT && next != SOT)
{
switch(next)
{
case MVL:
--bfi_head;
if(bfi_head < bfi_memory)
return bfi_execution_error("HEAD Got past the start of memory!", -INVALID_MEMORY_ADDRESS);
break;
case MVR:
++bfi_head;
if(bfi_head >= bfi_memory + NB_MEMORY_WORDS)
return bfi_execution_error("HEAD Got past the end of memory!", -INVALID_MEMORY_ADDRESS);
break;
case INC:
++*bfi_head;
break;
case DEC:
--*bfi_head;
break;
case PUT:
if(print_num != 0)
printf("%i", *bfi_head);
else
putchar(*bfi_head);
break;
case GET:
*bfi_head = getchar();
break;
case JZF:
if(*bfi_head == 0)
bfi_skip_forward();
break;
case JNB:
if(*bfi_head != 0)
bfi_skip_backward();
break;
case UKW:
default:
return bfi_execution_error("Unknown keyword !", -INVALID_OPERATION);
}
}
bfi_execution_error("End of Program", *bfi_head);
/* Ensure there is an end of line */
printf("\n");
return (int)*bfi_head;
}