00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <spl/Int32.h>
00018 #include <spl/xml/xpath/private/XPathOpAttrib.h>
00019 #include <spl/xml/xpath/private/XPathOpChildern.h>
00020 #include <spl/xml/xpath/private/XPathOpChildTree.h>
00021 #include <spl/xml/xpath/private/XPathOpError.h>
00022 #include <spl/xml/xpath/private/XPathOpNamedNode.h>
00023 #include <spl/xml/xpath/private/XPathOpRoot.h>
00024 #include <spl/xml/xpath/private/XPathParser.h>
00025 #include <spl/xml/xpath/private/XPathOpPredicate.h>
00026
00027 XPathParser::XPathParser()
00028 : m_lex(), m_exprStack(), m_out(NULL)
00029 {
00030 }
00031
00032 XPathParser::XPathParser(const XPathParser& parser)
00033 : m_lex(parser.m_lex), m_out(NULL), m_exprStack(parser.m_exprStack)
00034 {
00035 }
00036
00037 XPathParser::~XPathParser()
00038 {
00039 }
00040
00041 XPathParser& XPathParser::operator =(const XPathParser& parser)
00042 {
00043 m_lex = parser.m_lex;
00044 m_exprStack = parser.m_exprStack;
00045 return *this;
00046 }
00047
00048 Array<XPathOperatorPtr> XPathParser::Parse(const String& expr)
00049 {
00050 Vector<XPathOperatorPtr> ops;
00051 m_out = &ops;
00052
00053 m_lex.Tokenize(expr);
00054 Expr();
00055 if (m_lex.HasMoreTokens())
00056 {
00057 throw new XmlException("Parsing stopped at char position " + *Int32::ToString(m_lex.CurrentLexumInputCharPos()), 1, m_lex.CurrentLexumInputCharPos());
00058 }
00059 return Array<XPathOperatorPtr>(*ops.ToArray());
00060 }
00061
00062 #if defined(DEBUG) || defined(_DEBUG)
00063 void XPathParser::CheckMem() const
00064 {
00065 m_lex.CheckMem();
00066 m_exprStack.CheckMem();
00067 }
00068
00069 void XPathParser::ValidateMem() const
00070 {
00071 m_lex.ValidateMem();
00072 m_exprStack.ValidateMem();
00073 }
00074 #endif
00075
00076 void XPathParser::NodeSpec()
00077 {
00078 if (m_lex.CurrentToken() == XPathLex::XP_LITERAL)
00079 {
00080 String nodename = m_lex.CurrentLexum();
00081
00082 if (m_lex.HasMoreTokens() && m_lex.GetRelativeToken(1) == XPathLex::XP_COLON)
00083 {
00084
00085 m_lex.Match(XPathLex::XP_LITERAL);
00086 if (m_lex.Match(XPathLex::XP_COLON) != XPathLex::XP_LITERAL)
00087 {
00088 throw new XmlException("Expected node name after namespace " + nodename, 1, m_lex.CurrentLexumInputCharPos());
00089 }
00090 nodename = nodename + ":" + m_lex.CurrentLexum();
00091 }
00092 else if (m_lex.HasMoreTokens() && m_lex.GetRelativeToken(1) == XPathLex::XP_LPAR)
00093 {
00094
00095 String functionName = m_lex.CurrentLexum();
00096
00097 m_lex.Match(XPathLex::XP_LITERAL);
00098 m_lex.Match(XPathLex::XP_LPAR);
00099 ArgList();
00100 m_lex.Match(XPathLex::XP_RPAR);
00101 return;
00102 }
00103
00104 m_out->Add(XPathOpNamedNodePtr(new XPathOpNamedNode(nodename)));
00105 m_lex.Match(XPathLex::XP_LITERAL);
00106 return;
00107 }
00108
00109 if (m_lex.CurrentToken() == XPathLex::XP_DOT)
00110 {
00111
00112 m_lex.Match(XPathLex::XP_DOT);
00113 return;
00114 }
00115
00116 if (m_lex.CurrentToken() == XPathLex::XP_STAR)
00117 {
00118
00119 m_lex.Match(XPathLex::XP_STAR);
00120 return;
00121 }
00122
00123 if (m_lex.CurrentToken() == XPathLex::XP_DOTDOT)
00124 {
00125
00126 m_lex.Match(XPathLex::XP_DOTDOT);
00127 return;
00128 }
00129
00130 if (m_lex.CurrentToken() == XPathLex::XP_AT)
00131 {
00132 m_lex.Match(XPathLex::XP_AT);
00133 m_out->Add(XPathOpAttribPtr(new XPathOpAttrib()));
00134 return;
00135 }
00136
00137 throw new XmlException("Syntax error, expected node specifier.", 1, m_lex.CurrentLexumInputCharPos());
00138 }
00139
00140 void XPathParser::NodePath()
00141 {
00142 if (m_lex.CurrentToken() == XPathLex::XP_SLASHSLASH)
00143 {
00144
00145 m_lex.Match(XPathLex::XP_SLASHSLASH);
00146 m_out->Add(XPathOpChildTreePtr(new XPathOpChildTree()));
00147 }
00148 else if (m_lex.CurrentToken() == XPathLex::XP_SLASH)
00149 {
00150
00151 m_lex.Match(XPathLex::XP_SLASH);
00152 m_out->Add(XPathOpRootPtr(new XPathOpRoot()));
00153 if (m_lex.HasMoreTokens())
00154 {
00155
00156 m_out->Add(XPathOpChildernPtr(new XPathOpChildern()));
00157 }
00158 }
00159 else if (m_lex.CurrentToken() == XPathLex::XP_LITERAL)
00160 {
00161
00162 m_out->Add(XPathOpChildernPtr(new XPathOpChildern()));
00163 }
00164 else if (m_lex.CurrentToken() == XPathLex::XP_AT)
00165 {
00166 m_lex.Match(XPathLex::XP_AT);
00167 m_out->Add(XPathOpAttribPtr(new XPathOpAttrib()));
00168 }
00169 MorePath();
00170 }
00171
00172 void XPathParser::MorePath()
00173 {
00174 if (!m_lex.HasMoreTokens())
00175 {
00176 return;
00177 }
00178 if (m_lex.CurrentToken() == XPathLex::XP_LITERAL && m_lex.GetRelativeToken(1) == XPathLex::XP_LPAR)
00179 {
00180
00181 String functionName = m_lex.CurrentLexum();
00182 m_lex.Match(XPathLex::XP_LITERAL);
00183 m_lex.Match(XPathLex::XP_LPAR);
00184 ArgList();
00185 m_lex.Match(XPathLex::XP_RPAR);
00186 }
00187 else
00188 {
00189 Axis();
00190 NodeSpec();
00191 Predicate();
00192 }
00193 MoreMorePath();
00194 }
00195
00196 bool XPathParser::Axis()
00197 {
00198 if (m_lex.CurrentToken() != XPathLex::XP_LITERAL)
00199 {
00200 return false;
00201 }
00202 if (m_lex.GetRelativeToken(1) != XPathLex::XP_COLONCOLON)
00203 {
00204 return false;
00205 }
00206
00207 m_out->Add(XPathOpErrorPtr(new XPathOpError("axis operator not supported")));
00208
00209 String axis = m_lex.CurrentLexum();
00210 m_lex.Match(XPathLex::XP_LITERAL);
00211 m_lex.Match(XPathLex::XP_COLONCOLON);
00212
00213 return true;
00214 }
00215
00216 bool XPathParser::Predicate()
00217 {
00218 if (m_lex.CurrentToken() != XPathLex::XP_LBRAC)
00219 {
00220 return false;
00221 }
00222 m_lex.Match(XPathLex::XP_LBRAC);
00223
00224 Vector<XPathOperatorPtr> *outbak = m_out;
00225 XPathOpPredicatePtr oppred(new XPathOpPredicate());
00226 m_out = &oppred->Operators();
00227
00228 Expr();
00229
00230 if (m_exprStack.Count() != 2)
00231 {
00232 outbak->Add(XPathOpErrorPtr(new XPathOpError("Unsupported predicated expression.")));
00233 }
00234 else
00235 {
00236 *oppred->Arg() = m_exprStack.Peek();
00237 String op = m_exprStack.Tail();
00238
00239 if (op.Equals('='))
00240 {
00241 oppred->BinOp() = XPathOpPredicate::OP_EQ;
00242 }
00243 else if (op.Equals('<'))
00244 {
00245 oppred->BinOp() = XPathOpPredicate::OP_LT;
00246 }
00247 else if (op.Equals('>'))
00248 {
00249 oppred->BinOp() = XPathOpPredicate::OP_GT;
00250 }
00251 else if (op.Equals("<="))
00252 {
00253 oppred->BinOp() = XPathOpPredicate::OP_LTEQ;
00254 }
00255 else if (op.Equals(">="))
00256 {
00257 oppred->BinOp() = XPathOpPredicate::OP_GTEQ;
00258 }
00259 else if (op.Equals("!="))
00260 {
00261 oppred->BinOp() = XPathOpPredicate::OP_NEQ;
00262 }
00263 else
00264 {
00265 throw new SyntaxException("Unsupported predicated operator " + op);
00266 }
00267 }
00268
00269 m_exprStack.Clear();
00270 m_out = outbak;
00271 m_out->Add(oppred);
00272
00273 m_lex.Match(XPathLex::XP_RBRAC);
00274
00275 return true;
00276 }
00277
00278 bool XPathParser::MoreMorePath()
00279 {
00280 if (m_lex.CurrentToken() == XPathLex::XP_SLASH)
00281 {
00282 m_lex.Match(XPathLex::XP_SLASH);
00283 m_out->Add(XPathOpChildernPtr(new XPathOpChildern()));
00284
00285 if (! m_lex.HasMoreTokens())
00286 {
00287 throw new SyntaxException("xpath cannot end with a slash");
00288 }
00289 }
00290 else if (m_lex.CurrentToken() == XPathLex::XP_SLASHSLASH)
00291 {
00292 m_lex.Match(XPathLex::XP_SLASHSLASH);
00293 m_out->Add(XPathOpChildTreePtr(new XPathOpChildTree()));
00294
00295 if (! m_lex.HasMoreTokens())
00296 {
00297 throw new SyntaxException("xpath cannot end with a slash slash");
00298 }
00299 }
00300 else if (m_lex.CurrentToken() == XPathLex::XP_AT)
00301 {
00302 m_lex.Match(XPathLex::XP_AT);
00303 m_out->Add(XPathOpAttribPtr(new XPathOpAttrib()));
00304 }
00305 else if (m_lex.CurrentToken() == XPathLex::XP_STAR)
00306 {
00307
00308 m_lex.Match(XPathLex::XP_STAR);
00309 }
00310 else
00311 {
00312 return false;
00313 }
00314
00315 MorePath();
00316
00317 return true;
00318 }
00319
00320 bool XPathParser::Expr()
00321 {
00322 if (!m_lex.HasMoreTokens())
00323 {
00324 return false;
00325 }
00326
00327 if (m_lex.CurrentToken() == XPathLex::XP_LPAR)
00328 {
00329 return false;
00330 }
00331
00332 LogOp();
00333
00334 if (MoreLogOp())
00335 {
00336 MoreExpr();
00337 }
00338
00339 return true;
00340 }
00341
00342 bool XPathParser::MoreExpr()
00343 {
00344 if (m_lex.CurrentToken() == XPathLex::XP_PIPE)
00345 {
00346 m_lex.Match(XPathLex::XP_PIPE);
00347 Expr();
00348 return true;
00349 }
00350
00351 return false;
00352 }
00353
00354 void XPathParser::LogOp()
00355 {
00356 RelOp();
00357 MoreRelOps();
00358 }
00359
00360 bool XPathParser::MoreLogOp()
00361 {
00362 switch(m_lex.CurrentToken())
00363 {
00364 case XPathLex::XP_AND:
00365 m_lex.Match(XPathLex::XP_AND);
00366 break;
00367 case XPathLex::XP_OR:
00368 m_lex.Match(XPathLex::XP_OR);
00369 break;
00370 case XPathLex::XP_NEQ:
00371 m_exprStack.Add(m_lex.CurrentLexum());
00372 m_lex.Match(XPathLex::XP_NEQ);
00373 break;
00374 case XPathLex::XP_EQ:
00375 m_exprStack.Add(m_lex.CurrentLexum());
00376 m_lex.Match(XPathLex::XP_EQ);
00377 break;
00378 default:
00379 return false;
00380 }
00381
00382 LogOp();
00383 MoreLogOp();
00384
00385 return true;
00386 }
00387
00388 bool XPathParser::MoreRelOps()
00389 {
00390 switch(m_lex.CurrentToken())
00391 {
00392 case XPathLex::XP_LT:
00393 m_exprStack.Add(m_lex.CurrentLexum());
00394 m_lex.Match(XPathLex::XP_LT);
00395 break;
00396 case XPathLex::XP_GT:
00397 m_exprStack.Add(m_lex.CurrentLexum());
00398 m_lex.Match(XPathLex::XP_GT);
00399 break;
00400 case XPathLex::XP_LTEQ:
00401 m_exprStack.Add(m_lex.CurrentLexum());
00402 m_lex.Match(XPathLex::XP_LTEQ);
00403 break;
00404 case XPathLex::XP_GTEQ:
00405 m_exprStack.Add(m_lex.CurrentLexum());
00406 m_lex.Match(XPathLex::XP_GTEQ);
00407 break;
00408 default:
00409 return false;
00410 }
00411
00412 RelOp();
00413 MoreRelOps();
00414
00415 return true;
00416 }
00417
00418 void XPathParser::RelOp()
00419 {
00420 Term();
00421 MoreTerms();
00422 }
00423
00424 void XPathParser::Term()
00425 {
00426 Factor();
00427 MoreFactors();
00428 }
00429
00430 bool XPathParser::MoreTerms()
00431 {
00432 if (m_lex.CurrentToken() == XPathLex::XP_PLUS)
00433 {
00434 m_lex.Match(XPathLex::XP_PLUS);
00435 }
00436 else if (m_lex.CurrentToken() == XPathLex::XP_MIN)
00437 {
00438 m_lex.Match(XPathLex::XP_MIN);
00439 }
00440 else
00441 {
00442 return false;
00443 }
00444
00445 Term();
00446 MoreTerms();
00447 return true;
00448 }
00449
00450 void XPathParser::Factor()
00451 {
00452 PathExpr();
00453 MoreFactors();
00454 }
00455
00456 bool XPathParser::MoreFactors()
00457 {
00458 if (!m_lex.HasMoreTokens())
00459 {
00460 return false;
00461 }
00462
00463 switch(m_lex.CurrentToken())
00464 {
00465 case XPathLex::XP_STAR:
00466 m_lex.Match(XPathLex::XP_STAR);
00467 break;
00468 case XPathLex::XP_SLASH:
00469 m_lex.Match(XPathLex::XP_SLASH);
00470 break;
00471 case XPathLex::XP_MOD:
00472 m_lex.Match(XPathLex::XP_MOD);
00473 break;
00474 case XPathLex::XP_DIV:
00475 m_lex.Match(XPathLex::XP_DIV);
00476 break;
00477 default:
00478 return false;
00479 }
00480
00481 Factor();
00482 MoreFactors();
00483
00484 return true;
00485 }
00486
00487 bool XPathParser::PathExpr()
00488 {
00489 switch(m_lex.CurrentToken())
00490 {
00491 case XPathLex::XP_DOLLAR:
00492 m_lex.Match(XPathLex::XP_DOLLAR);
00493 m_lex.Match(XPathLex::XP_LITERAL);
00494 break;
00495 case XPathLex::XP_LPAR:
00496 m_lex.Match(XPathLex::XP_LPAR);
00497 Expr();
00498 m_lex.Match(XPathLex::XP_RPAR);
00499 break;
00500 case XPathLex::XP_INT:
00501 m_exprStack.Add(m_lex.CurrentLexum());
00502 m_lex.Match(XPathLex::XP_INT);
00503 break;
00504 case XPathLex::XP_FLOAT:
00505 m_exprStack.Add(m_lex.CurrentLexum());
00506 m_lex.Match(XPathLex::XP_FLOAT);
00507 break;
00508 case XPathLex::XP_STRING:
00509 m_exprStack.Add(m_lex.CurrentLexum());
00510 m_lex.Match(XPathLex::XP_STRING);
00511 break;
00512 case XPathLex::XP_SLASHSLASH:
00513 case XPathLex::XP_SLASH:
00514 case XPathLex::XP_LITERAL:
00515 case XPathLex::XP_LBRAC:
00516 case XPathLex::XP_DOT:
00517 case XPathLex::XP_DOTDOT:
00518 case XPathLex::XP_STAR:
00519 case XPathLex::XP_AT:
00520 NodePath();
00521 break;
00522 default:
00523 return false;
00524 }
00525
00526 return true;
00527 }
00528
00529 bool XPathParser::ArgList()
00530 {
00531 if (m_lex.CurrentToken() == XPathLex::XP_RPAR)
00532 {
00533 return false;
00534 }
00535
00536 Expr();
00537 MoreArgs();
00538
00539 return true;
00540 }
00541
00542 bool XPathParser::MoreArgs()
00543 {
00544 if (m_lex.CurrentToken() == XPathLex::XP_COMMA)
00545 {
00546 return false;
00547 }
00548
00549 while (m_lex.CurrentToken() == XPathLex::XP_COMMA)
00550 {
00551 m_lex.Match(XPathLex::XP_COMMA);
00552 Expr();
00553 }
00554
00555 return true;
00556 }