/* GWAAAAAAAH - Antoine Pultier - 2009
 * 
 * GWAAAAAAAH est un langage de programmation très similaire au Brainfuck,
 * à la différence qu'il peut être utilisé par des lapins crétins,
 * comme le Ook avec les orang-outants.
 * 
 * Vous pouvez faire ce que vous voulez avec ce programme (le modifier,
 * le vendre, l'utiliser pour coder un OS, faire fortune avec, etc…).
 * Cependant, on ne vous garantie rien, et vous devez aimer les lapins.
 * Ce programme est donc libre, mais pas totalement.
*/

#include <stdio.h>	// LAPIN
#include <stdlib.h>	// Idem
#include <errno.h>	// void perror(const char *chaine);

// La syntaxe lapin, c'est beau :-)

#ifndef	_MODE_BF_
	#define	LAPIN_PLUS	'G'
	#define	LAPIN_MOINS	'W'
	#define LAPIN_INCR	'A'
	#define	LAPIN_DECR	'O'
	#define	LAPIN_PUT	'H'
	#define	LAPIN_GET	'Z'
	#define	LAPIN_LOOP	'R'
	#define	LAPIN_END	'M'
#else
	#define	LAPIN_PLUS	'>'
	#define	LAPIN_MOINS	'<'
	#define LAPIN_INCR	'+'
	#define	LAPIN_DECR	'-'
	#define	LAPIN_PUT	'.'
	#define	LAPIN_GET	','
	#define	LAPIN_LOOP	'['
	#define	LAPIN_END	']'
#endif


// 128 emplacements car on est radin
#define LIMITE_RAM	128

// 16 boucles imbriquées car après, c'est dangereux pour la santé
#define LIMITE_BOUCLES	16

// Tout dans une fonction quand on est flemmard
int main(int argc, char * argv[])
{
	// Si l'on a pas de fichier
	if (argc == 1)
	{
		errno = EINVAL;
		perror("GGAAAAA !");
		return EXIT_FAILURE;
	}
	
	FILE * fichier = NULL;

	fichier = fopen(argv[1], "r");
	
	if (!fichier)
	{
		perror("RAARRRRRR");
		return EXIT_FAILURE;
	}
	
	// Un tout petit buffer :-)
	char b;

	// La mémoire, calloc car j'étais parti pour agrandir la mémoire si besoin
	int * ram = calloc(LIMITE_RAM, sizeof(int));

	// La pile pour les boucles
	long * pile = malloc(LIMITE_BOUCLES * sizeof(long));
	int ptr_pile = -1;

	// Le pointeur
	int * ptr = ram;

	do
	{
		b = getc(fichier); // Il dit quoi le monsieur ?

		// C'est beau <3
		switch (b)
		{
			case LAPIN_PLUS:
				++ptr;
				break;

			case LAPIN_MOINS:
				{
					--ptr;

					// Si on a un peut trop descendu le pointeur
					if (ptr==ram-1)
					{
						errno = EFAULT;
						perror("\n*___--- GAAAAAAA! ---___*");
						ptr = ram;
					}

				}
				break;

			case LAPIN_INCR:
				++(*ptr);
				break;

			case LAPIN_DECR:
				--(*ptr);
				break;

			case LAPIN_PUT:
				putchar(*ptr);
				break;

			case LAPIN_GET:
				{
					(*ptr) = getchar();
					if (*ptr == EOF) return EXIT_SUCCESS;
				}
				break;

			case LAPIN_LOOP:
				{

					// Si ça vaut le coup de se lancer dans tout ça
					if (*ptr)
					{
						++ptr_pile;

						// On sauvegarde la position dans le fichier
						*(pile+ptr_pile) = ftell(fichier);

					// Maintenant, il faut finir la boucle :/
					} else {
						--ptr_pile;

						int sb = 0; // Le compteur de sous-boucles
						char mb;

						for(;mb != EOF;)
						{
							mb = getc(fichier);

							// Si on a une nouvelle sous-boucle
							if (mb == LAPIN_LOOP)
								++sb;

							// Si une boucle se finie
							else if (mb == LAPIN_END)
								// Si c'est la fin :-)
							 	if (sb == 0)
									break;
								else
									--sb;	
						}
					}

				}
				break;

			case LAPIN_END:
				{
					// Si il faut repartir pour un tour
					if (*ptr)
					{
						// On se remet juste après la déclaration de la boucle
						fseek(fichier, *(pile+ptr_pile), SEEK_SET);
					} else {
						--ptr_pile;
					}
				}
				break;
		}

	} while( b != EOF );
	
	free(ram);
	free(pile);
			
	fclose(fichier);

	return EXIT_SUCCESS; 	// Faut être sympa avec le shell
}


