
/*  A Bison parser, made from ../../rlplot/mfcalc.y
    by GNU Bison version 1.28  */

#define YYBISON 1  /* Identify Bison output.  */

#define	NUM	257
#define	BOOLVAL	258
#define	STR	259
#define	ARR	260
#define	BLOCK	261
#define	PBLOCK	262
#define	IBLOCK	263
#define	PI	264
#define	E	265
#define	CLVAL	266
#define	PSEP	267
#define	IF	268
#define	ELSE	269
#define	BTRUE	270
#define	BFALSE	271
#define	DATE1	272
#define	TIME1	273
#define	DATETIME1	274
#define	DIM	275
#define	WHILE	276
#define	FOR	277
#define	INARR	278
#define	RANGEARR	279
#define	RETURN	280
#define	BREAK	281
#define	VAR	282
#define	FNCT	283
#define	BFNCT	284
#define	AFNCT	285
#define	SFNCT	286
#define	FUNC1	287
#define	TXT	288
#define	SRFUNC	289
#define	YYFNC	290
#define	FUNC4	291
#define	YYFNC2	292
#define	YYFNC3	293
#define	ADDEQ	294
#define	SUBEQ	295
#define	MULEQ	296
#define	DIVEQ	297
#define	LSEP	298
#define	CLAUSE	299
#define	SER	300
#define	COLC	301
#define	AND	302
#define	OR	303
#define	EQ	304
#define	NE	305
#define	GT	306
#define	GE	307
#define	LT	308
#define	LE	309
#define	NEG	310
#define	INC	311
#define	DEC	312
#define	PINC	313
#define	PDEC	314
#define	PDIM	315


/*
 mfcalc.y, mfcalc.cpp, Copyright (c) 2004-2008 R.Lackner
 parse string and simple math: based on the bison 'mfcalc' example

    This file is part of RLPlot.

    RLPlot 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.

    RLPlot 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 RLPlot; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include "rlplot.h"

class symrec {
public:
	int type, row, col, a_count;
	unsigned int h_name, h2_name;
	char *name, *text;
	double (*fnctptr)(...);
	symrec *next;
	double var, *a_data;

	symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt);
	~symrec();
	double GetValue();
	void GetValue(void *res);
	double SetValue(double v);
        void SetValue(void* dest, void* src);
	void SetName(char *nam);
	void InitSS();
	void NoInit();

private:
	bool isSSval, isValid;

};

// syntactical information
struct syntax_info {
	int last_tok;			//resolve ambiguous ':'
	double clval;			//current value for where - clause
	int cl1, cl2;			//limits of clause formula in buffer
	struct syntax_info *next;
	};
static syntax_info *syntax_level = 0L;


typedef struct{
	double  val;
	int type;
	symrec  *tptr;
	double *a_data;
	char *text;
	int a_count;

}YYSTYPE;

static int yy_maxiter = 100000;		//maximum loop count
static int block_res;			//result of eval()

static symrec *putsym (unsigned int h_name, unsigned int h2_name, int sym_type);
static symrec *getsym (unsigned int h_name, unsigned int h2_name, char *sym_name = 0L);
static int push(YYSTYPE *res, YYSTYPE *val);
static void yyCompare(YYSTYPE *res, YYSTYPE *arg1, YYSTYPE *arg2, int op);
static void store_res(YYSTYPE *res);
static char *PushString(char *text);
static double *PushArray(double *arr);
static double *ReallocArray(double *arr, int size);
static char *add_strings(char *st1, char *st2);
static char *string_value(YYSTYPE *exp);
static int eval(YYSTYPE *dst, YYSTYPE *sr);
static int range_array(YYSTYPE * res, char *range);
static int range_array2(YYSTYPE *res1, YYSTYPE *res2);
static void exec_clause(YYSTYPE *res);
static YYSTYPE *proc_clause(YYSTYPE *res);
static void yyerror(char *s);
static void make_time(YYSTYPE *dst, double h, double m, double s);
static int yylex(void);
static double nop() {return 0.0;};
static int for_loop(char *block1, char *block2);

static char res_txt[1000];
static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt, 0L, 0};
static DataObj *curr_data;
static char *last_error = 0L;		//error text
static char *last_err_desc = 0L;	//short error description

static char *buffer = 0L;		//the current command buffer
static int buff_pos = 0;
static bool bRecent = false;		//rearrange functions
static bool bNoWrite, bNoExec, bNoSS;	//while editing ...
static int parse_level = 0;		//count reentrances into parser
#define MAX_PARSE 50			//maximum number of recursive reentances 
#include <stdio.h>

#ifndef __cplusplus
#ifndef __STDC__
#define const
#endif
#endif



#define	YYFINAL		221
#define	YYFLAG		-32768
#define	YYNTBASE	77

#define YYTRANSLATE(x) ((unsigned)(x) <= 315 ? yytranslate[x] : 87)

static const char yytranslate[] = {     0,
     2,     2,     2,     2,     2,     2,     2,     2,     2,    72,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,    73,
    74,    60,    59,    71,    58,     2,    61,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,    76,    70,     2,
    40,     2,    49,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    63,     2,    75,    62,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     1,     3,     4,     5,     6,
     7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
    17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
    27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
    37,    38,    39,    41,    42,    43,    44,    45,    46,    47,
    48,    50,    51,    52,    53,    54,    55,    56,    57,    64,
    65,    66,    67,    68,    69
};

#if YYDEBUG != 0
static const short yyprhs[] = {     0,
     0,     1,     4,     6,     8,    10,    12,    14,    17,    20,
    23,    26,    30,    36,    40,    44,    47,    49,    52,    54,
    58,    62,    66,    71,    78,    80,    82,    84,    88,    92,
    94,    98,   100,   105,   107,   109,   113,   117,   121,   125,
   129,   133,   137,   141,   143,   145,   147,   149,   151,   153,
   155,   157,   159,   161,   163,   165,   167,   171,   175,   179,
   183,   187,   191,   196,   201,   208,   217,   222,   227,   234,
   245,   252,   259,   263,   268,   275,   280,   289,   296,   300,
   304,   308,   312,   315,   318,   321,   324,   328,   331,   335,
   341,   346,   353,   360,   367,   374,   381,   387,   391,   397,
   403,   409
};

static const short yyrhs[] = {    -1,
    77,    79,     0,    70,     0,    71,     0,    72,     0,    70,
     0,    71,     0,    86,    72,     0,    86,    78,     0,    80,
    72,     0,    80,    70,     0,    14,     8,    84,     0,    14,
     8,    84,    15,    84,     0,    23,     8,    84,     0,    22,
     8,    84,     0,    26,     9,     0,    27,     0,     1,    72,
     0,     5,     0,    80,    59,    86,     0,    86,    59,    80,
     0,    80,    59,    80,     0,    35,    73,    86,    74,     0,
    35,    73,    86,    78,    80,    74,     0,    80,     0,     6,
     0,    86,     0,    82,    45,    82,     0,    82,    46,    86,
     0,    81,     0,     3,    47,     3,     0,     4,     0,    30,
    73,    86,    74,     0,    16,     0,    17,     0,    86,    50,
    86,     0,    86,    51,    86,     0,    86,    52,    86,     0,
    86,    53,    86,     0,    86,    54,    86,     0,    86,    55,
    86,     0,    86,    56,    86,     0,    86,    57,    86,     0,
     7,     0,     9,     0,    86,     0,    80,     0,     3,     0,
    25,     0,    83,     0,    34,     0,    12,     0,    10,     0,
    11,     0,    28,     0,    84,     0,    28,    40,    86,     0,
    28,    40,    80,     0,    28,    41,    86,     0,    28,    42,
    86,     0,    28,    43,    86,     0,    28,    44,    86,     0,
    29,    73,    86,    74,     0,    31,    73,    82,    74,     0,
    31,    73,    86,    13,    82,    74,     0,    31,    73,    86,
    13,    86,    13,    86,    74,     0,    32,    73,    80,    74,
     0,    32,    73,    86,    74,     0,    32,    73,    85,    78,
    85,    74,     0,    37,    73,    86,    13,    86,    13,    82,
    13,    81,    74,     0,    33,    73,    82,    13,    81,    74,
     0,    33,    73,    82,    13,    25,    74,     0,    36,    73,
    74,     0,    36,    73,    82,    74,     0,    38,    73,    85,
    13,    85,    74,     0,    38,    73,    85,    74,     0,    39,
    73,    85,    13,    85,    13,    85,    74,     0,    39,    73,
    85,    13,    85,    74,     0,    86,    59,    86,     0,    86,
    58,    86,     0,    86,    60,    86,     0,    86,    61,    86,
     0,    28,    65,     0,    28,    66,     0,    65,    28,     0,
    66,    28,     0,    86,    62,    86,     0,    58,    86,     0,
    73,    85,    74,     0,    21,    28,    63,    86,    75,     0,
    86,    63,    86,    75,     0,    86,    63,    86,    75,    40,
    86,     0,    86,    63,    86,    75,    41,    86,     0,    86,
    63,    86,    75,    42,    86,     0,    86,    63,    86,    75,
    43,    86,     0,    86,    63,    86,    75,    44,    86,     0,
     3,    76,     3,    76,     3,     0,     3,    76,     3,     0,
    86,    49,    86,    48,    86,     0,    86,    49,     5,    48,
     5,     0,    86,    49,     5,    48,    86,     0,    86,    49,
    86,    48,     5,     0
};

#endif

#if YYDEBUG != 0
static const short yyrline[] = { 0,
   137,   138,   141,   141,   143,   143,   143,   144,   145,   146,
   147,   148,   150,   153,   154,   156,   157,   158,   161,   163,
   164,   165,   166,   167,   170,   174,   175,   176,   177,   178,
   179,   183,   184,   185,   186,   187,   188,   189,   190,   191,
   192,   193,   194,   197,   197,   199,   199,   201,   202,   203,
   204,   205,   206,   207,   208,   209,   210,   211,   212,   213,
   214,   215,   217,   218,   219,   221,   224,   225,   226,   227,
   228,   229,   230,   231,   232,   233,   234,   235,   236,   240,
   244,   245,   247,   248,   249,   250,   251,   252,   253,   254,
   256,   258,   262,   266,   270,   274,   279,   280,   281,   282,
   283,   284
};
#endif


#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)

static const char * const yytname[] = {   "$","error","$undefined.","NUM","BOOLVAL",
"STR","ARR","BLOCK","PBLOCK","IBLOCK","PI","E","CLVAL","PSEP","IF","ELSE","BTRUE",
"BFALSE","DATE1","TIME1","DATETIME1","DIM","WHILE","FOR","INARR","RANGEARR",
"RETURN","BREAK","VAR","FNCT","BFNCT","AFNCT","SFNCT","FUNC1","TXT","SRFUNC",
"YYFNC","FUNC4","YYFNC2","YYFNC3","'='","ADDEQ","SUBEQ","MULEQ","DIVEQ","LSEP",
"CLAUSE","SER","COLC","'?'","AND","OR","EQ","NE","GT","GE","LT","LE","'-'","'+'",
"'*'","'/'","'^'","'['","NEG","INC","DEC","PINC","PDEC","PDIM","';'","','","'\\n'",
"'('","')'","']'","':'","input","anysep","line","str_exp","range","arr","bool",
"block","anyarg","exp", NULL
};
#endif

static const short yyr1[] = {     0,
    77,    77,    78,    78,    79,    79,    79,    79,    79,    79,
    79,    79,    79,    79,    79,    79,    79,    79,    80,    80,
    80,    80,    80,    80,    81,    82,    82,    82,    82,    82,
    82,    83,    83,    83,    83,    83,    83,    83,    83,    83,
    83,    83,    83,    84,    84,    85,    85,    86,    86,    86,
    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
    86,    86
};

static const short yyr2[] = {     0,
     0,     2,     1,     1,     1,     1,     1,     2,     2,     2,
     2,     3,     5,     3,     3,     2,     1,     2,     1,     3,
     3,     3,     4,     6,     1,     1,     1,     3,     3,     1,
     3,     1,     4,     1,     1,     3,     3,     3,     3,     3,
     3,     3,     3,     1,     1,     1,     1,     1,     1,     1,
     1,     1,     1,     1,     1,     1,     3,     3,     3,     3,
     3,     3,     4,     4,     6,     8,     4,     4,     6,    10,
     6,     6,     3,     4,     6,     4,     8,     6,     3,     3,
     3,     3,     2,     2,     2,     2,     3,     2,     3,     5,
     4,     6,     6,     6,     6,     6,     5,     3,     5,     5,
     5,     5
};

static const short yydefact[] = {     1,
     0,     0,    48,    32,    19,    44,    45,    53,    54,    52,
     0,    34,    35,     0,     0,     0,    49,     0,    17,    55,
     0,     0,     0,     0,     0,    51,     0,     0,     0,     0,
     0,     0,     0,     0,     6,     7,     5,     0,     2,     0,
    50,    56,     0,    18,     0,     0,     0,     0,     0,    16,
     0,     0,     0,     0,     0,    83,    84,     0,     0,     0,
     0,     0,     0,     0,     0,     0,     0,    88,    85,    86,
    47,     0,    46,     0,    11,    10,     0,     0,     0,     0,
     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
     0,     3,     4,     8,     9,    98,    12,     0,    15,    14,
    58,    57,    59,    60,    61,    62,     0,     0,    48,    26,
    25,    30,     0,    27,    47,     0,    46,     0,    27,     0,
    73,     0,     0,     0,     0,     0,    89,    22,    20,     0,
     0,    36,    37,    38,    39,    40,    41,    42,    43,    80,
    21,    79,    81,    82,    87,     0,     0,     0,     0,    63,
    33,     0,     0,     0,    64,     0,    67,     0,    68,     0,
    23,     0,    74,     0,     0,    76,     0,    79,     0,     0,
    91,    97,    13,    90,    31,    28,    29,     0,    27,     0,
    49,     0,     0,     0,     0,     0,     0,   100,   101,   102,
    99,     0,     0,     0,     0,     0,    65,     0,    69,    72,
    71,    24,     0,    75,     0,    78,    92,    93,    94,    95,
    96,     0,     0,     0,    66,     0,    77,     0,    70,     0,
     0
};

static const short yydefgoto[] = {     1,
    95,    39,   111,   112,   113,    41,    42,    72,    73
};

static const short yypact[] = {-32768,
   235,   -46,   -48,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
    22,-32768,-32768,     4,    29,    33,-32768,    35,-32768,   145,
     1,     2,    18,    20,    21,-32768,    23,    34,    36,    37,
    39,   763,    42,    44,-32768,-32768,-32768,   443,-32768,   -30,
-32768,-32768,   814,-32768,    43,    13,    50,    13,    13,-32768,
   443,   763,   763,   763,   763,-32768,-32768,   763,   763,   378,
   443,   378,   763,   306,   763,   443,   443,-32768,-32768,-32768,
     6,    40,   854,   443,-32768,-32768,   573,   763,   763,   763,
   763,   763,   763,   763,   763,   763,   443,   763,   763,   763,
   763,-32768,-32768,-32768,-32768,    46,   108,   763,-32768,-32768,
     6,   854,   869,   869,   869,   869,   631,   697,   -20,-32768,
     6,-32768,   -31,   121,   -36,   -22,   756,   -12,   854,   566,
-32768,   -29,   228,    -8,   111,   763,-32768,-32768,    56,    78,
   839,   170,   170,    77,    77,    77,    77,    77,    77,    56,
-32768,    56,     5,     5,    64,   298,   126,    13,   370,-32768,
-32768,   127,   378,   763,-32768,   378,-32768,   443,-32768,   508,
-32768,   443,-32768,   763,   443,-32768,   443,    56,   638,   703,
    60,-32768,-32768,-32768,-32768,    85,   869,   -27,   436,    58,
    59,    68,   854,   -35,   501,    69,    -3,-32768,   869,-32768,
   869,   763,   763,   763,   763,   763,-32768,   763,-32768,-32768,
-32768,-32768,   378,-32768,   443,-32768,   869,   869,   869,   869,
   869,   788,   -10,    70,-32768,   443,-32768,    73,-32768,   148,
-32768
};

static const short yypgoto[] = {-32768,
   -95,-32768,    54,  -147,   -58,-32768,   -37,   -59,    -1
};


#define	YYLAST		932


static const short yytable[] = {    43,
   160,   116,   216,   118,   165,   122,   124,   125,    97,   205,
    99,   100,   182,   153,   154,   153,   154,   153,   154,     6,
   158,     7,    74,    74,   162,    44,   152,    45,    74,    46,
    68,    47,   153,   154,   153,   154,    48,   157,   202,    75,
    49,    76,   155,    50,   163,    96,   197,    92,    93,   102,
   103,   104,   105,   106,    40,    45,   107,   108,   114,   117,
   119,   120,   119,   123,    74,   166,    90,    91,   218,    69,
   206,    70,   129,    58,    59,   131,   132,   133,   134,   135,
   136,   137,   138,   139,   140,   142,   143,   144,   145,   146,
    60,    71,    61,    62,   176,    63,   149,   178,   180,   192,
   193,   194,   195,   196,   101,   186,    64,   187,    65,    66,
   173,    67,    98,   127,   115,    88,    89,    90,    91,    71,
    71,   147,   148,   167,   168,   169,    91,   128,   172,   175,
   154,   199,   200,   156,    86,   126,    88,    89,    90,    91,
   141,   201,   204,   217,   213,   214,   219,   221,     0,     0,
     0,   119,   177,     0,   179,     0,     0,     0,   183,     0,
   183,     0,   185,     0,     0,     0,     0,   189,   191,    77,
    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
    88,    89,    90,    91,    51,    52,    53,    54,    55,     0,
   207,   208,   209,   210,   211,     0,   212,     0,     0,     0,
     0,   119,     0,     0,     0,     0,     0,     0,     0,    56,
    57,    71,     0,     0,   183,   184,     0,     0,    71,     0,
    71,    80,    81,    82,    83,    84,    85,    86,   126,    88,
    89,    90,    91,     0,   220,     2,     0,     3,     4,     5,
   164,     6,     0,     7,     8,     9,    10,     0,    11,     0,
    12,    13,     0,     0,     0,    14,    15,    16,    71,    17,
    18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
    28,    29,    30,    31,     0,     0,    77,    78,    79,    80,
    81,    82,    83,    84,    85,    86,   126,    88,    89,    90,
    91,     0,    32,     0,     0,     0,     0,     0,     0,    33,
    34,     0,     0,     0,    35,    36,    37,    38,   109,     4,
     5,   110,     6,     0,     7,     8,     9,    10,     0,     0,
     0,    12,    13,     0,     0,     0,    14,     0,     0,     0,
    17,     0,     0,    20,    21,    22,    23,    24,    25,    26,
    27,    28,    29,    30,    31,     0,    77,    78,    79,    80,
    81,    82,    83,    84,    85,    86,   126,    88,    89,    90,
    91,     0,     0,    32,     0,     0,     0,     0,     0,     0,
    33,    34,   171,     0,     0,     0,     0,     0,    38,   121,
   109,     4,     5,   110,     6,     0,     7,     8,     9,    10,
     0,     0,     0,    12,    13,     0,     0,     0,    14,     0,
     0,     0,    17,     0,     0,    20,    21,    22,    23,    24,
    25,    26,    27,    28,    29,    30,    31,     0,    77,    78,
    79,    80,    81,    82,    83,    84,    85,    86,   126,    88,
    89,    90,    91,     0,     0,    32,     0,     0,     0,     0,
     0,     0,    33,    34,   174,     3,     4,     5,   198,     6,
    38,     7,     8,     9,    10,     0,     0,     0,    12,    13,
     0,     0,     0,    14,     0,     0,     0,    17,     0,     0,
    20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
    30,    31,     0,     0,    77,    78,    79,    80,    81,    82,
    83,    84,    85,    86,    87,    88,    89,    90,    91,     0,
    32,     0,     0,     0,     0,     0,     0,    33,    34,     0,
     3,     4,     5,   203,     6,    38,     7,     8,     9,    10,
     0,     0,     0,    12,    13,     0,     0,     0,    14,     0,
     0,     0,   181,     0,     0,    20,    21,    22,    23,    24,
    25,    26,    27,    28,    29,    30,    31,     0,     0,    77,
    78,    79,    80,    81,    82,    83,    84,    85,    86,   126,
    88,    89,    90,    91,     0,    32,     0,     0,     0,     0,
     0,     0,    33,    34,     0,     3,     4,   130,     0,     6,
    38,     7,     8,     9,    10,     0,     0,     0,    12,    13,
     0,     0,     0,    14,     0,     0,     0,    17,     0,     0,
    20,    21,    22,    23,    24,    25,    26,     0,    28,    29,
    30,    31,     0,     0,    77,    78,    79,    80,    81,    82,
    83,    84,    85,    86,   126,    88,    89,    90,    91,     0,
    32,     0,     0,     0,     0,    92,    93,    33,    34,   161,
     3,     4,   188,     0,     6,    38,     7,     8,     9,    10,
     0,     0,     0,    12,    13,     0,     0,     0,    14,     0,
     0,     0,    17,     0,     0,    20,    21,    22,    23,    24,
    25,    26,     0,    28,    29,    30,    31,     0,     0,    77,
    78,    79,    80,    81,    82,    83,    84,    85,    86,   126,
    88,    89,    90,    91,     0,    32,     0,     0,     0,     0,
     0,     0,    33,    34,   150,     3,     4,   190,     0,     6,
    38,     7,     8,     9,    10,     0,     0,     0,    12,    13,
     0,     0,     0,    14,     0,     0,     0,    17,     0,     0,
    20,    21,    22,    23,    24,    25,    26,     0,    28,    29,
    30,    31,     0,     0,     0,    77,    78,    79,    80,    81,
    82,    83,    84,    85,    86,   126,    88,    89,    90,    91,
    32,     0,     0,     0,     0,     3,     4,    33,    34,     6,
   151,     7,     8,     9,    10,    38,     0,     0,    12,    13,
     0,     0,     0,    14,     0,     0,     0,    17,     0,     0,
    20,    21,    22,    23,    24,    25,    26,     0,    28,    29,
    30,    31,     0,     0,    77,    78,    79,    80,    81,    82,
    83,    84,    85,    86,    87,    88,    89,    90,    91,     0,
    32,     0,     0,     0,     0,     0,     0,    33,    34,   159,
     0,     0,     0,     0,     0,    38,    77,    78,    79,    80,
    81,    82,    83,    84,    85,    86,   126,    88,    89,    90,
    91,     0,     0,     0,     0,     0,     0,     0,     0,     0,
     0,   215,    77,    78,    79,    80,    81,    82,    83,    84,
    85,    86,    87,    88,    89,    90,    91,     0,     0,     0,
     0,     0,     0,    92,    93,    94,   170,    77,    78,    79,
    80,    81,    82,    83,    84,    85,    86,   126,    88,    89,
    90,    91,    77,    78,    79,    80,    81,    82,    83,    84,
    85,    86,    87,    88,    89,    90,    91,    77,    78,    79,
    80,    81,    82,    83,    84,    85,    86,   126,    88,    89,
    90,    91
};

static const short yycheck[] = {     1,
    13,    61,    13,    62,    13,    64,    66,    67,    46,    13,
    48,    49,   160,    45,    46,    45,    46,    45,    46,     7,
   116,     9,    59,    59,   120,    72,    47,    76,    59,     8,
    32,    28,    45,    46,    45,    46,     8,    74,    74,    70,
     8,    72,    74,     9,    74,     3,    74,    70,    71,    51,
    52,    53,    54,    55,     1,    76,    58,    59,    60,    61,
    62,    63,    64,    65,    59,    74,    62,    63,   216,    28,
    74,    28,    74,    73,    73,    77,    78,    79,    80,    81,
    82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
    73,    38,    73,    73,   153,    73,    98,   156,   158,    40,
    41,    42,    43,    44,    51,   165,    73,   167,    73,    73,
   148,    73,    63,    74,    61,    60,    61,    62,    63,    66,
    67,    76,    15,    13,   126,    48,    63,    74,     3,     3,
    46,    74,    74,    13,    58,    59,    60,    61,    62,    63,
    87,    74,    74,    74,   203,   205,    74,     0,    -1,    -1,
    -1,   153,   154,    -1,   156,    -1,    -1,    -1,   160,    -1,
   162,    -1,   164,    -1,    -1,    -1,    -1,   169,   170,    49,
    50,    51,    52,    53,    54,    55,    56,    57,    58,    59,
    60,    61,    62,    63,    40,    41,    42,    43,    44,    -1,
   192,   193,   194,   195,   196,    -1,   198,    -1,    -1,    -1,
    -1,   203,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    65,
    66,   158,    -1,    -1,   216,   162,    -1,    -1,   165,    -1,
   167,    52,    53,    54,    55,    56,    57,    58,    59,    60,
    61,    62,    63,    -1,     0,     1,    -1,     3,     4,     5,
    13,     7,    -1,     9,    10,    11,    12,    -1,    14,    -1,
    16,    17,    -1,    -1,    -1,    21,    22,    23,   205,    25,
    26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
    36,    37,    38,    39,    -1,    -1,    49,    50,    51,    52,
    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
    63,    -1,    58,    -1,    -1,    -1,    -1,    -1,    -1,    65,
    66,    -1,    -1,    -1,    70,    71,    72,    73,     3,     4,
     5,     6,     7,    -1,     9,    10,    11,    12,    -1,    -1,
    -1,    16,    17,    -1,    -1,    -1,    21,    -1,    -1,    -1,
    25,    -1,    -1,    28,    29,    30,    31,    32,    33,    34,
    35,    36,    37,    38,    39,    -1,    49,    50,    51,    52,
    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
    63,    -1,    -1,    58,    -1,    -1,    -1,    -1,    -1,    -1,
    65,    66,    75,    -1,    -1,    -1,    -1,    -1,    73,    74,
     3,     4,     5,     6,     7,    -1,     9,    10,    11,    12,
    -1,    -1,    -1,    16,    17,    -1,    -1,    -1,    21,    -1,
    -1,    -1,    25,    -1,    -1,    28,    29,    30,    31,    32,
    33,    34,    35,    36,    37,    38,    39,    -1,    49,    50,
    51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
    61,    62,    63,    -1,    -1,    58,    -1,    -1,    -1,    -1,
    -1,    -1,    65,    66,    75,     3,     4,     5,    13,     7,
    73,     9,    10,    11,    12,    -1,    -1,    -1,    16,    17,
    -1,    -1,    -1,    21,    -1,    -1,    -1,    25,    -1,    -1,
    28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
    38,    39,    -1,    -1,    49,    50,    51,    52,    53,    54,
    55,    56,    57,    58,    59,    60,    61,    62,    63,    -1,
    58,    -1,    -1,    -1,    -1,    -1,    -1,    65,    66,    -1,
     3,     4,     5,    13,     7,    73,     9,    10,    11,    12,
    -1,    -1,    -1,    16,    17,    -1,    -1,    -1,    21,    -1,
    -1,    -1,    25,    -1,    -1,    28,    29,    30,    31,    32,
    33,    34,    35,    36,    37,    38,    39,    -1,    -1,    49,
    50,    51,    52,    53,    54,    55,    56,    57,    58,    59,
    60,    61,    62,    63,    -1,    58,    -1,    -1,    -1,    -1,
    -1,    -1,    65,    66,    -1,     3,     4,     5,    -1,     7,
    73,     9,    10,    11,    12,    -1,    -1,    -1,    16,    17,
    -1,    -1,    -1,    21,    -1,    -1,    -1,    25,    -1,    -1,
    28,    29,    30,    31,    32,    33,    34,    -1,    36,    37,
    38,    39,    -1,    -1,    49,    50,    51,    52,    53,    54,
    55,    56,    57,    58,    59,    60,    61,    62,    63,    -1,
    58,    -1,    -1,    -1,    -1,    70,    71,    65,    66,    74,
     3,     4,     5,    -1,     7,    73,     9,    10,    11,    12,
    -1,    -1,    -1,    16,    17,    -1,    -1,    -1,    21,    -1,
    -1,    -1,    25,    -1,    -1,    28,    29,    30,    31,    32,
    33,    34,    -1,    36,    37,    38,    39,    -1,    -1,    49,
    50,    51,    52,    53,    54,    55,    56,    57,    58,    59,
    60,    61,    62,    63,    -1,    58,    -1,    -1,    -1,    -1,
    -1,    -1,    65,    66,    74,     3,     4,     5,    -1,     7,
    73,     9,    10,    11,    12,    -1,    -1,    -1,    16,    17,
    -1,    -1,    -1,    21,    -1,    -1,    -1,    25,    -1,    -1,
    28,    29,    30,    31,    32,    33,    34,    -1,    36,    37,
    38,    39,    -1,    -1,    -1,    49,    50,    51,    52,    53,
    54,    55,    56,    57,    58,    59,    60,    61,    62,    63,
    58,    -1,    -1,    -1,    -1,     3,     4,    65,    66,     7,
    74,     9,    10,    11,    12,    73,    -1,    -1,    16,    17,
    -1,    -1,    -1,    21,    -1,    -1,    -1,    25,    -1,    -1,
    28,    29,    30,    31,    32,    33,    34,    -1,    36,    37,
    38,    39,    -1,    -1,    49,    50,    51,    52,    53,    54,
    55,    56,    57,    58,    59,    60,    61,    62,    63,    -1,
    58,    -1,    -1,    -1,    -1,    -1,    -1,    65,    66,    74,
    -1,    -1,    -1,    -1,    -1,    73,    49,    50,    51,    52,
    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
    63,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
    -1,    74,    49,    50,    51,    52,    53,    54,    55,    56,
    57,    58,    59,    60,    61,    62,    63,    -1,    -1,    -1,
    -1,    -1,    -1,    70,    71,    72,    48,    49,    50,    51,
    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
    62,    63,    49,    50,    51,    52,    53,    54,    55,    56,
    57,    58,    59,    60,    61,    62,    63,    49,    50,    51,
    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
    62,    63
};
/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */

/* This file comes from bison-1.28.  */

/* Skeleton output parser for bison,
   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.

   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, 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., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

/* As a special exception, when this file is copied by Bison into a
   Bison output file, you may use that output file without restriction.
   This special exception was added by the Free Software Foundation
   in version 1.24 of Bison.  */

/* This is the parser code that is written into each bison parser
  when the %semantic_parser declaration is not specified in the grammar.
  It was written by Richard Stallman by simplifying the hairy parser
  used when %semantic_parser is specified.  */

#ifndef YYSTACK_USE_ALLOCA
#ifdef alloca
#define YYSTACK_USE_ALLOCA
#else /* alloca not defined */
#ifdef __GNUC__
#define YYSTACK_USE_ALLOCA
#define alloca __builtin_alloca
#else /* not GNU C.  */
#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
#define YYSTACK_USE_ALLOCA
#include <alloca.h>
#else /* not sparc */
/* We think this test detects Watcom and Microsoft C.  */
/* This used to test MSDOS, but that is a bad idea
   since that symbol is in the user namespace.  */
#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
#if 0 /* No need for malloc.h, which pollutes the namespace;
	 instead, just don't use alloca.  */
#include <malloc.h>
#endif
#else /* not MSDOS, or __TURBOC__ */
#if defined(_AIX)
/* I don't know what this was needed for, but it pollutes the namespace.
   So I turned it off.   rms, 2 May 1997.  */
/* #include <malloc.h>  */
 #pragma alloca
#define YYSTACK_USE_ALLOCA
#else /* not MSDOS, or __TURBOC__, or _AIX */
#if 0
#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
		 and on HPUX 10.  Eventually we can turn this on.  */
#define YYSTACK_USE_ALLOCA
#define alloca __builtin_alloca
#endif /* __hpux */
#endif
#endif /* not _AIX */
#endif /* not MSDOS, or __TURBOC__ */
#endif /* not sparc */
#endif /* not GNU C */
#endif /* alloca not defined */
#endif /* YYSTACK_USE_ALLOCA not defined */

#ifdef YYSTACK_USE_ALLOCA
#define YYSTACK_ALLOC alloca
#else
#define YYSTACK_ALLOC malloc
#endif

/* Note: there must be only one dollar sign in this file.
   It is replaced by the list of actions, each action
   as one case of the switch.  */

#define yyerrok		(yyerrstatus = 0)
#define yyclearin	(yychar = YYEMPTY)
#define YYEMPTY		-2
#define YYEOF		0
#define YYACCEPT	goto yyacceptlab
#define YYABORT 	goto yyabortlab
#define YYERROR		goto yyerrlab1
/* Like YYERROR except do call yyerror.
   This remains here temporarily to ease the
   transition to the new meaning of YYERROR, for GCC.
   Once GCC version 2 has supplanted version 1, this can go.  */
#define YYFAIL		goto yyerrlab
#define YYRECOVERING()  (!!yyerrstatus)
#define YYBACKUP(token, value) \
do								\
  if (yychar == YYEMPTY && yylen == 1)				\
    { yychar = (token), yylval = (value);			\
      yychar1 = YYTRANSLATE (yychar);				\
      YYPOPSTACK;						\
      goto yybackup;						\
    }								\
  else								\
    { yyerror ("syntax error: cannot back up"); YYERROR; }	\
while (0)

#define YYTERROR	1
#define YYERRCODE	256

#ifndef YYPURE
#define YYLEX		yylex()
#endif

#ifdef YYPURE
#ifdef YYLSP_NEEDED
#ifdef YYLEX_PARAM
#define YYLEX		yylex(&yylval, &yylloc, YYLEX_PARAM)
#else
#define YYLEX		yylex(&yylval, &yylloc)
#endif
#else /* not YYLSP_NEEDED */
#ifdef YYLEX_PARAM
#define YYLEX		yylex(&yylval, YYLEX_PARAM)
#else
#define YYLEX		yylex(&yylval)
#endif
#endif /* not YYLSP_NEEDED */
#endif

/* If nonreentrant, generate the variables here */

#ifndef YYPURE

int	yychar;			/*  the lookahead symbol		*/
YYSTYPE	yylval;			/*  the semantic value of the		*/
				/*  lookahead symbol			*/

#ifdef YYLSP_NEEDED
YYLTYPE yylloc;			/*  location data for the lookahead	*/
				/*  symbol				*/
#endif

int yynerrs;			/*  number of parse errors so far       */
#endif  /* not YYPURE */

#if YYDEBUG != 0
int yydebug;			/*  nonzero means print parse trace	*/
/* Since this is uninitialized, it does not stop multiple parsers
   from coexisting.  */
#endif

/*  YYINITDEPTH indicates the initial size of the parser's stacks	*/

#ifndef	YYINITDEPTH
#define YYINITDEPTH 200
#endif

/*  YYMAXDEPTH is the maximum size the stacks can grow to
    (effective only if the built-in stack extension method is used).  */

#if YYMAXDEPTH == 0
#undef YYMAXDEPTH
#endif

#ifndef YYMAXDEPTH
#define YYMAXDEPTH 10000
#endif

/* Define __yy_memcpy.  Note that the size argument
   should be passed with type unsigned int, because that is what the non-GCC
   definitions require.  With GCC, __builtin_memcpy takes an arg
   of type size_t, but it can handle unsigned int.  */

#if __GNUC__ > 1		/* GNU C and GNU C++ define this.  */
#define __yy_memcpy(TO,FROM,COUNT)	__builtin_memcpy(TO,FROM,COUNT)
#else				/* not GNU C or C++ */
#ifndef __cplusplus

/* This is the most reliable way to avoid incompatibilities
   in available built-in functions on various systems.  */
static void
__yy_memcpy (to, from, count)
     char *to;
     char *from;
     unsigned int count;
{
  register char *f = from;
  register char *t = to;
  register int i = count;

  while (i-- > 0)
    *t++ = *f++;
}

#else /* __cplusplus */

/* This is the most reliable way to avoid incompatibilities
   in available built-in functions on various systems.  */
static void
__yy_memcpy (char *to, char *from, unsigned int count)
{
  register char *t = to;
  register char *f = from;
  register int i = count;

  while (i-- > 0)
    *t++ = *f++;
}

#endif
#endif



/* The user can define YYPARSE_PARAM as the name of an argument to be passed
   into yyparse.  The argument should have type void *.
   It should actually point to an object.
   Grammar actions can access the variable by casting it
   to the proper pointer type.  */

#ifdef YYPARSE_PARAM
#ifdef __cplusplus
#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
#define YYPARSE_PARAM_DECL
#else /* not __cplusplus */
#define YYPARSE_PARAM_ARG YYPARSE_PARAM
#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
#endif /* not __cplusplus */
#else /* not YYPARSE_PARAM */
#define YYPARSE_PARAM_ARG
#define YYPARSE_PARAM_DECL
#endif /* not YYPARSE_PARAM */

/* Prevent warning if -Wstrict-prototypes.  */
#ifdef __GNUC__
#ifdef YYPARSE_PARAM
int yyparse (void *);
#else
int yyparse (void);
#endif
#endif

int
yyparse(YYPARSE_PARAM_ARG)
     YYPARSE_PARAM_DECL
{
  register int yystate;
  register int yyn;
  register short *yyssp;
  register YYSTYPE *yyvsp;
  int yyerrstatus;	/*  number of tokens to shift before error messages enabled */
  int yychar1 = 0;		/*  lookahead token as an internal (translated) token number */

  short	yyssa[YYINITDEPTH];	/*  the state stack			*/
  YYSTYPE yyvsa[YYINITDEPTH];	/*  the semantic value stack		*/

  short *yyss = yyssa;		/*  refer to the stacks thru separate pointers */
  YYSTYPE *yyvs = yyvsa;	/*  to allow yyoverflow to reallocate them elsewhere */

#ifdef YYLSP_NEEDED
  YYLTYPE yylsa[YYINITDEPTH];	/*  the location stack			*/
  YYLTYPE *yyls = yylsa;
  YYLTYPE *yylsp;

#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
#else
#define YYPOPSTACK   (yyvsp--, yyssp--)
#endif

  int yystacksize = YYINITDEPTH;
  int yyfree_stacks = 0;

#ifdef YYPURE
  int yychar;
  YYSTYPE yylval;
  int yynerrs;
#ifdef YYLSP_NEEDED
  YYLTYPE yylloc;
#endif
#endif

  YYSTYPE yyval;		/*  the variable used to return		*/
				/*  semantic values from the action	*/
				/*  routines				*/

  int yylen;

#if YYDEBUG != 0
  if (yydebug)
    fprintf(stderr, "Starting parse\n");
#endif

  yystate = 0;
  yyerrstatus = 0;
  yynerrs = 0;
  yychar = YYEMPTY;		/* Cause a token to be read.  */

  /* Initialize stack pointers.
     Waste one element of value and location stack
     so that they stay on the same level as the state stack.
     The wasted elements are never initialized.  */

  yyssp = yyss - 1;
  yyvsp = yyvs;
#ifdef YYLSP_NEEDED
  yylsp = yyls;
#endif

/* Push a new state, which is found in  yystate  .  */
/* In all cases, when you get here, the value and location stacks
   have just been pushed. so pushing a state here evens the stacks.  */
yynewstate:

  *++yyssp = yystate;

  if (yyssp >= yyss + yystacksize - 1)
    {
      /* Give user a chance to reallocate the stack */
      /* Use copies of these so that the &'s don't force the real ones into memory. */
      YYSTYPE *yyvs1 = yyvs;
      short *yyss1 = yyss;
#ifdef YYLSP_NEEDED
      YYLTYPE *yyls1 = yyls;
#endif

      /* Get the current used size of the three stacks, in elements.  */
      int size = (int)(yyssp - yyss + 1);

#ifdef yyoverflow
      /* Each stack pointer address is followed by the size of
	 the data in use in that stack, in bytes.  */
#ifdef YYLSP_NEEDED
      /* This used to be a conditional around just the two extra args,
	 but that might be undefined if yyoverflow is a macro.  */
      yyoverflow("parser stack overflow",
		 &yyss1, size * sizeof (*yyssp),
		 &yyvs1, size * sizeof (*yyvsp),
		 &yyls1, size * sizeof (*yylsp),
		 &yystacksize);
#else
      yyoverflow("parser stack overflow",
		 &yyss1, size * sizeof (*yyssp),
		 &yyvs1, size * sizeof (*yyvsp),
		 &yystacksize);
#endif

      yyss = yyss1; yyvs = yyvs1;
#ifdef YYLSP_NEEDED
      yyls = yyls1;
#endif
#else /* no yyoverflow */
      /* Extend the stack our own way.  */
      if (yystacksize >= YYMAXDEPTH)
	{
	  yyerror("parser stack overflow");
	  if (yyfree_stacks)
	    {
	      free (yyss);
	      free (yyvs);
#ifdef YYLSP_NEEDED
	      free (yyls);
#endif
	    }
	  return 2;
	}
      yystacksize *= 2;
      if (yystacksize > YYMAXDEPTH)
	yystacksize = YYMAXDEPTH;
#ifndef YYSTACK_USE_ALLOCA
      yyfree_stacks = 1;
#endif
      yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
      __yy_memcpy ((char *)yyss, (char *)yyss1,
		   size * (unsigned int) sizeof (*yyssp));
      yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
      __yy_memcpy ((char *)yyvs, (char *)yyvs1,
		   size * (unsigned int) sizeof (*yyvsp));
#ifdef YYLSP_NEEDED
      yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
      __yy_memcpy ((char *)yyls, (char *)yyls1,
		   size * (unsigned int) sizeof (*yylsp));
#endif
#endif /* no yyoverflow */

      yyssp = yyss + size - 1;
      yyvsp = yyvs + size - 1;
#ifdef YYLSP_NEEDED
      yylsp = yyls + size - 1;
#endif

#if YYDEBUG != 0
      if (yydebug)
	fprintf(stderr, "Stack size increased to %d\n", yystacksize);
#endif

      if (yyssp >= yyss + yystacksize - 1)
	YYABORT;
    }

#if YYDEBUG != 0
  if (yydebug)
    fprintf(stderr, "Entering state %d\n", yystate);
#endif

  goto yybackup;
 yybackup:

/* Do appropriate processing given the current state.  */
/* Read a lookahead token if we need one and don't already have one.  */
/* yyresume: */

  /* First try to decide what to do without reference to lookahead token.  */

  yyn = yypact[yystate];
  if (yyn == YYFLAG)
    goto yydefault;

  /* Not known => get a lookahead token if don't already have one.  */

  /* yychar is either YYEMPTY or YYEOF
     or a valid token in external form.  */

  if (yychar == YYEMPTY)
    {
#if YYDEBUG != 0
      if (yydebug)
	fprintf(stderr, "Reading a token: ");
#endif
      yychar = YYLEX;
    }

  /* Convert token to internal form (in yychar1) for indexing tables with */

  if (yychar <= 0)		/* This means end of input. */
    {
      yychar1 = 0;
      yychar = YYEOF;		/* Don't call YYLEX any more */

#if YYDEBUG != 0
      if (yydebug)
	fprintf(stderr, "Now at end of input.\n");
#endif
    }
  else
    {
      yychar1 = YYTRANSLATE(yychar);

#if YYDEBUG != 0
      if (yydebug)
	{
	  fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
	  /* Give the individual parser a way to print the precise meaning
	     of a token, for further debugging info.  */
#ifdef YYPRINT
	  YYPRINT (stderr, yychar, yylval);
#endif
	  fprintf (stderr, ")\n");
	}
#endif
    }

  yyn += yychar1;
  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
    goto yydefault;

  yyn = yytable[yyn];

  /* yyn is what to do for this token type in this state.
     Negative => reduce, -yyn is rule number.
     Positive => shift, yyn is new state.
       New state is final state => don't bother to shift,
       just return success.
     0, or most negative number => error.  */

  if (yyn < 0)
    {
      if (yyn == YYFLAG)
	goto yyerrlab;
      yyn = -yyn;
      goto yyreduce;
    }
  else if (yyn == 0)
    goto yyerrlab;

  if (yyn == YYFINAL)
    YYACCEPT;

  /* Shift the lookahead token.  */

#if YYDEBUG != 0
  if (yydebug)
    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
#endif

  /* Discard the token being shifted unless it is eof.  */
  if (yychar != YYEOF)
    yychar = YYEMPTY;

  *++yyvsp = yylval;
#ifdef YYLSP_NEEDED
  *++yylsp = yylloc;
#endif

  /* count tokens shifted since error; after three, turn off error status.  */
  if (yyerrstatus) yyerrstatus--;

  yystate = yyn;
  goto yynewstate;

/* Do the default action for the current state.  */
yydefault:

  yyn = yydefact[yystate];
  if (yyn == 0)
    goto yyerrlab;

/* Do a reduction.  yyn is the number of a rule to reduce with.  */
yyreduce:
  yylen = yyr2[yyn];
  if (yylen > 0)
    yyval = yyvsp[1-yylen]; /* implement default value of the action */

#if YYDEBUG != 0
  if (yydebug)
    {
      int i;

      fprintf (stderr, "Reducing via rule %d (line %d), ",
	       yyn, yyrline[yyn]);

      /* Print the symbols being reduced, and their result.  */
      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
	fprintf (stderr, "%s ", yytname[yyrhs[i]]);
      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
    }
#endif


  switch (yyn) {

case 8:
{store_res(&yyvsp[-1]); return 0;;
    break;}
case 9:
{store_res(&yyvsp[-1]); return 0;;
    break;}
case 10:
{store_res(&yyvsp[-1]); return 0;;
    break;}
case 11:
{store_res(&yyvsp[-1]); return 0;;
    break;}
case 12:
{if(block_res = eval(&yyval, &yyvsp[-1]))return block_res; 
				if(yyval.val != 0.0) if(block_res = eval(&yyval, &yyvsp[0]))return block_res;;
    break;}
case 13:
{if(block_res = eval(&yyval, &yyvsp[-3])) return block_res; 
				if(yyval.val != 0.0) {if(block_res = eval(&yyval, &yyvsp[-2])) return block_res;} 
				else if(block_res = eval(&yyval, &yyvsp[0])) return block_res;;
    break;}
case 14:
{block_res = for_loop(yyvsp[-1].text, yyvsp[0].text); if(block_res == 1 || block_res == 2) return block_res;;
    break;}
case 15:
{for(int i=0; i< yy_maxiter; i++){ if(block_res = eval(&yyval, &yyvsp[-1]))return block_res; 
					if(yyval.val != 0.0){if(block_res = eval(&yyval, &yyvsp[0]))return block_res;} else break;};
    break;}
case 16:
{if(block_res = eval(&yyval, &yyvsp[0]) == 1) return 1; else return 2;;
    break;}
case 17:
{return 3;;
    break;}
case 18:
{yyerrok;;
    break;}
case 19:
{;;
    break;}
case 20:
{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type = STR;;
    break;}
case 21:
{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type = STR;;
    break;}
case 22:
{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type = STR;;
    break;}
case 23:
{if(yyvsp[-3].tptr->fnctptr)((yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;;
    break;}
case 24:
{if(yyvsp[-5].tptr->fnctptr)((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
    break;}
case 25:
{;;
    break;}
case 26:
{;;
    break;}
case 27:
{if(!yyval.a_data) {yyval.a_data = PushArray((double*)malloc(sizeof(double))); yyval.a_count = 1; yyval.a_data[0] = yyval.val;};
    break;}
case 28:
{push(&yyval, &yyvsp[0]);yyval.type = ARR;;
    break;}
case 29:
{exec_clause(&yyval);;
    break;}
case 30:
{range_array(&yyval, yyvsp[0].text);;
    break;}
case 31:
{if(yyvsp[-2].val < yyvsp[0].val && (yyval.a_data = PushArray((double*)malloc((int)(yyvsp[0].val-yyvsp[-2].val+2)*sizeof(double)))))
					for(yyval.a_count=0; yyvsp[-2].val<=yyvsp[0].val; yyval.a_data[yyval.a_count++] = yyvsp[-2].val, yyvsp[-2].val += 1.0 ); yyval.type = ARR;;
    break;}
case 33:
{yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)): 0.0; yyval.type = BOOLVAL;;
    break;}
case 34:
{yyval.val = 1.0; yyval.type = BOOLVAL;;
    break;}
case 35:
{yyval.val = 0.0; yyval.type = BOOLVAL;;
    break;}
case 36:
{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], AND);;
    break;}
case 37:
{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], OR);;
    break;}
case 38:
{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], EQ);;
    break;}
case 39:
{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], NE);;
    break;}
case 40:
{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], GT);;
    break;}
case 41:
{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], GE);;
    break;}
case 42:
{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], LT);;
    break;}
case 43:
{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], LE);;
    break;}
case 48:
{yyval.val = yyvsp[0].val; yyval.type = NUM;;
    break;}
case 50:
{yyval.val = yyvsp[0].val; yyval.type = BOOLVAL;;
    break;}
case 51:
{yyval.val = 0.0;;
    break;}
case 52:
{yyval.val = syntax_level ? syntax_level->clval : 0.0;  yyval.type = NUM;;
    break;}
case 53:
{yyval.val = _PI; yyval.type = NUM;;
    break;}
case 54:
{yyval.val = 2.71828182845905; yyval.type = NUM;;
    break;}
case 55:
{if(yyvsp[0].tptr)yyvsp[0].tptr->GetValue(&yyval);;
    break;}
case 56:
{if(block_res = eval(&yyval, &yyvsp[0]))return block_res;;
    break;}
case 57:
{if(yyvsp[-2].tptr)yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
    break;}
case 58:
{if(yyvsp[-2].tptr)yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
    break;}
case 59:
{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val + yyvsp[0].val);};
    break;}
case 60:
{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val - yyvsp[0].val);};
    break;}
case 61:
{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val * yyvsp[0].val);};
    break;}
case 62:
{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyvsp[0].val != 0.0 ? yyval.val / yyvsp[0].val :
		(getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue());};
    break;}
case 63:
{yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)): 0.0; yyval.type = NUM;;
    break;}
case 64:
{yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(proc_clause(&yyvsp[-1]))) : 0.0; yyval.type = NUM; yyval.a_data = 0L; yyval.a_count = 0; yyval.text = 0L;;
    break;}
case 65:
{ if(!yyval.a_data){yyval.a_data=PushArray((double*)malloc(sizeof(double)));yyval.a_data[0]=yyvsp[-3].val;yyval.a_count=1;}
		push(&yyval, &yyvsp[-1]);yyval.val = yyvsp[-5].tptr->fnctptr ?((yyvsp[-5].tptr->fnctptr)(&yyval)):0.0; yyval.type = NUM;;
    break;}
case 66:
{ yyval.a_data = PushArray((double*)malloc(3*sizeof(double)));
		yyval.a_count = 3; yyval.a_data[0] = yyvsp[-5].val; yyval.a_data[1] = yyvsp[-3].val; yyval.a_data[2] = yyvsp[-1].val;	
		yyval.val = yyvsp[-7].tptr->fnctptr ? ((yyvsp[-7].tptr->fnctptr)(&yyval)) : 0.0; yyval.type = NUM;;
    break;}
case 67:
{yyval.type = NUM; yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;;
    break;}
case 68:
{yyval.type = NUM; yyvsp[-1].text = string_value(&yyvsp[-1]); yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;;
    break;}
case 69:
{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
    break;}
case 70:
{proc_clause(&yyvsp[-3]); yyval.val=yyvsp[-9].tptr->fnctptr ? (*yyvsp[-9].tptr->fnctptr)(yyvsp[-7].val, yyvsp[-5].val, &yyvsp[-3], &yyvsp[-1]) : 0.0; yyval.type = NUM;;
    break;}
case 71:
{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;;
    break;}
case 72:
{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;;
    break;}
case 73:
{if(yyvsp[-2].tptr->fnctptr)(*yyvsp[-2].tptr->fnctptr)(&yyval, 0L);;
    break;}
case 74:
{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1]);;
    break;}
case 75:
{if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
    break;}
case 76:
{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L);;
    break;}
case 77:
{if(yyvsp[-7].tptr->fnctptr)(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
    break;}
case 78:
{if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1], 0L);;
    break;}
case 79:
{yyval.val = yyvsp[-2].val + yyvsp[0].val; yyval.type = NUM;
				if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
				else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
				else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;;
    break;}
case 80:
{yyval.val = yyvsp[-2].val - yyvsp[0].val; yyval.type = NUM;
				if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
				else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
				else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;;
    break;}
case 81:
{yyval.val = yyvsp[-2].val * yyvsp[0].val; yyval.type = NUM;;
    break;}
case 82:
{yyval.type = NUM; if(yyvsp[0].val != 0.0) yyval.val = yyvsp[-2].val / yyvsp[0].val;
					else yyval.val = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue(); ;
    break;}
case 83:
{yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val+1.0); yyval.val -= 1.0; yyval.type = NUM;;
    break;}
case 84:
{yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val-1.0); yyval.val += 1.0; yyval.type = NUM;;
    break;}
case 85:
{yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val+1.0); yyval.type = NUM;;
    break;}
case 86:
{yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val-1.0); yyval.type = NUM;;
    break;}
case 87:
{yyval.val = (yyvsp[0].val >0 && yyvsp[0].val/2.0 == floor(yyvsp[0].val/2.0)) ? fabs(pow(yyvsp[-2].val,yyvsp[0].val) ): pow(yyvsp[-2].val, yyvsp[0].val); yyval.type = NUM;;
    break;}
case 88:
{yyval.val = -yyvsp[0].val; yyval.type = NUM;;
    break;}
case 89:
{memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;;
    break;}
case 90:
{yyval.a_data = PushArray((double*)calloc((int)yyvsp[-1].val, sizeof(double))); yyval.a_count=(int)(yyvsp[-1].val); 
					yyval.type = ARR; yyvsp[-3].tptr->SetValue(&yyval,&yyval);;
    break;}
case 91:
{if(yyvsp[-3].a_data && yyvsp[-1].val >= 0.0 && yyvsp[-1].val < yyvsp[-3].a_count) yyval.val = yyvsp[-3].a_data[(int)yyvsp[-1].val];
				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.a_data = 0L; yyval.a_count = 0; yyval.type = NUM;;
    break;}
case 92:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count)
				{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] = yyvsp[0].val; 
				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
    break;}
case 93:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
				{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] += yyvsp[0].val;
				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
    break;}
case 94:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
				{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] -= yyvsp[0].val;
				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
    break;}
case 95:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
				{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] *= yyvsp[0].val;
				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
    break;}
case 96:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count){ 
				if(yyvsp[0].val != 0.0) {yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] /= yyvsp[0].val;
				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
				else {yyval.val = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue();}}
				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
    break;}
case 97:
{make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
    break;}
case 98:
{make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);;
    break;}
case 99:
{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
    break;}
case 100:
{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
    break;}
case 101:
{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
    break;}
case 102:
{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
    break;}
}
   /* the action file gets copied in in place of this dollarsign */


  yyvsp -= yylen;
  yyssp -= yylen;
#ifdef YYLSP_NEEDED
  yylsp -= yylen;
#endif

#if YYDEBUG != 0
  if (yydebug)
    {
      short *ssp1 = yyss - 1;
      fprintf (stderr, "state stack now");
      while (ssp1 != yyssp)
	fprintf (stderr, " %d", *++ssp1);
      fprintf (stderr, "\n");
    }
#endif

  *++yyvsp = yyval;

#ifdef YYLSP_NEEDED
  yylsp++;
  if (yylen == 0)
    {
      yylsp->first_line = yylloc.first_line;
      yylsp->first_column = yylloc.first_column;
      yylsp->last_line = (yylsp-1)->last_line;
      yylsp->last_column = (yylsp-1)->last_column;
      yylsp->text = 0;
    }
  else
    {
      yylsp->last_line = (yylsp+yylen-1)->last_line;
      yylsp->last_column = (yylsp+yylen-1)->last_column;
    }
#endif

  /* Now "shift" the result of the reduction.
     Determine what state that goes to,
     based on the state we popped back to
     and the rule number reduced by.  */

  yyn = yyr1[yyn];

  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
    yystate = yytable[yystate];
  else
    yystate = yydefgoto[yyn - YYNTBASE];

  goto yynewstate;

yyerrlab:   /* here on detecting error */

  if (! yyerrstatus)
    /* If not already recovering from an error, report this error.  */
    {
      ++yynerrs;

#ifdef YYERROR_VERBOSE
      yyn = yypact[yystate];

      if (yyn > YYFLAG && yyn < YYLAST)
	{
	  int size = 0;
	  char *msg;
	  int x, count;

	  count = 0;
	  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
	  for (x = (yyn < 0 ? -yyn : 0);
	       x < (sizeof(yytname) / sizeof(char *)); x++)
	    if (yycheck[x + yyn] == x)
	      size += strlen(yytname[x]) + 15, count++;
	  msg = (char *) malloc(size + 15);
	  if (msg != 0)
	    {
	      strcpy(msg, "parse error");

	      if (count < 5)
		{
		  count = 0;
		  for (x = (yyn < 0 ? -yyn : 0);
		       x < (sizeof(yytname) / sizeof(char *)); x++)
		    if (yycheck[x + yyn] == x)
		      {
			strcat(msg, count == 0 ? ", expecting `" : " or `");
			strcat(msg, yytname[x]);
			strcat(msg, "'");
			count++;
		      }
		}
	      yyerror(msg);
	      free(msg);
	    }
	  else
	    yyerror ("parse error; also virtual memory exceeded");
	}
      else
#endif /* YYERROR_VERBOSE */
	yyerror("parse error");
    }

  goto yyerrlab1;
yyerrlab1:   /* here on error raised explicitly by an action */

  if (yyerrstatus == 3)
    {
      /* if just tried and failed to reuse lookahead token after an error, discard it.  */

      /* return failure if at end of input */
      if (yychar == YYEOF)
	YYABORT;

#if YYDEBUG != 0
      if (yydebug)
	fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
#endif

      yychar = YYEMPTY;
    }

  /* Else will try to reuse lookahead token
     after shifting the error token.  */

  yyerrstatus = 3;		/* Each real token shifted decrements this */

  goto yyerrhandle;

yyerrdefault:  /* current state does not do anything special for the error token. */

#if 0
  /* This is wrong; only states that explicitly want error tokens
     should shift them.  */
  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
  if (yyn) goto yydefault;
#endif

yyerrpop:   /* pop the current state because it cannot handle the error token */

  if (yyssp == yyss) YYABORT;
  yyvsp--;
  yystate = *--yyssp;
#ifdef YYLSP_NEEDED
  yylsp--;
#endif

#if YYDEBUG != 0
  if (yydebug)
    {
      short *ssp1 = yyss - 1;
      fprintf (stderr, "Error: state stack now");
      while (ssp1 != yyssp)
	fprintf (stderr, " %d", *++ssp1);
      fprintf (stderr, "\n");
    }
#endif

yyerrhandle:

  yyn = yypact[yystate];
  if (yyn == YYFLAG)
    goto yyerrdefault;

  yyn += YYTERROR;
  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
    goto yyerrdefault;

  yyn = yytable[yyn];
  if (yyn < 0)
    {
      if (yyn == YYFLAG)
	goto yyerrpop;
      yyn = -yyn;
      goto yyreduce;
    }
  else if (yyn == 0)
    goto yyerrpop;

  if (yyn == YYFINAL)
    YYACCEPT;

#if YYDEBUG != 0
  if (yydebug)
    fprintf(stderr, "Shifting error token, ");
#endif

  *++yyvsp = yylval;
#ifdef YYLSP_NEEDED
  *++yylsp = yylloc;
#endif

  yystate = yyn;
  goto yynewstate;

 yyacceptlab:
  /* YYACCEPT comes here.  */
  if (yyfree_stacks)
    {
      free (yyss);
      free (yyvs);
#ifdef YYLSP_NEEDED
      free (yyls);
#endif
    }
  return 0;

 yyabortlab:
  /* YYABORT comes here.  */
  if (yyfree_stacks)
    {
      free (yyss);
      free (yyvs);
#ifdef YYLSP_NEEDED
      free (yyls);
#endif
    }
  return 1;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Cache spreadsheet data for repeated access
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SsRangeData {
typedef struct _rng_data {
	_rng_data *next;
	unsigned int h1, h2;
	RECT rec;
	double *vals;
	char *name;
	int nvals;
	double dSum, dMean, dQuart1, dQuart2, dQuart3;
	bool bSum, bMean, bQuart1, bQuart2, bQuart3;
	}rng_data;

public:
	SsRangeData();
	~SsRangeData();
	void Clear();
	bool GetData(char *rng_desc,  double **vals, int *nvals, char **name);
	void rmData(double *vals, int nvals);
	void cellModified(int row, int col);
	double sum(double *vals, int nvals);
	double mean(double *vals, int nvals);
	double quartile1(double *vals, int nvals);
	double quartile2(double *vals, int nvals);
	double quartile3(double *vals, int nvals);

private:
	rng_data *RngData;

	bool FindData(unsigned int h1, unsigned int h2, rng_data **rda);
	bool FindData(double *vals, int nvals, rng_data **rda);
	bool SetArray(rng_data *rda, char *range);
	void do_quartiles(rng_data *rda);
}; 
 
SsRangeData::SsRangeData()
{
	RngData = 0L;
} 

SsRangeData::~SsRangeData()
{
	Clear();
}

void
SsRangeData::Clear()
{
	rng_data *nxt;

	nxt = RngData;
	while(nxt) {
		nxt = RngData->next;
		if(RngData->vals) free(RngData->vals);
		if(RngData->name) free(RngData->name);
		free(RngData); 		RngData = nxt;
		}
}

bool
SsRangeData::FindData(unsigned int h1, unsigned int h2, rng_data **rda)
{ 
	rng_data *nxt;

	nxt = RngData;
	while(nxt) {
		if(nxt->h1 == h1 && nxt->h2 == h2) {
			*rda = nxt; 	return true;
			}
		nxt = nxt->next;
		}
	return false;
}

bool
SsRangeData::FindData(double *vals, int nvals, rng_data **rda)
{
	rng_data *nxt;

	nxt = RngData;
	while(nxt) {
		if(nxt->vals == vals && nxt->nvals == nvals) {
			*rda = nxt;	return true;
			}
		nxt = nxt->next;
		}
	return false;
}

bool
SsRangeData::SetArray(rng_data *rda, char *range)
{ 
	AccRange *r;
	int row, col;
	anyResult ares;

	if(!range || !range[0] || !(r = new AccRange(range))) return false;
	if(!r->GetFirst(&col, &row) || !(rda->vals =  (double*)malloc(r->CountItems() * sizeof(double)))) {
		delete(r); 		return false;
		} 
	r->BoundRec(&rda->rec);
	parse_level++;			r->GetFirst(&col, &row);
	for(rda->nvals = 0; r->GetNext(&col, &row); ) {
		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)) {
			switch(ares.type) {
			case ET_VALUE:	case ET_TIME:	case ET_DATE:	case ET_DATETIME:	case ET_BOOL:
				rda->vals[rda->nvals++] = ares.value;
				break;
				}
			}
		}
	rda->name = (char*)memdup(range, (int)strlen(range)+1, 0);
	parse_level--;
	delete(r);
	return true;
}

void
SsRangeData::rmData(double *vals, int nvals)
{
	rng_data *rda, *rmrda;

	if(!FindData(vals, nvals, &rmrda)) return;
	if(rmrda == RngData) RngData = RngData->next;
	else {
		rda = RngData;
		while(rda->next && rda->next != rmrda) rda = rda->next;
		if(rda->next == rmrda) rda->next = rmrda->next;
		else return;
		}
	rda = RngData;
	while(rda) {
		if(((rda->rec.top <= rmrda->rec.top && rda->rec.bottom >= rmrda->rec.top)
			|| (rda->rec.top <= rmrda->rec.bottom && rda->rec.top >= rmrda->rec.top))
			&&((rda->rec.left <= rmrda->rec.left && rda->rec.right >= rmrda->rec.left)
			|| (rda->rec.left <= rmrda->rec.right && rda->rec.left >= rmrda->rec.left))){
			rmData(rda->vals, rda->nvals);
			rda = RngData;
			}
		else rda = rda->next;
		}
	if(rmrda->vals) free(rmrda->vals);
	if(rmrda->name) free(rmrda->name);
	free(rmrda);
}

void
SsRangeData::cellModified(int row, int col)
{
	rng_data *nxt;

	nxt = RngData;
	while(nxt) {
		if(col >= nxt->rec.left && col <= nxt->rec.right && row >= nxt->rec.top && col <= nxt->rec.bottom){
			rmData(nxt->vals, nxt->nvals);
			nxt = RngData;
			}
		else nxt = nxt->next;
		}
	return;
}

void
SsRangeData::do_quartiles(rng_data *rda)
{
	double *vals;

	if(rda->vals && rda->nvals && (vals = (double*)memdup(rda->vals, rda->nvals*sizeof(double), 0))){
		d_quartile(rda->nvals, vals, &rda->dQuart1, &rda->dQuart2, &rda->dQuart3);
		free(vals);
		}
	rda->bQuart1 = rda->bQuart2 = rda->bQuart3 = true;
}

bool  
SsRangeData::GetData(char *rng_desc, double **vals, int *nvals, char **name)
{ 
	rng_data *rda;
	unsigned int h1, h2;

	h1 = HashValue((unsigned char*) rng_desc);
	h2 = Hash2((unsigned char*) rng_desc);
	if(FindData(h1, h2, &rda)) {
		*vals = rda->vals;	*nvals = rda->nvals;
		if(name) *name = rda->name;
		return true;
		}
	if(!(rda = (rng_data*) calloc(1, sizeof(rng_data))))return false;
	SetArray(rda, rng_desc);
	*vals = rda->vals; 		*nvals = rda->nvals;
	if(name) *name = rda->name;
	rda->h1 = h1; 			rda->h2 = h2; 
	rda->next = RngData;		RngData = rda;
	return true;
}

double
SsRangeData::sum(double *vals, int nvals)
{
	rng_data *rda;
	int i;
	double tmp;

	if(FindData(vals, nvals, &rda)) {
		if(rda->bSum) return rda->dSum;
		for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i];
		rda->dSum = tmp;	rda->bSum = true;
		return rda->dSum;
		}
	for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i];
	return tmp;
}

double
SsRangeData::mean(double *vals, int nvals)
{
	rng_data *rda;

	if(FindData(vals, nvals, &rda)) {
		if(rda->bMean) return rda->dMean;
		rda->dMean = d_amean(nvals, vals);
		rda->bMean = true;
		return rda->dMean;
		}
	return d_amean(nvals, vals);
}

double
SsRangeData::quartile1(double *vals, int nvals)
{
	rng_data *rda;

	if(FindData(vals, nvals, &rda)) {
		if(rda->bQuart1) return rda->dQuart1;
		do_quartiles(rda);	return rda->dQuart1;
		}
	return HUGE_VAL;
}

double
SsRangeData::quartile2(double *vals, int nvals)
{
	rng_data *rda;

	if(FindData(vals, nvals, &rda)) {
		if(rda->bQuart2) return rda->dQuart2;
		do_quartiles(rda);	return rda->dQuart2;
		}
	return HUGE_VAL;
}

double
SsRangeData::quartile3(double *vals, int nvals)
{
	rng_data *rda;

	if(FindData(vals, nvals, &rda)) {
		if(rda->bQuart3) return rda->dQuart3;
		do_quartiles(rda);	return rda->dQuart3;
		}
	return HUGE_VAL;
}

static SsRangeData RangeData;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The symrec class
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt) 
{
	h_name = h_n;	h2_name = h2_n;		type = typ;
	next = nxt;	row = col = -1;		name = text = 0L;
	var = 0.0;	isSSval = isValid = false;
	a_data = 0L;	a_count = 0;
	fnctptr = (double (*)(...))nop;
}

symrec::~symrec()
{
	if(name) free(name);		name = 0L;
	if(text) free(text);		text = 0L;
}

double
symrec::GetValue()
{
	anyResult ares;

	if(isSSval && !bNoSS) {
		if(row < 0 && col < 0) InitSS();
		//GetResult( , , ,true) inhibits reentrance into parser !
		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){
			return var = ares.value;
			}
		isSSval = false;
		row = col = -1;
		}
	if(!isValid) NoInit();
	return var;
}

void
symrec::GetValue(void *re)
{
	anyResult ares;
	YYSTYPE *res = (YYSTYPE*)re;
	int i;

	if(!res) return;
	if(isSSval && !bNoSS) {
		if(row < 0 && col < 0) InitSS();
		res->a_data = 0L;	res->a_count = 0;
		//GetResult( , , ,true) inhibits reentrance into parser !
		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){
			isValid = true;
			if(text) free(text);		text = 0L;
			switch(ares.type) {
			case ET_VALUE:
				res->type = NUM;	res->val = ares.value;
				res->text = 0L;		break;
			case ET_BOOL:
				res->type = BOOLVAL;	res->val = ares.value;
				res->text = 0L;		break;
			case ET_DATE:
				res->type = DATE1;	res->val = ares.value;
				res->text = 0L;		break;
			case ET_TIME:
				res->type = TIME1;	res->val = ares.value;
				res->text = 0L;		break;
			case ET_DATETIME:
				res->type = DATETIME1;	res->val = ares.value;
				res->text = 0L;		break;
			case ET_TEXT:
				i = 0;			res->val = 0.0;
				if(ares.text) for( ; ares.text && ares.text[i] != ':'; i++);
				if(i > 1 && ares.text[i] 
					&& (isalpha(ares.text[0]) || ares.text[0] =='$')
					&& (isalpha(ares.text[i+1]) || ares.text[i+1] =='$')
					&& isdigit(ares.text[i-1])) {
					RangeData.GetData(ares.text, &res->a_data, &res->a_count, &res->text); 
					res->type = RANGEARR;
					}
				else {
					res->type = STR;
					if(ares.text) res->text = PushString(text = (char*)memdup(ares.text, (int)strlen(ares.text)+1, 0));
					else res->text = 0L;
					}
				break;
			default:
				res->type = NUM;	res->val = var;
				res->text = 0L;		break;
				}
			var = res->val;
			return;
			}
		isSSval = false;
		row = col = -1;
		}
	if(!isValid) NoInit();
	if(a_data && a_count) {
		res->text = 0L;		res->a_count = a_count;
		res->a_data = a_data;	res->val = 0.0;
		res->type = ARR;
		}
	else if(text && text[0]) {
		res->text = text;
		res->a_data = 0L;	res->a_count = 0;
		res->val = 0.0;		res->type = STR;
		}
	else {
		res->type = NUM;	res->val = var;
		res->a_data = 0L;	res->a_count = 0;
		res->text = 0L;
		}
}

double 
symrec::SetValue(double v)
{
	if(isSSval && !bNoWrite) {
		if(row < 0 && col < 0) InitSS();
		if(curr_data->SetValue(row, col, v)){
			if(curr_data) curr_data->Command(CMD_UPDATE, 0L, 0L);
			RangeData.cellModified(row, col);
			return var = v;
			}
		isSSval = false;
		row = col = -1;
		}
	isValid = true;
	a_data = 0L;	a_count = 0;
	return var = v;
}

void 
symrec::SetValue(void* d, void* s)
{
	YYSTYPE *dest = (YYSTYPE*)d;
	YYSTYPE *src = (YYSTYPE*)s;

	if(isSSval && curr_data && !bNoWrite) {
		if(row < 0 && col < 0) InitSS();
		if(last_err_desc) curr_data->SetText(row, col, last_err_desc);
		else if(src->type == STR) curr_data->SetText(row, col, src->text);
		else if(src->type == ARR || src->type == RANGEARR || (src->a_data)) 
			curr_data->SetText(row, col, "#ARRAY");
		else if(src->type == VAR && src->tptr->type == TXT) curr_data->SetText(row, col, src->tptr->text);
		else {
			if(curr_data->SetValue(row, col, src->val))
				switch(src->type) {
				case BOOLVAL:
					curr_data->etRows[row][col]->type = ET_BOOL;	break;
				}
			}
		curr_data->Command(CMD_UPDATE, 0L, 0L);
		RangeData.cellModified(row, col);
		}
	isValid = true;			var = src->val;
	if(src->a_data && src->a_count) {
		a_data = src->a_data;		a_count = src->a_count;
		}
	else if(src->text && src->text[0] && src->text != text) {
		if(text) free(text);		text = 0L;
		text =(char*)memdup(src->text, (int)strlen(src->text)+1, 0);
		}
	if(d) GetValue(d);
	return;
}

void
symrec::SetName(char *nam)
{
	if(name || !nam || !nam[0]) return;
	name = (char*)memdup(nam, (int)strlen(nam)+1, 0);
	isValid = false;
	if((name && curr_data) && (isalpha(name[0]) || name[0] == '$') && isdigit(name[strlen(name)-1])) isSSval=true;
}

void
symrec::InitSS()
{
	AccRange *ar;

	if(row<0 && col<0 &&(ar = new AccRange(name))) {
		ar->GetFirst(&col, &row);
		delete(ar);
		}
}

void
symrec::NoInit()
{
	char message[200];

#ifdef USE_WIN_SECURE
	sprintf_s(message, 80, "Accessing variable '%s'\nwithout initialization!\n", name);
#else
	sprintf(message, "Accessing variable '%s'\nwithout initialization!\n", name);
#endif
	yywarn(message, true);
}
 
void LockData(bool lockExec, bool lockWrite) 
{ 
	RangeData.Clear();
	bNoWrite = lockWrite;
	bNoExec = lockExec;
	bNoSS = false;
} 
 
static void yyerror(char *s)
{  
	//called by yyparse on error
	if(curr_data) curr_data->Command(CMD_ERROR, last_error = s, 0L);
	else printf("%s\n", s);
}

static void yyargserr(char *s)
{
	//call from function on argument type mismatch
	yyerror(s);	last_err_desc = "#ARGS";
}

static void yyargcnterr(char *s)
{
	//call from function on argument number mismatch
	static char arg_cnt_err[80];
	int cb;

	cb = rlp_strcpy(arg_cnt_err, 80, "Wrong number of arguments\nin call to ");
	cb += rlp_strcpy(arg_cnt_err+cb, 80-cb, s);
	rlp_strcpy(arg_cnt_err+cb, 80-cb, ".");
	yyargserr(arg_cnt_err);
}

static void yybadargerr(char *s)
{
	//call from function on argument number mismatch
	static char bad_arg_err[80];
	int cb;

	cb = rlp_strcpy(bad_arg_err, 80, "Bad arguments in call to function\n");
	cb += rlp_strcpy(bad_arg_err+cb, 80-cb, s);
	rlp_strcpy(bad_arg_err+cb, 80-cb, ".");
	yyargserr(bad_arg_err);
}


static char txt_tokenerr[80];
static void yytokenerr(int c)
{
#ifdef USE_WIN_SECURE
	sprintf_s(txt_tokenerr, 80, "Illegal character\nor token '%c'\n", (char)c);
#else
	sprintf(txt_tokenerr, "Illegal character\nor token '%c'\n", (char)c);
#endif
	yyerror(txt_tokenerr);
}

static void make_time(YYSTYPE *dst, double h, double m, double s)
{
	if(!dst || h < 0.0 || 24.0 < h || m < 0.0 || 60.0 < m || s < 0.0 || 60.0 < s) {
		yyerror("parse error");			return;
		}
	dst->val = s/60.0 + m;		dst->val = dst->val/60.0 + h;
	dst->val /= 24.0;		dst->type = TIME1;
}

static char yywarn_text[200];
char  *yywarn(char *txt, bool bNew)
{
	if(bNew) {
		if(txt && txt[0]) {
			rlp_strcpy(yywarn_text, 200, txt);
			return yywarn_text;
			}
		else {
			yywarn_text[0] = 0;
			return 0L;
			}
		}
	else if(yywarn_text[0]) return yywarn_text;
	else return 0L;
}

static void yyCompare(YYSTYPE *res, YYSTYPE *arg1, YYSTYPE *arg2, int op)
{
	int cmp;

	if(!res || !arg1 || !arg2) return;
	if(arg1->type == STR && arg2->type == STR) {
		if (arg1->text && arg1->text[0] && arg2->text
			&& arg2->text[0]) cmp = strcmp(arg1->text, arg2->text);
		else if(arg1->text && arg1->text[0]) cmp = 1;
		else if(arg2->text && arg2->text[0]) cmp = -1;
		else cmp = 0;
		switch(op) {
		case AND:
			res->val = (arg1->text && arg1->text[0] && arg2->text
			&& arg2->text[0]) ? 1.0 : 0.0;		break;
		case OR:
			res->val = ((arg1->text && arg1->text[0]) || (arg2->text
			&& arg2->text[0])) ? 1.0 : 0.0;		break;
		case EQ:
			res->val = cmp ? 0.0 : 1.0;		break;
		case NE:
			res->val = cmp ? 1.0 : 0.0;		break;
		case GT:
			res->val = cmp > 0 ? 1.0 : 0.0;		break;
		case GE:
			res->val = cmp >= 0 ? 1.0 : 0.0;	break;
		case LT:
			res->val = cmp < 0 ? 1.0 : 0.0;		break;
		case LE:
			res->val = cmp <= 0 ? 1.0 : 0.0;	break;
			}
		}
	else {
		switch(op) {
		case AND:
			res->val = (arg1->val != 0.0 && arg2->val != 0.0)
			? 1.0 : 0.0;				break;
		case OR:
			res->val = (arg1->val != 0.0 || arg2->val != 0.0)
			? 1.0 : 0.0;				break;
		case EQ:
			res->val = (arg1->val ==  arg2->val) ? 1.0 : 0.0;
			break;
		case NE:
			res->val = (arg1->val !=  arg2->val) ? 1.0 : 0.0;
			break;
		case GT:
			res->val = (arg1->val >  arg2->val) ? 1.0 : 0.0;
			break;
		case GE:
			res->val = (arg1->val >=  arg2->val) ? 1.0 : 0.0;
			break;
		case LT:
			res->val = (arg1->val <  arg2->val) ? 1.0 : 0.0;
			break;
		case LE:
			res->val = (arg1->val <=  arg2->val) ? 1.0 : 0.0;
			break;
			}
		}
	res->type = BOOLVAL;
}

static void store_res(YYSTYPE *res)
{
	if(last_err_desc) {
		line_res.type = ET_TEXT;
		line_res.value = 0.0;
		rlp_strcpy(res_txt, 1000, last_err_desc);
		}
	else if(res->type == NUM){
		line_res.type = ET_VALUE;
		line_res.value = res->val;
		}
	else if(res->type == BOOLVAL){
		line_res.type = ET_BOOL;
		line_res.value = res->val;
		}
	else if(res->type == DATE1){
		line_res.type = ET_DATE;
		line_res.value = res->val;
		}
	else if(res->type == TIME1){
		line_res.type = ET_TIME;
		line_res.value = res->val;
		}
	else if(res->type == DATETIME1){
		line_res.type = ET_DATETIME;
		line_res.value = res->val;
		}
 	else if(res->type == STR) {
		line_res.type = ET_TEXT;
		line_res.value = 0.0;
		if(res->text) rlp_strcpy(res_txt, 1000, res->text);
		}
	else if((res->type == ARR || res->type == RANGEARR || (res->a_data)) && res->a_count == 1) {
		line_res.type = ET_VALUE;
		line_res.value = res->a_data[0];
		}
	else if(res->type == ARR && !(res->a_data) && !(res->a_count)) {
		line_res.type = ET_VALUE;
		line_res.value = res->val;
		}
	else if(res->type == ARR || res->type == RANGEARR || (res->a_data)) {
		line_res.type = ET_TEXT;
		line_res.value = 0.0;
		line_res.a_data = res->a_data;
		line_res.a_count = res->a_count;
		if(res->text) rlp_strcpy(res_txt, 1000, res->text);
		else rlp_strcpy(res_txt, 1000, "#ARRAY");
		}
	else if(res->tptr && res->tptr->type == TXT) {
		line_res.type = ET_TEXT;
		line_res.value = 0.0;
		if(res->tptr->text) rlp_strcpy(res_txt, 1000, res->tptr->text);
		}
	else {
		line_res.type = ET_VALUE;
		line_res.value = res->val;
		}
}

static char *add_strings(char *st1, char *st2)
{
	char *newstr, *ret;
	int cb;

	if(st1 && st2) {
		if(newstr = (char*)malloc(cb = (int)(strlen(st1) +strlen(st2) +4))) {
#ifdef USE_WIN_SECURE
			sprintf_s(newstr, cb, "%s%s", st1, st2);
#else
			sprintf(newstr, "%s%s", st1, st2);
#endif
			ret = PushString(newstr);
			free(newstr);
			return ret;
			}
		else return 0L;
		}
	if(st1) return st1;
	if(st2) return st2;
	return 0L;
}

static char *string_value(YYSTYPE *exp)
{
	char *st1, tmp[50];

	if(exp->type == STR){
		st1 = exp->text;
		}
	else if(exp->tptr && exp->tptr->type == TXT) {
		st1 = exp->tptr->text;
		}
	else {
#ifdef USE_WIN_SECURE
		sprintf_s(tmp, 50, "%g", exp->val);
#else
		sprintf(tmp,"%g", exp->val);
#endif
		st1 = tmp;
		}
	return PushString(st1);
}

// store syntactical information
static void push_syntax()
{
	syntax_info *next;

	if(!(next = (syntax_info*)calloc(1, sizeof(syntax_info)))) return;
	if(syntax_level)memcpy(next, syntax_level, sizeof(syntax_info));
	next->next=syntax_level;
	syntax_level = next;
}

static void pop_syntax()
{
	syntax_info *si;

	if(si = syntax_level) {
		syntax_level = si->next;
		free(si);
		}
}

static int eval(YYSTYPE *dst, YYSTYPE *sr) 
{
	char *s_buffer;
	int s_buff_pos, s_yychar, s_yynerrs, length, parse_res;
	anyResult *ar;

	if(bNoExec) return 0;
	if(!sr || !sr->text || !sr->text[0]) return 1;
	s_buffer = buffer;		s_buff_pos = buff_pos;
	s_yychar = yychar;		s_yynerrs = yynerrs;
	if(!(length = (int)strlen(sr->text)))return 1;
	parse_level++;
	if(sr->text[length-1] == ';') buffer = sr->text;
	else {
		buffer = (char*)malloc(length+2);
		rlp_strcpy(buffer, length+1, sr->text);
		buffer[length++] = ';';		buffer[length] = 0;
		}
	if(buffer && buffer[0]){
		buff_pos = 0;
		while(!(parse_res = yyparse()) && buff_pos < length);
		if(buffer != sr->text) free(buffer);
		ar = &line_res;
		buffer = s_buffer;		buff_pos = s_buff_pos;
		yychar = s_yychar;		yynerrs = s_yynerrs;
		}
	else return 1;
	dst->a_data = ar->a_data;	dst->a_count = ar->a_count;
	if(parse_res == 2) return 2;
	else if(parse_res == 3 && sr->type == IBLOCK) return 3;
	else if(parse_res == 1) return 1;
	switch(ar->type) {
	case ET_BOOL:
		dst->type = BOOLVAL;	dst->val = ar->value;
		dst->text = 0L;		break;
	case ET_VALUE:
		dst->type = NUM;	dst->val = ar->value;
		dst->text = 0L;		break;
	case ET_TEXT:
		dst->type = STR;	dst->val = 0.0;
		dst->text = PushString(ar->text);
		break;
	default:
		dst->type = NUM;	dst->val = 0.0;
		dst->text = 0L;		break;
		}
	parse_level--;
	return 0;
}

// more functions
static double sign(double v)
{
	if(v > 0.0) return 1.0;
	if(v < 0.0) return -1.0;
	return 0.0;
}

static long idum=0;
static double rand1(YYSTYPE *dst, YYSTYPE *src)
{
	if(!dst) return 0.0;
	dst->type = NUM;
	return(dst->val = ran2(&idum));
}

static double srand(double v)
{
	idum = (long)v;
	return v;
}

static double maxiter(YYSTYPE *dst, YYSTYPE *src)
{
	if(!dst) return 0.0;
	if(src) yy_maxiter = (int)src->val;
	dst->type = NUM;
	return(dst->val = (double)yy_maxiter);
}

static double factorial(double v)
{
	return factrl((int)v);
}

static double _strlen(YYSTYPE *sr, YYSTYPE *dst, char *dum)
{
	if(dum) yyerror("parse error");
	if(!sr || !sr->text) return 0.0;
	return (double)strlen(sr->text);
}

#undef min
static double min(YYSTYPE *sr) 
{
	int i;

	if(!sr || !sr->a_count) return 0.0;
	if(sr->a_data && sr->a_data){
		for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) 
			if(sr->a_data[i] < sr->val) sr->val = sr->a_data[i];
		}
	return sr->val;
}

#undef max
static double max(YYSTYPE *sr) 
{
	int i;

	if(!sr || !sr->a_count) return 0.0;
	if(sr->a_data){
		for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) 
			if(sr->a_data[i] > sr->val) sr->val = sr->a_data[i];
		}
	return sr->val;
}

static double count(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	if(sr->a_data) sr->val = (double)sr->a_count;
	else sr->val = 0.0;
	return sr->val;
}

static double sum(YYSTYPE *sr) 
{
	int i;

	if(!sr) return 0.0;
	if(sr->type == RANGEARR && sr->a_data) {
		sr->val = RangeData.sum(sr->a_data, sr->a_count);
		}
	else if(sr->a_data){
		for(i = 0, sr->val = 0.0; i < sr->a_count; i++) sr->val += sr->a_data[i];
		}
	else sr->val = 0.0;
	return sr->val;
}

static double mean(YYSTYPE *sr) 
{
	if(!sr) return 0.0;
	if(sr->type == RANGEARR && sr->a_data) {
		sr->val = RangeData.mean(sr->a_data, sr->a_count);
		}
	else if(sr->a_data && sr->a_count){
		sr->val = d_amean(sr->a_count, sr->a_data );
		}
	else sr->val = 0.0;
	return sr->val;
}

static double kurt(YYSTYPE *sr) 
{
	if(!sr) return 0.0;
	if(sr->a_data && sr->a_count > 3){
		sr->val = d_kurt(sr->a_count, sr->a_data );
		}
	else sr->val = 0.0;
	return sr->val;
}

static double skew(YYSTYPE *sr) 
{
	if(!sr) return 0.0;
	if(sr->a_data && sr->a_count > 2){
		sr->val = d_skew(sr->a_count, sr->a_data );
		}
	else sr->val = 0.0;
	return sr->val;
}

static double gmean(YYSTYPE *sr) 
{
	int i;

	if(!sr) return 0.0;
	if(sr->a_data && sr->a_count){
		for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) {
			last_err_desc = "#VALUE";
			return sr->val = 0.0;
			}
		sr->val = d_gmean(sr->a_count, sr->a_data );
		}
	else sr->val = 0.0;
	return sr->val;
}

static double hmean(YYSTYPE *sr) 
{
	int i;

	if(!sr) return 0.0;
	if(sr->a_data && sr->a_count){
		for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) {
			last_err_desc = "#VALUE";
			return sr->val = 0.0;
			}
		sr->val = d_hmean(sr->a_count, sr->a_data );
		}
	else sr->val = 0.0;
	return sr->val;
}

static double quartile1(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	if(sr->type == RANGEARR && sr->a_data) {
		sr->val = RangeData.quartile1(sr->a_data, sr->a_count);
		}
	else if(sr->a_data && sr->a_count){
		d_quartile(sr->a_count, sr->a_data, &sr->val, 0L, 0L);
		}
	else sr->val = 0.0;
	return sr->val;
}

static double quartile2(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	if(sr->type == RANGEARR && sr->a_data) {
		sr->val = RangeData.quartile2(sr->a_data, sr->a_count);
		}
	else if(sr->a_data && sr->a_count){
		d_quartile(sr->a_count, sr->a_data, 0L, &sr->val, 0L);
		}
	else sr->val = 0.0;
	return sr->val;
}

static double quartile3(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	if(sr->type == RANGEARR && sr->a_data) {
		sr->val = RangeData.quartile3(sr->a_data, sr->a_count);
		}
	else if(sr->a_data && sr->a_count){
		d_quartile(sr->a_count, sr->a_data, 0L, 0L, &sr->val);
		}
	else sr->val = 0.0;
	return sr->val;
}

static double variance(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count){
		sr->val = d_variance(sr->a_count, sr->a_data);
		}
	return sr->val;
}

static double stdev(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count){
		sr->val = sqrt(d_variance(sr->a_count, sr->a_data));
		}
	return sr->val;
}

static double sterr(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count){
		sr->val = sqrt(d_variance(sr->a_count, sr->a_data))/sqrt((double)sr->a_count);
		}
	return sr->val;
}

static double beta(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 2){
		sr->val = betaf(sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("beta(u, v)");
	return sr->val;
}

static double _gammp(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 2){
		sr->val = gammp(sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("gammp(a, x)");
	return sr->val;
}

static double _gammq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 2){
		sr->val = gammq(sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("gammq(a, x)");
	return sr->val;
}

static double _betai(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 3){
		if(sr->a_data[2] < 0.0 || sr->a_data[2] > 1.0) {
			last_err_desc = "#VALUE";
			return sr->val = 0.0;
			}
		sr->val = betai(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("betai(a, b, x)");
	return sr->val;
}

static double _bincof(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 2){
		sr->val = bincof(sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("bincof(n, k)");
	return sr->val;
}

static double binomdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 3){
		sr->val = binomdistf(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("binomdist(s, n, p)");
	return sr->val;
}

static double binomfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 3){
		sr->val = bincof(sr->a_data[1], sr->a_data[0]);
		sr->val *= pow(sr->a_data[2], sr->a_data[0]);
		sr->val *= pow(1.0 - sr->a_data[2], sr->a_data[1] - sr->a_data[0]);
		}
	else yyargcnterr("binomfreq(s, n, p)");
	return sr->val;
}

static double normdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 3){
		sr->val = norm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("normdist(x, mean, SD)");
	return sr->val;
}

static double norminv(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 3) {
		sr->val = distinv(norm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("norminv(p, mean, SD)");
	return sr->val;
}

static double normfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 3){
		sr->val = norm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("normfreq(x, mean, SD)");
	return sr->val;
}

static double expdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = exp_dist(sr->a_data[0], sr->a_data[1], 0.0);
		}
	else yyargcnterr("expdist(x, l)");
	return sr->val;
}

static double expinv(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 2) {
		sr->val = exp_inv(sr->a_data[0], sr->a_data[1], 0.0);
		}
	else yyargcnterr("expinv(p, l)");
	return sr->val;
}

static double expfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = exp_freq(sr->a_data[0], sr->a_data[1], 0.0);
		}
	else yyargcnterr("expfreq(x, l)");
	return sr->val;
}

static double lognormdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 3){
		sr->val = lognorm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("lognormdist(x, mean, SD)");
	return sr->val;
}

static double lognormfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 3){
		sr->val = lognorm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("lognormfreq(x, mean, SD)");
	return sr->val;
}

static double lognorminv(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 3) {
		sr->val = distinv(lognorm_dist, sr->a_data[1], sr->a_data[2], sr->a_data[0], exp(sr->a_data[1]));
		}
	else yyargcnterr("lognorminv(p, mean, SD)");
	return sr->val;
}

static double chidist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = chi_dist(sr->a_data[0], sr->a_data[1], 1.0);
		}
	else yyargcnterr("chidist(x, df)");
	return sr->val;
}

static double chifreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = chi_freq(sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("chifreq(x, df)");
	return sr->val;
}

static double chiinv(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
        if(sr->a_data && sr->a_count == 2) {
		sr->val = distinv(chi_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0);
		}
	else yyargcnterr("chiinv(p, df)");
	return sr->val;
}

static double tdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = t_dist(sr->a_data[0], sr->a_data[1], 1.0);
		}
	else yyargcnterr("tdist(x, df)");
	return sr->val;
}

static double tfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = t_freq(sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("tfreq(x, df)");
	return sr->val;
}

static double tinv(YYSTYPE *sr)
{
	double dtmp;

	if(!sr) return 0.0;
	sr->val = 0.0;
	dtmp = sr->a_data[1] > 1.0E+10 ? 1.0E+10 : sr->a_data[1];
        if(sr->a_data && sr->a_count == 2) {
		sr->val = fabs(distinv(t_dist,dtmp, 1.0, sr->a_data[0], 2.0));
		}
	else yyargcnterr("tinv(p, df)");
	return sr->val;
}

static double poisdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = pois_dist(sr->a_data[0], sr->a_data[1], 1.0);
		}
	else yyargcnterr("poisdist(x, mean)");
	return sr->val;
}

static double poisfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = exp(log(sr->a_data[1])*sr->a_data[0] - sr->a_data[1] - gammln(1.0 + sr->a_data[0]));
		}
	else yyargcnterr("poisfreq(x, mean)");
	return sr->val;
}

static double fdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 3){
		sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("fdist(x, df1, df2)");
	return sr->val;
}

static double ffreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 3){
		sr->val = f_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("ffreq(x, df1, df2)");
	return sr->val;
}

static double finv(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0;
	if(sr->a_data && sr->a_count == 3){
		sr->val = distinv(f_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
		}
	else yyargcnterr("finv(p, df1, df2)");
	return sr->val;
}

static double weibdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = weib_dist(sr->a_data[0], sr->a_data[1], 1.0);
		}
	if(sr->a_data && sr->a_count == 3){
		sr->val = weib_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("weibdist(x, shape[, scale=1])");
	return sr->val;
}

static double weibfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = weib_freq(sr->a_data[0], sr->a_data[1], 1.0);
		}
	if(sr->a_data && sr->a_count == 3){
		sr->val = weib_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("weibfreq(x, shape[, scale=1])");
	return sr->val;
}

static double weibinv(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = distinv(weib_dist,sr->a_data[1], 1.0, sr->a_data[0], 1.0);
		}
	else if(sr->a_data && sr->a_count == 3){
		sr->val = distinv(weib_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0],sr->a_data[2]);
		}
	else yyargcnterr("weibinv(p, shape[, scale=1])");
	return sr->val;
}

static double geomfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = geom_freq(sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("geomfreq(x, p)");
	return sr->val;
}

static double geomdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = geom_dist(sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("geomdist(x, p)");
	return sr->val;
}

static double hyperfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 4){
		sr->val = hyper_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2], sr->a_data[3]);
		}
	else yyargcnterr("hyperfreq(k, N, m, n)");
	return sr->val;
}

static double hyperdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 4){
		sr->val = hyper_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2], sr->a_data[3]);
		}
	else yyargcnterr("hyperdist(k, N, m, n)");
	return sr->val;
}

static double cauchydist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], 1.0);
		}
	else if(sr->a_data && sr->a_count == 3){
		sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("cauchydist(x, location[, scale=1])");
	return sr->val;
}

static double cauchyfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], 1.0);
		}
	else if(sr->a_data && sr->a_count == 3){
		sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("cauchyfreq(x, location[, scale=1])");
	return sr->val;
}

static double cauchyinv(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = distinv(cauch_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]);
		}
	else if(sr->a_data && sr->a_count == 3){
		sr->val = distinv(cauch_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("cauchyinv(p, location[, scale=1])");
	return sr->val;
}

static double logisdist(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = logis_dist(sr->a_data[0], sr->a_data[1], 1.0);
		}
	else if(sr->a_data && sr->a_count == 3){
		sr->val = logis_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("logisdist(x, location[, scale=1])");
	return sr->val;
}

static double logisfreq(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0.0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = logis_freq(sr->a_data[0], sr->a_data[1], 1.0);
		}
	else if(sr->a_data && sr->a_count == 3){
		sr->val = logis_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
		}
	else yyargcnterr("logisfreq(x, location[, scale=1])");
	return sr->val;
}

static double logisinv(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0;
	if(sr->a_data && sr->a_count == 2){
		sr->val = distinv(logis_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]);
		}
	else if(sr->a_data && sr->a_count == 3){
		sr->val = distinv(logis_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
		}
	else yyargcnterr("logisinv(p, location[, scale=1])");
	return sr->val;
}

static void pearson(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
{
	char *dest;
	double *arr;

	if(!sr1 || !sr2) return;
	if(dst && !bNoWrite) dest = dst->text;
	else dest = 0L;
	if(dst && dst->a_data && dst->a_count > 3) arr = dst->a_data;
	else arr = 0L;
	lval->val = 0.0;	lval->type = NUM;
	if(sr1->text && sr2->text)range_array2(sr1, sr2);
	if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
		lval->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
		}
	else yybadargerr("pearson(range1; range2 [;\"dest\"])");
	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
}

static void spearman(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
{
	char *dest;
	double *arr;

	if(!sr1 || !sr2) return;
	if(dst && !bNoWrite) dest = dst->text;
	else dest = 0L;
	if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data;
	else arr = 0L;
	lval->val = 0.0;	lval->type = NUM;
	if(sr1->text && sr2->text)range_array2(sr1, sr2);
	if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
		lval->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
		}
	else yybadargerr("spearman(range1; range2 [;\"dest\"])");
	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
}

static void kendall(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
{
	char *dest;
	double *arr;

	if(!sr1 || !sr2) return;
	if(dst && !bNoWrite) dest = dst->text;
	else dest = 0L;
	if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data;
	else arr = 0L;
	lval->val = 0.0;	lval->type = NUM;
	if(sr1->text && sr2->text)range_array2(sr1, sr2);
	if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
		lval->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
		}
	else yybadargerr("kendall(range1; range2 [;\"dest\"])");
	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
}

static void regression(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
{
	char *dest;
	double *arr;

	if(!sr1 || !sr2) return;
	if(dst && !bNoWrite) dest = dst->text;
	else dest = 0L;
	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
	else arr = 0L;
	lval->val = 0.0;	lval->type = NUM;
	if(sr1->text && sr2->text)range_array2(sr1, sr2);
	if(!dest && !arr) yyargserr("No destination range in call to function\nregression(range1; range2; \"dest\").");
        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
		lval->val = d_regression(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
		}
	else yybadargerr("regression(range1; range2; \"dest\")");
	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
}

static void _covar(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2)
{
	if(!sr1 || !sr2) return;
	lval->val = 0.0;
	if(sr1->text && sr2->text)range_array2(sr1, sr2);
        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
		lval->val = d_covar(sr1->a_data, sr2->a_data, sr1->a_count, 0L, curr_data);
		}
	else yybadargerr("covar(range1; range2)");
	return;
}

static void ttest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
{
	char *dest;
	double *arr;

	if(!sr1 || !sr2) return;
	if(dst && !bNoWrite) dest = dst->text;
	else dest = 0L;
	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
	else arr = 0L;
	lval->val = 0.0;	lval->type = NUM;
        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){
		lval->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr);
		}
	else yybadargerr("ttest(array1; array2[;\"dest\"])");
	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
}

static void ttest2(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
{
	char *dest;
	double *arr;

	if(!sr1 || !sr2) return;
	if(dst && !bNoWrite) dest = dst->text;
	else dest = 0L;
	if(dst && dst->a_data && dst->a_count > 6) arr = dst->a_data;
	else arr = 0L;
	lval->val = 0.0;	lval->type = NUM;
	if(sr1->text && sr2->text)range_array2(sr1, sr2);
        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count == sr1->a_count){
		lval->val = sr2->val = d_ttest2(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
		}
	else yybadargerr("ttest2(range1; range2[;\"dest\"])");
	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
}

static void utest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
{
	char *dest;
	double *arr;

	if(!sr1 || !sr2) return;
	if(dst && !bNoWrite) dest = dst->text;
	else dest = 0L;
	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
	else arr = 0L;
	lval->val = 0.0;	lval->type = NUM;
        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){
		lval->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr);
		}
	else yybadargerr("utest2(array1; array2[;\"dest\"])");
	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
}

static void ftest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
{
	char *dest;
	double *arr;

	if(!sr1 || !sr2) return;
	if(dst && !bNoWrite) dest = dst->text;
	else dest = 0L;
	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
	else arr = 0L;
	lval->val = 0.0;	lval->type = NUM;
        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count > 1){
		lval->val = d_ftest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr);
		}
	else yybadargerr("ftest(range1; range2[;\"dest\"])");
}

static double p_tukey(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0;
	if(sr->a_data && sr->a_count == 4){
		sr->val = ptukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0);
		}
	else if(sr->a_data && sr->a_count == 3){
		sr->val = ptukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
		}
	else yyargcnterr("ptukey(q, nm, df[, nr = 1])");
	return sr->val;
}

static double q_tukey(YYSTYPE *sr)
{
	if(!sr) return 0.0;
	sr->val = 0;
	if(sr->a_data && sr->a_count == 4){
		sr->val = qtukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0);
		}
	else if(sr->a_data && sr->a_count == 3){
		sr->val = qtukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
		}
	else yyargcnterr("qtukey(p, nm, df[, nr = 1])");
	return sr->val;
}

static double fill(YYSTYPE *sr, char *dest)
{
	AccRange *ar;
	int i, r, c;

	if(!sr || !sr->a_data || !sr->a_count || !dest || !dest[0] || bNoWrite) return 0.0;
	if(ar = new AccRange(dest)) {
		for(i=0, ar->GetFirst(&c, &r); ar->GetNext(&c, &r) && i < sr->a_count; i++) {
			curr_data->SetValue(r, c, sr->a_data[i]);
			}
		delete ar;
		}
	return sr->val = i;
}

static void datestr(YYSTYPE *dst, YYSTYPE *src, char *fmt)
{
	dst->text = PushString(value_date(src->val, fmt));
}

static double dateval(YYSTYPE *sr, YYSTYPE *dst, char *fmt)
{
	if(!sr || !sr->text) return 0.0;
	if(fmt && fmt[0] && date_value(sr->text, fmt, &dst->val)) return dst->val;
	if(date_value(sr->text, 0L, &dst->val)) return dst->val;
	else return dst->val = 0.0;
}

static double leapyear(double year)
{
	int y = (int)year;

	return (double)((y % 4 == 0 && y % 100 != 0) || y % 400 == 0);
}

static void today(YYSTYPE *dst, YYSTYPE *src)
{
	if(src) yyerror("parse error");
	if(!dst) return;
	dst->val = floor(now_today());
	dst->type = DATE1;
}

static void now(YYSTYPE *dst, YYSTYPE *src)
{
	if(src) yyerror("parse error");
	if(!dst) return;
	dst->val = now_today();			dst->val -= floor(dst->val);
	dst->type = TIME1;
}

static double year(double dv)
{
	int res;

	split_date(dv, &res, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
	return (double)res;
}

static double month(double dv)
{
	int res;

	split_date(dv, 0L, &res, 0L, 0L, 0L, 0L, 0L, 0L);
	return (double)res;
}

static double dom(double dv)
{
	int res;

	split_date(dv, 0L, 0L, &res, 0L, 0L, 0L, 0L, 0L);
	return (double)res;
}

static double dow(double dv)
{
	int res;

	split_date(dv, 0L, 0L, 0L, &res, 0L, 0L, 0L, 0L);
	return (double)res;
}

static double doy(double dv)
{
	int res;

	split_date(dv, 0L, 0L, 0L, 0L, &res, 0L, 0L, 0L);
	return (double)res;
}

static double hours(double dv)
{
	int res;

	split_date(dv, 0L, 0L, 0L, 0L, 0L, &res, 0L, 0L);
	return (double)res;
}

static double minutes(double dv)
{
	int res;

	split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, &res, 0L);
	return (double)res;
}

static double seconds(double dv)
{
	double res;

	split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, 0L, &res);
	if(res < 0.0005) res = 0.0;
	return res;
}

static void fdate(YYSTYPE *dst, YYSTYPE *src)
{
	if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) {
		yyerror("parse error");	
		return;
		}
	dst->type = DATE1;		dst->val = src->val;
}

static void fdatetime(YYSTYPE *dst, YYSTYPE *src)
{
	if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) {
		yyerror("parse error");	
		return;
		}
	dst->type = DATETIME1;		dst->val = src->val;
}

static void ftime(YYSTYPE *dst, YYSTYPE *src)
{
	if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) {
		yyerror("parse error");	
		return;
		}
	dst->type = TIME1;		dst->val = src->val;
}

static void invert(YYSTYPE *dst, YYSTYPE *src)
{
	int i;

	if(!dst || !src) return;
	switch(src->a_count) {
	case 0:
		dst->a_data = PushArray((double*)malloc(sizeof(double)));
		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
		break;
	case 1:
		dst->a_data = PushArray((double*)malloc(sizeof(double)));
		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
		break;
	default:
		dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0));
		dst->a_count = src->a_count;
		for(i = 0; i < src->a_count; i++) dst->a_data[i] = src->a_data[src->a_count-1-i];
		}
}

static void asort(YYSTYPE *dst, YYSTYPE *src)
{
	if(!dst || !src) return;
	dst->type = ARR;
	switch(src->a_count) {
	case 0:
		dst->a_data = PushArray((double*)malloc(sizeof(double)));
		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
		break;
	case 1:
		dst->a_data = PushArray((double*)malloc(sizeof(double)));
		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
		break;
	default:
		dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0));
		dst->a_count = src->a_count;
		SortArray(dst->a_count, dst->a_data);
		}
}

static void _randarr(YYSTYPE *dst, YYSTYPE *src)
{
	if(!dst || !src) return;
	dst->type = ARR;
	switch(src->a_count) {
	case 0:
		dst->a_data = PushArray((double*)malloc(sizeof(double)));
		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
		break;
	case 1:
		dst->a_data = PushArray((double*)malloc(sizeof(double)));
		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
		break;
	default:
		dst->a_data = randarr(src->a_data, src->a_count, &idum);
		dst->a_count = src->a_count;
		}
}

static void _resample(YYSTYPE *dst, YYSTYPE *src)
{
	if(!dst || !src) return;
	dst->type = ARR;
	switch(src->a_count) {
	case 0:
		dst->a_data = PushArray((double*)malloc(sizeof(double)));
		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
		break;
	case 1:
		dst->a_data = PushArray((double*)malloc(sizeof(double)));
		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
		break;
	default:
		dst->a_data = resample(src->a_data, src->a_count, &idum);
		dst->a_count = src->a_count;
		}
}

static void mkarr(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char*fmt)
{
	AccRange *rD;
	int i, n, r, c;
	anyResult ares;

	if(fmt || !sr2 || !sr1 || !sr1->text) yyargcnterr("mkarr(range, MD)");
	if(!(rD = new AccRange(sr1->text)) || !(n = rD->CountItems())) {
		yybadargerr("mkarr(range, MD)");
		}
	res->a_data = PushArray((double*)calloc(n, sizeof(double)));
	for(i = 0, rD->GetFirst(&c, &r); i < n; i++) {
		rD->GetNext(&c, &r);
		if(curr_data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE) res->a_data[i] = ares.value;
		else res->a_data[i] = sr2->val;
		res->a_count = i;
		}
	if(rD) delete rD;
}

static void asort2(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char *fmt)
{
	int n;

	res->val = 0.0;		res->type = NUM;
	if(!sr1 || !sr2 || !sr1->a_data || !sr2->a_data) return;
	n = sr1->a_count > sr2->a_count ? sr2->a_count : sr1->a_count;
	res->val = (double)n;
	if(n >1) SortArray2(n, sr1->a_data, sr2->a_data);
	return;
}

static double _crank(YYSTYPE *src)
{
	double tmp = -1.0;

	if(!src) return tmp;
	tmp = 0.0;
	if(src->a_data && src->a_count > 1.0)crank(src->a_count, src->a_data, &tmp);
	if(src->type == RANGEARR) RangeData.rmData(src->a_data, src->a_count);
	return tmp;
}

static void subarr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
{
	int i, pos2;

	if(!src1->a_data) yybadargerr("subarr(array; pos1[; pos2])");
	else {
		if(src3) pos2 = (int)(src3->val);
		else pos2 = src1->a_count;
		dst->type = ARR;
		dst->a_data = PushArray((double*)malloc(src1->a_count*sizeof(double)));
		for(i = (int)(src2->val), dst->a_count = 0; i <= pos2 && i < src1->a_count; i++) {
			dst->a_data[dst->a_count++] = src1->a_data[i];
			}
		}
}

static void ltrim(YYSTYPE *dst, YYSTYPE *src)
{
	if(!src || !dst || !src->text) return;
	dst->text = PushString(str_ltrim(src->text));
	dst->type = STR;	dst->val = 0.0;
}

static void rtrim(YYSTYPE *dst, YYSTYPE *src)
{
	if(!src || !dst || !src->text) return;
	dst->text = PushString(str_rtrim(src->text));
	dst->type = STR;	dst->val = 0.0;
}

static void trim(YYSTYPE *dst, YYSTYPE *src)
{
	if(!src || !dst || !src->text) return;
	dst->text = PushString(str_trim(src->text));
	dst->type = STR;	dst->val = 0.0;
}

static double rank(YYSTYPE *sr) 
{
	if(sr->a_count < 2 || !sr->a_data) return 0.0;
	return d_rank(sr->a_count-1, sr->a_data+1, sr->a_data[0]);
}

static double classes(double start, double step, YYSTYPE *src, YYSTYPE *dest)
{
	return d_classes(curr_data, start, step, src->a_data, src->a_count, dest->text);
}

static void _strpos(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
{
	dst->type = NUM;
	dst->val = (double)strpos(src1->text, src2->text);
}

static void strrepl(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
{
	if(src3) {
		dst->type = STR;
		dst->text = PushString(strreplace(src1->text, src2->text, src3->text));
		}
	else yyargcnterr("strrepl(search; replace; haystack)");
}

static void _substr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
{
	if(src3) {
		dst->type = STR;
		dst->text = PushString(substr(src1->text, (int)(src2->val), (int)(src3->val)));
		}
	else yyargcnterr("substr(text; pos1; pos2)");
}

static double asc(YYSTYPE *sr, YYSTYPE *dst, char *dum)
{
	if(dum) yyerror("parse error");
	if(!sr || !sr->text) return 0.0;
	return (double)((unsigned char)(sr->text[0]));
}

static void chr(YYSTYPE *dst, YYSTYPE *src)
{
	char tpl[] = "?\0";

	if(!dst || !src) return;
	tpl[0] = (src->val >=32.0 && src->val <= 255.0) ? (char)(src->val) :  '?';
	dst->type = STR;
	dst->text = PushString(tpl);
}

static void to_upper(YYSTYPE *dst, YYSTYPE *src)
{
	int i;

	if(!dst || !src) return;
	dst->type = STR;
	if(src->text && src->text[0]) {
		dst->text = PushString(src->text);
		for(i = 0; src->text[i]; i++) dst->text[i] = toupper(src->text[i]);
		}
	else dst->text = 0L;
}

static void to_lower(YYSTYPE *dst, YYSTYPE *src)
{
	int i;

	if(!dst || !src) return;
	dst->type = STR;
	if(src->text && src->text[0]) {
		dst->text = PushString(src->text);
		for(i = 0; src->text[i]; i++) dst->text[i] = tolower(src->text[i]);
		}
	else dst->text = 0L;
}

static void uc_first(YYSTYPE *dst, YYSTYPE *src)
{
	if(!dst || !src) return;
	dst->type = STR;
	if(src->text && src->text[0]) {
		dst->text = PushString(src->text);
		dst->text[0] = toupper(src->text[0]);
		}
	else dst->text = 0L;
}

static void uc_word(YYSTYPE *dst, YYSTYPE *src)
{
	int i;

	if(!dst || !src) return;
	dst->type = STR;
	if(src->text && src->text[0]) {
		dst->text = PushString(src->text);
		dst->text[0] = toupper(src->text[0]);
		for(i = 1; src->text[i]; i++) {
			if(isalpha(src->text[i]) && src->text[i-1] < 'A') dst->text[i] = toupper(src->text[i]);
			}
		}
	else dst->text = 0L;
}

static void exec_block(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, bool namespc)
{
	char *cmd = 0L;
	int cmd_pos = 0, cmd_size, r, c;
	AccRange *ar = 0L;
	anyResult res, *eres;
	YYSTYPE evsrc, evdst;

	if(bNoExec) return;
	if(!src1 || !src1->text || !src1->text[0]) return;
	if((cmd =(char*)malloc((cmd_size = 1000) * sizeof(char))) && (ar = new AccRange(src1->text))) {
		if(src2 && src2->text[0] && src2->text[0]) {
			add_to_buff(&cmd, &cmd_pos, &cmd_size, src2->text, 0);
			while(cmd_pos && cmd[cmd_pos-1] < 33) cmd_pos--;
			if(cmd_pos && cmd[cmd_pos-1] != ';') cmd[cmd_pos++] = ';';
			}
		cmd[cmd_pos] = 0;
		ar->GetFirst(&c, &r);	ar->GetNext(&c, &r);
		do {
			curr_data->GetResult(&res, r, c, false);
			switch(res.type) {
			case ET_VALUE:				//numerical value
				if(res.value == -HUGE_VAL)
					add_to_buff(&cmd, &cmd_pos, &cmd_size, "-inf", 4);
				else if(res.value == HUGE_VAL)
					add_to_buff(&cmd, &cmd_pos, &cmd_size, "inf", 3);
				else add_dbl_to_buff(&cmd, &cmd_pos, &cmd_size, res.value, false);
				break;
			case ET_TEXT:					//text cell
				if(res.text && res.text[0]) {
					if(res.text[0] == res.text[1] && res.text[0] == '/') ar->NextRow(&r);
					else add_to_buff(&cmd, &cmd_pos, &cmd_size, res.text, 0);
					}
				break;
				}
			}while(ar->GetNext(&c, &r));
		if(namespc) {
			eres = do_formula(curr_data, cmd);
			}
		else {
			memset(&evsrc, 0, sizeof(YYSTYPE));	memset(&evdst, 0, sizeof(YYSTYPE));
			evsrc.text = cmd;			eval(&evdst, &evsrc);
			eres = &line_res;
			}
		switch(eres->type) {
		case ET_BOOL:
			dst->type = BOOLVAL;	dst->val = eres->value;
			dst->text = 0L;				break;
		case ET_VALUE:
			dst->type = NUM;	dst->val = eres->value;
			dst->text = 0L;				break;
		case ET_TEXT:
			dst->type = STR;	dst->val = 0.0;
			dst->text = PushString(eres->text);	break;
		default:
			dst->type = NUM;	dst->val = 0.0;
			dst->text = 0L;		break;
			}
		}
	if(cmd) free(cmd);	if(ar) delete ar;
}

static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
{
	exec_block(dst, src1, src2, true);
}

static void call(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
{
	exec_block(dst, src1, src2, false);
}


// Store strings in a list
static char **str_list = 0L;
static int n_str = 0;

static char *PushString(char *text)
{
	if(text && text[0]) {
		if(str_list = (char**)realloc(str_list, sizeof(char*)*(n_str+1)))
			str_list[n_str] = (char*)memdup(text, (int)strlen(text)+1, 0);
		return str_list[n_str++];
		}
	return 0L;
}

//Store arrays in a list
static double **arr_list = 0L;
static int n_arr = 0;

static double *PushArray(double *arr)
{
	if(arr) {
		if(arr_list = (double**)realloc(arr_list, sizeof(double*)*(n_arr+1))){
			arr_list[n_arr] = arr;
			return arr_list[n_arr++];
			}
		}
	return 0L;
}

static double *ReallocArray(double *arr, int size)
{
	int i;

	if(arr && size) {
		for(i = 0; i < n_arr; i++) if(arr_list[i] == arr) {
			arr_list[i] = (double*)realloc(arr, size);
			return arr_list[i];
			}
		arr = (double*)realloc(arr, size);
		return PushArray(arr);
		}
	return 0L;
}


//The symbol table: a chain of `struct symrec'
static symrec *sym_table, *sym_tab_first;

//Rearrange function table with previously used functions in front
void ArrangeFunctions()
{
	symrec *ptr, *ptr1, *ptr2, *next;

	for(ptr = sym_table, ptr1 = ptr2 = 0L; (ptr); ) {
		next = ptr->next;
		if(ptr->name) {
			ptr->next = ptr1;
			ptr1 = ptr;
			}
		else {
			ptr->next = ptr2;
			ptr2 = ptr;
			}
		ptr = next;
		}
	for(sym_table = 0L, ptr = ptr2; (ptr); ){
		next = ptr->next;
		ptr->next = sym_table;
		sym_table = ptr;
		ptr = next;
		}
	for(ptr = ptr1; (ptr); ){
		next = ptr->next;
		ptr->next = sym_table;
		sym_table = ptr;
		ptr = next;
		}
	sym_tab_first = sym_table;
	bRecent = false;
}

// Put arithmetic functions and predifened variables in table
#define INIT_SYM(TYP,NAM,FNC) {TYP,NAM,(double(*)(double))&FNC} 
void InitArithFuncs(DataObj *d)
{
	struct fdef {
		int f_type;
		char *name;
		double (*fnct)(double);
		};
	fdef fncts[] = {
	INIT_SYM(AFNCT, "geomfreq", geomfreq),		INIT_SYM(AFNCT, "geomdist", geomdist),
	INIT_SYM(AFNCT, "hyperfreq", hyperfreq),	INIT_SYM(AFNCT, "hyperdist", hyperdist),
	INIT_SYM(YYFNC3, "mkarr", mkarr),		INIT_SYM(YYFNC, "maxiter", maxiter),
	INIT_SYM(YYFNC, "randarr", _randarr),		INIT_SYM(YYFNC, "resample", _resample),
	INIT_SYM(AFNCT, "weibdist", weibdist),		INIT_SYM(AFNCT, "weibfreq", weibfreq),
	INIT_SYM(AFNCT, "weibinv", weibinv),		INIT_SYM(AFNCT, "cauchydist", cauchydist),
	INIT_SYM(AFNCT, "cauchyfreq", cauchyfreq),	INIT_SYM(AFNCT, "cauchyinv", cauchyinv),
	INIT_SYM(AFNCT, "logisdist", logisdist),	INIT_SYM(AFNCT, "logisfreq", logisfreq),
	INIT_SYM(AFNCT, "logisinv", logisinv),		INIT_SYM(YYFNC2, "call", call),
	INIT_SYM(AFNCT, "ptukey", p_tukey),		INIT_SYM(AFNCT, "qtukey", q_tukey),
	INIT_SYM(YYFNC, "toupper", to_upper),		INIT_SYM(YYFNC, "tolower", to_lower),
	INIT_SYM(YYFNC, "ucfirst", uc_first),		INIT_SYM(YYFNC, "ucword", uc_word),
	INIT_SYM(SFNCT, "asc", asc),			INIT_SYM(YYFNC, "chr", chr),
	INIT_SYM(YYFNC3, "strrepl",strrepl),		INIT_SYM(YYFNC3, "substr", _substr),
	INIT_SYM(YYFNC2, "strpos",_strpos),		INIT_SYM(FUNC4, "classes", classes),
	INIT_SYM(AFNCT, "rank", rank),			INIT_SYM(YYFNC, "ltrim", ltrim),
	INIT_SYM(YYFNC, "rtrim", rtrim),		INIT_SYM(YYFNC, "trim", trim),
	INIT_SYM(YYFNC, "asort", asort),		INIT_SYM(AFNCT, "crank", _crank),
	INIT_SYM(SRFUNC, "datestr", datestr),		INIT_SYM(SFNCT, "dateval", dateval),
	INIT_SYM(BFNCT, "leapyear", leapyear),		INIT_SYM(YYFNC, "today", today),
	INIT_SYM(YYFNC, "now", now),			INIT_SYM(FNCT, "year", year),
	INIT_SYM(FNCT, "month", month),			INIT_SYM(FNCT, "dom", dom),
	INIT_SYM(FNCT, "dow", dow),			INIT_SYM(FNCT, "doy", doy),
	INIT_SYM(FNCT, "hours", hours),			INIT_SYM(FNCT, "minutes", minutes),
	INIT_SYM(FNCT, "seconds", seconds),		INIT_SYM(YYFNC, "date", fdate),
	INIT_SYM(YYFNC, "datetime", fdatetime),		INIT_SYM(YYFNC, "time", ftime),
	INIT_SYM(FUNC1, "fill", fill),			INIT_SYM(YYFNC3, "pearson", pearson),
	INIT_SYM(YYFNC3, "spearman", spearman),		INIT_SYM(YYFNC3, "kendall", kendall),		
	INIT_SYM(YYFNC3, "correl", pearson),		INIT_SYM(YYFNC3, "regression", regression),
	INIT_SYM(YYFNC2, "covar", _covar),		INIT_SYM(YYFNC2, "exec", exec),
	INIT_SYM(YYFNC3, "utest", utest),		INIT_SYM(YYFNC3, "ttest2", ttest2),
	INIT_SYM(YYFNC3, "ttest", ttest),		INIT_SYM(YYFNC3, "ftest", ftest),
	INIT_SYM(AFNCT, "variance", variance),		INIT_SYM(AFNCT, "stdev", stdev),
	INIT_SYM(AFNCT, "sterr", sterr),		INIT_SYM(AFNCT, "min", min),
	INIT_SYM(AFNCT, "max", max),			INIT_SYM(AFNCT, "count", count),
	INIT_SYM(AFNCT, "sum", sum),			INIT_SYM(AFNCT, "mean", mean),
	INIT_SYM(AFNCT, "kurt", kurt),			INIT_SYM(AFNCT, "skew", skew),
	INIT_SYM(AFNCT, "median", quartile2),		INIT_SYM(AFNCT, "quartile1", quartile1),
	INIT_SYM(AFNCT, "quartile2",quartile2),		INIT_SYM(AFNCT, "quartile3", quartile3),
	INIT_SYM(AFNCT, "gmean", gmean),		INIT_SYM(AFNCT, "hmean", hmean),
	INIT_SYM(AFNCT, "tdist", tdist),		INIT_SYM(AFNCT, "tfreq", tfreq),
	INIT_SYM(AFNCT, "tinv", tinv),			INIT_SYM(YYFNC, "invert", invert),
	INIT_SYM(AFNCT, "poisdist", poisdist),		INIT_SYM(AFNCT, "poisfreq", poisfreq),		
	INIT_SYM(AFNCT, "expdist", expdist),		INIT_SYM(AFNCT, "expfreq", expfreq),		
	INIT_SYM(AFNCT, "expinv", expinv),		INIT_SYM(AFNCT, "fdist", fdist),
	INIT_SYM(AFNCT, "ffreq", ffreq),		INIT_SYM(YYFNC3, "subarr", subarr),
	INIT_SYM(AFNCT, "finv", finv),			INIT_SYM(AFNCT, "gammp", _gammp),
	INIT_SYM(AFNCT, "gammq", _gammq),		INIT_SYM(AFNCT, "beta", beta),
	INIT_SYM(AFNCT, "betai", _betai),		INIT_SYM(AFNCT, "bincof", _bincof),
	INIT_SYM(AFNCT, "binomdist",binomdist),		INIT_SYM(AFNCT, "binomfreq",binomfreq),
	INIT_SYM(AFNCT, "normdist", normdist),		INIT_SYM(AFNCT, "average", mean),
	INIT_SYM(AFNCT, "norminv", norminv),		INIT_SYM(AFNCT, "normfreq", normfreq),
	INIT_SYM(AFNCT, "lognormdist", lognormdist),	INIT_SYM(AFNCT, "lognormfreq", lognormfreq),
	INIT_SYM(AFNCT, "lognorminv",lognorminv),	INIT_SYM(AFNCT, "chidist", chidist),
	INIT_SYM(AFNCT, "chifreq", chifreq),		INIT_SYM(YYFNC2, "asort2", asort2),
	INIT_SYM(AFNCT, "chiinv", chiinv),		INIT_SYM(SFNCT, "strlen", _strlen),
	INIT_SYM(YYFNC, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
	INIT_SYM(FNCT, "erfc", errfc),			INIT_SYM(FNCT, "sign", sign),
	INIT_SYM(FNCT, "gammaln", gammln),		INIT_SYM(FNCT, "factorial", factorial),
	INIT_SYM(YYFNC, "rand", rand1),			INIT_SYM(FNCT, "srand", srand),
	INIT_SYM(FNCT, "floor", floor),			INIT_SYM(FNCT, "abs", fabs),
	INIT_SYM(FNCT, "asin", asin),			INIT_SYM(FNCT, "acos", acos),
	INIT_SYM(FNCT, "atan", atan),			INIT_SYM(FNCT, "sinh", sinh),
	INIT_SYM(FNCT, "cosh", cosh),			INIT_SYM(FNCT, "tanh", tanh),
	INIT_SYM(FNCT, "sin", sin),			INIT_SYM(FNCT, "cos", cos),
	INIT_SYM(FNCT, "tan", tan),			INIT_SYM(FNCT, "log10", log10),
	INIT_SYM(FNCT, "ln", log),			INIT_SYM(FNCT, "log", log),
	INIT_SYM(FNCT, "exp", exp),			INIT_SYM(FNCT, "sqrt", sqrt),
	INIT_SYM(0, 0L, nop)};
	int i;
	symrec *ptr, *next;

	if(d) curr_data = d;
	if(sym_table) {
		for (ptr = sym_table; ptr != (symrec *) 0;){
			if(ptr) {
				next = ptr->next;
				delete (ptr);
				}
			ptr = next;
			}
		sym_table = sym_tab_first = (symrec *) 0;
		}
	for (i = 0; fncts[i].name; i++) {
		ptr = putsym (HashValue((unsigned char*) fncts[i].name), Hash2((unsigned char*) fncts[i].name), fncts[i].f_type);
		ptr->fnctptr = (double (*)(...))fncts[i].fnct;
		}
	ptr = putsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv"), VAR);	ptr->SetValue(1.0);
	sym_tab_first = sym_table;
}
#undef INIT_SYM

static void init_table (void)
{
	str_list = 0L;		n_str = 0;
	arr_list = 0L;		n_arr = 0;
	push_syntax();
}

static void clear_table()
{
	int i;

	if(str_list) {
		for(i = 0; i < n_str; i++) if(str_list[i]) free(str_list[i]);
		free(str_list);		str_list = 0L;		n_str = 0;
		}
	if(arr_list) {
		for(i = 0; i < n_arr; i++) if(arr_list[i]) free(arr_list[i]);
		free(arr_list);		arr_list = 0L;		n_arr = 0;
		}
	pop_syntax();
}

static symrec *
putsym (unsigned int h_name, unsigned int h2_name, int sym_type)
{
	sym_table = new symrec(h_name, h2_name, sym_type, sym_table);
	return sym_table;
}

static symrec *
getsym (unsigned int h_name, unsigned int h2_name, char *sym_name)
{
	symrec *ptr;

	if(!h_name) return 0;
	for (ptr = sym_table; ptr != (symrec *) 0; ptr = (symrec *)ptr->next) {
		if (ptr->h_name == h_name && ptr->h2_name == h2_name){
			if(sym_name && !ptr->name) {
				ptr->SetName(sym_name);
				bRecent = true;
				}
			return ptr;
			}
		//predefined variables rarely end on a digit
		else if(ptr == sym_tab_first) {
			if(sym_name && isdigit(sym_name[strlen(sym_name)-1]) && strlen(sym_name) < 5) return 0;
			}
		}
	return 0;
}

static int
push(YYSTYPE *res, YYSTYPE *val)
{
	double *tmparr;

	if(res->type == RANGEARR || res->text) {
		if((tmparr = res->a_data) && (res->a_data = PushArray((double*)malloc((res->a_count+1)*sizeof(double))))){
			memcpy(res->a_data, tmparr, res->a_count * sizeof(double));
			res->type = ARR;	res->text = 0L;
			}
		}
	if(val->a_data) {
		if(!(res->a_data)) {
			if(!(val->a_data=ReallocArray(val->a_data, (val->a_count+2)*sizeof(double))))return 0;
			val->a_data[val->a_count++] = res->val;
			res->a_data = val->a_data;		res->a_count = val->a_count;
			val->a_data = 0L;			val->a_count = 0;
			val->val = res->val;			return 1;
			}
		else {
			if(!(res->a_data=ReallocArray(res->a_data, (val->a_count+res->a_count)*sizeof(double))))return 0;
			memcpy(&res->a_data[res->a_count], val->a_data, val->a_count*sizeof(double));
			res->a_count += val->a_count;
			val->a_data = 0L;			val->a_count = 0;
			return 1;
			}
		}
	if(!(res->a_data )){
		if(!(res->a_data =  PushArray((double*)malloc(2*sizeof(double)))))return 0;
		res->a_data[0] = res->val;			res->a_data[1] = val->val;
		res->a_count = 2;
		return 1;
		}
	else {
		if(!(res->a_data = ReallocArray(res->a_data, (res->a_count+2)*sizeof(double))))return 0; 
		res->a_data[res->a_count] = val->val;		res->a_count++;
		return 1;
		}
	return 0;
}

static int
range_array(YYSTYPE *res, char *range)
{
	RangeData.GetData(range, &res->a_data, &res->a_count, &res->text); 
	res->val = 0.0;		res->type = RANGEARR;
	return 1;
}

static int
range_array2(YYSTYPE *res1, YYSTYPE *res2)
{
	AccRange *r1, *r2;
	int row1, col1, row2, col2;
	anyResult ares1, ares2;
	char *range1, *range2;

	range1 = res1->text;	range2 = res2->text;
	if(!range1 || !range1[0] || !range2 || !range2[0] || !(r1 = new AccRange(range1)) 
		|| !(r2 = new AccRange(range2))) return 0;
	if(!r1->GetFirst(&col1, &row1) || !(res1->a_data =  PushArray((double*)malloc(r1->CountItems() * sizeof(double))))) {
		delete(r1);	delete(r2);
		return 0;
		}
	if(!r2->GetFirst(&col2, &row2) || !(res2->a_data =  PushArray((double*)malloc(r2->CountItems() * sizeof(double))))) {
		delete(r1);	delete(r2);
		return 0;
		}
	parse_level++;
	for(res1->a_count = res2->a_count = 0; r1->GetNext(&col1, &row1) && r2->GetNext(&col2, &row2); ) {
		if(curr_data->GetResult(&ares1, row1, col1, parse_level > MAX_PARSE) 
			&& curr_data->GetResult(&ares2, row2, col2, parse_level > MAX_PARSE)
			&& (ares1.type==ET_VALUE || ares1.type==ET_TIME || ares1.type==ET_DATE || ares1.type==ET_DATETIME || ares1.type==ET_BOOL)
			&& (ares2.type==ET_VALUE || ares2.type==ET_TIME || ares2.type==ET_DATE || ares2.type==ET_DATETIME || ares2.type==ET_BOOL)){
			res1->a_data[res1->a_count++] = ares1.value;
			res2->a_data[res2->a_count++] = ares2.value;
			}
		}
	parse_level--;	res1->type = res2->type = ARR;
	delete(r1);	delete(r2);
	return 1;
}

static YYSTYPE *proc_clause(YYSTYPE *res)
{
	int i, n, o_pos;
	char *o_cmd;
	double *n_data;

	if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return res;
	if(!res->text) return res;
	if(!res->a_data && (res->a_data = PushArray((double*)malloc(sizeof(double))))) {
		res->a_data[0] = res->type == VAR && res->tptr ? res->tptr->GetValue() : res->val;
		res->a_count = 1;
		}
	else if(!res->a_data) return res;
	if(!(n_data = PushArray((double*)malloc(res->a_count * sizeof(double))))) return res;
	o_pos = buff_pos;	o_cmd = buffer;
	for(i = n = 0; i < res->a_count; i++) {
		buffer = res->text;	buff_pos = 0;
		if(!syntax_level) break;
		syntax_level->clval = res->a_data[i];
		yyparse();
		if((line_res.type == ET_VALUE || line_res.type == ET_BOOL) && line_res.value != 0.0) n_data[n++] = res->a_data[i];
		}
	res->a_data = n_data;		res->a_count = n;
	res->text=0L;
	syntax_level->cl1 = syntax_level->cl2 = 0;
	buffer = o_cmd;	buff_pos = o_pos;
	return res;
}

static void exec_clause(YYSTYPE *res)
{
	int i, j;
	char *cmd;

	if((!res->a_data || res->a_count <2) && res->text && res->text[0]) range_array(res, res->text);
	if(!res->a_data) {
		if(res->a_data = PushArray((double*)malloc(2*sizeof(double)))) {
			res->a_data[0] = res->val;	res->a_count = 1;
			InfoBox("fixed data");
			}
		}
	if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return;
	if(!(cmd = (char*)malloc(syntax_level->cl2 - syntax_level->cl1 +2)))return;
	while(buffer[syntax_level->cl1] <= ' ' && syntax_level->cl1 < syntax_level->cl2) syntax_level->cl1++;
	for(j = 0, i = syntax_level->cl1; i< syntax_level->cl2; i++) {
		cmd[j++] = buffer[i];
		}
	cmd[j++] = ';';		cmd[j++] = 0;
	res->text = PushString(cmd);
	free(cmd);
}

struct parse_info  {
	char *buffer;
	int buff_pos;
	DataObj *curr_data;
	symrec *sym_table;
	YYSTYPE yylval;
	struct parse_info *next;
	char **str_list;
	double **arr_list;
	char *last_err_desc;
	int n_str, n_arr, yychar, yynerrs;
};
static parse_info *parse_stack = 0L;

static void push_parser()
{
	parse_info *ptr;

	if(!sym_table) InitArithFuncs(0L);
	else if(!parse_level && bRecent) ArrangeFunctions();
	ptr = (parse_info *) malloc(sizeof(parse_info));
	ptr->buffer = buffer;			ptr->buff_pos = buff_pos;
	ptr->curr_data = curr_data;		ptr->last_err_desc = last_err_desc;
	ptr->sym_table = sym_table;		sym_table = sym_tab_first;
	memcpy(&ptr->yylval, &yylval, sizeof(YYSTYPE));
	ptr->next = parse_stack;
	ptr->str_list = str_list;		str_list = 0L;
	ptr->n_str = n_str;			n_str = 0;
	ptr->arr_list = arr_list;		arr_list = 0L;
	ptr->n_arr = n_arr;			n_arr = 0;
	ptr->yychar = yychar;			ptr->yynerrs = yynerrs;
	parse_stack = ptr;			last_err_desc = 0L;
	parse_level++;				//reenter ?
	push_syntax();				syntax_level->last_tok = 0;
}

static void pop_parser()
{
	parse_info *ptr;
	symrec *n;

	if(ptr = parse_stack) {
		while(sym_table  && sym_table != sym_tab_first) {
			n = sym_table->next;
			delete(sym_table);
			sym_table = n;
			}
		if(sym_table) sym_table = ptr->sym_table;
		parse_stack = ptr->next;
		buffer = ptr->buffer;		buff_pos = ptr->buff_pos;
		curr_data = ptr->curr_data;	last_err_desc = ptr->last_err_desc;
		memcpy(&yylval, &ptr->yylval, sizeof(YYSTYPE));
		str_list = ptr->str_list;	n_str = ptr->n_str;
		arr_list = ptr->arr_list;	n_arr = ptr->n_arr;
		yychar = ptr->yychar;		yynerrs = ptr->yynerrs;
		free(ptr);
		parse_level--;
		}
	pop_syntax();
}

static int is_ttoken(unsigned int h_nam, unsigned int h2_nam)
{
	switch(h_nam) {
	case 69:
		if(h2_nam == 101) return E;
		break;
	case 393:
		if(h2_nam == 47081) return PI;
		break;
	case 28381:
		if((h2_nam & 0x7fffffff) == 0x7c2706ed) {
			if(syntax_level) syntax_level->cl1 = buff_pos;
			return CLAUSE;
			}
		break;
	case 20:
		if(h2_nam == 5220) return CLVAL;
		break;
	case 362:
		if(h2_nam == 42878) return (syntax_level->last_tok = IF);
		break;
	case 28421:
		if(h2_nam == 82147317) return (syntax_level->last_tok = WHILE);
		break;
	case 1518:
		if(h2_nam == 20654586) return (syntax_level->last_tok = FOR);
		break;
	case 370:
		if(h2_nam == 46206) return INARR;
		break;
	case 1457:
		if(h2_nam == 18357885) return DIM;
		break;
	case 108774:
		if(h2_nam == 0x27d5d1fe) return (syntax_level->last_tok = RETURN);
		break;
	case 23583:
		if(h2_nam == 0x954f67ff) return BREAK;
		break;
	case 6033:
		if((h2_nam & 0x7fffffff) == 0x6371377d) return (syntax_level->last_tok = ELSE);
		break;
	case 7097:
		if((h2_nam & 0x7fffffff) == 0x550a2d65) return BTRUE;
		break;
	case 23697:
		if((h2_nam & 0x7fffffff) == 0x155f977d) return BFALSE;
		break;
		}
	return 0;
}

static char *copy_block()
{
	char first[50], last[50], *res, *src;
	int i, j, level, mode;

	src = buffer + buff_pos-1;
	switch(*src){
	case '{':
		first[0] = '{';		last[0] = '}';	break;
	case '(':
		first[0] = '(';		last[0] = ')';	break;
	default:
		first[0] = '\0';	last[0] = ';';	break;
		}
	if(!(res = (char*)malloc(strlen(src)+2))) return 0L;
	for(i = 1, level = mode = j = 0; src[i]; i++) {
		res[j++] = src[i];
		if(mode && level) {					//embeded string
			if(src[i] == last[level]) {
				mode = 0;	level--;
				}
			res[j++] = src[i];
			}
		else {
 			if(src[i] == last[level]) {
				if(level) level--;
				else {
					if(res[j-2] == ';'){
						res[j-1] = 0;
						}
					else {
						res[j-1] = ';';		res[j] = 0;	
						}
					buff_pos += j;
					return res;
					}
				}
			else switch(src[i]) {
			case '"':
				level++;	first[level] = last[level] = '"';			break;
			case '\'':
				level++;	first[level] = last[level] = '\'';			break;
			case '{':
				level++;	first[level] = '{';		last[level] = '}';	break;
			case '(':
				level++;	first[level] = '(';		last[level] = ')';	break;
				}
			}
		}
	if(res[j-1] == ';') j--;
	res[j] = ';';	res[j+1] = 0;		buff_pos += j;
	return res;
}

static symrec *curr_sym;
static int for_loop(char *block1, char *block2)
{
	char *last_buffer, *bb1, *bb2, *bb3;
	int i, a_count, last_buff_pos, cb1, bres;
	double *a_data;
	YYSTYPE yyres, yysrc;
	symrec *var;

	if(!block1 || !block1[0] || bNoExec) return 0;
	bb1 = bb2 = bb3 = 0L;		parse_level++;
	cb1 = (int)strlen(block1);	bres = 0;
	last_buffer = buffer;		last_buff_pos = buff_pos;
	buffer = block1;		buff_pos = 0;
	//test for syntax 1
	bb1 = copy_block();
	if(buff_pos < cb1) bb2 = copy_block();
	if(buff_pos < cb1) bb3 = copy_block();
	if(bb1 && bb2 && bb3) {		//syntax 1 found !
		yysrc.text = bb1;	if(bb1[0]) bres = eval(&yyres, &yysrc);
		for(i = 0; !bres && i < yy_maxiter; i++) {
			yysrc.text = bb2;
			if(bb2[0]) {
				bres = eval(&yyres, &yysrc);
				if(yyres.type != NUM && yyres.type != BOOLVAL) yyres.val = 0.0;
				}
			else yyres.val = 1.0;
			if(yyres.val != 0.0) {
				if(block2 && block2[0]) {
					yysrc.text = block2;
					bres = eval(&yyres, &yysrc);
					}
				yysrc.text = bb3;
				bres = eval(&yyres, &yysrc);
				}
			else break;		
			}
		if(i) last_error = 0L;
		}
	//test for syntax 2
	else if(!bb2) {
		buff_pos = 0;
		if (VAR == yylex() && (var = curr_sym) && INARR == yylex() && buffer[buff_pos]){
			yysrc.text = buffer + buff_pos;
			bres = eval(&yyres, &yysrc);
			a_count = yyres.a_count;
			a_data = yyres.a_data;
			for(i = 0; !bres && i < a_count && i < yy_maxiter; i++) {
				var->SetValue(a_data[i]);
				if(block2 && block2[0]) {
					yysrc.text = block2;
					bres = eval(&yyres, &yysrc);
					}
				}
			last_error = 0;
			}
		else yyerror("parse error");
		}
	else yyerror("parse error");
	if(bb1) free(bb1);	if(bb2) free(bb2);	if(bb3) free(bb3);
	buffer = last_buffer;		buff_pos = last_buff_pos;
	parse_level--;
	return bres;
}

static int yylex()
{
	int i, c, tok;
	unsigned int h_nam, h2_nam;
	char tmp_txt[80], *block;
	symrec *s;

	memset(&yylval, 0, sizeof(YYSTYPE));
	while((c = buffer[buff_pos++]) == ' ' || c == '\t');	//get first nonwhite char
	if(!c) return 0;
	//test for implicit block statement
	if(syntax_level && (syntax_level->last_tok == PBLOCK 
		|| syntax_level->last_tok == ELSE || syntax_level->last_tok == RETURN) && c != '{'){
		buff_pos--;
		if(block = copy_block()) {
			yylval.text = PushString(block);
			free(block);
			}
		syntax_level->last_tok = 0;
		return yylval.type = IBLOCK;
		}
	//test for block statement
	if(c == '{') {
		if(block = copy_block()) {
			yylval.text = PushString(block);
			free(block);
			}
		syntax_level->last_tok = 0;
		return yylval.type = BLOCK;
		}
	//test for '..' operator
	if(c == '.' && buffer[buff_pos] == '.') {
		buff_pos++;
		return yylval.type = SER;
		}
	//test for number
	if(c > 31 &&(c == '.' || isdigit(c))) {
		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) == '.' || isdigit(c)); buff_pos++) {
			tmp_txt[i++] = (char)c;
			if(i && buffer[buff_pos+1] == 'e' && (buffer[buff_pos+2] == '-' || buffer[buff_pos+2] == '+')){
				tmp_txt[i++] = buffer[++buff_pos];
				tmp_txt[i++] = buffer[++buff_pos];
				}
			if(i && buffer[buff_pos+1] == '.' && buffer[buff_pos+2]  == '.') {	//operator '..'
				buff_pos++;
				break;
				}
			}
		tmp_txt[i] = 0;
#ifdef USE_WIN_SECURE
		sscanf_s(tmp_txt, "%lf", &yylval.val);
#else
		sscanf(tmp_txt, "%lf", &yylval.val);
#endif
		return yylval.type = NUM;
		}
	//test for name or stringtoken
	if(c > 31 && (isalpha(c) || c=='$' || c =='_')) {
 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$' || c == '_')); buff_pos++) {
			tmp_txt[i++] = (char)c; 
			}
		while(buffer[buff_pos] == ' ' || buffer[buff_pos] == '\t') buff_pos++;
		if(buffer[buff_pos] == ':' && !(syntax_level && syntax_level->last_tok == '?')){
			tmp_txt[i++] = buffer[buff_pos++];
			for(; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$')); buff_pos++) {
				tmp_txt[i++] = (char)c; 
				}
			tmp_txt[i] = 0;
			RangeData.GetData(tmp_txt, &yylval.a_data, &yylval.a_count, &yylval.text); 
			yylval.val = 0.0; 
			return yylval.type = (yylval.a_data && yylval.a_count) ? RANGEARR : STR;
			}
		tmp_txt[i] = 0;
		h_nam = HashValue((unsigned char*)tmp_txt);
		h2_nam = Hash2((unsigned char*)tmp_txt);
		if(h_nam == 1550 && h2_nam == 18852086) {	//'inf' = huge value
			yylval.val = HUGE_VAL;
			return yylval.type = NUM;
			}
		if(tok = is_ttoken(h_nam, h2_nam)) return tok;
		if(!(s = getsym(h_nam, h2_nam, tmp_txt))){
			s = putsym(h_nam, h2_nam, VAR);
			s->SetName(tmp_txt);
			}	
		curr_sym = yylval.tptr = s;	return s->type;
		}
	//test for string
	if(c == '"' || c == '\'') {
		for(i= 0; i < 79 && ((tok = buffer[buff_pos]) && (tok != c)); buff_pos++) {
			tmp_txt[i++] = (char)tok;
			}
		if(buffer[buff_pos] == c)buff_pos++;
		tmp_txt[i] = 0;
		yylval.text = PushString(tmp_txt);
		return yylval.type = STR;
		}
	tok = 0;
	switch(c) {
	case '=':
		if(buffer[buff_pos] == '=') tok = EQ;
		break;
	case '!':
		if(buffer[buff_pos] == '=') tok = NE;
		break;
	case '>':
		if(buffer[buff_pos] == '=') tok = GE;
		else return GT;
		break;
	case '<':
		if(buffer[buff_pos] == '=') tok = LE;
		else if(buffer[buff_pos] == '>') tok = NE;
		else return LT;
		break;
	case '&':
		if(buffer[buff_pos] == '&') tok = AND;
		break;
	case '|':
		if(buffer[buff_pos] == '|') tok = OR;
		break;
	case ')':
		if(syntax_level) {
			if(syntax_level->cl1 && syntax_level->next) {
				syntax_level->next->cl1 = syntax_level->cl1;
				syntax_level->next->cl2 = buff_pos-1;
				}
			}
		pop_syntax();
		break;
	case '(':
		if(syntax_level->last_tok == WHILE || syntax_level->last_tok == FOR
			|| syntax_level->last_tok == IF){
			if(block = copy_block()) {
				yylval.text = PushString(block);
				free(block);
				}
			return yylval.type = syntax_level->last_tok = PBLOCK;
			}
		push_syntax();
		if(syntax_level) syntax_level->last_tok = c;
		break;
	case '?':
		if(syntax_level) syntax_level->last_tok = c;
		break;
	case ':':
		if(syntax_level) {
			if(syntax_level->last_tok == '?') return COLC;
			}
		break;
	case ';':
		if(buff_pos <2)return yylex();
		if(syntax_level) {
			if(syntax_level->last_tok == '(') return PSEP;
			else syntax_level->last_tok = 0;
			}
		break;
	case ',':
		if(syntax_level && syntax_level->last_tok == '(') return LSEP;
		break;
	case '*':
		if(buffer[buff_pos] == '=') tok = MULEQ;
		break;
	case '/':
		if(buffer[buff_pos] == '=') tok = DIVEQ;
		break;
	case '+':
		if(buffer[buff_pos] == '+') tok = INC;
		else if(buffer[buff_pos] == '=') tok = ADDEQ;
		break;
	case '-':
		if(buffer[buff_pos] == '-') tok = DEC;
		else if(buffer[buff_pos] == '=') tok = SUBEQ;
		break;
		}
	if(tok) {
		buff_pos++;		return tok;
		}
	//Any other character is a token by itself
	if(c < 0 || c > 127)yytokenerr(c);
	return c;
}

static unsigned int hn_x = HashValue((unsigned char *)"x");
static unsigned int hn_y = HashValue((unsigned char *)"y");
static unsigned int hn_z = HashValue((unsigned char *)"z");
static unsigned int h2_x = Hash2((unsigned char *)"x");
static unsigned int h2_y = Hash2((unsigned char *)"y");
static unsigned int h2_z = Hash2((unsigned char *)"z");

bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOINT **pts, long *npts, char *param)
{
	double x, y;
	symrec *sx, *sy;
	lfPOINT *new_points;
	long npoints = 0;
	int length, parse_res, res_mode = 0;

	if(x1 < x2) step = fabs(step);
	else if(x1 == x2) return false;
	else step = -fabs(step);
	if(!(new_points = (lfPOINT*)calloc((iround(fabs(x2-x1)/fabs(step))+2), sizeof(lfPOINT))))
		return false;
	if(d) curr_data = d;
	push_parser();
	init_table();
	if(param) {
		length = (int)strlen(param);
		if(!(buffer = (char*)malloc(length+2))){
			pop_parser();
			return false;
			}
		rlp_strcpy(buffer, length+1, param);
		buffer[length++] = ';';
		buffer[length] = 0;	buff_pos = 0;
		while(!(parse_res = yyparse()) && buff_pos < length);
		free(buffer);		buffer = 0L;
		}		
	length = (int)strlen(expr);
	buffer = expr;		sx = putsym(hn_x, h2_x, VAR);
	for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) {
		if(sx){
			sx->SetValue(x);	buff_pos = 0;
			while(!(parse_res = yyparse()) && buff_pos < length);
			switch (res_mode) {
			case 1:
				y = sy->GetValue();	break;
			case 2:
				y = line_res.value;	break;
			default:
				if(sy = getsym(hn_y, h2_y)) {
					y = sy->GetValue();	res_mode = 1;
					}
				else {
					y = line_res.value;	res_mode = 2;
					}
				break;
				}
			new_points[npoints].fx = (getsym(hn_x, h2_x))->GetValue();
			new_points[npoints++].fy = y;
			}
		}
	*pts = new_points;	*npts = npoints;
	clear_table();
	pop_parser();
	if(d) {
		d->Command(CMD_CLEAR_ERROR, 0L, 0L);
		d->Command(CMD_REDRAW, 0L, 0L);
		}
	return true;
}

bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double z2, double zstep, 
	char *expr, char *param)
{
	int length, parse_res, nr, nc, r, c, res_mode=0;
	symrec *sx, *sz, *sy;
	double x, y, z;

	if(!d || x2 <= x1 || z2 <= z1 || xstep <= 0.0 || zstep <= 0.0) return false;
	push_parser();
	init_table();
	if(param) {
		length = (int)strlen(param);
		if(!(buffer = (char*)malloc(length+2))){
			pop_parser();
			return false;
			}
		rlp_strcpy(buffer, length+1, param);
		buffer[length++] = ';';
		buffer[length] = 0;	buff_pos = 0;
		while(!(parse_res = yyparse()) && buff_pos < length);
		free(buffer);		buffer = 0L;
		}		
	length = (int)strlen(expr);		buffer = expr;
	sx = putsym(hn_x, h2_x, VAR);	sz = putsym(hn_z, h2_z, VAR);
	nr = iround((z2-z1)/zstep)+1;	nc = iround((x2-x1)/xstep)+1;
	d->Init(nr, nc);
	for(r = 0, x = x1; r < nr; r++, x += xstep) {
		for(c = 0, z = z1; c < nc; c++, z+= zstep) {
			sx->SetValue(x);	sz->SetValue(z);	buff_pos = 0;
			while(!(parse_res = yyparse()) && buff_pos < length);
			switch (res_mode) {
			case 1:
				y = sy->GetValue();	break;
			case 2:
				y = line_res.value;	break;
			default:
				if(sy = getsym(hn_y, h2_y)) {
					y = sy->GetValue();	res_mode = 1;
					}
				else {
					y = line_res.value;	res_mode = 2;
					}
				break;
				}
			d->SetValue(r, c, y);
			}
		} 
	clear_table();
	pop_parser();
	return true;
}

anyResult *do_formula(DataObj *d, char *expr)
{
	int length, parse_res;
	static anyResult ret, *pret = 0L;

	if(d) curr_data = d;
	ret.type = ET_ERROR;		ret.text = 0L;
	ret.a_data = 0L;		ret.a_count = 0;
	if(!expr || !expr[0]) {
		if(!sym_table) InitArithFuncs(0L);
		last_error = 0L;
		return &ret;
		}
	push_parser();		//make code reentrant
	init_table();		length = (int)strlen(expr);
	if(!(buffer = (char*)malloc(length+2))){
		pop_parser();
		return &ret;
		}
	rlp_strcpy(buffer, length+1, expr);
	if(buffer[length-1] != ';') buffer[length++] = ';';
	buffer[length] = 0;	buff_pos = 0;
	while(!(parse_res= yyparse()) && buff_pos < length);
	ret.type = ET_ERROR;		ret.text = 0L;
	if(parse_res == 1 && curr_data) {
		if(last_error && (!(strcmp(last_error, "parse error")))) curr_data->Command(CMD_ERROR, 0L, 0L);
		if(last_err_desc) pret = &line_res;
		else pret = &ret;
		}
	else pret = &line_res;
	last_error = last_err_desc = 0L;
	free(buffer);		buffer = 0L;
	clear_table();
	pop_parser();
	return pret;
}

bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int r0, int c0)
{
	int length, length2, tok, pos, i;
	char *res, desc1[2], desc2[2];

	if(d) curr_data = d;
	if(!curr_data || !of || !of[0] || !nf) return false;
	push_parser();		//make code reentrant
	init_table();		length = (int)strlen(of);
	if(!(buffer = (char*)malloc(length+2))){
		pop_parser();
		return false;
		}
	rlp_strcpy(buffer, length+1, of);	buffer[length++] = ';';
	buffer[length] = 0;	buff_pos = pos = 0;
	if(!(res = (char *)calloc(length2 = (length*2+10), sizeof(char))))return false;
	length2--;
	do {
		tok = yylex ();
		if(tok && tok < 256) {
			if(res[pos-1] == ' ') pos--;
			res[pos++] = (char)tok;
			}
		else switch(tok) {
			case NUM:
#ifdef USE_WIN_SECURE
				pos += sprintf_s(res+pos, 20, "%g", yylval.val);
#else
				pos += sprintf(res+pos, "%g", yylval.val);
#endif
				break;
			case FNCT:	case FUNC1:	case AFNCT:	case SFNCT:
			case SRFUNC:	case BFNCT:	case YYFNC:	case FUNC4:	case YYFNC2:
			case YYFNC3:
				pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
				break;
			case COLC:
				res[pos++] = ':';
				break;
			case PSEP:
				res[pos++] = ';';
				break;
			case LSEP:
				res[pos++] = ',';
				break;
			case CLVAL:
				res[pos++] = '$';	res[pos++] = '$';
				break;
			case CLAUSE:
				pos += rlp_strcpy(res+pos, length2-pos, " where ");
				break;
			case DIM:
				pos += rlp_strcpy(res+pos, length2-pos, "dim ");
				break;
			case VAR:
				curr_sym->InitSS();
				if(curr_sym->col >= 0 && curr_sym->row >= 0) {
					desc1[0] = desc1[1] = desc2[0] = desc2[1] = 0;
					for(i=(int)strlen(curr_sym->name)-1; i>0 && isdigit(curr_sym->name[i]); i--);
					if(curr_sym->name[0] == '$') desc1[0] = '$';
					if(curr_sym->name[i] == '$') desc2[0] = '$';
#ifdef USE_WIN_SECURE
					pos += sprintf_s(res+pos, length2-pos, "%s%s%s%d", desc1,
#else
					pos += sprintf(res+pos, "%s%s%s%d", desc1, 
#endif
						Int2ColLabel(desc1[0] || curr_sym->col < c0 ? curr_sym->col : curr_sym->col+dx >=0 ?
						curr_sym->col+dx > c0 ? curr_sym->col+dx : c0 : 0, false),
						desc2, desc2[0] || curr_sym->row < r0 ? curr_sym->row+1 : curr_sym->row + dy >= 0 ? 
						curr_sym->row+dy > r0 ? curr_sym->row+1+dy : r0 : 1);
					}
				else pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
				break;
			case STR:
				pos += rlp_strcpy(res+pos, length2-pos, "\"");
				pos += rlp_strcpy(res+pos, length2-pos, yylval.text);
				pos += rlp_strcpy(res+pos, length2-pos, "\"");
				break;
			case SER:
				res[pos++] = '.';	res[pos++] = '.';
				break;
			case INC:
				res[pos++] = '+';	res[pos++] = '+';
				break;
			case DEC:
				res[pos++] = '-';	res[pos++] = '-';
				break;
			case PI:
				res[pos++] = 'p';	res[pos++] = 'i';
				break;
			case E:
				res[pos++] = 'e';
				break;
			case BTRUE:
				pos += rlp_strcpy(res+pos, length2-pos, "true");
				break;
			case BFALSE:
				pos += rlp_strcpy(res+pos, length2-pos, "false");
				break;
			case AND:
				pos += rlp_strcpy(res+pos, length2-pos, " && ");
				break;
			case OR:
				pos += rlp_strcpy(res+pos, length2-pos, " || ");
				break;
			case EQ:
				pos += rlp_strcpy(res+pos, length2-pos, " == ");
				break;
			case NE:
				pos += rlp_strcpy(res+pos, length2-pos, " != ");
				break;
			case GT:
				res[pos++] = '>';
				break;
			case GE:
				res[pos++] = '>';	res[pos++] = '=';
				break;
			case LT:
				res[pos++] = '<';
				break;
			case LE:
				res[pos++] = '<';	res[pos++] = '=';
				break;
			case IF: 
				res[pos++] = 'i';	res[pos++] = 'f';
				break;
			case ADDEQ: 
				res[pos++] = '+';	res[pos++] = '=';
				break;
			case SUBEQ: 
				res[pos++] = '-';	res[pos++] = '=';
				break;
			case MULEQ: 
				res[pos++] = '*';	res[pos++] = '=';
				break;
			case DIVEQ: 
				res[pos++] = '/';	res[pos++] = '=';
				break;
			case WHILE: 
				pos += rlp_strcpy(res+pos, length2-pos, "while");
				break;
			case FOR: 
				pos += rlp_strcpy(res+pos, length2-pos, "for");
				break;
			case INARR: 
				pos += rlp_strcpy(res+pos, length2-pos, "in");
				break;
			case ELSE: 
				pos += rlp_strcpy(res+pos, length2-pos, "else");
				break;
			case RETURN:
				pos += rlp_strcpy(res+pos, length2-pos, " return");
				break;
			case BREAK:
				pos += rlp_strcpy(res+pos, length2-pos, " break");
				break;
			case RANGEARR:
				if(yylval.text && yylval.text[0]) {
					for(i = 0; yylval.text[i]; i++) if(yylval.text[i] == ':') {
						yylval.text[i] = ';';	break;
						}
					MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
					}
				while(res[pos]) {
					pos++;			if(res[pos] == ';') res[pos] = ':';
					}
				break;
			case BLOCK:
				res[pos++] = '{';
				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
				pos += (int)strlen(res+pos);
				res[pos++] = '}';
				break;
			case IBLOCK:
				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
				pos += (int)strlen(res+pos);
				res[pos++] = ';';
				break;
			case PBLOCK:
				res[pos++] = '(';
				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
				pos += (int)strlen(res+pos);
				res[pos++] = ')';
				break;
			}
		res[pos] = 0;
		}while(buff_pos < length);
	while((res[pos-1] == ';' || res[pos-1] == ' ') && pos > 0) { res[pos-1] = 0; pos--;} 
	rlp_strcpy(nf, nfsize, res);	free(res);
	free(buffer);		buffer = 0L;
	clear_table();
	pop_parser();
	return true;
}

static char *txt_formula;	//function to fit
static double **parval;		//pointers to parameter values
static void fcurve(double x, double z, double **a, double *y, double dyda[], int ma)
{
	int i, length, parse_res;
	double tmp, y1, y2;
	symrec *symx, *symz, *sy=0L;

	if(!(symx = getsym(hn_x, h2_x))) symx = putsym(hn_x, h2_x, VAR);
	if(!(symz = getsym(hn_z, h2_z))) symz = putsym(hn_z, h2_z, VAR);
	//swap parameters to requested set
	if(a != parval) for(i = 0; i < ma; i++) {
		tmp = *parval[i];	*parval[i]  = *a[i];	*a[i] = tmp;
		}
	//calc result
	symx->SetValue(x);	symz->SetValue(z);	
	buffer = txt_formula;	bNoSS = true;
	buff_pos = 0;		length = (int)strlen(txt_formula);
	while(!(parse_res = yyparse()) && buff_pos < length);
	if(sy = getsym(hn_y, h2_y)) *y = sy->GetValue();
	else *y = line_res.value;
	if(*y == HUGE_VAL || *y == -HUGE_VAL) {
		for(i = 0, *y = 0.0; i < ma; dyda[i++] = 0.0);
		return;
		}
	//partial derivatives for each parameter by numerical differentiation
	for(i = 0; i < ma; i++) {
		if(*parval[i] != 0.0) {
			tmp = *parval[i];
			*parval[i] = tmp*.995;
			buff_pos = 0;
			while(!(parse_res = yyparse()) && buff_pos < length);
			y1 = sy ? sy->GetValue() : line_res.value;
			*parval[i] = tmp*1.005;
			buff_pos = 0;
			while(!(parse_res = yyparse()) && buff_pos < length);
			y2 = sy ? sy->GetValue() : line_res.value;
			*parval[i] = tmp;
			dyda[i] = (y2-y1)*100.0/tmp;
			}
		else dyda[i] = 0.0;
		}
	//swap parameters back to original
	if(a != parval) for(i = 0; i < ma; i++) {
		tmp = *parval[i];	*parval[i]  = *a[i];	*a[i] = tmp;
		}
	bNoSS = false;
}

int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, double conv, int maxiter, double *chi_2)
{
	int length, i, j, k, l, ndata, nparam, r1, r2, r3, c1, c2, c3;
	int *lista, itst, itst1, parse_res;
	symrec *tab1, *tab2, *csr, **parsym;
	AccRange *arx, *ary, *arz;
	double *x, *y, *z, currx, curry, currz, alamda, chisq, ochisq;
	double **covar, **alpha;
	char tmp_txt[500];

	if(d) curr_data = d;
	if(chi_2) *chi_2 = 0.0;
	txt_formula = expr;
	if(!curr_data || !par || !expr || !rx || !ry) return 0;
	//process ranges and create arrays
	arx = ary = arz = 0L;	x = y = z = 0L;	parval = 0L;	parsym = 0L;
	if(!(arx = new AccRange(rx)))return 0;
	i = arx->CountItems()+1;
	if(!(ary = new AccRange(ry))){
		delete arx;	return 0;
		}
	if(rz && !(arz = new AccRange(rz))){
		delete ary;	delete arx;	return 0;
		}
	if(!(x = (double*)malloc(i * sizeof(double)))){
		if(arz) delete arz;
		delete ary;	delete arx;	return 0;
		}
	if(!(y = (double*)malloc(i * sizeof(double)))){
		if(arz) delete arz;
		free(x);	delete arx;	delete ary;	return 0;
		}
	if(rz && !(z = (double*)malloc(i * sizeof(double)))){
		if(arz) delete arz;
		free(y);	free(x);	delete arx;	delete ary;	return 0;
		}
	arx->GetFirst(&c1, &r1);	ary->GetFirst(&c2, &r2);
	if(rz) arz->GetFirst(&c3, &r3);
	for(ndata = j = 0; j < i; j++) {
		if(rz) {
			if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) && arz->GetNext(&c3, &r3) &&
				curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry) &&
				curr_data->GetValue(r3, c3, &currz)) {
				x[ndata] = currx;	y[ndata] = curry;	z[ndata] = currz;	ndata++;
				}
			}
		else {
			if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) &&
				curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry)) {
				x[ndata] = currx;	y[ndata] = curry;	ndata++;
				}
			}
		}
	//common initialization for parser tasks
	push_parser();		//make code reentrant
	init_table();		length = (int)strlen(*par);
	//process parameters
	if(!(buffer = (char*)malloc(length+2))){
		clear_table();	pop_parser();
		if(arz) delete arz;
		free(y);	free(x);	delete arx;	delete ary;
		return 0;
		}
	rlp_strcpy(buffer, length, *par);	buffer[length++] = ';';
	buffer[length] = 0;	buff_pos = 0;
	tab1 = sym_table;
	while(!(parse_res = yyparse()) && buff_pos < length);
	tab2 = sym_table;	free(buffer);	buffer =0L;
	for(nparam = 0, csr=tab2; csr != tab1; nparam++, csr = csr->next);
	parsym = (symrec**)malloc((nparam+1)*sizeof(symrec*));
	parval = (double**)malloc((nparam+1)*sizeof(double*));
	for(i = 0, csr=tab2; csr != tab1 && i < nparam; i++, csr = csr->next){
		parsym[i] = csr;	parval[i] = &csr->var;
		}
	//do iteratations to optimize fit
	lista = (int*)malloc(sizeof(int)*nparam);
	for(i = 0; i< nparam; i++) lista[i] = i;
	covar = dmatrix(1, nparam, 1, nparam);
	alpha = dmatrix(1, nparam, 1, nparam);
	alamda = -1.0;		itst = 0;
	mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
	if(!Check_MRQerror()) {
		for(itst = itst1 = 0, ochisq = chisq; itst < maxiter && chisq > conv && ochisq >= chisq && itst1 < 9; itst++) {
			ochisq = chisq;
			mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
			if(ochisq == chisq) itst1++;
			else itst1 = 0;
			}
		alamda = 0.0;
		mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
		Check_MRQerror();
		}
	bNoSS = true;
	for(i = nparam-1, j = k = l = 0; i >= 0; l = 0, i--) {
		if(k > 20) {
			if(tmp_txt[j-1] == ' ') j--;
			if(tmp_txt[j-1] == ';') j--;
#ifdef USE_WIN_SECURE
			l = sprintf_s(tmp_txt+j, 500-j, "\n");
#else
			l = sprintf(tmp_txt+j, "\n");
#endif
			j += l;		k = 0;
			}
#ifdef USE_WIN_SECURE
		l += sprintf_s(tmp_txt+j, 500-j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue());
#else
		l += sprintf(tmp_txt+j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue());
#endif
		j += l;			k += l;
		}
	free(*par);
	*par = (char*)memdup(tmp_txt, (int)strlen(tmp_txt)+1, 0);
	if(chi_2) *chi_2 = chisq;
	//write back spreadsheet data if necessary
	buffer = *par;	length = (int)strlen(buffer);
	while(!(parse_res = yyparse()) && buff_pos < length);
	buffer = 0L;
	free_dmatrix(alpha, 1, nparam, 1, nparam);
	free_dmatrix(covar, 1, nparam, 1, nparam);
	if(arz) delete arz;		if(z) free(z);
	free(y);	free(x);	delete arx;	delete ary;
	if(parval) free(parval);	if(parsym) free(parsym);
	clear_table();
	pop_parser();
	if(d){
		d->Command(CMD_CLEAR_ERROR, 0L, 0L);
		d->Command(CMD_REDRAW, 0L, 0L);
		}
	bNoSS = false;
	return itst < maxiter ? itst+1 : maxiter;
}

