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

Last change on this file since 836 was 836, checked in by Maciej Komosinski, 7 weeks ago

Introduced ternary conditional operator a?b:c

  • Property svn:eol-style set to native
File size: 52.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 a 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 the 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       | expr '?'
875 {
876 trctx.emitLine();
877// trctx.out->printf("\n####### conditional operator\n");
878 $$.counter=trctx.labelcounter++;
879 warnTruthValue($1);
880 if ($1.constant)
881         {
882         ExtValue::CompareResult cond=$1.compare(ExtValue::zero());
883         $1.counter=0;
884         if (resultIsRelaxedEqual(cond))
885                 trctx.out->printf("jump :_cond_false_%d\n",$$.counter);
886         }
887 else
888         {
889         trstack.adjust(+1);
890         trctx.out->printf("if ~=,m[m0++],:_cond_false_%d\n",$$.counter);
891         }
892 $$.stack=trstack.currentPos();
893// trctx.out->printf("\n####### conditional - true\n");
894 }
895         stackexpr ':'
896 {
897 trctx.emitLine();
898 trctx.out->printf("jump :_cond_end_%d\n",$3.counter);
899 trctx.out->printf(":_cond_false_%d\n",$3.counter);
900// trctx.out->printf("\n####### conditional - false\n");
901 trstack.adjust($3.stack-trstack.currentPos());
902 }
903         stackexpr
904 {
905 trctx.emitLine();
906 trctx.out->printf(":_cond_end_%d\n",$3.counter);
907// trctx.out->printf("\n####### conditional - end\n");
908 $$.ident=false; $$.constant=0; $$.parens=0; $$.assign=0;
909 }
910         
911       | expr LSHIFT expr { handleTwoArg($$,$1,$3,LSHIFT,"shift",0,0); }
912       | expr RSHIFT expr { handleTwoArg($$,$1,$3,RSHIFT,"shift",1,0); }
913       | expr EQUAL expr     { if (!handleCompare($$,$1,$3,ExtValue::CmpEQ,"==")) return 1; }
914       | expr NOT_EQUAL expr { if (!handleCompare($$,$1,$3,ExtValue::CmpNE,"!=")) return 1; }
915       | expr GEQUAL expr    { if (!handleCompare($$,$1,$3,ExtValue::CmpGE,">=")) return 1; }
916       | expr LEQUAL expr    { if (!handleCompare($$,$1,$3,ExtValue::CmpLE,"<=")) return 1; }
917       | expr '>' expr       { if (!handleCompare($$,$1,$3,ExtValue::CmpGT,">")) return 1; }
918       | expr '<' expr       { if (!handleCompare($$,$1,$3,ExtValue::CmpLT,"<")) return 1; }
919
920       | '!' expr        {
921                         trctx.emitLine(); $$.assign=$2.assign; $$.parens=0; $$.ident=0;
922                         if ($2.constant)
923                                 {$$.constant=1; ExtValue::CompareResult res=$2.compare(ExtValue((paInt)0)); $$.setInt(resultIsRelaxedEqual(res));}
924                         else
925                                {trctx.out->printf("setif ~=,s0,s0\n");}
926                         }
927
928     | '-' expr %prec NEG {
929                          trctx.emitLine(); $$.assign=$2.assign; $$.parens=0; $$.ident=0;
930                          if ($2.constant)
931                                  { $$.constant=$2.constant;
932                                   if ($2.type==TInt) $$.setInt(-$2.getInt());
933                                   else if ($2.type==TDouble) $$.setDouble(-$2.getDouble());
934                                   else $$=$2;
935                                  }
936                             else
937                                  {
938                                  $$.constant=0; SString t="-"; t+=$2.getString(); $$.setString(t);
939                                  trctx.out->printf("mul -1,s0\n");
940                                  }
941                          }
942
943     | '(' expr ')'    { trctx.emitLine(); $$ = $2; $$.assign=$2.assign?(!$2.parens):0; $$.parens=1; $$.ident=0; }
944
945     | OBJNAME '.' member {
946                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
947                        if ($3.constant)
948                                {
949                                trctx.out->printf("push %s.%s\n",str($1),str($3)); trstack.adjust(-1);
950                                }
951                        else
952                                {
953                                trctx.out->printf("move s0,m1\nmove %s.[m1],s0\n",str($1));
954                                }
955                        }
956
957     | OBJNAME '.' member assign_op expr
958                  { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
959                  if ($3.constant)
960                          {
961                          handleAssignOp2($$,t.c_str(),$5,assign_op_names[$4.getInt()],0,1);
962                          }
963                  else
964                          {
965                          int sp=($5.constant)?0:1;
966                          t=$1.getString();t+=".[m1]";
967                          trctx.out->printf("move s0,m1\n",str($1));
968                          handleAssignOp2($$,t.c_str(),$5,assign_op_names[$4.getInt()],sp,0);
969                          if (sp) {trctx.out->printf("inc m0\n"); trstack.adjust(1);}
970                          }
971                  }
972
973     | plusminus OBJNAME '.' member {
974                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$2.getString(); t+="."; t+=$4.getString(); $$.setString(t);
975                        if ($4.constant)
976                                {
977                                trctx.out->printf("%s %s.%s\npush %s.%s\n",$1.getInt()?"inc":"dec",
978                                                  str($2),str($4),str($2),str($4));
979                                trstack.adjust(-1);
980                                }
981                        else
982                                {
983                                trctx.out->printf("move s0,m1\n%s %s.[m1]\nmove %s.[m1],s0\n",
984                                                  $1.getInt()?"inc":"dec",str($2),str($2));
985                                }
986                        }
987
988     | OBJNAME '.' member plusminus {
989                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
990                        if ($3.constant)
991                                {
992                                trctx.out->printf("push %s.%s\n%s %s.%s\n",
993                                                  str($1),str($3),$4.getInt()?"inc":"dec",str($1),str($3));
994                                trstack.adjust(-1);
995                                }
996                        else
997                                {
998                                trctx.out->printf("move s0,m1\nmove %s.[m1],s0\n%s %s.[m1]\n",
999                                                  str($1),$4.getInt()?"inc":"dec",str($1));
1000                                }
1001                        }
1002
1003     | OBJNAME '.' '*'    {
1004                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".*"; $$.setString(t);
1005                        trctx.out->printf("push %s.*\n",str($1)); trstack.adjust(-1);
1006                        }
1007
1008
1009     | OBJNAME '.' member '=' expr {
1010                        trctx.emitLine(); $$=$5; $$.assign=1; $$.parens=0; $$.ident=0;
1011                        if ($3.constant)
1012                                {
1013                                if ($$.constant)
1014                                        trctx.out->printf("move %s,%s.%s\n",litstr($5),str($1),str($3));
1015                                else
1016                                        trctx.out->printf("move s0,%s.%s\n",str($1),str($3));
1017                                }
1018                        else
1019                                {
1020                                if ($$.constant)
1021                                        {
1022                                        trctx.out->printf("move m[m0++],m1\nmove %s,%s.[m1]\n",
1023                                                          litstr($5),str($1));
1024                                        trstack.adjust(1);
1025                                        }
1026                                else
1027                                        {
1028                                        trctx.out->printf("move s1,m1\nmove m[m0++],s0\nmove s0,%s.[m1]\n",
1029                                                          str($1));
1030                                        trstack.adjust(1);
1031                                        }
1032                                }
1033                        }
1034
1035     | OBJNAME '.' member '(' arguments ')'
1036                        {
1037                        trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
1038                        int adj=0,adj2=0;
1039                        if ($5.getInt()==0)
1040                                {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
1041                        if ($3.constant)
1042                                trctx.out->printf("call %s.%s\n",str($1),str($3));
1043                        else
1044                                {
1045                                trctx.out->printf("move s%d,m1\ncall %s.[m1]\n",$5.getInt()+adj,str($1));
1046                                adj2=1;
1047                                }
1048                        adj2+=$5.getInt()-1+adj;
1049                        if (adj2>0)
1050                                {
1051                                trctx.out->printf("add %d,m0\nxmove s%d,s0\n",adj2,-adj2);
1052                                trstack.adjust(adj2);
1053                                }
1054                        }
1055
1056     | CALL expr '(' arguments ')'
1057             { trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString($2.getString());
1058             short adj=0;
1059             if ($4.getInt()==0)
1060                     {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
1061             if ($2.constant)
1062                     trctx.out->printf("call %s\n",litstr($2));
1063             else
1064                     trctx.out->printf("call s%d\n",$4.getInt()+adj);
1065             if (($4.getInt()+adj) > 0)
1066                     {
1067                     trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$4.getInt()+adj,-($4.getInt()+adj));
1068                     trstack.adjust($4.getInt()+adj);
1069                     }
1070             }
1071
1072     | FUNCTION IDENT
1073             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=":"; t+=$1.getString(); $$.setString(t);
1074             trctx.out->printf("push :%s\n",$2.getString().c_str());
1075             trstack.adjust(-1);
1076             }
1077
1078     | stackexpr '.' member
1079             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
1080             if ($3.constant)
1081                     trctx.out->printf("move s0,m1\nmove [m1].%s,s0\n",str($3));
1082             else
1083//                   trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
1084                     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");trstack.adjust(1);}
1085             }
1086
1087     | stackexpr ARROW IDENT       /* shortcut: expr.get("ident") */
1088             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="->"; t+=$3.getString(); $$.setString(t);
1089             trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n",litstr($3));
1090             }
1091
1092     | OBJNAME ARROW IDENT       /* shortcut: StaticObject.get("ident") */
1093             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="->"; t+=$3.getString(); $$.setString(t);
1094             trctx.out->printf("dec m0\ncall %s.\"get\",%s\n",$1.getString().c_str(),litstr($3)); trstack.adjust(-1);
1095             }
1096
1097     | plusminus stackexpr ARROW IDENT       /* shortcut: expr.set("ident",expr.get("ident")+/-1) */
1098             { trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString("");
1099             trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n"
1100                               "move s0,m2\n%s m2\n"
1101                               "call [m1].\"set\",%s,m2\nmove m2,s0\n",
1102                               litstr($4),$1.getInt()?"inc":"dec",litstr($4));
1103             }
1104
1105     | stackexpr ARROW IDENT plusminus       /* shortcut: expr.set("ident",expr.get("ident")+/-1) */
1106             { trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString("");
1107             trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n"
1108                               "move s0,m2\n%s s0\n"
1109                               "call [m1].\"set\",%s,s0\nmove m2,s0\n",
1110                               litstr($3),$4.getInt()?"inc":"dec",litstr($3));
1111             }
1112
1113     | stackexpr ARROW IDENT assign_op expr    /* shortcut: expr1.set("ident",expr1.get("ident") +*-/ expr2) */
1114             { trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString("");
1115             if ($5.constant)
1116                     trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n"
1117                                       "move s0,m2\n%s %s,m2\n"
1118                                       "call [m1].\"set\",%s,m2\nmove m2,s0\n",
1119                                       litstr($3),assign_op_names[$4.getInt()],litstr($5),litstr($3));
1120             else
1121                     {
1122                     trctx.out->printf("move s0,m3\nmove s1,m1\ncall [m1].\"get\",%s\n"
1123                                       "move s0,m2\n%s m3,m2\n"
1124                                       "call [m1].\"set\",%s,m2\ninc m0\nmove m2,s0\n",
1125                                       litstr($3),assign_op_names[$4.getInt()],litstr($3));
1126                     trstack.adjust(1);
1127                     }
1128             }
1129
1130     | plusminus stackexpr '.' member
1131             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$2.getString(); t+="."; t+=$4.getString(); $$.setString(t);
1132             if ($4.constant)
1133                     trctx.out->printf("move s0,m1\n%s [m1].%s\nmove [m1].%s,s0\n",
1134                                       $1.getInt()?"inc":"dec",str($4),str($4));
1135             else
1136//                   trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
1137                     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\n%s [m1].[m2]\nmove [m1].[m2],s0\n",
1138                                        $1.getInt()?"inc":"dec");trstack.adjust(1);}
1139             }
1140
1141     | stackexpr '.' member plusminus
1142             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
1143             if ($3.constant)
1144                     trctx.out->printf("move s0,m1\nmove [m1].%s,s0\n%s [m1].%s\n",
1145                                       str($3),$4.getInt()?"inc":"dec",str($3));
1146             else
1147//                   trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n");
1148                     {trctx.out->printf("move s1,m1\nmove m[m0++],m2\nmove [m1].[m2],s0\n%s [m1].[m2]\n",
1149                                        $4.getInt()?"inc":"dec");trstack.adjust(1);}
1150             }
1151
1152     | stackexpr '.' member assign_op expr
1153             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
1154             if ($3.constant)
1155                     {
1156                     int sp;
1157                     if ($5.constant)
1158                             {sp=0; trctx.out->printf("move s0,m1\n");}
1159                     else
1160                             {sp=1; trctx.out->printf("move s1,m1\n");}
1161                     t="[m1]."; t+=str($3);
1162                     handleAssignOp2($$,t.c_str(),$5,assign_op_names[$4.getInt()],sp,0);
1163                     if (sp) {trctx.out->printf("inc m0\n");trstack.adjust(1);}
1164                     }
1165             else
1166                     {
1167                     int sp;
1168                     char *t;
1169                     if ($5.constant)
1170                             {sp=1; t="move s1,m1\nmove s0,m2\n";}
1171                     else
1172                             {sp=2; t="move s2,m1\nmove s1,m2\n";}
1173                     trctx.out->printf(t);
1174                     handleAssignOp2($$,"[m1].[m2]",$5,assign_op_names[$4.getInt()],sp,0);
1175                     trctx.out->printf("add %d,m0\n",sp);
1176                     trstack.adjust(sp);
1177                     }
1178             }
1179
1180     | stackexpr '.' member '=' stackexpr
1181             { trctx.emitLine(); $$=$5; $$.assign=1; $$.parens=0; $$.ident=0;
1182             if ($3.constant)
1183                     {
1184                     trctx.out->printf("move s1,m1\nmove m[m0++],s0\nmove s0,[m1].%s\n",str($3));
1185                     trstack.adjust(1);
1186                     }
1187             else
1188                     {
1189                     trctx.out->printf("move s2,m1\nmove s1,m2\nmove s0,[m1].[m2]\nadd 2,m0\nmove s-2,s0\n");
1190                     trstack.adjust(2);
1191                     }
1192             }
1193
1194     | stackexpr '.' member '(' arguments ')'
1195             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+="."; t+=$3.getString(); $$.setString(t);
1196             int adj=0;
1197             if ($5.getInt()==0)
1198                     {trctx.out->printf("dec m0\n");trstack.adjust(-1);adj=1;}
1199             if ($3.constant)
1200                     {
1201                     trctx.out->printf("move s%d,m1\ncall [m1].%s\n",$5.getInt()+adj,str($3));
1202                     adj+=1;
1203                     }
1204             else
1205                     {
1206                     trctx.out->printf("move s%d,m2\nmove s%d,m1\ncall [m2].[m1]\n",
1207                                       $5.getInt()+adj+1,$5.getInt()+adj);
1208                     adj+=2;
1209                     }
1210             if (($5.getInt()+adj) > 1)
1211                     {
1212                     trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$5.getInt()-1+adj,-($5.getInt()-1+adj));
1213                     trstack.adjust($5.getInt()-1+adj);
1214                     }
1215             }
1216
1217      | stackexpr '[' expr ']' '=' expr    // shortcut: expr.set(expr,expr)
1218             { trctx.emitLine(); $$=$6; $$.assign=1; $$.parens=0; $$.ident=0;
1219             if ($3.constant)
1220                     {
1221                     if ($6.constant)
1222                             {trctx.out->printf("move s0,m1\ncall [m1].\"set\",%s,%s\ninc m0\n",litstr($3),litstr($6));trstack.adjust(+1);}
1223                     else
1224                             {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);}
1225                     }
1226             else
1227                     {
1228                     if ($6.constant)
1229                             {trctx.out->printf("move s1,m1\npush %s\ncall [m1].\"set\"\nadd 3,m0\n",litstr($6)); trstack.adjust(+2);}
1230                     else
1231                             {trctx.out->printf("move s2,m1\npush s1\npush s1\ncall [m1].\"set\"\nadd 4,m0\nmove s-2,s0\n"); trstack.adjust(+2);}
1232                     }
1233             }
1234
1235      | plusminus stackexpr '[' expr ']'  /* shortcut: o.set(index,o.get(index)+/-1) */
1236             { trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString("");
1237             if ($4.constant)
1238                     trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n"
1239                                       "move s0,m2\n%s m2\n"
1240                                       "call [m1].\"set\",%s,m2\nmove m2,s0\n",
1241                                       litstr($4),$1.getInt()?"inc":"dec",litstr($4));
1242             else
1243                     {
1244                     trctx.out->printf("move s0,m3\nmove s1,m1\ncall [m1].\"get\",m3\n"
1245                                       "move s0,m2\n%s m2\n"
1246                                       "call [m1].\"set\",m3,m2\ninc m0\nmove m2,s0\n",
1247                                       $1.getInt()?"inc":"dec");
1248                     trstack.adjust(1);
1249                     }
1250             }
1251
1252      | stackexpr '[' expr ']' plusminus  /* shortcut: o.set(index,o.get(index)+/-1) */
1253             { trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString("");
1254             if ($3.constant)
1255                     trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n"
1256                                       "move s0,m2\n%s s0\n"
1257                                       "call [m1].\"set\",%s,s0\nmove m2,s0\n",
1258                                       litstr($3),$5.getInt()?"inc":"dec",litstr($3));
1259             else
1260                     {
1261                     trctx.out->printf("move s0,m3\nmove s1,m1\ncall [m1].\"get\",m3\n"
1262                                       "move s0,m2\n%s s0\n"
1263                                       "call [m1].\"set\",m3,s0\ninc m0\nmove m2,s0\n",
1264                                       $5.getInt()?"inc":"dec");
1265                     trstack.adjust(1);
1266                     }
1267             }
1268
1269      | stackexpr '[' expr ']' assign_op expr /* shortcut: o.set(index,o.get(index) +*-/ expr) */
1270             { trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString("");
1271             if ($6.constant)
1272                     {
1273                     if ($3.constant)
1274                             trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n"
1275                                               "move s0,m2\n%s %s,m2\n"
1276                                               "call [m1].\"set\",%s,m2\nmove m2,s0\n",
1277                                               litstr($3),assign_op_names[$5.getInt()],litstr($6),litstr($3));
1278                     else
1279                             {
1280                             trctx.out->printf("move s0,m3\nmove s1,m1\ncall [m1].\"get\",m3\n"
1281                                               "move s0,m2\n%s %s,m2\n"
1282                                               "call [m1].\"set\",m3,m2\ninc m0\nmove m2,s0\n",
1283                                               assign_op_names[$5.getInt()],litstr($6));
1284                             trstack.adjust(1);
1285                             }
1286                     }
1287             else
1288                     {
1289                     if ($3.constant)
1290                             {
1291                             trctx.out->printf("move s0,m3\nmove s1,m1\ncall [m1].\"get\",%s\n"
1292                                               "move s0,m2\n%s m3,m2\n"
1293                                               "call [m1].\"set\",%s,m2\ninc m0\nmove m2,s0\n",
1294                                               litstr($3),assign_op_names[$5.getInt()],litstr($3));
1295                             trstack.adjust(1);
1296                             }
1297                     else
1298                             {
1299                             trctx.out->printf("move s0,m3\nmove s1,m4\nmove s2,m1\ncall [m1].\"get\",m4\n"
1300                                               "move s0,m2\n%s m3,m2\n"
1301                                               "call [m1].\"set\",m4,m2\nadd 2,m0\nmove m2,s0\n",
1302                                               assign_op_names[$5.getInt()]);
1303                             trstack.adjust(2);
1304                             }
1305                     }
1306             }
1307
1308
1309     | stackexpr ARROW IDENT '=' expr       /* shortcut: expr.set("ident",expr) */
1310             { trctx.emitLine(); $$=$5; $$.assign=1; $$.ident=0; $$.parens=0;
1311                     if ($5.constant)
1312                             {trctx.out->printf("move s0,m1\ncall [m1].\"set\",%s,%s\ninc m0\n",litstr($3),litstr($5));$$=$5;trstack.adjust(+1);}
1313                     else
1314                             {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);}
1315             }
1316
1317      | stackexpr '[' expr ']'    /* shortcut: expr.get(expr) */
1318             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".get"; $$.setString(t);
1319             if ($3.constant)
1320                     {
1321                     trctx.out->printf("move s0,m1\ncall [m1].\"get\",%s\n",litstr($3));
1322                     }
1323             else
1324                     {
1325                     trctx.out->printf("move s1,m1\ncall [m1].\"get\"\ninc m0\nmove s-1,s0\n");
1326                     trstack.adjust(+1);
1327                     }
1328             }
1329
1330     | IDENT '=' expr { trctx.emitLine(); $$=$3; $$.assign=1; $$.ident=0;
1331                        int loc=trstack.getVariableLocation($1.getString());
1332                        if (loc!=TranslatorStack::NOTFOUND)
1333                            {
1334                            if ($3.constant)
1335                              trctx.out->printf("move %s,s%d\n",litstr($3),loc-trstack.currentPos());
1336                            else
1337                              trctx.out->printf("move s0,s%d\n",loc-trstack.currentPos());
1338                            }
1339                        else if (globalOk($1)) { $$=$3; $$.ident=0; $$.assign=1;
1340                          if ($3.constant) trctx.out->printf("move %s,@%s\n",litstr($3),str($1));
1341                          else trctx.out->printf("move s0,@%s\n",str($1));}
1342                        else {trctx.err->printf("undefined variable: '%s'\n",str($1)); return 1;}
1343                      }
1344
1345      | OBJNAME '[' expr ']'    /* shortcut: OBJNAME.get(expr) */
1346             { trctx.emitLine(); $$.constant=0; $$.ident=0; SString t=$1.getString(); t+=".get"; $$.setString(t);
1347             if ($3.constant)
1348                     {
1349                     trctx.out->printf("dec m0\ncall %s.get,%s\n",str($1),litstr($3));
1350                     trstack.adjust(-1);
1351                     }
1352             else
1353                     {
1354                     trctx.out->printf("call %s.get\n",str($1));
1355                     }
1356             }
1357
1358      | IDENT '(' arguments ')'
1359{
1360trctx.emitLine(); $$.constant=0; $$.ident=0; $$.setString("function call");
1361if ($3.getInt()==0)
1362        {trctx.out->printf("dec m0\n");trstack.adjust(-1);}
1363trctx.out->printf("call :%s\n",str($1));
1364if ($3.getInt()>1)
1365        {
1366        trctx.out->printf("add %d,m0\nxmove s%d,s0\n",$3.getInt()-1,-($3.getInt()-1));
1367        trstack.adjust($3.getInt()-1);
1368        }
1369}
1370
1371| '[' {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)
1372        v_elements ']'
1373        {$$.constant=0; trctx.out->printf("inc m0\n");trstack.adjust(1);}
1374
1375| '{' {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)
1376        d_elements '}'
1377        {$$.constant=0; trctx.out->printf("inc m0\n"); trstack.adjust(1);}
1378
1379//      | '&' stackexpr {trctx.out->printf("call Ref.new\n");}
1380
1381      | '&' IDENT {
1382        trctx.emitLine(); $$.ident=0;
1383        int loc=trstack.getVariableLocation($2.getString());
1384        if (loc!=TranslatorStack::NOTFOUND)
1385                {
1386                trctx.out->printf("push &%d\n",loc-trstack.currentPos());trstack.adjust(-1);
1387                }
1388        else if (globalOk($2))
1389                {
1390                trctx.out->printf("gpush &@%s\ncall Ref.newO\ninc m0\nmove s-1,s0\n",str($2));
1391                trstack.adjust(-1);
1392                }
1393        else {trctx.err->printf("undefined variable: '%s'\n",str($1)); return 1;}
1394            }
1395
1396      | '&' OBJNAME '.' member {
1397      trctx.emitLine(); $$.ident=0;
1398      if ($4.constant)
1399              {
1400              trctx.out->printf("dec m0\ncall Ref.newO,%s.*,%s:%s\n",str($2),str($2),str($4));
1401              trstack.adjust(-1);
1402              }
1403      else
1404              {
1405              trctx.out->printf("call Ref.newO,%s.*,s0\n",str($2));
1406              }
1407      }
1408
1409      | '&' '(' stackexpr ')' '.' member {
1410      trctx.emitLine(); $$.ident=0;
1411      if ($6.constant)
1412              {
1413              trctx.out->printf("call Ref.newO,s0,%s\n",litstr($6));
1414              }
1415      else
1416              {
1417              trctx.out->printf("call Ref.newO,s1,s0\ninc m0\nmove s-1,s0\n");
1418              trstack.adjust(1);
1419              }
1420      }
1421
1422      | '(' stackexpr ',' stackexpr ',' stackexpr ')' {
1423      trctx.emitLine(); $$.ident=0;
1424      trctx.out->printf("call XYZ.new\nadd 2,m0\nmove s-2,s0\n");trstack.adjust(2);}
1425;
1426
1427v_elements: /* empty */
1428      | v_element
1429      | v_elements ',' v_element
1430;
1431
1432d_elements: /* empty */
1433      | d_element
1434      | d_elements ',' d_element
1435;
1436
1437v_element: expr
1438{
1439if ($1.constant)
1440        trctx.out->printf("move s1,m1\ncall [m1].Vector:add,%s\n",litstr($1));
1441else
1442        {trctx.out->printf("move s2,m1\ncall [m1].Vector:add\ninc m0\n");trstack.adjust(1);}
1443}
1444;
1445
1446d_element: expr ':' expr
1447{
1448if ($1.constant)
1449        {
1450        if ($3.constant)
1451                trctx.out->printf("move s1,m1\ncall [m1].Dictionary:set,%s,%s\n",litstr($1),litstr($3));
1452        else
1453                {trctx.out->printf("move s2,m1\nmove %s,s1\ncall [m1].Dictionary:set\ninc m0\n",litstr($1));trstack.adjust(1);}
1454        }
1455else
1456        {
1457        if ($3.constant)
1458                {trctx.out->printf("move s2,m1\nmove s0,s1\nmove %s,s0\ncall [m1].Dictionary:set\ninc m0\n",litstr($3));trstack.adjust(1);}
1459        else
1460                {trctx.out->printf("move s3,m1\ncall [m1].Dictionary:set\nadd 2,m0\n");trstack.adjust(2);}
1461        }
1462}
1463;
1464
1465member:    IDENT { $$=$1; $$.constant=1;}
1466         | OBJNAME ':' IDENT { SString t=$1.getString();t+=":";t+=$3.getString();
1467                               $$.setString(t);$$.constant=1;}
1468         | '[' stackexpr ']' { SString t="["; t+=$2.getString(); t+="]";
1469                               $$.setString(t); $$.constant=0;}
1470
1471arguments: /* empty */         { $$.setInt(0); }
1472         |  stackexpr               { $$.setInt(1); }
1473         |  arguments ',' stackexpr  {$$.setInt($1.getInt()+1);}
1474;
1475
1476%%
1477
1478SString makeLitString(const ExtValue& val)
1479{
1480if (val.type!=TString)
1481        return val.getString();
1482SString s=val.getString();
1483int len=s.len();
1484SString ret((len*11)/10+10);
1485ret+='\"';
1486const char*t=s.c_str();
1487while(len>0)
1488        {
1489        switch(*t)
1490                {
1491                case '\n': ret+="\\n"; break;
1492                case '\r': ret+="\\r"; break;
1493                case '\t': ret+="\\t"; break;
1494                default: ret+=*t;
1495                }
1496        t++; len--;
1497        }
1498ret+='\"';
1499return ret;
1500}
1501
1502static void yyprint (FILE *file,int type,YYSTYPE value)
1503{
1504fprintf(file,"(%s)%s",str(value),value.constant?"c":"");
1505}
1506
1507int yyerror (const char *s)  /* Called by yyparse on error */
1508{
1509trctx.err->printf ("%s\n",s);
1510return 0; // w przykladach do bisona tez nie dali returna...
1511}
1512
1513void handleTwoArg(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,
1514                  int optoken,const char* opname,bool negarg2,bool uniq)
1515{
1516trctx.emitLine();
1517result.ident=false;
1518if (arg1.constant && arg2.constant)
1519        {
1520        result=arg1;
1521        switch(optoken)
1522                {
1523                case '+': result+=arg2; break;
1524                case '-': result-=arg2; break;
1525                case '*': result*=arg2; break;
1526                case '/': result/=arg2; break;
1527                case '%': result%=arg2; break;
1528                case '&': result.setInt(arg1.getInt() & arg2.getInt()); break;
1529                case '|': result.setInt(arg1.getInt() | arg2.getInt()); break;
1530                case LSHIFT: result.setInt(arg1.getInt() << arg2.getInt()); break;
1531                case RSHIFT: result.setInt(arg1.getInt() >> arg2.getInt()); break;
1532                }
1533        }
1534else
1535        {
1536        //TODO: prawie kazde uzycie uniq jest niepotrzebne bo typem rzadko bedzie vector, ale w wiekszosci miejsc okreslenie typu wartosci
1537        // byloby bardzo trudne lub niemozliwe. mozna byloby natomiast zapamietywac przy parsowaniu czy dana wartosc na stosie jest
1538        // skopiowana ze zmiennej/pola czy jest wynikiem wczesniejszej operacji co pozwoliloby na likwidacje bardzo wielu uniq
1539        result.constant=0;
1540        result.assign=arg1.assign || arg2.assign;
1541        result.parens=0;
1542        result.setString(opname);
1543        if (arg1.constant)
1544                trctx.out->printf("move %s,m1\n%s%s s0,m1\nmove m1,s0\n",litstr(arg1),
1545                                  negarg2?"neg s0\n":"",
1546                                  opname);
1547        else if (arg2.constant)
1548                {
1549                if (negarg2)
1550                        trctx.out->printf("%s %d,s0\n",opname,-arg2.getInt());
1551                else
1552                        trctx.out->printf("%s%s %s,s0\n",(uniq?"uniq s0\n":""),opname,litstr(arg2));
1553                }
1554        else
1555                {
1556                trctx.out->printf("%s%s%s s0,s1\ninc m0\n",
1557                                  uniq?"uniq s1\n":"",
1558                                  negarg2?"neg s0\n":"",
1559                                  opname);
1560                trstack.adjust(+1);
1561                }
1562        }
1563}
1564
1565bool handleAssignOp(YYSTYPE& result,const YYSTYPE& var,const YYSTYPE& arg,const char* opname)
1566{
1567int loc; if (variableOk(result,var,loc))
1568        {
1569        loc-=trstack.currentPos();
1570        if (arg.constant)
1571                {
1572                trctx.out->printf("%s %s,s%d\npush s%d\n",opname,litstr(arg),loc,loc);
1573                trstack.adjust(-1);
1574                }
1575        else
1576                trctx.out->printf("%s s0,s%d\nmove s%d,s0\n",opname,loc,loc);
1577        return 1;
1578        }
1579return 0;
1580}
1581
1582bool handleAssignOp2(YYSTYPE& result,const char *var,const YYSTYPE& arg,const char* opname,int stackpos,bool push)
1583{
1584if (arg.constant)
1585        {
1586        trctx.out->printf("%s %s,%s\n",opname,litstr(arg),var);
1587        if (!push)
1588                trctx.out->printf("move %s,s%d\n",var,stackpos);
1589        else
1590                {
1591                trctx.out->printf("push %s\n",var);
1592                trstack.adjust(-1);
1593                }
1594        }
1595else
1596        trctx.out->printf("%s s0,%s\nmove %s,s%d\n",opname,var,var,stackpos);
1597return 1;
1598}
1599
1600bool handleCompare(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,ExtValue::CmpOperator op,const char* opname)
1601{
1602trctx.emitLine();
1603result.ident=0;
1604if (arg1.constant && arg2.constant)
1605        {
1606        result.constant=1;
1607        ExtValue::CompareResult cmp=arg1.compare(arg2);
1608        ExtValue::CmpContext context;
1609        context.v1=&arg1;
1610        context.v2=&arg2;
1611        int ret=ExtValue::interpretCompare(op,cmp,&context);
1612        if (ret<0)
1613                result.setEmpty();//return false;
1614        else
1615                result.setInt(ret);
1616        return true;
1617        }
1618else
1619        {
1620        result.constant=0;
1621        result.assign=arg1.assign || arg2.assign;
1622        result.parens=0;
1623        result.setString(opname);
1624        if (arg1.constant)
1625                trctx.out->printf("setif %s,%s,s0,s0\n",litstr(arg1),opname);
1626        else if (arg2.constant)
1627                trctx.out->printf("setif s0,%s,%s,s0\n",opname,litstr(arg2));
1628        else
1629                {
1630                trctx.out->printf("setif s1,%s,s0,s1\ninc m0\n",opname);
1631                trstack.adjust(+1);
1632                }
1633        return true;
1634        }
1635}
1636
1637static bool resultIsRelaxedEqual(ExtValue::CompareResult res)
1638{
1639return (res==ExtValue::ResultEqual)||(res==ExtValue::ResultEqualUnordered)||(res==ExtValue::ResultUnequal_RelaxedEqual);
1640}
1641
1642bool canAddName(const SString &name,NameKind kind)
1643{
1644ExtValue dummy;
1645NameKind found=NameNotFound;
1646if (globalNameOk(name)) found=GlobalName;
1647else if (trstack.getConstant(name,dummy)) found=ConstName;
1648else if (kind!=VariableName) { if (variableNameOk(name)!=TranslatorStack::NOTFOUND) found=VariableName; }
1649if (found!=NameNotFound)
1650        { 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; }
1651return true;
1652}
1653
1654int variableNameOk(const SString &name)
1655{
1656int loc=trstack.getVariableLocation(name);
1657if (loc != TranslatorStack::NOTFOUND)
1658        {
1659        if ((trctx.functionstackpos!=TranslatorContext::NOT_IN_FUNCTION)
1660            && (loc>=trctx.beforefunctionstackpos))
1661                return TranslatorStack::NOTFOUND;
1662        return loc;
1663        }
1664return TranslatorStack::NOTFOUND;
1665}
1666
1667bool variableOk(TokenValue &tok, const TokenValue& var,int &loc)
1668{
1669loc=variableNameOk(var.getString());
1670if (loc != TranslatorStack::NOTFOUND)
1671        {
1672        tok.setInt(loc); tok.constant=0;
1673        return true;
1674        }
1675return false;
1676}
1677
1678bool globalOk(const TokenValue& var)
1679{
1680return globalNameOk(var.getString());
1681}
1682
1683bool globalNameOk(const SString& name)
1684{
1685SymTabEntry* found=trstack.globals.find(name);
1686if (found) return true;
1687return framscriptIsGlobalName(name.c_str());
1688}
1689
1690void badVariable(TokenValue &tok, const TokenValue& var)
1691{
1692tok=var; tok.constant=1;
1693trctx.err->printf("undefined variable '%s'\n",str(var));
1694}
1695
1696bool doBreak(int level)
1697{
1698if (trstack.loops.size()<level)
1699        {trctx.err->printf("invalid 'break'\n"); return 0;}
1700LoopInfo* li=trstack.loops.getLoop(level-1);
1701if (li->location != trstack.currentPos())
1702        trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
1703trctx.out->printf("jump :_loop_end_%d\n",li->id);
1704return 1;
1705}
1706
1707bool doContinue(int level)
1708{
1709if (trstack.loops.size()<level)
1710        {trctx.err->printf("invalid 'continue'\n"); return 0;}
1711LoopInfo* li=trstack.loops.getLoop(level-1);
1712if (li->location != trstack.currentPos())
1713        trctx.out->printf("add %d,m0\n",li->location-trstack.currentPos());
1714trctx.out->printf("jump :_loop_%d\n",li->id);
1715return 1;
1716}
1717
1718int lookupToken(char *s)
1719{
1720int len=strlen(s);
1721int i;
1722const char *t;
1723for (i = 0; i < YYNTOKENS; i++)
1724        {
1725        t=yytname[i];
1726        if (t && (t[0]=='"')
1727           && (!strncmp(t+1,s,len))
1728           && (t[len+1]=='"')
1729           && (t[len+2] == 0))
1730                return yytoknum[i];
1731        }
1732return -1;
1733}
1734
1735void warnTruthValue(const TokenValue& t)
1736{
1737if (t.assign && (!t.parens))
1738        logPrintf("FramScriptCompiler","translate",LOG_WARN,"Assignment used as truth value, use ((double parens)) if you really mean it");
1739}
1740
1741void outFunName(const TokenValue& t)
1742{
1743if (trctx.functiontmplabel<0)
1744        {
1745        trctx.functiontmplabel=trctx.labelcounter++;
1746        trctx.out->printf("jump :_skipfun_%d\n",trctx.functiontmplabel);
1747        }
1748trctx.out->printf(":%s\n",str(t));
1749}
1750
1751bool evalVariable(TokenValue &tok,const TokenValue &var)
1752{
1753int loc;
1754if (variableOk(tok,var,loc))
1755        {
1756        trctx.out->printf("push s%d\n",loc-trstack.currentPos());
1757        trstack.adjust(-1);
1758        return true;
1759        }
1760else if (globalOk(var))
1761        {
1762        trctx.out->printf("push @%s\n",var.getString().c_str());
1763        trstack.adjust(-1);
1764        return true;
1765        }
1766else
1767        {
1768        badVariable(tok,var); return false;
1769        }
1770}
Note: See TracBrowser for help on using the repository browser.