/*	Copyright (C) 1990 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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 1, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "funcdef.h"
#ifdef TEST_YYLEX

#include <ctype.h>

/* #include "node.h"
#include "eval.h"
#include "var.h" */

CELLREF cur_row=1,cur_col=1;

struct node *yylval;

int
main FUN0()
{
	char buf[80];
	int ret;
	extern char *instr;

	init_parse();
	printf("Read lines and print what they lex to.\n");
	while(printf("lex->"),gets(buf)) {
		instr=buf;
		while(ret=yylex()) {
			if(isascii(ret))
				printf("'%c' ",ret);
			else
				printf("%d ",ret);
			if(yylval->comp_value) {
				putchar('[');
				/* printf("%d",yylval->node_type); */
				printf("%d",yylval->comp_value);
				switch(yylval->comp_value) {
				case CONST_FLT:
					printf(" %g",yylval->n_x.v_float);
					break;
				case CONST_INT:
					printf(" %ld",yylval->n_x.v_int);
					break;
				case CONST_STR:
					printf(" \"%s\"",yylval->n_x.v_string);
					break;
				case R_CELL:
					printf(" %d:%d",yylval->n_x.v_dex[0],yylval->n_x.v_dex[1]);
					break;
				case R_CELL|COLREL:
					printf(" %d:%+d",yylval->n_x.v_dex[0],yylval->n_x.v_dex[1]);
					break;
				case R_CELL|ROWREL:
					printf(" %+d:%d",yylval->n_x.v_dex[0],yylval->n_x.v_dex[1]);
					break;
				case R_CELL|ROWREL|COLREL:
					printf(" %+d:%+d",yylval->n_x.v_dex[0],yylval->n_x.v_dex[1]);
					break;

				case SUM:
				case POW:
				case PROD:
				case MOD:
				case NOTEQUAL:
				case LESS:
				case LESSEQ:
				case GREATER:
				case GREATEQ:
				case EQUAL:
				case DIV:
				case DIFF:
					break;

				case AREA_SUM:
				case AREA_PROD:
				case AREA_AVG:
				case AREA_STD:
				case AREA_MAX:
				case AREA_MIN:
					break;

				default:
					printf(" ???");
					break;
				}
				putchar(']');
				putchar(' ');
			}
		}
		putchar('\n');
	}
	return 0;
}

struct var *
find_or_make_var FUN2(char *, string, int, len)
{
	struct var *ret;
	void *ck_malloc();

	ret=(struct var *)ck_malloc(sizeof(struct var)+len+1);
	bcopy(string,ret->var_name,len);
	ret->var_name[len]='\0';
	ret->var_flags=VAR_UNDEF;
	return ret;
}

#endif

#ifdef TEST_PARSE
/* #include "eval.h"
#include "node.h"
#include "var.h" */

CELLREF cur_row=1,cur_col=1;

void print_node EXT2(struct node *, int);

int
main FUN0()
{
	char buf[200];
	int ret;
	extern char *instr;
	extern struct node *parse_return;
	extern int parse_error;

	init_parse();
	printf("Read lines, parse them, and print the results\n");
	while(printf("parse->"),gets(buf)) {
		instr=buf;
		ret=yyparse();
		if(ret || parse_error)
			printf("ERROR %d %d\n",ret,parse_error);
		if(parse_return)
			print_node(parse_return,0);
		parse_free();
	}
	return 0;
}

void
print_node FUN2(struct node *,node, int,depth)
{
	struct function *f;

	f= &the_funs[node->comp_value];
	printf("%*s %#x: comp %d  add %d comp %d\n",depth,"",node->comp_value,node->add_byte,f->fn_comptype);
	switch(f->fn_comptype) {
	case C_IF:
		printf("Test-code:\n");
		print_node(node->n_x.v_subs[0]->n_x.v_subs[0],depth+1);
		printf("True-code:\n");
		print_node(node->n_x.v_subs[0]->n_x.v_subs[1],depth+1);
		printf("False-code:\n");
		print_node(node->n_x.v_subs[1],depth+1);
		break;

	case C_ANDOR:
		printf("First-code:\n");
		print_node(node->n_x.v_subs[0],depth+1);
		printf("Second-code:\n");
		print_node(node->n_x.v_subs[1],depth+1);
		break;

	case C_ERR:
		printf("Err %d",node->n_x.v_val);
		break;

	case C_FLT:
		printf("Float %.12g\n",node->n_x.v_float);
		break;

	case C_INT:
		printf("Int %ld\n",node->n_x.v_int);
		break;

	case C_STR:
		printf("String \"%s\"\n",node->n_x.v_string);
		break;

	case C_VAR:
		printf("Var %#x\n",node->n_x.v_var);
		break;

	case C_CELL:
		printf("Cell %d %d\n",node->n_x.v_dex[0],node->n_x.v_dex[1]);
		break;

	case C_RANGE:
		printf("Range %d %d %d %d\n",node->n_x.v_dex[0],node->n_x.v_dex[1],node->n_x.v_dex[2],node->n_x.v_dex[3]);
		break;

	case C_FN0:
	case C_TIM|C_FN0:
		printf("FUN0: %s\n",f->fn_str);
		break;

	case C_FN1:
	case C_TIM|C_FN1:
	case C_FN0X:
		printf("FUN1: %s\n",f->fn_str);
		print_node(node->n_x.v_subs[0],depth+1);
		break;

	case C_FN2:
	case C_TIM|C_FN2:
		printf("FUN2: %s  First:\n",f->fn_str);
		print_node(node->n_x.v_subs[0],depth+1);
		printf("Second:\n");
		print_node(node->n_x.v_subs[1],depth+1);
		break;

	case C_FN3:
	case C_TIM|C_FN3:
		printf("FUN3: %s  First:\n",f->fn_str);
		print_node(node->n_x.v_subs[0]->n_x.v_subs[0],depth+1);
		printf("Second:\n");
		print_node(node->n_x.v_subs[0]->n_x.v_subs[1],depth+1);
		printf("Third:\n");
		print_node(node->n_x.v_subs[1],depth+1);
		break;

	case C_FN4:
	case C_TIM|C_FN4:
		printf("FUN4: %s  First:\n",f->fn_str);
		print_node(node->n_x.v_subs[0]->n_x.v_subs[0],depth+1);
		printf("Second:\n");
		print_node(node->n_x.v_subs[0]->n_x.v_subs[1],depth+1);
		printf("Third:\n");
		print_node(node->n_x.v_subs[1]->n_x.v_subs[0],depth+1);
		printf("Fourth:\n");
		print_node(node->n_x.v_subs[1]->n_x.v_subs[1],depth+1);
		break;

	case C_FNN:
		printf("FNN: %s  First:\n",f->fn_str);
		for(node=node->n_x.v_subs[0];node;node=node->n_x.v_subs[1])
			print_node(node->n_x.v_subs[0],depth+1);
		break;

	default:
		panic("Unknown fn_comptype %d",f->fn_comptype);
	}
}

struct var *
find_or_make_var FUN2(char *, string, int, len)
{
	struct var *ret;
	void *ck_malloc();

	ret=(struct var *)ck_malloc(sizeof(struct var)+len+1);
	bcopy(string,ret->var_name,len);
	ret->var_name[len]='\0';
	ret->var_flags=VAR_UNDEF;
	return ret;
}

#endif

#ifdef TEST_COMPILE
/* #include "var.h" */

unsigned char cur_row=1, cur_col=1;

int
main FUN0()
{
	char buf[200];
	unsigned char *ret;
	extern char *instr;
	extern unsigned char *byte_compile();

	init_parse();
	init_byte();
	printf("Read lines, parse and compile them, and print the results\n");
	while(printf("compile->"),gets(buf)) {
		instr=buf;
		yyparse();
		ret=byte_compile();
		print_decompile(ret);
	}
	return 0;
}

struct var *
find_or_make_var FUN2(char *, string, int, len)
{
	struct var *ret;
	void *ck_malloc();

	ret=(struct var *)ck_malloc(sizeof(struct var)+len+1);
	bcopy(string,ret->var_name,len);
	ret->var_name[len]='\0';
	ret->var_flags=VAR_UNDEF;
	return ret;
}

void
add_timer_ref FUN2(unsigned char,type, int,whereto)
{
	printf("Add timer ref %d to %d\n",type, whereto);
}

void
add_ref FUN3(unsigned char, type, short, rowbit, short, colbit)
{
	printf("ref %d to %d, %d\n",type, rowbit,colbit);
}

void
add_range_ref FUN5(unsigned char, type,
			short, r1bit,
 			short, c1bit,
 			short, r2bit,
 			short, c2bit)
{
	printf("r_ref %d to %d:%d, %d:%d\n",type,r1bit,r2bit,c1bit,c2bit);
}

void
add_var_ref FUN1(struct var *, var)
{
	printf("v_ref\n");
}

#endif

#ifdef TEST_DECOMPILE
/* #include "var.h" */

struct pr_node {
	int tightness;
	int len;
	char string[1];
};

char inbuf[120];

CELLREF cur_row = 1, cur_col = 1;

struct pr_node *byte_decompile();

main FUN0()
{
	unsigned char *prog;
	struct pr_node *ptr;
	unsigned char *parse_and_compile();

	printf("Read a line, parse, byte-compile, decompile it\n");
	init_parse();
	while(printf("decomp->"),gets(inbuf)) {
		prog=parse_and_compile(inbuf);
		if(!prog) {
			printf("couldn't parse\n");
			continue;
		}
		ptr=byte_decompile(prog);
		printf("'%d: %s'\n", ptr->len, ptr->string);
	}
}

struct var *
find_or_make_var FUN2(char *, string, int, len)
{
	struct var *ret;
	void *ck_malloc();

	ret=(struct var *)ck_malloc(sizeof(struct var)+len+1);
	bcopy(string,ret->var_name,len);
	ret->var_name[len]='\0';
	ret->var_flags=VAR_UNDEF;
	return ret;
}

void
add_timer_ref FUN2(unsigned char,type, int,whereto)
{
	printf("Add timer ref %d to %d\n",type, whereto);
}

void
add_ref FUN3(unsigned char, type, short, rowbit, short, colbit)
{
	printf("ref %d to %d, %d\n",type, rowbit,colbit);
}

void
add_range_ref FUN5(unsigned char, type,
			short, r1bit,
 			short, c1bit,
 			short, r2bit,
 			short, c2bit)
{
	printf("r_ref %d to %d:%d, %d:%d\n",type,r1bit,r2bit,c1bit,c2bit);
}

void
add_var_ref FUN1(struct var *, var)
{
	printf("v_ref\n");
}

#endif

#ifdef TEST_EVAL
/* #include "cell.h"
#include "var.h" */

struct value {
	int	type;
	union vals x;
};
#define Float	x.c_d
#define String	x.c_s
#define Int	x.c_l
#define Value	x.c_i
#define Index	x.c_x

struct cell v[10][10];

void
push_refs()
{
}

void
set_cell FUN3(CELLREF, row, CELLREF, col,struct value *, val)
{
	v[row][col].cell_flags= val->type;
	v[row][col].c_z=val->x;
}

struct cell *
find_cell FUN2(CELLREF, row,CELLREF, col)
{
	return &v[row][col];
}

struct cell *
find_or_make_cell FUN2(CELLREF, row, CELLREF, col)
{
	return &v[row][col];
}

struct var *
find_or_make_var FUN2(char *, string, int, len)
{
	struct var *ret;
	void *ck_malloc();

	ret=(struct var *)ck_malloc(sizeof(struct var)+len+1);
	bcopy(string,ret->var_name,len);
	ret->var_name[len]='\0';
	ret->var_flags=VAR_UNDEF;
	return ret;
}

void
add_ref FUN3(unsigned char, type, short, rowbit, short, colbit)
{
	printf("ref %d to %d, %d\n",type, rowbit,colbit);
}

void
add_range_ref FUN5(unsigned char, type,
			short, r1bit,
 			short, c1bit,
 			short, r2bit,
 			short, c2bit)
{
	printf("r_ref %d to %d:%d, %d:%d\n",type,r1bit,r2bit,c1bit,c2bit);
}

void
add_var_ref FUN1(struct var *, var)
{
	printf("v_ref\n");
}

int
main FUN0()
{
	char inbuf[160];
	char *ptr;
	unsigned char *prog;
	struct value *ret;
	int row,col;

	extern unsigned char *parse_and_compile();
	struct value *eval_expression();

	init_eval();
	init_parse();

	for(row=0;row<10;row++)
		for(col=0;col<10;col++) {
			v[row][col].cell_int=row*col+row+col;
			v[row][col].cell_flags=TYP_INT;
		}

	printf("read in a line, parse, compile, and eval it\n");
	while(printf("eval->"),gets(inbuf)) {
		ptr=inbuf;
		if(inbuf[0]==' ') {
			ptr++;
			row=astol(&ptr);
			if(*ptr==',')
				ptr++;
			col=astol(&ptr);
		} else row= -1;
		prog=parse_and_compile(ptr);
		if(!prog) {
			printf("Compile failed\n");
			continue;
		}
		ret=eval_expression(prog);
		switch(ret->type) {
		case TYP_FLT:
			printf("(float) %g\n",ret->Float);
			break;
		case TYP_INT:
			printf("(int) %ld\n",ret->Int);
			break;
		case TYP_ERR:
			printf("(error) %d\n",ret->Value);
			break;
		case TYP_BOL:
			printf("(bool) %s\n",ret->Value? "TRUE" : "FALSE");
			break;
		case TYP_STR:
			printf("(string) '%s'\n",ret->String);
			break;
		default:
			printf("Eh, wot\n");
			break;
		}
		if(row!=-1)
			set_cell(row,col,ret);
	}
	return 0;
}

#endif

#ifdef TEST_CELL
/* #include "cell.h" */

struct init {
	CELLREF row,col;
};

struct init inits [] = {
	{ 0, 3},{ 0, 2},{ 0, 1},{ 0, 5},{ 0, 4}, { 0,10},{ 0,11},{ 0,12},


	{ 3, 1},




	{ 8, 4},{ 8, 3},{ 8, 2},{ 8, 5},{ 8, 6},
	{ 9, 0},{ 9, 1},{ 9, 2},{ 9, 6},{ 9, 7},


	{12, 1},{12, 2},{12, 3},{12, 4},{12, 5}, {12, 6},{12, 7},{12, 8},{12, 9},

	{20, 0},{20, 8},{20, 7},{20, 6},{20, 9}, {20,10},{20,11},{20,12},{20,13},
	{21, 0},{21, 8},{21, 7},{21, 6},{21, 5}, {21, 9},{21,10},{21,11},{21,12},{21,13},{21,14},{21,14},{21,15},{21,16},
	{22, 0},{22, 7},{22, 6},{22, 5},{22, 8}, {22, 9},
	{23, 0},{23,14},{23,13},{23,12},{23,15}, {23,16},
	{24, 0},{24, 7},{24, 6},{24, 5},{24, 8}, {24, 9}, {24,14},{24,13},{24,12},{24,15},{24,16},
	{25, 0},
	{26, 0},
	{27, 0},
	{28, 0},
	{29, 0},
	{30, 0},
	{31, 0},

};

main FUN0()
{
	char inbuf[160];
	char *ptr;
	char fun;
	long row,row1,col,col1;
	long num;
	struct cell *ret;
	struct init *ip;

	for(ip=inits;ip<&inits[sizeof(inits)/sizeof(inits[0])];ip++) {
		ret=find_or_make_cell(ip->row,ip->col);
		ret->cell_flags=1;
		ret->cell_int=10000L+ip->row*100+ip->col;
	}

	while(printf("cell-> "),gets(inbuf)) {
		ptr=inbuf;
		switch(*ptr) {
		case 'f':
			ptr++;
			row=astol(&ptr);
			col=astol(&ptr);
			ret=find_cell((CELLREF)row,(CELLREF)col);
			if(!ret)
				printf("(null)\n");
			else if(!ret->cell_flags)
				printf("'%ld'\n",ret->cell_int);
			else
				printf("%ld\n",ret->cell_int);
			break;

		case 'm':
			ptr++;
			row=astol(&ptr);
			col=astol(&ptr);
			ret=find_or_make_cell((CELLREF)row,(CELLREF)col);
			ret->cell_flags=1;
			ret->cell_int=astol(&ptr);
			break;

		case ' ':
			ptr++;
			row=astol(&ptr);
			row1=astol(&ptr);
			col=astol(&ptr);
			col1=astol(&ptr);
			find_cells_in_range((CELLREF)row, (CELLREF)col, (CELLREF)row1, (CELLREF)col1);
			while(ret=next_cell_in_range()) {
				if(!ret->cell_flags)
					printf("'%ld'\n",ret->cell_int);
				else
					printf("%ld\n",ret->cell_int);
			}
			break;

		case 'i':
			fun= *++ptr;
			ptr++;
			row=astol(&ptr);
			num=astol(&ptr);
			col=astol(&ptr);
			col1=astol(&ptr);
			if(fun=='r')
				insert_rows((CELLREF)row,num,(CELLREF)col,(CELLREF)col1);
			else if(fun=='c')
				insert_cols((CELLREF)row,num,(CELLREF)col,(CELLREF)col1);
			else
				printf("'ir' or 'ic' only\n");
			break;

		case 'd':
			fun= *++ptr;
			ptr++;
			row=astol(&ptr);
			num=astol(&ptr);
			col=astol(&ptr);
			col1=astol(&ptr);
			if(fun=='r')
				delete_rows((CELLREF)row,num,(CELLREF)col,(CELLREF)col1);
			else if(fun=='c')
				delete_cols((CELLREF)row,num,(CELLREF)col,(CELLREF)col1);
			else
				printf("'dr' or 'dc' only\n");
			break;

		case 'p':
			ptr++;
			col=astol(&ptr);
			col1=astol(&ptr);
			row=astol(&ptr);
			row1=astol(&ptr);
			while(row<=row1) {
				for(num=col;num<=col1;num++) {
					ret=find_cell((CELLREF)row,(CELLREF)num);
					if(!ret)
						printf("     . ");
					else if(!ret->cell_flags)
						printf("'%5ld ",ret->cell_int);
					else
						printf("%6ld ",ret->cell_int);
				}
				putchar('\n');
				row++;
			}
			break;

		case 'P':
			print_array(0);
			break;

		default:
			printf("'f', 'm', 'i', 'd', or ' ' only\n");
			break;
		}
	}
}
#endif

#ifdef TEST_REF
#include <stdio.h>
/* #include "cell.h"
#include "var.h" */

main FUN0()
{
	char inbuf[160];
	CELLREF row,col;
	CELLREF lr,hr,lc,hc;
	CELL *cp;
	char *ptr;
	FILE *fp;
	char base,fun;
	int num;
	extern unsigned short current_cycle;

	init_parse();
	init_eval();
	init_refs();
	fp=stdin;
	current_cycle++;
	printf("Read lines of row,col_expr and eval/store\n");
	for(;;) {
		printf("ref-> ");
		if(!fgets(inbuf,160,fp)) {
			if(fp==stdin)
				break;
			printf("<EOF>\n");
			fclose(fp);
			fp=stdin;
			continue;
		} else if(fp!=stdin)
			printf(inbuf);
		ptr=inbuf;
		while(*ptr && *ptr!='\n')
			ptr++;
		if(*ptr=='\n')
			*ptr=0;
		ptr=inbuf;
		switch(*ptr) {
		case 'f':
			ptr++;
			while(*ptr==' ')
				ptr++;
			fp=fopen(ptr,"r");
			if(!fp) {
				fp=stdin;
				perror(ptr);
			}
			break;
		case 'p':
			ptr++;
			lr=astol(&ptr)-1;
			if(*ptr==',')
				ptr++;
			hr=astol(&ptr)-1;
			if(*ptr==',')
				ptr++;
			lc=astol(&ptr)-1;
			if(*ptr==',')
				ptr++;
			hc=astol(&ptr)-1;
			if(*ptr==',')
				ptr++;

			if(lr<MIN_ROW || lr>MAX_ROW || hr<MIN_ROW || hr>MAX_ROW
 			   || lc<MIN_COL || lc>MAX_COL || hc<MIN_COL || hc>MAX_COL) {
				printf("Out of range?\n");
				break;
			}
			for(row=lr;row<=hr;row++) {
				int space = 0;

				for(col=lc;col<=hc;col++) {
					cp=find_cell(row,col);
					if(!cp)
						space+=11;
					else {
						if(space) {
							printf("%*s",space,"");
							space=0;
						}
						pr_cell(MAX_ROW,MAX_COL,cp);
					}
				}
				printf("\n");
				space=0;
			}
			break;

		case 's':
			ptr++;
			row=astol(&ptr)-1;
			if(*ptr==',')
				ptr++;
			col=astol(&ptr)-1;
			if(row<MIN_ROW || row>MAX_ROW || col<MIN_COL || col>MAX_COL) {
				printf("Out of range?\n");
				break;
			}
			cp=find_cell(row,col);
			if(!cp)
				printf("No Can Do!\n");
			else {
				printf("%d,%d",row,col);
				pr_cell(row,col,cp);
				printf("\n");
			}
			break;

		case 'P':
			print_array(0);
			break;

		case 'd':
		case 'i':
			base= *ptr++;
			fun = *ptr++;
			row=astol(&ptr)-1;
			if(*ptr==',')
				ptr++;
			num=astol(&ptr);
			if(*ptr==',')
				ptr++;
			lc=astol(&ptr)-1;
			if(*ptr==',')
				ptr++;
			hc=astol(&ptr)-1;
			if(*ptr==',')
				ptr++;
			if(base=='i') {
				if(fun=='r') {
					shift_ref(row, MAX_ROW, lc, hc, num, 0);
					insert_rows(row,num,lc,hc);
				} else if(fun=='c') {
					shift_ref(lc, hc, row, MAX_COL, 0, num);
					insert_cols(row,num,lc,hc);
				} else
					base='?';
			}
			if(base=='d') {
				if(fun=='r') {
					shift_ref(row, MAX_ROW, lc, hc, -num, 0);
					delete_rows(row,num,lc,hc);
				} else if(fun=='c') {
					shift_ref(lc, hc, row, MAX_COL, 0, -num);
					delete_cols(row,num,lc,hc);
				} else
					base='?';
			}
			if(base!='i' && base!='d')
				printf("[ir   ic   dr   dc]    <startat> <number> <low> <high>\n");
			break;
		case 'v':
			ptr++;
			while(*ptr==' ')
				ptr++;
			for(num=0;ptr[num] && ptr[num]!=' ';num++)
				;
			if(ptr[num]) {
				ptr=new_var_value(ptr,num,&ptr[num+1]);
				if(ptr)
					printf("Fail: %s\n",ptr);
			}
			break;

		default:
			printf("f <filename>   [id][rc] <numbers>   p   P   or <row> <col> <formula>\n");
			break;

		case ' ':
		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			row=astol(&ptr)-1;
			if(*ptr==',')
				ptr++;
			col=astol(&ptr)-1;
			if(row<MIN_ROW || row>MAX_ROW || col<MIN_COL || col>MAX_COL) {
				printf("Out of range?\n");
				break;
			}
			ptr=new_value(row, col, ptr);
			if(ptr)
				printf("Fail: %s\n",ptr);
			else
				pr_cell(row,col,find_cell(row,col));
			break;
		}
		current_cycle++;
		while(eval_next_cell())
			;
	}
}
void
pr_cell FUN3(CELLREF, r,  CELLREF, c,  CELL *,cell)
{
	if(r!=MAX_ROW)
		printf("%d,%d: ",r+1, c+1);
	switch(GET_TYP(cell)) {
	case 0:
		printf("     .     ");
		break;
	case TYP_FLT:
		printf("f%010g",cell->cell_flt);
		break;
	case TYP_INT:
		printf("i%010ld",cell->cell_int);
		break;
	case TYP_ERR:
		printf("e%010d",cell->cell_err);
		break;
	case TYP_BOL:
		printf("b%10s",cell->cell_bol ? "TRUE" : "FALSE");
		break;
	case TYP_STR:
		printf("s%10s",cell->cell_str);
		break;
	default:
		printf("Eh, wot    ");
		break;
	}
	if(r!=MAX_ROW)
		printf("\n");
}

#endif
