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

Last change on this file since 546 was 538, checked in by Maciej Komosinski, 8 years ago

Value of the assignment statement is now consistently the assigned value. Previously it was the value returned from set() (in cases where set() is used and the assigned expression is not a constant). Interestingly, Dictionary.set() returns the "before" value for the given key, and this created the delayed "assignment propagation" effect.

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