Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/gameengine/Expressions/InputParser.cpp')
-rw-r--r--source/gameengine/Expressions/InputParser.cpp648
1 files changed, 648 insertions, 0 deletions
diff --git a/source/gameengine/Expressions/InputParser.cpp b/source/gameengine/Expressions/InputParser.cpp
new file mode 100644
index 00000000000..efb5e277737
--- /dev/null
+++ b/source/gameengine/Expressions/InputParser.cpp
@@ -0,0 +1,648 @@
+// 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>
+
+#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"
+
+
+#define NUM_PRIORITY 6
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CParser::CParser() : m_identifierContext(NULL)
+{
+}
+
+
+
+CParser::~CParser()
+{
+ if (m_identifierContext)
+ m_identifierContext->Release();
+}
+
+
+
+void CParser::ScanError(STR_String str)
+{
+ // 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;
+}
+
+
+
+CExpression* CParser::Error(STR_String str)
+{
+ // 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);
+}
+
+
+
+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)
+ {
+ case '(':
+ sym = lbracksym; NextCh();
+ break;
+ case ')':
+ sym = rbracksym; NextCh();
+ break;
+ case ',':
+ sym = commasym; 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;
+ NextCh();
+ if (ch == '=')
+ {
+ opkind = OPunequal;
+ NextCh();
+ }
+ else
+ {
+ opkind = OPnot;
+ }
+ break;
+ case '>':
+ sym = opsym;
+ NextCh();
+ if (ch == '=')
+ {
+ opkind = OPgreaterequal;
+ NextCh();
+ }
+ else
+ {
+ opkind = OPgreater;
+ }
+ break;
+ case '<':
+ sym = opsym;
+ NextCh();
+ if (ch == '=') {
+ opkind = OPlessequal;
+ NextCh();
+ } else {
+ opkind = OPless;
+ }
+ break;
+ case '\"' : {
+ int start;
+ sym = constsym;
+ constkind = stringtype;
+ NextCh();
+ start = chcount;
+ while ((ch != '\"') && (ch != 0x0))
+ NextCh();
+ GrabString(start);
+ TermChar('\"'); // check for eol before '\"'
+ break;
+ }
+ case 0x0: sym = eolsym; break;
+ default:
+ {
+ 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'))
+ || ((ch >= 'A') && (ch <= 'Z')))
+ { // reserved word?
+ int start;
+ STR_String funstr;
+ start = chcount;
+ CharRep();
+ GrabString(start);
+ funstr = const_as_string;
+ funstr.Upper();
+ if (funstr == STR_String("SUM")) {
+ sym = sumsym;
+ }
+ else if (funstr == STR_String("NOT")) {
+ sym = opsym;
+ opkind = OPnot;
+ }
+ else if (funstr == STR_String("AND")) {
+ sym = opsym; opkind = OPand;
+ }
+ else if (funstr == STR_String("OR")) {
+ sym = opsym; opkind = OPor;
+ }
+ else if (funstr == STR_String("IF")) {
+ sym = ifsym;
+ } else if (funstr == STR_String("WHOMADE")) {
+ sym = whocodedsym;
+ } else if (funstr == STR_String("FALSE")) {
+ sym = constsym; constkind = booltype; boolvalue = false;
+ } else if (funstr == STR_String("TRUE")) {
+ 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;
+ }
+ }
+ }
+}
+
+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);
+}
+
+STR_String CParser::Symbol2Str(int s) {
+ // returns a string representation of of symbol s,
+ // for use in Term when generating an error
+ switch(s) {
+ 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
+ }
+}
+
+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) {
+ 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 OPtimes:
+ case OPdivide: return 5;
+ }
+ assert(false);
+ 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) {
+ 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;
+ default: assert(false); break; // should not happen
+ }
+ }
+ } 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:
+ {
+ int temp;
+ temp = atoi(const_as_string);
+ 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 :
+ assert(false);
+ 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:
+ {
+ assert(!e1);
+ 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 ?
+ assert ("does this happen");
+ }
+ }
+ e1 = Error(errtext);
+
+ break;
+ }
+ default:
+ NextSym();
+ //return Error("Expression expected");
+ assert(!e1);
+ 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
+(STR_String intext) {
+
+ // 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;
+}
+
+
+
+float CParser::GetFloat(STR_String txt)
+{
+ // 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();
+ result=val->GetNumber();
+
+
+
+ val->Release();
+ expr->Release();
+ }
+// tmpstr.Format("parseresult=%g",result);
+// AfxMessageBox(tmpstr);
+ return result;
+}
+
+CValue* CParser::GetValue(STR_String txt, bool bFallbackToText)
+{
+ // 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;
+}
+
+
+
+
+PyObject* CParserPyMake(PyObject* ignored,PyObject* args)
+{
+ char* txt;
+ Py_Try(PyArg_ParseTuple(args,"s",&txt));
+ CParser parser;
+ CExpression* expr = parser.ProcessText(txt);
+ CValue* val = expr->Calculate();
+ expr->Release();
+ return val;
+}
+
+static PyMethodDef CParserMethods[] =
+{
+ { "calc", CParserPyMake , Py_NEWARGS},
+ { NULL,NULL} // Sentinel
+};
+
+extern "C" {
+ void initExpressionModule(void)
+ {
+ Py_InitModule("Expression",CParserMethods);
+ }
+}
+