//
// Copyright(c) 2001 Simon Howard
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License
// as published by the Free Software Foundation.
// 
// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//------------------------------------------------------------------------------
//
// Output print functions for MS IL (.Net)
//
//------------------------------------------------------------------------------

#include "parser.h"

#define ARRAY_SIZE 8000

void print_plusnode(treenode_t *node, FILE *fstream)
{
	int n = node->data.i;

	if (n == 0)
		return;
	
	fprintf(fstream,
		// 2nd arguments for write back
		
		"\t\tldloc bfarray\n"
		"\t\tldloc bfarrayloc\n"
		"\n"
		// load value
		
		"\t\tldloc bfarray\n"                // array
		"\t\tldloc bfarrayloc\n"             // index
		"\t\tldelem.i1\n"                  // load
		);

	if (n > 0) {

		fprintf(fstream, 
			// add value
			
			"\t\tldc.i4.s %i \n"
			"\t\tadd\n",
			n);
	} else {
		fprintf(fstream,

			// subtract value

			"\t\tldc.i4.s %i\n"
			"\t\tsub\n",
			-n);
	}

	fprintf(fstream,
		"\n"
		"\t\tstelem.i1\n"                  // save
		"\n"
		);
}

void print_nextnode(treenode_t *node, FILE *fstream)
{
	int n = node->data.i;

	if (n > 0) {
		
		fprintf(fstream,
			"\t\tldloc bfarrayloc\n"
			"\t\tldc.i4.s %i\n"
			"\t\tadd\n"
			"\t\tstloc bfarrayloc\n"
			"\n",
			n			
			);
	} else if (n < 0) {
		fprintf(fstream,
			"\t\tldloc bfarrayloc\n"
			"\t\tldc.i4.s %i\n"
			"\t\tsub\n"
			"\t\tstloc bfarrayloc\n"
			"\n",
			-n
			);
	} // n == 0 -> do nothing
}

void print_loopnode(treenode_t *node, FILE *fstream)
{
	loopnode_t *loop = (loopnode_t *) node->data.v;
	
	fprintf(fstream,
		"\tloop%istart:\n",
		loop->loop_num);

	// check current value under pointer is non-zero

	fprintf(fstream,
		"\t\tldloc bfarray\n"
		"\t\tldloc bfarrayloc\n"
		"\t\tldelem.i1\n"
		"\t\tbrfalse loop%iend\n"
		"\n",
		loop->loop_num);

	loop->list->print(loop->list, fstream);
	
	fprintf(fstream,
		"\t\tbr loop%istart\n"
		"\tloop%iend:\n"
		"\n",
		loop->loop_num,
		loop->loop_num);
		
}

void print_readnode(treenode_t *node, FILE *fstream)
{
	fprintf(fstream,
		"\t\tldloc bfarray\n"
		"\t\tldloc bfarrayloc\n"
		"\t\tcall int32 [mscorlib] System.Console::Read()\n"
		"\t\tstelem.i1\n"
		"\n"
		);
}

void print_printnode(treenode_t *node, FILE *fstream)
{
	fprintf(fstream,
		"\t\tldloc bfarray\n"
		"\t\tldloc bfarrayloc\n"
		"\t\tldelem.i1\n"
		"\t\tcall void [mscorlib] System.Console::Write(char)\n"
		"\n"
		);
		
}

// start of file

void print_head(FILE *fstream)
{
	fprintf(fstream,
		".assembly extern mscorlib {}\n"
		".class public brainfuck extends [mscorlib] System.Object {\n"
		"\t.method static public void main() il managed {\n"
		"\t\t.maxstack 10\n"
		"\t\t.entrypoint\n"
		"\t\t.locals (int8[] bfarray, int32 bfarrayloc)\n"
		"\n"
		);

	fprintf(fstream,
		"\t\tldc.i4.s %i\n"
		"\t\tnewarr int8\n"
		"\t\tstloc bfarray\n"
		"\n",
		ARRAY_SIZE
		);

	fprintf(fstream,
		"\t\tldc.i4.s %i\n"
		"\t\tstloc bfarrayloc\n"
		"\n",
		ARRAY_SIZE / 2
		);
}

// end of file

void print_tail(FILE *fstream)
{
	fprintf(fstream,
		"\t\tret\n"
		"\t}\n"
		"}\n"
		"\n"
		);
}
       
