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

Last change on this file since 859 was 859, checked in by Maciej Komosinski, 5 years ago

Made operator precedence more standard: conditional (?:) and logical not (!)

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