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

Last change on this file since 468 was 468, checked in by Maciej Komosinski, 6 years ago

More sophisticated and accurate parsing of numbers

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