svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r20849:20855
[blender.git] / source / gameengine / Expressions / InputParser.cpp
1 // Parser.cpp: implementation of the CParser class.
2 /*
3  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
4  *
5  * Permission to use, copy, modify, distribute and sell this software
6  * and its documentation for any purpose is hereby granted without fee,
7  * provided that the above copyright notice appear in all copies and
8  * that both that copyright notice and this permission notice appear
9  * in supporting documentation.  Erwin Coumans makes no
10  * representations about the suitability of this software for any
11  * purpose.  It is provided "as is" without express or implied warranty.
12  *
13  */
14
15 #include <stdlib.h>
16
17 #include "MT_assert.h"
18
19 #include "Value.h"
20 #include "InputParser.h"
21 #include "ErrorValue.h"
22 #include "IntValue.h"
23 #include "StringValue.h"
24 #include "FloatValue.h"
25 #include "BoolValue.h"
26 #include "EmptyValue.h"
27 #include "ConstExpr.h"
28 #include "Operator2Expr.h"
29 #include "Operator1Expr.h"
30 #include "IdentifierExpr.h"
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 // this is disable at the moment, I expected a memleak from it, but the error-cleanup was the reason
37 // well, looks we don't need it anyway, until maybe the Curved Surfaces are integrated into CSG 
38 // cool things like (IF(LOD==1,CCurvedValue,IF(LOD==2,CCurvedValue2)) etc...
39 #include "IfExpr.h" 
40
41 #if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS)
42 #define strcasecmp      _stricmp
43
44 #ifndef strtoll
45 #define strtoll         _strtoi64
46 #endif
47
48 #endif /* Def WIN32 or Def WIN64 */
49
50 #define NUM_PRIORITY 6
51 //////////////////////////////////////////////////////////////////////
52 // Construction/Destruction
53 //////////////////////////////////////////////////////////////////////
54
55 CParser::CParser() : m_identifierContext(NULL)
56 {
57 }
58
59
60
61 CParser::~CParser()
62 {
63         if (m_identifierContext)
64                 m_identifierContext->Release();
65 }
66
67
68
69 void CParser::ScanError(const char *str)
70 {
71         // sets the global variable errmsg to an errormessage with
72         // contents str, appending if it already exists
73         //      AfxMessageBox("Parse Error:"+str,MB_ICONERROR);
74         if (errmsg)
75                 errmsg = new COperator2Expr(VALUE_ADD_OPERATOR, errmsg, Error(str));
76         else
77                 errmsg = Error(str);
78
79         sym = errorsym;
80 }
81
82
83
84 CExpression* CParser::Error(const char *str)
85 {
86         // makes and returns a new CConstExpr filled with an CErrorValue
87         // with string str
88         //      AfxMessageBox("Error:"+str,MB_ICONERROR);
89         return new CConstExpr(new CErrorValue(str));
90 }
91
92
93
94 void CParser::NextCh()
95 {
96         // sets the global variable ch to the next character, if it exists
97         // and increases the global variable chcount
98         chcount++;
99
100         if (chcount < text.Length())
101                 ch = text[chcount];
102         else
103                 ch = 0x00;
104 }
105
106
107
108 void CParser::TermChar(char c)
109 {
110         // generates an error if the next char isn't the specified char c,
111         // otherwise, skip the char
112         if(ch == c)
113         {
114                 NextCh();
115         }
116         else
117         {
118                 STR_String str;
119                 str.Format("Warning: %c expected\ncontinuing without it", c);
120                 trace(str);
121         }
122 }
123
124
125
126 void CParser::DigRep()
127 {
128         // changes the current character to the first character that
129         // isn't a decimal
130         while ((ch >= '0') && (ch <= '9'))
131                 NextCh();
132 }
133
134
135
136 void CParser::CharRep()
137 {
138         // changes the current character to the first character that
139         // isn't an alphanumeric character
140         while (((ch >= '0') && (ch <= '9'))
141                 || ((ch >= 'a') && (ch <= 'z'))
142                 || ((ch >= 'A') && (ch <= 'Z'))
143                 || (ch == '.') || (ch == '_'))
144                 NextCh();
145 }
146
147
148
149 void CParser::GrabString(int start)
150 {
151         // puts part of the input string into the global variable
152         // const_as_string, from position start, to position chchount
153         const_as_string = text.Mid(start, chcount-start);
154 }
155
156
157
158 void CParser::NextSym()
159 {
160         // sets the global variable sym to the next symbol, and
161         // if it is an operator
162         //   sets the global variable opkind to the kind of operator
163         // if it is a constant
164         //   sets the global variable constkind to the kind of operator
165         // if it is a reference to a cell
166         //   sets the global variable cellcoord to the kind of operator
167         
168         errmsg = NULL;
169         while(ch == ' ' || ch == 0x9)
170                 NextCh();
171
172         switch(ch)
173         {
174     case '(':
175                 sym = lbracksym; NextCh();
176                 break;
177     case ')':
178                 sym = rbracksym; NextCh();
179                 break;
180     case ',':
181                 sym = commasym; NextCh();
182                 break;
183         case '%' :
184                 sym = opsym; opkind = OPmodulus; NextCh();
185                 break;
186     case '+' :
187                 sym = opsym; opkind = OPplus; NextCh();
188                 break;
189     case '-' :
190                 sym = opsym; opkind = OPminus; NextCh();
191                 break;
192     case '*' :
193                 sym = opsym; opkind = OPtimes; NextCh();
194                 break;
195     case '/' :
196                 sym = opsym; opkind = OPdivide; NextCh();
197                 break;
198         case '&' :
199                 sym = opsym; opkind = OPand; NextCh(); TermChar('&');
200                 break;
201         case '|' :
202                 sym = opsym; opkind = OPor; NextCh(); TermChar('|');
203                 break;
204         case '=' :
205                 sym = opsym; opkind = OPequal; NextCh(); TermChar('=');
206                 break;
207         case '!' :
208                 sym = opsym;
209                 NextCh();
210                 if (ch == '=')
211                 {
212                         opkind = OPunequal;
213                         NextCh();
214                 }
215                 else
216                 {
217                         opkind = OPnot;
218                 }
219                 break;
220         case '>':
221                 sym = opsym;
222                 NextCh();
223                 if (ch == '=')
224                 {
225                         opkind = OPgreaterequal;
226                         NextCh();
227                 }
228                 else
229                 {
230                         opkind = OPgreater;
231                 }
232                 break;
233         case '<':
234                 sym = opsym;
235                 NextCh();
236                 if (ch == '=') {
237                         opkind = OPlessequal;
238                         NextCh();
239                 } else {
240                         opkind = OPless;
241                 }
242                 break;
243     case '\"' : {
244                 int start;
245                 sym = constsym;
246                 constkind = stringtype;
247                 NextCh();
248                 start = chcount;
249                 while ((ch != '\"') && (ch != 0x0))
250                         NextCh();
251                 GrabString(start);
252                 TermChar('\"'); // check for eol before '\"'
253                 break;
254                                 }
255     case 0x0: sym = eolsym; break;
256     default: 
257                 {
258                         int start;
259                         start = chcount;
260                         DigRep();
261                         if ((start != chcount) || (ch == '.')) { // number
262                                 sym = constsym;
263                                 if (ch == '.') {
264                                         constkind = floattype;
265                                         NextCh();
266                                         DigRep();
267                                 }
268                                 else constkind = inttype;
269                                 if ((ch == 'e') || (ch == 'E')) {
270                                         int mark;
271                                         constkind = floattype;
272                                         NextCh();
273                                         if ((ch == '+') || (ch == '-')) NextCh();
274                                         mark = chcount;
275                                         DigRep();
276                                         if (mark == chcount) {
277                                                 ScanError("Number expected after 'E'");
278                                                 return;
279                                         }
280                                 }
281                                 GrabString(start);
282                         } else if (((ch >= 'a') && (ch <= 'z'))
283                                 || ((ch >= 'A') && (ch <= 'Z')))
284                         { // reserved word?
285                                 
286                                 start = chcount;
287                                 CharRep();
288                                 GrabString(start);
289                                 if (!strcasecmp(const_as_string, "SUM")) {
290                                         sym = sumsym;
291                                 }
292                                 else if (!strcasecmp(const_as_string, "NOT")) {
293                                         sym = opsym;
294                                         opkind = OPnot;
295                                 }
296                                 else if (!strcasecmp(const_as_string, "AND")) {
297                                         sym = opsym; opkind = OPand;
298                                 }
299                                 else if (!strcasecmp(const_as_string, "OR")) {
300                                         sym = opsym; opkind = OPor;
301                                 }
302                                 else if (!strcasecmp(const_as_string, "IF"))
303                                         sym = ifsym;
304                                 else if (!strcasecmp(const_as_string, "WHOMADE"))
305                                         sym = whocodedsym;
306                                 else if (!strcasecmp(const_as_string, "FALSE")) {
307                                         sym = constsym; constkind = booltype; boolvalue = false;
308                                 } else if (!strcasecmp(const_as_string, "TRUE")) {
309                                         sym = constsym; constkind = booltype; boolvalue = true;
310                                 } else {
311                                         sym = idsym;
312                                         //STR_String str;
313                                         //str.Format("'%s' makes no sense here", (const char*)funstr);
314                                         //ScanError(str);
315                                 }
316                         } else { // unknown symbol
317                                 STR_String str;
318                                 str.Format("Unexpected character '%c'", ch);
319                                 NextCh();
320                                 ScanError(str);
321                                 return;
322                         }
323                 }
324         }
325 }
326
327 #if 0
328 int CParser::MakeInt() {
329         // returns the integer representation of the value in the global
330         // variable const_as_string
331         // pre: const_as_string contains only numercal chars
332         return atoi(const_as_string);
333 }
334 #endif
335
336 STR_String CParser::Symbol2Str(int s) {
337         // returns a string representation of of symbol s,
338         // for use in Term when generating an error
339         switch(s) {
340     case errorsym: return "error";
341     case lbracksym: return "(";
342     case rbracksym: return ")";
343     case commasym: return ",";
344     case opsym: return "operator";
345     case constsym: return "constant";
346         case sumsym: return "SUM";
347         case ifsym: return "IF";
348         case whocodedsym: return "WHOMADE";
349     case eolsym: return "end of line";
350         case idsym: return "identifier";
351     default: return "unknown";  // should not happen
352         }
353 }
354
355 void CParser::Term(int s) {
356         // generates an error if the next symbol isn't the specified symbol s
357         // otherwise, skip the symbol
358         if(s == sym) NextSym();
359         else {
360                 STR_String msg;
361                 msg.Format("Warning: " + Symbol2Str(s) + " expected\ncontinuing without it");
362
363 //              AfxMessageBox(msg,MB_ICONERROR);
364
365                 trace(msg);
366         }
367 }
368
369 int CParser::Priority(int optorkind) {
370         // returns the priority of an operator
371         // higher number means higher priority
372         switch(optorkind) {
373         case OPor: return 1;
374         case OPand: return 2;
375         case OPgreater:
376         case OPless:
377         case OPgreaterequal:
378         case OPlessequal:
379         case OPequal:
380         case OPunequal: return 3;
381     case OPplus:
382     case OPminus: return 4;
383         case OPmodulus:
384     case OPtimes:
385     case OPdivide: return 5;
386         }
387         MT_assert(false);
388         return 0;      // should not happen
389 }
390
391 CExpression *CParser::Ex(int i) {
392         // parses an expression in the imput, starting at priority i, and
393         // returns an CExpression, containing the parsed input
394         CExpression *e1 = NULL, *e2 = NULL;
395         int opkind2;
396         
397         if (i < NUM_PRIORITY) {
398                 e1 = Ex(i + 1);
399                 while ((sym == opsym) && (Priority(opkind) == i)) {
400                         opkind2 = opkind;
401                         NextSym();
402                         e2 = Ex(i + 1);
403                         switch(opkind2) {
404                         case OPmodulus: e1 = new COperator2Expr(VALUE_MOD_OPERATOR,e1, e2); break;
405                         case OPplus: e1 = new COperator2Expr(VALUE_ADD_OPERATOR,e1, e2); break;
406                         case OPminus: e1 = new COperator2Expr(VALUE_SUB_OPERATOR,e1, e2); break;
407                         case OPtimes:   e1 = new COperator2Expr(VALUE_MUL_OPERATOR,e1, e2); break;
408                         case OPdivide: e1 = new COperator2Expr(VALUE_DIV_OPERATOR,e1, e2); break;
409                         case OPand: e1 = new COperator2Expr(VALUE_AND_OPERATOR,e1, e2); break;
410                         case OPor: e1 = new COperator2Expr(VALUE_OR_OPERATOR,e1, e2); break;
411                         case OPequal: e1 = new COperator2Expr(VALUE_EQL_OPERATOR,e1, e2); break;
412                         case OPunequal: e1 = new COperator2Expr(VALUE_NEQ_OPERATOR,e1, e2); break;
413                         case OPgreater: e1 = new COperator2Expr(VALUE_GRE_OPERATOR,e1, e2); break;
414                         case OPless: e1 = new COperator2Expr(VALUE_LES_OPERATOR,e1, e2); break;
415                         case OPgreaterequal: e1 = new COperator2Expr(VALUE_GEQ_OPERATOR,e1, e2); break;
416                         case OPlessequal: e1 = new COperator2Expr(VALUE_LEQ_OPERATOR,e1, e2); break;
417                         default: MT_assert(false);      break; // should not happen
418                         }
419                 }
420         } else if (i == NUM_PRIORITY) {
421                 if ((sym == opsym) 
422                         && ( (opkind == OPminus) || (opkind == OPnot) || (opkind == OPplus) ) 
423                         )
424                 {
425                         NextSym();
426                         switch(opkind) {
427                         /* +1 is also a valid number! */
428                         case OPplus: e1 = new COperator1Expr(VALUE_POS_OPERATOR, Ex(NUM_PRIORITY)); break;
429                         case OPminus: e1 = new COperator1Expr(VALUE_NEG_OPERATOR, Ex(NUM_PRIORITY)); break;
430                         case OPnot: e1 = new COperator1Expr(VALUE_NOT_OPERATOR, Ex(NUM_PRIORITY)); break;
431                         default: {
432                                                 // should not happen
433                                                 e1 = Error("operator +, - or ! expected");
434                                          }
435                         }
436                 }
437                 else {
438                         switch(sym) {
439                         case constsym: {
440                                 switch(constkind) {
441                                 case booltype:
442                                         e1 = new CConstExpr(new CBoolValue(boolvalue));
443                                         break;
444                                 case inttype:
445                                         {
446                                                 cInt temp;
447                                                 temp = strtoll(const_as_string, NULL, 10); /* atoi is for int only */
448                                                 e1 = new CConstExpr(new CIntValue(temp));
449                                                 break;
450                                         }
451                                 case floattype:
452                                         {
453                                                 double temp;
454                                                 temp = atof(const_as_string);
455                                                 e1 = new CConstExpr(new CFloatValue(temp));
456                                                 break;
457                                         }
458                                 case stringtype:
459                                         e1 = new CConstExpr(new CStringValue(const_as_string,""));
460                                         break;
461                                 default :
462                                         MT_assert(false);
463                                         break;
464                                 }
465                                 NextSym();
466                                 break;
467                                                    }
468                         case lbracksym:
469                                 NextSym();
470                                 e1 = Ex(1);
471                                 Term(rbracksym);
472                                 break;
473                         case ifsym:
474                         {
475                                 CExpression *e3;
476                                 NextSym();
477                                 Term(lbracksym);
478                                 e1 = Ex(1);
479                                 Term(commasym);
480                                 e2 = Ex(1);
481                                 if (sym == commasym) {
482                                         NextSym();
483                                         e3 = Ex(1);
484                                 } else {
485                                         e3 = new CConstExpr(new CEmptyValue());
486                                 }
487                                 Term(rbracksym);
488                                 e1 = new CIfExpr(e1, e2, e3);
489                                 break;
490                         }
491                         case idsym:
492                                 {
493                                         e1 = new CIdentifierExpr(const_as_string,m_identifierContext);
494                                         NextSym();
495                                         
496                                         break;
497                                 }
498                         case errorsym:
499                                 {
500                                         MT_assert(!e1);
501                                         STR_String errtext="[no info]";
502                                         if (errmsg)
503                                         {
504                                                 CValue* errmsgval = errmsg->Calculate();
505                                                 errtext=errmsgval->GetText();
506                                                 errmsgval->Release();
507                                         
508                                                 //e1 = Error(errmsg->Calculate()->GetText());//new CConstExpr(errmsg->Calculate());
509                                                 
510                                                 if ( !(errmsg->Release()) )
511                                                 {
512                                                         errmsg=NULL;
513                                                 } else {
514                                                         // does this happen ?
515                                                         MT_assert ("does this happen");
516                                                 }
517                                         }
518                                         e1 = Error(errtext);
519
520                                         break;                          
521                                 }
522                         default:
523                                 NextSym();
524                                 //return Error("Expression expected");
525                                 MT_assert(!e1);
526                                 e1 = Error("Expression expected");
527                         }
528                 }
529         }
530         return e1;
531 }
532
533 CExpression *CParser::Expr() {
534         // parses an expression in the imput, and
535         // returns an CExpression, containing the parsed input
536         return Ex(1);
537 }
538
539 CExpression* CParser::ProcessText
540 (const char *intext) {
541         
542         // and parses the string in intext and returns it.
543         
544         
545         CExpression* expr;
546         text = intext;
547         
548         
549         chcount = 0;    
550         if (text.Length() == 0) {
551                 return NULL;
552         }
553         
554         ch = text[0];
555         /*if (ch != '=') {
556         expr = new CConstExpr(new CStringValue(text));
557         *dependant = deplist;
558         return expr;
559         } else 
560         */
561         //      NextCh();
562         NextSym();
563         expr = Expr();
564         if (sym != eolsym) {
565                 CExpression* oldexpr = expr;
566                 expr = new COperator2Expr(VALUE_ADD_OPERATOR,
567                         oldexpr, Error(STR_String("Extra characters after expression")));//new CConstExpr(new CErrorValue("Extra characters after expression")));
568         }
569         if (errmsg)
570                 errmsg->Release();
571         
572         return expr;
573 }
574
575
576
577 float CParser::GetFloat(STR_String& txt)
578 {
579         // returns parsed text into a float
580         // empty string returns -1
581         
582 //      AfxMessageBox("parsed string="+txt);
583         CValue* val=NULL;
584         float result=-1;
585 //      String tmpstr;
586
587         CExpression* expr = ProcessText(txt);
588         if (expr) {
589                 val = expr->Calculate();
590                 result=(float)val->GetNumber();
591                 
592                 
593         
594                 val->Release();
595                 expr->Release();
596         }
597 //      tmpstr.Format("parseresult=%g",result);
598 //              AfxMessageBox(tmpstr);
599         return result;
600 }
601
602 CValue* CParser::GetValue(STR_String& txt, bool bFallbackToText)
603 {
604         // returns parsed text into a value, 
605         // empty string returns NULL value !
606         // if bFallbackToText then unparsed stuff is put into text
607         
608         CValue* result=NULL;
609         CExpression* expr = ProcessText(txt);
610         if (expr) {
611                 result = expr->Calculate();
612                 expr->Release();
613         }
614         if (result)
615         {
616                 // if the parsed stuff lead to an errorvalue, don't return errors, just NULL
617                 if (result->IsError()) {
618                         result->Release();
619                         result=NULL;
620                         if (bFallbackToText) {
621                                 if (txt.Length()>0)
622                                 {
623                                         result = new CStringValue(txt,"");
624                                 }
625                         }
626                 }
627         }
628         return result;
629 }
630
631 void CParser::SetContext(CValue* context)
632 {
633         if (m_identifierContext)
634         {
635                 m_identifierContext->Release();
636         }
637         m_identifierContext = context;
638 }
639
640
641
642
643 PyObject*       CParserPyMake(PyObject* ignored,PyObject* args)
644 {
645         char* txt;
646         if (!PyArg_ParseTuple(args,"s",&txt))
647                 return NULL;
648         CParser parser;
649         CExpression* expr = parser.ProcessText(txt);
650         CValue* val = expr->Calculate();
651         expr->Release();
652         return val->GetProxy();
653 }
654
655 static PyMethodDef      CParserMethods[] = 
656 {
657         { "calc", CParserPyMake , METH_VARARGS},
658         { NULL,NULL}    // Sentinel
659 };
660
661
662 #if (PY_VERSION_HEX >= 0x03000000)
663 static struct PyModuleDef Expression_module_def = {
664         {}, /* m_base */
665         "Expression",  /* m_name */
666         0,  /* m_doc */
667         0,  /* m_size */
668         CParserMethods,  /* m_methods */
669         0,  /* m_reload */
670         0,  /* m_traverse */
671         0,  /* m_clear */
672         0,  /* m_free */
673 };
674 #endif
675
676 extern "C" {
677         void initExpressionModule(void)
678         {
679                 PyObject *m;
680                 /* Use existing module where possible
681                  * be careful not to init any runtime vars after this */
682                 m = PyImport_ImportModule( "Expression" );
683                 if(m) {
684                         Py_DECREF(m);
685                         //return m;
686                 }
687                 else {
688                         PyErr_Clear();
689                 
690 #if (PY_VERSION_HEX >= 0x03000000)
691                         PyModule_Create(&Expression_module_def);
692 #else
693                         Py_InitModule("Expression",CParserMethods);
694 #endif
695                 }
696         }
697 }
698