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

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