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

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

"const" keyword, detecting variable name clashes, error on iterating null, "->" notation for dictionaries

  • 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            {fputs(str($1),trctx.out);fputc('\n',trctx.out);}
152        | asmlines ASMLINE   {fputs(str($2),trctx.out);fputc('\n',trctx.out);}
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,==,null,:_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,==,0,:_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));$$=$6;trstack.adjust(+1);}
1187                     else
1188                             {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);}
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\ncall [m1].\"set\"\nadd 2,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\nmove %s,s1\ncall [m1].\"set\"\nadd 2,m0\nmove s-2,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.