%token	NAME INTEGER FLOAT ACCIDENTAL SYMBOL STRING ASCII PRIMITIVENAME CLASSNAME CURRYARG
%token  VAR ARG CLASSVAR CONST 
%token	NILOBJ TRUEOBJ FALSEOBJ
%token	PSEUDOVAR
%token  ELLIPSIS DOTDOT PIE BEGINCLOSEDFUNC
%token  BADTOKEN INTERPRET
%token  BEGINGENERATOR LEFTARROW WHILE
%left	':'
%right  '='
%left	BINOP KEYBINOP '-' '<' '>' '*' '+' '|' READWRITEVAR
%left	'.'
%right  '`'
%right  UMINUS
%start  root

%{

#include <stdlib.h>
#include <string.h>
#include "PyrLexer.h"
#include "PyrParseNode.h"
#include "SC_Constants.h"
#include "SC_InlineUnaryOp.h"
#include "SC_InlineBinaryOp.h"
#include "InitAlloc.h"
#include "PredefinedSymbols.h"
#include "SimpleStack.h"

void *alloca(unsigned long size); 
void bcopy(void *src, void *dst, size_t size) ;
int yyparse();
extern bool compilingCmdLine;
extern LongStack generatorStack;


%}

%%

root	: classes 
			{ gRootParseNode = (PyrParseNode*)$1; gParserResult = 1; }
		| classextensions 
			{ gRootParseNode = (PyrParseNode*)$1; gParserResult = 1; }
		| INTERPRET cmdlinecode
			{ gRootParseNode = (PyrParseNode*)$2; gParserResult = 2; }
		;
		
classes : { $$ = 0; }
		|	classes classdef 
			{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); }
		;

classextensions : classextension
				| classextensions classextension 
				{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); }
				;

classdef	: classname superclass '{' classvardecls methods '}'
				{ $$ = (long)newPyrClassNode((PyrSlotNode*)$1, (PyrSlotNode*)$2, 
					(PyrVarListNode*)$4, (PyrMethodNode*)$5, 0); 
				}
			| classname '[' optname ']' superclass '{' classvardecls methods '}'
				{ $$ = (long)newPyrClassNode((PyrSlotNode*)$1, (PyrSlotNode*)$5, 
					(PyrVarListNode*)$7, (PyrMethodNode*)$8, 
					(PyrSlotNode*)$3); 
				}
			;
			
classextension : '+' classname '{' methods '}'
				{ 
					$$ = (long)newPyrClassExtNode((PyrSlotNode*)$2, (PyrMethodNode*)$4); 
				}
			;
			
optname		: { $$ = 0; }
			| name
			;
			
superclass	: { $$ = 0; }
			| ':' classname
				{ $$ = $2; }
			;

classvardecls	: { $$ = 0; }
				| classvardecls classvardecl 
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); }
				;
				
classvardecl	: CLASSVAR rwslotdeflist ';'
					{ $$ = (long)newPyrVarListNode((PyrVarDefNode*)$2, varClass); }
				| VAR rwslotdeflist ';'
					{ $$ = (long)newPyrVarListNode((PyrVarDefNode*)$2, varInst); }
				| CONST constdeflist ';'
					{ $$ = (long)newPyrVarListNode((PyrVarDefNode*)$2, varConst); }
				;
															
methods		: { $$ = 0; }
			| methods methoddef
				{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); }
			;

methoddef	: name '{' argdecls funcvardecls primitive methbody '}'
				{ $$ = (long)newPyrMethodNode((PyrSlotNode*)$1, (PyrSlotNode*)$5, 
					(PyrArgListNode*)$3, (PyrVarListNode*)$4, (PyrParseNode*)$6, 0); }
			| '*' name '{' argdecls funcvardecls primitive methbody '}'
				{ $$ = (long)newPyrMethodNode((PyrSlotNode*)$2, (PyrSlotNode*)$6, 
					(PyrArgListNode*)$4, (PyrVarListNode*)$5, (PyrParseNode*)$7, 1); }					
			| binop '{' argdecls funcvardecls primitive methbody '}'
				{ $$ = (long)newPyrMethodNode((PyrSlotNode*)$1, (PyrSlotNode*)$5, 
					(PyrArgListNode*)$3, (PyrVarListNode*)$4, (PyrParseNode*)$6, 0); }
			| '*' binop '{' argdecls funcvardecls primitive methbody '}'
				{ $$ = (long)newPyrMethodNode((PyrSlotNode*)$2, (PyrSlotNode*)$6, 
					(PyrArgListNode*)$4, (PyrVarListNode*)$5, (PyrParseNode*)$7, 1); }
			;

optsemi		:
			| ';'
			;
			
optcomma	:
			| ','
			;
			
optequal	:
			| '='
			;
			
funcbody	: funretval
			| exprseq funretval
				{ $$ = (long)newPyrDropNode((PyrParseNode*)$1, (PyrParseNode*)$2); }
			;

cmdlinecode	: '(' funcvardecls1 funcbody ')'
				{ $$ = (long)newPyrBlockNode(NULL, (PyrVarListNode*)$2, (PyrParseNode*)$3, false); }
			| funcvardecls1 funcbody
				{ $$ = (long)newPyrBlockNode(NULL, (PyrVarListNode*)$1, (PyrParseNode*)$2, false); }
			| funcbody
				{ $$ = (long)newPyrBlockNode(NULL, NULL, (PyrParseNode*)$1, false); }
			;

methbody	: retval
			| exprseq retval
				{ $$ = (long)newPyrDropNode((PyrParseNode*)$1, (PyrParseNode*)$2); }
			;

primitive	: { $$ = 0; }
			| primname optsemi
				{ $$ = $1; }
			;
		
retval	:
			{ $$ = (long)newPyrReturnNode(NULL); }
		| '^' expr optsemi
			{ $$ = (long)newPyrReturnNode((PyrParseNode*)$2); }
		;			

funretval	:
			{ $$ = (long)newPyrBlockReturnNode(); }
		| '^' expr optsemi
			{ $$ = (long)newPyrReturnNode((PyrParseNode*)$2); }
		;			

blocklist1	: blocklistitem
		| blocklist1 blocklistitem
				{ 
					$$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); 
				}
			;

blocklistitem : blockliteral
				| generator
				;

blocklist	:	{ $$ = 0; }
			| blocklist1
			;

msgsend : name blocklist1
			{ 
				$$ = (long)newPyrCallNode((PyrSlotNode*)$1, (PyrParseNode*)$2, 0, 0); 
			}
		| '(' binop2 ')' blocklist1
			{ 
				$$ = (long)newPyrCallNode((PyrSlotNode*)$2, (PyrParseNode*)$4, 0, 0); 
			}
		| name '(' arglist1 optkeyarglist ')' blocklist
			{ 
				$$ = (long)newPyrCallNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 
						(PyrParseNode*)$4, (PyrParseNode*)$6); 
			}
		| '(' binop2 ')' '(' arglist1 optkeyarglist ')' blocklist
			{
				$$ = (long)newPyrCallNode((PyrSlotNode*)$2, (PyrParseNode*)$5, 
						(PyrParseNode*)$6, (PyrParseNode*)$8); 
			}
		| name '(' arglistv1 optkeyarglist ')'
			{
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				if (isSuperObjNode((PyrParseNode*)$3)) {
					((PyrPushNameNode*)$3)->mSlot.us = s_this;
					SetSymbol(&slot, s_superPerformList);
				} else {
					SetSymbol(&slot, s_performList);
				}
				selectornode = newPyrSlotNode(&slot);
				args = linkAfterHead(
					(PyrParseNode*)$3,
					newPyrPushLitNode((PyrSlotNode*)$1, NULL));
				$$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$4, 0); 
			}
		| '(' binop2 ')' '(' arglistv1 optkeyarglist ')'
			{
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				SetSymbol(&slot, s_performList);
				selectornode = newPyrSlotNode(&slot);
				args = linkAfterHead(
					(PyrParseNode*)$5,
					newPyrPushLitNode((PyrSlotNode*)$2, NULL));
				$$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$6, 0); 
			}
		| classname '[' arrayelems ']'
			{ $$ = (long)newPyrDynListNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
		| classname blocklist1
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				SetSymbol(&slot, s_new);
				selectornode = newPyrSlotNode(&slot);
				args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1);
				$$ = (long)newPyrCallNode(selectornode, args, 0, (PyrParseNode*)$2); 
			}
		| classname '(' keyarglist1 ')' blocklist
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				SetSymbol(&slot, s_new);
				selectornode = newPyrSlotNode(&slot);
				args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1);
				$$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$3, (PyrParseNode*)$5); 
			}
		| classname '(' arglist1 optkeyarglist ')' blocklist
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				SetSymbol(&slot, s_new);
				selectornode = newPyrSlotNode(&slot);
				args = linkNextNode(
					(PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1), 
					(PyrParseNode*)$3);
				$$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$4, (PyrParseNode*)$6); 
			}
		| classname '(' arglistv1 optkeyarglist ')'
			{
				PyrSlotNode *selectornode, *selectornode2;
				PyrSlot slot, slot2;
				PyrParseNode* args;
				
				if (isSuperObjNode((PyrParseNode*)$1)) {
					((PyrPushNameNode*)$1)->mSlot.us = s_this;
					SetSymbol(&slot, s_superPerformList);
				} else {
					SetSymbol(&slot, s_performList);
				}
				SetSymbol(&slot2, s_new);
				selectornode = newPyrSlotNode(&slot);
				selectornode2 = newPyrSlotNode(&slot2);
				args = linkNextNode(
					(PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1),
					newPyrPushLitNode(selectornode2, NULL));
				args = linkNextNode(args, (PyrParseNode*)$3);
				$$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$5, 0); 
			}
		| expr '.' '(' keyarglist1 ')' blocklist
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				
				SetSymbol(&slot, s_value);
				selectornode = newPyrSlotNode(&slot);
				$$ = (long)newPyrCallNode(selectornode, (PyrParseNode*)$1, (PyrParseNode*)$4, (PyrParseNode*)$6); 
			}
		| expr '.' name '(' keyarglist1 ')' blocklist
			{ 
				$$ = (long)newPyrCallNode((PyrSlotNode*)$3, (PyrParseNode*)$1, 
					(PyrParseNode*)$5, (PyrParseNode*)$7); 
			}
		| expr '.' '(' arglist1 optkeyarglist ')' blocklist
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				SetSymbol(&slot, s_value);
				selectornode = newPyrSlotNode(&slot);
				args = linkNextNode(
					(PyrParseNode*)$1, 
					(PyrParseNode*)$4);
				$$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$5, (PyrParseNode*)$7); 
			}
		| expr '.' '(' arglistv1 optkeyarglist ')'
			{
				PyrSlotNode *selectornode;
				PyrSlot slot, slot2;
				PyrParseNode* args;
				
				if (isSuperObjNode((PyrParseNode*)$1)) {
					((PyrPushNameNode*)$1)->mSlot.us = s_this;
					SetSymbol(&slot, s_superPerformList);
				} else {
					SetSymbol(&slot, s_performList);
				}
				SetSymbol(&slot2, s_value);
				selectornode = newPyrSlotNode(&slot);
				args = linkNextNode(
					(PyrParseNode*)$1,
					newPyrPushLitNode(newPyrSlotNode(&slot2), NULL));
				args = linkNextNode(args, (PyrParseNode*)$4);
				$$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$5, 0); 
			}
		| expr '.' name '(' arglist1 optkeyarglist ')' blocklist
			{ 
				PyrParseNode* args;
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$5);
				$$ = (long)newPyrCallNode((PyrSlotNode*)$3, args, (PyrParseNode*)$6, (PyrParseNode*)$8); 
			}
		| expr '.' classname '(' arglist1 optkeyarglist ')' blocklist
			{ 
				PyrParseNode* args;
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$5);
				$$ = (long)newPyrCallNode((PyrSlotNode*)$3, args, (PyrParseNode*)$6, (PyrParseNode*)$8); 
			}		
		| expr '.' name '(' arglistv1 optkeyarglist ')'
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				if (isSuperObjNode((PyrParseNode*)$1)) {
					((PyrPushNameNode*)$1)->mSlot.us = s_this;
					SetSymbol(&slot, s_superPerformList);
				} else {
					SetSymbol(&slot, s_performList);
				}
				selectornode = newPyrSlotNode(&slot);

				args = linkNextNode((PyrParseNode*)$1, newPyrPushLitNode((PyrSlotNode*)$3, NULL));
				args = linkNextNode(args, (PyrParseNode*)$5);
				$$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$6, 0); 
			}
		| expr '.' classname '(' arglistv1 optkeyarglist ')'
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				if (isSuperObjNode((PyrParseNode*)$1)) {
					((PyrPushNameNode*)$1)->mSlot.us = s_this;
					SetSymbol(&slot, s_superPerformList);
				} else {
					SetSymbol(&slot, s_performList);
				}
				selectornode = newPyrSlotNode(&slot);

				args = linkNextNode((PyrParseNode*)$1, newPyrPushLitNode((PyrSlotNode*)$3, NULL));
				args = linkNextNode(args, (PyrParseNode*)$5);
				$$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$6, 0); 
			}
		| expr '.' name blocklist
			{ 
				$$ = (long)newPyrCallNode((PyrSlotNode*)$3, (PyrParseNode*)$1, 0, (PyrParseNode*)$4); 
			}
		;

generator : '{' ':' exprseq { pushls(&generatorStack, $3); pushls(&generatorStack, 1); } ',' qual '}'
			{
				PyrSlot slot;
				SetSymbol(&slot, getsym("r"));
				PyrSlotNode* selectornode = newPyrSlotNode(&slot);
				
				PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)$6, false);
				PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block);
				$$ = (long)newPyrCallNode(selectornode, (PyrParseNode*)blocklit, 0, 0); 
			}
		| '{' ';' exprseq { pushls(&generatorStack, $3); pushls(&generatorStack, 2); } ',' qual '}'
			{
				$$ = $6;
			}
		;

nextqual	: 
				{ 
					// innermost part
					int action = popls(&generatorStack); 
					PyrParseNode* expr = (PyrParseNode*)popls(&generatorStack);
					
					switch (action) 
					{
						case 1 :
						{
							PyrSlot slot;
							SetSymbol(&slot, getsym("yield"));
							PyrSlotNode* selectornode = newPyrSlotNode(&slot);
					
							$$ = (long)newPyrCallNode(selectornode, expr, 0, 0);
						} break;
						case 2 :
						{
							$$ = (long)expr;
						} break;
					}
				}
			| ',' qual
				{ $$ = $2; }
			;
		
qual	: name LEFTARROW exprseq nextqual
			{ 
				// later should check if exprseq is a series and optimize it to for loop
				PyrParseNode *exprseq = (PyrParseNode*)$3;
				if (exprseq->mClassno == pn_CallNode) {
					PyrCallNode *callnode = (PyrCallNode*)exprseq;
					if (callnode->mSelector->mSlot.us == s_series)
					{
						SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries"));

						PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0);
						PyrArgListNode* args = newPyrArgListNode(var, NULL);
						PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$4, false);
						PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block);
						
						callnode->mArglist = linkNextNode(callnode->mArglist, blocklit);
						$$ = (long)callnode; 
						
					} else goto notoptimized1;
				} else {
					notoptimized1:
					PyrSlot slot;
					SetSymbol(&slot, getsym("do"));
					PyrSlotNode* selectornode = newPyrSlotNode(&slot);

					PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0);
					PyrArgListNode* args = newPyrArgListNode(var, NULL);
					PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$4, false);
					PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block);
					
					PyrParseNode* args2 = linkNextNode(exprseq, blocklit);
					$$ = (long)newPyrCallNode(selectornode, args2, 0, 0); 
				}
			}
		| name name LEFTARROW exprseq nextqual
			{ 
				// later should check if exprseq is a series and optimize it to for loop
				PyrParseNode *exprseq = (PyrParseNode*)$4;
				if (exprseq->mClassno == pn_CallNode) {
					PyrCallNode *callnode = (PyrCallNode*)exprseq;
					if (callnode->mSelector->mSlot.us == s_series)
					{
						SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries"));

						PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0);
						PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)$2, NULL, 0);
						PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2);
						PyrArgListNode* args = newPyrArgListNode(vars, NULL);
						PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$5, false);
						PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block);
						
						callnode->mArglist = linkNextNode(callnode->mArglist, blocklit);
						$$ = (long)callnode; 
						
					} else goto notoptimized2;
				} else {
					notoptimized2:
					PyrSlot slot;
					SetSymbol(&slot, getsym("do"));
					PyrSlotNode* selectornode = newPyrSlotNode(&slot);

					PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0);
					PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)$2, NULL, 0);
					PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2);
					PyrArgListNode* args = newPyrArgListNode(vars, NULL);
					PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$5, false);
					PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block);
					
					PyrParseNode* args2 = linkNextNode(exprseq, blocklit);
					$$ = (long)newPyrCallNode(selectornode, args2, 0, 0); 
				}
			}
		| VAR name '=' exprseq nextqual
			{ 
				PyrSlot slot;
				SetSymbol(&slot, s_value);
				PyrSlotNode* selectornode = newPyrSlotNode(&slot);

				PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)$2, NULL, 0);
				PyrArgListNode* args = newPyrArgListNode(var, NULL);
				PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$5, false);
				PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block);
				PyrParseNode* args2 = (PyrParseNode*)linkNextNode(blocklit, (PyrParseNode*)$4);
				
				$$ = (long)newPyrCallNode(selectornode, args2, 0, 0); 
			}
		| exprseq nextqual
			{
				PyrSlot slot;
				SetSymbol(&slot, getsym("if"));
				PyrSlotNode* selectornode = newPyrSlotNode(&slot);
				PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)$2, false);
				PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block);
				PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)$1, blocklit);

				$$ = (long)newPyrCallNode(selectornode, args2, 0, 0); 
			}
		| ':' ':' exprseq nextqual
			{ 
				$$ = (long)newPyrDropNode((PyrParseNode*)$3, (PyrParseNode*)$4); 
			}
		| ':' WHILE exprseq nextqual
			{
				PyrSlot slot;
				SetSymbol(&slot, getsym("alwaysYield"));
				PyrSlotNode* selectornode1 = newPyrSlotNode(&slot);
				
				SetSymbol(&slot, getsym("if"));
				PyrSlotNode* selectornode2 = newPyrSlotNode(&slot);
				
				SetNil(&slot);
				PyrParseNode *pushnil = (PyrParseNode*)newPyrPushLitNode(newPyrSlotNode(&slot), NULL);
				
				PyrParseNode *yieldNil = (PyrParseNode*)newPyrCallNode(selectornode1, pushnil, 0, 0); 
				
				PyrParseNode *block1 = (PyrParseNode*)newPyrBlockNode(0, 0, yieldNil, false);
				PyrParseNode *blocklit1 = (PyrParseNode*)newPyrPushLitNode(NULL, block1);
				PyrParseNode *block2 = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)$4, false);
				PyrParseNode *blocklit2 = (PyrParseNode*)newPyrPushLitNode(NULL, block2);
				PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)$3, blocklit2);
				PyrParseNode* args3 = (PyrParseNode*)linkNextNode(args2, blocklit1);

				$$ = (long)newPyrCallNode(selectornode2, args3, 0, 0); 
			}
		;

expr1	: pushliteral
		| blockliteral
		| generator
		| pushname
		| curryarg
		| msgsend
		| '(' exprseq ')'
			{ 
				PyrParseNode* node = (PyrParseNode*)$2; 
				node->mParens = 1;
				$$ = $2; 
			}
		| '~' name
			{ 
				PyrParseNode* argnode;
				PyrSlotNode* selectornode;
				PyrSlot slot;
				argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)$2, NULL);
				SetSymbol(&slot, s_envirGet);
				selectornode = newPyrSlotNode(&slot);
				$$ = (long)newPyrCallNode(selectornode, argnode, 0, 0); 
			}
		|  '[' arrayelems ']'
			{ $$ = (long)newPyrDynListNode(0, (PyrParseNode*)$2); }
		|	'(' valrange2 ')'
			{ $$ = $2; }
		|	'(' ':' valrange3 ')'
			{ $$ = $3; }
		|	'(' dictslotlist ')'
			{ $$ = (long)newPyrDynDictNode((PyrParseNode*)$2); }
		| pseudovar
			{ $$ = (long)newPyrPushNameNode((PyrSlotNode*)$1); }
		| expr1 '[' arglist1 ']'
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				SetSymbol(&slot, s_at);
				selectornode = newPyrSlotNode(&slot);
				args = linkNextNode(
					(PyrParseNode*)$1, 
					(PyrParseNode*)$3);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| valrangex1
		;

valrangex1	: expr1 '[' arglist1 DOTDOT ']'
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				int arglen = nodeListLength((PyrParseNode*)$3);
				if (arglen > 2) {
					error("ArrayedCollection subrange has too many arguments.\n");
					nodePostErrorLine((PyrParseNode*)$3);
					compileErrors++;
				}

				SetNil(&nilSlot);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_copyseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3);
				if (arglen < 2) {
					nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
					args = linkNextNode(args, nilnode1);
				}
				args = linkNextNode(args, nilnode2);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr1 '[' DOTDOT exprseq ']'
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				SetNil(&nilSlot);
				nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_copyseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, nilnode1);
				args = linkNextNode(args, nilnode2);
				args = linkNextNode(args, (PyrParseNode*)$4);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr1 '[' arglist1 DOTDOT exprseq ']'
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				int arglen = nodeListLength((PyrParseNode*)$3);
				if (arglen > 2) {
					error("ArrayedCollection subrange has too many arguments.\n");
					nodePostErrorLine((PyrParseNode*)$3);
					compileErrors++;
				}
				
				SetSymbol(&selectorSlot, s_copyseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3);
				if (arglen < 2) {
					SetNil(&nilSlot);
					nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
					args = linkNextNode(args, nilnode1);
				}
				args = linkNextNode(args, (PyrParseNode*)$5);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		;
		
valrangeassign : expr1 '[' arglist1 DOTDOT ']' '=' expr
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				int arglen = nodeListLength((PyrParseNode*)$3);
				if (arglen > 2) {
					error("ArrayedCollection subrange has too many arguments.\n");
					nodePostErrorLine((PyrParseNode*)$3);
					compileErrors++;
				}

				SetNil(&nilSlot);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_putseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3);
				if (arglen < 2) {
					nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
					args = linkNextNode(args, nilnode1);
				}
				args = linkNextNode(args, nilnode2);
				args = linkNextNode(args, (PyrParseNode*)$7);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr1 '[' DOTDOT exprseq ']' '=' expr
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				SetNil(&nilSlot);
				nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_putseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, nilnode1);
				args = linkNextNode(args, nilnode2);
				args = linkNextNode(args, (PyrParseNode*)$4);
				args = linkNextNode(args, (PyrParseNode*)$7);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr1 '[' arglist1 DOTDOT exprseq ']' '=' expr
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				int arglen = nodeListLength((PyrParseNode*)$3);
				if (arglen > 2) {
					error("ArrayedCollection subrange has too many arguments.\n");
					nodePostErrorLine((PyrParseNode*)$3);
					compileErrors++;
				}
				
				SetSymbol(&selectorSlot, s_putseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3);
				if (arglen < 2) {
					SetNil(&nilSlot);
					nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
					args = linkNextNode(args, nilnode1);
				}
				args = linkNextNode(args, (PyrParseNode*)$5);
				args = linkNextNode(args, (PyrParseNode*)$8);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	;

valrangexd	: expr '.' '[' arglist1 DOTDOT ']'
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;
				
				int arglen = nodeListLength((PyrParseNode*)$4);
				if (arglen > 2) {
					error("ArrayedCollection subrange has too many arguments.\n");
					nodePostErrorLine((PyrParseNode*)$3);
					compileErrors++;
				}
				
				SetNil(&nilSlot);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_copyseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4);
				if (arglen < 2) {
					nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
					args = linkNextNode(args, nilnode1);
				}
				args = linkNextNode(args, nilnode2);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr '.' '[' DOTDOT exprseq ']'
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				SetNil(&nilSlot);
				nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_copyseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, nilnode1);
				args = linkNextNode(args, nilnode2);
				args = linkNextNode(args, (PyrParseNode*)$5);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr '.' '[' arglist1 DOTDOT exprseq ']'
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;
				
				int arglen = nodeListLength((PyrParseNode*)$4);
				if (arglen > 2) {
					error("ArrayedCollection subrange has too many arguments.\n");
					nodePostErrorLine((PyrParseNode*)$3);
					compileErrors++;
				}
				
				SetSymbol(&selectorSlot, s_copyseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4);
				if (arglen < 2) {
					SetNil(&nilSlot);
					nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
					args = linkNextNode(args, nilnode1);
				}
				args = linkNextNode(args, (PyrParseNode*)$6);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr '.' '[' arglist1 DOTDOT ']' '=' expr
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;
				
				int arglen = nodeListLength((PyrParseNode*)$4);
				if (arglen > 2) {
					error("ArrayedCollection subrange has too many arguments.\n");
					nodePostErrorLine((PyrParseNode*)$3);
					compileErrors++;
				}
				
				SetNil(&nilSlot);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_putseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4);
				if (arglen < 2) {
					nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
					args = linkNextNode(args, nilnode1);
				}
				args = linkNextNode(args, nilnode2);
				args = linkNextNode(args, (PyrParseNode*)$8);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr '.' '[' DOTDOT exprseq ']' '=' expr
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				SetNil(&nilSlot);
				nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_putseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, nilnode1);
				args = linkNextNode(args, nilnode2);
				args = linkNextNode(args, (PyrParseNode*)$5);
				args = linkNextNode(args, (PyrParseNode*)$8);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr '.' '[' arglist1 DOTDOT exprseq ']' '=' expr
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode1;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;
				
				int arglen = nodeListLength((PyrParseNode*)$4);
				if (arglen > 2) {
					error("ArrayedCollection subrange has too many arguments.\n");
					nodePostErrorLine((PyrParseNode*)$3);
					compileErrors++;
				}
				
				SetSymbol(&selectorSlot, s_putseries);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4);
				if (arglen < 2) {
					SetNil(&nilSlot);
					nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
					args = linkNextNode(args, nilnode1);
				}
				args = linkNextNode(args, (PyrParseNode*)$6);
				args = linkNextNode(args, (PyrParseNode*)$9);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	;
		
valrange2	: exprseq DOTDOT 
			{
				// if this is not used in a 'do' or list comprehension, then should return an error.
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				SetNil(&nilSlot);
				nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_series);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, nilnode);
				args = linkNextNode(args, nilnode2);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	
		| DOTDOT exprseq
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode, *zeronode;
				PyrSlot selectorSlot, nilSlot, zeroSlot;
				PyrParseNode* args;

				SetInt(&zeroSlot, 0);
				SetNil(&nilSlot);
				nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL);
				
				SetSymbol(&selectorSlot, s_series);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode(zeronode, nilnode);
				args = linkNextNode(args, (PyrParseNode*)$2);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	
		| exprseq DOTDOT exprseq
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				SetNil(&nilSlot);
				nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_series);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, nilnode);
				args = linkNextNode(args, (PyrParseNode*)$3);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	
		| exprseq ',' exprseq DOTDOT exprseq
			{ 
				PyrSlotNode *selectornode;
				PyrSlot selectorSlot;
				PyrParseNode* args;
				
				SetSymbol(&selectorSlot, s_series);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode(
					(PyrParseNode*)$1, 
					(PyrParseNode*)$3);
				args = linkNextNode(args, (PyrParseNode*)$5);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| exprseq ',' exprseq DOTDOT
			{ 
				// if this is not used in a 'do' or list comprehension, then should return an error.
				PyrSlotNode *selectornode;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;
				PyrPushLitNode *nilnode;

				SetNil(&nilSlot);
				nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, s_series);
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode(
					(PyrParseNode*)$1, 
					(PyrParseNode*)$3);
				args = linkNextNode(args, nilnode);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	;
	
valrange3	: DOTDOT exprseq
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode, *zeronode;
				PyrSlot selectorSlot, nilSlot, zeroSlot;
				PyrParseNode* args;

				SetInt(&zeroSlot, 0);
				SetNil(&nilSlot);
				nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL);
				
				SetSymbol(&selectorSlot, getsym("seriesIter"));
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode(zeronode, nilnode);
				args = linkNextNode(args, (PyrParseNode*)$2);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	
		| exprseq DOTDOT
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode, *nilnode2;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				SetNil(&nilSlot);
				nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, getsym("seriesIter"));
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, nilnode);
				args = linkNextNode(args, nilnode2);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	
		| exprseq DOTDOT exprseq
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				SetNil(&nilSlot);
				nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, getsym("seriesIter"));
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, nilnode);
				args = linkNextNode(args, (PyrParseNode*)$3);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	
		| exprseq ',' exprseq DOTDOT
			{ 
				PyrSlotNode *selectornode;
				PyrPushLitNode *nilnode;
				PyrSlot selectorSlot, nilSlot;
				PyrParseNode* args;

				SetNil(&nilSlot);
				nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL);
				
				SetSymbol(&selectorSlot, getsym("seriesIter"));
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3);
				args = linkNextNode(args, nilnode);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| exprseq ',' exprseq DOTDOT exprseq
			{ 
				PyrSlotNode *selectornode;
				PyrSlot selectorSlot;
				PyrParseNode* args;
				
				SetSymbol(&selectorSlot, getsym("seriesIter"));
				selectornode = newPyrSlotNode(&selectorSlot);
				args = linkNextNode(
					(PyrParseNode*)$1, 
					(PyrParseNode*)$3);
				args = linkNextNode(args, (PyrParseNode*)$5);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
	;
	
expr	: expr1
		| valrangexd
		| valrangeassign
		| classname { $$ = (long)newPyrPushNameNode((PyrSlotNode*)$1); }
		| expr '.' '[' arglist1 ']'
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				SetSymbol(&slot, s_at);
				selectornode = newPyrSlotNode(&slot);
				args = linkNextNode(
					(PyrParseNode*)$1, 
					(PyrParseNode*)$4);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| '`' expr 
			{
				PyrParseNode *node, *args;
				PyrSlotNode *slotnode;
				PyrSlot slot;
				
				SetSymbol(&slot, s_ref);
				slotnode = newPyrSlotNode(&slot);
				node = (PyrParseNode*)newPyrPushNameNode(slotnode);
				args = linkNextNode(node, (PyrParseNode*)$2);
				SetSymbol(&slot, s_new);
				slotnode = newPyrSlotNode(&slot);
				$$ = (long)newPyrCallNode(slotnode, args, 0, 0); 
			}
		| expr binop2 adverb expr %prec BINOP
			{ 
				$$ = (long)newPyrBinopCallNode((PyrSlotNode*)$2, 
						(PyrParseNode*)$1, (PyrParseNode*)$4, (PyrParseNode*)$3); 
			}
		| name '=' expr
			{ 
				$$ = (long)newPyrAssignNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 0); 
			}
		| '~' name '=' expr
			{ 
				PyrParseNode *argnode, *args;
				PyrSlotNode* selectornode;
				PyrSlot slot;
				argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)$2, NULL);
				args = linkNextNode(argnode, (PyrParseNode*)$4);
				SetSymbol(&slot, s_envirPut);
				selectornode = newPyrSlotNode(&slot);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr '.' name '=' expr
			{ 
				$$ = (long)newPyrSetterNode((PyrSlotNode*)$3, 
						(PyrParseNode*)$1, (PyrParseNode*)$5); 
			}
		| name '(' arglist1 optkeyarglist ')' '=' expr
			{ 
				if ($4 != 0) {
					error("Setter method called with keyword arguments.\n");
					nodePostErrorLine((PyrParseNode*)$4);
					compileErrors++;
				}
				$$ = (long)newPyrSetterNode((PyrSlotNode*)$1, 
						(PyrParseNode*)$3, (PyrParseNode*)$7); 
			}
		| '#' mavars '=' expr
			{ 
				$$ = (long)newPyrMultiAssignNode((PyrMultiAssignVarListNode*)$2, 
					(PyrParseNode*)$4, 0); 
			}
		| expr1 '[' arglist1 ']' '=' expr
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				SetSymbol(&slot, s_put);
				selectornode = newPyrSlotNode(&slot);
				args = linkNextNode(
					(PyrParseNode*)$1, 
					(PyrParseNode*)$3);
				args = linkNextNode( args, (PyrParseNode*)$6);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		| expr '.' '[' arglist1 ']' '=' expr
			{ 
				PyrSlotNode *selectornode;
				PyrSlot slot;
				PyrParseNode* args;
				
				SetSymbol(&slot, s_put);
				selectornode = newPyrSlotNode(&slot);
				args = linkNextNode(
					(PyrParseNode*)$1, 
					(PyrParseNode*)$4);
				args = linkNextNode( args, (PyrParseNode*)$7);
				$$ = (long)newPyrCallNode(selectornode, args, 0, 0); 
			}
		;

adverb  : { $$ = 0; }
		| '.' name { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$2, NULL); }
		| '.' integer { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$2, NULL); }
		| '.' '(' exprseq ')' { $$ = $3; }
		;
		
exprn	: expr
		| exprn ';' expr
			{ 
				$$ = (long)newPyrDropNode((PyrParseNode*)$1, (PyrParseNode*)$3); 
			}
		;
		
exprseq : exprn optsemi
		;
				
arrayelems	: { $$ = 0; }
			| arrayelems1 optcomma
			  { $$ = $1; }
			;

arrayelems1	: exprseq
			| exprseq ':' exprseq
				{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
			| keybinop exprseq
				{
					PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$1, NULL);
					$$ = (long)linkNextNode(key, (PyrParseNode*)$2); 
				}
			| arrayelems1 ',' exprseq
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
			| arrayelems1 ',' keybinop exprseq
				{
					PyrParseNode* elems;
					PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$3, NULL);
					elems = (PyrParseNode*)linkNextNode(key, (PyrParseNode*)$4); 
					$$ = (long)linkNextNode((PyrParseNode*)$1, elems); 
				}
			| arrayelems1 ',' exprseq ':' exprseq
				{
					PyrParseNode* elems;
					elems = (PyrParseNode*)linkNextNode((PyrParseNode*)$3, (PyrParseNode*)$5); 
					$$ = (long)linkNextNode((PyrParseNode*)$1, elems); 
				}
			;
								
arglist1	: exprseq
			| arglist1 ',' exprseq
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
			;

arglistv1	: '*' exprseq
				{ $$ = $2; }
			| arglist1 ',' '*' exprseq
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); }
			;

keyarglist1	: keyarg
			| keyarglist1 ',' keyarg
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
			;

keyarg	: keybinop exprseq
				{ $$ = (long)newPyrPushKeyArgNode((PyrSlotNode*)$1, (PyrParseNode*)$2); }
		;

optkeyarglist	: { $$ = 0; }
				| ',' keyarglist1 { $$ = $2; }
				;
			
mavars	: mavarlist
			{ $$ = (long)newPyrMultiAssignVarListNode((PyrSlotNode*)$1, NULL); }
		| mavarlist ELLIPSIS name
			{ $$ = (long)newPyrMultiAssignVarListNode((PyrSlotNode*)$1, (PyrSlotNode*)$3); }
		;

mavarlist	: name
			| mavarlist ',' name 
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
			;
		
slotliteral	
		: integer	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
		| floatp	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
		| ascii		{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
		| string	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
		| symbol	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
		| trueobj	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
		| falseobj	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
		| nilobj	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
		| listlit	{ $$ = (long)newPyrLiteralNode(NULL, (PyrParseNode*)$1); }
		| dictlit   { $$ = (long)newPyrLiteralNode(NULL, (PyrParseNode*)$1); }
		;

blockliteral : block	{ $$ = (long)newPyrPushLitNode(NULL, (PyrParseNode*)$1); }
			;
			
pushname	: name		{ $$ = (long)newPyrPushNameNode((PyrSlotNode*)$1); }
			;
			
pushliteral	: integer	{ $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); }
			| floatp	{ $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); }
			| ascii		{ $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); }
			| string	{ $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); }
			| symbol	{ $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); }
			| trueobj	{ $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); }
			| falseobj	{ $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); }
			| nilobj	{ $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); }
			| listlit	{ $$ = (long)newPyrPushLitNode(NULL, (PyrParseNode*)$1); }
			| dictlit	{ $$ = (long)newPyrPushLitNode(NULL, (PyrParseNode*)$1); }
			;

listliteral	: integer	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
			| floatp	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
			| ascii		{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
			| string	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
			| symbol	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
			| name		{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
			| trueobj	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
			| falseobj	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
			| nilobj	{ $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); }
			| listlit2	{ $$ = (long)newPyrLiteralNode(NULL, (PyrParseNode*)$1); }
			| dictlit2  { $$ = (long)newPyrLiteralNode(NULL, (PyrParseNode*)$1); }
			;
			
block	: '{' argdecls funcvardecls funcbody '}'
				{ $$ = (long)newPyrBlockNode((PyrArgListNode*)$2, (PyrVarListNode*)$3, 
					(PyrParseNode*)$4, false); }
		| BEGINCLOSEDFUNC argdecls funcvardecls funcbody '}'
				{ $$ = (long)newPyrBlockNode((PyrArgListNode*)$2, (PyrVarListNode*)$3, 
					(PyrParseNode*)$4, true); }
		;

funcvardecls	: { $$ = 0; }
				| funcvardecls funcvardecl
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); }
				;

funcvardecls1	: funcvardecl
				| funcvardecls1 funcvardecl
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); }
				;

funcvardecl	: VAR vardeflist ';'
				{ $$ = (long)newPyrVarListNode((PyrVarDefNode*)$2, varLocal); }
			;

argdecls	: { $$ = 0; }
			| ARG vardeflist ';'
				{
					$$ = (long)newPyrArgListNode((PyrVarDefNode*)$2, NULL); 
				}
			| ARG vardeflist0 ELLIPSIS name ';'
				{ 
					$$ = (long)newPyrArgListNode((PyrVarDefNode*)$2, (PyrSlotNode*)$4); 
				}
			| '|' slotdeflist '|'
				{
					$$ = (long)newPyrArgListNode((PyrVarDefNode*)$2, NULL); 
				}
			| '|' slotdeflist0 ELLIPSIS name '|'
				{ 
					$$ = (long)newPyrArgListNode((PyrVarDefNode*)$2, (PyrSlotNode*)$4); 
				}
			;
				
constdeflist	: constdef
				| constdeflist optcomma constdef
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
				;

constdef	: rspec name '=' slotliteral
				{ $$ = (long)newPyrVarDefNode((PyrSlotNode*)$2, (PyrParseNode*)$4, $1); }
			;
											
slotdeflist0 	: { $$ = 0; }
				| slotdeflist
				;
				
slotdeflist	: slotdef
			| slotdeflist optcomma slotdef
				{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
			;

slotdef		: name
				{ $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); }
			| name optequal slotliteral
				{ $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 0); }
			| name optequal '(' exprseq ')'
				{
					PyrParseNode* node = (PyrParseNode*)$4; 
					node->mParens = 1;
					$$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, node, 0);
				}
			;
			
vardeflist0 	: { $$ = 0; }
				| vardeflist
				;
				
vardeflist      : vardef
                        | vardeflist ',' vardef
                                { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
                        ;

vardef          : name
                                { $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); }
                        | name '=' expr
                                { $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 0); }
                        | name '(' exprseq ')'
                                { 
									PyrParseNode* node = (PyrParseNode*)$3; 
									node->mParens = 1;
									$$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, node, 0); 
								}
                        ;                              
				
dictslotdef	: exprseq ':' exprseq
				{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
			| keybinop exprseq
				{
					PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$1, NULL);
					$$ = (long)linkNextNode(key, (PyrParseNode*)$2); 
				}
			;
				
dictslotlist1	: dictslotdef
				| dictslotlist1 ',' dictslotdef
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
				;
				
dictslotlist	: { $$ = 0; }
				| dictslotlist1
				;
				
rwslotdeflist	: rwslotdef
				| rwslotdeflist ',' rwslotdef
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
				;

rwslotdef		: rwspec name
					{ $$ = (long)newPyrVarDefNode((PyrSlotNode*)$2, NULL, $1); }
				| rwspec name '=' slotliteral
					{ $$ = (long)newPyrVarDefNode((PyrSlotNode*)$2, (PyrParseNode*)$4, $1); }
				;			
								
dictlit		:	'#' '(' litdictslotlist ')'
				{ $$ = (long)newPyrLitDictNode((PyrParseNode*)$3); }
			;
			
dictlit2	: '(' litdictslotlist ')'
				{ $$ = (long)newPyrLitDictNode((PyrParseNode*)$2); }
			;
			
litdictslotdef	: listliteral ':' listliteral
				{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
			| keybinop listliteral
				{
					PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$1, NULL);
					$$ = (long)linkNextNode(key, (PyrParseNode*)$2); 
				}
			;
				
litdictslotlist1	: litdictslotdef
				| litdictslotlist1 ',' litdictslotdef
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
				;
				
litdictslotlist	: { $$ = 0; }
				| litdictslotlist1
				;
				

				
listlit	: '#' '[' literallistc ']'
				{ $$ = (long)newPyrLitListNode(0, (PyrParseNode*)$3); }
		| '#' classname  '[' literallistc ']'
				{ $$ = (long)newPyrLitListNode((PyrParseNode*)$2, (PyrParseNode*)$4); }
		;

listlit2	: '[' literallistc ']'
				{ $$ = (long)newPyrLitListNode(0, (PyrParseNode*)$2); }
			| classname  '[' literallistc ']'
				{ $$ = (long)newPyrLitListNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
			;

literallistc	: { $$ = 0; }
				| literallist1 optcomma
				;
					
literallist1	: listliteral
				| literallist1 ',' listliteral
					{ $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); }
				;			
					
rwspec	:  { $$ = rwPrivate; }
		| '<'
			{ $$ = rwReadOnly; }
		| READWRITEVAR
			{ $$ = rwReadWrite; }
		| '>'
			{ $$ = rwWriteOnly; }
		;

rspec	:  { $$ = rwPrivate; }
		| '<'
			{ $$ = rwReadOnly; }
		;
		
integer	: INTEGER { $$ = zzval; }
		| '-'INTEGER %prec UMINUS 
			{
				PyrSlotNode *node; 
				node = (PyrSlotNode*)zzval; 
				node->mSlot.ui = -node->mSlot.ui;
				$$ = zzval;
			} 
	;
	
floatr	: FLOAT { $$ = zzval; }
		| '-' FLOAT %prec UMINUS 
			{
				PyrSlotNode *node; 
				node = (PyrSlotNode*)zzval; 
				node->mSlot.uf = -node->mSlot.uf;
				$$ = zzval;
			} 
	;

accidental : ACCIDENTAL { $$ = zzval; }
			| '-' ACCIDENTAL %prec UMINUS 
				{
					PyrSlotNode *node; 
					double intval, fracval;
					node = (PyrSlotNode*)zzval;
					intval = floor(node->mSlot.uf + 0.5);
					fracval = node->mSlot.uf - intval;
					node->mSlot.uf = -intval + fracval;
					$$ = zzval;
				} 

pie		: PIE { $$ = zzval; }
	;
	
floatp	: floatr
		| accidental
		| floatr pie
			{
				PyrSlotNode *node; 
				node = (PyrSlotNode*)$1;
				node->mSlot.uf *= pi;
			}
		| integer pie
			{
				PyrSlotNode *node; 
				double ival;
				node = (PyrSlotNode*)$1;
				ival = node->mSlot.ui;
				node->mSlot.uf = ival * pi;
			}
		| pie 
			{
				PyrSlotNode *node; 
				node = (PyrSlotNode*)zzval; 
				node->mSlot.uf = pi;
				$$ = zzval;
			} 
		| '-' pie 
			{
				PyrSlotNode *node; 
				node = (PyrSlotNode*)zzval; 
				node->mSlot.uf = -pi;
				$$ = zzval;
			} 
	;
		
name		: NAME { $$ = zzval; }	
			| WHILE { $$ = zzval; }
		;

classname		: CLASSNAME { $$ = zzval; }	
		;

primname		: PRIMITIVENAME { $$ = zzval; }	
		;

trueobj		: TRUEOBJ { $$ = zzval; }	
		;

falseobj	: FALSEOBJ { $$ = zzval; }	
		;

nilobj		: NILOBJ { $$ = zzval; }	
		;
		
ascii		: ASCII { $$ = zzval; }	
		;

symbol		: SYMBOL { $$ = zzval; }	
		;
			
string		: STRING { $$ = zzval; }	
		;

pseudovar	: PSEUDOVAR { $$ = zzval; }	
		;

binop	: BINOP { $$ = zzval; }	
		| READWRITEVAR { $$ = zzval; }
		| '<'  { $$ = zzval; }	
		| '>'  { $$ = zzval; }	
		| '-'  { $$ = zzval; }	
		| '*'  { $$ = zzval; }	
		| '+'  { $$ = zzval; }	
		| '|'  { $$ = zzval; }	
	;

keybinop : KEYBINOP { $$ = zzval; }	
		;
		
binop2  : binop
		| keybinop
		;
		
curryarg : CURRYARG { $$ = zzval; }

