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

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