#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
	Auteur: Benoit Papillault
	Creation: Mercredi 1er Octobre 1997
	Derniere modification: Vendredi 3 Octobre 1997

	Mise en oeuvre d'expression simple.
	Cette version constitue une bibliotheque de reference.

	"rexp" = Register EXPression.

	10/01/1998: remaniement complet pour utiliser une representation
	sous forme de quadruplets avec des variables temporaires.
	Cette representation est explique dans COMPILATEURS: Principes,
	techniques et outils par Alfred Aho, Ravi Sethi et Jeffrey Ullman
	1989, InterEditions pp 520-521

*/

#include "expression.h"

LISTE_c(expression,struct quadruplet);

struct operande operande_constante(int value)
{
	struct operande result;

	result.type = CONSTANTE;
	result.value = value;

	return result;
}

struct operande operande_registre(int reg)
{
	struct operande result;

	result.type = REGISTRE;
	result.value = reg;

	return result;
}

struct operande operande_temporaire()
{
	static n_tmp = 0;
	struct operande result;

	result.type = TEMPORAIRE;
	result.value = ++n_tmp;

	return result;
}

void operande_print(const struct operande *o)
{
	switch (o->type)
	{
	case CONSTANTE:
		printf("%d",o->value);
		break;
	case REGISTRE:
		printf("reg%d",o->value);
		break;
	case TEMPORAIRE:
		printf("tmp%d",o->value);
		break;
	case VAR_LOCALE:
		printf("locale%d",o->value);
		break;
	case VAR_GLOBALE:
		printf("globale%d",o->value);
		break;
	}
}

void quadruplet_print(const struct quadruplet *q)
{


	switch (q->op)
	{
	case OP_OR:
		operande_print(&q->resultat);
		printf("=");
		operande_print(&q->arg1);
		printf("|");
		operande_print(&q->arg2);
		break;
	case OP_ADD:
		operande_print(&q->resultat);
		printf("=");
		operande_print(&q->arg1);
		printf("+");
		operande_print(&q->arg2);
		break;
	case OP_SUB:
		operande_print(&q->resultat);
		printf("=");
		operande_print(&q->arg1);
		printf("-");
		operande_print(&q->arg2);
		break;
	case OP_EGAL:
		operande_print(&q->resultat);
		printf("=");
		operande_print(&q->arg1);
		break;
	case OP_BRANCH:
		printf("if ");
		operande_print(&q->arg2);
		switch (q->arg1.value)
		{
		case EGAL:	printf(" ==");	break;
		case DIFFERENT:	printf(" !=");	break;
		case INFERIEUR:	printf(" <");	break;
		case INFERIEUR_OU_EGAL:	printf(" <=");	break;
		case SUPERIEUR:	printf(" >");	break;
		case SUPERIEUR_OU_EGAL:	printf(" >=");	break;
		default:	printf(" ?");	break;
		}
		printf(" goto ");
		operande_print(&q->resultat);
		break;
	case OP_CALL:
		printf("call ");
		operande_print(&q->resultat);
		break;
	case OP_CALLS:
		printf("call %s",(char *)q->resultat.value);
		break;
	case OP_LOAD:
		operande_print(&q->resultat);
		printf("= load [");
		operande_print(&q->arg1);
		printf(":");
		operande_print(&q->arg2);
		printf("]");
		break;
	case OP_STORE:
		printf("store [");
		operande_print(&q->arg1);
		printf(":");
		operande_print(&q->arg2);
		printf("]");
		printf("=");
		operande_print(&q->resultat);
		break;
	case OP_CMP:
		operande_print(&q->resultat);
		printf("=");
		operande_print(&q->arg1);
		printf("?");
		operande_print(&q->arg2);
		break;
	case OP_RET:
		printf("ret");
		break;
	case OP_JUMP:
		printf("jump ");
		operande_print(&q->resultat);
		break;
	case OP_NOP:
		printf("nop");
		break;
	default:
		printf("quadruplet.op incorrect (%d)\n",q->op);
		break;
	}
}

void expression_print(const struct expression *e)
{
	int i;

	for (i=0;i<e->nb;i++)
		quadruplet_print(&e->liste[i]);
}
