/*****************************/
/*   bf Interpreter          */
/*   Made by: smiley         */
/*****************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

#define DEBUG 0   //set to 1 to print "Hello World!" as a test

typedef unsigned char byte;

/*Operators*/

#define INCREMENT_PTR '>'
#define	DECREMENT_PTR '<'
#define	INCREMENT_VAL '+'
#define	DECREMENT_VAL '-'
#define	OUTPUT_VAL    '.'
#define	INPUT_VAL     ','
#define	START_LOOP    '['
#define	END_LOOP      ']'



/*Globals variables related to the interpreter*/
#define MAX_NUMBER_CELLS 30000 //Each cells are a single byte
#define MAX_CODE_SIZE 100000 //Max size of the source code, that should be enough

byte Cells[MAX_NUMBER_CELLS]; //We will have to null them

int main(int argc, char** argv){

	char src[MAX_CODE_SIZE];
	int curCell = 0; //Current Cell
	int flen = 0;    //File Length


	/*ZeroMemory*/
	memset(src, 0, MAX_CODE_SIZE);
	memset(Cells, 0, MAX_NUMBER_CELLS);

	if (!DEBUG){ //This variable is set manually at the beginning of the code
		if (argc < 2){
			printf("Usage:Brainfuck.exe \"Input file\"\nExample: Brainfuck.exe \"C:\\test.txt\"\n\n");
			getchar();
			return -1;
		}
		/*Get Source code*/
		FILE* in = fopen(argv[1], "r");
		if (in != NULL){
			fseek(in, 0, SEEK_END);
			flen = ftell(in);
			if (flen > MAX_CODE_SIZE){
				fclose(in);
				printf("File is too big! Max length: %i\n", MAX_CODE_SIZE);
				getchar();
				return -1;
			}
			fseek(in, 0, SEEK_SET);
			fread(src, flen, 1, in);
			fclose(in);

		}
		else{
			printf("File cannot be read! Try to move it to your desktop?\n");
			getchar();
			return -1;
		}

	}
	else{
		/*This debug string will print "Hello World!" */
		strcpy(src, "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.");
	}



	int srcLen = strlen(src);

	/*Iterate through every char*/
	for (int i = 0; i < srcLen; i++){

		switch (src[i]){

		case INCREMENT_PTR:
			if (curCell == MAX_NUMBER_CELLS - 1) curCell = 0;
			else curCell++;
			break;

		case DECREMENT_PTR:
			if (curCell == 0) curCell = MAX_NUMBER_CELLS - 1;
			else curCell--;
			break;

		case INCREMENT_VAL:
			Cells[curCell]++;
			break;

		case DECREMENT_VAL:
			Cells[curCell]--;
			break;

		case OUTPUT_VAL:
			printf("%c", Cells[curCell]);
			break;

		case INPUT_VAL:
			printf("\nInput: ");
			Cells[curCell] = _getch();
			printf("\n");
			break;


		/*Gotta test*/
		case START_LOOP:
			/*incase we start a loop with 0 as a value*/
			if (Cells[curCell] == 0){
				int occurences = 0;  //number of loops after it
				for (int a = i+1; a > srcLen; a++){
					if (src[a] == START_LOOP){
						occurences++; //we found another loop, we will have to skip his 'START_LOOP'
					}
					else if (src[a] == END_LOOP){
						if (occurences > 0){ occurences--; } //we have skipped a loop
						else{ break; } //gotta take a break
					}

				}
			}
			break;


		case END_LOOP:
			if (Cells[curCell] != 0){
				int occurences = 0;  //number of loops before it
				for (int a = i-1; a > 0; a--){
					if (src[a] == START_LOOP){
						if (occurences > 0){ occurences--; }
						else{ i = a - 1; break; }
					}
					else if (src[a] == END_LOOP){
						occurences++;
					}
					if (a == 1){ return -1; }
				}
			}
			break;


		}

	}

	printf("\n\n\n\n****----DONE----****");
	getchar(); getchar();
	return 0;
}