// ruri - ruri language compiler
// Copyright 2000 Tom Rothamel <tom-ruri@onegeek.org>
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  

// This is a program that generates another program. As an exemption,
// the output file does not need to be placed under the GPL, provided
// that the following paragraph is placed in the generated output. Please
// note that this is not an authorization to modify this program to cause
// it to output more of itself in order to circumvent my copyright.
//
// 	This program contains code Copyright 2000 Tom Rothamel.
//	It is provided without warranty, and may be redistributed 
//	and used in modified or unmodified form, provided this 
//	copyright notice is retained in the source code.

#include "parse.h"

int cnum_seq = 0;

int cnum() {
	return cnum_seq++;
}

bool Condition::alwaystrue() {
	return false;
}

bool Condition::alwaysfalse() {
	return false;
}

void Condition::settrue(int n) {
	true_num = n;
}

void Condition::setfalse(int n) {
	false_num = n;
}

bool Condition::codeinverse(int, int) {
	return false;
}

Condition::Condition() {
}


// CTrue /////////////////////////////////////////////////////////////////////

bool CTrue::alwaystrue() {
	return true;
}

void CTrue::code() {
	iprint("GOTO", "cond", true_num, "true");	
}

bool CTrue::codeinverse(int tn, int fn) {
	iprint("GOTO", "cond", fn, "false");
	return true;
}

string CTrue::text() {
	return "true";
}

// CFalse ////////////////////////////////////////////////////////////////////

bool CFalse::alwaysfalse() {
	return true;
}

void CFalse::code() {
	iprint("GOTO", "cond", false_num, "false");	
}

bool CFalse::codeinverse(int tn, int fn) {
	iprint("GOTO", "cond", tn, "true");
	return true;
}

string CFalse::text() {
	return "false";
}

// CLt ///////////////////////////////////////////////////////////////////////

string CLt::text() {
	return e0->text() + " < " + e1->text();
}
	
void CLt::code() {
	e0->optimize(NULL);
	e0->gencode();
	e1->optimize(NULL);
	e1->gencode();
	iprint("ISUB");
	iprint("IFLT", "cond", true_num, "true");
	iprint("GOTO", "cond", false_num, "false");
}

bool CLt::codeinverse(int tn, int fn) {
	e0->optimize(NULL);
	e0->gencode();
	e1->optimize(NULL);
	e1->gencode();
	iprint("ISUB");
	iprint("IFLT", "cond", fn, "false");
	iprint("GOTO", "cond", tn, "true");

	return true;	
}
	
CLt::CLt(Expr *ie0, Expr *ie1) {
	e0 = ie0;
	e1 = ie1;
}

CLt::~CLt() {
	delete e0;
	delete e1;
}

// CGt ///////////////////////////////////////////////////////////////////////

string CGt::text() {
	return e0->text() + " > " + e1->text();
}
	
void CGt::code() {
	e1->optimize(NULL);
	e1->gencode();
	e0->optimize(NULL);
	e0->gencode();
	iprint("ISUB");
	iprint("IFLT", "cond", true_num, "true");
	iprint("GOTO", "cond", false_num, "false");
}

bool CGt::codeinverse(int tn, int fn) {
	e1->optimize(NULL);
	e1->gencode();
	e0->optimize(NULL);
	e0->gencode();
	iprint("ISUB");
	iprint("IFLT", "cond", fn, "false");
	iprint("GOTO", "cond", tn, "true");

	return true;
}

CGt::CGt(Expr *ie0, Expr *ie1) {
	e0 = ie0;
	e1 = ie1;
}

CGt::~CGt() {
	delete e0;
	delete e1;
}

// CEq ///////////////////////////////////////////////////////////////////////

string CEq::text() {
	return e0->text() + " == " + e1->text();
}
	
void CEq::code() {
	e1->optimize(NULL);
	e1->gencode();
	e0->optimize(NULL);
	e0->gencode();
	iprint("IF_ICMPEQ", "cond", true_num, "true");
	iprint("GOTO", "cond", false_num, "false");
}

bool CEq::codeinverse(int tn, int fn) {
	e1->optimize(NULL);
	e1->gencode();
	e0->optimize(NULL);
	e0->gencode();
	iprint("IF_ICMPEQ", "cond", fn, "false");
	iprint("GOTO", "cond", tn, "true");
	return true;
}

CEq::CEq(Expr *ie0, Expr *ie1) {
	e0 = ie0;
	e1 = ie1;
}

CEq::~CEq() {
	delete e0;
	delete e1;
}

// CAnd //////////////////////////////////////////////////////////////////////

void CAnd::code() {
	int n = cnum();

	c1->settrue(n);
	c1->setfalse(false_num);
	c2->settrue(true_num);
	c2->setfalse(false_num);

	c1->code();
	ilabel("cond", n, "true");
	c2->code();
}

string CAnd::text() {
	return c1->text() + " && " + c2->text();
}

CAnd::CAnd(Condition *ic1, Condition *ic2) {
	c1 = ic1;
	c2 = ic2;
}

CAnd::~CAnd() {
	delete c1;
	delete c2;
}
		
// COr ///////////////////////////////////////////////////////////////////////

void COr::code() {
	int n = cnum();

	c1->settrue(true_num);
	c1->setfalse(n);
	c2->settrue(true_num);
	c2->setfalse(false_num);

	c1->code();
	ilabel("cond", n, "false");
	c2->code();
}

string COr::text() {
	return c1->text() + " || " + c2->text();
}

COr::COr(Condition *ic1, Condition *ic2) {
	c1 = ic1;
	c2 = ic2;
}

COr::~COr() {
	delete c1;
	delete c2;
}

// CNot //////////////////////////////////////////////////////////////////////

void CNot::code() {

	if (cond->codeinverse(true_num, false_num)) return;

	int n = cnum();

	cond->settrue(n);
	cond->setfalse(n);
	cond->code();

	ilabel("cond", n, "true");
	iprint("GOTO", "cond", false_num, "false");
	ilabel("cond", n, "false");
	iprint("GOTO", "cond", true_num, "true");	
}

string CNot::text() {
	return "!(" + cond->text() + ")";
}

bool CNot::alwaystrue() {
	return cond->alwaysfalse();
}

bool CNot::alwaysfalse() {
	return cond->alwaystrue();
}

CNot::CNot(Condition *c) {
	cond = c;
}

CNot::~CNot() {
	delete cond;
}

// CExpr /////////////////////////////////////////////////////////////////////

void CExpr::code() {
	e->gencode();
	iprint("IFEQ", "cond", false_num, "false");
	iprint("GOTO", "cond", true_num, "true");
}

bool CExpr::codeinverse(int tn, int fn) {
	e->gencode();
	iprint("IFEQ", "cond", tn, "true");
	iprint("GOTO", "cond", fn, "false");
	return true;
}

string CExpr::text() {
	return e->text();
}

CExpr::CExpr(Expr *ie) {
	e = ie;
}

CExpr::~CExpr() {
	delete e;
}
