Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

InputParser.cpp

Go to the documentation of this file.
00001 // Parser.cpp: implementation of the CParser class.
00002 /*
00003  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>

00004  *
00005  * Permission to use, copy, modify, distribute and sell this software

00006  * and its documentation for any purpose is hereby granted without fee,

00007  * provided that the above copyright notice appear in all copies and

00008  * that both that copyright notice and this permission notice appear

00009  * in supporting documentation.  Erwin Coumans makes no

00010  * representations about the suitability of this software for any

00011  * purpose.  It is provided "as is" without express or implied warranty.

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 // this is disable at the moment, I expected a memleak from it, but the error-cleanup was the reason
00031 // well, looks we don't need it anyway, until maybe the Curved Surfaces are integrated into CSG 
00032 // cool things like (IF(LOD==1,CCurvedValue,IF(LOD==2,CCurvedValue2)) etc...
00033 #include "IfExpr.h" 
00034 
00035 
00036 #define NUM_PRIORITY 6
00037 
00038 // Construction/Destruction
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         // sets the global variable errmsg to an errormessage with
00054         // contents str, appending if it already exists
00055         //      AfxMessageBox("Parse Error:"+str,MB_ICONERROR);
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         // makes and returns a new CConstExpr filled with an CErrorValue
00065         // with string str
00066         //      AfxMessageBox("Error:"+str,MB_ICONERROR);
00067         return new CConstExpr(new CErrorValue(str));
00068 }
00069 
00070 void CParser::NextCh() {
00071         // sets the global variable ch to the next character, if it exists
00072         // and increases the global variable chcount
00073         chcount++;
00074         if (chcount < text.Length()) ch = text[chcount];
00075         else ch = 0x00;
00076 }
00077 
00078 void CParser::TermChar(char c) {
00079         // generates an error if the next char isn't the specified char c,
00080         // otherwise, skip the char
00081         if(ch == c) NextCh();
00082         else {
00083                 CCString str;
00084                 str.Format("Warning: %c expected\ncontinuing without it", c);
00085                 
00086                 //AfxMessageBox(str,MB_ICONERROR);
00087                 
00088                 trace(str);
00089         }
00090 }
00091 
00092 
00093 void CParser::DigRep() {
00094         // changes the current character to the first character that
00095         // isn't a decimal
00096         while ((ch >= '0') && (ch <= '9'))
00097                 NextCh();
00098 }
00099 
00100 void CParser::CharRep() {
00101         // changes the current character to the first character that
00102         // isn't an alphanumeric character
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         // puts part of the input string into the global variable
00112         // const_as_string, from position start, to position chchount
00113         const_as_string = text.Mid(start, chcount-start);
00114 }
00115 
00116 void CParser::NextSym() {
00117         // sets the global variable sym to the next symbol, and
00118         // if it is an operator
00119         //   sets the global variable opkind to the kind of operator
00120         // if it is a constant
00121         //   sets the global variable constkind to the kind of operator
00122         // if it is a reference to a cell
00123         //   sets the global variable cellcoord to the kind of operator
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('\"'); // check for eol before '\"'
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 == '.')) { // number
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                         { // reserved word?
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                                         //CCString str;
00241                                         //str.Format("'%s' makes no sense here", (const char*)funstr);
00242                                         //ScanError(str);
00243                                 }
00244                         } else { // unknown symbol
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         // returns the integer representation of the value in the global
00257         // variable const_as_string
00258         // pre: const_as_string contains only numercal chars
00259         return atoi(const_as_string);
00260 }
00261 
00262 CCString CParser::Symbol2Str(int s) {
00263         // returns a string representation of of symbol s,
00264         // for use in Term when generating an error
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";  // should not happen
00278         }
00279 }
00280 
00281 void CParser::Term(int s) {
00282         // generates an error if the next symbol isn't the specified symbol s
00283         // otherwise, skip the symbol
00284         if(s == sym) NextSym();
00285         else {
00286                 CCString msg;
00287                 msg.Format("Warning: " + Symbol2Str(s) + " expected\ncontinuing without it");
00288 
00289 //              AfxMessageBox(msg,MB_ICONERROR);
00290 
00291                 trace(msg);
00292         }
00293 }
00294 
00295 int CParser::Priority(int optorkind) {
00296         // returns the priority of an operator
00297         // higher number means higher priority
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;      // should not happen
00314 }
00315 
00316 CExpression *CParser::Ex(int i) {
00317         // parses an expression in the imput, starting at priority i, and
00318         // returns an CExpression, containing the parsed input
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; // should not happen
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                                                 // should not happen
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                                 // no entry in the following list of names (credits) may be removed
00420                                 // without permission of Erwin Coumans, coockie@acm.org
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                                                 //e1 = Error(errmsg->Calculate()->GetText());//new CConstExpr(errmsg->Calculate());
00464                                                 
00465                                                 if ( !(errmsg->Release()) )
00466                                                 {
00467                                                         errmsg=NULL;
00468                                                 } else {
00469                                                         // does this happen ?
00470                                                         assert ("does this happen");
00471                                                 }
00472                                         }
00473                                         e1 = Error(errtext);
00474 
00475                                         break;                          
00476                                 }
00477                         default:
00478                                 NextSym();
00479                                 //return Error("Expression expected");
00480                                 assert(!e1);
00481                                 e1 = Error("Expression expected");
00482                         }
00483                 }
00484         }
00485         return e1;
00486 }
00487 
00488 CExpression *CParser::Expr() {
00489         // parses an expression in the imput, and
00490         // returns an CExpression, containing the parsed input
00491         return Ex(1);
00492 }
00493 
00494 CExpression* CParser::ProcessText
00495 (CCString intext) {
00496         
00497         // and parses the string in intext and returns it.
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         /*if (ch != '=') {

00511         expr = new CConstExpr(new CStringValue(text));

00512         *dependant = deplist;

00513         return expr;

00514         } else 

00515         */
00516         //      NextCh();
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")));//new CConstExpr(new CErrorValue("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         // returns parsed text into a float
00535         // empty string returns -1
00536         
00537 //      AfxMessageBox("parsed string="+txt);
00538         CValue* val=NULL;
00539         float result=-1;
00540 //      String tmpstr;
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 //      tmpstr.Format("parseresult=%g",result);
00553 //              AfxMessageBox(tmpstr);
00554         return result;
00555 }
00556 
00557 CValue* CParser::GetValue(CCString txt, bool bFallbackToText)

00558 {
00559         // returns parsed text into a value, 
00560         // empty string returns NULL value !
00561         // if bFallbackToText then unparsed stuff is put into text
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                 // if the parsed stuff lead to an errorvalue, don't return errors, just NULL
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}    // Sentinel
00614 };
00615 
00616 extern "C" {
00617         void initExpressionModule(void)

00618         {
00619                 Py_InitModule("Expression",CParserMethods);
00620         }
00621 }
00622 
00623 #endif //EXP_PYTHON_EMBEDDING

Generated at Thu Feb 1 13:03:03 2001 for Ketsji Game Engine by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000