| 
									
										
										
										
											2011-02-25 13:31:23 +00:00
										 |  |  | /** \file gameengine/Expressions/InputParser.cpp
 | 
					
						
							|  |  |  |  *  \ingroup expressions | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | // Parser.cpp: implementation of the CParser class.
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Permission to use, copy, modify, distribute and sell this software | 
					
						
							|  |  |  |  * and its documentation for any purpose is hereby granted without fee, | 
					
						
							|  |  |  |  * provided that the above copyright notice appear in all copies and | 
					
						
							|  |  |  |  * that both that copyright notice and this permission notice appear | 
					
						
							|  |  |  |  * in supporting documentation.  Erwin Coumans makes no | 
					
						
							|  |  |  |  * representations about the suitability of this software for any | 
					
						
							|  |  |  |  * purpose.  It is provided "as is" without express or implied warranty. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-03-25 10:33:39 +00:00
										 |  |  | #include "MT_assert.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | #include "Value.h"
 | 
					
						
							|  |  |  | #include "InputParser.h"
 | 
					
						
							|  |  |  | #include "ErrorValue.h"
 | 
					
						
							|  |  |  | #include "IntValue.h"
 | 
					
						
							|  |  |  | #include "StringValue.h"
 | 
					
						
							|  |  |  | #include "FloatValue.h"
 | 
					
						
							|  |  |  | #include "BoolValue.h"
 | 
					
						
							|  |  |  | #include "EmptyValue.h"
 | 
					
						
							|  |  |  | #include "ConstExpr.h"
 | 
					
						
							|  |  |  | #include "Operator2Expr.h"
 | 
					
						
							|  |  |  | #include "Operator1Expr.h"
 | 
					
						
							|  |  |  | #include "IdentifierExpr.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // this is disable at the moment, I expected a memleak from it, but the error-cleanup was the reason
 | 
					
						
							|  |  |  | // well, looks we don't need it anyway, until maybe the Curved Surfaces are integrated into CSG 
 | 
					
						
							|  |  |  | // cool things like (IF(LOD==1,CCurvedValue,IF(LOD==2,CCurvedValue2)) etc...
 | 
					
						
							|  |  |  | #include "IfExpr.h" 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-27 07:07:22 +00:00
										 |  |  | #if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS)
 | 
					
						
							| 
									
										
										
										
											2009-04-12 10:56:36 +00:00
										 |  |  | #define strcasecmp	_stricmp
 | 
					
						
							| 
									
										
										
										
											2009-04-12 22:05:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifndef strtoll
 | 
					
						
							| 
									
										
										
										
											2009-04-12 10:56:36 +00:00
										 |  |  | #define strtoll		_strtoi64
 | 
					
						
							| 
									
										
										
										
											2009-04-12 22:05:09 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-19 23:13:41 +00:00
										 |  |  | #endif /* Def WIN32 or Def WIN64 */
 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define NUM_PRIORITY 6
 | 
					
						
							|  |  |  | //////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // Construction/Destruction
 | 
					
						
							|  |  |  | //////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CParser::CParser() : m_identifierContext(NULL) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CParser::~CParser() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (m_identifierContext) | 
					
						
							|  |  |  | 		m_identifierContext->Release(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-10 20:53:58 +00:00
										 |  |  | void CParser::ScanError(const char *str) | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	// sets the global variable errmsg to an errormessage with
 | 
					
						
							|  |  |  | 	// contents str, appending if it already exists
 | 
					
						
							|  |  |  | 	//	AfxMessageBox("Parse Error:"+str,MB_ICONERROR);
 | 
					
						
							|  |  |  | 	if (errmsg) | 
					
						
							|  |  |  | 		errmsg = new COperator2Expr(VALUE_ADD_OPERATOR, errmsg,	Error(str)); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		errmsg = Error(str); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sym = errorsym; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-10 20:53:58 +00:00
										 |  |  | CExpression* CParser::Error(const char *str) | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	// makes and returns a new CConstExpr filled with an CErrorValue
 | 
					
						
							|  |  |  | 	// with string str
 | 
					
						
							|  |  |  | 	//	AfxMessageBox("Error:"+str,MB_ICONERROR);
 | 
					
						
							|  |  |  | 	return new CConstExpr(new CErrorValue(str)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CParser::NextCh() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// sets the global variable ch to the next character, if it exists
 | 
					
						
							|  |  |  | 	// and increases the global variable chcount
 | 
					
						
							|  |  |  | 	chcount++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (chcount < text.Length()) | 
					
						
							|  |  |  | 		ch = text[chcount]; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		ch = 0x00; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CParser::TermChar(char c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// generates an error if the next char isn't the specified char c,
 | 
					
						
							|  |  |  | 	// otherwise, skip the char
 | 
					
						
							|  |  |  | 	if(ch == c) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		NextCh(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		STR_String str; | 
					
						
							|  |  |  | 		str.Format("Warning: %c expected\ncontinuing without it", c); | 
					
						
							|  |  |  | 		trace(str); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CParser::DigRep() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// changes the current character to the first character that
 | 
					
						
							|  |  |  | 	// isn't a decimal
 | 
					
						
							|  |  |  | 	while ((ch >= '0') && (ch <= '9')) | 
					
						
							|  |  |  | 		NextCh(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CParser::CharRep() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// changes the current character to the first character that
 | 
					
						
							|  |  |  | 	// isn't an alphanumeric character
 | 
					
						
							|  |  |  | 	while (((ch >= '0') && (ch <= '9')) | 
					
						
							|  |  |  | 		|| ((ch >= 'a') && (ch <= 'z')) | 
					
						
							|  |  |  | 		|| ((ch >= 'A') && (ch <= 'Z')) | 
					
						
							|  |  |  | 		|| (ch == '.') || (ch == '_')) | 
					
						
							|  |  |  | 		NextCh(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CParser::GrabString(int start) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// puts part of the input string into the global variable
 | 
					
						
							|  |  |  | 	// const_as_string, from position start, to position chchount
 | 
					
						
							|  |  |  | 	const_as_string = text.Mid(start, chcount-start); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-18 10:10:48 +00:00
										 |  |  | void CParser::GrabRealString(int start) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// works like GrabString but converting \\n to \n
 | 
					
						
							|  |  |  | 	// puts part of the input string into the global variable
 | 
					
						
							|  |  |  | 	// const_as_string, from position start, to position chchount
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	char tmpch; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const_as_string = STR_String(); | 
					
						
							|  |  |  | 	for (i=start;i<chcount;i++) { | 
					
						
							|  |  |  | 		tmpch= text[i]; | 
					
						
							|  |  |  | 		if ((tmpch =='\\') && (text[i+1] == 'n')){ | 
					
						
							|  |  |  | 			tmpch = '\n'; | 
					
						
							|  |  |  | 			i++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		const_as_string += tmpch; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | void CParser::NextSym() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// sets the global variable sym to the next symbol, and
 | 
					
						
							|  |  |  | 	// if it is an operator
 | 
					
						
							|  |  |  | 	//   sets the global variable opkind to the kind of operator
 | 
					
						
							|  |  |  | 	// if it is a constant
 | 
					
						
							|  |  |  | 	//   sets the global variable constkind to the kind of operator
 | 
					
						
							|  |  |  | 	// if it is a reference to a cell
 | 
					
						
							|  |  |  | 	//   sets the global variable cellcoord to the kind of operator
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	errmsg = NULL; | 
					
						
							|  |  |  | 	while(ch == ' ' || ch == 0x9) | 
					
						
							|  |  |  | 		NextCh(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch(ch) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-09-01 02:12:53 +00:00
										 |  |  | 		case '(': | 
					
						
							|  |  |  | 			sym = lbracksym; NextCh(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case ')': | 
					
						
							|  |  |  | 			sym = rbracksym; NextCh(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case ',': | 
					
						
							|  |  |  | 			sym = commasym; NextCh(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '%' : | 
					
						
							|  |  |  | 			sym = opsym; opkind = OPmodulus; NextCh(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '+' : | 
					
						
							|  |  |  | 			sym = opsym; opkind = OPplus; NextCh(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '-' : | 
					
						
							|  |  |  | 			sym = opsym; opkind = OPminus; NextCh(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '*' : | 
					
						
							|  |  |  | 			sym = opsym; opkind = OPtimes; NextCh(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '/' : | 
					
						
							|  |  |  | 			sym = opsym; opkind = OPdivide; NextCh(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '&' : | 
					
						
							|  |  |  | 			sym = opsym; opkind = OPand; NextCh(); TermChar('&'); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '|' : | 
					
						
							|  |  |  | 			sym = opsym; opkind = OPor; NextCh(); TermChar('|'); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '=' : | 
					
						
							|  |  |  | 			sym = opsym; opkind = OPequal; NextCh(); TermChar('='); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '!' : | 
					
						
							|  |  |  | 			sym = opsym; | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 			NextCh(); | 
					
						
							| 
									
										
										
										
											2011-09-01 02:12:53 +00:00
										 |  |  | 			if (ch == '=') | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				opkind = OPunequal; | 
					
						
							|  |  |  | 				NextCh(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				opkind = OPnot; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '>': | 
					
						
							|  |  |  | 			sym = opsym; | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 			NextCh(); | 
					
						
							| 
									
										
										
										
											2011-09-01 02:12:53 +00:00
										 |  |  | 			if (ch == '=') | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				opkind = OPgreaterequal; | 
					
						
							|  |  |  | 				NextCh(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				opkind = OPgreater; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '<': | 
					
						
							|  |  |  | 			sym = opsym; | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 			NextCh(); | 
					
						
							| 
									
										
										
										
											2011-09-01 02:12:53 +00:00
										 |  |  | 			if (ch == '=') { | 
					
						
							|  |  |  | 				opkind = OPlessequal; | 
					
						
							|  |  |  | 				NextCh(); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				opkind = OPless; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '\"' : { | 
					
						
							|  |  |  | 			int start; | 
					
						
							|  |  |  | 			sym = constsym; | 
					
						
							|  |  |  | 			constkind = stringtype; | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 			NextCh(); | 
					
						
							| 
									
										
										
										
											2011-09-01 02:12:53 +00:00
										 |  |  | 			start = chcount; | 
					
						
							|  |  |  | 			while ((ch != '\"') && (ch != 0x0)) | 
					
						
							|  |  |  | 				NextCh(); | 
					
						
							|  |  |  | 			GrabRealString(start); | 
					
						
							|  |  |  | 			TermChar('\"');	// check for eol before '\"'
 | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		case 0x0: sym = eolsym; break; | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			int start; | 
					
						
							|  |  |  | 			start = chcount; | 
					
						
							|  |  |  | 			DigRep(); | 
					
						
							|  |  |  | 			if ((start != chcount) || (ch == '.')) { // number
 | 
					
						
							|  |  |  | 				sym = constsym; | 
					
						
							|  |  |  | 				if (ch == '.') { | 
					
						
							|  |  |  | 					constkind = floattype; | 
					
						
							|  |  |  | 					NextCh(); | 
					
						
							|  |  |  | 					DigRep(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else constkind = inttype; | 
					
						
							|  |  |  | 				if ((ch == 'e') || (ch == 'E')) { | 
					
						
							|  |  |  | 					int mark; | 
					
						
							|  |  |  | 					constkind = floattype; | 
					
						
							|  |  |  | 					NextCh(); | 
					
						
							|  |  |  | 					if ((ch == '+') || (ch == '-')) NextCh(); | 
					
						
							|  |  |  | 					mark = chcount; | 
					
						
							|  |  |  | 					DigRep(); | 
					
						
							|  |  |  | 					if (mark == chcount) { | 
					
						
							|  |  |  | 						ScanError("Number expected after 'E'"); | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				GrabString(start); | 
					
						
							|  |  |  | 			} else if (((ch >= 'a') && (ch <= 'z')) | 
					
						
							| 
									
										
										
										
											2011-09-01 02:12:53 +00:00
										 |  |  | 			           || ((ch >= 'A') && (ch <= 'Z'))) | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 			{ // reserved word?
 | 
					
						
							| 
									
										
										
										
											2009-02-25 03:26:02 +00:00
										 |  |  | 				 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 				start = chcount; | 
					
						
							|  |  |  | 				CharRep(); | 
					
						
							|  |  |  | 				GrabString(start); | 
					
						
							| 
									
										
										
										
											2009-02-19 07:01:49 +00:00
										 |  |  | 				if (!strcasecmp(const_as_string, "SUM")) { | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					sym = sumsym; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2009-02-19 07:01:49 +00:00
										 |  |  | 				else if (!strcasecmp(const_as_string, "NOT")) { | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					sym = opsym; | 
					
						
							|  |  |  | 					opkind = OPnot; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2009-02-19 07:01:49 +00:00
										 |  |  | 				else if (!strcasecmp(const_as_string, "AND")) { | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					sym = opsym; opkind = OPand; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2009-02-19 07:01:49 +00:00
										 |  |  | 				else if (!strcasecmp(const_as_string, "OR")) { | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					sym = opsym; opkind = OPor; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2009-02-19 07:01:49 +00:00
										 |  |  | 				else if (!strcasecmp(const_as_string, "IF")) | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					sym = ifsym; | 
					
						
							| 
									
										
										
										
											2009-02-19 07:01:49 +00:00
										 |  |  | 				else if (!strcasecmp(const_as_string, "WHOMADE")) | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					sym = whocodedsym; | 
					
						
							| 
									
										
										
										
											2009-02-19 07:01:49 +00:00
										 |  |  | 				else if (!strcasecmp(const_as_string, "FALSE")) { | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					sym = constsym; constkind = booltype; boolvalue = false; | 
					
						
							| 
									
										
										
										
											2009-02-19 07:01:49 +00:00
										 |  |  | 				} else if (!strcasecmp(const_as_string, "TRUE")) { | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					sym = constsym; constkind = booltype; boolvalue = true; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					sym = idsym; | 
					
						
							|  |  |  | 					//STR_String str;
 | 
					
						
							|  |  |  | 					//str.Format("'%s' makes no sense here", (const char*)funstr);
 | 
					
						
							|  |  |  | 					//ScanError(str);
 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { // unknown symbol
 | 
					
						
							|  |  |  | 				STR_String str; | 
					
						
							|  |  |  | 				str.Format("Unexpected character '%c'", ch); | 
					
						
							|  |  |  | 				NextCh(); | 
					
						
							|  |  |  | 				ScanError(str); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-12 06:41:01 +00:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | int CParser::MakeInt() { | 
					
						
							|  |  |  | 	// returns the integer representation of the value in the global
 | 
					
						
							|  |  |  | 	// variable const_as_string
 | 
					
						
							|  |  |  | 	// pre: const_as_string contains only numercal chars
 | 
					
						
							|  |  |  | 	return atoi(const_as_string); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-04-12 06:41:01 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | STR_String CParser::Symbol2Str(int s) { | 
					
						
							|  |  |  | 	// returns a string representation of of symbol s,
 | 
					
						
							|  |  |  | 	// for use in Term when generating an error
 | 
					
						
							|  |  |  | 	switch(s) { | 
					
						
							| 
									
										
										
										
											2011-09-01 02:12:53 +00:00
										 |  |  | 		case errorsym: return "error"; | 
					
						
							|  |  |  | 		case lbracksym: return "("; | 
					
						
							|  |  |  | 		case rbracksym: return ")"; | 
					
						
							|  |  |  | 		case commasym: return ","; | 
					
						
							|  |  |  | 		case opsym: return "operator"; | 
					
						
							|  |  |  | 		case constsym: return "constant"; | 
					
						
							|  |  |  | 		case sumsym: return "SUM"; | 
					
						
							|  |  |  | 		case ifsym: return "IF"; | 
					
						
							|  |  |  | 		case whocodedsym: return "WHOMADE"; | 
					
						
							|  |  |  | 		case eolsym: return "end of line"; | 
					
						
							|  |  |  | 		case idsym: return "identifier"; | 
					
						
							|  |  |  | 		default: return "unknown";  // should not happen
 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CParser::Term(int s) { | 
					
						
							|  |  |  | 	// generates an error if the next symbol isn't the specified symbol s
 | 
					
						
							|  |  |  | 	// otherwise, skip the symbol
 | 
					
						
							|  |  |  | 	if(s == sym) NextSym(); | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		STR_String msg; | 
					
						
							|  |  |  | 		msg.Format("Warning: " + Symbol2Str(s) + " expected\ncontinuing without it"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //		AfxMessageBox(msg,MB_ICONERROR);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		trace(msg); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CParser::Priority(int optorkind) { | 
					
						
							|  |  |  | 	// returns the priority of an operator
 | 
					
						
							|  |  |  | 	// higher number means higher priority
 | 
					
						
							|  |  |  | 	switch(optorkind) { | 
					
						
							| 
									
										
										
										
											2011-09-01 02:12:53 +00:00
										 |  |  | 		case OPor: return 1; | 
					
						
							|  |  |  | 		case OPand: return 2; | 
					
						
							|  |  |  | 		case OPgreater: | 
					
						
							|  |  |  | 		case OPless: | 
					
						
							|  |  |  | 		case OPgreaterequal: | 
					
						
							|  |  |  | 		case OPlessequal: | 
					
						
							|  |  |  | 		case OPequal: | 
					
						
							|  |  |  | 		case OPunequal: return 3; | 
					
						
							|  |  |  | 		case OPplus: | 
					
						
							|  |  |  | 		case OPminus: return 4; | 
					
						
							|  |  |  | 		case OPmodulus: | 
					
						
							|  |  |  | 		case OPtimes: | 
					
						
							|  |  |  | 		case OPdivide: return 5; | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-03-25 10:33:39 +00:00
										 |  |  | 	MT_assert(false); | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 	return 0;      // should not happen
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CExpression *CParser::Ex(int i) { | 
					
						
							|  |  |  | 	// parses an expression in the imput, starting at priority i, and
 | 
					
						
							|  |  |  | 	// returns an CExpression, containing the parsed input
 | 
					
						
							|  |  |  | 	CExpression *e1 = NULL, *e2 = NULL; | 
					
						
							|  |  |  | 	int opkind2; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (i < NUM_PRIORITY) { | 
					
						
							|  |  |  | 		e1 = Ex(i + 1); | 
					
						
							|  |  |  | 		while ((sym == opsym) && (Priority(opkind) == i)) { | 
					
						
							|  |  |  | 			opkind2 = opkind; | 
					
						
							|  |  |  | 			NextSym(); | 
					
						
							|  |  |  | 			e2 = Ex(i + 1); | 
					
						
							|  |  |  | 			switch(opkind2) { | 
					
						
							| 
									
										
										
										
											2009-03-11 22:11:52 +00:00
										 |  |  | 			case OPmodulus: e1 = new COperator2Expr(VALUE_MOD_OPERATOR,e1, e2); break; | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 			case OPplus: e1 = new COperator2Expr(VALUE_ADD_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPminus: e1 = new COperator2Expr(VALUE_SUB_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPtimes:	e1 = new COperator2Expr(VALUE_MUL_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPdivide: e1 = new COperator2Expr(VALUE_DIV_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPand: e1 = new COperator2Expr(VALUE_AND_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPor: e1 = new COperator2Expr(VALUE_OR_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPequal: e1 = new COperator2Expr(VALUE_EQL_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPunequal: e1 = new COperator2Expr(VALUE_NEQ_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPgreater: e1 = new COperator2Expr(VALUE_GRE_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPless: e1 = new COperator2Expr(VALUE_LES_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPgreaterequal: e1 = new COperator2Expr(VALUE_GEQ_OPERATOR,e1, e2); break; | 
					
						
							|  |  |  | 			case OPlessequal: e1 = new COperator2Expr(VALUE_LEQ_OPERATOR,e1, e2); break; | 
					
						
							| 
									
										
										
										
											2005-03-25 10:33:39 +00:00
										 |  |  | 			default: MT_assert(false);	break; // should not happen
 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if (i == NUM_PRIORITY) { | 
					
						
							|  |  |  | 		if ((sym == opsym)  | 
					
						
							|  |  |  | 			&& ( (opkind == OPminus) || (opkind == OPnot) || (opkind == OPplus) )  | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			NextSym(); | 
					
						
							|  |  |  | 			switch(opkind) { | 
					
						
							|  |  |  | 			/* +1 is also a valid number! */ | 
					
						
							|  |  |  | 			case OPplus: e1 = new COperator1Expr(VALUE_POS_OPERATOR, Ex(NUM_PRIORITY)); break; | 
					
						
							|  |  |  | 			case OPminus: e1 = new COperator1Expr(VALUE_NEG_OPERATOR, Ex(NUM_PRIORITY)); break; | 
					
						
							|  |  |  | 			case OPnot: e1 = new COperator1Expr(VALUE_NOT_OPERATOR, Ex(NUM_PRIORITY)); break; | 
					
						
							|  |  |  | 			default: { | 
					
						
							|  |  |  | 						// should not happen
 | 
					
						
							|  |  |  | 						e1 = Error("operator +, - or ! expected"); | 
					
						
							|  |  |  | 					 } | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			switch(sym) { | 
					
						
							|  |  |  | 			case constsym: { | 
					
						
							|  |  |  | 				switch(constkind) { | 
					
						
							|  |  |  | 				case booltype: | 
					
						
							|  |  |  | 					e1 = new CConstExpr(new CBoolValue(boolvalue)); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				case inttype: | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2009-04-12 06:41:01 +00:00
										 |  |  | 						cInt temp; | 
					
						
							|  |  |  | 						temp = strtoll(const_as_string, NULL, 10); /* atoi is for int only */ | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 						e1 = new CConstExpr(new CIntValue(temp)); | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				case floattype: | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						double temp; | 
					
						
							|  |  |  | 						temp = atof(const_as_string); | 
					
						
							|  |  |  | 						e1 = new CConstExpr(new CFloatValue(temp)); | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				case stringtype: | 
					
						
							|  |  |  | 					e1 = new CConstExpr(new CStringValue(const_as_string,"")); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				default : | 
					
						
							| 
									
										
										
										
											2005-03-25 10:33:39 +00:00
										 |  |  | 					MT_assert(false); | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				NextSym(); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 						   } | 
					
						
							|  |  |  | 			case lbracksym: | 
					
						
							|  |  |  | 				NextSym(); | 
					
						
							|  |  |  | 				e1 = Ex(1); | 
					
						
							|  |  |  | 				Term(rbracksym); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case ifsym: | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				CExpression *e3; | 
					
						
							|  |  |  | 				NextSym(); | 
					
						
							|  |  |  | 				Term(lbracksym); | 
					
						
							|  |  |  | 				e1 = Ex(1); | 
					
						
							|  |  |  | 				Term(commasym); | 
					
						
							|  |  |  | 				e2 = Ex(1); | 
					
						
							|  |  |  | 				if (sym == commasym) { | 
					
						
							|  |  |  | 					NextSym(); | 
					
						
							|  |  |  | 					e3 = Ex(1); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					e3 = new CConstExpr(new CEmptyValue()); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				Term(rbracksym); | 
					
						
							|  |  |  | 				e1 = new CIfExpr(e1, e2, e3); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			case idsym: | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					e1 = new CIdentifierExpr(const_as_string,m_identifierContext); | 
					
						
							|  |  |  | 					NextSym(); | 
					
						
							|  |  |  | 					 | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			case errorsym: | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2005-03-25 10:33:39 +00:00
										 |  |  | 					MT_assert(!e1); | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 					STR_String errtext="[no info]"; | 
					
						
							|  |  |  | 					if (errmsg) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						CValue* errmsgval = errmsg->Calculate(); | 
					
						
							|  |  |  | 						errtext=errmsgval->GetText(); | 
					
						
							|  |  |  | 						errmsgval->Release(); | 
					
						
							|  |  |  | 					 | 
					
						
							|  |  |  | 						//e1 = Error(errmsg->Calculate()->GetText());//new CConstExpr(errmsg->Calculate());
 | 
					
						
							|  |  |  | 						 | 
					
						
							|  |  |  | 						if ( !(errmsg->Release()) ) | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							errmsg=NULL; | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							// does this happen ?
 | 
					
						
							| 
									
										
										
										
											2005-03-25 10:33:39 +00:00
										 |  |  | 							MT_assert ("does this happen"); | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					e1 = Error(errtext); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					break;				 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				NextSym(); | 
					
						
							|  |  |  | 				//return Error("Expression expected");
 | 
					
						
							| 
									
										
										
										
											2005-03-25 10:33:39 +00:00
										 |  |  | 				MT_assert(!e1); | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 				e1 = Error("Expression expected"); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return e1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CExpression *CParser::Expr() { | 
					
						
							|  |  |  | 	// parses an expression in the imput, and
 | 
					
						
							|  |  |  | 	// returns an CExpression, containing the parsed input
 | 
					
						
							|  |  |  | 	return Ex(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CExpression* CParser::ProcessText | 
					
						
							| 
									
										
										
										
											2009-05-10 20:53:58 +00:00
										 |  |  | (const char *intext) { | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	// and parses the string in intext and returns it.
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	CExpression* expr; | 
					
						
							|  |  |  | 	text = intext; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	chcount = 0;	 | 
					
						
							|  |  |  | 	if (text.Length() == 0) { | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	ch = text[0]; | 
					
						
							|  |  |  | 	/*if (ch != '=') {
 | 
					
						
							|  |  |  | 	expr = new CConstExpr(new CStringValue(text)); | 
					
						
							|  |  |  | 	*dependant = deplist; | 
					
						
							|  |  |  | 	return expr; | 
					
						
							|  |  |  | 	} else  | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	//	NextCh();
 | 
					
						
							|  |  |  | 	NextSym(); | 
					
						
							|  |  |  | 	expr = Expr(); | 
					
						
							|  |  |  | 	if (sym != eolsym) { | 
					
						
							|  |  |  | 		CExpression* oldexpr = expr; | 
					
						
							|  |  |  | 		expr = new COperator2Expr(VALUE_ADD_OPERATOR, | 
					
						
							|  |  |  | 			oldexpr, Error(STR_String("Extra characters after expression")));//new CConstExpr(new CErrorValue("Extra characters after expression")));
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (errmsg) | 
					
						
							|  |  |  | 		errmsg->Release(); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return expr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-10 20:53:58 +00:00
										 |  |  | float CParser::GetFloat(STR_String& txt) | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	// returns parsed text into a float
 | 
					
						
							|  |  |  | 	// empty string returns -1
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | //	AfxMessageBox("parsed string="+txt);
 | 
					
						
							|  |  |  | 	CValue* val=NULL; | 
					
						
							|  |  |  | 	float result=-1; | 
					
						
							|  |  |  | //	String tmpstr;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CExpression* expr = ProcessText(txt); | 
					
						
							|  |  |  | 	if (expr) { | 
					
						
							|  |  |  | 		val = expr->Calculate(); | 
					
						
							| 
									
										
										
										
											2009-04-12 06:41:01 +00:00
										 |  |  | 		result=(float)val->GetNumber(); | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 		val->Release(); | 
					
						
							|  |  |  | 		expr->Release(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | //	tmpstr.Format("parseresult=%g",result);
 | 
					
						
							|  |  |  | //		AfxMessageBox(tmpstr);
 | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-10 20:53:58 +00:00
										 |  |  | CValue* CParser::GetValue(STR_String& txt, bool bFallbackToText) | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	// returns parsed text into a value, 
 | 
					
						
							|  |  |  | 	// empty string returns NULL value !
 | 
					
						
							|  |  |  | 	// if bFallbackToText then unparsed stuff is put into text
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	CValue* result=NULL; | 
					
						
							|  |  |  | 	CExpression* expr = ProcessText(txt); | 
					
						
							|  |  |  | 	if (expr) { | 
					
						
							|  |  |  | 		result = expr->Calculate(); | 
					
						
							|  |  |  | 		expr->Release(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (result) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// if the parsed stuff lead to an errorvalue, don't return errors, just NULL
 | 
					
						
							|  |  |  | 		if (result->IsError()) { | 
					
						
							|  |  |  | 			result->Release(); | 
					
						
							|  |  |  | 			result=NULL; | 
					
						
							|  |  |  | 			if (bFallbackToText) { | 
					
						
							|  |  |  | 				if (txt.Length()>0) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					result = new CStringValue(txt,""); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CParser::SetContext(CValue* context) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (m_identifierContext) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_identifierContext->Release(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	m_identifierContext = context; | 
					
						
							|  |  |  | } |