source: cpp/frams/vm/framscript.y @ 426

Last change on this file since 426 was 382, checked in by sz, 10 years ago

Moving frams/virtfile to common/virtfile:

  • file references updated (includes, makefile)
  • common/virtfile can no longer use the Framsticks specific SString (using std::string instead)
  • Property svn:eol-style set to native
File size: 43.9 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
[163]4
5%{
6#include "framscript-defs.h"
[375]7#include "common/log.h"
[163]8#include <math.h>
9#include <ctype.h>
10#include <stdio.h>
11
12#define YYERROR_VERBOSE
13#define YYPRINT(file,type,value) yyprint (file,type,value)
14
15static void yyprint (FILE *file,int type,YYSTYPE value);
16void handleTwoArg(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,
[332]17                  int optoken,const char* opname, bool negarg2, bool uniq);
18bool handleCompare(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,
19                   ExtValue::CmpOperator,const char* opname);
[163]20bool handleAssignOp(YYSTYPE& result,const YYSTYPE& var,const YYSTYPE& arg,const char* opname);
21bool handleAssignOp2(YYSTYPE& result,const char *var,const YYSTYPE& arg,const char* opname,int stackpos,bool push);
22bool variableOk(TokenValue &tok, const TokenValue& var,int &loc);
23bool globalOk(const TokenValue& var);
24void badVariable(TokenValue &tok, const TokenValue &var);
25bool evalVariable(TokenValue &tok, const TokenValue &var);
26bool doBreak(int level);
27bool doContinue(int level);
28void warnTruthValue(const TokenValue& t);
29void outFunName(const TokenValue& t);
[333]30static bool resultIsRelaxedEqual(ExtValue::CompareResult res);
[163]31
32static const char* assign_op_names[]={"add","sub","mul","div","mod"};
33
34%}
35
36%token_table
37
38%token CONSTANT
39
40%nonassoc ASSIGN_ADD ASSIGN_SUB ASSIGN_MUL ASSIGN_DIV ASSIGN_MOD
41%nonassoc PLUSPLUS MINUSMINUS
42%left LOGIC_AND LOGIC_OR '!'
43%left EQUAL NOT_EQUAL GEQUAL LEQUAL '>' '<'
44%left '|' '&' '^'
45%left '-' '+'
46%left '*' '/' '%'
47%left NEG     /* negation--unary minus */
48%left TYPEOF
[333]49%left INT_TYPE
50%left FLOAT_TYPE
51%left STRING_TYPE
[163]52
53%token IDENT
54%token OBJNAME
55
56%token IF      "if"
57%token ELSE    "else"
58%token FOR     "for"
59%token INNN    "in"
60%token WHILE   "while"
61%token DO      "do"
62%token GOTO    "goto"
63%token RETURN  "return"
64%token BREAK    "break"
65%token CONTINUE "continue"
66%token SWITCH   "switch"
67%token CASE     "case"
68%token DEFAULT  "default"
69
[333]70%token TYPEOF      "typeof"
71%token INT_TYPE    "int"
72%token FLOAT_TYPE  "float"
73%token STRING_TYPE "string"
[163]74
75%token ASM     
76%token ASMLINE
77             
78%token VAR      "var"
79%token GLOBAL   "global"
80%token FUNCTION "function"
81
82%token CALL    "call"
83
84%token ASSIGN
85%token ASSIGN_ADD
86%token ASSIGN_SUB
87%token ASSIGN_MUL
88%token ASSIGN_DIV
89
90%token EQUAL
91%token NOT_EQUAL
92%token GEQUAL
93%token LEQUAL
94
95%token LOGIC_AND
96%token LOGIC_OR
97
98%token PLUSPLUS
99%token MINUSMINUS
100
101%token LSHIFT
102%token RSHIFT
103
104%%
105code: {$$.setInt(trstack.currentPos());} recurcode
106{
107int pos=$1.getInt();
108if (pos!=trstack.currentPos()) trctx.out->printf("add %d,m0\n",pos-trstack.currentPos());
109}
110;
111
112recurcode:    /* empty string */
113       | recurcode statement
114;
115     
116statement: ';'
117      | VAR vardeflist ';'
118      | GLOBAL globaldeflist ';'
119      | IDENT ':'     {trctx.out->printf(":%s\n",str($1));}
[332]120      | expr ';'      {if (!$1.constant) { trctx.out->printf("inc m0\n"); trstack.adjust(+1); } trctx.emitLine(); }
[163]121      | functiondef
122      | blok
123      | if_statement
124      | goto_statement
125      | return_statement
126      | for_statement
127      | while_statement
128      | dowhile_statement
129      | break_statement
130      | continue_statement
131      | switch_statement
132//      | error ';'
133      | asmblock
134;
135
136asmblock: ASM asmlines '}'
137;
138
139asmlines: /* empty */
140        | ASMLINE            {fputs(str($1),trctx.out);fputc('\n',trctx.out);}
141        | asmlines ASMLINE   {fputs(str($2),trctx.out);fputc('\n',trctx.out);}
142;
143
144goto_statement: GOTO IDENT ';'
145 {
146#ifdef FRAMSCRIPT_GOTO
[375]147trctx.out->printf("jump :%s\n",str($2)); logPrintf("FramScriptCompiler","translate",LOG_WARN,"goto is not recommended"); trctx.emitLine();
[163]148#else
[245]149trctx.err->printf("goto is not supported\n");return 1;
[163]150#endif
151 }
152;
153
154return_statement: RETURN expr ';'
155{
156int offset;
157if (trctx.functionstackpos==999)
158        offset=-trstack.currentPos();
159else
160        offset=trctx.functionstackpos-trstack.currentPos();
161if (!offset)
162        {
163        if ($2.constant)
164                trctx.out->printf("move %s,s0\nreturn\n",litstr($2));
165        else
166                {
167                trctx.out->printf("move m[m0++],s0\nreturn\n");
168                trstack.adjust(+1);
169                }
170        }
171else
172        {
173        if ($2.constant)
174                {
175                trctx.out->printf("add %d,m0\nmove %s,s0\nreturn\n",offset,litstr($2));
176                trstack.adjust(offset);
177                }
178        else
179                {
180                trctx.out->printf("move s0,s%d\nadd %d,m0\nreturn\n",offset,offset);
181                trstack.adjust(offset);
182                }
183        }
184}
185          | RETURN ';'
186{
187int offset;
188if (trctx.functionstackpos==999)
189        offset=-trstack.currentPos();
190else
191        offset=trctx.functionstackpos-trstack.currentPos();
[332]192trctx.emitLine();
[163]193if (!offset)
194        trctx.out->printf("move invalid,s0\nreturn\n");
195else
196        trctx.out->printf("add %d,m0\nmove invalid,s0\nreturn\n",offset);
197}
198;
199
200vardeflist: vardef
201          | vardeflist ',' vardef
202;
203
[332]204vardef: IDENT               { trctx.emitLine(); trstack.addVariable($1.getString()); trctx.out->printf("push invalid\n");}
205      | IDENT '=' stackexpr { trctx.emitLine(); trstack.adjust(1); trstack.addVariable($1.getString());}
[163]206;
207
208globaldeflist: globaldef
209          | globaldeflist ',' globaldef
210;
211
212globaldef: IDENT     {trstack.globals.add($1.getString(),0);
213                      trctx.out->printf("global %s\n",str($1));}
214;
215
216funparam: IDENT { trstack.addVariable($1.getString()); };
217
218paramlist: /* empty */             {$$.setInt(0); }
219         | funparam                {$$.setInt(1); }
220         | paramlist ',' funparam  {$$.setInt($1.getInt()+1);}
221;
222
223funnamelist:
224         IDENT {outFunName($1);}
225         | funnamelist ',' IDENT {outFunName($3);}
226;
227
228functiondef:                FUNCTION funnamelist
229{
[332]230trctx.emitLine();
[163]231int pos=trstack.currentPos();
232$$.setInt(pos);
233if (trctx.functionstackpos!=999)
[245]234        {trctx.err->printf("functions cannot be nested\n");return 1;}
[163]235}
236                            '(' paramlist ')'
237{
238trctx.functionstackpos=trstack.currentPos();
239}
240                            blok
241{trctx.out->printf("move invalid,s0\nreturn\n");
242int pos=$3.getInt();
243trstack.dropToPos(pos);
244trctx.functionstackpos=999;
245trctx.out->printf(":_skipfun_%d\n",trctx.functiontmplabel);
246trctx.functiontmplabel=-1;
[332]247trctx.emitLine();
[163]248};
249
250break_statement: BREAK ';'         {if (!doBreak(1)) return 1;}
251               | BREAK expr ';'
252{
[332]253trctx.emitLine();
[163]254if (!$2.constant)
[245]255        {trctx.err->printf("break level must be a constant expression\n");return 1;}
[163]256int level=$2.getInt();
257if (level<1)
[245]258        {trctx.err->printf("break level must be a positive integer\n");return 1;}
[163]259if (!doBreak(level)) return 1;
[332]260trctx.emitLine();
[163]261};
262
263continue_statement: CONTINUE ';'         {if (!doContinue(1)) return 1;}
264                  | CONTINUE expr ';'
265{
266if (!$2.constant)
[245]267        {trctx.err->printf("continue level must be a constant expression\n");return 1;}
[163]268int level=$2.getInt();
269if (level<1)
[245]270        {trctx.err->printf("continue level must be a positive integer\n");return 1;}
[163]271if (!doContinue(level)) return 1;
[332]272trctx.emitLine();
[163]273};
274
275while_statement: WHILE '('
[332]276{
277int c=trctx.labelcounter++; $$.setInt(c);
[163]278$$.stack=trstack.currentPos();
279trstack.loops.addLoop(c,$$.stack);
280trctx.out->printf(":_loop_%d\n",c);}
281                              expr ')'
282{
283int c=$3.getInt();
284warnTruthValue($4);
285if ($4.constant)
286        {if (!$4.getInt()) trctx.out->printf("jump :_loop_end_%d\n",c);}
287else
288        {
[332]289        trctx.out->printf("if ~=,m[m0++],:_loop_end_%d\n",c,c);
[163]290        trstack.adjust(+1);
291        }
292}
293                 pseudoblok_statement
[332]294{
295trctx.out->printf("jump :_loop_%d\n:_loop_end_%d\n",$3.getInt(),$3.getInt());
[163]296trstack.adjust($3.stack-trstack.currentPos());
297trstack.loops.drop();
298}
299;
300
301dowhile_statement: DO
[332]302{
303trctx.emitLine();
304int c=trctx.labelcounter++; $$.setInt(c);
[163]305$$.stack=trstack.currentPos();
306trstack.loops.addLoop(c,$$.stack);
307trctx.out->printf(":_loop_%d\n",c);} //2
308
309pseudoblok_statement WHILE '(' expr ')'
310
311{//8
312int c=$2.getInt();
313warnTruthValue($6);
314if ($6.constant)
315        {if ($6.getInt()) trctx.out->printf("jump :_loop_%d\n",c);}
316else
317        {
[332]318        trctx.out->printf("if !~,m[m0++],:_loop_%d\n",c);
[163]319        trstack.adjust(+1);
320        }
321trctx.out->printf(":_loop_end_%d\n",c);
322trstack.adjust($2.stack-trstack.currentPos());
323trstack.loops.drop();
[332]324trctx.emitLine();
[163]325}
326;
327
328switch_statement: SWITCH '('
[332]329{
330int c=trctx.labelcounter++; $1.setInt(c);
[163]331trstack.loops.addLoop(c,trstack.currentPos());}
332       stackexpr ')'
[332]333{trctx.emitLine(); trctx.out->printf("dec m0\n"); trstack.adjust(-1);}
[163]334 '{' inside_switch '}'
[332]335{
336trctx.emitLine();
337LoopInfo *li=trstack.loops.getLoop(0);
338trctx.out->printf(":_case_after_%d_%d\n"
339                  "add 2,m0\n"
340                  ":_loop_end_%d\n",
341                  li->id,li->casecounter,
342                  li->id);
343trstack.adjust(+2);
344trstack.loops.drop();
345}
[163]346;
347
348inside_switch: /* empty */
349       | case_label
350       | inside_switch case_label
351;
352
353case_label: CASE expr ':'
[332]354{
355LoopInfo *li=trstack.loops.getLoop(0);
356if ($2.constant)
357        trctx.out->printf("if s1,!=,%s,:_case_before_%d_%d\n",
358                          litstr($2),
359                          li->id,li->casecounter+1);
360else
361        {
362        trctx.out->printf("if s2,!=,m[m0++],:_case_before_%d_%d\n",
363                          li->id,li->casecounter+1);
364        trstack.adjust(+1);
365        }
366trctx.out->printf(":_case_after_%d_%d\n",
367                  li->id,li->casecounter);
[163]368int pos=trstack.currentPos(); $$.setInt(pos);
369}
370 recurcode
371{
[332]372trctx.emitLine();
373LoopInfo *li=trstack.loops.getLoop(0);
[163]374int pos=$4.getInt();
375if (pos!=trstack.currentPos()) trctx.out->printf("add %d,m0\n",pos-trstack.currentPos());
376trstack.dropToPos(pos);
[332]377li->casecounter++;
378trctx.out->printf("jump :_case_after_%d_%d\n"
379                  ":_case_before_%d_%d\n",
380                  li->id,li->casecounter,
381                  li->id,li->casecounter);
[163]382}
[332]383      |  DEFAULT ':'
384  {
385  LoopInfo *li=trstack.loops.getLoop(0);
386  trctx.out->printf(":_case_after_%d_%d\n",li->id,li->casecounter);
387  }
388  recurcode
389  {
390  LoopInfo *li=trstack.loops.getLoop(0);
391  li->casecounter++;
392  }
[163]393;
394
395newvar_or_expr:
396              VAR IDENT { $$.setInt(trstack.addVariable($2.getString())); trctx.out->printf("push invalid\n"); $$.ident=true; $$.var=true; }
397
398              |
399              VAR IDENT '=' stackexpr
400              {
401              //trctx.out->printf("# VAR IDENT '=' stackexpr pos=%d\n",trstack.currentPos());
402              trstack.adjust(+1);
403              $$.setInt(trstack.addVariable($2.getString()));
404              $$.ident=true; $$.var=true;
405              }
406
407              |
408              expr_special_ident
409              {
410              $$=$1;
411              }
412
413              | //nic
414              {
415              $$.setInt(1); $$.assign=false; $$.ident=false; $$.var=false; $$.constant=true;
416              }
417;
418
419expr_or_objname:
420              expr { $$=$1; $$.objname=false; }
421              |
422              OBJNAME { $$.setString($1.getString()); $$.objname=true; }
423;
424
425for_statement_begin: FOR '('
426{
427int c=trctx.labelcounter++; $$.counter=c; $$.stack=trstack.currentPos();
428}
429newvar_or_expr
430{
431$$=$4; $$.counter=$3.counter; $$.stack=$3.stack;
432};
433
434for_statement:
435
436           ///////////  for(in) ...  ////////////
437           for_statement_begin INNN
438           {//3
439           if (!$1.ident)
440                   {
441                   trctx.err->printf("for(... in ...) requires an variable\n");
442                   return 1;
443                   }
444           int loc;
445           if ($1.var) // for(var x[=expr] in
446                   $$.setInt($1.getInt());
447           else
448                   {  // for(x in
449                   if (variableOk($$,$1,loc))
450                           $$.setInt(loc);
451                   else if (globalOk($1))
452                           {
453                           trctx.err->printf("global '%s' can't be iterating variable in for\n",str($1));
454                           return 1;
455                           }
456                   else
457                           {
458                           badVariable($$,$1);
459                           return 1;
460                           }
461                   }
462           }
463           expr_or_objname ')'
464           {//6
[332]465           trctx.emitLine();
[163]466           if ($4.constant)
467                   {trctx.err->printf("%s can't be iterated\n",str($4)); return 1;}
468           if ($4.objname)
[348]469                   trctx.out->printf("move %s.iterator,m[--m0]\n",$4.getString().c_str());
[163]470           else
471                   trctx.out->printf("move s%d,m1\nmove [m1].\"iterator\",m[--m0]\n",0);
472           trstack.adjust(-1);
473           // s0=iterator s1=obj (=obj.iterator)
474           trstack.loops.addLoop($1.counter,trstack.currentPos());
475           trctx.out->printf(":_loop1_%d\n",$1.counter);
476           trctx.out->printf(":_loop_%d\n",$1.counter);
477           trctx.out->printf("move s0,m1\nmove [m1].\"next\",m2\n");
478           trctx.out->printf("if m2,==,0,:_loop_end_%d\n",$1.counter);
479           trctx.out->printf("move [m1].\"value\",s%d\n",$3.getInt()-trstack.currentPos());
480           }
481           pseudoblok_statement
482           {
483           trctx.out->printf("jump :_loop1_%d\n",$1.counter);
484           trctx.out->printf(":_loop_end_%d\n",$1.counter);
485           trstack.loops.drop();
486           if ($1.stack != trstack.currentPos())
487                   trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
488           trstack.adjust($1.stack-trstack.currentPos());
489           }
490           
491|
492
493           ///////////  for(;;) ...  ////////////
494           for_statement_begin ';'
495           { //3
[332]496           trctx.emitLine();
[163]497           //trctx.out->printf("# for_statement_begin pos=%d ident=%d var=%d\n",trstack.currentPos(),$1.ident,$1.var);
498           if ((!$1.var) && ($1.ident))
499                   {  // for(x;
500                   int loc;
501                   if ((!variableOk($$,$1,loc)) || (globalOk($1)))
502                           {
503                           badVariable($$,$1);
504                           return 1;
505                           }
506                   }
507           if (!$1.constant && !$1.ident)
508                   {
509                   trctx.out->printf("inc m0\n");
510                   trstack.adjust(+1);
511                   }
512           trstack.loops.addLoop($1.counter,trstack.currentPos());
513           trctx.out->printf(":_loop1_%d\n",$1.counter);
514           //trctx.out->printf("# expr#2\n");
515           }
516           expr_or_empty ';'
517           { //6
[332]518           trctx.emitLine();
[163]519           int c=$1.counter;
520           warnTruthValue($4);
521           if ($4.constant)
522                   {if (!$4.getInt()) trctx.out->printf("jump :_loop_end_%d\n",c);}
523           else
524                   {
525                   trctx.out->printf("if m[m0++],==,0,:_loop_end_%d\n",c,c);
526                   trstack.adjust(+1);
527                   }
[382]528           trctx.tmp="";
[163]529           trctx.divertOut();
530           //trctx.out->printf("# expr#3\n");
531           }
532           expr_or_empty ')'
533           { //9
[332]534           trctx.emitLine();
[163]535           if (!$7.constant) { trctx.out->printf("inc m0\n"); trstack.adjust(+1); }
536           trctx.restoreOut();
[382]537           $$.setString(trctx.tmp.c_str());
[163]538           //trctx.out->printf("# pseudoblok_statement pos=%d\n",trstack.currentPos());
539           }
540           pseudoblok_statement
541           {//11
542           trctx.out->printf(":_loop_%d\n",$1.counter);
543           LoopInfo* li=trstack.loops.getLoop(0);
544           if (li->location != trstack.currentPos())
545                   trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
546           trctx.out->printf(str($9));
547           if (li->location != trstack.currentPos())
548                   trctx.out->printf("sub %d,m0\n",li->location-trstack.currentPos());
549           trctx.out->printf("jump :_loop1_%d\n:_loop_end_%d\n",$1.counter,$1.counter);
550           if ($1.stack != trstack.currentPos())
551                   trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
552           trstack.adjust($1.stack-trstack.currentPos());
553           trstack.loops.drop();
554           }
555;
556
557pseudoblok_statement:
[332]558{trctx.emitLine(); int pos=trstack.currentPos(); $$.setInt(pos);}
[163]559  statement
560{
561int pos=$1.getInt();
562if (pos!=trstack.currentPos()) trctx.out->printf("add %d,m0\n",pos-trstack.currentPos());
563trstack.dropToPos(pos);
[332]564trctx.emitLine();
[163]565};
566
567if_statement:
568 if_condition pseudoblok_statement
569                       {
570                       if ($1.stack!=trstack.currentPos())
571                               trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
572                       trstack.adjust(trstack.currentPos()-$1.stack);
573                       trctx.out->printf("jump :_if_end_%d\n:_if_else_%d\n",$1.getInt(),$1.getInt());
574                       }
575         ELSE
576                       {trstack.adjust($1.stack-trstack.currentPos());}
577         pseudoblok_statement
578                       {
579                       if ($1.stack!=trstack.currentPos())
580                               trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
581                       trstack.adjust(trstack.currentPos()-$1.stack);
582                       trctx.out->printf(":_if_end_%d\n",$1.getInt());
583                       }
584|
585 if_condition pseudoblok_statement
586                       {
587                       if ($1.stack!=trstack.currentPos())
588                               trctx.out->printf("add %d,m0\n",$1.stack-trstack.currentPos());
589                       trstack.dropToPos($1.stack);
590                       trctx.out->printf(":_if_else_%d\n",$1.getInt());
591                       }
592;
593
594if_condition: IF
[332]595{$$.stack=trstack.currentPos();trctx.emitLine();}
[163]596
597 '(' expr ')'
598{
[332]599trctx.emitLine();
[163]600int c=trctx.labelcounter++;
601$$.setInt(c);
602warnTruthValue($4);
603if ($4.constant)
604        {
605        if (!$4.getInt()) trctx.out->printf("jump :_if_else_%d\n",c);
606        }
607else
608        {
[332]609        trctx.out->printf("if ~=,m[m0++],:_if_else_%d\n",c);
[163]610        trstack.adjust(+1);
611        }
612$$.stack=$2.stack;
613};
614
615blok:    '{'
616{ int pos=trstack.currentPos();
617$$.setInt(pos);
618}
619         recurcode '}'
620{
621int pos=$2.getInt();
622if (pos!=trstack.currentPos()) trctx.out->printf("add %d,m0\n",pos-trstack.currentPos());
623trstack.dropToPos(pos);
624}
625
626assign_op: ASSIGN_ADD {$$.setInt(0);}
627         | ASSIGN_SUB {$$.setInt(1);}
628         | ASSIGN_MUL {$$.setInt(2);}
629         | ASSIGN_DIV {$$.setInt(3);}
630         | ASSIGN_MOD {$$.setInt(4);}
631
632plusminus: PLUSPLUS {$$.setInt(1);} | MINUSMINUS {$$.setInt(0);}
633
634expr: expr_special_ident
635  {
636  //trctx.out->printf("# expr: ident=%d str=%s\n",$1.ident,(const char*)$1.getString());
637  if ($1.ident)
638          {
639          if (evalVariable($$,$1))
640                  $$.constant=false;
641          else
642                  return 1;
643          }
644  else
645          {$$=$1; $$.ident=false;}
[332]646  trctx.emitLine();
[163]647  }
648;
649
[345]650stackexpr: expr {if ($1.constant) {trctx.out->printf("push %s\n",litstr($1)); trstack.adjust(-1); $$.constant=0;} }
651
[163]652expr_or_empty:
653         expr {$$=$1;}
654
655         | //nic
656         { $$.setInt(1); $$.assign=false; $$.constant=true; $$.ident=false; $$.ident=false; }
657;
658
659expr_special_ident:    CONSTANT             { $$=$1; $$.constant=1; $$.ident=0; }
660
661       | IDENT                { $$.ident=true; $$.setString($1.getString()); }
662
663       | OBJNAME ':' IDENT    {$$.constant=0; $$.ident=0;
[348]664                              trctx.out->printf("push %s:%s\n",$1.getString().c_str(),
665                                                 $3.getString().c_str());
[163]666                              trstack.adjust(-1);
667                              }
668       | plusminus IDENT
669{
[332]670trctx.emitLine();
[163]671$$.ident=0;
672int loc; if (variableOk($$,$2,loc))
673        { loc-=trstack.currentPos();
674        trctx.out->printf("%s s%d\npush s%d\n",$1.getInt()?"inc":"dec",loc,loc);
675        trstack.adjust(-1);}
676        else if (globalOk($2))
677        { trctx.out->printf("%s @%s\npush @%s\n",$1.getInt()?"inc":"dec",str($2),str($2));
678        trstack.adjust(-1);}
679        else {badVariable($$,$2); return 1;}
680}
681
682       | IDENT plusminus
683{
[332]684trctx.emitLine();
[163]685$$.ident=0;
686int loc; if (variableOk($$,$1,loc))
687        {loc-=trstack.currentPos(); trctx.out->printf("push s%d\n%s s%d\n",loc,$2.getInt()?"inc":"dec",loc+1);
688        trstack.adjust(-1);}
689        else if (globalOk($1))
[348]690        { trctx.out->printf("push @%s\n%s @%s\n",$1.getString().c_str(),
691                            $2.getInt()?"inc":"dec",$1.getString().c_str());
[163]692        trstack.adjust(-1);}
693        else {badVariable($$,$1); return 1;}
694}
695
[332]696       | IDENT assign_op expr { trctx.emitLine(); $$.ident=0;
[163]697                                if (!handleAssignOp($$,$1,$3,assign_op_names[$2.getInt()]))
698                                if (globalOk($1)) {SString t="@"; t+=$1.getString();
[348]699                                  handleAssignOp2($$,t.c_str(),$3,assign_op_names[$2.getInt()],0,1);}
[163]700                                else { badVariable($$,$1); return 1; }
701                              }
702
[332]703       | TYPEOF '(' expr ')' { trctx.emitLine(); $$.ident=0;
704                       if ($3.constant)
705                             {$$.constant=1; $$=$3.getExtType();}
[163]706                       else
707                             {trctx.out->printf("type s0,s0\n");}
708                     }
[333]709       | INT_TYPE '(' expr ')' { trctx.emitLine(); $$.ident=0;
[332]710                       if ($3.constant)
711                             {$$.constant=1; $$=ExtValue($3.getInt());}
712                       else
713                             {trctx.out->printf("conv 1,s0\n");}
714                     }
[333]715       | FLOAT_TYPE '(' expr ')' { trctx.emitLine(); $$.ident=0;
[332]716                       if ($3.constant)
717                             {$$.constant=1; $$=ExtValue($3.getDouble());}
718                       else
719                             {trctx.out->printf("conv 2,s0\n");}
720                     }
[333]721       | STRING_TYPE '(' expr ')' { trctx.emitLine(); $$.ident=0;
[332]722                       if ($3.constant)
723                             {$$.constant=1; $$=ExtValue($3.getString());}
724                       else
725                             {trctx.out->printf("conv 3,s0\n");}
726                     }
[163]727
[332]728       | expr '+' expr { handleTwoArg($$,$1,$3,'+',"add",0,1); }
729       | expr '-' expr { handleTwoArg($$,$1,$3,'-',"sub",0,0); }
730       | expr '*' expr { handleTwoArg($$,$1,$3,'*',"mul",0,1); }
731       | expr '/' expr { handleTwoArg($$,$1,$3,'/',"div",0,0); }
732       | expr '&' expr { handleTwoArg($$,$1,$3,'&',"and",0,0); }
733       | expr '|' expr { handleTwoArg($$,$1,$3,'|',"or",0,0); }
734       | expr '%' expr { handleTwoArg($$,$1,$3,'%',"mod",0,0); }
[163]735
[332]736       | expr LOGIC_AND
737 {
738 // a && b:
739 //   push a
740 //   if (a)
741 //     pop; goto and_b
742 //   else
743 //     pop; push 0; goto and_end
744 // and_b:
745 //   push b
746 // and_end:
747 trctx.emitLine();
748// trctx.out->printf("\n####### logic AND\n");
749 int c=trctx.labelcounter++;
750 $$.setInt(c);
751 if ($1.constant)
752         {
[333]753         ExtValue::CompareResult cond=$1.compare(ExtValue::zero());
754         if (resultIsRelaxedEqual(cond))
[332]755                 {
756                 $1.counter=0;
757                 // no stack adjust - next tokens are processed in a different context
758                 trctx.out->printf("push 0\njump :_and_end_%d\n",c);
759                 }
760         else
761                 $1.counter=1;
762         }
763 else
764         {
765         trstack.adjust(+1); // stack as if (a==true), b expr is processed
766         trctx.out->printf("if !~,m[m0++],:_and_b_%d\n"
767                           "push 0\n"
768                           "jump :_and_end_%d\n"
769                           ":_and_b_%d\n"
770                           ,c,c,c);
771         }
772 }
773         expr
774 {
775 $$.ident=false;
776 $$.constant=0;
777 if ($4.constant)
778         {
779         if (!($1.constant && $1.counter==0))
780                 {
[333]781                 ExtValue::CompareResult  cond=$4.compare(ExtValue::zero());
782                 bool value=!resultIsRelaxedEqual(cond);
[332]783                 trstack.adjust(-1);
784                 trctx.out->printf("push %d\n",value);
785                 }
786         }
787 trctx.out->printf(":_and_end_%d\n",$3.getInt());
788// trctx.out->printf("#################\n\n");
789 }
790
791       | expr LOGIC_OR
792 {
793 // a || b:
794 //   push a
795 //   if (!a)
796 //     pop; goto and_b
797 //   else
798 //     pop; push 1; goto and_end
799 // and_b:
800 //   push b
801 // and_end:
802 trctx.emitLine();
803// trctx.out->printf("\n####### logic AND\n");
804 int c=trctx.labelcounter++;
805 $$.setInt(c);
806 if ($1.constant)
807         {
[333]808         ExtValue::CompareResult  cond=$1.compare(ExtValue::zero());
809         if (!resultIsRelaxedEqual(cond))
[332]810                 {
811                 $1.counter=1;
812                 // no stack adjust - next tokens are processed in a different context
813                 trctx.out->printf("push 1\njump :_or_end_%d\n",c);
814                 }
815         else
816                 $1.counter=0;
817         }
818 else
819         {
820         trstack.adjust(+1); // stack for (a==false)
821         trctx.out->printf("if ~=,m[m0++],:_or_b_%d\n"
822                           "push 1\n"
823                           "jump :_or_end_%d\n"
824                           ":_or_b_%d\n"
825                           ,c,c,c);
826         }
827 }
828         expr
829 {
830 $$.ident=false;
831 $$.constant=0;
832 if ($4.constant)
833         {
834         if (!($1.constant && $1.counter==1))
835                 {
[333]836                 ExtValue::CompareResult cond=$4.compare(ExtValue::zero());
837                 bool value=!resultIsRelaxedEqual(cond);
[332]838                 trstack.adjust(-1);
839                 trctx.out->printf("push %d\n",value);
840                 }
841         }
842 trctx.out->printf(":_or_end_%d\n",$3.getInt());
843// trctx.out->printf("#################\n\n");
844 }
845
846
847       | expr LSHIFT expr { handleTwoArg($$,$1,$3,LSHIFT,"shift",0,0); }
848       | expr RSHIFT expr { handleTwoArg($$,$1,$3,RSHIFT,"shift",1,0); }
849       | expr EQUAL expr     { if (!handleCompare($$,$1,$3,ExtValue::CmpEQ,"==")) return 1; }
850       | expr NOT_EQUAL expr { if (!handleCompare($$,$1,$3,ExtValue::CmpNE,"!=")) return 1; }
851       | expr GEQUAL expr    { if (!handleCompare($$,$1,$3,ExtValue::CmpGE,">=")) return 1; }
852       | expr LEQUAL expr    { if (!handleCompare($$,$1,$3,ExtValue::CmpLE,"<=")) return 1; }
853       | expr '>' expr       { if (!handleCompare($$,$1,$3,ExtValue::CmpGT,">")) return 1; }
854       | expr '<' expr       { if (!handleCompare($$,$1,$3,ExtValue::CmpLT,"<")) return 1; }
855
[163]856       | '!' expr        {
[332]857                         trctx.emitLine(); $$.assign=$2.assign; $$.parens=0; $$.ident=0;
[163]858                         if ($2.constant)
[333]859                                 {$$.constant=1; ExtValue::CompareResult res=$2.compare(ExtValue((paInt)0)); $$.setInt(resultIsRelaxedEqual(res));}
[163]860                         else
[332]861                                {trctx.out->printf("setif ~=,s0,s0\n");}
[163]862                         }
863
864     | '-' expr %prec NEG {
[332]865                          trctx.emitLine(); $$.assign=$2.assign; $$.parens=0; $$.ident=0;
[163]866                          if ($2.constant)
867                                  { $$.constant=$2.constant;
868                                   if ($2.type==TInt) $$.setInt(-$2.getInt());
869                                   else if ($2.type==TDouble) $$.setDouble(-$2.getDouble());
870                                   else $$=$2;
871                                  }
872                             else
873                                  {
874                                  $$.constant=0; SString t="-"; t+=$2.getString(); $$.setString(t);
875                                  trctx.out->printf("mul -1,s0\n");
876                                  }
877                          }
878
[332]879     | '(' expr ')'    { trctx.emitLine(); $$ = $2; $$.assign=$2.assign?(!$2.parens):0; $$.parens=1; $$.ident=0; }
[163]880
881     | OBJNAME '.' member {
[332]882                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]883                        if ($3.constant)
884                                {
885                                trctx.out->printf("push %s.%s\n",str($1),str($3)); trstack.adjust(-1);
886                                }
887                        else
888                                {
889                                trctx.out->printf("move s0,m1\nmove %s.[m1],s0\n",str($1));
890                                }
891                        }
892
893     | OBJNAME '.' member assign_op expr
[332]894                  { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]895                  if ($3.constant)
896                          {
[348]897                          handleAssignOp2($$,t.c_str(),$5,assign_op_names[$4.getInt()],0,1);
[163]898                          }
899                  else
900                          {
901                          int sp=($5.constant)?0:1;
902                          t=$1.getString();t+=".[m1]";
903                          trctx.out->printf("move s0,m1\n",str($1));
[348]904                          handleAssignOp2($$,t.c_str(),$5,assign_op_names[$4.getInt()],sp,0);
[163]905                          if (sp) {trctx.out->printf("inc m0\n"); trstack.adjust(1);}
906                          }
907                  }
908
909     | plusminus OBJNAME '.' member {
[332]910                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$2.getString(); t+="."; t+=$4.getString(); $$.setString(t);
[163]911                        if ($4.constant)
912                                {
913                                trctx.out->printf("%s %s.%s\npush %s.%s\n",$1.getInt()?"inc":"dec",
914                                                  str($2),str($4),str($2),str($4));
915                                trstack.adjust(-1);
916                                }
917                        else
918                                {
919                                trctx.out->printf("move s0,m1\n%s %s.[m1]\nmove %s.[m1],s0\n",
920                                                  $1.getInt()?"inc":"dec",str($2),str($2));
921                                }
922                        }
923
924     | OBJNAME '.' member plusminus {
[332]925                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]926                        if ($3.constant)
927                                {
928                                trctx.out->printf("push %s.%s\n%s %s.%s\n",
929                                                  str($1),str($3),$4.getInt()?"inc":"dec",str($1),str($3));
930                                trstack.adjust(-1);
931                                }
932                        else
933                                {
934                                trctx.out->printf("move s0,m1\nmove %s.[m1],s0\n%s %s.[m1]\n",
935                                                  str($1),$4.getInt()?"inc":"dec",str($1));
936                                }
937                        }
938
939     | OBJNAME '.' '*'    {
[332]940                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".*"; $$.setString(t);
[163]941                        trctx.out->printf("push %s.*\n",str($1)); trstack.adjust(-1);
942                        }
943
944
945     | OBJNAME '.' member '=' expr {
[332]946                        trctx.emitLine(); $$=$5; $$.assign=1; $$.parens=0; $$.ident=0;
[163]947                        if ($3.constant)
948                                {
949                                if ($$.constant)
950                                        trctx.out->printf("move %s,%s.%s\n",litstr($5),str($1),str($3));
951                                else
952                                        trctx.out->printf("move s0,%s.%s\n",str($1),str($3));
953                                }
954                        else
955                                {
956                                if ($$.constant)
957                                        {
958                                        trctx.out->printf("move m[m0++],m1\nmove %s,%s.[m1]\n",
959                                                          litstr($5),str($1));
960                                        trstack.adjust(1);
961                                        }
962                                else
963                                        {
964                                        trctx.out->printf("move s1,m1\nmove m[m0++],s0\nmove s0,%s.[m1]\n",
965                                                          str($1));
966                                        trstack.adjust(1);
967                                        }
968                                }
969                        }
970
971     | OBJNAME '.' member '(' arguments ')'
972                        {
[332]973                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]974                        int adj=0,adj2=0;
975                        if ($5.getInt()==0)
976                                {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
977                        if ($3.constant)
978                                trctx.out->printf("call %s.%s\n",str($1),str($3));
979                        else
980                                {
981                                trctx.out->printf("move s%d,m1\ncall %s.[m1]\n",$5.getInt()+adj,str($1));
982                                adj2=1;
983                                }
984                        adj2+=$5.getInt()-1+adj;
985                        if (adj2>0)
986                                {
987                                trctx.out->printf("add %d,m0\nxmove s%d,s0\n",adj2,-adj2);
988                                trstack.adjust(adj2);
989                                }
990                        }
991
992     | CALL expr '(' arguments ')'
[332]993             { trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString($2.getString());
[163]994             short adj=0;
995             if ($4.getInt()==0)
996                     {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
997             if ($2.constant)
998                     trctx.out->printf("call %s\n",litstr($2));
999             else
1000                     trctx.out->printf("call s%d\n",$4.getInt()+adj);
1001             if (($4.getInt()+adj) > 0)
1002                     {
1003                     trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$4.getInt()+adj,-($4.getInt()+adj));
1004                     trstack.adjust($4.getInt()+adj);
1005                     }
1006             }
1007
1008     | FUNCTION IDENT
[332]1009             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=":"; t+=$1.getString(); $$.setString(t);
[348]1010             trctx.out->printf("push :%s\n",$2.getString().c_str());
[163]1011             trstack.adjust(-1);
1012             }
1013
[341]1014     | stackexpr '.' member
[332]1015             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]1016             if ($3.constant)
1017                     trctx.out->printf("move s0,m1\nmove [m1].%s,s0\n",str($3));
1018             else
1019//                   trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
1020                     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");trstack.adjust(1);}
1021             }
1022
[341]1023     | plusminus stackexpr '.' member
[332]1024             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$2.getString(); t+="."; t+=$4.getString(); $$.setString(t);
[163]1025             if ($4.constant)
1026                     trctx.out->printf("move s0,m1\n%s [m1].%s\nmove [m1].%s,s0\n",
1027                                       $1.getInt()?"inc":"dec",str($4),str($4));
1028             else
1029//                   trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
1030                     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\n%s [m1].[m2]\nmove [m1].[m2],s0\n",
1031                                        $1.getInt()?"inc":"dec");trstack.adjust(1);}
1032             }
1033
[341]1034     | stackexpr '.' member plusminus
[332]1035             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]1036             if ($3.constant)
1037                     trctx.out->printf("move s0,m1\nmove [m1].%s,s0\n%s [m1].%s\n",
1038                                       str($3),$4.getInt()?"inc":"dec",str($3));
1039             else
1040//                   trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
1041                     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n%s [m1].[m2]\n",
1042                                        $4.getInt()?"inc":"dec");trstack.adjust(1);}
1043             }
1044
[341]1045     | stackexpr '.' member assign_op expr
[332]1046             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]1047             if ($3.constant)
1048                     {
1049                     int sp;
1050                     if ($5.constant)
1051                             {sp=0; trctx.out->printf("move s0,m1\n");}
1052                     else
1053                             {sp=1; trctx.out->printf("move s1,m1\n");}
1054                     t="[m1]."; t+=str($3);
[348]1055                     handleAssignOp2($$,t.c_str(),$5,assign_op_names[$4.getInt()],sp,0);
[163]1056                     if (sp) {trctx.out->printf("inc m0\n");trstack.adjust(1);}
1057                     }
1058             else
1059                     {
1060                     int sp;
1061                     char *t;
1062                     if ($5.constant)
1063                             {sp=1; t="move s1,m1\nmove s0,m2\n";}
1064                     else
1065                             {sp=2; t="move s2,m1\nmove s1,m2\n";}
1066                     trctx.out->printf(t);
1067                     handleAssignOp2($$,"[m1].[m2]",$5,assign_op_names[$4.getInt()],sp,0);
1068                     trctx.out->printf("add %d,m0\n",sp);
1069                     trstack.adjust(sp);
1070                     }
1071             }
1072
[341]1073     | stackexpr '.' member '=' stackexpr
[332]1074             { trctx.emitLine(); $$=$5; $$.assign=1; $$.parens=0; $$.ident=0;
[163]1075             if ($3.constant)
1076                     {
1077                     trctx.out->printf("move s1,m1\nmove m[m0++],s0\nmove s0,[m1].%s\n",str($3));
1078                     trstack.adjust(1);
1079                     }
1080             else
1081                     {
1082                     trctx.out->printf("move s2,m1\nmove s1,m2\nmove s0,[m1].[m2]\nadd 2,m0\nmove s-2,s0\n");
1083                     trstack.adjust(2);
1084                     }
1085             }
1086
[341]1087     | stackexpr '.' member '(' arguments ')'
[332]1088             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]1089             int adj=0;
1090             if ($5.getInt()==0)
1091                     {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
1092             if ($3.constant)
1093                     {
1094                     trctx.out->printf("move s%d,m1\ncall [m1].%s\n",$5.getInt()+adj,str($3));
1095                     adj+=1;
1096                     }
1097             else
1098                     {
1099                     trctx.out->printf("move s%d,m2\nmove s%d,m1\ncall [m2].[m1]\n",
1100                                       $5.getInt()+adj+1,$5.getInt()+adj);
1101                     adj+=2;
1102                     }
1103             if (($5.getInt()+adj) > 1)
1104                     {
1105                     trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$5.getInt()-1+adj,-($5.getInt()-1+adj));
1106                     trstack.adjust($5.getInt()-1+adj);
1107                     }
1108             }
1109
[341]1110      | stackexpr '[' expr ']' '=' expr    // shortcut: expr.set(expr,expr)
[332]1111             { trctx.emitLine(); $$=$6; $$.assign=1; $$.parens=0; $$.ident=0;
[163]1112             if ($3.constant)
1113                     {
1114                     if ($6.constant)
1115                             {trctx.out->printf("move s0,m1\ncall [m1].\"set\",%s,%s\ninc m0\n",litstr($3),litstr($6));$$=$6;trstack.adjust(+1);}
1116                     else
1117                             {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);}
1118                     }
1119             else
1120                     {
1121                     if ($6.constant)
1122                             {trctx.out->printf("move s1,m1\npush %s\ncall [m1].\"set\"\nadd 3,m0\n",litstr($6)); trstack.adjust(+2);}
1123                     else
1124                             {trctx.out->printf("move s2,m1\ncall [m1].\"set\"\nadd 2,m0\nmove s-2,s0\n"); trstack.adjust(+2);}
1125                     }
1126             }
1127
[341]1128      | stackexpr '[' expr ']'    /* shortcut: expr.get(expr) */
[332]1129             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".get"; $$.setString(t);
[163]1130             if ($3.constant)
1131                     {
1132                     trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n",litstr($3));
1133                     }
1134             else
1135                     {
1136                     trctx.out->printf("move s1,m1\ncall [m1].\"get\"\ninc m0\nmove s-1,s0\n");
1137                     trstack.adjust(+1);
1138                     }
1139             }
1140
[332]1141     | IDENT '=' expr { trctx.emitLine(); $$=$3; $$.assign=1; $$.ident=0;
[163]1142                        int loc=trstack.getVariableLocation($1.getString());
1143                        if (loc!=TranslatorStack::NOTFOUND)
1144                            {
1145                            if ($3.constant)
1146                              trctx.out->printf("move %s,s%d\n",litstr($3),loc-trstack.currentPos());
1147                            else
1148                              trctx.out->printf("move s0,s%d\n",loc-trstack.currentPos());
1149                            }
1150                        else if (globalOk($1)) { $$=$3; $$.ident=0; $$.assign=1;
1151                          if ($3.constant) trctx.out->printf("move %s,@%s\n",litstr($3),str($1));
1152                          else trctx.out->printf("move s0,@%s\n",str($1));}
[245]1153                        else {trctx.err->printf("undefined variable: '%s'\n",str($1)); return 1;}
[163]1154                      }
1155
1156      | OBJNAME '[' expr ']'    /* shortcut: OBJNAME.get(expr) */
[332]1157             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".get"; $$.setString(t);
[163]1158             if ($3.constant)
1159                     {
1160                     trctx.out->printf("dec m0\ncall %s.get,%s\n",str($1),litstr($3));
1161                     trstack.adjust(-1);
1162                     }
1163             else
1164                     {
1165                     trctx.out->printf("call %s.get\n",str($1));
1166                     }
1167             }
1168
1169      | IDENT '(' arguments ')'
1170{
[332]1171trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString("function call");
[163]1172if ($3.getInt()==0)
1173        {trctx.out->printf("dec m0\n");trstack.adjust(-1);}
1174trctx.out->printf("call :%s\n",str($1));
1175if ($3.getInt()>1)
1176        {
1177        trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$3.getInt()-1,-($3.getInt()-1));
1178        trstack.adjust($3.getInt()-1);
1179        }
1180}
1181
[332]1182| '[' {trctx.emitLine(); $$.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)
[163]1183        v_elements ']'
1184        {$$.constant=0; trctx.out->printf("inc m0\n");trstack.adjust(1);}
1185
[332]1186| '{' {trctx.emitLine(); $$.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)
[163]1187        d_elements '}'
1188        {$$.constant=0; trctx.out->printf("inc m0\n"); trstack.adjust(1);}
1189
1190//      | '&' stackexpr {trctx.out->printf("call Ref.new\n");}
1191
1192      | '&' IDENT {
[332]1193        trctx.emitLine(); $$.ident=0;
[163]1194        int loc=trstack.getVariableLocation($2.getString());
1195        if (loc!=TranslatorStack::NOTFOUND)
1196                {
[247]1197                trctx.out->printf("push &%d\n",loc-trstack.currentPos());trstack.adjust(-1);
[163]1198                }
1199        else if (globalOk($2))
1200                {
1201                trctx.out->printf("gpush &@%s\ncall Ref.newO\ninc m0\nmove s-1,s0\n",str($2));
1202                trstack.adjust(-1);
1203                }
[245]1204        else {trctx.err->printf("undefined variable: '%s'\n",str($1)); return 1;}
[163]1205            }
1206
1207      | '&' OBJNAME '.' member {
[332]1208      trctx.emitLine(); $$.ident=0;
[163]1209      if ($4.constant)
1210              {
1211              trctx.out->printf("dec m0\ncall Ref.newO,%s.*,%s:%s\n",str($2),str($2),str($4));
1212              trstack.adjust(-1);
1213              }
1214      else
1215              {
1216              trctx.out->printf("call Ref.newO,%s.*,s0\n",str($2));
1217              }
1218      }
1219
1220      | '&' '(' stackexpr ')' '.' member {
[332]1221      trctx.emitLine(); $$.ident=0;
[163]1222      if ($6.constant)
1223              {
1224              trctx.out->printf("call Ref.newO,s0,%s\n",litstr($6));
1225              }
1226      else
1227              {
1228              trctx.out->printf("call Ref.newO,s1,s0\ninc m0\nmove s-1,s0\n");
1229              trstack.adjust(1);
1230              }
1231      }
1232
1233      | '(' stackexpr ',' stackexpr ',' stackexpr ')' {
[332]1234      trctx.emitLine(); $$.ident=0;
[163]1235      trctx.out->printf("call XYZ.new\nadd 2,m0\nmove s-2,s0\n");trstack.adjust(2);}
1236;
1237
1238v_elements: /* empty */
1239      | v_element
1240      | v_elements ',' v_element
1241;
1242
1243d_elements: /* empty */
1244      | d_element
1245      | d_elements ',' d_element
1246;
1247
1248v_element: expr
1249{
1250if ($1.constant)
1251        trctx.out->printf("move s1,m1\ncall [m1].Vector:add,%s\n",litstr($1));
1252else
1253        {trctx.out->printf("move s2,m1\ncall [m1].Vector:add\ninc m0\n");trstack.adjust(1);}
1254}
1255;
1256
1257d_element: expr ':' expr
1258{
1259if ($1.constant)
1260        {
1261        if ($3.constant)
1262                trctx.out->printf("move s1,m1\ncall [m1].Dictionary:set,%s,%s\n",litstr($1),litstr($3));
1263        else
1264                {trctx.out->printf("move s2,m1\nmove %s,s1\ncall [m1].Dictionary:set\ninc m0\n",litstr($1));trstack.adjust(1);}
1265        }
1266else
1267        {
1268        if ($3.constant)
1269                {trctx.out->printf("move s2,m1\nmove s0,s1\nmove %s,s0\ncall [m1].Dictionary:set\ninc m0\n",litstr($3));trstack.adjust(1);}
1270        else
1271                {trctx.out->printf("move s3,m1\ncall [m1].Dictionary:set\nadd 2,m0\n");trstack.adjust(2);}
1272        }
1273}
1274;
1275
1276member:    IDENT { $$=$1; $$.constant=1;}
1277         | OBJNAME ':' IDENT { SString t=$1.getString();t+=":";t+=$3.getString();
1278                               $$.setString(t);$$.constant=1;}
1279         | '[' stackexpr ']' { SString t="["; t+=$2.getString(); t+="]";
1280                               $$.setString(t); $$.constant=0;}
1281
1282arguments: /* empty */         { $$.setInt(0); }
1283         |  stackexpr               { $$.setInt(1); }
1284         |  arguments ',' stackexpr  {$$.setInt($1.getInt()+1);}
1285;
1286
1287%%
1288
1289SString makeLitString(const ExtValue& val)
1290{
1291if (val.type!=TString)
1292        return val.getString();
1293SString s=val.getString();
1294int len=s.len();
1295SString ret((len*11)/10+10);
1296ret+='\"';
[348]1297const char*t=s.c_str();
[163]1298while(len>0)
1299        {
1300        switch(*t)
1301                {
1302                case '\n': ret+="\\n"; break;
1303                case '\r': ret+="\\r"; break;
1304                case '\t': ret+="\\t"; break;
1305                default: ret+=*t;
1306                }
1307        t++; len--;
1308        }
1309ret+='\"';
1310return ret;
1311}
1312
1313static void yyprint (FILE *file,int type,YYSTYPE value)
1314{
1315fprintf(file,"(%s)%s",str(value),value.constant?"c":"");
1316}
1317
1318int yyerror (const char *s)  /* Called by yyparse on error */
1319{
1320trctx.err->printf ("%s\n",s);
1321return 0; // w przykladach do bisona tez nie dali returna...
1322}
1323
1324void handleTwoArg(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,
[332]1325                  int optoken,const char* opname,bool negarg2,bool uniq)
[163]1326{
[332]1327trctx.emitLine();
[163]1328result.ident=false;
1329if (arg1.constant && arg2.constant)
1330        {
1331        result=arg1;
1332        switch(optoken)
1333                {
1334                case '+': result+=arg2; break;
1335                case '-': result-=arg2; break;
1336                case '*': result*=arg2; break;
1337                case '/': result/=arg2; break;
1338                case '%': result%=arg2; break;
1339                case '&': result.setInt(arg1.getInt() & arg2.getInt()); break;
1340                case '|': result.setInt(arg1.getInt() | arg2.getInt()); break;
1341                case LSHIFT: result.setInt(arg1.getInt() << arg2.getInt()); break;
1342                case RSHIFT: result.setInt(arg1.getInt() >> arg2.getInt()); break;
1343                }
1344        }
1345else
1346        {
1347        //TODO: prawie kazde uzycie uniq jest niepotrzebne bo typem rzadko bedzie vector, ale w wiekszosci miejsc okreslenie typu wartosci
1348        // byloby bardzo trudne lub niemozliwe. mozna byloby natomiast zapamietywac przy parsowaniu czy dana wartosc na stosie jest
1349        // skopiowana ze zmiennej/pola czy jest wynikiem wczesniejszej operacji co pozwoliloby na likwidacje bardzo wielu uniq
1350        result.constant=0;
1351        result.assign=arg1.assign || arg2.assign;
1352        result.parens=0;
1353        result.setString(opname);
1354        if (arg1.constant)
[332]1355                trctx.out->printf("move %s,m1\n%s%s s0,m1\nmove m1,s0\n",litstr(arg1),
[163]1356                                  negarg2?"neg s0\n":"",
1357                                  opname);
1358        else if (arg2.constant)
1359                {
[332]1360                if (negarg2)
1361                        trctx.out->printf("%s %d,s0\n",opname,-arg2.getInt());
[163]1362                else
[332]1363                        trctx.out->printf("%s%s %s,s0\n",(uniq?"uniq s0\n":""),opname,litstr(arg2));
[163]1364                }
1365        else
1366                {
1367                trctx.out->printf("%s%s%s s0,s1\ninc m0\n",
[332]1368                                  uniq?"uniq s1\n":"",
[163]1369                                  negarg2?"neg s0\n":"",
1370                                  opname);
1371                trstack.adjust(+1);
1372                }
1373        }
1374}
1375
1376bool handleAssignOp(YYSTYPE& result,const YYSTYPE& var,const YYSTYPE& arg,const char* opname)
1377{
1378int loc; if (variableOk(result,var,loc))
1379        {
1380        loc-=trstack.currentPos();
1381        if (arg.constant)
1382                {
1383                trctx.out->printf("%s %s,s%d\npush s%d\n",opname,litstr(arg),loc,loc);
1384                trstack.adjust(-1);
1385                }
1386        else
1387                trctx.out->printf("%s s0,s%d\nmove s%d,s0\n",opname,loc,loc);
1388        return 1;
1389        }
1390return 0;
1391}
1392
1393bool handleAssignOp2(YYSTYPE& result,const char *var,const YYSTYPE& arg,const char* opname,int stackpos,bool push)
1394{
1395if (arg.constant)
1396        {
1397        trctx.out->printf("%s %s,%s\n",opname,litstr(arg),var);
1398        if (!push)
1399                trctx.out->printf("move %s,s%d\n",var,stackpos);
1400        else
1401                {
1402                trctx.out->printf("push %s\n",var);
1403                trstack.adjust(-1);
1404                }
1405        }
1406else
1407        trctx.out->printf("%s s0,%s\nmove %s,s%d\n",opname,var,var,stackpos);
1408return 1;
1409}
1410
[332]1411bool handleCompare(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,ExtValue::CmpOperator op,const char* opname)
1412{
1413trctx.emitLine();
[163]1414result.ident=0;
1415if (arg1.constant && arg2.constant)
1416        {
1417        result.constant=1;
[333]1418        ExtValue::CompareResult cmp=arg1.compare(arg2);
[332]1419        ExtValue::CmpContext context;
1420        context.v1=&arg1;
1421        context.v2=&arg2;
1422        int ret=ExtValue::interpretCompare(op,cmp,&context);
1423        if (ret<0)
1424                result.setEmpty();//return false;
1425        else
1426                result.setInt(ret);
1427        return true;
[163]1428        }
1429else
1430        {
1431        result.constant=0;
1432        result.assign=arg1.assign || arg2.assign;
1433        result.parens=0;
1434        result.setString(opname);
1435        if (arg1.constant)
1436                trctx.out->printf("setif %s,%s,s0,s0\n",litstr(arg1),opname);
1437        else if (arg2.constant)
1438                trctx.out->printf("setif s0,%s,%s,s0\n",opname,litstr(arg2));
1439        else
1440                {
1441                trctx.out->printf("setif s1,%s,s0,s1\ninc m0\n",opname);
1442                trstack.adjust(+1);
1443                }
[332]1444        return true;
[163]1445        }
1446}
1447
[333]1448static bool resultIsRelaxedEqual(ExtValue::CompareResult res)
1449{
1450return (res==ExtValue::ResultEqual)||(res==ExtValue::ResultEqualUnordered)||(res==ExtValue::ResultUnequal_RelaxedEqual);
1451}
1452
[163]1453bool variableOk(TokenValue &tok, const TokenValue& var,int &loc)
1454{
1455loc=trstack.getVariableLocation(var.getString());
1456if (loc != TranslatorStack::NOTFOUND)
1457        {tok.setInt(loc); tok.constant=0;
1458        return 1;}
1459return 0;
1460}
1461
1462bool globalOk(const TokenValue& var)
1463{
1464SymTabEntry* found=trstack.globals.find(var.getString());
1465if (found) return true;
[348]1466return framscriptIsGlobalName(var.getString().c_str());
[163]1467}
1468
1469void badVariable(TokenValue &tok, const TokenValue& var)
1470{
1471tok=var; tok.constant=1;
1472trctx.err->printf("undefined variable '%s'\n",str(var));
1473}
1474
1475bool doBreak(int level)
1476{
1477if (trstack.loops.size()<level)
[245]1478        {trctx.err->printf("invalid 'break'\n"); return 0;}
[163]1479LoopInfo* li=trstack.loops.getLoop(level-1);
1480if (li->location != trstack.currentPos())
1481        trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
1482trctx.out->printf("jump :_loop_end_%d\n",li->id);
1483return 1;
1484}
1485
1486bool doContinue(int level)
1487{
1488if (trstack.loops.size()<level)
[245]1489        {trctx.err->printf("invalid 'continue'\n"); return 0;}
[163]1490LoopInfo* li=trstack.loops.getLoop(level-1);
1491if (li->location != trstack.currentPos())
1492        trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
1493trctx.out->printf("jump :_loop_%d\n",li->id);
1494return 1;
1495}
1496
1497int lookupToken(char *s)
1498{
1499int len=strlen(s);
1500int i;
1501const char *t;
1502for (i = 0; i < YYNTOKENS; i++)
1503        {
1504        t=yytname[i];
1505        if (t && (t[0]=='"')
1506           && (!strncmp(t+1,s,len))
1507           && (t[len+1]=='"')
1508           && (t[len+2] == 0))
1509                return yytoknum[i];
1510        }
1511return -1;
1512}
1513
1514void warnTruthValue(const TokenValue& t)
1515{
1516if (t.assign && (!t.parens))
[375]1517        logPrintf("FramScriptCompiler","translate",LOG_WARN,"Assignment used as truth value, use ((double parens)) if you really mean it");
[163]1518}
1519
1520void outFunName(const TokenValue& t)
1521{
1522if (trctx.functiontmplabel<0)
1523        {
1524        trctx.functiontmplabel=trctx.labelcounter++;
1525        trctx.out->printf("jump :_skipfun_%d\n",trctx.functiontmplabel);
1526        }
1527trctx.out->printf(":%s\n",str(t));
1528}
1529
1530bool evalVariable(TokenValue &tok,const TokenValue &var)
1531{
1532int loc;
1533if (variableOk(tok,var,loc))
1534        {
1535        trctx.out->printf("push s%d\n",loc-trstack.currentPos());
1536        trstack.adjust(-1);
1537        return true;
1538        }
1539else if (globalOk(var))
1540        {
[348]1541        trctx.out->printf("push @%s\n",var.getString().c_str());
[163]1542        trstack.adjust(-1);
1543        return true;
1544        }
1545else
1546        {
1547        badVariable(tok,var); return false;
1548        }
1549}
Note: See TracBrowser for help on using the repository browser.