PageRenderTime 55ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/demo/generic/domxpath.c

http://tcltcc.googlecode.com/
C | 1902 lines | 1683 code | 111 blank | 108 comment | 194 complexity | 681d1290e61b202fd229fbf3f2fbe79d MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*----------------------------------------------------------------------------
  2. | Copyright (c) 1999-2001 Jochen Loewer (loewerj@hotmail.com)
  3. |-----------------------------------------------------------------------------
  4. |
  5. | $Id: domxpath.c,v 1.94 2007/08/05 17:52:35 rolf Exp $
  6. |
  7. |
  8. | A XPath implementation (lexer/parser/evaluator) for tDOM,
  9. | the DOM implementation for Tcl.
  10. | Based on November 16 1999 Recommendation of the W3C
  11. | (http://www.w3.org/TR/1999/REC-xslt-19991116)
  12. |
  13. |
  14. | The contents of this file are subject to the Mozilla Public License
  15. | Version 1.1 (the "License"); you may not use this file except in
  16. | compliance with the License. You may obtain a copy of the License at
  17. | http://www.mozilla.org/MPL/
  18. |
  19. | Software distributed under the License is distributed on an "AS IS"
  20. | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  21. | License for the specific language governing rights and limitations
  22. | under the License.
  23. |
  24. | The Original Code is tDOM.
  25. |
  26. | The Initial Developer of the Original Code is Jochen Loewer
  27. | Portions created by Jochen Loewer are Copyright (C) 1999 - 2001
  28. | Jochen Loewer. All Rights Reserved.
  29. |
  30. | Portions created by Zoran Vasiljevic are Copyright (C) 2000-2002
  31. | Zoran Vasiljevic. All Rights Reserved.
  32. |
  33. | Portions created by Rolf Ade are Copyright (C) 1999-2007
  34. | Rolf Ade. All Rights Reserved.
  35. |
  36. | Contributor(s):
  37. | April00 Rolf Ade Add support for following/preceding/
  38. | precedingSibling axis plus several
  39. | bug fixes
  40. |
  41. | Aug00 Rolf Ade Rewrite of comparisons plus several
  42. | bug fixes/reports
  43. |
  44. | Aug01 Rolf Ade id(), unparsed-entity(), lang(), fixes
  45. |
  46. | 2002 Rolf Ade Namespace aware nodetests and NS wildcard
  47. | expr, namespace aware variables, keys and
  48. | function, made lexer utf-8 aware, node sets
  49. | could now include nodes of different types,
  50. | better IEEE 754 rules support, code
  51. | restructured, serveral optimizations and bug
  52. | fixes.
  53. |
  54. | written by Jochen Loewer
  55. | July, 1999
  56. |
  57. \---------------------------------------------------------------------------*/
  58. /*----------------------------------------------------------------------------
  59. | Includes
  60. |
  61. \---------------------------------------------------------------------------*/
  62. #include <stdio.h>
  63. #include <stdlib.h>
  64. #include <string.h>
  65. #include <float.h>
  66. #include <math.h>
  67. #include <limits.h>
  68. #include <ctype.h>
  69. #include <dom.h>
  70. #include <domxpath.h>
  71. #include <domxslt.h>
  72. /*----------------------------------------------------------------------------
  73. | Macros
  74. |
  75. \---------------------------------------------------------------------------*/
  76. #define JDBG(x)
  77. #define DBG(x)
  78. #define DDBG(x)
  79. #define TRACE(x) DDBG(fprintf(stderr,(x)))
  80. #define TRACE1(x,a) DDBG(fprintf(stderr,(x),(a)))
  81. #define TRACE2(x,a,b) DDBG(fprintf(stderr,(x),(a),(b)))
  82. #define TRACE3(x,a,b,c) DDBG(fprintf(stderr,(x),(a),(b),(c)))
  83. #define INITIAL_SIZE 100
  84. #define ADD_TOKEN(t) if ((l+1)>=allocated) { \
  85. tokens=(XPathTokens)REALLOC((char*)tokens, 2*allocated\
  86. *sizeof(XPathToken)); \
  87. allocated = allocated * 2; \
  88. } \
  89. tokens[l].token = (t); \
  90. tokens[l++].pos = i; \
  91. tokens[l].token = EOS; \
  92. tokens[l].strvalue = NULL; \
  93. tokens[l].intvalue = 0; \
  94. tokens[l].realvalue = 0.0;
  95. #define DeclProduction(name) static ast name (int *l,XPathTokens tokens,char **errMsg)
  96. #define Production(name) static ast name (int *l,XPathTokens tokens,char **errMsg) \
  97. { char *__func = #name; \
  98. ast a = NULL; \
  99. TRACE2("\nProduction "#name": start l=%d next:%s\n", \
  100. *l,token2str[tokens[*l].token]);
  101. #define EndProduction TRACE3("EndProd %s: start l=%d next:%s\n", \
  102. __func, *l,token2str[tokens[*l].token]); \
  103. DDBG(printAst(0,a);) \
  104. return a; \
  105. }
  106. #define LA tokens[*l].token
  107. #define LA2 tokens[*l+1].token
  108. #define LA3 tokens[*l+2].token
  109. /* #define Recurse(p) rc=p(l,tokens,errMsg);if(rc==NULL)return rc;*/
  110. #define Recurse(p) p(l,tokens,errMsg)
  111. #define Consume(tk) if (tokens[*l].token == tk) { \
  112. TRACE2("Production %s: %s consumed\n", \
  113. __func, token2str[tokens[*l].token]); \
  114. (*l)++; \
  115. } else { \
  116. if (*errMsg==NULL) {ErrExpected(#tk);} \
  117. else return a; \
  118. }
  119. #define STRVAL tokens[(*l)-1].strvalue
  120. #define INTVAL tokens[(*l)-1].intvalue
  121. #define REALVAL tokens[(*l)-1].realvalue
  122. #define NEWCONS ((ast)MALLOC(sizeof(astElem)))
  123. #define IS_STR(c,s) (c==*(tokens[(*l)-1].strvalue))&&(strcmp(tokens[(*l)-1].strvalue,s)==0)
  124. #define IS_FUNC(c,s) ((*(step->strvalue)==(c)) && (strcmp((s),step->strvalue)==0))
  125. #define ErrExpected(msg) *errMsg = (char*)MALLOC(255); \
  126. **errMsg = '\0'; \
  127. strcpy(*errMsg, __func); \
  128. strcat(*errMsg, ": Expected " #msg); \
  129. return a;
  130. #define CHECK_RC if (rc) return rc
  131. #define checkRsAddNode(rs,node) if (useFastAdd) rsAddNodeFast( rs,node); \
  132. else rsAddNode (rs,node);
  133. /*----------------------------------------------------------------------------
  134. | Types for Lexer
  135. |
  136. \---------------------------------------------------------------------------*/
  137. typedef enum {
  138. LPAR, RPAR, LBRACKET, RBRACKET, DOT, DOTDOT, ATTRIBUTEPREFIX,
  139. ATTRIBUTE, COMMA, COLONCOLON, LITERAL, NSPREFIX, NSWC,
  140. INTNUMBER, REALNUMBER, SLASH, SLASHSLASH,
  141. PIPE, PLUS, MINUS, EQUAL, NOTEQ, LT, LTE, GT, GTE,
  142. AND, OR, MOD, DIV, MULTIPLY, FUNCTION, VARIABLE,
  143. FQVARIABLE, WCARDNAME, COMMENT, TEXT, PINSTR, NODE, AXISNAME,
  144. EOS
  145. } Token;
  146. static char *token2str[] = {
  147. "LPAR", "RPAR", "LBRACKET", "RBRACKET", "DOT", "DOTDOT", "ATTRIBUTEPREFIX",
  148. "ATTRIBUTE", "COMMA", "COLONCOLON", "LITERAL", "NSPREFIX", "NSWC",
  149. "INTNUMBER", "REALNUMBER", "SLASH", "SLASHSLASH",
  150. "PIPE", "PLUS", "MINUS", "EQUAL", "NOTEQ", "LT", "LTE", "GT", "GTE",
  151. "AND", "OR", "MOD", "DIV", "MULTIPLY", "FUNCTION", "VARIABLE",
  152. "FQVARIABLE", "WCARDNAME", "COMMENT", "TEXT", "PI", "NODE", "AXISNAME",
  153. "EOS"
  154. };
  155. typedef struct {
  156. Token token;
  157. char *strvalue;
  158. int intvalue;
  159. double realvalue;
  160. int pos;
  161. } XPathToken;
  162. typedef XPathToken *XPathTokens;
  163. /*----------------------------------------------------------------------------
  164. | Types for abstract syntax trees
  165. |
  166. \---------------------------------------------------------------------------*/
  167. static char *astType2str[] = {
  168. "Int", "Real", "Mult", "Div", "Mod", "UnaryMinus", "IsNSElement",
  169. "IsNode", "IsComment", "IsText", "IsPI", "IsSpecificPI", "IsElement",
  170. "IsFQElement", "GetVar", "GetFQVar", "Literal", "ExecFunction", "Pred",
  171. "EvalSteps", "SelectRoot", "CombineSets", "Add", "Substract", "Less",
  172. "LessOrEq", "Greater", "GreaterOrEq", "Equal", "NotEqual", "And", "Or",
  173. "IsNSAttr", "IsAttr", "AxisAncestor", "AxisAncestorOrSelf",
  174. "AxisAttribute", "AxisChild",
  175. "AxisDescendant", "AxisDescendantOrSelf", "AxisFollowing",
  176. "AxisFollowingSibling", "AxisNamespace", "AxisParent",
  177. "AxisPreceding", "AxisPrecedingSilbing", "AxisSelf",
  178. "GetContextNode", "GetParentNode", "AxisDescendantOrSelfLit",
  179. "AxisDescendantLit", "SlashSlash",
  180. "CombinePath", "IsRoot", "ToParent", "ToAncestors", "FillNodeList",
  181. "FillWithCurrentNode",
  182. "ExecIdKey"
  183. };
  184. /*----------------------------------------------------------------------------
  185. | functionTag
  186. |
  187. \---------------------------------------------------------------------------*/
  188. typedef enum {
  189. f_unknown = 1,
  190. f_boolean, f_ceiling, f_concat, f_contains, f_count, f_false, f_floor,
  191. f_generateId, f_id, f_lang, f_last, f_localName, f_name, f_namespaceUri,
  192. f_normalizeSpace, f_not, f_number, f_position, f_round, f_startsWith,
  193. f_string, f_stringLength, f_substring, f_substringAfter,
  194. f_substringBefore, f_sum, f_translate, f_true, f_unparsedEntityUri,
  195. f_fqfunction
  196. } functionTag;
  197. /*----------------------------------------------------------------------------
  198. | Prototypes / Forwards
  199. |
  200. \---------------------------------------------------------------------------*/
  201. DeclProduction(OrExpr);
  202. DeclProduction(Predicate);
  203. DeclProduction(RelativeLocationPath);
  204. DeclProduction(AbsoluteLocationPath);
  205. char *xpathFuncString (xpathResultSet *rs );
  206. static int xpathEvalStep (ast step, domNode *ctxNode, domNode *exprContext,
  207. int position, xpathResultSet *nodeList,
  208. xpathCBs *cbs, xpathResultSet *result,
  209. int *docOrder, char **errMsg);
  210. static int xpathEvalPredicate (ast steps, domNode *exprContext,
  211. xpathResultSet *result,
  212. xpathResultSet *stepResult,
  213. xpathCBs *cbs, int *docOrder, char **errMsg);
  214. /*----------------------------------------------------------------------------
  215. | xpath result set functions
  216. |
  217. \---------------------------------------------------------------------------*/
  218. void xpathRSFree ( xpathResultSet *rs ) {
  219. if (rs->type == xNodeSetResult) {
  220. if (!rs->intvalue) {
  221. if (rs->nodes) FREE((char*)rs->nodes);
  222. }
  223. rs->nr_nodes = 0;
  224. } else
  225. if (rs->type == StringResult) {
  226. if (rs->string) FREE((char*)rs->string);
  227. }
  228. rs->type = EmptyResult;
  229. }
  230. void rsPrint ( xpathResultSet *rs ) {
  231. int i = 0,l; char tmp[80];
  232. switch (rs->type) {
  233. case EmptyResult:
  234. fprintf(stderr, "empty result \n");
  235. break;
  236. case BoolResult:
  237. fprintf(stderr, "boolean result: %d \n", rs->intvalue);
  238. break;
  239. case IntResult:
  240. fprintf(stderr, "int result: %d \n", rs->intvalue);
  241. break;
  242. case RealResult:
  243. fprintf(stderr, "real result: %f \n", rs->realvalue);
  244. break;
  245. case StringResult:
  246. fprintf(stderr, "string result: -%*s-\n", rs->string_len,
  247. rs->string);
  248. break;
  249. case xNodeSetResult:
  250. if (!i) fprintf(stderr,"nodeSet result (len %d):\n",rs->nr_nodes);
  251. for (i=0; i<rs->nr_nodes; i++) {
  252. if (rs->nodes[i]->nodeType == ELEMENT_NODE) {
  253. fprintf(stderr, "%2d domNode%p %s ",
  254. i, rs->nodes[i], rs->nodes[i]->nodeName);
  255. if (rs->nodes[i]->firstChild &&
  256. rs->nodes[i]->firstChild->nodeType == TEXT_NODE)
  257. {
  258. l = ((domTextNode*)rs->nodes[i]->firstChild)->valueLength;
  259. if (l > 25) l = 25;
  260. memcpy(tmp, ((domTextNode*)rs->nodes[i]->firstChild)->nodeValue, l);
  261. tmp[l] = '\0';
  262. fprintf(stderr, "'%s'", tmp);
  263. }
  264. fprintf(stderr, "\n");
  265. } else
  266. if (rs->nodes[i]->nodeType == TEXT_NODE) {
  267. l = ((domTextNode*)rs->nodes[i])->valueLength;
  268. if (l > 60) l = 60;
  269. memcpy(tmp, ((domTextNode*)rs->nodes[i])->nodeValue, l);
  270. tmp[l] = '\0';
  271. fprintf(stderr, "%2d domNode%p text:'%s' \n",
  272. i, rs->nodes[i], tmp);
  273. } else
  274. if (rs->nodes[i]->nodeType == COMMENT_NODE) {
  275. l = ((domTextNode*)rs->nodes[i])->valueLength;
  276. memcpy (tmp, "<!--", 4);
  277. if (l > 60) l = 60;
  278. memcpy(&tmp[4], ((domTextNode*)rs->nodes[i])->nodeValue, l);
  279. memcpy(&tmp[4+l], "-->", 3);
  280. tmp[7+l] = '\0';
  281. fprintf(stderr, "%2d domNode%p text:'%s' \n",
  282. i, rs->nodes[i], tmp);
  283. } else
  284. if (rs->nodes[i]->nodeType == ATTRIBUTE_NODE) {
  285. fprintf(stderr, "%2d Attr %s='%*s'\n", i,
  286. ((domAttrNode*)rs->nodes[i])->nodeName,
  287. ((domAttrNode*)rs->nodes[i])->valueLength,
  288. ((domAttrNode*)rs->nodes[i])->nodeValue);
  289. }
  290. }
  291. break;
  292. case NaNResult: fprintf (stderr, "NaN result\n"); break;
  293. case InfResult: fprintf (stderr, "Inf result\n"); break;
  294. case NInfResult: fprintf (stderr, "-Inf result\n"); break;
  295. default:
  296. fprintf (stderr, "unknown result type: '%d'!!!\n", rs->type);
  297. break;
  298. }
  299. }
  300. void rsSetReal ( xpathResultSet *rs, double d) {
  301. rs->type = RealResult;
  302. rs->realvalue = d;
  303. }
  304. void rsSetNaN ( xpathResultSet *rs ) {
  305. rs->type = NaNResult;
  306. }
  307. void rsSetInf ( xpathResultSet *rs ) {
  308. rs->type = InfResult;
  309. }
  310. void rsSetNInf ( xpathResultSet *rs ) {
  311. rs->type = NInfResult;
  312. }
  313. void rsSetInt ( xpathResultSet *rs, int i) {
  314. rs->type = IntResult;
  315. rs->intvalue = i;
  316. }
  317. void rsSetBool ( xpathResultSet *rs, int i) {
  318. rs->type = BoolResult;
  319. rs->intvalue = (i ? 1 : 0);
  320. }
  321. void rsSetString ( xpathResultSet *rs, char *s) {
  322. rs->type = StringResult;
  323. if (s) {
  324. rs->string = tdomstrdup(s);
  325. rs->string_len = strlen(s);
  326. } else {
  327. rs->string = tdomstrdup("");
  328. rs->string_len = 0;
  329. }
  330. rs->nr_nodes = 0;
  331. }
  332. void rsAddNode ( xpathResultSet *rs, domNode *node) {
  333. if ((rs->type != EmptyResult) && (rs->type != xNodeSetResult)) {
  334. domPanic("Can not add node to non NodeSetResult xpathResultSet!");
  335. }
  336. if (rs->type == EmptyResult) {
  337. rs->type = xNodeSetResult;
  338. rs->nodes = (domNode**)MALLOC(INITIAL_SIZE * sizeof(domNode*));
  339. rs->allocated = INITIAL_SIZE;
  340. rs->nr_nodes = 1;
  341. rs->nodes[0] = node;
  342. } else {
  343. int insertIndex;
  344. int i;
  345. if (rs->intvalue) {
  346. /* we must do a copy-on-write */
  347. domNode **nodes;
  348. nodes = (domNode**)MALLOC(rs->allocated * sizeof(domNode*));
  349. memcpy (nodes, rs->nodes, sizeof(domNode*) * rs->nr_nodes);
  350. rs->nodes = nodes;
  351. rs->intvalue = 0;
  352. }
  353. insertIndex = rs->nr_nodes;
  354. for (i = rs->nr_nodes - 1; i >= 0; i--) {
  355. if (node == rs->nodes[i]) return;
  356. if (!domPrecedes (node, rs->nodes[i])) {
  357. break;
  358. }
  359. insertIndex--;
  360. }
  361. if ((rs->nr_nodes+1) >= rs->allocated) {
  362. rs->nodes = (domNode**)REALLOC((void*)rs->nodes,
  363. 2 * rs->allocated * sizeof(domNode*));
  364. rs->allocated = rs->allocated * 2;
  365. }
  366. if (insertIndex == rs->nr_nodes) {
  367. rs->nodes[rs->nr_nodes++] = node;
  368. } else {
  369. for (i = rs->nr_nodes - 1; i >= insertIndex; i--) {
  370. rs->nodes[i+1] = rs->nodes[i];
  371. }
  372. rs->nodes[insertIndex] = node;
  373. rs->nr_nodes++;
  374. }
  375. }
  376. }
  377. void rsAddNodeFast ( xpathResultSet *rs, domNode *node) {
  378. if ((rs->type != EmptyResult) && (rs->type != xNodeSetResult)) {
  379. fprintf(stderr, "could not add node to non NodeSetResult xpathResultSet!"); return;
  380. }
  381. if (rs->type == EmptyResult) {
  382. rs->type = xNodeSetResult;
  383. rs->nodes = (domNode**)MALLOC(INITIAL_SIZE * sizeof(domNode*));
  384. rs->allocated = INITIAL_SIZE;
  385. rs->nr_nodes = 1;
  386. rs->nodes[0] = node;
  387. } else {
  388. if ((rs->nr_nodes+1) >= rs->allocated) {
  389. rs->nodes = (domNode**)REALLOC((void*)rs->nodes,
  390. 2 * rs->allocated * sizeof(domNode*));
  391. rs->allocated = rs->allocated * 2;
  392. }
  393. rs->nodes[rs->nr_nodes++] = node;
  394. }
  395. }
  396. void rsCopy ( xpathResultSet *to, xpathResultSet *from ) {
  397. int i;
  398. to->type = from->type;
  399. to->intvalue = from->intvalue;
  400. if (from->type == RealResult) {
  401. to->realvalue = from->realvalue;
  402. } else
  403. if (from->type == StringResult) {
  404. to->string = tdomstrdup(from->string);
  405. to->string_len = from->string_len;
  406. } else
  407. if (from->type == xNodeSetResult) {
  408. to->nr_nodes = from->nr_nodes;
  409. to->nodes = (domNode**)MALLOC(from->nr_nodes * sizeof(domNode*));
  410. for (i=0; i<from->nr_nodes; i++)
  411. to->nodes[i] = from->nodes[i];
  412. to->intvalue = 0;
  413. }
  414. }
  415. /*----------------------------------------------------------------------------
  416. | AST construct functions
  417. |
  418. \---------------------------------------------------------------------------*/
  419. static ast New( astType type ) {
  420. ast t = NEWCONS;
  421. t->type = type;
  422. t->next = t->child = NULL;
  423. t->strvalue = NULL;
  424. t->intvalue = 0;
  425. t->realvalue = 0.0;
  426. return t;
  427. }
  428. static ast New1( astType type, ast a) {
  429. ast t = NEWCONS;
  430. t->type = type;
  431. t->next = NULL;
  432. t->child = a;
  433. t->strvalue = NULL;
  434. t->intvalue = 0;
  435. t->realvalue = 0.0;
  436. return t;
  437. }
  438. static ast New1WithEvalSteps( astType type, ast a) {
  439. ast t = NEWCONS;
  440. t->type = type;
  441. t->next = NULL;
  442. if (a && a->next) {
  443. t->child = New1(EvalSteps,a);
  444. } else {
  445. t->child = a;
  446. }
  447. t->strvalue = NULL;
  448. t->intvalue = 0;
  449. t->realvalue = 0.0;
  450. return t;
  451. }
  452. static ast New2( astType type, ast a, ast b ) {
  453. ast t = NEWCONS;
  454. t->type = type;
  455. t->next = NULL;
  456. t->strvalue = NULL;
  457. t->intvalue = 0;
  458. t->realvalue = 0.0;
  459. if (a && a->next) {
  460. t->child = New1(EvalSteps,a);
  461. } else {
  462. t->child = a;
  463. }
  464. if (b && b->next) {
  465. t->child->next = New1(EvalSteps, b);
  466. } else {
  467. t->child->next = b;
  468. }
  469. return t;
  470. }
  471. static ast NewInt( int i ) {
  472. ast t = NEWCONS;
  473. t->type = Int;
  474. t->strvalue = NULL;
  475. t->intvalue = i;
  476. t->realvalue = 0.0;
  477. t->next = t->child = NULL;
  478. return t;
  479. }
  480. static ast NewReal( double r ) {
  481. ast t = NEWCONS;
  482. t->type = Real;
  483. t->strvalue = NULL;
  484. t->intvalue = 0;
  485. t->realvalue = r;
  486. t->next = t->child = NULL;
  487. return t;
  488. }
  489. static ast NewStr( astType type, char *str ) {
  490. ast t = NEWCONS;
  491. t->type = type;
  492. t->strvalue = tdomstrdup(str);
  493. t->intvalue = 0;
  494. t->realvalue = 0.0;
  495. t->next = t->child = NULL;
  496. return t;
  497. }
  498. static ast Append( ast m, ast n ) {
  499. if (!n) return NULL;
  500. if (!m) return NULL;
  501. while (m->next != NULL) m = m->next;
  502. m->next = n;
  503. return m;
  504. }
  505. static ast AddChild( ast m, ast child ) {
  506. if (!child) return NULL;
  507. if (!m) return NULL;
  508. if (m->child == NULL) {
  509. m->child = child;
  510. } else {
  511. ast c = m->child;
  512. while (c->next != NULL) c = c->next;
  513. c->next = child;
  514. }
  515. return m;
  516. }
  517. static ast AddChildWithEvalSteps( ast m, ast child ) {
  518. if (!child) return NULL;
  519. if (!m) return NULL;
  520. if (child->next) {
  521. child = New1(EvalSteps, child);
  522. }
  523. if (m->child == NULL) {
  524. m->child = child;
  525. } else {
  526. ast c = m->child;
  527. while (c->next != NULL) c = c->next;
  528. c->next = child;
  529. }
  530. /*child->next = NULL;*/
  531. return m;
  532. }
  533. static void freeAst (ast t)
  534. {
  535. ast tmp;
  536. while (t) {
  537. tmp = t->next;
  538. if (t->strvalue) FREE(t->strvalue);
  539. if (t->child) freeAst (t->child);
  540. FREE((char*)t);
  541. t = tmp;
  542. }
  543. }
  544. void printAst (int depth, ast t)
  545. {
  546. int i;
  547. while (t) {
  548. for (i=0; i<depth; i++) fprintf(stderr, " ");
  549. fprintf(stderr, "%s ", astType2str[t->type]);
  550. switch (t->type) {
  551. case Int : fprintf(stderr, "%d", t->intvalue); break;
  552. case Real: fprintf(stderr, "%f", t->realvalue); break;
  553. case IsElement:
  554. case IsFQElement:
  555. case IsNSAttr:
  556. case IsAttr:
  557. case ExecFunction:
  558. case Literal:
  559. case GetFQVar:
  560. case GetVar: fprintf(stderr, "'%s'", t->strvalue); break;
  561. default: break;
  562. }
  563. fprintf(stderr, "\n");
  564. if (t->child) printAst (depth+1, t->child);
  565. t = t->next;
  566. }
  567. }
  568. /*----------------------------------------------------------------------------
  569. | xpathFreeAst
  570. |
  571. \---------------------------------------------------------------------------*/
  572. void xpathFreeAst(
  573. ast t
  574. )
  575. {
  576. freeAst(t);
  577. }
  578. /*----------------------------------------------------------------------------
  579. | xpathLexer
  580. |
  581. \---------------------------------------------------------------------------*/
  582. static XPathTokens xpathLexer (
  583. char *xpath,
  584. domNode *exprContext,
  585. char **prefixMappings,
  586. int *useNamespaceAxis,
  587. xpathParseVarCB *varParseCB,
  588. char **errMsg
  589. )
  590. {
  591. int l, allocated;
  592. int i, k, start, offset;
  593. char delim, *ps, save, *uri, tmpErr[80];
  594. XPathTokens tokens;
  595. int token = EOS;
  596. tokens = (XPathTokens)MALLOC(INITIAL_SIZE * sizeof(XPathToken));
  597. if (tokens == NULL) {
  598. *errMsg = tdomstrdup("Unable to alloc initial memory!");
  599. return NULL;
  600. }
  601. allocated = INITIAL_SIZE;
  602. l = 0;
  603. tokens[l].token = EOS;
  604. tokens[l].strvalue = NULL;
  605. tokens[l].intvalue = 0;
  606. tokens[l].realvalue = 0.0;
  607. i = 0;
  608. while (xpath[i]) {
  609. switch (xpath[i]) {
  610. case ' ' :
  611. case '\n':
  612. case '\r':
  613. case '\t': i++; continue;
  614. case '(': token = LPAR; break;
  615. case ')': token = RPAR; break;
  616. case '[': token = LBRACKET; break;
  617. case ']': token = RBRACKET; break;
  618. case '@': i++;
  619. while (xpath[i] && IS_XML_WHITESPACE(xpath[i])) i++;
  620. if ( isNCNameStart (&xpath[i]) ) {
  621. ps = &(xpath[i]);
  622. i += UTF8_CHAR_LEN (xpath[i]);
  623. while (xpath[i] && isNCNameChar (&xpath[i]))
  624. i += UTF8_CHAR_LEN (xpath[i]);
  625. save = xpath[i];
  626. xpath[i] = '\0';
  627. if (save == ':' && xpath[i+1] != ':') {
  628. uri = domLookupPrefixWithMappings (
  629. exprContext, ps, prefixMappings);
  630. if (!uri) {
  631. xpath[i] = save;
  632. *errMsg = tdomstrdup ("Prefix doesn't"
  633. " resolve");
  634. return tokens;
  635. }
  636. tokens[l].strvalue = tdomstrdup (uri);
  637. xpath[i] = save;
  638. token = ATTRIBUTEPREFIX;
  639. ADD_TOKEN (token);
  640. if (xpath[i+1] == '*') {
  641. token = ATTRIBUTE;
  642. tokens[l].strvalue = tdomstrdup("*");
  643. i++;
  644. } else {
  645. ps = &(xpath[++i]);
  646. if (!(isNCNameStart (&xpath[i]))) {
  647. *errMsg =
  648. tdomstrdup ("Illegal attribute"
  649. " name");
  650. return tokens;
  651. }
  652. i += UTF8_CHAR_LEN (xpath[i]);
  653. while (xpath[i] && isNCNameChar (&xpath[i]))
  654. i += UTF8_CHAR_LEN (xpath[i]);
  655. save = xpath[i];
  656. xpath[i] = '\0';
  657. token = ATTRIBUTE;
  658. tokens[l].strvalue = tdomstrdup(ps);
  659. xpath[i--] = save;
  660. }
  661. } else {
  662. tokens[l].strvalue = tdomstrdup(ps);
  663. xpath[i] = save;
  664. token = ATTRIBUTE;
  665. i--;
  666. }
  667. } else if (xpath[i]=='*') {
  668. tokens[l].strvalue = tdomstrdup("*");
  669. token = ATTRIBUTE;
  670. } else {
  671. *errMsg = tdomstrdup("Expected attribute name");
  672. return tokens;
  673. }; break;
  674. case ',': token = COMMA; break;
  675. case ':': if (xpath[i+1] == ':') {
  676. token = COLONCOLON;
  677. i++;
  678. } else {
  679. *errMsg = tdomstrdup("Unexpected token ':'");
  680. return tokens;
  681. }; break;
  682. case '"' :
  683. case '\'': delim = xpath[i]; start = ++i;
  684. while (xpath[i] && (xpath[i] != delim)) i++;
  685. if (!xpath[i]) {
  686. *errMsg = tdomstrdup("Undetermined string");
  687. return tokens;
  688. }
  689. xpath[i] = '\0'; /* terminate string */
  690. tokens[l].strvalue = tdomstrdup(&xpath[start]);
  691. token = LITERAL;
  692. xpath[i] = delim;
  693. break;
  694. case '/': if (xpath[i+1] == '/') {
  695. token = SLASHSLASH;
  696. i++;
  697. } else {
  698. token = SLASH;
  699. };
  700. break;
  701. case '|': token = PIPE; break;
  702. case '+': token = PLUS; break;
  703. case '-': token = MINUS; break;
  704. case '=': token = EQUAL; break;
  705. case '!': if (xpath[i+1] == '=') {
  706. token = NOTEQ;
  707. i++;
  708. } else {
  709. *errMsg = tdomstrdup("Unexpected token '!'");
  710. return tokens;
  711. }; break;
  712. case '<': if (xpath[i+1] == '=') {
  713. token = LTE;
  714. i++;
  715. } else {
  716. token = LT;
  717. };break;
  718. case '>': if (xpath[i+1] == '=') {
  719. token = GTE;
  720. i++;
  721. } else {
  722. token = GT;
  723. }; break;
  724. case '*': if ((l>0)
  725. && (tokens[l-1].token != COLONCOLON)
  726. && (tokens[l-1].token != LPAR)
  727. && (tokens[l-1].token != LBRACKET)
  728. && (tokens[l-1].token != COMMA)
  729. && (tokens[l-1].token != SLASH)
  730. && (tokens[l-1].token != SLASHSLASH)
  731. ) {
  732. token = MULTIPLY;
  733. } else {
  734. token = WCARDNAME;
  735. tokens[l].strvalue = tdomstrdup("*");
  736. }; break;
  737. case '$': if (varParseCB) {
  738. ps = (varParseCB->parseVarCB) (
  739. varParseCB->parseVarClientData, &xpath[i],
  740. &offset, errMsg
  741. );
  742. if (ps) {
  743. token = LITERAL;
  744. tokens[l].strvalue = tdomstrdup (ps);
  745. i += offset - 1;
  746. } else {
  747. return tokens;
  748. }
  749. } else {
  750. i++;
  751. if ( isNCNameStart (&xpath[i])) {
  752. ps = &(xpath[i]);
  753. i += UTF8_CHAR_LEN (xpath[i]);
  754. while (xpath[i] && isNCNameChar(&xpath[i]))
  755. i += UTF8_CHAR_LEN(xpath[i]);
  756. if (xpath[i] == ':' && xpath[i+1] != ':') {
  757. token = FQVARIABLE;
  758. save = xpath[i];
  759. xpath[i] = '\0';
  760. uri = domLookupPrefixWithMappings (
  761. exprContext, ps, prefixMappings);
  762. if (!uri) {
  763. xpath[i] = save;
  764. *errMsg = tdomstrdup ("Prefix doesn't"
  765. " resolve");
  766. return tokens;
  767. }
  768. tokens[l].strvalue = tdomstrdup (uri);
  769. xpath[i] = save;
  770. ADD_TOKEN (token);
  771. ps = &(xpath[++i]);
  772. if (!isNCNameStart (&xpath[i])) {
  773. *errMsg = tdomstrdup ("Illegal variable"
  774. " name");
  775. return tokens;
  776. }
  777. i += UTF8_CHAR_LEN (xpath[i]);
  778. while (xpath[i] && isNCNameChar (&xpath[i]))
  779. i += UTF8_CHAR_LEN (xpath[i]);
  780. }
  781. token = VARIABLE;
  782. save = xpath[i];
  783. xpath[i] = '\0';
  784. tokens[l].strvalue = tdomstrdup(ps);
  785. xpath[i--] = save;
  786. } else {
  787. *errMsg = tdomstrdup("Expected variable name");
  788. return tokens;
  789. }
  790. }
  791. break;
  792. case '.': if (xpath[i+1] == '.') {
  793. token = DOTDOT;
  794. i++;
  795. break;
  796. } else if (!isdigit((unsigned char)xpath[i+1])) {
  797. token = DOT;
  798. break;
  799. }
  800. /* DOT followed by digit, ie a REAL.
  801. Handled by default. Fall throu */
  802. default: if ( isNCNameStart (&xpath[i])) {
  803. ps = &(xpath[i]);
  804. i += UTF8_CHAR_LEN (xpath[i]);
  805. while (xpath[i] && isNCNameChar(&xpath[i])) {
  806. i += UTF8_CHAR_LEN(xpath[i]);
  807. }
  808. k = i;
  809. if (xpath[i] == ':') {
  810. if (xpath[i+1] == '*') {
  811. save = xpath[i];
  812. xpath[i] = '\0'; /* terminate */
  813. token = NSWC;
  814. uri = domLookupPrefixWithMappings (
  815. exprContext, ps, prefixMappings);
  816. if (!uri) {
  817. xpath[i] = save;
  818. *errMsg = tdomstrdup ("Prefix doesn't"
  819. " resolve");
  820. return tokens;
  821. }
  822. tokens[l].strvalue = tdomstrdup (uri);
  823. xpath[i] = save;
  824. i++;
  825. break;
  826. }
  827. if (xpath[i+1] != ':') {
  828. save = xpath[i];
  829. xpath[i] = '\0'; /* terminate */
  830. token = NSPREFIX;
  831. uri = domLookupPrefixWithMappings (
  832. exprContext, ps, prefixMappings);
  833. if (!uri) {
  834. xpath[i] = save;
  835. *errMsg = tdomstrdup ("Prefix doesn't"
  836. " resolve");
  837. return tokens;
  838. }
  839. tokens[l].strvalue = tdomstrdup (uri);
  840. xpath[i] = save;
  841. ADD_TOKEN (token);
  842. ps = &(xpath[++i]);
  843. if (!(isNCNameStart (&xpath[i]))) {
  844. *errMsg =
  845. tdomstrdup ("Illegal character in"
  846. " localname");
  847. return tokens;
  848. }
  849. i += UTF8_CHAR_LEN (xpath[i]);
  850. while (xpath[i] && isNCNameChar (&xpath[i]))
  851. i += UTF8_CHAR_LEN (xpath[i]);
  852. k = i;
  853. }
  854. }
  855. /* read over white space */
  856. while ((xpath[k] == ' ') ||
  857. (xpath[k] == '\n') ||
  858. (xpath[k] == '\r') ||
  859. (xpath[k] == '\t') ) k++;
  860. if (l>0 && tokens[l-1].token == NSPREFIX) {
  861. if (xpath[k]!='(') token = WCARDNAME;
  862. else token = FUNCTION;
  863. save = xpath[i];
  864. xpath[i] = '\0';
  865. tokens[l].strvalue = tdomstrdup(ps);
  866. xpath[i--] = save;
  867. break;
  868. }
  869. if (xpath[k]=='(') {
  870. save = xpath[i];
  871. xpath[i] = '\0'; /* terminate */
  872. if (strcmp(ps,"text")==0) {
  873. token = TEXT;
  874. } else if (strcmp(ps,"node")==0) {
  875. token = NODE;
  876. } else if (strcmp(ps,"comment")==0) {
  877. token = COMMENT;
  878. } else if (strcmp(ps,"processing-instruction")==0) {
  879. token = PINSTR;
  880. } else {
  881. if ((save!='(') && (strcmp(ps,"and")==0)) token = AND;
  882. else
  883. if ((save!='(') && (strcmp(ps,"or")==0)) token = OR;
  884. else
  885. if ((save!='(') && (strcmp(ps,"mod")==0)) token = MOD;
  886. else
  887. if ((save!='(') && (strcmp(ps,"div")==0)) token = DIV;
  888. else {
  889. token = FUNCTION;
  890. tokens[l].strvalue = tdomstrdup(ps);
  891. }
  892. }
  893. xpath[i] = save;
  894. } else if ((xpath[k]==':') && (xpath[k+1]==':')) {
  895. token = AXISNAME;
  896. save = xpath[i];
  897. xpath[i] = '\0'; /* terminate */
  898. tokens[l].strvalue = tdomstrdup(ps);
  899. if (ps[0] == 'n'&& strcmp(ps, "namespace")==0) {
  900. *useNamespaceAxis = 1;
  901. }
  902. xpath[i] = save;
  903. } else {
  904. save = xpath[i];
  905. xpath[i] = '\0';
  906. if ((l>0)
  907. && (tokens[l-1].token != COLONCOLON)
  908. && (tokens[l-1].token != LPAR)
  909. && (tokens[l-1].token != LBRACKET)
  910. && (tokens[l-1].token != COMMA)
  911. && (tokens[l-1].token != SLASH)
  912. && (tokens[l-1].token != SLASHSLASH)
  913. && (tokens[l-1].token != PIPE)
  914. && (tokens[l-1].token != PLUS)
  915. && (tokens[l-1].token != MINUS)
  916. && (tokens[l-1].token != EQUAL)
  917. && (tokens[l-1].token != NOTEQ)
  918. && (tokens[l-1].token != LT)
  919. && (tokens[l-1].token != LTE)
  920. && (tokens[l-1].token != GT)
  921. && (tokens[l-1].token != GTE)
  922. && (tokens[l-1].token != AND)
  923. && (tokens[l-1].token != OR)
  924. && (tokens[l-1].token != MOD)
  925. && (tokens[l-1].token != DIV)
  926. && (tokens[l-1].token != MULTIPLY)
  927. ) {
  928. if (strcmp(ps,"and")==0) {
  929. token = AND;
  930. } else if (strcmp(ps,"or")==0) {
  931. token = OR;
  932. } else if (strcmp(ps,"mod")==0) {
  933. token = MOD;
  934. } else if (strcmp(ps,"div")==0) {
  935. token = DIV;
  936. } else {
  937. token = WCARDNAME;
  938. tokens[l].strvalue = tdomstrdup(ps);
  939. }
  940. } else {
  941. token = WCARDNAME;
  942. tokens[l].strvalue = tdomstrdup(ps);
  943. }
  944. xpath[i] = save;
  945. }
  946. i--;
  947. } else if (isdigit((unsigned char)xpath[i])
  948. || (xpath[i] == '.')) {
  949. if (xpath[i] == '.') {
  950. token = REALNUMBER;
  951. } else {
  952. token = INTNUMBER;
  953. }
  954. ps = &(xpath[i++]);
  955. while (xpath[i] && isdigit((unsigned char)xpath[i]))
  956. i++;
  957. if (xpath[i]=='.') {
  958. if (token == REALNUMBER) {
  959. sprintf (tmpErr, "Unexpected character "
  960. "'%c' at position %d", xpath[i],
  961. i);
  962. *errMsg = tdomstrdup (tmpErr);
  963. return tokens;
  964. }
  965. token = REALNUMBER;
  966. i++;
  967. while (xpath[i]
  968. && isdigit((unsigned char)xpath[i])) i++;
  969. }
  970. save = xpath[i];
  971. xpath[i] = '\0';
  972. if (token == INTNUMBER) {
  973. tokens[l].intvalue = atoi(ps);
  974. }
  975. tokens[l].realvalue = (double)atof(ps);
  976. xpath[i--] = save;
  977. } else {
  978. sprintf (tmpErr, "Unexpected character '%c' at "
  979. "position %d", xpath[i], i);
  980. *errMsg = tdomstrdup (tmpErr);
  981. return tokens;
  982. }
  983. break;
  984. } /* switch */
  985. ADD_TOKEN(token);
  986. i++;
  987. }
  988. ADD_TOKEN(EOS);
  989. return tokens;
  990. } /* xpathLexer */
  991. /*-----------------------------------------------------------------
  992. | NodeTest production
  993. |
  994. \----------------------------------------------------------------*/
  995. Production(NodeTest)
  996. if (LA==NODE) {
  997. Consume(NODE);
  998. Consume(LPAR);
  999. Consume(RPAR);
  1000. a = New (IsNode);
  1001. } else
  1002. if (LA==TEXT) {
  1003. Consume(TEXT);
  1004. Consume(LPAR);
  1005. Consume(RPAR);
  1006. a = New (IsText);
  1007. } else
  1008. if (LA==COMMENT) {
  1009. Consume(COMMENT);
  1010. Consume(LPAR);
  1011. Consume(RPAR);
  1012. a = New (IsComment);
  1013. } else
  1014. if (LA==PINSTR) {
  1015. Consume(PINSTR);
  1016. Consume(LPAR);
  1017. if (LA==LITERAL) {
  1018. Consume(LITERAL);
  1019. a = NewStr (IsSpecificPI, STRVAL);
  1020. } else {
  1021. a = New (IsPI);
  1022. }
  1023. Consume(RPAR);
  1024. } else
  1025. if (LA==MULTIPLY) {
  1026. Consume(MULTIPLY);
  1027. a = NewStr (IsElement, "*");
  1028. } else
  1029. if (LA==NSPREFIX) {
  1030. ast b;
  1031. Consume (NSPREFIX);
  1032. a = NewStr (IsFQElement, STRVAL);
  1033. Consume (WCARDNAME);
  1034. b = NewStr (IsElement, STRVAL);
  1035. AddChild (a, b);
  1036. } else
  1037. if (LA==NSWC) {
  1038. Consume (NSWC);
  1039. a = NewStr (IsNSElement, STRVAL);
  1040. } else {
  1041. Consume(WCARDNAME);
  1042. a = NewStr (IsElement, STRVAL);
  1043. }
  1044. EndProduction
  1045. /*-----------------------------------------------------------------
  1046. | AbbreviatedBasis production
  1047. |
  1048. \----------------------------------------------------------------*/
  1049. Production(AbbreviatedBasis)
  1050. if (LA==ATTRIBUTE) {
  1051. Consume(ATTRIBUTE);
  1052. a = New1( AxisAttribute, NewStr(IsAttr, STRVAL) );
  1053. } else
  1054. if (LA==ATTRIBUTEPREFIX) {
  1055. ast b, c;
  1056. Consume(ATTRIBUTEPREFIX);
  1057. a = New (AxisAttribute);
  1058. b = NewStr (IsNSAttr, STRVAL);
  1059. AddChild (a, b);
  1060. Consume(ATTRIBUTE);
  1061. c = NewStr (IsAttr, STRVAL);
  1062. AddChild (b, c);
  1063. }
  1064. else {
  1065. a = New1( AxisChild, Recurse(NodeTest));
  1066. }
  1067. EndProduction
  1068. /*-----------------------------------------------------------------
  1069. | getFunctionTag
  1070. |
  1071. \----------------------------------------------------------------*/
  1072. static functionTag
  1073. getFunctionTag (char *funcName)
  1074. {
  1075. switch (funcName[0]) {
  1076. case 'b':
  1077. if (strcmp (funcName, "boolean")==0) return f_boolean;
  1078. break;
  1079. case 'c':
  1080. if (strcmp (funcName, "ceiling")==0) return f_ceiling;
  1081. else if (strcmp (funcName, "concat")==0) return f_concat;
  1082. else if (strcmp (funcName, "contains")==0) return f_contains;
  1083. else if (strcmp (funcName, "count")==0) return f_count;
  1084. break;
  1085. case 'f':
  1086. if (strcmp (funcName, "false")==0) return f_false;
  1087. else if (strcmp (funcName, "floor")==0) return f_floor;
  1088. break;
  1089. case 'g':
  1090. if (strcmp (funcName, "generate-id")==0) return f_generateId;
  1091. break;
  1092. case 'i':
  1093. if (strcmp (funcName, "id")==0) return f_id;
  1094. case 'l':
  1095. if (strcmp (funcName, "lang")==0) return f_lang;
  1096. else if (strcmp (funcName, "last")==0) return f_last;
  1097. else if (strcmp (funcName, "local-name")==0) return f_localName;
  1098. break;
  1099. case 'n':
  1100. if (strcmp (funcName, "name")==0) return f_name;
  1101. else if (strcmp (funcName, "namespace-uri")==0) return f_namespaceUri;
  1102. else if (strcmp (funcName, "normalize-space")==0) return f_normalizeSpace;
  1103. else if (strcmp (funcName, "not")==0) return f_not;
  1104. else if (strcmp (funcName, "number")==0) return f_number;
  1105. break;
  1106. case 'p':
  1107. if (strcmp (funcName, "position")==0) return f_position;
  1108. break;
  1109. case 'r':
  1110. if (strcmp (funcName, "round")==0) return f_round;
  1111. break;
  1112. case 's':
  1113. if (strcmp (funcName, "starts-with")==0) return f_startsWith;
  1114. else if (strcmp (funcName, "string")==0) return f_string;
  1115. else if (strcmp (funcName, "string-length")==0) return f_stringLength;
  1116. else if (strcmp (funcName, "substring")==0) return f_substring;
  1117. else if (strcmp (funcName, "substring-after")==0) return f_substringAfter;
  1118. else if (strcmp (funcName, "substring-before")==0) return f_substringBefore;
  1119. else if (strcmp (funcName, "sum")==0) return f_sum;
  1120. break;
  1121. case 't':
  1122. if (strcmp (funcName, "translate")==0) return f_translate;
  1123. else if (strcmp (funcName, "true")==0) return f_true;
  1124. break;
  1125. case 'u':
  1126. if (strcmp (funcName, "unparsed-entity-uri")==0) return f_unparsedEntityUri;
  1127. break;
  1128. default:
  1129. break;
  1130. }
  1131. return f_unknown;
  1132. }
  1133. /*-----------------------------------------------------------------
  1134. | FilterExpr production
  1135. |
  1136. \----------------------------------------------------------------*/
  1137. Production(FilterExpr)
  1138. if (LA==VARIABLE) {
  1139. Consume(VARIABLE);
  1140. a = NewStr( GetVar, STRVAL);
  1141. } else if (LA==FQVARIABLE) {
  1142. Consume(FQVARIABLE);
  1143. a = NewStr( GetFQVar, STRVAL);
  1144. Consume(VARIABLE);
  1145. AddChild (a, NewStr( GetVar, STRVAL));
  1146. } else if (LA==LPAR) {
  1147. Consume(LPAR);
  1148. a = New1(EvalSteps, Recurse(OrExpr));
  1149. Consume(RPAR);
  1150. } else if (LA==LITERAL) {
  1151. Consume(LITERAL);
  1152. a = NewStr( Literal, STRVAL);
  1153. } else if (LA==INTNUMBER) {
  1154. Consume(INTNUMBER);
  1155. a = NewInt( INTVAL );
  1156. } else if (LA==REALNUMBER) {
  1157. Consume(REALNUMBER);
  1158. a = NewReal( REALVAL );
  1159. } else if (LA==FUNCTION || LA==NSPREFIX) {
  1160. if (LA==FUNCTION) {
  1161. Consume(FUNCTION);
  1162. a = NewStr( ExecFunction, STRVAL);
  1163. a->intvalue = getFunctionTag (STRVAL);
  1164. } else {
  1165. Consume(NSPREFIX);
  1166. a = NewStr( ExecFunction, STRVAL);
  1167. a->intvalue = f_fqfunction;
  1168. Consume(FUNCTION);
  1169. AddChild (a, NewStr( ExecFunction, STRVAL));
  1170. }
  1171. Consume(LPAR);
  1172. if (LA!=RPAR) {
  1173. AddChildWithEvalSteps (a, Recurse(OrExpr));
  1174. while(LA==COMMA) {
  1175. Consume(COMMA);
  1176. AddChildWithEvalSteps (a, Recurse(OrExpr) );
  1177. }
  1178. }
  1179. Consume(RPAR);
  1180. } else {
  1181. ErrExpected("$var or (expr) or literal or number or func");
  1182. }
  1183. while (LA==LBRACKET) {
  1184. ast b;
  1185. b = Recurse(Predicate);
  1186. if (!b) return NULL;
  1187. Append( a, New1WithEvalSteps( Pred, b));
  1188. }
  1189. EndProduction
  1190. /*-----------------------------------------------------------------
  1191. | PathExpr production
  1192. |
  1193. \----------------------------------------------------------------*/
  1194. Production(PathExpr)
  1195. if ( (LA==VARIABLE)
  1196. ||(LA==FQVARIABLE)
  1197. ||(LA==LPAR)
  1198. ||(LA==LITERAL)
  1199. ||(LA==INTNUMBER)
  1200. ||(LA==REALNUMBER)
  1201. ||(LA==FUNCTION)
  1202. ||(LA==NSPREFIX && LA2==FUNCTION)
  1203. ) {
  1204. a = Recurse(FilterExpr);
  1205. if (LA==SLASH) {
  1206. Consume(SLASH);
  1207. Append(a, Recurse(RelativeLocationPath));
  1208. } else if (LA==SLASHSLASH) {
  1209. ast b;
  1210. Consume(SLASHSLASH);
  1211. b = Recurse(RelativeLocation

Large files files are truncated, but you can click here to view the full file