diff options
author | Hans Lambermont <hans@lambermont.dyndns.org> | 2002-10-12 15:37:38 +0400 |
---|---|---|
committer | Hans Lambermont <hans@lambermont.dyndns.org> | 2002-10-12 15:37:38 +0400 |
commit | 12315f4d0e0ae993805f141f64cb8c73c5297311 (patch) | |
tree | 59b45827cd8293cfb727758989c7a74b40183974 /source/gameengine/Expressions/InputParser.cpp |
Initial revisionv2.25
Diffstat (limited to 'source/gameengine/Expressions/InputParser.cpp')
-rw-r--r-- | source/gameengine/Expressions/InputParser.cpp | 648 |
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); + } +} + |