Index: cpp/frams/vm/framscript.l
===================================================================
--- cpp/frams/vm/framscript.l	(revision 163)
+++ cpp/frams/vm/framscript.l	(revision 163)
@@ -0,0 +1,101 @@
+%{
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include "framscript-defs.h"
+#include "framscript.tab.cpp.h"
+#include <math.h>
+
+#define YY_INPUT(buf,result,maxsize) {result=trctx.in->Vread(buf,1,maxsize);}
+#define YY_NEVER_INTERACTIVE 1
+
+%}
+
+%option noyywrap
+%x asmcode
+%x asmcode2
+%x comment
+
+%%
+
+\$[0-9a-fA-F]+ {int i; sscanf(yytext+1,"%x",&i); framscriptlval.setInt(i); return CONSTANT;}
+0x[0-9a-fA-F]+ {int i; sscanf(yytext+2,"%x",&i); framscriptlval.setInt(i); return CONSTANT;}
+[0-9]+\.[0-9]*    {framscriptlval.setDouble(atof(yytext)); return CONSTANT;}
+[0-9]+            {framscriptlval.setInt(atoi(yytext)); return CONSTANT;}
+[0-9]+\.[0-9]*[eE][+-]?[0-9]+    {framscriptlval.setDouble(atof(yytext)); return CONSTANT;}
+[0-9]+*[eE][+-]?[0-9]+           {framscriptlval.setDouble(atof(yytext)); return CONSTANT;}
+"null"            {framscriptlval.setEmpty(); return CONSTANT;}
+\"([^\\\"]|\\.)*\" {framscriptlval.setString(SString(yytext+1,yyleng-2));return CONSTANT;}
+"@line "[0-9]+\n   {trctx.line=atol(yytext+6);}
+"@file "[^\n\t\r]+\n {trctx.srcname=SString(yytext+6,yyleng-7);}
+
+[a-zA-Z_][a-zA-Z0-9_]* { int t=lookupToken(yytext);
+                         if (t>=0) return t;
+                         else
+                            {
+                            framscriptlval.setString(yytext);
+                            return framscriptIsObjectName(yytext)?OBJNAME:IDENT;
+                            }
+                       }
+"=="               return EQUAL;
+"<>"               return NOT_EQUAL;
+"!="               return NOT_EQUAL;
+">="               return GEQUAL;
+"<="               return LEQUAL;
+
+"+="                return ASSIGN_ADD;
+"-="                return ASSIGN_SUB;
+"*="                return ASSIGN_MUL;
+"/="                return ASSIGN_DIV;
+"%="                return ASSIGN_MOD;
+
+"++"                return PLUSPLUS;
+"--"                return MINUSMINUS;
+
+"&&"                return LOGIC_AND;
+"||"                return LOGIC_OR;
+
+"<<"                return LSHIFT;
+">>"                return RSHIFT;
+
+<INITIAL,asmcode,asmcode2>\/\/.*\n         {trctx.line++;} // komentarz jednoliniowy
+<INITIAL,asmcode,asmcode2>\/\/[^\n]*       ;               // komentarz ale nie ma potem \n
+
+<INITIAL>\/\*       BEGIN comment;
+<comment>\n         {trctx.line++;}
+<comment>\*\/       BEGIN 0;
+<comment>.          ;
+
+[ \t\r\f]           ;
+\n                  {trctx.line++;}
+.                   return yytext[0];
+
+"asm"[ \t\n\r]*"{"  {
+                    BEGIN asmcode;
+                    char *t=yytext;
+                    while(t=strchr(t+1,'\n')) trctx.line++;
+                    return ASM;
+                    }
+<asmcode>.*\n {
+              char *t=yytext;
+              trctx.line++;
+              while ((*t==' ')||(*t=='\t')) t++;
+              if (*t=='}') {yyless((t-yytext)+1); BEGIN 0; return '}';}
+              char *e=yytext+yyleng-1;
+              while (e[-1]=='\r') e--;
+              framscriptlval.setString(SString(t,e-t));
+              return ASMLINE;
+              }
+
+%%
+void framscript_init_lex()
+{
+BEGIN 0;
+yyrestart(0);
+}
+
+void framscript_cleanup_lex()
+{
+yy_delete_buffer(yy_current_buffer);
+}
Index: cpp/frams/vm/framscript.y
===================================================================
--- cpp/frams/vm/framscript.y	(revision 163)
+++ cpp/frams/vm/framscript.y	(revision 163)
@@ -0,0 +1,1359 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+%{
+#include "framscript-defs.h"
+#include "common/framsg.h"
+#include <math.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#define YYERROR_VERBOSE
+#define YYPRINT(file,type,value) yyprint (file,type,value)
+
+static void yyprint (FILE *file,int type,YYSTYPE value);
+void handleTwoArg(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,
+		  int optoken,const char* opname, bool logic, bool negarg2, bool uniq);
+void handleCompare(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,
+		   int optoken,const char* opname);
+bool handleAssignOp(YYSTYPE& result,const YYSTYPE& var,const YYSTYPE& arg,const char* opname);
+bool handleAssignOp2(YYSTYPE& result,const char *var,const YYSTYPE& arg,const char* opname,int stackpos,bool push);
+bool variableOk(TokenValue &tok, const TokenValue& var,int &loc);
+bool globalOk(const TokenValue& var);
+void badVariable(TokenValue &tok, const TokenValue &var);
+bool evalVariable(TokenValue &tok, const TokenValue &var);
+bool doBreak(int level);
+bool doContinue(int level);
+void warnTruthValue(const TokenValue& t);
+void outFunName(const TokenValue& t);
+
+static const char* assign_op_names[]={"add","sub","mul","div","mod"};
+
+%}
+
+%token_table
+
+%token CONSTANT
+
+%nonassoc ASSIGN_ADD ASSIGN_SUB ASSIGN_MUL ASSIGN_DIV ASSIGN_MOD
+%nonassoc PLUSPLUS MINUSMINUS 
+%left LOGIC_AND LOGIC_OR '!'
+%left EQUAL NOT_EQUAL GEQUAL LEQUAL '>' '<'
+%left '|' '&' '^'
+%left '-' '+'
+%left '*' '/' '%'
+%left NEG     /* negation--unary minus */
+%left TYPEOF
+
+%token IDENT
+%token OBJNAME
+
+%token IF      "if"
+%token ELSE    "else"
+%token FOR     "for"
+%token INNN    "in"
+%token WHILE   "while"
+%token DO      "do"
+%token GOTO    "goto"
+%token RETURN  "return"
+%token BREAK    "break"
+%token CONTINUE "continue"
+%token SWITCH   "switch"
+%token CASE     "case"
+%token DEFAULT  "default"
+
+%token TYPEOF    "typeof"
+
+%token ASM     
+%token ASMLINE
+              
+%token VAR      "var"
+%token GLOBAL   "global"
+%token FUNCTION "function"
+
+%token CALL    "call"
+
+%token ASSIGN
+%token ASSIGN_ADD
+%token ASSIGN_SUB
+%token ASSIGN_MUL
+%token ASSIGN_DIV
+
+%token EQUAL
+%token NOT_EQUAL
+%token GEQUAL
+%token LEQUAL
+
+%token LOGIC_AND
+%token LOGIC_OR
+
+%token PLUSPLUS
+%token MINUSMINUS
+
+%token LSHIFT
+%token RSHIFT
+
+%%
+code: {$$.setInt(trstack.currentPos());} recurcode
+{
+int pos=$1.getInt();
+if (pos!=trstack.currentPos()) trctx.out->printf("add %d,m0\n",pos-trstack.currentPos());
+}
+;
+
+recurcode:    /* empty string */
+       | recurcode statement
+;
+     
+statement: ';'
+      | VAR vardeflist ';'
+      | GLOBAL globaldeflist ';'
+      | IDENT ':'     {trctx.out->printf(":%s\n",str($1));}
+      | expr ';'      {if (!$1.constant) { trctx.out->printf("inc m0\n"); trstack.adjust(+1); } }
+      | functiondef
+      | blok
+      | if_statement
+      | goto_statement
+      | return_statement
+      | for_statement
+      | while_statement
+      | dowhile_statement
+      | break_statement
+      | continue_statement
+      | switch_statement
+//      | error ';'
+      | asmblock
+;
+
+asmblock: ASM asmlines '}'
+;
+
+asmlines: /* empty */
+        | ASMLINE            {fputs(str($1),trctx.out);fputc('\n',trctx.out);}
+        | asmlines ASMLINE   {fputs(str($2),trctx.out);fputc('\n',trctx.out);}
+;
+
+goto_statement: GOTO IDENT ';'
+ {
+#ifdef FRAMSCRIPT_GOTO
+trctx.out->printf("jump :%s\n",str($2)); FMprintf("FramScriptCompiler","translate",FMLV_WARN,"goto is not recommended (%s line %d)",(const char*)trctx.srcname,trctx.line);
+#else
+trctx.err->printf("goto is not supported");return 1;
+#endif
+ }
+;
+
+return_statement: RETURN expr ';'
+{
+int offset;
+if (trctx.functionstackpos==999)
+	offset=-trstack.currentPos();
+else
+	offset=trctx.functionstackpos-trstack.currentPos();
+if (!offset)
+	{
+	if ($2.constant)
+		trctx.out->printf("move %s,s0\nreturn\n",litstr($2));
+	else
+		{
+		trctx.out->printf("move m[m0++],s0\nreturn\n");
+		trstack.adjust(+1);
+		}
+	}
+else
+	{
+	if ($2.constant)
+		{
+		trctx.out->printf("add %d,m0\nmove %s,s0\nreturn\n",offset,litstr($2));
+		trstack.adjust(offset);
+		}
+	else
+		{
+		trctx.out->printf("move s0,s%d\nadd %d,m0\nreturn\n",offset,offset);
+		trstack.adjust(offset);
+		}
+	}
+}
+          | RETURN ';'
+{
+int offset;
+if (trctx.functionstackpos==999)
+	offset=-trstack.currentPos();
+else
+	offset=trctx.functionstackpos-trstack.currentPos();
+if (!offset)
+	trctx.out->printf("move invalid,s0\nreturn\n");
+else
+	trctx.out->printf("add %d,m0\nmove invalid,s0\nreturn\n",offset);
+}
+;
+
+vardeflist: vardef
+          | vardeflist ',' vardef
+;
+
+vardef: IDENT               {trstack.addVariable($1.getString()); trctx.out->printf("push invalid\n");}
+      | IDENT '=' stackexpr {trstack.adjust(1); trstack.addVariable($1.getString());}
+;
+
+globaldeflist: globaldef
+          | globaldeflist ',' globaldef
+;
+
+globaldef: IDENT     {trstack.globals.add($1.getString(),0);
+                      trctx.out->printf("global %s\n",str($1));}
+;
+
+funparam: IDENT { trstack.addVariable($1.getString()); };
+
+paramlist: /* empty */             {$$.setInt(0); }
+         | funparam                {$$.setInt(1); }
+         | paramlist ',' funparam  {$$.setInt($1.getInt()+1);}
+;
+
+funnamelist:
+         IDENT {outFunName($1);}
+         | funnamelist ',' IDENT {outFunName($3);}
+;
+
+functiondef:                FUNCTION funnamelist
+{
+int pos=trstack.currentPos();
+$$.setInt(pos);
+if (trctx.functionstackpos!=999)
+	{trctx.err->printf("functions cannot be nested");return 1;}
+}
+                            '(' paramlist ')'
+{
+trctx.functionstackpos=trstack.currentPos();
+}
+                            blok
+{trctx.out->printf("move invalid,s0\nreturn\n");
+int pos=$3.getInt();
+trstack.dropToPos(pos);
+trctx.functionstackpos=999;
+trctx.out->printf(":_skipfun_%d\n",trctx.functiontmplabel);
+trctx.functiontmplabel=-1;
+};
+
+break_statement: BREAK ';'         {if (!doBreak(1)) return 1;}
+               | BREAK expr ';'
+{
+if (!$2.constant)
+	{trctx.err->printf("break level must be a constant expression");return 1;}
+int level=$2.getInt();
+if (level<1)
+	{trctx.err->printf("break level must be a positive integer");return 1;}
+if (!doBreak(level)) return 1;
+};
+
+continue_statement: CONTINUE ';'         {if (!doContinue(1)) return 1;}
+                  | CONTINUE expr ';'
+{
+if (!$2.constant)
+	{trctx.err->printf("continue level must be a constant expression");return 1;}
+int level=$2.getInt();
+if (level<1)
+	{trctx.err->printf("continue level must be a positive integer");return 1;}
+if (!doContinue(level)) return 1;
+};
+
+while_statement: WHILE '('
+{ int c=trctx.labelcounter++; $$.setInt(c);
+$$.stack=trstack.currentPos();
+trstack.loops.addLoop(c,$$.stack);
+trctx.out->printf(":_loop_%d\n",c);}
+                              expr ')'
+{
+int c=$3.getInt();
+warnTruthValue($4);
+if ($4.constant)
+	{if (!$4.getInt()) trctx.out->printf("jump :_loop_end_%d\n",c);}
+else
+	{
+	trctx.out->printf("if m[m0++],==,0,:_loop_end_%d\n",c,c);
+	trstack.adjust(+1);
+	}
+}
+                 pseudoblok_statement
+{trctx.out->printf("jump :_loop_%d\n:_loop_end_%d\n",$3.getInt(),$3.getInt());
+trstack.adjust($3.stack-trstack.currentPos());
+trstack.loops.drop();
+}
+;
+
+dowhile_statement: DO
+{ int c=trctx.labelcounter++; $$.setInt(c);
+$$.stack=trstack.currentPos();
+trstack.loops.addLoop(c,$$.stack);
+trctx.out->printf(":_loop_%d\n",c);} //2
+
+pseudoblok_statement WHILE '(' expr ')'
+
+{//8
+int c=$2.getInt();
+warnTruthValue($6);
+if ($6.constant)
+	{if ($6.getInt()) trctx.out->printf("jump :_loop_%d\n",c);}
+else
+	{
+	trctx.out->printf("if !=,m[m0++],:_loop_%d\n",c);
+	trstack.adjust(+1);
+	}
+trctx.out->printf(":_loop_end_%d\n",c);
+trstack.adjust($2.stack-trstack.currentPos());
+trstack.loops.drop();
+}
+;
+
+switch_statement: SWITCH '('
+{int c=trctx.labelcounter++; $1.setInt(c);
+trstack.loops.addLoop(c,trstack.currentPos());}
+       stackexpr ')'
+{trctx.out->printf("dec m0\n");trstack.adjust(-1);}
+ '{' inside_switch '}'
+{int c=$1.getInt(); trctx.out->printf("add 2,m0\n:_loop_end_%d\n",c); trstack.adjust(+2);
+trstack.loops.drop();}
+;
+
+inside_switch: /* empty */
+       | case_label
+       | inside_switch case_label
+;
+
+case_label: CASE expr ':'
+{if (!$2.constant) {trctx.err->printf("case label must be a constant expression");return 1;}
+int c=trctx.labelcounter++; $1.setInt(c);
+trctx.out->printf("if s1,!=,%s,:_skip_%d\n",litstr($2),c);
+int pos=trstack.currentPos(); $$.setInt(pos);
+}
+ recurcode
+{
+int pos=$4.getInt();
+if (pos!=trstack.currentPos()) trctx.out->printf("add %d,m0\n",pos-trstack.currentPos());
+trstack.dropToPos(pos);
+trctx.out->printf(":_skip_%d\n",$1.getInt());
+}
+      |  DEFAULT ':' recurcode
+;
+
+newvar_or_expr:
+	      VAR IDENT { $$.setInt(trstack.addVariable($2.getString())); trctx.out->printf("push invalid\n"); $$.ident=true; $$.var=true; }
+
+	      |
+	      VAR IDENT '=' stackexpr
+	      {
+	      //trctx.out->printf("# VAR IDENT '=' stackexpr pos=%d\n",trstack.currentPos());
+	      trstack.adjust(+1);
+	      $$.setInt(trstack.addVariable($2.getString()));
+	      $$.ident=true; $$.var=true;
+	      }
+
+	      |
+	      expr_special_ident
+	      {
+	      $$=$1;
+	      }
+
+              | //nic
+	      {
+	      $$.setInt(1); $$.assign=false; $$.ident=false; $$.var=false; $$.constant=true;
+	      }
+;
+
+expr_or_objname:
+              expr { $$=$1; $$.objname=false; }
+              |
+	      OBJNAME { $$.setString($1.getString()); $$.objname=true; }
+;
+
+for_statement_begin: FOR '('
+{
+int c=trctx.labelcounter++; $$.counter=c; $$.stack=trstack.currentPos();
+}
+newvar_or_expr
+{
+$$=$4; $$.counter=$3.counter; $$.stack=$3.stack;
+};
+
+for_statement:
+
+	   ///////////  for(in) ...  ////////////
+           for_statement_begin INNN
+	   {//3
+	   if (!$1.ident)
+		   {
+		   trctx.err->printf("for(... in ...) requires an variable\n");
+		   return 1;
+		   }
+	   int loc;
+	   if ($1.var) // for(var x[=expr] in
+		   $$.setInt($1.getInt());
+	   else
+		   {  // for(x in
+		   if (variableOk($$,$1,loc))
+			   $$.setInt(loc);
+		   else if (globalOk($1))
+			   {
+			   trctx.err->printf("global '%s' can't be iterating variable in for\n",str($1));
+			   return 1;
+			   }
+		   else
+			   {
+			   badVariable($$,$1);
+			   return 1;
+			   }
+		   }
+	   }
+           expr_or_objname ')'
+	   {//6
+	   if ($4.constant) 
+		   {trctx.err->printf("%s can't be iterated\n",str($4)); return 1;}
+	   if ($4.objname) 
+		   trctx.out->printf("move %s.iterator,m[--m0]\n",(const char*)$4.getString());
+	   else
+		   trctx.out->printf("move s%d,m1\nmove [m1].\"iterator\",m[--m0]\n",0);
+	   trstack.adjust(-1);
+	   // s0=iterator s1=obj (=obj.iterator)
+	   trstack.loops.addLoop($1.counter,trstack.currentPos());
+	   trctx.out->printf(":_loop1_%d\n",$1.counter);
+	   trctx.out->printf(":_loop_%d\n",$1.counter);
+	   trctx.out->printf("move s0,m1\nmove [m1].\"next\",m2\n");
+	   trctx.out->printf("if m2,==,0,:_loop_end_%d\n",$1.counter);
+	   trctx.out->printf("move [m1].\"value\",s%d\n",$3.getInt()-trstack.currentPos());
+	   }
+	   pseudoblok_statement
+	   {
+	   trctx.out->printf("jump :_loop1_%d\n",$1.counter);
+	   trctx.out->printf(":_loop_end_%d\n",$1.counter);
+	   trstack.loops.drop();
+	   if ($1.stack != trstack.currentPos())
+		   trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
+	   trstack.adjust($1.stack-trstack.currentPos());
+	   }
+	   
+|
+
+	   ///////////  for(;;) ...  ////////////
+           for_statement_begin ';'
+           { //3
+	   //trctx.out->printf("# for_statement_begin pos=%d ident=%d var=%d\n",trstack.currentPos(),$1.ident,$1.var);
+	   if ((!$1.var) && ($1.ident))
+		   {  // for(x;
+		   int loc;
+		   if ((!variableOk($$,$1,loc)) || (globalOk($1)))
+			   {
+			   badVariable($$,$1);
+			   return 1;
+			   }
+		   }
+	   if (!$1.constant && !$1.ident)
+		   {
+		   trctx.out->printf("inc m0\n");
+		   trstack.adjust(+1);
+		   }
+	   trstack.loops.addLoop($1.counter,trstack.currentPos());
+	   trctx.out->printf(":_loop1_%d\n",$1.counter);
+	   //trctx.out->printf("# expr#2\n");
+           }
+           expr_or_empty ';'
+	   { //6
+	   int c=$1.counter;
+	   warnTruthValue($4);
+	   if ($4.constant)
+		   {if (!$4.getInt()) trctx.out->printf("jump :_loop_end_%d\n",c);}
+	   else
+		   {
+		   trctx.out->printf("if m[m0++],==,0,:_loop_end_%d\n",c,c);
+		   trstack.adjust(+1);
+		   }
+	   trctx.tmp=0;
+	   trctx.divertOut();
+	   //trctx.out->printf("# expr#3\n");
+	   }
+           expr_or_empty ')'
+	   { //9
+	   if (!$7.constant) { trctx.out->printf("inc m0\n"); trstack.adjust(+1); }
+	   trctx.restoreOut();
+	   $$.setString(trctx.tmp);
+	   //trctx.out->printf("# pseudoblok_statement pos=%d\n",trstack.currentPos());
+	   }
+           pseudoblok_statement
+	   {//11
+	   trctx.out->printf(":_loop_%d\n",$1.counter);
+	   LoopInfo* li=trstack.loops.getLoop(0);
+	   if (li->location != trstack.currentPos())
+		   trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
+	   trctx.out->printf(str($9));
+	   if (li->location != trstack.currentPos())
+		   trctx.out->printf("sub %d,m0\n",li->location-trstack.currentPos());
+	   trctx.out->printf("jump :_loop1_%d\n:_loop_end_%d\n",$1.counter,$1.counter);
+	   if ($1.stack != trstack.currentPos())
+		   trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
+	   trstack.adjust($1.stack-trstack.currentPos());
+	   trstack.loops.drop();
+	   }
+;
+
+pseudoblok_statement:
+{int pos=trstack.currentPos(); $$.setInt(pos);
+}
+  statement
+{
+int pos=$1.getInt();
+if (pos!=trstack.currentPos()) trctx.out->printf("add %d,m0\n",pos-trstack.currentPos());
+trstack.dropToPos(pos);
+};
+
+if_statement:
+ if_condition pseudoblok_statement
+                       {
+		       if ($1.stack!=trstack.currentPos())
+			       trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
+		       trstack.adjust(trstack.currentPos()-$1.stack);
+		       trctx.out->printf("jump :_if_end_%d\n:_if_else_%d\n",$1.getInt(),$1.getInt());
+		       }
+         ELSE
+	               {trstack.adjust($1.stack-trstack.currentPos());}
+         pseudoblok_statement
+                       {
+		       if ($1.stack!=trstack.currentPos())
+			       trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
+		       trstack.adjust(trstack.currentPos()-$1.stack);
+		       trctx.out->printf(":_if_end_%d\n",$1.getInt());
+		       }
+| 
+ if_condition pseudoblok_statement
+                       {
+		       if ($1.stack!=trstack.currentPos())
+			       trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
+		       trstack.dropToPos($1.stack);
+		       trctx.out->printf(":_if_else_%d\n",$1.getInt());
+		       }
+;
+
+if_condition: IF
+{$$.stack=trstack.currentPos();}
+
+ '(' expr ')'
+{
+int c=trctx.labelcounter++;
+$$.setInt(c);
+warnTruthValue($4);
+if ($4.constant)
+	{
+	if (!$4.getInt()) trctx.out->printf("jump :_if_else_%d\n",c);
+	}
+else
+	{
+	trctx.out->printf("if m[m0++],==,0,:_if_else_%d\n",c);
+	trstack.adjust(+1);
+	}
+$$.stack=$2.stack;
+};
+
+blok:    '{'
+{ int pos=trstack.currentPos();
+$$.setInt(pos);
+}
+         recurcode '}'
+{
+int pos=$2.getInt();
+if (pos!=trstack.currentPos()) trctx.out->printf("add %d,m0\n",pos-trstack.currentPos());
+trstack.dropToPos(pos);
+}
+
+assign_op: ASSIGN_ADD {$$.setInt(0);}
+         | ASSIGN_SUB {$$.setInt(1);}
+         | ASSIGN_MUL {$$.setInt(2);}
+         | ASSIGN_DIV {$$.setInt(3);}
+         | ASSIGN_MOD {$$.setInt(4);}
+
+plusminus: PLUSPLUS {$$.setInt(1);} | MINUSMINUS {$$.setInt(0);}
+
+expr: expr_special_ident
+  {
+  //trctx.out->printf("# expr: ident=%d str=%s\n",$1.ident,(const char*)$1.getString());
+  if ($1.ident)
+	  {
+	  if (evalVariable($$,$1))
+		  $$.constant=false;
+	  else
+		  return 1;
+	  }
+  else
+	  {$$=$1; $$.ident=false;}
+  }
+;
+
+expr_or_empty:
+         expr {$$=$1;}
+
+         | //nic
+	 { $$.setInt(1); $$.assign=false; $$.constant=true; $$.ident=false; $$.ident=false; }
+;
+
+expr_special_ident:    CONSTANT             { $$=$1; $$.constant=1; $$.ident=0; }
+
+       | IDENT                { $$.ident=true; $$.setString($1.getString()); }
+
+       | OBJNAME ':' IDENT    {$$.constant=0; $$.ident=0;
+                              trctx.out->printf("push %s:%s\n",(const char*)$1.getString(),
+						 (const char*)$3.getString());
+			      trstack.adjust(-1);
+                              }
+       | plusminus IDENT
+{
+$$.ident=0;
+int loc; if (variableOk($$,$2,loc))
+	{ loc-=trstack.currentPos();
+	trctx.out->printf("%s s%d\npush s%d\n",$1.getInt()?"inc":"dec",loc,loc);
+	trstack.adjust(-1);}
+        else if (globalOk($2))
+	{ trctx.out->printf("%s @%s\npush @%s\n",$1.getInt()?"inc":"dec",str($2),str($2));
+	trstack.adjust(-1);}
+	else {badVariable($$,$2); return 1;}
+}
+
+       | IDENT plusminus
+{
+$$.ident=0;
+int loc; if (variableOk($$,$1,loc))
+	{loc-=trstack.currentPos(); trctx.out->printf("push s%d\n%s s%d\n",loc,$2.getInt()?"inc":"dec",loc+1);
+	trstack.adjust(-1);}
+        else if (globalOk($1))
+	{ trctx.out->printf("push @%s\n%s @%s\n",(const char*)$1.getString(),
+			    $2.getInt()?"inc":"dec",(const char*)$1.getString());
+	trstack.adjust(-1);}
+	else {badVariable($$,$1); return 1;}
+}
+
+       | IDENT assign_op expr { $$.ident=0;
+                                if (!handleAssignOp($$,$1,$3,assign_op_names[$2.getInt()]))
+	                        if (globalOk($1)) {SString t="@"; t+=$1.getString();
+                                  handleAssignOp2($$,(const char*)t,$3,assign_op_names[$2.getInt()],0,1);}
+				else { badVariable($$,$1); return 1; }
+                              }
+
+       | TYPEOF expr { $$.ident=0;
+                       if ($2.constant)
+                             {$$.constant=1; $$=$2.getExtType();}
+                       else
+                             {trctx.out->printf("type s0,s0\n");}
+                     }
+
+       | expr '+' expr { handleTwoArg($$,$1,$3,'+',"add",0,0,1); }
+       | expr '-' expr { handleTwoArg($$,$1,$3,'-',"sub",0,0,0); }
+       | expr '*' expr { handleTwoArg($$,$1,$3,'*',"mul",0,0,1); }
+       | expr '/' expr { handleTwoArg($$,$1,$3,'/',"div",0,0,0); }
+       | expr '&' expr { handleTwoArg($$,$1,$3,'&',"and",0,0,0); }
+       | expr '|' expr { handleTwoArg($$,$1,$3,'|',"or",0,0,0); }
+       | expr '%' expr { handleTwoArg($$,$1,$3,'%',"mod",0,0,0); }
+       | expr LOGIC_AND expr { handleTwoArg($$,$1,$3,LOGIC_AND,"and",1,0,0); }
+       | expr LOGIC_OR expr { handleTwoArg($$,$1,$3,LOGIC_OR,"or",1,0,0); }
+       | expr LSHIFT expr { handleTwoArg($$,$1,$3,LSHIFT,"shift",0,0,0); }
+       | expr RSHIFT expr { handleTwoArg($$,$1,$3,RSHIFT,"shift",0,1,0); }
+       | expr EQUAL expr     { handleCompare($$,$1,$3,EQUAL,"=="); }
+       | expr NOT_EQUAL expr { handleCompare($$,$1,$3,NOT_EQUAL,"!="); }
+       | expr GEQUAL expr    { handleCompare($$,$1,$3,GEQUAL,">="); }
+       | expr LEQUAL expr    { handleCompare($$,$1,$3,LEQUAL,"<="); }
+       | expr '>' expr       { handleCompare($$,$1,$3,'>',">"); }
+       | expr '<' expr       { handleCompare($$,$1,$3,'<',"<"); }
+
+       | '!' expr        {
+                         $$.assign=$2.assign; $$.parens=0; $$.ident=0;
+                         if ($2.constant)
+                                {$$.constant=1; $$.setInt(!$2.getInt());}
+                         else
+				{trctx.out->printf("setif ==,s0,s0\n");}
+                         }
+
+     | '-' expr %prec NEG { 
+                          $$.assign=$2.assign; $$.parens=0; $$.ident=0;
+                          if ($2.constant)
+	                          { $$.constant=$2.constant;
+				   if ($2.type==TInt) $$.setInt(-$2.getInt());
+				   else if ($2.type==TDouble) $$.setDouble(-$2.getDouble());
+				   else $$=$2;
+				  }
+			     else 
+				  {
+				  $$.constant=0; SString t="-"; t+=$2.getString(); $$.setString(t);
+				  trctx.out->printf("mul -1,s0\n");
+				  }
+                          }
+
+     | '(' expr ')'    { $$ = $2; $$.assign=$2.assign?(!$2.parens):0; $$.parens=1; $$.ident=0; }
+
+     | OBJNAME '.' member {
+                        $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
+			if ($3.constant)
+				{
+				trctx.out->printf("push %s.%s\n",str($1),str($3)); trstack.adjust(-1);
+				}
+			else
+				{
+				trctx.out->printf("move s0,m1\nmove %s.[m1],s0\n",str($1));
+				}
+                        }
+
+     | OBJNAME '.' member assign_op expr
+                  { $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
+		  if ($3.constant)
+			  {
+			  handleAssignOp2($$,(const char*)t,$5,assign_op_names[$4.getInt()],0,1);
+			  }
+		  else
+			  {
+			  int sp=($5.constant)?0:1;
+			  t=$1.getString();t+=".[m1]";
+			  trctx.out->printf("move s0,m1\n",str($1));
+			  handleAssignOp2($$,(const char*)t,$5,assign_op_names[$4.getInt()],sp,0);
+			  if (sp) {trctx.out->printf("inc m0\n"); trstack.adjust(1);}
+			  }
+                  }
+
+     | plusminus OBJNAME '.' member {
+                        $$.constant=0; $$.ident=0; SString t=$2.getString(); t+="."; t+=$4.getString(); $$.setString(t);
+			if ($4.constant)
+				{
+				trctx.out->printf("%s %s.%s\npush %s.%s\n",$1.getInt()?"inc":"dec",
+						  str($2),str($4),str($2),str($4));
+				trstack.adjust(-1);
+				}
+			else
+				{
+				trctx.out->printf("move s0,m1\n%s %s.[m1]\nmove %s.[m1],s0\n",
+						  $1.getInt()?"inc":"dec",str($2),str($2));
+				}
+                        }
+
+     | OBJNAME '.' member plusminus {
+                        $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
+			if ($3.constant)
+				{
+				trctx.out->printf("push %s.%s\n%s %s.%s\n",
+						  str($1),str($3),$4.getInt()?"inc":"dec",str($1),str($3));
+				trstack.adjust(-1);
+				}
+			else
+				{
+				trctx.out->printf("move s0,m1\nmove %s.[m1],s0\n%s %s.[m1]\n",
+						  str($1),$4.getInt()?"inc":"dec",str($1));
+				}
+                        }
+
+     | OBJNAME '.' '*'    {
+                        $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".*"; $$.setString(t);
+			trctx.out->printf("push %s.*\n",str($1)); trstack.adjust(-1);
+                        }
+
+
+     | OBJNAME '.' member '=' expr {
+			$$=$5; $$.assign=1; $$.parens=0; $$.ident=0;
+			if ($3.constant)
+				{
+				if ($$.constant)
+					trctx.out->printf("move %s,%s.%s\n",litstr($5),str($1),str($3));
+				else
+					trctx.out->printf("move s0,%s.%s\n",str($1),str($3));
+				}
+			else
+				{
+				if ($$.constant)
+					{
+					trctx.out->printf("move m[m0++],m1\nmove %s,%s.[m1]\n",
+							  litstr($5),str($1));
+					trstack.adjust(1);
+					}
+				else
+					{
+					trctx.out->printf("move s1,m1\nmove m[m0++],s0\nmove s0,%s.[m1]\n",
+							  str($1));
+					trstack.adjust(1);
+					}
+				}
+                        }
+
+     | OBJNAME '.' member '(' arguments ')' 
+                        {
+                        $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
+			int adj=0,adj2=0;
+			if ($5.getInt()==0)
+				{trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
+			if ($3.constant)
+				trctx.out->printf("call %s.%s\n",str($1),str($3));
+			else
+				{
+				trctx.out->printf("move s%d,m1\ncall %s.[m1]\n",$5.getInt()+adj,str($1));
+				adj2=1;
+				}
+			adj2+=$5.getInt()-1+adj;
+			if (adj2>0)
+				{
+				trctx.out->printf("add %d,m0\nxmove s%d,s0\n",adj2,-adj2);
+				trstack.adjust(adj2);
+				}
+                        }
+
+     | CALL expr '(' arguments ')'
+             { $$.constant=0; $$.ident=0; $$.setString($2.getString());
+	     short adj=0;
+	     if ($4.getInt()==0)
+		     {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
+	     if ($2.constant)
+		     trctx.out->printf("call %s\n",litstr($2));
+	     else
+		     trctx.out->printf("call s%d\n",$4.getInt()+adj);
+	     if (($4.getInt()+adj) > 0)
+		     {
+		     trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$4.getInt()+adj,-($4.getInt()+adj));
+		     trstack.adjust($4.getInt()+adj);
+		     }
+	     }
+
+     | FUNCTION IDENT
+             { $$.constant=0; $$.ident=0; SString t=":"; t+=$1.getString(); $$.setString(t);
+	     trctx.out->printf("push :%s\n",(const char*)$2.getString());
+	     trstack.adjust(-1);
+	     }
+
+     | expr '.' member
+             { $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
+	     if ($3.constant)
+		     trctx.out->printf("move s0,m1\nmove [m1].%s,s0\n",str($3));
+	     else
+//		     trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
+		     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");trstack.adjust(1);}
+	     }
+
+     | plusminus expr '.' member
+             { $$.constant=0; $$.ident=0; SString t=$2.getString(); t+="."; t+=$4.getString(); $$.setString(t);
+	     if ($4.constant)
+		     trctx.out->printf("move s0,m1\n%s [m1].%s\nmove [m1].%s,s0\n",
+				       $1.getInt()?"inc":"dec",str($4),str($4));
+	     else
+//		     trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
+		     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\n%s [m1].[m2]\nmove [m1].[m2],s0\n",
+					$1.getInt()?"inc":"dec");trstack.adjust(1);}
+	     }
+
+     | expr '.' member plusminus
+             { $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
+	     if ($3.constant)
+		     trctx.out->printf("move s0,m1\nmove [m1].%s,s0\n%s [m1].%s\n",
+				       str($3),$4.getInt()?"inc":"dec",str($3));
+	     else
+//		     trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
+		     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n%s [m1].[m2]\n",
+					$4.getInt()?"inc":"dec");trstack.adjust(1);}
+	     }
+
+     | expr '.' member assign_op expr
+             { $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
+	     if ($3.constant)
+		     {
+		     int sp;
+		     if ($5.constant)
+			     {sp=0; trctx.out->printf("move s0,m1\n");}
+		     else
+			     {sp=1; trctx.out->printf("move s1,m1\n");}
+		     t="[m1]."; t+=str($3);
+		     handleAssignOp2($$,(const char*)t,$5,assign_op_names[$4.getInt()],sp,0);
+		     if (sp) {trctx.out->printf("inc m0\n");trstack.adjust(1);}
+		     }
+	     else
+		     {
+		     int sp;
+		     char *t;
+		     if ($5.constant)
+			     {sp=1; t="move s1,m1\nmove s0,m2\n";}
+		     else
+			     {sp=2; t="move s2,m1\nmove s1,m2\n";}
+		     trctx.out->printf(t);
+		     handleAssignOp2($$,"[m1].[m2]",$5,assign_op_names[$4.getInt()],sp,0);
+		     trctx.out->printf("add %d,m0\n",sp);
+		     trstack.adjust(sp);
+		     }
+	     }
+
+     | expr '.' member '=' stackexpr
+	     { $$=$5; $$.assign=1; $$.parens=0; $$.ident=0;
+	     if ($3.constant)
+		     {
+		     trctx.out->printf("move s1,m1\nmove m[m0++],s0\nmove s0,[m1].%s\n",str($3));
+		     trstack.adjust(1);
+		     }
+	     else
+		     {
+		     trctx.out->printf("move s2,m1\nmove s1,m2\nmove s0,[m1].[m2]\nadd 2,m0\nmove s-2,s0\n");
+		     trstack.adjust(2);
+		     }
+	     }
+
+     | expr '.' member '(' arguments ')'
+             { $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
+	     int adj=0;
+	     if ($5.getInt()==0)
+		     {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
+	     if ($3.constant)
+		     {
+		     trctx.out->printf("move s%d,m1\ncall [m1].%s\n",$5.getInt()+adj,str($3));
+		     adj+=1;
+		     }
+	     else
+		     {
+		     trctx.out->printf("move s%d,m2\nmove s%d,m1\ncall [m2].[m1]\n",
+				       $5.getInt()+adj+1,$5.getInt()+adj);
+		     adj+=2;
+		     }
+	     if (($5.getInt()+adj) > 1)
+		     {
+		     trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$5.getInt()-1+adj,-($5.getInt()-1+adj));
+		     trstack.adjust($5.getInt()-1+adj);
+		     }
+	     }
+
+      | expr '[' expr ']' '=' expr    // shortcut: expr.set(expr,expr)
+	     { $$=$6; $$.assign=1; $$.parens=0; $$.ident=0;
+	     if ($3.constant)
+		     {
+		     if ($6.constant)
+			     {trctx.out->printf("move s0,m1\ncall [m1].\"set\",%s,%s\ninc m0\n",litstr($3),litstr($6));$$=$6;trstack.adjust(+1);}
+		     else
+			     {trctx.out->printf("move s1,m1\npush s0\nmove %s,s1\ncall [m1].\"set\"\nadd 2,m0\nmove s-2,s0\n",litstr($3));trstack.adjust(+1);}
+		     }
+	     else
+		     {
+		     if ($6.constant)
+			     {trctx.out->printf("move s1,m1\npush %s\ncall [m1].\"set\"\nadd 3,m0\n",litstr($6)); trstack.adjust(+2);}
+		     else
+			     {trctx.out->printf("move s2,m1\ncall [m1].\"set\"\nadd 2,m0\nmove s-2,s0\n"); trstack.adjust(+2);}
+		     }
+	     }
+
+      | expr '[' expr ']'    /* shortcut: expr.get(expr) */
+             { $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".get"; $$.setString(t);
+	     if ($3.constant)
+		     {
+		     trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n",litstr($3));
+		     }
+	     else
+		     {
+		     trctx.out->printf("move s1,m1\ncall [m1].\"get\"\ninc m0\nmove s-1,s0\n");
+		     trstack.adjust(+1);
+		     }
+	     }
+
+     | IDENT '=' expr { $$=$3; $$.assign=1; $$.ident=0;
+                        int loc=trstack.getVariableLocation($1.getString());
+			if (loc!=TranslatorStack::NOTFOUND)
+			    {
+			    if ($3.constant) 
+			      trctx.out->printf("move %s,s%d\n",litstr($3),loc-trstack.currentPos());
+			    else
+			      trctx.out->printf("move s0,s%d\n",loc-trstack.currentPos());
+			    }
+		        else if (globalOk($1)) { $$=$3; $$.ident=0; $$.assign=1;
+			  if ($3.constant) trctx.out->printf("move %s,@%s\n",litstr($3),str($1));
+			  else trctx.out->printf("move s0,@%s\n",str($1));}
+			else {trctx.err->printf("undefined variable: %s\n",str($1)); return 1;}
+                      }
+
+      | OBJNAME '[' expr ']'    /* shortcut: OBJNAME.get(expr) */
+             { $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".get"; $$.setString(t);
+	     if ($3.constant)
+		     {
+		     trctx.out->printf("dec m0\ncall %s.get,%s\n",str($1),litstr($3));
+		     trstack.adjust(-1);
+		     }
+	     else
+		     {
+		     trctx.out->printf("call %s.get\n",str($1));
+		     }
+	     }
+
+      | IDENT '(' arguments ')'
+{
+$$.constant=0; $$.ident=0; $$.setString("function call");
+if ($3.getInt()==0)
+	{trctx.out->printf("dec m0\n");trstack.adjust(-1);}
+trctx.out->printf("call :%s\n",str($1));
+if ($3.getInt()>1)
+	{
+	trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$3.getInt()-1,-($3.getInt()-1));
+	trstack.adjust($3.getInt()-1);
+	}
+}
+
+| '[' {$$.ident=0; trctx.out->printf("add -2,m0\ncall Vector.new\nmove s0,s1\n");trstack.adjust(-2);} // s1=vector, s0=nieuzywane ale zarezerwowane zeby nie przesuwac stosu przy kazdym elemencie (trafia tu wartosc zwracana przez add/set)
+        v_elements ']'
+        {$$.constant=0; trctx.out->printf("inc m0\n");trstack.adjust(1);}
+
+| '{' {$$.ident=0; trctx.out->printf("add -2,m0\ncall Dictionary.new\nmove s0,s1\n");trstack.adjust(-2);} // s1=dict, s0=nieuzywane ale zarezerwowane zeby nie przesuwac stosu przy kazdym elemencie (trafia tu wartosc zwracana przez add/set)
+        d_elements '}'
+        {$$.constant=0; trctx.out->printf("inc m0\n"); trstack.adjust(1);}
+
+//      | '&' stackexpr {trctx.out->printf("call Ref.new\n");}
+
+      | '&' IDENT {
+        $$.ident=0;
+	int loc=trstack.getVariableLocation($2.getString());
+	if (loc!=TranslatorStack::NOTFOUND)
+		{
+		trctx.out->printf("push &%d\ncall Ref.newS\n",loc-trstack.currentPos());trstack.adjust(-1);
+		}
+	else if (globalOk($2))
+		{
+		trctx.out->printf("gpush &@%s\ncall Ref.newO\ninc m0\nmove s-1,s0\n",str($2));
+		trstack.adjust(-1);
+		}
+	else {trctx.err->printf("undefined variable: %s\n",str($1)); return 1;}
+            }
+
+      | '&' OBJNAME '.' member {
+      $$.ident=0;
+      if ($4.constant)
+	      {
+	      trctx.out->printf("dec m0\ncall Ref.newO,%s.*,%s:%s\n",str($2),str($2),str($4));
+	      trstack.adjust(-1);
+	      }
+      else
+	      {
+	      trctx.out->printf("call Ref.newO,%s.*,s0\n",str($2));
+	      }
+      }
+
+      | '&' '(' stackexpr ')' '.' member {
+      $$.ident=0;
+      if ($6.constant)
+	      {
+	      trctx.out->printf("call Ref.newO,s0,%s\n",litstr($6));
+	      }
+      else
+	      {
+	      trctx.out->printf("call Ref.newO,s1,s0\ninc m0\nmove s-1,s0\n");
+	      trstack.adjust(1);
+	      }
+      }
+
+      | '(' stackexpr ',' stackexpr ',' stackexpr ')' {
+      $$.ident=0;
+      trctx.out->printf("call XYZ.new\nadd 2,m0\nmove s-2,s0\n");trstack.adjust(2);}
+;
+
+v_elements: /* empty */
+      | v_element 
+      | v_elements ',' v_element
+;
+
+d_elements: /* empty */
+      | d_element 
+      | d_elements ',' d_element
+;
+
+v_element: expr
+{
+if ($1.constant)
+	trctx.out->printf("move s1,m1\ncall [m1].Vector:add,%s\n",litstr($1));
+else
+	{trctx.out->printf("move s2,m1\ncall [m1].Vector:add\ninc m0\n");trstack.adjust(1);}
+}
+;
+
+d_element: expr ':' expr
+{
+if ($1.constant)
+	{
+	if ($3.constant)
+		trctx.out->printf("move s1,m1\ncall [m1].Dictionary:set,%s,%s\n",litstr($1),litstr($3));
+	else
+		{trctx.out->printf("move s2,m1\nmove %s,s1\ncall [m1].Dictionary:set\ninc m0\n",litstr($1));trstack.adjust(1);}
+	}
+else
+	{
+	if ($3.constant)
+		{trctx.out->printf("move s2,m1\nmove s0,s1\nmove %s,s0\ncall [m1].Dictionary:set\ninc m0\n",litstr($3));trstack.adjust(1);}
+	else
+		{trctx.out->printf("move s3,m1\ncall [m1].Dictionary:set\nadd 2,m0\n");trstack.adjust(2);}
+	}
+}
+;
+
+member:    IDENT { $$=$1; $$.constant=1;}
+         | OBJNAME ':' IDENT { SString t=$1.getString();t+=":";t+=$3.getString();
+	                       $$.setString(t);$$.constant=1;}
+         | '[' stackexpr ']' { SString t="["; t+=$2.getString(); t+="]";
+                               $$.setString(t); $$.constant=0;}
+
+stackexpr: expr {if ($1.constant) {trctx.out->printf("push %s\n",litstr($1)); trstack.adjust(-1); $$.constant=0;} }
+
+arguments: /* empty */         { $$.setInt(0); }
+         |  stackexpr               { $$.setInt(1); }
+         |  arguments ',' stackexpr  {$$.setInt($1.getInt()+1);}
+;
+
+%%
+
+SString makeLitString(const ExtValue& val)
+{
+if (val.type!=TString)
+	return val.getString();
+SString s=val.getString();
+int len=s.len();
+SString ret((len*11)/10+10);
+ret+='\"';
+const char*t=(const char*)s;
+while(len>0)
+	{
+	switch(*t)
+		{
+		case '\n': ret+="\\n"; break;
+		case '\r': ret+="\\r"; break;
+		case '\t': ret+="\\t"; break;
+		default: ret+=*t;
+		}
+	t++; len--;
+	}
+ret+='\"';
+return ret;
+}
+
+static void yyprint (FILE *file,int type,YYSTYPE value)
+{
+fprintf(file,"(%s)%s",str(value),value.constant?"c":"");
+}
+
+int yyerror (const char *s)  /* Called by yyparse on error */
+{
+trctx.err->printf ("%s\n",s);
+return 0; // w przykladach do bisona tez nie dali returna...
+}
+
+void handleTwoArg(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,
+		  int optoken,const char* opname,bool logic,bool negarg2,bool uniq)
+{
+result.ident=false;
+if (arg1.constant && arg2.constant)
+	{
+	result=arg1;
+	switch(optoken)
+		{
+		case '+': result+=arg2; break;
+		case '-': result-=arg2; break;
+		case '*': result*=arg2; break;
+		case '/': result/=arg2; break;
+		case '%': result%=arg2; break;
+		case '&': result.setInt(arg1.getInt() & arg2.getInt()); break;
+		case '|': result.setInt(arg1.getInt() | arg2.getInt()); break;
+		case LSHIFT: result.setInt(arg1.getInt() << arg2.getInt()); break;
+		case RSHIFT: result.setInt(arg1.getInt() >> arg2.getInt()); break;
+		case LOGIC_AND: result.setInt(arg1.getInt() && arg2.getInt()); break;
+		case LOGIC_OR: result.setInt(arg1.getInt() || arg2.getInt()); break;
+		}
+	}
+else
+	{
+	//TODO: prawie kazde uzycie uniq jest niepotrzebne bo typem rzadko bedzie vector, ale w wiekszosci miejsc okreslenie typu wartosci
+	// byloby bardzo trudne lub niemozliwe. mozna byloby natomiast zapamietywac przy parsowaniu czy dana wartosc na stosie jest
+	// skopiowana ze zmiennej/pola czy jest wynikiem wczesniejszej operacji co pozwoliloby na likwidacje bardzo wielu uniq
+	result.constant=0;
+	result.assign=arg1.assign || arg2.assign;
+	result.parens=0;
+	result.setString(opname);
+	if (arg1.constant)
+		trctx.out->printf("move %s,m1\n%s%s%s s0,m1\nmove m1,s0\n",litstr(arg1),
+				  (logic?"setif !=,m1,m1\nsetif !=,s0,s0\n":""),
+				  negarg2?"neg s0\n":"",
+				  opname);
+	else if (arg2.constant)
+		{
+		if (logic)
+			trctx.out->printf("move %s,m1\nsetif !=,m1,m1\nsetif !=,s0,s0\n%s m1,s0\n",
+					  litstr(arg2),opname);
+		else
+			{
+			if (negarg2)
+				trctx.out->printf("%s %d,s0\n",opname,-arg2.getInt());
+			else
+				trctx.out->printf("%s%s %s,s0\n",(uniq?"uniq s0\n":""),opname,litstr(arg2));
+			}
+		}
+	else 
+		{
+		trctx.out->printf("%s%s%s s0,s1\ninc m0\n",
+				  (logic?"setif !=,s0,s0\nsetif !=,s1,s1\n":(uniq?"uniq s1\n":"")),
+				  negarg2?"neg s0\n":"",
+				  opname);
+		trstack.adjust(+1);
+		}
+	}
+}
+
+bool handleAssignOp(YYSTYPE& result,const YYSTYPE& var,const YYSTYPE& arg,const char* opname)
+{
+int loc; if (variableOk(result,var,loc))
+	{
+	loc-=trstack.currentPos();
+	if (arg.constant)
+		{
+		trctx.out->printf("%s %s,s%d\npush s%d\n",opname,litstr(arg),loc,loc);
+		trstack.adjust(-1);
+		}
+	else
+		trctx.out->printf("%s s0,s%d\nmove s%d,s0\n",opname,loc,loc);
+	return 1;
+	}
+return 0;
+}
+
+bool handleAssignOp2(YYSTYPE& result,const char *var,const YYSTYPE& arg,const char* opname,int stackpos,bool push)
+{
+if (arg.constant)
+	{
+	trctx.out->printf("%s %s,%s\n",opname,litstr(arg),var);
+	if (!push)
+		trctx.out->printf("move %s,s%d\n",var,stackpos);
+	else
+		{
+		trctx.out->printf("push %s\n",var);
+		trstack.adjust(-1);
+		}
+	}
+else
+	trctx.out->printf("%s s0,%s\nmove %s,s%d\n",opname,var,var,stackpos);
+return 1;
+}
+
+void handleCompare(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,int optoken,const char* opname)
+{
+result.ident=0;
+if (arg1.constant && arg2.constant)
+	{
+	result.constant=1;
+	switch(optoken)
+		{
+		case '>': result.setInt(arg1.compare(arg2) > 0); break;
+		case '<': result.setInt(arg1.compare(arg2) < 0); break;
+		case EQUAL: result.setInt(arg1.compare(arg2) == 0); break;
+		case NOT_EQUAL: result.setInt(arg1.compare(arg2) != 0); break;
+		case GEQUAL: result.setInt(arg1.compare(arg2) >= 0); break;
+		case LEQUAL: result.setInt(arg1.compare(arg2) <= 0); break;
+		}
+	}
+else
+	{
+	result.constant=0;
+	result.assign=arg1.assign || arg2.assign;
+	result.parens=0;
+	result.setString(opname);
+	if (arg1.constant)
+		trctx.out->printf("setif %s,%s,s0,s0\n",litstr(arg1),opname);
+	else if (arg2.constant)
+		trctx.out->printf("setif s0,%s,%s,s0\n",opname,litstr(arg2));
+	else 
+		{
+		trctx.out->printf("setif s1,%s,s0,s1\ninc m0\n",opname);
+		trstack.adjust(+1);
+		}
+	}
+}
+
+bool variableOk(TokenValue &tok, const TokenValue& var,int &loc)
+{
+loc=trstack.getVariableLocation(var.getString());
+if (loc != TranslatorStack::NOTFOUND)
+	{tok.setInt(loc); tok.constant=0;
+	return 1;}
+return 0;
+}
+
+bool globalOk(const TokenValue& var)
+{
+SymTabEntry* found=trstack.globals.find(var.getString());
+if (found) return true;
+return framscriptIsGlobalName(var.getString());
+}
+
+void badVariable(TokenValue &tok, const TokenValue& var)
+{
+tok=var; tok.constant=1;
+trctx.err->printf("undefined variable '%s'\n",str(var));
+}
+
+bool doBreak(int level)
+{
+if (trstack.loops.size()<level)
+	{trctx.err->printf("invalid 'break'"); return 0;}
+LoopInfo* li=trstack.loops.getLoop(level-1);
+if (li->location != trstack.currentPos())
+	trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
+trctx.out->printf("jump :_loop_end_%d\n",li->id);
+return 1;
+}
+
+bool doContinue(int level)
+{
+if (trstack.loops.size()<level)
+	{trctx.err->printf("invalid 'continue'"); return 0;}
+LoopInfo* li=trstack.loops.getLoop(level-1);
+if (li->location != trstack.currentPos())
+	trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
+trctx.out->printf("jump :_loop_%d\n",li->id);
+return 1;
+}
+
+int lookupToken(char *s)
+{
+int len=strlen(s);
+int i;
+const char *t;
+for (i = 0; i < YYNTOKENS; i++)
+	{
+	t=yytname[i];
+	if (t && (t[0]=='"') 
+	   && (!strncmp(t+1,s,len))
+	   && (t[len+1]=='"') 
+	   && (t[len+2] == 0))
+		return yytoknum[i];
+	}
+return -1;
+}
+
+void warnTruthValue(const TokenValue& t)
+{
+if (t.assign && (!t.parens))
+	FMprintf("FramScriptCompiler","translate",FMLV_WARN,"Assignment used as truth value, use double parens if you really mean it (%s line %d)",(const char*)trctx.srcname,trctx.line);
+}
+
+void outFunName(const TokenValue& t)
+{
+if (trctx.functiontmplabel<0)
+	{
+	trctx.functiontmplabel=trctx.labelcounter++;
+	trctx.out->printf("jump :_skipfun_%d\n",trctx.functiontmplabel);
+	}
+trctx.out->printf(":%s\n",str(t));
+}
+
+bool evalVariable(TokenValue &tok,const TokenValue &var)
+{
+int loc;
+if (variableOk(tok,var,loc))
+	{
+	trctx.out->printf("push s%d\n",loc-trstack.currentPos());
+	trstack.adjust(-1);
+	return true;
+	}
+else if (globalOk(var))
+	{
+	trctx.out->printf("push @%s\n",(const char*)var.getString());
+	trstack.adjust(-1);
+	return true;
+	}
+else
+	{
+	badVariable(tok,var); return false;
+	}
+}
