00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <stdlib.h>
00016
00017 #include "Value.h"
00018 #include "InputParser.h"
00019 #include "ErrorValue.h"
00020 #include "IntValue.h"
00021 #include "StringValue.h"
00022 #include "FloatValue.h"
00023 #include "BoolValue.h"
00024 #include "EmptyValue.h"
00025 #include "ConstExpr.h"
00026 #include "Operator2Expr.h"
00027 #include "Operator1Expr.h"
00028 #include "IdentifierExpr.h"
00029
00030
00031
00032
00033 #include "IfExpr.h"
00034
00035
00036 #define NUM_PRIORITY 6
00037
00038
00040
00041 CParser::~CParser() {
00042 if (m_identifierContext)
00043 {
00044 m_identifierContext->Release();
00045 }
00046 }
00047
00048 CParser::CParser() : m_identifierContext(NULL) {
00049
00050 }
00051
00052 void CParser::ScanError(CCString str) {
00053
00054
00055
00056 if (errmsg)
00057 errmsg = new COperator2Expr(VALUE_ADD_OPERATOR, errmsg,
00058 Error(str));
00059 else errmsg = Error(str);
00060 sym = errorsym;
00061 }
00062
00063 CExpression* CParser::Error(CCString str) {
00064
00065
00066
00067 return new CConstExpr(new CErrorValue(str));
00068 }
00069
00070 void CParser::NextCh() {
00071
00072
00073 chcount++;
00074 if (chcount < text.Length()) ch = text[chcount];
00075 else ch = 0x00;
00076 }
00077
00078 void CParser::TermChar(char c) {
00079
00080
00081 if(ch == c) NextCh();
00082 else {
00083 CCString str;
00084 str.Format("Warning: %c expected\ncontinuing without it", c);
00085
00086
00087
00088 trace(str);
00089 }
00090 }
00091
00092
00093 void CParser::DigRep() {
00094
00095
00096 while ((ch >= '0') && (ch <= '9'))
00097 NextCh();
00098 }
00099
00100 void CParser::CharRep() {
00101
00102
00103 while (((ch >= '0') && (ch <= '9'))
00104 || ((ch >= 'a') && (ch <= 'z'))
00105 || ((ch >= 'A') && (ch <= 'Z'))
00106 || (ch == '.') || (ch == '_'))
00107 NextCh();
00108 }
00109
00110 void CParser::GrabString(int start) {
00111
00112
00113 const_as_string = text.Mid(start, chcount-start);
00114 }
00115
00116 void CParser::NextSym() {
00117
00118
00119
00120
00121
00122
00123
00124
00125 errmsg = NULL;
00126 while(ch == ' ' || ch == 0x9) NextCh();
00127 switch(ch) {
00128 case '(': sym = lbracksym; NextCh(); break;
00129 case ')': sym = rbracksym; NextCh(); break;
00130 case ',': sym = commasym; NextCh(); break;
00131 case '+' : sym = opsym; opkind = OPplus; NextCh(); break;
00132 case '-' : sym = opsym; opkind = OPminus; NextCh(); break;
00133 case '*' : sym = opsym; opkind = OPtimes; NextCh(); break;
00134 case '/' : sym = opsym; opkind = OPdivide; NextCh(); break;
00135 case '&' : sym = opsym; opkind = OPand; NextCh(); TermChar('&'); break;
00136 case '|' : sym = opsym; opkind = OPor; NextCh(); TermChar('|'); break;
00137 case '=' : sym = opsym; opkind = OPequal; NextCh(); TermChar('='); break;
00138 case '!' :
00139 sym = opsym;
00140 NextCh();
00141 if (ch == '=') {
00142 opkind = OPunequal;
00143 NextCh();
00144 } else {
00145 opkind = OPnot;
00146 }
00147 break;
00148 case '>':
00149 sym = opsym;
00150 NextCh();
00151 if (ch == '=') {
00152 opkind = OPgreaterequal;
00153 NextCh();
00154 } else {
00155 opkind = OPgreater;
00156 }
00157 break;
00158 case '<':
00159 sym = opsym;
00160 NextCh();
00161 if (ch == '=') {
00162 opkind = OPlessequal;
00163 NextCh();
00164 } else {
00165 opkind = OPless;
00166 }
00167 break;
00168 case '\"' : {
00169 int start;
00170 sym = constsym;
00171 constkind = stringtype;
00172 NextCh();
00173 start = chcount;
00174 while ((ch != '\"') && (ch != 0x0))
00175 NextCh();
00176 GrabString(start);
00177 TermChar('\"');
00178 break;
00179 }
00180 case 0x0: sym = eolsym; break;
00181 default:
00182 {
00183 int start;
00184 start = chcount;
00185 DigRep();
00186 if ((start != chcount) || (ch == '.')) {
00187 sym = constsym;
00188 if (ch == '.') {
00189 constkind = floattype;
00190 NextCh();
00191 DigRep();
00192 }
00193 else constkind = inttype;
00194 if ((ch == 'e') || (ch == 'E')) {
00195 int mark;
00196 constkind = floattype;
00197 NextCh();
00198 if ((ch == '+') || (ch == '-')) NextCh();
00199 mark = chcount;
00200 DigRep();
00201 if (mark == chcount) {
00202 ScanError("Number expected after 'E'");
00203 return;
00204 }
00205 }
00206 GrabString(start);
00207 } else if (((ch >= 'a') && (ch <= 'z'))
00208 || ((ch >= 'A') && (ch <= 'Z')))
00209 {
00210 int start;
00211 CCString funstr;
00212 start = chcount;
00213 CharRep();
00214 GrabString(start);
00215 funstr = const_as_string;
00216 funstr.Upper();
00217 if (funstr == CCString("SUM")) {
00218 sym = sumsym;
00219 }
00220 else if (funstr == CCString("NOT")) {
00221 sym = opsym;
00222 opkind = OPnot;
00223 }
00224 else if (funstr == CCString("AND")) {
00225 sym = opsym; opkind = OPand;
00226 }
00227 else if (funstr == CCString("OR")) {
00228 sym = opsym; opkind = OPor;
00229 }
00230 else if (funstr == CCString("IF")) {
00231 sym = ifsym;
00232 } else if (funstr == CCString("WHOMADE")) {
00233 sym = whocodedsym;
00234 } else if (funstr == CCString("FALSE")) {
00235 sym = constsym; constkind = booltype; boolvalue = false;
00236 } else if (funstr == CCString("TRUE")) {
00237 sym = constsym; constkind = booltype; boolvalue = true;
00238 } else {
00239 sym = idsym;
00240
00241
00242
00243 }
00244 } else {
00245 CCString str;
00246 str.Format("Unexpected character '%c'", ch);
00247 NextCh();
00248 ScanError(str);
00249 return;
00250 }
00251 }
00252 }
00253 }
00254
00255 int CParser::MakeInt() {
00256
00257
00258
00259 return atoi(const_as_string);
00260 }
00261
00262 CCString CParser::Symbol2Str(int s) {
00263
00264
00265 switch(s) {
00266 case errorsym: return "error";
00267 case lbracksym: return "(";
00268 case rbracksym: return ")";
00269 case commasym: return ",";
00270 case opsym: return "operator";
00271 case constsym: return "constant";
00272 case sumsym: return "SUM";
00273 case ifsym: return "IF";
00274 case whocodedsym: return "WHOMADE";
00275 case eolsym: return "end of line";
00276 case idsym: return "identifier";
00277 default: return "unknown";
00278 }
00279 }
00280
00281 void CParser::Term(int s) {
00282
00283
00284 if(s == sym) NextSym();
00285 else {
00286 CCString msg;
00287 msg.Format("Warning: " + Symbol2Str(s) + " expected\ncontinuing without it");
00288
00289
00290
00291 trace(msg);
00292 }
00293 }
00294
00295 int CParser::Priority(int optorkind) {
00296
00297
00298 switch(optorkind) {
00299 case OPor: return 1;
00300 case OPand: return 2;
00301 case OPgreater:
00302 case OPless:
00303 case OPgreaterequal:
00304 case OPlessequal:
00305 case OPequal:
00306 case OPunequal: return 3;
00307 case OPplus:
00308 case OPminus: return 4;
00309 case OPtimes:
00310 case OPdivide: return 5;
00311 }
00312 assert(false);
00313 return 0;
00314 }
00315
00316 CExpression *CParser::Ex(int i) {
00317
00318
00319 CExpression *e1 = NULL, *e2 = NULL;
00320 int opkind2;
00321
00322 if (i < NUM_PRIORITY) {
00323 e1 = Ex(i + 1);
00324 while ((sym == opsym) && (Priority(opkind) == i)) {
00325 opkind2 = opkind;
00326 NextSym();
00327 e2 = Ex(i + 1);
00328 switch(opkind2) {
00329 case OPplus: e1 = new COperator2Expr(VALUE_ADD_OPERATOR,e1, e2); break;
00330 case OPminus: e1 = new COperator2Expr(VALUE_SUB_OPERATOR,e1, e2); break;
00331 case OPtimes: e1 = new COperator2Expr(VALUE_MUL_OPERATOR,e1, e2); break;
00332 case OPdivide: e1 = new COperator2Expr(VALUE_DIV_OPERATOR,e1, e2); break;
00333 case OPand: e1 = new COperator2Expr(VALUE_AND_OPERATOR,e1, e2); break;
00334 case OPor: e1 = new COperator2Expr(VALUE_OR_OPERATOR,e1, e2); break;
00335 case OPequal: e1 = new COperator2Expr(VALUE_EQL_OPERATOR,e1, e2); break;
00336 case OPunequal: e1 = new COperator2Expr(VALUE_NEQ_OPERATOR,e1, e2); break;
00337 case OPgreater: e1 = new COperator2Expr(VALUE_GRE_OPERATOR,e1, e2); break;
00338 case OPless: e1 = new COperator2Expr(VALUE_LES_OPERATOR,e1, e2); break;
00339 case OPgreaterequal: e1 = new COperator2Expr(VALUE_GEQ_OPERATOR,e1, e2); break;
00340 case OPlessequal: e1 = new COperator2Expr(VALUE_LEQ_OPERATOR,e1, e2); break;
00341 default: assert(false); break;
00342 }
00343 }
00344 } else if (i == NUM_PRIORITY) {
00345 if ((sym == opsym) && ((opkind == OPminus) || (opkind == OPnot)))
00346 {
00347 NextSym();
00348 switch(opkind) {
00349 case OPminus: e1 = new COperator1Expr(VALUE_NEG_OPERATOR, Ex(NUM_PRIORITY)); break;
00350 case OPnot: e1 = new COperator1Expr(VALUE_NOT_OPERATOR, Ex(NUM_PRIORITY)); break;
00351 default: {
00352
00353 e1 = Error("operator - or ! expected");
00354 }
00355 }
00356 }
00357 else {
00358 switch(sym) {
00359 case constsym: {
00360 switch(constkind) {
00361 case booltype:
00362 e1 = new CConstExpr(new CBoolValue(boolvalue));
00363 break;
00364 case inttype:
00365 {
00366 int temp;
00367 temp = atoi(const_as_string);
00368 e1 = new CConstExpr(new CIntValue(temp));
00369 break;
00370 }
00371 case floattype:
00372 {
00373 double temp;
00374 temp = atof(const_as_string);
00375 e1 = new CConstExpr(new CFloatValue(temp));
00376 break;
00377 }
00378 case stringtype:
00379 e1 = new CConstExpr(new CStringValue(const_as_string,""));
00380 break;
00381 default :
00382 assert(false);
00383 break;
00384 }
00385 NextSym();
00386 break;
00387 }
00388 case lbracksym:
00389 NextSym();
00390 e1 = Ex(1);
00391 Term(rbracksym);
00392 break;
00393 case ifsym:
00394 {
00395 CExpression *e3;
00396 NextSym();
00397 Term(lbracksym);
00398 e1 = Ex(1);
00399 Term(commasym);
00400 e2 = Ex(1);
00401 if (sym == commasym) {
00402 NextSym();
00403 e3 = Ex(1);
00404 } else {
00405 e3 = new CConstExpr(new CEmptyValue());
00406 }
00407 Term(rbracksym);
00408 e1 = new CIfExpr(e1, e2, e3);
00409 break;
00410 }
00411 case idsym:
00412 {
00413 e1 = new CIdentifierExpr(const_as_string,m_identifierContext);
00414 NextSym();
00415
00416 break;
00417 }
00418 case whocodedsym: {
00419
00420
00421
00422 CCString text;
00423 NextSym();
00424 Term(lbracksym);
00425 if ((sym != constsym) || (constkind != stringtype))
00426 e1 = Error("Intelligent input expected");
00427 else if (const_as_string == CCString("solid"))
00428 text = "Gino van den Bergen";
00429 else if (const_as_string == CCString("blender"))
00430 text = "Ton_Roosendaal";
00431 else if (const_as_string == CCString("engine"))
00432 text = "Henk_Kok";
00433 else if (const_as_string == CCString("pigs"))
00434 text = "Michiel_Ouwehand";
00435 else if (const_as_string == CCString("editor"))
00436 text = "Erwin_Coumans";
00437 else if (const_as_string == CCString("bezier"))
00438 text = "Arjan_Brussee";
00439 else if (const_as_string == CCString("level"))
00440 text = "Roy_Postma";
00441 else if (const_as_string == CCString("textures"))
00442 text = "Edwin_Bakker";
00443 else if (const_as_string == CCString("parser"))
00444 text = "Serge_van_den_Boom";
00445 else if (const_as_string == CCString("cvalue"))
00446 text = "Tom Geelen, Erwin Coumans and Serge van den Boom";
00447 else e1 = Error("How should I know? I'm just an expressionparser.");
00448 NextSym();
00449 Term(rbracksym);
00450 if (!e1) e1 = new CConstExpr(new CStringValue(text,""));
00451 break;
00452 }
00453 case errorsym:
00454 {
00455 assert(!e1);
00456 CCString errtext="[no info]";
00457 if (errmsg)
00458 {
00459 CValue* errmsgval = errmsg->Calculate();
00460 errtext=errmsgval->GetText();
00461 errmsgval->Release();
00462
00463
00464
00465 if ( !(errmsg->Release()) )
00466 {
00467 errmsg=NULL;
00468 } else {
00469
00470 assert ("does this happen");
00471 }
00472 }
00473 e1 = Error(errtext);
00474
00475 break;
00476 }
00477 default:
00478 NextSym();
00479
00480 assert(!e1);
00481 e1 = Error("Expression expected");
00482 }
00483 }
00484 }
00485 return e1;
00486 }
00487
00488 CExpression *CParser::Expr() {
00489
00490
00491 return Ex(1);
00492 }
00493
00494 CExpression* CParser::ProcessText
00495 (CCString intext) {
00496
00497
00498
00499
00500 CExpression* expr;
00501 text = intext;
00502
00503
00504 chcount = 0;
00505 if (text.Length() == 0) {
00506 return NULL;
00507 }
00508
00509 ch = text[0];
00510
00511
00512
00513
00514
00515
00516
00517 NextSym();
00518 expr = Expr();
00519 if (sym != eolsym) {
00520 CExpression* oldexpr = expr;
00521 expr = new COperator2Expr(VALUE_ADD_OPERATOR,
00522 oldexpr, Error(CCString("Extra characters after expression")));
00523 }
00524 if (errmsg)
00525 errmsg->Release();
00526
00527 return expr;
00528 }
00529
00530
00531
00532 float CParser::GetFloat(CCString txt)
00533 {
00534
00535
00536
00537
00538 CValue* val=NULL;
00539 float result=-1;
00540
00541
00542 CExpression* expr = ProcessText(txt);
00543 if (expr) {
00544 val = expr->Calculate();
00545 result=val->GetNumber();
00546
00547
00548
00549 val->Release();
00550 expr->Release();
00551 }
00552
00553
00554 return result;
00555 }
00556
00557 CValue* CParser::GetValue(CCString txt, bool bFallbackToText)
00558 {
00559
00560
00561
00562
00563 CValue* result=NULL;
00564 CExpression* expr = ProcessText(txt);
00565 if (expr) {
00566 result = expr->Calculate();
00567 expr->Release();
00568 }
00569 if (result)
00570 {
00571
00572 if (result->IsError()) {
00573 result->Release();
00574 result=NULL;
00575 if (bFallbackToText) {
00576 if (txt.Length()>0)
00577 {
00578 result = new CStringValue(txt,"");
00579 }
00580 }
00581 }
00582 }
00583 return result;
00584 }
00585
00586 void CParser::SetContext(CValue* context)
00587 {
00588 if (m_identifierContext)
00589 {
00590 m_identifierContext->Release();
00591 }
00592 m_identifierContext = context;
00593 }
00594
00595
00596 #ifdef EXP_PYTHON_EMBEDDING
00597
00598
00599 PyObject* CParserPyMake(PyObject* ignored,PyObject* args)
00600 {
00601 char* txt;
00602 Py_Try(PyArg_ParseTuple(args,"s",&txt));
00603 CParser parser;
00604 CExpression* expr = parser.ProcessText(txt);
00605 CValue* val = expr->Calculate();
00606 expr->Release();
00607 return val;
00608 }
00609
00610 static PyMethodDef CParserMethods[] =
00611 {
00612 { "calc", CParserPyMake , Py_NEWARGS},
00613 { NULL,NULL}
00614 };
00615
00616 extern "C" {
00617 void initExpressionModule(void)
00618 {
00619 Py_InitModule("Expression",CParserMethods);
00620 }
00621 }
00622
00623 #endif //EXP_PYTHON_EMBEDDING