/*

  This is a part of the Project Frontier's Source code.

  Copyright (C) 1997-98 Francis Gastellu
                    aka Lone Runner/Aegis

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
%{

#define YYSTYPE char*
#pragma warn -ias

#define LOOP_WHILE  1
#define LOOP_FOR    2
#define LOOP_IF     3
#define LOOP_CASE   4
#define LOOP_ELSEIF 5

#define STRCONST 1
#define INTCONST 2
#define HEXCONST 3
#define SYMBOL   4
#define DBLCONST 5

#define FUNC_IDENTIFIER 1
#define PROC_IDENTIFIER 2
#define VAR_IDENTIFIER  3

void sendVar(int varnum);
void nextArg(void);
void sendFunc(int funcnum);
void registerIdent(char *data);
void registerIdentList(int type);
void checkIdentifier(void);
char *mkFunc(int f);
char *mkStat(unsigned int s);
char *concat(char *c1, char *c2);
char *separator(int s, int argNum);
void initbuild(void);
void build(char *value);
char *retreiveBuild(void);
char *newTempLabel(void);
void fakeNextLabel(char *);
void pushLabelStack(char *s);
char *popLabelStack(void);
char *lookup(int type);
void pushSelect(char *var);
char *popSelect(void);
void switchLastLabels(void);
char *semValue(char *s);
void checkDim(char *var, int n);
char *semText(char *s);
void invalidVar(char *v);
void registerProc(char *procName, int nArgs, char *argTypes, int pf, int funcReturnType);
void checkProc(char *procName, int nArgs, char *argTypes, int pf, int funcReturnType);
char *zero(void);
void enterProc(char *procName, int type);
void leaveProc(int type);
char *toVar(char *sem);
void correctAssign(void);
void checkFunc(int func, int npar);
void pushParamN(int n);
int popParamN(void);
void checkUserProc(int varnum, int nargs);
void tooManyArgsProc(int p);
void notEnoughArgsProc(int p);
void honnor(int ver);
void checkStatArg(char *s, char *a1, char *a2, char *a3, char *a4, char *a5, char *a6, char *a7, char *a8, char *a9, char *a10);
int argClass(char *arg);
void checkUserProcArgTypes(char *p, int n);
void internalFunc(char *f);
void internalProc(char *f);
void closeLoop(char *s, int loopType);
void checkLoop(char *s, int loopType);
void checkProcFuncName(char *w);
void initLogicalLine(void);
void closeLogicalLine(void);

extern int curArg, statArg;
extern int totalArgs;
extern char yytext[256];
extern char predefValue[];
extern char **labelStack;
extern int labelStackSize;
extern int labelStackPos;
extern int errorOccured;
char *c;
int nCase;
int aa, b;
extern char far msg[];
extern int *loop;
extern int loopSize;
extern int loopPos;
extern int identHdr;
extern int procCount;
extern int beginUsed;
extern int lexn;
extern int declaration, mustBeType;
extern int allowTo;
extern int allowStep;
extern int yyStackSize;

extern char nDim;
extern int dim1, dim2, dim3;

char *wh3, *if3, *fn1, *fn2;
extern int totalParam;

char userProcArgType[256];
extern int linePart;

extern int forceLabel;

%}

%token TYPE

%token DECLARE BEGIN PROCEDURE FUNCTION
%token BREAK CONTINUE END
%token SELECT CASE DEFAULT ENDSELECT SUBRANGE
%token WHILE DO ENDWHILE
%token FOR TO STEP NEXT
%token GOSUB GOTO GO SUB
%token IF THEN ELSE ELSEIF ENDIF
%token FUNC PROC
%token VAR
%token LABELMARKER

%token OP_AND OP_OR OP_NOT OP_LE OP_AE OP_EQ OP_NE OP_LO OP_AB

%token INTFUNC
%token S_0ARG S_1ARG S_2ARG S_3ARG S_4ARG S_5ARG S_6ARG S_7ARG S_8ARG S_9ARG S_10ARG
%token S_0PARG S_1PARG S_2PARG
%token S_1T4ARG
%token LET

%token IDENTIFIER USERPROC USERFUNC

%left OP_AND OP_OR
%left OP_LE OP_AE OP_EQ OP_NE OP_LO OP_AB '='
%left '-' '+'
%left '*' '/' '%'
%left UNARAY
%right '^'

%%

/* --------------------------------------------------------------------------
 *  LINES OF CODE
 * --------------------------------------------------------------------------
 */

physical_line
	: line
    | physical_line_separator line
    ;

physical_line_separator
	: physical_line ':' { closeLogicalLine(); initLogicalLine(); }
    ;

line
	: /* empty */
	| code_line 	{ sendToBuffer($1+2, *(int *)$1); }
    | nocode_line
    ;

code_line
    : statement                                     { $$ = $1; }
    | switch_case                                   { $$ = $1; }
    | label_marker                                  { $$ = $1; }
    | begin                                         { $$ = $1; }
    | endfuncproc                                   { $$ = $1; }
    | for_end                                       { $$ = $1; }
    | endwhile                                      { $$ = $1; }
    ;

nocode_line
	: identifier_declaration
    | procedure_declaration
    | function_declaration
    | procedure_body
    | function_body                                 
    ;

/* --------------------------------------------------------------------------
 *  ARGS & EXPR
 * --------------------------------------------------------------------------
 */

primary_expr
	: any_identifier	{ $$ = $1; }
    | function_call 	{ $$ = $1; }
    | '(' math_expr ')' { $$ = $2; }
    ;

math_expr
	: primary_expr           		{ $$ = $1; }
    | math_expr OP_LE math_expr 	{ $$ = concat(concat($1, $3), mkFunc(13)); }
    | math_expr OP_AE math_expr 	{ $$ = concat(concat($1, $3), mkFunc(15)); }
    | math_expr OP_EQ math_expr 	{ $$ = concat(concat($1, $3), mkFunc(10)); }
    | math_expr '=' math_expr 		{ $$ = concat(concat($1, $3), mkFunc(10)); }
    | math_expr OP_NE math_expr 	{ $$ = concat(concat($1, $3), mkFunc(11)); }
    | math_expr OP_LO math_expr 	{ $$ = concat(concat($1, $3), mkFunc(12)); }
    | math_expr OP_AB math_expr 	{ $$ = concat(concat($1, $3), mkFunc(14)); }
    | math_expr OP_AND math_expr 	{ $$ = concat(concat($1, $3), mkFunc(17)); }
    | math_expr OP_OR math_expr 	{ $$ = concat(concat($1, $3), mkFunc(18)); }
    | math_expr '+' math_expr 		{ $$ = concat(concat($1, $3), mkFunc(8)); }
    | math_expr '-' math_expr 		{ $$ = concat(concat($1, $3), mkFunc(9)); }
    | math_expr '/' math_expr 		{ $$ = concat(concat($1, $3), mkFunc(6)); }
    | math_expr '*' math_expr 		{ $$ = concat(concat($1, $3), mkFunc(5)); }
    | math_expr '%' math_expr 		{ $$ = concat(concat($1, $3), mkFunc(7)); }
    | math_expr '^' math_expr 		{ $$ = concat(concat($1, $3), mkFunc(4)); }
    | '-' math_expr %prec UNARAY    { $$ = concat($2, mkFunc(3)); }
    | '+' math_expr %prec UNARAY    { $$ = concat($2, mkFunc(2)); }
    | OP_NOT math_expr %prec UNARAY { $$ = concat($2, mkFunc(16)); }
    ;

expr
	: math_expr 		 { $$ = $1; }
    ;

/* arg is a statement argument */

arg
	: math_expr { $$ = $1; totalArgs++;}
    ;

arg_list
	: arg 				{ $$ = $1; userProcArgType[totalArgs-1] = argClass($1); }
    | arg_list ',' arg 	{ $$ = concat($1, concat(mkStat(0), $3)); userProcArgType[totalArgs-1] = argClass($3); }
    ;

param
	: math_expr { $$ = $1; totalParam++; }
    ;

internalfunc_param_list
	: param                				{ $$ = $1; }
    | internalfunc_param_list ',' param { $$ = concat($1, $3); }
    ;

userfunc_param_list
	: param                             { $$ = $1; }
    | userfunc_param_list ',' param     { $$ = concat($1, concat(mkStat(0),$3)); }
    ;

function_call
	: internal_func '(' ')' 											{ checkFunc(*(int *)($1+2), totalParam); $$ = mkFunc(*(int *)($1+2)); totalParam=popParamN(); }
    | internal_func '(' internalfunc_param_list ')'                     { checkFunc(*(int *)($1+2), totalParam); $$ = concat($3, mkFunc(*(int *)($1+2))); totalParam=popParamN(); }
    | internal_func 													{ $$ = zero(); yyerror("opening parenthesis not found"); }
    | user_function_call                                                { $$ = $1; }
    ;

internal_func
	: INTFUNC { $$ = $1; pushParamN(totalParam); }
    ;

user_func
	: USERFUNC { $$ = $1; pushParamN(totalParam); }

user_function_call
	: user_func '(' userfunc_param_list ')'	{
									honnor(1520);
								  	initbuild();
                                  	build($1);
                                  	build(mkStat(0));
                                  	build($3);
                                  	build(mkStat(0));
                                  	$$ = retreiveBuild();
                                    checkUserProc(*(int *)($1+2), totalParam);
                                    totalParam=popParamN();
									}
	| user_func '(' ')'          	{
									honnor(1520);
								  	initbuild();
                                  	build($1);
                                  	build(mkStat(0));
                                  	$$ = retreiveBuild();
                                    if (totalParam != 0)
                                    	yyerror("internal error counting number of parameters in function");
                                    checkUserProc(*(int *)($1+2), totalParam);
                                    totalParam=popParamN();
									}
    ;

/* --------------------------------------------------------------------------
 *  STATEMENTS
 * --------------------------------------------------------------------------
 */

user_procedure_call
	: USERPROC '(' arg_list ')' 	{
									honnor(1520);
									initbuild();
                                  	build(mkStat(0xA8));
                                  	build($1);
                                  	build(mkStat(0));
                                  	build($3);
                                  	build(mkStat(0));
                                  	$$ = retreiveBuild();
                                    checkUserProc(*(int *)($1+2), totalArgs);
                                    checkUserProcArgTypes($1, totalArgs);
									}
	| USERPROC '(' ')'          	{
									honnor(1520);
								  	initbuild();
                                  	build(mkStat(0xA8));
                                  	build($1);
                                  	build(mkStat(0));
                                  	$$ = retreiveBuild();
                                    if (totalArgs != 0)
                                    	yyerror("internal error counting number of parameters in procedure");
                                    checkUserProc(*(int *)($1+2), totalArgs);
                                    checkUserProcArgTypes($1, totalArgs);
									}
    ;

internal_statement
	: S_0ARG 									 										  { $$ = mkStat(*(int *)($1+2)); }
    | S_1ARG arg								 										  {
    																			            checkStatArg($1, $2, 0, 0, 0, 0, 0, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							$$ = retreiveBuild();
																						  }
    | S_2ARG arg ',' arg 						 										  {
    																			            checkStatArg($1, $2, $4, 0, 0, 0, 0, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							$$ = retreiveBuild();
																						  }
    | S_3ARG arg ',' arg ',' arg 				 										  {
    																			            checkStatArg($1, $2, $4, $6, 0, 0, 0, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							$$ = retreiveBuild();
																						  }
    | S_4ARG arg ',' arg ',' arg ',' arg         										  {
    																			            checkStatArg($1, $2, $4, $6, $8, 0, 0, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							build($8);
																							build(separator(*(int *)($1+2), 4));
																							$$ = retreiveBuild();
																						  }
    | S_5ARG arg ',' arg ',' arg ',' arg ',' arg 										  {
    																			            checkStatArg($1, $2, $4, $6, $8, $10, 0, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							build($8);
																							build(separator(*(int *)($1+2), 4));
																							build($10);
																							build(separator(*(int *)($1+2), 5));
																							$$ = retreiveBuild();
																						  }
    | S_6ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg                                  {
    																			            checkStatArg($1, $2, $4, $6, $8, $10, $12, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							build($8);
																							build(separator(*(int *)($1+2), 4));
					   																		build($10);
																							build(separator(*(int *)($1+2), 5));
																							build($12);
																							build(separator(*(int *)($1+2), 6));
																							$$ = retreiveBuild();
																						  }
    | S_7ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg                          {
    																			            checkStatArg($1, $2, $4, $6, $8, $10, $12, $14, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							build($8);
																							build(separator(*(int *)($1+2), 4));
																							build($10);
																							build(separator(*(int *)($1+2), 5));
																							build($12);
																							build(separator(*(int *)($1+2), 6));
																							build($14);
																							build(separator(*(int *)($1+2), 7));
																							$$ = retreiveBuild();
																						  }
    | S_8ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg                  {
    																			            checkStatArg($1, $2, $4, $6, $8, $10, $12, $14, $16, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							build($8);
																							build(separator(*(int *)($1+2), 4));
																							build($10);
																							build(separator(*(int *)($1+2), 5));
																							build($12);
																							build(separator(*(int *)($1+2), 6));
																							build($14);
																							build(separator(*(int *)($1+2), 7));
																							build($16);
																							build(separator(*(int *)($1+2), 8));
																							$$ = retreiveBuild();
																						  }
    | S_9ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg          {
    																			            checkStatArg($1, $2, $4, $6, $8, $10, $12, $14, $16, $18, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							build($8);
																							build(separator(*(int *)($1+2), 4));
																							build($10);
																							build(separator(*(int *)($1+2), 5));
																							build($12);
																							build(separator(*(int *)($1+2), 6));
																							build($14);
																							build(separator(*(int *)($1+2), 7));
																							build($16);
																							build(separator(*(int *)($1+2), 8));
																							build($18);
																							build(separator(*(int *)($1+2), 9));
																							$$ = retreiveBuild();
																						  }
    | S_10ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg {
    																			            checkStatArg($1, $2, $4, $6, $8, $10, $12, $14, $16, $18, $20);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							build($8);
																							build(separator(*(int *)($1+2), 4));
																							build($10);
																							build(separator(*(int *)($1+2), 5));
																							build($12);
																							build(separator(*(int *)($1+2), 6));
																							build($14);
																							build(separator(*(int *)($1+2), 7));
																							build($16);
																							build(separator(*(int *)($1+2), 8));
																							build($18);
																							build(separator(*(int *)($1+2), 9));
																							build($20);
																							build(separator(*(int *)($1+2), 10));
																							$$ = retreiveBuild();
																						  }
    | S_0PARG arg_list 																	  {
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
                                                                                            build(mkStat(totalArgs));
                                                                                            totalArgs=0;
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							$$ = retreiveBuild();
																						  }
    | S_0PARG          																	  {
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
                                                                                            build(mkStat(0));
																							$$ = retreiveBuild();
																						  }
    | S_1PARG arg      																	  {
    																			            checkStatArg($1, $2, 0, 0, 0, 0, 0, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
                                                                                            build(mkStat(1));
                                                                                            totalArgs=0;
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							$$ = retreiveBuild();
																						  }
	| S_1PARG arg ',' arg_list                                                            {
    																			            checkStatArg($1, $2, 0, 0, 0, 0, 0, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
                                                                                            build(mkStat(totalArgs));
                                                                                            totalArgs=0;
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							$$ = retreiveBuild();
																						  }
    | S_2PARG arg ',' arg                                                                 {
    																			            checkStatArg($1, $2, $4, 0, 0, 0, 0, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
                                                                                            build(mkStat(2));
                                                                                            totalArgs=0;
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							$$ = retreiveBuild();
																						  }
	| S_2PARG arg ',' arg ',' arg_list                                                    {
    																			            checkStatArg($1, $2, $4, 0, 0, 0, 0, 0, 0, 0, 0);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
                                                                                            build(mkStat(totalArgs));
                                                                                            totalArgs=0;
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							$$ = retreiveBuild();
																						  }
    | S_1T4ARG primary_identifier ',' arg                         						  {
    																			            checkStatArg($1, $2, 0, 0, 0, 0, 0, 0, 0, 0, 0);
                                                                                            checkDim($2, totalArgs);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
                                                                                            build(mkStat(2));
																							build($2);
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							$$ = retreiveBuild();
																						  }
    | S_1T4ARG primary_identifier ',' arg ',' arg                 						  {
    																			            checkStatArg($1, $2, 0, 0, 0, 0, 0, 0, 0, 0, 0);
                                                                                            checkDim($2, totalArgs);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
                                                                                            build(mkStat(3));
																							build($2);
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							$$ = retreiveBuild();
																						  }
    | S_1T4ARG primary_identifier ',' arg ',' arg ',' arg         						  {
    																			            checkStatArg($1, $2, 0, 0, 0, 0, 0, 0, 0, 0, 0);
                                                                                            checkDim($2, totalArgs);
																							initbuild();
																							build(mkStat(*(int *)($1+2)));
                                                                                            build(mkStat(4));
																							build($2);
																							build($4);
																							build(separator(*(int *)($1+2), 2));
																							build($6);
																							build(separator(*(int *)($1+2), 3));
																							build($8);
																							build(separator(*(int *)($1+2), 4));
																							$$ = retreiveBuild();
																						  }
    | END                                                                                   { $$ = mkStat(1); }
    | END arg                                                                             {
																							honnor(2000);
																							initbuild();
																							build(mkStat(415));
																							build($2);
																							build(separator(*(int *)($1+2), 1));
																							$$ = retreiveBuild();
																						  }
    | internal_statement_error 															  { $$ = zero(); }
    ;

arg10plist
	: arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg_list { $$ = zero(); }
    ;

internal_statement_error
	: S_0ARG arg 																		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_0ARG arg ',' arg														  		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_0ARG arg ',' arg ',' arg												  		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_0ARG arg ',' arg ',' arg ',' arg 												  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_0ARG arg ',' arg ',' arg ',' arg ',' arg 										  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_0ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg 								  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_0ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 						  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_0ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 				  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_0ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_0ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_0ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
/*    | END arg                                                                             { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) } */
	| END arg ',' arg														  		  	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| END arg ',' arg ',' arg												  		  	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| END arg ',' arg ',' arg ',' arg 												  	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| END arg ',' arg ',' arg ',' arg ',' arg 										  	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| END arg ',' arg ',' arg ',' arg ',' arg ',' arg 								  	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| END arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 						  	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| END arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 				  	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| END arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| END arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | END arg10plist                                                                   	  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_1ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_1ARG arg ',' arg														  		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_1ARG arg ',' arg ',' arg												  		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_1ARG arg ',' arg ',' arg ',' arg 												  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_1ARG arg ',' arg ',' arg ',' arg ',' arg 										  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_1ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg 								  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_1ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 						  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_1ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 				  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_1ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_1ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_1ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_2ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_2ARG arg        														  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_2ARG arg ',' arg ',' arg												  		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_2ARG arg ',' arg ',' arg ',' arg 												  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_2ARG arg ',' arg ',' arg ',' arg ',' arg 										  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_2ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg 								  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_2ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 						  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_2ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 				  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_2ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_2ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_2ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_3ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_3ARG arg        														  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_3ARG arg ',' arg       												  		  	  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_3ARG arg ',' arg ',' arg ',' arg 												  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_3ARG arg ',' arg ',' arg ',' arg ',' arg 										  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_3ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg 								  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_3ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 						  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_3ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 				  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_3ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_3ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_3ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_4ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_4ARG arg        														  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_4ARG arg ',' arg       												  		  	  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_4ARG arg ',' arg ',' arg         												  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_4ARG arg ',' arg ',' arg ',' arg ',' arg 										  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_4ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg 								  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_4ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 						  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_4ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 				  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_4ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_4ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_4ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_5ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_5ARG arg        														  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_5ARG arg ',' arg       												  		  	  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_5ARG arg ',' arg ',' arg         												  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_5ARG arg ',' arg ',' arg ',' arg         										  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_5ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg 								  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_5ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 						  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_5ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 				  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_5ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_5ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_5ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_6ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_6ARG arg        														  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_6ARG arg ',' arg       												  		  	  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_6ARG arg ',' arg ',' arg         												  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_6ARG arg ',' arg ',' arg ',' arg         										  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_6ARG arg ',' arg ',' arg ',' arg ',' arg         								  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_6ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 						  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_6ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 				  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_6ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_6ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_6ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_7ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_7ARG arg        														  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_7ARG arg ',' arg       												  		  	  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_7ARG arg ',' arg ',' arg         												  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_7ARG arg ',' arg ',' arg ',' arg         										  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_7ARG arg ',' arg ',' arg ',' arg ',' arg         								  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_7ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg         						  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_7ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 				  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_7ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_7ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_7ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_8ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_8ARG arg        														  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_8ARG arg ',' arg       												  		  	  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_8ARG arg ',' arg ',' arg         												  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_8ARG arg ',' arg ',' arg ',' arg         										  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_8ARG arg ',' arg ',' arg ',' arg ',' arg         								  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_8ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg         						  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_8ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg         				  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_8ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg 		  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_8ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_8ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_9ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_9ARG arg        														  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_9ARG arg ',' arg       												  		  	  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_9ARG arg ',' arg ',' arg         												  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_9ARG arg ',' arg ',' arg ',' arg         										  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_9ARG arg ',' arg ',' arg ',' arg ',' arg         								  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_9ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg         						  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_9ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg         				  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_9ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg         		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_9ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_9ARG arg10plist                                                                   { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
	| S_10ARG     																		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_10ARG arg        														  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_10ARG arg ',' arg       												  		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_10ARG arg ',' arg ',' arg         												  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_10ARG arg ',' arg ',' arg ',' arg         										  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_10ARG arg ',' arg ',' arg ',' arg ',' arg         								  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_10ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg         						  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_10ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg         				  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_10ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg         		  { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
	| S_10ARG arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg         { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
    | S_10ARG arg10plist                                                                  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_1PARG                                                                             { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
    | S_2PARG                                                                             { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
    | S_2PARG arg                                                                         { $$ = zero(); notEnoughArgsProc(*(int*)($1+2)) }
    | S_1T4ARG primary_identifier                                                         { $$ = zero();
    																						yyerror("wrong type of argument or no enough arguments passed to 'Redim'");
																						  }
    | S_1T4ARG primary_identifier ',' arg ',' arg ',' arg ',' arg                         { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_1T4ARG primary_identifier ',' arg ',' arg ',' arg ',' arg ',' arg                 { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_1T4ARG primary_identifier ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg         { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_1T4ARG primary_identifier ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_1T4ARG primary_identifier ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_1T4ARG primary_identifier ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg ',' arg { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    | S_1T4ARG primary_identifier ',' arg10plist 										  { $$ = zero(); tooManyArgsProc(*(int*)($1+2)) }
    ;

statement
	: internal_statement            													  { $$ = $1; }
    | iteration_control                                                                   { $$ = $1; }
	| any_identifier '=' expr      		{
							            checkStatArg(mkStat(8), $1, $3, 0, 0, 0, 0, 0, 0, 0, 0);
										$$ = concat( mkStat(8), concat( $1, concat($3, separator(8,2)) ) );
										}
    | LET any_identifier '=' expr  		{
							            checkStatArg(mkStat(8), $2, $4, 0, 0, 0, 0, 0, 0, 0, 0);
										$$ = concat( mkStat(8), concat( $2, concat($4, separator(8,2)) ) );
										}
	| user_procedure_call                                                                 { $$ = $1; }
	| conditional_expr                                                                    { $$ = $1; }
	| simple_while                                                                        { $$ = $1; }
    | goto_st TXTIDENTIFIER  			{ strcpy(yytext, $2); $$ = concat(mkStat(7), mkStat(65535));/* forceLabel = 0;*/ } /* mkStat(65535) = registerJump(); */
    | gosub_st TXTIDENTIFIER 			{ strcpy(yytext, $2); $$ = concat(mkStat(41), mkStat(65535));/* forceLabel = 0;*/ }

    | cplx_conditional_expr                         { $$ = $1; }
    | conditional_expr_control                      { $$ = $1; }
    | for_start                                     { $$ = $1; }
    | cplx_while_start                              { $$ = $1; }
    | switch_start
    ;

/* --------------------------------------------------------------------------
 *  USER PROCEDURES
 * --------------------------------------------------------------------------
 */

/* Declaration */

procedure_declaration
	: procedure_declarator  procedure_decl_param_list ')' 				{
																		honnor(1520);
                                                                        registerProc($1, totalArgs, $2, PROC_IDENTIFIER, 0);
																		totalArgs = 0;
																		}
	| procedure_declarator ')' 											{
																		honnor(1520);
                                                                        registerProc($1, totalArgs, zero(), PROC_IDENTIFIER, 0);
																		totalArgs = 0;
																		}
    ;

procedure_declarator
	: DECLARE PROCEDURE declarator_name '(' 				{ $$ = $3; mustBeType=1; }
	| DECLARE PROCEDURE procedure_body_declarator '(' 		{ $$ = $3; mustBeType=1; yyerror("procedure already defined"); }
	| DECLARE PROCEDURE user_procedure_name_err '(' 		{ $$ = $3; mustBeType=1; internalProc($3) }
	| DECLARE PROCEDURE INTFUNC '(' 						{ $$ = $3; mustBeType=1; internalFunc($3) }
    ;

procedure_decl_param_list
	: procedure_decl_param                            		{ totalArgs++; $$ = $1; mustBeType=0; }
    | procedure_decl_param_coma procedure_decl_param        { totalArgs++; $$ = concat($1,$2); mustBeType=0; }
    ;

procedure_decl_param
	: param_decl_type TXTIDENTIFIER 	  					{ $$ = $1; strcpy(yytext, $2); declaration = 0;}
    ;

procedure_decl_param_coma
	: procedure_decl_param_list ',' 						{ mustBeType=1; $$ = $1; }
    ;

param_decl_type
	: TYPE      { $$ = $1; mustBeType = 0; }
    | VAR TYPE  { $$ = concat(mkStat(255), $2); mustBeType = 0; }
    ;

/* Body */

procedure_body
	: procedure_body_begin procedure_param_list ')' 					  {
                                                                          c = mkStat(1);
																		  sendToBuffer(c+2, *(int *)c);
                                                                          checkProc($1, totalArgs, $2, PROC_IDENTIFIER, 0);
                                                                          enterProc($1, PROC_IDENTIFIER);
                                                                          }
	| procedure_body_begin ')' 			  								  {
                                                                          c = mkStat(1);
																		  sendToBuffer(c+2, *(int *)c);
                                                                          checkProc($1, totalArgs, zero(), PROC_IDENTIFIER,0);
                                                                          enterProc($1, PROC_IDENTIFIER);
                                                                          }
    ;

procedure_body_begin
	: PROCEDURE procedure_body_declarator '(' 		{ $$ = $2; mustBeType = 1; identHdr = ++procCount;}
	| PROCEDURE declarator_name '(' 		        { $$ = $2; mustBeType = 1; identHdr = ++procCount; yyerror("undeclared procedure"); }
	| PROCEDURE user_procedure_name_err '(' 		{ $$ = $2; mustBeType=1; internalProc($3) }
	| PROCEDURE INTFUNC '(' 						{ $$ = $2; mustBeType=1; internalFunc($3) }
    ;

procedure_body_declarator
	: USERPROC  { $$ = semText(yytext); }
    | USERFUNC  { sprintf(msg,"'%s' already defined as a function", yytext); yyerror(msg); }
    ;

procedure_param_list
	: procedure_param                       	  	{ totalArgs++; $$ = $1; }
    | procedure_param_list_coma procedure_param   	{ totalArgs++; $$ = concat($1, $2); }
    ;

procedure_param_list_coma
	: procedure_param_list ',' 						{ mustBeType=1; $$ = $1; }
    ;

procedure_param
	: param_type proc_identifier 	   				{
													$$ = $1;
                                                    if (*(int *)($1+2) == 255)
                                                    	registerIdentList(*(int *)($1+4));
                                                    else
														registerIdentList(*(int *)($1+2));
													declaration = 0;
													}
    ;

param_type
	: TYPE      { $$ = $1; mustBeType = 0; }
    | VAR TYPE  { $$ = concat(mkStat(255), $2); mustBeType = 0; }
    ;

proc_identifier
	: TXTIDENTIFIER           	{
    							strcpy(yytext, $1);
								nDim = 0;
								dim1=0;
								dim2=0;
							    dim3=0;
							   	registerIdent(NULL);
							   }
    ;

/* --------------------------------------------------------------------------
 *  USER FUNCTIONS
 * --------------------------------------------------------------------------
 */

/* Declaration */

function_declaration
	: function_declarator_part1 TYPE 						{
                                                            registerProc(fn1, totalArgs, fn2, FUNC_IDENTIFIER,*(int *)($2+2));
															totalArgs = 0;
                                                            mustBeType = 0;
															}
	| function_declarator_part1 { yyerror("function return type not specified"); }
    ;

function_declarator_part1
	: function_declarator function_decl_param_list ')' 	{ mustBeType = 1; fn1 = $1; fn2 = $2; }
    | function_declarator ')'                          	{ mustBeType = 1; fn1 = $1; fn2 = zero(); }
    ;

function_declarator
	: DECLARE FUNCTION declarator_name '(' 				{ $$ = $3; mustBeType=1; }
	| DECLARE FUNCTION function_body_declarator '(' 	{ $$ = $3; mustBeType=1; yyerror("function already defined"); }
	| DECLARE FUNCTION user_procedure_name_err '(' 		{ $$ = $3; mustBeType=1; internalProc($3) }
	| DECLARE FUNCTION INTFUNC '(' 						{ $$ = $3; mustBeType=1; internalFunc($3) }
    ;

function_decl_param_list
	: function_decl_param                           	{ totalArgs++; $$ = $1; }
    | function_decl_param_list_coma function_decl_param { totalArgs++; $$ = concat($1,$2); }
    ;

function_decl_param_list_coma
	: function_decl_param_list ',' 						{ mustBeType = 1; $$ = $1; }
    ;

function_decl_param
	: function_decl_type TXTIDENTIFIER 					{ strcpy(yytext, $2); $$ = $1; declaration = 0; }
    ;

function_decl_type
	: TYPE { mustBeType = 0; $$ = $1; }
    ;

/* Body */

function_body
	: function_body_part1 TYPE  						{
                                                        c = mkStat(1);
														sendToBuffer(c+2, *(int *)c);
                                        				checkProc(fn1, totalArgs, fn2, FUNC_IDENTIFIER, *(int *)($2+2));
                                        				enterProc(fn1, FUNC_IDENTIFIER);
                                                        mustBeType=0;
                                        				}
	| function_body_part1 { yyerror("function return type not specified"); }
    ;

function_body_part1
	: function_body_begin function_param_list ')' 		{ mustBeType = 1; fn1 = $1; fn2 = $2; }
	| function_body_begin  ')'                    		{ mustBeType = 1; fn1 = $1; fn2 = zero(); }
    ;

function_body_begin
	: FUNCTION function_body_declarator '(' 			{ mustBeType = 1; $$ = $2; identHdr = ++procCount;}
	| FUNCTION declarator_name '(' 						{ mustBeType = 1; $$ = $2; identHdr = ++procCount; yyerror("undeclared function"); }
	| FUNCTION user_procedure_name_err '(' 				{ $$ = $2; mustBeType=1; internalProc($3) }
	| FUNCTION INTFUNC '(' 								{ $$ = $2; mustBeType=1; internalFunc($3) }
    ;

function_body_declarator
	: USERFUNC  { $$ = semText(yytext); }
    | USERPROC  { sprintf(msg,"'%s' already defined as a procedure", yytext); yyerror(msg); }
    ;

function_param_list
	: function_param                    	  			{ totalArgs++; $$ = $1; }
    | function_param_list_coma function_param 			{ totalArgs++; $$ = concat($1, $2); }
    ;

function_param_list_coma
	: function_param_list ',' 							{ mustBeType = 1; $$ = $1; }
    ;

function_param
	: func_param_type proc_identifier 					{ $$ = $1; registerIdentList(*(int *)($1+2)); declaration = 0; }
    ;

func_param_type
	: TYPE { mustBeType = 0; $$ = $1; }
    ;

user_procedure_name_err
	: S_0ARG
	| END
	| S_1ARG
	| S_2ARG
	| S_3ARG
	| S_4ARG
	| S_5ARG
	| S_6ARG
	| S_7ARG
	| S_8ARG
	| S_9ARG
	| S_10ARG
    | S_1PARG
    | S_2PARG
    | S_1T4ARG
    ;

/* --------------------------------------------------------------------------
 *  IDENTIFIERS
 * --------------------------------------------------------------------------
 */

identifier_declaration
	: TYPE identifier_list { registerIdentList(*(int *)($1+2)); declaration=0;}
    ;

identifier_list
	: declarator_identifier
    | identifier_list ',' declarator_identifier
    ;

declarator_identifier
	: declarator_name											    {
																	nDim = 0;
																	dim1=0;
																	dim2=0;
																	dim3=0;
                                                                    strcpy(yytext, $1);
																	registerIdent(NULL);
																	}
    | declarator_name '(' declarator_dim ')'                        {
                                                                    nDim = 1;
    																dim1 = *(int *)$3;
                                                                    dim2=0;
                                                                    dim3=0;
                                                                    strcpy(yytext, $1);
                                                                    registerIdent(NULL);
    																}
    | declarator_name '(' declarator_dim ',' declarator_dim ')'     {
                                                                    nDim = 2;
    																dim1 = *(int *)$3;
                                                                    dim2 = *(int *)$5;
                                                                    dim3=0;
                                                                    strcpy(yytext, $1);
                                                                    registerIdent(NULL);
    																}
    | declarator_name '(' declarator_dim ',' declarator_dim ',' declarator_dim ')' {
    																nDim = 3;
    																dim1 = *(int *)$3;
                                                                    dim2 = *(int *)$5;
                                                                    dim3 = *(int *)$7;
                                                                    strcpy(yytext, $1);
                                                                    registerIdent(NULL);
    																}
    | declarator_name '['                         					{ yyerror("string subscript not allowed in declaration"); }
    | INTFUNC { $$ = zero(); internalFunc($1); }
    ;

declarator_name
	: TXTIDENTIFIER 	{ $$ = $1; }
    ;


declarator_dim
	: TXTIDENTIFIER 	{
				  		$$ = semValue($1);
                  		if (errorOccured)
                            break;
				  		invalidVar(yytext);
				 		}
    ;

TXTIDENTIFIER
	: IDENTIFIER 		{ $$ = semText(yytext); }
    ;

simple_identifier
	: primary_identifier 					{ $$ = concat($1, mkStat(0)); }
	| primary_identifier '(' ')'    		{ $$ = concat($1, mkStat(0)); }
    ;

any_identifier
	: var_identifier                        { $$ = $1 }
    | any_identifier '[' expr ']'           {
                                            initbuild();
                                            build($1);
                                            build($3);
                                            strcpy(yytext, "1");
                                            build(lookup(INTCONST));
                                            build(mkStat(0));
                                            build(mkFunc(23));
											$$ = retreiveBuild();
											}
	;

var_identifier
    : simple_identifier 													{ checkDim($1, 0); $$ = $1; }
	| primary_identifier '(' expr ')' 										{
																			checkDim($1, 1);
                                                                            if (errorOccured)
                                                                            	{
                                                                                $$ = zero();
																				break;
                                                                                }
																			initbuild();
                                                                            build($1);
																			build(mkStat(1));
																			build($3);
																			build(mkStat(0));
                                                                            $$ = retreiveBuild();
                                                                            }
	| primary_identifier '(' expr ',' expr ')'								{
    																		checkDim($1, 2);
                                                                            if (errorOccured)
													                        	{
													                            $$ = zero();
													                            break;
													                            }
																			initbuild();
                                                                            build($1);
																			build(mkStat(2));
																			build($3);
                                                                            build(mkStat(0));
																			build($5);
																			build(mkStat(0));
                                                                            $$ = retreiveBuild();
                                                                            }
	| primary_identifier '(' expr ',' expr ',' expr ')' 					{
    																		checkDim($1, 3);
                                                                            if (errorOccured)
													                        	{
													                            $$ = zero();
													                            break;
													                            }
																			initbuild();
                                                                            build($1);
																			build(mkStat(3));
																			build($3);
                                                                            build(mkStat(0));
																			build($5);
                                                                            build(mkStat(0));
																			build($7);
																			build(mkStat(0));
                                                                            $$ = retreiveBuild();
                                                                            }
    ;

primary_identifier
	: TXTIDENTIFIER 	{
    					strcpy(yytext, $1);
                        if (predefValue[0] == 0)
							checkIdentifier();
                        if (errorOccured)
                        	{
                            $$ = zero();
                            break;
                            }
						$$ = toVar($1);
						}
    ;

/* --------------------------------------------------------------------------
 *  IF
 * --------------------------------------------------------------------------
 */

if_body
	: IF '(' expr ')' 			{ if3 = $3; lexn = 0; }
    ;

elseif_body_part1
    : else_if '(' expr ')'     { if3 = $3; lexn = 0; }
    ;

elseif_body
    : elseif_body_part1
    | elseif_body_part1 then_st
    ;

cplx_conditional_expr
	: cplx_conditional_expr_begin            	{ $$ = $1; }
    | cplx_conditional_expr_begin statement  	{ $$ = concat($1, $2); }
    ;

conditional_expr_else
	: conditional_expr_else_begin            	{ $$ = $1; }
    | conditional_expr_else_begin statement  	{ $$ = concat($1, $2); }
    ;

else_word
	: ELSE { lexn = 0; linePart++; }
    ;

cplx_conditional_expr_begin
	: if_body then_st              		{
    									initbuild();
                                        build(mkStat(0xB));
                                        build(if3);
                                        build(separator(0xB, 1));
                                        strcpy(msg, yytext);
                                        strcpy(yytext, newTempLabel());
                                        build(mkStat(65535));
                                        pushLabelStack(yytext);
                                        strcpy(yytext, msg);
                                        openLoop(LOOP_IF);
                                        $$ = retreiveBuild();
                                        lexn=0;
                                        linePart++;
										}

    | elseif_body   					{
                                        initbuild();
                                        checkLoop("ElseIf", LOOP_IF);
                                        if (errorOccured)
				                        	{
				                            $$ = zero();
                				            break;
				                            }
                                        endifLoop(); // set current loop to LOOP_ENDIF+n
                                        build(mkStat(7));
                                        strcpy(msg, yytext);
                                        strcpy(yytext, newTempLabel());
                                        build(mkStat(65535));
                                        pushLabelStack(yytext);
                                        switchLastLabels();
                                        strcpy(yytext, popLabelStack());
                                        build(mkStat(65534));
                                        build(mkStat(0xB));
                                        build(if3);
                                        build(separator(0xB, 1));
                                        strcpy(yytext, newTempLabel());
                                        pushLabelStack(yytext);
//                                        strcpy(yytext, labelStack[labelStackPos-1]);
                                        build(mkStat(65535));
                                        strcpy(yytext,msg);
                                        $$ = retreiveBuild();
                                        linePart++;
										}
    ;

conditional_expr
	: if_body statement 				{
										initbuild();
			                            build(mkStat(11));
            			                build(if3);
                        			    build(separator(11, 1));
                                        strcpy(msg, yytext);
			                            strcpy(yytext, newTempLabel());
            			                build(mkStat(65535));
			                            fakeNextLabel(yytext);
                                        strcpy(yytext, msg);
										build($2);
                                        $$ = retreiveBuild();
                                        }
    ;

else_if
	: ELSEIF
    | else_word IF
    ;

conditional_expr_else_begin
	: else_word                         {
    									initbuild();
                                        checkLoop("Else", LOOP_IF);
                                        if (errorOccured)
				                        	{
				                            $$ = zero();
				                            break;
				                            }
                                        build(mkStat(7));
                                        strcpy(msg, yytext);
                                        strcpy(yytext, newTempLabel());
                                        build(mkStat(65535));
                                        pushLabelStack(yytext);
                                        switchLastLabels();
                                        strcpy(yytext, popLabelStack());
                                        build(mkStat(65534));
                                        strcpy(yytext,msg);
                                        $$ = retreiveBuild();
                                        linePart++;
										}
    ;

conditional_expr_control
	: conditional_expr_else             { $$ = $1; }
    | endif_expr
                                        {
    									initbuild();
										if (loop[loopPos-1] >= LOOP_ELSEIF && loopPos>0)
                                        	{
                                            aa = loop[loopPos-1]-3;
                                        	closeLoop("EndIf", LOOP_ELSEIF);
	                                        if (errorOccured)
					                        	{
					                            $$ = zero();
					                            break;
					                            }
                                            for (b=0;b<aa;b++)
                                            	{
		                                        strcpy(msg, yytext);
					                            strcpy(yytext, popLabelStack());
    		                                    build(mkStat(65534));
		                                        strcpy(yytext,msg);
                                            	}
                                        	}
                                        else
	    									{
											closeLoop("EndIf", LOOP_IF);
	                                        if (errorOccured)
					                        	{
					                            $$ = zero();
					                            break;
					                            }
	                                        strcpy(msg, yytext);
				                            strcpy(yytext, popLabelStack());
    	                                    build(mkStat(65534));
	                                        strcpy(yytext, msg);
                                            }
                                        $$ = retreiveBuild();
                                        }
    ;

endif_expr
	: ENDIF
    | END IF
    ;

/* --------------------------------------------------------------------------
 *  FOR
 * --------------------------------------------------------------------------
 */

for_start
	: FOR any_identifier '=' expr TO expr  		{
    											initbuild();
                                                build(mkStat(8));
                                                build($2);
                                                build(separator(8,1));
                                                build($4);
                                                build(separator(8,2));
                                                build(mkStat(7));
		                                        strcpy(msg, yytext);
                                                strcpy(yytext, newTempLabel());
                                                build(mkStat(65535));
                                                pushLabelStack(yytext);
                                                strcpy(yytext, newTempLabel());
                                                build(mkStat(65534));
                                                pushLabelStack(yytext);
                                                switchLastLabels();
                                                build(mkStat(8));
                                                build($2);
                                                build(separator(8,1));
                                                build($2);
                                                strcpy(yytext, "1");
                                                build(lookup(INTCONST));
                                                build(mkStat(0));
                                                build(mkFunc(8));
                                                build(separator(8,2));
                                                strcpy(yytext, popLabelStack());
                                                build(mkStat(65534));
                                                build(mkStat(0xB));
                                                build($2);
                                                build($6);
                                                build(mkFunc(13)); /* <= */
                                                build(separator(0xB,1));
                                                strcpy(yytext, newTempLabel());
                                                build(mkStat(65535));
                                                pushLabelStack(yytext);
                                                switchLastLabels();
		                                        strcpy(yytext, msg);
    											openLoop(LOOP_FOR);
                                                $$ = retreiveBuild();
    											}
    | FOR any_identifier '=' expr TO expr STEP expr {
    											initbuild();
                                                build(mkStat(8));
                                                build($2);
                                                build(separator(8,1));
                                                build($4);
                                                build(separator(8,2));
                                                build(mkStat(7));
		                                        strcpy(msg, yytext);
                                                strcpy(yytext, newTempLabel());
                                                build(mkStat(65535));
                                                pushLabelStack(yytext);
                                                strcpy(yytext, newTempLabel());
                                                build(mkStat(65534));
                                                pushLabelStack(yytext);
                                                switchLastLabels();
                                                build(mkStat(8));
                                                build($2);
                                                build(separator(8,1));
                                                build($2);
                                                build($8);
                                                build(mkFunc(8));
                                                build(separator(8,2));
                                                strcpy(yytext, popLabelStack());
                                                build(mkStat(65534));
                                                build(mkStat(0xB));
                                                build($8);
                                                strcpy(yytext, "0");
                                                build(lookup(INTCONST));
                                                build(mkStat(0));
                                                build(mkFunc(12));
                                                build($2);
                                                build($6);
                                                build(mkFunc(15));
                                                build(mkFunc(17));
												build($8);
                                                strcpy(yytext, "0");
                                                build(lookup(INTCONST));
                                                build(mkStat(0));
                                                build(mkFunc(15));
                                                build($2);
                                                build($6);
                                                build(mkFunc(13));
                                                build(mkFunc(17));
                                                build(mkFunc(18));
                                                build(separator(0xB,1));
                                                strcpy(yytext, newTempLabel());
                                                build(mkStat(65535));
                                                pushLabelStack(yytext);
                                                switchLastLabels();
		                                        strcpy(yytext, msg);
    											openLoop(LOOP_FOR);
                                                $$ = retreiveBuild();
    											}
    ;

for_end
	: next_stmt                                 {
    											closeLoop("Next", LOOP_FOR);
                                                if (errorOccured)
						                        	{
						                            $$ = zero();
                        						    break;
						                            }
    											initbuild();
                                                build(mkStat(7));
		                                        strcpy(msg, yytext);
                                                strcpy(yytext, popLabelStack());
                                                build(mkStat(65535));
                                                strcpy(yytext, popLabelStack());
                                                build(mkStat(65534));
		                                        strcpy(yytext, msg);
                                                $$ = retreiveBuild();
    											}
    ;

next_stmt
	: nxt
	| nxt any_identifier               			{ yywarning("old basic syntax, identifier ignored"); }
    ;

nxt
	: NEXT
    | END FOR
    ;

/* --------------------------------------------------------------------------
 *  WHILE
 * --------------------------------------------------------------------------
 */

while_body
	: WHILE '(' expr ')' 				{ wh3 = $3; lexn=0; }
	;

cplx_while_start_begin
	: while_body then_st       			{
    									initbuild();
                                        strcpy(msg, yytext);
                                        strcpy(yytext, newTempLabel());
                                        pushLabelStack(yytext);
                                        build(mkStat(65534));
                                        build(mkStat(0xB));
                                        build(wh3);
                                        build(separator(0xB, 1));
                                        strcpy(yytext, newTempLabel());
                                        build(mkStat(65535));
                                        pushLabelStack(yytext);
                                        switchLastLabels();
                                        strcpy(yytext, msg);
                                        openLoop(LOOP_WHILE);
                                        $$ = retreiveBuild();
                                        lexn = 0;
                                        linePart++;
    							   		}

	;

cplx_while_start
	: cplx_while_start_begin           { $$ = $1; }
	| cplx_while_start_begin statement { $$ = concat($1, $2); }
    ;

while_end
	: ENDWHILE
    | END WHILE
    ;

endwhile
	: while_end 									{
    												closeLoop("EndWhile", LOOP_WHILE);
                                                    if (errorOccured)
							                        	{
							                            $$ = zero();
							                            break;
							                            }
    												initbuild();
                                                    build(mkStat(7));
			                                        strcpy(msg, yytext);
			                                        strcpy(yytext, popLabelStack());
                                                    build(mkStat(65535));
			                                        strcpy(yytext, popLabelStack());
                                                    build(mkStat(65534));
			                                        strcpy(yytext, msg);
                                                    $$ = retreiveBuild();
                                                    }
    ;

simple_while
	: while_body statement      		{
    									initbuild();
                                        strcpy(msg, yytext);
                                        strcpy(yytext, newTempLabel());
                                        pushLabelStack(yytext);
                                        build(mkStat(65534));
                                        build(mkStat(0xB));
                                        build(wh3);
                                        build(separator(0xB, 1));
                                        strcpy(yytext, newTempLabel());
                                        build(mkStat(65535));
                                        pushLabelStack(yytext);
                                        switchLastLabels();
										build($2);
                                        build(mkStat(7));
			                            strcpy(yytext, popLabelStack());
                                        build(mkStat(65535));
			                            strcpy(yytext, popLabelStack());
                                        build(mkStat(65534));
                                        strcpy(yytext, msg);
                                        $$ = retreiveBuild();
    									}
	;

/* --------------------------------------------------------------------------
 *  SELECT CASE
 * --------------------------------------------------------------------------
 */

switch_start
	: SELECT CASE expr     			 {
    								 nCase=0;
                                     pushSelect($3);
                                     openLoop(LOOP_CASE);
                                     strcpy(msg, yytext);
                                     strcpy(yytext, newTempLabel());
                                     pushLabelStack(yytext);
                                     strcpy(yytext, newTempLabel());
                                     pushLabelStack(yytext);
                                     switchLastLabels();
                                     strcpy(yytext, msg);
                                     $$ = zero();
    								 }
    ;

switch_case
	: CASE case_expr_list           {
    								initbuild();
                                    strcpy(msg, yytext);
                                    checkLoop("Case", LOOP_CASE);
                                    if (errorOccured)
			                          	{
              				            $$ = zero();
                            			break;
			                            }
    								nCase++;
                                    if (nCase > 1)
                                    	{
                                        switchLastLabels();
                                        build(mkStat(7));
                                        strcpy(yytext, popLabelStack());
                                        build(mkStat(65535)); /* Goto */
	                                    pushLabelStack(yytext);
                                        switchLastLabels();
                                        }
                                    strcpy(yytext, popLabelStack());
                                    build(mkStat(65534)); /* Label */
                                    build(mkStat(0xB));
                                    build($2);
                                    build(separator(0xB, 1));
                                    strcpy(yytext, newTempLabel());
                                    build(mkStat(65535)); /* Goto */
                                    pushLabelStack(yytext);
                                    strcpy(yytext, msg);
                                    $$ = retreiveBuild();
    								}
    | case_default
    								{
                                    initbuild();
                                    strcpy(msg, yytext);
                                    checkLoop("Default", LOOP_CASE);
                                    if (errorOccured)
				                       	{
                			            $$ = zero();
            	                		break;
			                            }
    								nCase++;
                                    if (nCase > 1)
                                    	{
                                        switchLastLabels();
                                        build(mkStat(7));
                                        strcpy(yytext, popLabelStack());
                                        build(mkStat(65535)); /* Goto */
	                                    pushLabelStack(yytext);
                                        switchLastLabels();
                                        }
                                    strcpy(yytext, popLabelStack());
                                    build(mkStat(65534)); /* Label */
                                    strcpy(yytext, newTempLabel());
                                    pushLabelStack(yytext);
                                    strcpy(yytext, msg);
                                    $$ = retreiveBuild();
                                    }
    | switch_end                    {
    								initbuild();
                                    strcpy(msg, yytext);
                                    closeLoop("EndSelect", LOOP_CASE);
                                    if (errorOccured)
			                        	{
			                            $$ = zero();
            			                break;
                        			    }
                                    strcpy(yytext, popLabelStack());
                                    build(mkStat(65534)); /* Label */
                                    strcpy(yytext, popLabelStack());
                                    build(mkStat(65534)); /* Label */
                                    popSelect();
                                    strcpy(yytext, msg);
                                    $$ = retreiveBuild();
    								}
    ;

case_default
	: CASE else_word
    | DEFAULT
    ;

case_expr_list
	: case_expr                    { $$ = $1; }
    | case_expr_list ',' case_expr { $$ = concat($1, concat($3, mkFunc(18))); }
    ;

case_expr
	: expr                          {
    								initbuild();
                                    c = popSelect();
                                    if (errorOccured)
			                        	{
            			                $$ = zero();
                        			    break;
			                            }
                                    pushSelect(c);
                                    build(c);
                                    build($1);
                                    build(mkFunc(10));
                                    $$ = retreiveBuild();
    								}
	| expr SUBRANGE expr            {
    								initbuild();
                                    c = popSelect();
                                    if (errorOccured)
			                        	{
            			                $$ = zero();
                        			    break;
			                            }
                                    pushSelect(c);
                                    build(c);
                                    build($1);
                                    build(mkFunc(15));
                                    build(c);
                                    build($3);
                                    build(mkFunc(13));
                                    build(mkFunc(17));
                                    $$ = retreiveBuild();
    								}
    ;

switch_end
	: END SELECT
    | ENDSELECT
    ;

/* --------------------------------------------------------------------------
 *  STRUCTURE CONTROL
 * --------------------------------------------------------------------------
 */

iteration_control
	: BREAK                         {
    								if (loop[loopPos-1] == LOOP_IF || loop[loopPos-1] == LOOP_CASE || loop[loopPos-1] >= LOOP_ELSEIF)
                                    	{
										aa = loopPos-1;
                                        b = labelStackPos;
                                        for (aa=aa;aa>=0;aa--)
                                        	{
                                            switch(loop[aa])
                                            	{
                                                case LOOP_IF:
                                                	b--;
                                                    break;
                                                case LOOP_CASE:
                                                	b-=2;
                                                    break;
                                                default:
                                                	if (loop[aa] < LOOP_ELSEIF)
	                                                	goto found;
                                                }
                                            if (loop[aa] >= LOOP_ELSEIF)
                                            	b -= loop[aa]-3;
                                            }
                                        yyerror("'break' invalid in this context");
                                        break;
                                        }
                                    else
                                    	{
                                    	aa = loop[loopPos-1];
                                        b = labelStackPos;
                                        }
                                    found:

                                   	initbuild();
                                    strcpy(msg, yytext);
                                    build(mkStat(7));
                                    strcpy(yytext, labelStack[b-2]);
                                    build(mkStat(65535)); /* Goto */
                                    strcpy(yytext, msg);
                                    $$ = retreiveBuild();
    								}
    | CONTINUE                      {
    								if (loop[loopPos-1] == LOOP_IF || loop[loopPos-1] == LOOP_CASE || loop[loopPos-1] >= LOOP_ELSEIF)
                                    	{
										aa = loopPos-1;
                                        b = labelStackPos;
                                        for (aa=aa;aa>=0;aa--)
                                        	{
                                            switch(loop[aa])
                                            	{
                                                case LOOP_IF:
                                                	b--;
                                                    break;
                                                case LOOP_CASE:
                                                	b-=2;
                                                    break;
                                                default:
                                                	if (loop[aa] < LOOP_ELSEIF)
	                                                	goto found2;
                                                }
                                            if (loop[aa] >= LOOP_ELSEIF)
                                            	b -= loop[aa]-3;
                                            }
                                        yyerror("'continue' invalid in this context");
                                        break;
                                        }
                                    else
                                    	{
                                    	aa = loop[loopPos-1];
                                        b = labelStackPos;
                                        }
                                    found2:

                                   	initbuild();
                                    strcpy(msg, yytext);
                                    build(mkStat(7));
                                    strcpy(yytext, labelStack[b-1]);
                                    build(mkStat(65535)); /* Goto */
                                    strcpy(yytext, msg);
                                    $$ = retreiveBuild();
    								}
    ;

/* --------------------------------------------------------------------------
 *  LABELS
 * --------------------------------------------------------------------------
 */

label_marker_part1
	: LABELMARKER { forceLabel = 1; }
    ;

label_marker
	: label_marker_part1 TXTIDENTIFIER { strcpy(yytext, $2); $$ = mkStat(65534); forceLabel = 0; } /* mkStat(65534) = insert a label */
/*	| LABELMARKER INTFUNC       { $$ = zero(); internalFunc($2); }
	| LABELMARKER S_0ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_1ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_2ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_3ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_4ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_5ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_6ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_7ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_8ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_9ARG        { $$ = zero(); internalProc($2); }
	| LABELMARKER S_10ARG       { $$ = zero(); internalProc($2); }
	| LABELMARKER S_0PARG       { $$ = zero(); internalProc($2); }
	| LABELMARKER S_1PARG       { $$ = zero(); internalProc($2); }
	| LABELMARKER S_2PARG       { $$ = zero(); internalProc($2); }
	| LABELMARKER S_1T4ARG      { $$ = zero(); internalProc($2); }
	| LABELMARKER LET           { $$ = zero(); internalProc($2); }
    ;*/

/* --------------------------------------------------------------------------
 *  MISC
 * --------------------------------------------------------------------------
 */

begin
	: BEGIN			    {
						strcpy(yytext, "~BEGIN");
                        beginUsed=1;
                        $$ = mkStat(65534); /* label */
                        }
    ;

endfuncproc
	: END FUNC          { honnor(1520); leaveProc(PROC_IDENTIFIER); identHdr=0; $$ = mkStat(171); }
    | END PROC          { honnor(1520); leaveProc(PROC_IDENTIFIER); identHdr=0; $$ = mkStat(169); }
    ;

goto_st
	: GOTO  { forceLabel = 1; }
    | GO TO { forceLabel = 1; }
    ;

gosub_st
	: GOSUB  { forceLabel = 1; }
    | GO SUB { forceLabel = 1; }
    ;

then_st
	: THEN { lexn = 0; }
    | DO   { lexn = 0; }
    ;

%%

#pragma warn .ias
