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

Last change on this file since 333 was 333, checked in by Maciej Komosinski, 9 years ago
  • use source/code mapping for line number and file information in vm error messages
  • enum ExtValue::CompareResult? instead of int
  • Property svn:eol-style set to native
File size: 44.4 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"
7#include "common/framsg.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,
[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
[332]147trctx.out->printf("jump :%s\n",str($2)); FMprintf("FramScriptCompiler","translate",FMLV_WARN,"goto is not recommended (%s line %d)",(const char*)trctx.srcname,trctx.line); 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)
469                   trctx.out->printf("move %s.iterator,m[--m0]\n",(const char*)$4.getString());
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                   }
528           trctx.tmp=0;
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();
537           $$.setString(trctx.tmp);
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
650expr_or_empty:
651         expr {$$=$1;}
652
653         | //nic
654         { $$.setInt(1); $$.assign=false; $$.constant=true; $$.ident=false; $$.ident=false; }
655;
656
657expr_special_ident:    CONSTANT             { $$=$1; $$.constant=1; $$.ident=0; }
658
659       | IDENT                { $$.ident=true; $$.setString($1.getString()); }
660
661       | OBJNAME ':' IDENT    {$$.constant=0; $$.ident=0;
662                              trctx.out->printf("push %s:%s\n",(const char*)$1.getString(),
663                                                 (const char*)$3.getString());
664                              trstack.adjust(-1);
665                              }
666       | plusminus IDENT
667{
[332]668trctx.emitLine();
[163]669$$.ident=0;
670int loc; if (variableOk($$,$2,loc))
671        { loc-=trstack.currentPos();
672        trctx.out->printf("%s s%d\npush s%d\n",$1.getInt()?"inc":"dec",loc,loc);
673        trstack.adjust(-1);}
674        else if (globalOk($2))
675        { trctx.out->printf("%s @%s\npush @%s\n",$1.getInt()?"inc":"dec",str($2),str($2));
676        trstack.adjust(-1);}
677        else {badVariable($$,$2); return 1;}
678}
679
680       | IDENT plusminus
681{
[332]682trctx.emitLine();
[163]683$$.ident=0;
684int loc; if (variableOk($$,$1,loc))
685        {loc-=trstack.currentPos(); trctx.out->printf("push s%d\n%s s%d\n",loc,$2.getInt()?"inc":"dec",loc+1);
686        trstack.adjust(-1);}
687        else if (globalOk($1))
688        { trctx.out->printf("push @%s\n%s @%s\n",(const char*)$1.getString(),
689                            $2.getInt()?"inc":"dec",(const char*)$1.getString());
690        trstack.adjust(-1);}
691        else {badVariable($$,$1); return 1;}
692}
693
[332]694       | IDENT assign_op expr { trctx.emitLine(); $$.ident=0;
[163]695                                if (!handleAssignOp($$,$1,$3,assign_op_names[$2.getInt()]))
696                                if (globalOk($1)) {SString t="@"; t+=$1.getString();
697                                  handleAssignOp2($$,(const char*)t,$3,assign_op_names[$2.getInt()],0,1);}
698                                else { badVariable($$,$1); return 1; }
699                              }
700
[332]701       | TYPEOF '(' expr ')' { trctx.emitLine(); $$.ident=0;
702                       if ($3.constant)
703                             {$$.constant=1; $$=$3.getExtType();}
[163]704                       else
705                             {trctx.out->printf("type s0,s0\n");}
706                     }
[333]707       | INT_TYPE '(' expr ')' { trctx.emitLine(); $$.ident=0;
[332]708                       if ($3.constant)
709                             {$$.constant=1; $$=ExtValue($3.getInt());}
710                       else
711                             {trctx.out->printf("conv 1,s0\n");}
712                     }
[333]713       | FLOAT_TYPE '(' expr ')' { trctx.emitLine(); $$.ident=0;
[332]714                       if ($3.constant)
715                             {$$.constant=1; $$=ExtValue($3.getDouble());}
716                       else
717                             {trctx.out->printf("conv 2,s0\n");}
718                     }
[333]719       | STRING_TYPE '(' expr ')' { trctx.emitLine(); $$.ident=0;
[332]720                       if ($3.constant)
721                             {$$.constant=1; $$=ExtValue($3.getString());}
722                       else
723                             {trctx.out->printf("conv 3,s0\n");}
724                     }
[163]725
[332]726       | expr '+' expr { handleTwoArg($$,$1,$3,'+',"add",0,1); }
727       | expr '-' expr { handleTwoArg($$,$1,$3,'-',"sub",0,0); }
728       | expr '*' expr { handleTwoArg($$,$1,$3,'*',"mul",0,1); }
729       | expr '/' expr { handleTwoArg($$,$1,$3,'/',"div",0,0); }
730       | expr '&' expr { handleTwoArg($$,$1,$3,'&',"and",0,0); }
731       | expr '|' expr { handleTwoArg($$,$1,$3,'|',"or",0,0); }
732       | expr '%' expr { handleTwoArg($$,$1,$3,'%',"mod",0,0); }
[163]733
[332]734       | expr LOGIC_AND
735 {
736 // a && b:
737 //   push a
738 //   if (a)
739 //     pop; goto and_b
740 //   else
741 //     pop; push 0; goto and_end
742 // and_b:
743 //   push b
744 // and_end:
745 trctx.emitLine();
746// trctx.out->printf("\n####### logic AND\n");
747 int c=trctx.labelcounter++;
748 $$.setInt(c);
749 if ($1.constant)
750         {
[333]751         ExtValue::CompareResult cond=$1.compare(ExtValue::zero());
752         if (resultIsRelaxedEqual(cond))
[332]753                 {
754                 $1.counter=0;
755                 // no stack adjust - next tokens are processed in a different context
756                 trctx.out->printf("push 0\njump :_and_end_%d\n",c);
757                 }
758         else
759                 $1.counter=1;
760         }
761 else
762         {
763         trstack.adjust(+1); // stack as if (a==true), b expr is processed
764         trctx.out->printf("if !~,m[m0++],:_and_b_%d\n"
765                           "push 0\n"
766                           "jump :_and_end_%d\n"
767                           ":_and_b_%d\n"
768                           ,c,c,c);
769         }
770 }
771         expr
772 {
773 $$.ident=false;
774 $$.constant=0;
775 if ($4.constant)
776         {
777         if (!($1.constant && $1.counter==0))
778                 {
[333]779                 ExtValue::CompareResult  cond=$4.compare(ExtValue::zero());
780                 bool value=!resultIsRelaxedEqual(cond);
[332]781                 trstack.adjust(-1);
782                 trctx.out->printf("push %d\n",value);
783                 }
784         }
785 trctx.out->printf(":_and_end_%d\n",$3.getInt());
786// trctx.out->printf("#################\n\n");
787 }
788
789       | expr LOGIC_OR
790 {
791 // a || b:
792 //   push a
793 //   if (!a)
794 //     pop; goto and_b
795 //   else
796 //     pop; push 1; goto and_end
797 // and_b:
798 //   push b
799 // and_end:
800 trctx.emitLine();
801// trctx.out->printf("\n####### logic AND\n");
802 int c=trctx.labelcounter++;
803 $$.setInt(c);
804 if ($1.constant)
805         {
[333]806         ExtValue::CompareResult  cond=$1.compare(ExtValue::zero());
807         if (!resultIsRelaxedEqual(cond))
[332]808                 {
809                 $1.counter=1;
810                 // no stack adjust - next tokens are processed in a different context
811                 trctx.out->printf("push 1\njump :_or_end_%d\n",c);
812                 }
813         else
814                 $1.counter=0;
815         }
816 else
817         {
818         trstack.adjust(+1); // stack for (a==false)
819         trctx.out->printf("if ~=,m[m0++],:_or_b_%d\n"
820                           "push 1\n"
821                           "jump :_or_end_%d\n"
822                           ":_or_b_%d\n"
823                           ,c,c,c);
824         }
825 }
826         expr
827 {
828 $$.ident=false;
829 $$.constant=0;
830 if ($4.constant)
831         {
832         if (!($1.constant && $1.counter==1))
833                 {
[333]834                 ExtValue::CompareResult cond=$4.compare(ExtValue::zero());
835                 bool value=!resultIsRelaxedEqual(cond);
[332]836                 trstack.adjust(-1);
837                 trctx.out->printf("push %d\n",value);
838                 }
839         }
840 trctx.out->printf(":_or_end_%d\n",$3.getInt());
841// trctx.out->printf("#################\n\n");
842 }
843
844
845       | expr LSHIFT expr { handleTwoArg($$,$1,$3,LSHIFT,"shift",0,0); }
846       | expr RSHIFT expr { handleTwoArg($$,$1,$3,RSHIFT,"shift",1,0); }
847       | expr EQUAL expr     { if (!handleCompare($$,$1,$3,ExtValue::CmpEQ,"==")) return 1; }
848       | expr NOT_EQUAL expr { if (!handleCompare($$,$1,$3,ExtValue::CmpNE,"!=")) return 1; }
849       | expr GEQUAL expr    { if (!handleCompare($$,$1,$3,ExtValue::CmpGE,">=")) return 1; }
850       | expr LEQUAL expr    { if (!handleCompare($$,$1,$3,ExtValue::CmpLE,"<=")) return 1; }
851       | expr '>' expr       { if (!handleCompare($$,$1,$3,ExtValue::CmpGT,">")) return 1; }
852       | expr '<' expr       { if (!handleCompare($$,$1,$3,ExtValue::CmpLT,"<")) return 1; }
853
[163]854       | '!' expr        {
[332]855                         trctx.emitLine(); $$.assign=$2.assign; $$.parens=0; $$.ident=0;
[163]856                         if ($2.constant)
[333]857                                 {$$.constant=1; ExtValue::CompareResult res=$2.compare(ExtValue((paInt)0)); $$.setInt(resultIsRelaxedEqual(res));}
[163]858                         else
[332]859                                {trctx.out->printf("setif ~=,s0,s0\n");}
[163]860                         }
861
862     | '-' expr %prec NEG {
[332]863                          trctx.emitLine(); $$.assign=$2.assign; $$.parens=0; $$.ident=0;
[163]864                          if ($2.constant)
865                                  { $$.constant=$2.constant;
866                                   if ($2.type==TInt) $$.setInt(-$2.getInt());
867                                   else if ($2.type==TDouble) $$.setDouble(-$2.getDouble());
868                                   else $$=$2;
869                                  }
870                             else
871                                  {
872                                  $$.constant=0; SString t="-"; t+=$2.getString(); $$.setString(t);
873                                  trctx.out->printf("mul -1,s0\n");
874                                  }
875                          }
876
[332]877     | '(' expr ')'    { trctx.emitLine(); $$ = $2; $$.assign=$2.assign?(!$2.parens):0; $$.parens=1; $$.ident=0; }
[163]878
879     | OBJNAME '.' member {
[332]880                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]881                        if ($3.constant)
882                                {
883                                trctx.out->printf("push %s.%s\n",str($1),str($3)); trstack.adjust(-1);
884                                }
885                        else
886                                {
887                                trctx.out->printf("move s0,m1\nmove %s.[m1],s0\n",str($1));
888                                }
889                        }
890
891     | OBJNAME '.' member assign_op expr
[332]892                  { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]893                  if ($3.constant)
894                          {
895                          handleAssignOp2($$,(const char*)t,$5,assign_op_names[$4.getInt()],0,1);
896                          }
897                  else
898                          {
899                          int sp=($5.constant)?0:1;
900                          t=$1.getString();t+=".[m1]";
901                          trctx.out->printf("move s0,m1\n",str($1));
902                          handleAssignOp2($$,(const char*)t,$5,assign_op_names[$4.getInt()],sp,0);
903                          if (sp) {trctx.out->printf("inc m0\n"); trstack.adjust(1);}
904                          }
905                  }
906
907     | plusminus OBJNAME '.' member {
[332]908                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$2.getString(); t+="."; t+=$4.getString(); $$.setString(t);
[163]909                        if ($4.constant)
910                                {
911                                trctx.out->printf("%s %s.%s\npush %s.%s\n",$1.getInt()?"inc":"dec",
912                                                  str($2),str($4),str($2),str($4));
913                                trstack.adjust(-1);
914                                }
915                        else
916                                {
917                                trctx.out->printf("move s0,m1\n%s %s.[m1]\nmove %s.[m1],s0\n",
918                                                  $1.getInt()?"inc":"dec",str($2),str($2));
919                                }
920                        }
921
922     | OBJNAME '.' member plusminus {
[332]923                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]924                        if ($3.constant)
925                                {
926                                trctx.out->printf("push %s.%s\n%s %s.%s\n",
927                                                  str($1),str($3),$4.getInt()?"inc":"dec",str($1),str($3));
928                                trstack.adjust(-1);
929                                }
930                        else
931                                {
932                                trctx.out->printf("move s0,m1\nmove %s.[m1],s0\n%s %s.[m1]\n",
933                                                  str($1),$4.getInt()?"inc":"dec",str($1));
934                                }
935                        }
936
937     | OBJNAME '.' '*'    {
[332]938                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".*"; $$.setString(t);
[163]939                        trctx.out->printf("push %s.*\n",str($1)); trstack.adjust(-1);
940                        }
941
942
943     | OBJNAME '.' member '=' expr {
[332]944                        trctx.emitLine(); $$=$5; $$.assign=1; $$.parens=0; $$.ident=0;
[163]945                        if ($3.constant)
946                                {
947                                if ($$.constant)
948                                        trctx.out->printf("move %s,%s.%s\n",litstr($5),str($1),str($3));
949                                else
950                                        trctx.out->printf("move s0,%s.%s\n",str($1),str($3));
951                                }
952                        else
953                                {
954                                if ($$.constant)
955                                        {
956                                        trctx.out->printf("move m[m0++],m1\nmove %s,%s.[m1]\n",
957                                                          litstr($5),str($1));
958                                        trstack.adjust(1);
959                                        }
960                                else
961                                        {
962                                        trctx.out->printf("move s1,m1\nmove m[m0++],s0\nmove s0,%s.[m1]\n",
963                                                          str($1));
964                                        trstack.adjust(1);
965                                        }
966                                }
967                        }
968
969     | OBJNAME '.' member '(' arguments ')'
970                        {
[332]971                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]972                        int adj=0,adj2=0;
973                        if ($5.getInt()==0)
974                                {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
975                        if ($3.constant)
976                                trctx.out->printf("call %s.%s\n",str($1),str($3));
977                        else
978                                {
979                                trctx.out->printf("move s%d,m1\ncall %s.[m1]\n",$5.getInt()+adj,str($1));
980                                adj2=1;
981                                }
982                        adj2+=$5.getInt()-1+adj;
983                        if (adj2>0)
984                                {
985                                trctx.out->printf("add %d,m0\nxmove s%d,s0\n",adj2,-adj2);
986                                trstack.adjust(adj2);
987                                }
988                        }
989
990     | CALL expr '(' arguments ')'
[332]991             { trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString($2.getString());
[163]992             short adj=0;
993             if ($4.getInt()==0)
994                     {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
995             if ($2.constant)
996                     trctx.out->printf("call %s\n",litstr($2));
997             else
998                     trctx.out->printf("call s%d\n",$4.getInt()+adj);
999             if (($4.getInt()+adj) > 0)
1000                     {
1001                     trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$4.getInt()+adj,-($4.getInt()+adj));
1002                     trstack.adjust($4.getInt()+adj);
1003                     }
1004             }
1005
1006     | FUNCTION IDENT
[332]1007             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=":"; t+=$1.getString(); $$.setString(t);
[163]1008             trctx.out->printf("push :%s\n",(const char*)$2.getString());
1009             trstack.adjust(-1);
1010             }
1011
1012     | expr '.' member
[332]1013             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]1014             if ($3.constant)
1015                     trctx.out->printf("move s0,m1\nmove [m1].%s,s0\n",str($3));
1016             else
1017//                   trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
1018                     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");trstack.adjust(1);}
1019             }
1020
1021     | plusminus expr '.' member
[332]1022             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$2.getString(); t+="."; t+=$4.getString(); $$.setString(t);
[163]1023             if ($4.constant)
1024                     trctx.out->printf("move s0,m1\n%s [m1].%s\nmove [m1].%s,s0\n",
1025                                       $1.getInt()?"inc":"dec",str($4),str($4));
1026             else
1027//                   trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
1028                     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\n%s [m1].[m2]\nmove [m1].[m2],s0\n",
1029                                        $1.getInt()?"inc":"dec");trstack.adjust(1);}
1030             }
1031
1032     | expr '.' member plusminus
[332]1033             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]1034             if ($3.constant)
1035                     trctx.out->printf("move s0,m1\nmove [m1].%s,s0\n%s [m1].%s\n",
1036                                       str($3),$4.getInt()?"inc":"dec",str($3));
1037             else
1038//                   trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
1039                     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n%s [m1].[m2]\n",
1040                                        $4.getInt()?"inc":"dec");trstack.adjust(1);}
1041             }
1042
1043     | expr '.' member assign_op expr
[332]1044             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]1045             if ($3.constant)
1046                     {
1047                     int sp;
1048                     if ($5.constant)
1049                             {sp=0; trctx.out->printf("move s0,m1\n");}
1050                     else
1051                             {sp=1; trctx.out->printf("move s1,m1\n");}
1052                     t="[m1]."; t+=str($3);
1053                     handleAssignOp2($$,(const char*)t,$5,assign_op_names[$4.getInt()],sp,0);
1054                     if (sp) {trctx.out->printf("inc m0\n");trstack.adjust(1);}
1055                     }
1056             else
1057                     {
1058                     int sp;
1059                     char *t;
1060                     if ($5.constant)
1061                             {sp=1; t="move s1,m1\nmove s0,m2\n";}
1062                     else
1063                             {sp=2; t="move s2,m1\nmove s1,m2\n";}
1064                     trctx.out->printf(t);
1065                     handleAssignOp2($$,"[m1].[m2]",$5,assign_op_names[$4.getInt()],sp,0);
1066                     trctx.out->printf("add %d,m0\n",sp);
1067                     trstack.adjust(sp);
1068                     }
1069             }
1070
1071     | expr '.' member '=' stackexpr
[332]1072             { trctx.emitLine(); $$=$5; $$.assign=1; $$.parens=0; $$.ident=0;
[163]1073             if ($3.constant)
1074                     {
1075                     trctx.out->printf("move s1,m1\nmove m[m0++],s0\nmove s0,[m1].%s\n",str($3));
1076                     trstack.adjust(1);
1077                     }
1078             else
1079                     {
1080                     trctx.out->printf("move s2,m1\nmove s1,m2\nmove s0,[m1].[m2]\nadd 2,m0\nmove s-2,s0\n");
1081                     trstack.adjust(2);
1082                     }
1083             }
1084
1085     | expr '.' member '(' arguments ')'
[332]1086             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
[163]1087             int adj=0;
1088             if ($5.getInt()==0)
1089                     {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
1090             if ($3.constant)
1091                     {
1092                     trctx.out->printf("move s%d,m1\ncall [m1].%s\n",$5.getInt()+adj,str($3));
1093                     adj+=1;
1094                     }
1095             else
1096                     {
1097                     trctx.out->printf("move s%d,m2\nmove s%d,m1\ncall [m2].[m1]\n",
1098                                       $5.getInt()+adj+1,$5.getInt()+adj);
1099                     adj+=2;
1100                     }
1101             if (($5.getInt()+adj) > 1)
1102                     {
1103                     trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$5.getInt()-1+adj,-($5.getInt()-1+adj));
1104                     trstack.adjust($5.getInt()-1+adj);
1105                     }
1106             }
1107
1108      | expr '[' expr ']' '=' expr    // shortcut: expr.set(expr,expr)
[332]1109             { trctx.emitLine(); $$=$6; $$.assign=1; $$.parens=0; $$.ident=0;
[163]1110             if ($3.constant)
1111                     {
1112                     if ($6.constant)
1113                             {trctx.out->printf("move s0,m1\ncall [m1].\"set\",%s,%s\ninc m0\n",litstr($3),litstr($6));$$=$6;trstack.adjust(+1);}
1114                     else
1115                             {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);}
1116                     }
1117             else
1118                     {
1119                     if ($6.constant)
1120                             {trctx.out->printf("move s1,m1\npush %s\ncall [m1].\"set\"\nadd 3,m0\n",litstr($6)); trstack.adjust(+2);}
1121                     else
1122                             {trctx.out->printf("move s2,m1\ncall [m1].\"set\"\nadd 2,m0\nmove s-2,s0\n"); trstack.adjust(+2);}
1123                     }
1124             }
1125
1126      | expr '[' expr ']'    /* shortcut: expr.get(expr) */
[332]1127             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".get"; $$.setString(t);
[163]1128             if ($3.constant)
1129                     {
1130                     trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n",litstr($3));
1131                     }
1132             else
1133                     {
1134                     trctx.out->printf("move s1,m1\ncall [m1].\"get\"\ninc m0\nmove s-1,s0\n");
1135                     trstack.adjust(+1);
1136                     }
1137             }
1138
[332]1139     | IDENT '=' expr { trctx.emitLine(); $$=$3; $$.assign=1; $$.ident=0;
[163]1140                        int loc=trstack.getVariableLocation($1.getString());
1141                        if (loc!=TranslatorStack::NOTFOUND)
1142                            {
1143                            if ($3.constant)
1144                              trctx.out->printf("move %s,s%d\n",litstr($3),loc-trstack.currentPos());
1145                            else
1146                              trctx.out->printf("move s0,s%d\n",loc-trstack.currentPos());
1147                            }
1148                        else if (globalOk($1)) { $$=$3; $$.ident=0; $$.assign=1;
1149                          if ($3.constant) trctx.out->printf("move %s,@%s\n",litstr($3),str($1));
1150                          else trctx.out->printf("move s0,@%s\n",str($1));}
[245]1151                        else {trctx.err->printf("undefined variable: '%s'\n",str($1)); return 1;}
[163]1152                      }
1153
1154      | OBJNAME '[' expr ']'    /* shortcut: OBJNAME.get(expr) */
[332]1155             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".get"; $$.setString(t);
[163]1156             if ($3.constant)
1157                     {
1158                     trctx.out->printf("dec m0\ncall %s.get,%s\n",str($1),litstr($3));
1159                     trstack.adjust(-1);
1160                     }
1161             else
1162                     {
1163                     trctx.out->printf("call %s.get\n",str($1));
1164                     }
1165             }
1166
1167      | IDENT '(' arguments ')'
1168{
[332]1169trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString("function call");
[163]1170if ($3.getInt()==0)
1171        {trctx.out->printf("dec m0\n");trstack.adjust(-1);}
1172trctx.out->printf("call :%s\n",str($1));
1173if ($3.getInt()>1)
1174        {
1175        trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$3.getInt()-1,-($3.getInt()-1));
1176        trstack.adjust($3.getInt()-1);
1177        }
1178}
1179
[332]1180| '[' {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]1181        v_elements ']'
1182        {$$.constant=0; trctx.out->printf("inc m0\n");trstack.adjust(1);}
1183
[332]1184| '{' {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]1185        d_elements '}'
1186        {$$.constant=0; trctx.out->printf("inc m0\n"); trstack.adjust(1);}
1187
1188//      | '&' stackexpr {trctx.out->printf("call Ref.new\n");}
1189
1190      | '&' IDENT {
[332]1191        trctx.emitLine(); $$.ident=0;
[163]1192        int loc=trstack.getVariableLocation($2.getString());
1193        if (loc!=TranslatorStack::NOTFOUND)
1194                {
[247]1195                trctx.out->printf("push &%d\n",loc-trstack.currentPos());trstack.adjust(-1);
[163]1196                }
1197        else if (globalOk($2))
1198                {
1199                trctx.out->printf("gpush &@%s\ncall Ref.newO\ninc m0\nmove s-1,s0\n",str($2));
1200                trstack.adjust(-1);
1201                }
[245]1202        else {trctx.err->printf("undefined variable: '%s'\n",str($1)); return 1;}
[163]1203            }
1204
1205      | '&' OBJNAME '.' member {
[332]1206      trctx.emitLine(); $$.ident=0;
[163]1207      if ($4.constant)
1208              {
1209              trctx.out->printf("dec m0\ncall Ref.newO,%s.*,%s:%s\n",str($2),str($2),str($4));
1210              trstack.adjust(-1);
1211              }
1212      else
1213              {
1214              trctx.out->printf("call Ref.newO,%s.*,s0\n",str($2));
1215              }
1216      }
1217
1218      | '&' '(' stackexpr ')' '.' member {
[332]1219      trctx.emitLine(); $$.ident=0;
[163]1220      if ($6.constant)
1221              {
1222              trctx.out->printf("call Ref.newO,s0,%s\n",litstr($6));
1223              }
1224      else
1225              {
1226              trctx.out->printf("call Ref.newO,s1,s0\ninc m0\nmove s-1,s0\n");
1227              trstack.adjust(1);
1228              }
1229      }
1230
1231      | '(' stackexpr ',' stackexpr ',' stackexpr ')' {
[332]1232      trctx.emitLine(); $$.ident=0;
[163]1233      trctx.out->printf("call XYZ.new\nadd 2,m0\nmove s-2,s0\n");trstack.adjust(2);}
1234;
1235
1236v_elements: /* empty */
1237      | v_element
1238      | v_elements ',' v_element
1239;
1240
1241d_elements: /* empty */
1242      | d_element
1243      | d_elements ',' d_element
1244;
1245
1246v_element: expr
1247{
1248if ($1.constant)
1249        trctx.out->printf("move s1,m1\ncall [m1].Vector:add,%s\n",litstr($1));
1250else
1251        {trctx.out->printf("move s2,m1\ncall [m1].Vector:add\ninc m0\n");trstack.adjust(1);}
1252}
1253;
1254
1255d_element: expr ':' expr
1256{
1257if ($1.constant)
1258        {
1259        if ($3.constant)
1260                trctx.out->printf("move s1,m1\ncall [m1].Dictionary:set,%s,%s\n",litstr($1),litstr($3));
1261        else
1262                {trctx.out->printf("move s2,m1\nmove %s,s1\ncall [m1].Dictionary:set\ninc m0\n",litstr($1));trstack.adjust(1);}
1263        }
1264else
1265        {
1266        if ($3.constant)
1267                {trctx.out->printf("move s2,m1\nmove s0,s1\nmove %s,s0\ncall [m1].Dictionary:set\ninc m0\n",litstr($3));trstack.adjust(1);}
1268        else
1269                {trctx.out->printf("move s3,m1\ncall [m1].Dictionary:set\nadd 2,m0\n");trstack.adjust(2);}
1270        }
1271}
1272;
1273
1274member:    IDENT { $$=$1; $$.constant=1;}
1275         | OBJNAME ':' IDENT { SString t=$1.getString();t+=":";t+=$3.getString();
1276                               $$.setString(t);$$.constant=1;}
1277         | '[' stackexpr ']' { SString t="["; t+=$2.getString(); t+="]";
1278                               $$.setString(t); $$.constant=0;}
1279
1280stackexpr: expr {if ($1.constant) {trctx.out->printf("push %s\n",litstr($1)); trstack.adjust(-1); $$.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+='\"';
1297const char*t=(const char*)s;
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]1411class FramscriptCmpMessageHandler: public ExtValue::CmpMessageHandler
[163]1412{
[332]1413  public:
1414void cmpMessage(SString& msg)
1415  {
1416  FMprintf("FramScriptCompiler","translate",FMLV_WARN,"%s (%s line %d)",(const char*)msg,(const char*)trctx.srcname,trctx.line);
1417  //trctx.err->printf("%s",(const char*)msg);
1418  }
1419};
1420
1421static FramscriptCmpMessageHandler framscript_cmp_messages;
1422
1423bool handleCompare(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,ExtValue::CmpOperator op,const char* opname)
1424{
1425trctx.emitLine();
[163]1426result.ident=0;
1427if (arg1.constant && arg2.constant)
1428        {
1429        result.constant=1;
[333]1430        ExtValue::CompareResult cmp=arg1.compare(arg2);
[332]1431        ExtValue::CmpContext context;
1432        context.v1=&arg1;
1433        context.v2=&arg2;
1434        context.handler=&framscript_cmp_messages;
1435        int ret=ExtValue::interpretCompare(op,cmp,&context);
1436        if (ret<0)
1437                result.setEmpty();//return false;
1438        else
1439                result.setInt(ret);
1440        return true;
[163]1441        }
1442else
1443        {
1444        result.constant=0;
1445        result.assign=arg1.assign || arg2.assign;
1446        result.parens=0;
1447        result.setString(opname);
1448        if (arg1.constant)
1449                trctx.out->printf("setif %s,%s,s0,s0\n",litstr(arg1),opname);
1450        else if (arg2.constant)
1451                trctx.out->printf("setif s0,%s,%s,s0\n",opname,litstr(arg2));
1452        else
1453                {
1454                trctx.out->printf("setif s1,%s,s0,s1\ninc m0\n",opname);
1455                trstack.adjust(+1);
1456                }
[332]1457        return true;
[163]1458        }
1459}
1460
[333]1461static bool resultIsRelaxedEqual(ExtValue::CompareResult res)
1462{
1463return (res==ExtValue::ResultEqual)||(res==ExtValue::ResultEqualUnordered)||(res==ExtValue::ResultUnequal_RelaxedEqual);
1464}
1465
[163]1466bool variableOk(TokenValue &tok, const TokenValue& var,int &loc)
1467{
1468loc=trstack.getVariableLocation(var.getString());
1469if (loc != TranslatorStack::NOTFOUND)
1470        {tok.setInt(loc); tok.constant=0;
1471        return 1;}
1472return 0;
1473}
1474
1475bool globalOk(const TokenValue& var)
1476{
1477SymTabEntry* found=trstack.globals.find(var.getString());
1478if (found) return true;
1479return framscriptIsGlobalName(var.getString());
1480}
1481
1482void badVariable(TokenValue &tok, const TokenValue& var)
1483{
1484tok=var; tok.constant=1;
1485trctx.err->printf("undefined variable '%s'\n",str(var));
1486}
1487
1488bool doBreak(int level)
1489{
1490if (trstack.loops.size()<level)
[245]1491        {trctx.err->printf("invalid 'break'\n"); return 0;}
[163]1492LoopInfo* li=trstack.loops.getLoop(level-1);
1493if (li->location != trstack.currentPos())
1494        trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
1495trctx.out->printf("jump :_loop_end_%d\n",li->id);
1496return 1;
1497}
1498
1499bool doContinue(int level)
1500{
1501if (trstack.loops.size()<level)
[245]1502        {trctx.err->printf("invalid 'continue'\n"); return 0;}
[163]1503LoopInfo* li=trstack.loops.getLoop(level-1);
1504if (li->location != trstack.currentPos())
1505        trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
1506trctx.out->printf("jump :_loop_%d\n",li->id);
1507return 1;
1508}
1509
1510int lookupToken(char *s)
1511{
1512int len=strlen(s);
1513int i;
1514const char *t;
1515for (i = 0; i < YYNTOKENS; i++)
1516        {
1517        t=yytname[i];
1518        if (t && (t[0]=='"')
1519           && (!strncmp(t+1,s,len))
1520           && (t[len+1]=='"')
1521           && (t[len+2] == 0))
1522                return yytoknum[i];
1523        }
1524return -1;
1525}
1526
1527void warnTruthValue(const TokenValue& t)
1528{
1529if (t.assign && (!t.parens))
1530        FMprintf("FramScriptCompiler","translate",FMLV_WARN,"Assignment used as truth value, use double parens if you really mean it (%s line %d)",(const char*)trctx.srcname,trctx.line);
1531}
1532
1533void outFunName(const TokenValue& t)
1534{
1535if (trctx.functiontmplabel<0)
1536        {
1537        trctx.functiontmplabel=trctx.labelcounter++;
1538        trctx.out->printf("jump :_skipfun_%d\n",trctx.functiontmplabel);
1539        }
1540trctx.out->printf(":%s\n",str(t));
1541}
1542
1543bool evalVariable(TokenValue &tok,const TokenValue &var)
1544{
1545int loc;
1546if (variableOk(tok,var,loc))
1547        {
1548        trctx.out->printf("push s%d\n",loc-trstack.currentPos());
1549        trstack.adjust(-1);
1550        return true;
1551        }
1552else if (globalOk(var))
1553        {
1554        trctx.out->printf("push @%s\n",(const char*)var.getString());
1555        trstack.adjust(-1);
1556        return true;
1557        }
1558else
1559        {
1560        badVariable(tok,var); return false;
1561        }
1562}
Note: See TracBrowser for help on using the repository browser.