1 /* Driver template for the LEMON parser generator.
2 ** The author disclaims copyright to this source code.
3 */
4 /* First off, code is include which follows the "include" declaration
5 ** in the input file. */
6 #include <stdio.h>
7 #line 6 "./mod_ssi_exprparser.y"
8 
9 #include "mod_ssi_expr.h"
10 #include "buffer.h"
11 
12 #include <assert.h>
13 #include <string.h>
14 
15 #line 16 "mod_ssi_exprparser.c"
16 /* Next is all token values, in a form suitable for use by makeheaders.
17 ** This section will be null unless lemon is run with the -m switch.
18 */
19 /*
20 ** These constants (all generated automatically by the parser generator)
21 ** specify the various kinds of tokens (terminals) that the parser
22 ** understands.
23 **
24 ** Each symbol here is a terminal symbol in the grammar.
25 */
26 /* Make sure the INTERFACE macro is defined.
27 */
28 #ifndef INTERFACE
29 # define INTERFACE 1
30 #endif
31 /* The next thing included is series of defines which control
32 ** various aspects of the generated parser.
33 **    YYCODETYPE         is the data type used for storing terminal
34 **                       and nonterminal numbers.  "unsigned char" is
35 **                       used if there are fewer than 250 terminals
36 **                       and nonterminals.  "int" is used otherwise.
37 **    YYNOCODE           is a number of type YYCODETYPE which corresponds
38 **                       to no legal terminal or nonterminal number.  This
39 **                       number is used to fill in empty slots of the hash
40 **                       table.
41 **    YYFALLBACK         If defined, this indicates that one or more tokens
42 **                       have fall-back values which should be used if the
43 **                       original value of the token will not parse.
44 **    YYACTIONTYPE       is the data type used for storing terminal
45 **                       and nonterminal numbers.  "unsigned char" is
46 **                       used if there are fewer than 250 rules and
47 **                       states combined.  "int" is used otherwise.
48 **    ssiexprparserTOKENTYPE     is the data type used for minor tokens given
49 **                       directly to the parser from the tokenizer.
50 **    YYMINORTYPE        is the data type used for all minor tokens.
51 **                       This is typically a union of many types, one of
52 **                       which is ssiexprparserTOKENTYPE.  The entry in the union
53 **                       for base tokens is called "yy0".
54 **    YYSTACKDEPTH       is the maximum depth of the parser's stack.
55 **    ssiexprparserARG_SDECL     A static variable declaration for the %extra_argument
56 **    ssiexprparserARG_PDECL     A parameter declaration for the %extra_argument
57 **    ssiexprparserARG_STORE     Code to store %extra_argument into yypParser
58 **    ssiexprparserARG_FETCH     Code to extract %extra_argument from yypParser
59 **    YYNSTATE           the combined number of states.
60 **    YYNRULE            the number of rules in the grammar
61 **    YYERRORSYMBOL      is the code number of the error symbol.  If not
62 **                       defined, then do no error processing.
63 */
64 /*  */
65 #define YYCODETYPE unsigned char
66 #define YYNOCODE 20
67 #define YYACTIONTYPE unsigned char
68 #define ssiexprparserTOKENTYPE buffer *
69 typedef union {
70   ssiexprparserTOKENTYPE yy0;
71   int yy8;
72   buffer * yy19;
73   ssi_val_t * yy29;
74   int yy39;
75 } YYMINORTYPE;
76 #define YYSTACKDEPTH 100
77 #define ssiexprparserARG_SDECL ssi_ctx_t *ctx;
78 #define ssiexprparserARG_PDECL ,ssi_ctx_t *ctx
79 #define ssiexprparserARG_FETCH ssi_ctx_t *ctx = yypParser->ctx
80 #define ssiexprparserARG_STORE yypParser->ctx = ctx
81 #define YYNSTATE 23
82 #define YYNRULE 16
83 #define YYERRORSYMBOL 13
84 #define YYERRSYMDT yy39
85 #define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
86 #define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
87 #define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
88 
89 /* Next are that tables used to determine what action to take based on the
90 ** current state and lookahead token.  These tables are used to implement
91 ** functions that take a state number and lookahead value and return an
92 ** action integer.
93 **
94 ** Suppose the action integer is N.  Then the action is determined as
95 ** follows
96 **
97 **   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
98 **                                      token onto the stack and goto state N.
99 **
100 **   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
101 **
102 **   N == YYNSTATE+YYNRULE              A syntax error has occurred.
103 **
104 **   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
105 **
106 **   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
107 **                                      slots in the yy_action[] table.
108 **
109 ** The action table is constructed as a single large table named yy_action[].
110 ** Given state S and lookahead X, the action is computed as
111 **
112 **      yy_action[ yy_shift_ofst[S] + X ]
113 **
114 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
115 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
116 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
117 ** and that yy_default[S] should be used instead.
118 **
119 ** The formula above is for computing the action when the lookahead is
120 ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
121 ** a reduce action) then the yy_reduce_ofst[] array is used in place of
122 ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
123 ** YY_SHIFT_USE_DFLT.
124 **
125 ** The following are the tables generated in this section:
126 **
127 **  yy_action[]        A single table containing all actions.
128 **  yy_lookahead[]     A table containing the lookahead for each entry in
129 **                     yy_action.  Used to detect hash collisions.
130 **  yy_shift_ofst[]    For each state, the offset into yy_action for
131 **                     shifting terminals.
132 **  yy_reduce_ofst[]   For each state, the offset into yy_action for
133 **                     shifting non-terminals after a reduce.
134 **  yy_default[]       Default action for each state.
135 */
136 static YYACTIONTYPE yy_action[] = {
137  /*     0 */     5,    7,   17,   18,   22,   20,   21,   19,    2,   14,
138  /*    10 */     1,   23,   40,    9,   11,    3,   16,    2,   14,   12,
139  /*    20 */     4,   14,    5,    7,    6,   14,    7,    8,   14,   10,
140  /*    30 */    14,   13,   37,   37,   15,
141 };
142 static YYCODETYPE yy_lookahead[] = {
143  /*     0 */     1,    2,    3,    4,    5,    6,    7,    8,   14,   15,
144  /*    10 */    16,    0,   18,    9,   10,   17,   12,   14,   15,   16,
145  /*    20 */    14,   15,    1,    2,   14,   15,    2,   14,   15,   14,
146  /*    30 */    15,   11,   19,   19,   12,
147 };
148 #define YY_SHIFT_USE_DFLT (-2)
149 static signed char yy_shift_ofst[] = {
150  /*     0 */     4,   11,   -1,    4,   21,    4,   24,    4,   -2,    4,
151  /*    10 */    -2,    4,   20,   -2,   22,   -2,   -2,   -2,   -2,   -2,
152  /*    20 */    -2,   -2,   -2,
153 };
154 #define YY_REDUCE_USE_DFLT (-7)
155 static signed char yy_reduce_ofst[] = {
156  /*     0 */    -6,   -7,   -2,    6,   -7,   10,   -7,   13,   -7,   15,
157  /*    10 */    -7,    3,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,
158  /*    20 */    -7,   -7,   -7,
159 };
160 static YYACTIONTYPE yy_default[] = {
161  /*     0 */    39,   39,   25,   39,   24,   39,   26,   39,   27,   39,
162  /*    10 */    28,   39,   39,   29,   30,   32,   31,   33,   34,   35,
163  /*    20 */    36,   37,   38,
164 };
165 #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
166 
167 /* The next table maps tokens into fallback tokens.  If a construct
168 ** like the following:
169 **
170 **      %fallback ID X Y Z.
171 **
172 ** appears in the grammer, then ID becomes a fallback token for X, Y,
173 ** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
174 ** but it does not parse, the type of the token is changed to ID and
175 ** the parse is retried before an error is thrown.
176 */
177 #ifdef YYFALLBACK
178 static const YYCODETYPE yyFallback[] = {
179 };
180 #endif /* YYFALLBACK */
181 
182 /* The following structure represents a single element of the
183 ** parser's stack.  Information stored includes:
184 **
185 **   +  The state number for the parser at this level of the stack.
186 **
187 **   +  The value of the token stored at this level of the stack.
188 **      (In other words, the "major" token.)
189 **
190 **   +  The semantic value stored at this level of the stack.  This is
191 **      the information used by the action routines in the grammar.
192 **      It is sometimes called the "minor" token.
193 */
194 struct yyStackEntry {
195   int stateno;       /* The state-number */
196   int major;         /* The major token value.  This is the code
197                      ** number for the token at this stack level */
198   YYMINORTYPE minor; /* The user-supplied minor token value.  This
199                      ** is the value of the token  */
200 };
201 typedef struct yyStackEntry yyStackEntry;
202 
203 /* The state of the parser is completely contained in an instance of
204 ** the following structure */
205 struct yyParser {
206   int yyidx;                    /* Index of top element in stack */
207   int yyerrcnt;                 /* Shifts left before out of the error */
208   ssiexprparserARG_SDECL                /* A place to hold %extra_argument */
209   yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
210 };
211 typedef struct yyParser yyParser;
212 
213 #ifndef NDEBUG
214 #include <stdio.h>
215 static FILE *yyTraceFILE = NULL;
216 static char *yyTracePrompt = NULL;
217 #endif /* NDEBUG */
218 
219 #ifndef NDEBUG
220 /*
221 ** Turn parser tracing on by giving a stream to which to write the trace
222 ** and a prompt to preface each trace message.  Tracing is turned off
223 ** by making either argument NULL
224 **
225 ** Inputs:
226 ** <ul>
227 ** <li> A FILE* to which trace output should be written.
228 **      If NULL, then tracing is turned off.
229 ** <li> A prefix string written at the beginning of every
230 **      line of trace output.  If NULL, then tracing is
231 **      turned off.
232 ** </ul>
233 **
234 ** Outputs:
235 ** None.
236 */
237 #if 0
238 void ssiexprparserTrace(FILE *TraceFILE, char *zTracePrompt){
239   yyTraceFILE = TraceFILE;
240   yyTracePrompt = zTracePrompt;
241   if( yyTraceFILE==0 ) yyTracePrompt = 0;
242   else if( yyTracePrompt==0 ) yyTraceFILE = 0;
243 }
244 #endif
245 #endif /* NDEBUG */
246 
247 #ifndef NDEBUG
248 /* For tracing shifts, the names of all terminals and nonterminals
249 ** are required.  The following table supplies these names */
250 static const char *yyTokenName[] = {
251   "$",             "AND",           "OR",            "EQ",
252   "NE",            "GT",            "GE",            "LT",
253   "LE",            "NOT",           "LPARAN",        "RPARAN",
254   "VALUE",         "error",         "expr",          "value",
255   "exprline",      "cond",          "input",
256 };
257 #endif /* NDEBUG */
258 
259 #ifndef NDEBUG
260 /* For tracing reduce actions, the names of all rules are required.
261 */
262 static const char *yyRuleName[] = {
263  /*   0 */ "input ::= exprline",
264  /*   1 */ "exprline ::= expr cond expr",
265  /*   2 */ "exprline ::= expr",
266  /*   3 */ "expr ::= expr AND expr",
267  /*   4 */ "expr ::= expr OR expr",
268  /*   5 */ "expr ::= NOT expr",
269  /*   6 */ "expr ::= LPARAN exprline RPARAN",
270  /*   7 */ "expr ::= value",
271  /*   8 */ "value ::= VALUE",
272  /*   9 */ "value ::= value VALUE",
273  /*  10 */ "cond ::= EQ",
274  /*  11 */ "cond ::= NE",
275  /*  12 */ "cond ::= LE",
276  /*  13 */ "cond ::= GE",
277  /*  14 */ "cond ::= LT",
278  /*  15 */ "cond ::= GT",
279 };
280 #endif /* NDEBUG */
281 
282 /*
283 ** This function returns the symbolic name associated with a token
284 ** value.
285 */
286 #if 0
287 const char *ssiexprparserTokenName(int tokenType){
288 #ifndef NDEBUG
289   if( tokenType>0 && (size_t)tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
290     return yyTokenName[tokenType];
291   }else{
292     return "Unknown";
293   }
294 #else
295   return "";
296 #endif
297 }
298 #endif
299 
300 /*
301 ** This function allocates a new parser.
302 ** The only argument is a pointer to a function which works like
303 ** malloc.
304 **
305 ** Inputs:
306 ** A pointer to the function used to allocate memory.
307 **
308 ** Outputs:
309 ** A pointer to a parser.  This pointer is used in subsequent calls
310 ** to ssiexprparser and ssiexprparserFree.
311 */
312 void *ssiexprparserAlloc(void *(*mallocProc)(size_t)){
313   yyParser *pParser;
314   pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
315   if( pParser ){
316     pParser->yyidx = -1;
317   }
318   return pParser;
319 }
320 
321 /* The following function deletes the value associated with a
322 ** symbol.  The symbol can be either a terminal or nonterminal.
323 ** "yymajor" is the symbol code, and "yypminor" is a pointer to
324 ** the value.
325 */
326 static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
327   switch( yymajor ){
328     /* Here is inserted the actions which take place when a
329     ** terminal or non-terminal is destroyed.  This can happen
330     ** when the symbol is popped from the stack during a
331     ** reduce or during error processing or when a parser is
332     ** being destroyed before it is finished parsing.
333     **
334     ** Note: during a reduce, the only symbols destroyed are those
335     ** which appear on the RHS of the rule, but which are not used
336     ** inside the C code.
337     */
338     case 1:
339     case 2:
340     case 3:
341     case 4:
342     case 5:
343     case 6:
344     case 7:
345     case 8:
346     case 9:
347     case 10:
348     case 11:
349     case 12:
350 #line 22 "./mod_ssi_exprparser.y"
351 { buffer_free((yypminor->yy0)); }
352 #line 352 "mod_ssi_exprparser.c"
353       break;
354     default:  break;   /* If no destructor action specified: do nothing */
355   }
356 }
357 
358 /*
359 ** Pop the parser's stack once.
360 **
361 ** If there is a destructor routine associated with the token which
362 ** is popped from the stack, then call it.
363 **
364 ** Return the major token number for the symbol popped.
365 */
366 static int yy_pop_parser_stack(yyParser *pParser){
367   YYCODETYPE yymajor;
368   yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
369 
370   if( pParser->yyidx<0 ) return 0;
371 #ifndef NDEBUG
372   if( yyTraceFILE && pParser->yyidx>=0 ){
373     fprintf(yyTraceFILE,"%sPopping %s\n",
374       yyTracePrompt,
375       yyTokenName[yytos->major]);
376   }
377 #endif
378   yymajor = yytos->major;
379   yy_destructor( yymajor, &yytos->minor);
380   pParser->yyidx--;
381   return yymajor;
382 }
383 
384 /*
385 ** Deallocate and destroy a parser.  Destructors are all called for
386 ** all stack elements before shutting the parser down.
387 **
388 ** Inputs:
389 ** <ul>
390 ** <li>  A pointer to the parser.  This should be a pointer
391 **       obtained from ssiexprparserAlloc.
392 ** <li>  A pointer to a function used to reclaim memory obtained
393 **       from malloc.
394 ** </ul>
395 */
396 void ssiexprparserFree(
397   void *p,                    /* The parser to be deleted */
398   void (*freeProc)(void*)     /* Function used to reclaim memory */
399 ){
400   yyParser *pParser = (yyParser*)p;
401   if( pParser==NULL ) return;
402   while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
403   (*freeProc)((void*)pParser);
404 }
405 
406 /*
407 ** Find the appropriate action for a parser given the terminal
408 ** look-ahead token iLookAhead.
409 **
410 ** If the look-ahead token is YYNOCODE, then check to see if the action is
411 ** independent of the look-ahead.  If it is, return the action, otherwise
412 ** return YY_NO_ACTION.
413 */
414 static int yy_find_shift_action(
415   yyParser *pParser,        /* The parser */
416   int iLookAhead            /* The look-ahead token */
417 ){
418   int i;
419   int stateno = pParser->yystack[pParser->yyidx].stateno;
420 
421   /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
422   i = yy_shift_ofst[stateno];
423   if( i==YY_SHIFT_USE_DFLT ){
424     return yy_default[stateno];
425   }
426   if( iLookAhead==YYNOCODE ){
427     return YY_NO_ACTION;
428   }
429   i += iLookAhead;
430   if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
431 #ifdef YYFALLBACK
432     int iFallback;            /* Fallback token */
433     if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
434            && (iFallback = yyFallback[iLookAhead])!=0 ){
435 #ifndef NDEBUG
436       if( yyTraceFILE ){
437         fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
438            yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
439       }
440 #endif
441       return yy_find_shift_action(pParser, iFallback);
442     }
443 #endif
444     return yy_default[stateno];
445   }else{
446     return yy_action[i];
447   }
448 }
449 
450 /*
451 ** Find the appropriate action for a parser given the non-terminal
452 ** look-ahead token iLookAhead.
453 **
454 ** If the look-ahead token is YYNOCODE, then check to see if the action is
455 ** independent of the look-ahead.  If it is, return the action, otherwise
456 ** return YY_NO_ACTION.
457 */
458 static int yy_find_reduce_action(
459   yyParser *pParser,        /* The parser */
460   int iLookAhead            /* The look-ahead token */
461 ){
462   int i;
463   int stateno = pParser->yystack[pParser->yyidx].stateno;
464 
465   i = yy_reduce_ofst[stateno];
466   if( i==YY_REDUCE_USE_DFLT ){
467     return yy_default[stateno];
468   }
469   if( iLookAhead==YYNOCODE ){
470     return YY_NO_ACTION;
471   }
472   i += iLookAhead;
473   if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
474     return yy_default[stateno];
475   }else{
476     return yy_action[i];
477   }
478 }
479 
480 /*
481 ** Perform a shift action.
482 */
483 static void yy_shift(
484   yyParser *yypParser,          /* The parser to be shifted */
485   int yyNewState,               /* The new state to shift in */
486   int yyMajor,                  /* The major token to shift in */
487   YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
488 ){
489   yyStackEntry *yytos;
490   yypParser->yyidx++;
491   if( yypParser->yyidx>=YYSTACKDEPTH ){
492      ssiexprparserARG_FETCH;
493      yypParser->yyidx--;
494 #ifndef NDEBUG
495      if( yyTraceFILE ){
496        fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
497      }
498 #endif
499      while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
500      /* Here code is inserted which will execute if the parser
501      ** stack every overflows */
502      ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument var */
503      return;
504   }
505   yytos = &yypParser->yystack[yypParser->yyidx];
506   yytos->stateno = yyNewState;
507   yytos->major = yyMajor;
508   yytos->minor = *yypMinor;
509 #ifndef NDEBUG
510   if( yyTraceFILE && yypParser->yyidx>0 ){
511     int i;
512     fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
513     fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
514     for(i=1; i<=yypParser->yyidx; i++)
515       fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
516     fprintf(yyTraceFILE,"\n");
517   }
518 #endif
519 }
520 
521 /* The following table contains information about every rule that
522 ** is used during the reduce.
523 */
524 static struct {
525   YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
526   unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
527 } yyRuleInfo[] = {
528   { 18, 1 },
529   { 16, 3 },
530   { 16, 1 },
531   { 14, 3 },
532   { 14, 3 },
533   { 14, 2 },
534   { 14, 3 },
535   { 14, 1 },
536   { 15, 1 },
537   { 15, 2 },
538   { 17, 1 },
539   { 17, 1 },
540   { 17, 1 },
541   { 17, 1 },
542   { 17, 1 },
543   { 17, 1 },
544 };
545 
546 static void yy_accept(yyParser*);  /* Forward Declaration */
547 
548 /*
549 ** Perform a reduce action and the shift that must immediately
550 ** follow the reduce.
551 */
552 static void yy_reduce(
553   yyParser *yypParser,         /* The parser */
554   int yyruleno                 /* Number of the rule by which to reduce */
555 ){
556   int yygoto;                     /* The next state */
557   int yyact;                      /* The next action */
558   YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
559   yyStackEntry *yymsp;            /* The top of the parser's stack */
560   int yysize;                     /* Amount to pop the stack */
561   ssiexprparserARG_FETCH;
562   yymsp = &yypParser->yystack[yypParser->yyidx];
563 #ifndef NDEBUG
564   if( yyTraceFILE && yyruleno>=0
565         && (size_t)yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
566     fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
567       yyRuleName[yyruleno]);
568   }
569 #endif /* NDEBUG */
570 
571   switch( yyruleno ){
572   /* Beginning here are the reduction cases.  A typical example
573   ** follows:
574   **   case 0:
575   **  #line <lineno> <grammarfile>
576   **     { ... }           // User supplied code
577   **  #line <lineno> <thisfile>
578   **     break;
579   */
580       case 0:
581 #line 29 "./mod_ssi_exprparser.y"
582 {
583   ctx->val.bo = ssi_val_tobool(yymsp[0].minor.yy29);
584   ctx->val.type = SSI_TYPE_BOOL;
585 
586   ssi_val_free(yymsp[0].minor.yy29);
587 }
588 #line 588 "mod_ssi_exprparser.c"
589         break;
590       case 1:
591 #line 36 "./mod_ssi_exprparser.y"
592 {
593   int cmp;
594 
595   if (yymsp[-2].minor.yy29->type == SSI_TYPE_STRING &&
596       yymsp[0].minor.yy29->type == SSI_TYPE_STRING) {
597        cmp = strcmp(yymsp[-2].minor.yy29->str->ptr, yymsp[0].minor.yy29->str->ptr);
598   } else {
599     cmp = ssi_val_tobool(yymsp[-2].minor.yy29) - ssi_val_tobool(yymsp[0].minor.yy29);
600   }
601 
602   yygotominor.yy29 = yymsp[-2].minor.yy29;
603 
604   switch(yymsp[-1].minor.yy8) {
605   case SSI_COND_EQ: yygotominor.yy29->bo = (cmp == 0) ? 1 : 0; break;
606   case SSI_COND_NE: yygotominor.yy29->bo = (cmp != 0) ? 1 : 0; break;
607   case SSI_COND_GE: yygotominor.yy29->bo = (cmp >= 0) ? 1 : 0; break;
608   case SSI_COND_GT: yygotominor.yy29->bo = (cmp > 0) ? 1 : 0; break;
609   case SSI_COND_LE: yygotominor.yy29->bo = (cmp <= 0) ? 1 : 0; break;
610   case SSI_COND_LT: yygotominor.yy29->bo = (cmp < 0) ? 1 : 0; break;
611   }
612 
613   yygotominor.yy29->type = SSI_TYPE_BOOL;
614 
615   ssi_val_free(yymsp[0].minor.yy29);
616 }
617 #line 617 "mod_ssi_exprparser.c"
618         break;
619       case 2:
620 #line 61 "./mod_ssi_exprparser.y"
621 {
622   yygotominor.yy29 = yymsp[0].minor.yy29;
623 }
624 #line 624 "mod_ssi_exprparser.c"
625         break;
626       case 3:
627 #line 64 "./mod_ssi_exprparser.y"
628 {
629   int e;
630 
631   e = ssi_val_tobool(yymsp[-2].minor.yy29) && ssi_val_tobool(yymsp[0].minor.yy29);
632 
633   yygotominor.yy29 = yymsp[-2].minor.yy29;
634   yygotominor.yy29->bo = e;
635   yygotominor.yy29->type = SSI_TYPE_BOOL;
636   ssi_val_free(yymsp[0].minor.yy29);
637 }
638 #line 638 "mod_ssi_exprparser.c"
639   yy_destructor(1,&yymsp[-1].minor);
640         break;
641       case 4:
642 #line 75 "./mod_ssi_exprparser.y"
643 {
644   int e;
645 
646   e = ssi_val_tobool(yymsp[-2].minor.yy29) || ssi_val_tobool(yymsp[0].minor.yy29);
647 
648   yygotominor.yy29 = yymsp[-2].minor.yy29;
649   yygotominor.yy29->bo = e;
650   yygotominor.yy29->type = SSI_TYPE_BOOL;
651   ssi_val_free(yymsp[0].minor.yy29);
652 }
653 #line 653 "mod_ssi_exprparser.c"
654   yy_destructor(2,&yymsp[-1].minor);
655         break;
656       case 5:
657 #line 86 "./mod_ssi_exprparser.y"
658 {
659   int e;
660 
661   e = !ssi_val_tobool(yymsp[0].minor.yy29);
662 
663   yygotominor.yy29 = yymsp[0].minor.yy29;
664   yygotominor.yy29->bo = e;
665   yygotominor.yy29->type = SSI_TYPE_BOOL;
666 }
667 #line 667 "mod_ssi_exprparser.c"
668   yy_destructor(9,&yymsp[-1].minor);
669         break;
670       case 6:
671 #line 95 "./mod_ssi_exprparser.y"
672 {
673   yygotominor.yy29 = yymsp[-1].minor.yy29;
674 }
675 #line 675 "mod_ssi_exprparser.c"
676   yy_destructor(10,&yymsp[-2].minor);
677   yy_destructor(11,&yymsp[0].minor);
678         break;
679       case 7:
680 #line 99 "./mod_ssi_exprparser.y"
681 {
682   yygotominor.yy29 = ssi_val_init();
683   yygotominor.yy29->str = yymsp[0].minor.yy19;
684   yygotominor.yy29->type = SSI_TYPE_STRING;
685 }
686 #line 686 "mod_ssi_exprparser.c"
687         break;
688       case 8:
689 #line 105 "./mod_ssi_exprparser.y"
690 {
691   yygotominor.yy19 = yymsp[0].minor.yy0;
692 }
693 #line 693 "mod_ssi_exprparser.c"
694         break;
695       case 9:
696 #line 109 "./mod_ssi_exprparser.y"
697 {
698   yygotominor.yy19 = yymsp[-1].minor.yy19;
699   buffer_append_string_buffer(yygotominor.yy19, yymsp[0].minor.yy0);
700   buffer_free(yymsp[0].minor.yy0);
701 }
702 #line 702 "mod_ssi_exprparser.c"
703         break;
704       case 10:
705 #line 115 "./mod_ssi_exprparser.y"
706 { yygotominor.yy8 = SSI_COND_EQ; }
707 #line 707 "mod_ssi_exprparser.c"
708   yy_destructor(3,&yymsp[0].minor);
709         break;
710       case 11:
711 #line 116 "./mod_ssi_exprparser.y"
712 { yygotominor.yy8 = SSI_COND_NE; }
713 #line 713 "mod_ssi_exprparser.c"
714   yy_destructor(4,&yymsp[0].minor);
715         break;
716       case 12:
717 #line 117 "./mod_ssi_exprparser.y"
718 { yygotominor.yy8 = SSI_COND_LE; }
719 #line 719 "mod_ssi_exprparser.c"
720   yy_destructor(8,&yymsp[0].minor);
721         break;
722       case 13:
723 #line 118 "./mod_ssi_exprparser.y"
724 { yygotominor.yy8 = SSI_COND_GE; }
725 #line 725 "mod_ssi_exprparser.c"
726   yy_destructor(6,&yymsp[0].minor);
727         break;
728       case 14:
729 #line 119 "./mod_ssi_exprparser.y"
730 { yygotominor.yy8 = SSI_COND_LT; }
731 #line 731 "mod_ssi_exprparser.c"
732   yy_destructor(7,&yymsp[0].minor);
733         break;
734       case 15:
735 #line 120 "./mod_ssi_exprparser.y"
736 { yygotominor.yy8 = SSI_COND_GT; }
737 #line 737 "mod_ssi_exprparser.c"
738   yy_destructor(5,&yymsp[0].minor);
739         break;
740   };
741   yygoto = yyRuleInfo[yyruleno].lhs;
742   yysize = yyRuleInfo[yyruleno].nrhs;
743   yypParser->yyidx -= yysize;
744   yyact = yy_find_reduce_action(yypParser,yygoto);
745   if( yyact < YYNSTATE ){
746     yy_shift(yypParser,yyact,yygoto,&yygotominor);
747   }else if( yyact == YYNSTATE + YYNRULE + 1 ){
748     yy_accept(yypParser);
749   }
750 }
751 
752 /*
753 ** The following code executes when the parse fails
754 */
755 static void yy_parse_failed(
756   yyParser *yypParser           /* The parser */
757 ){
758   ssiexprparserARG_FETCH;
759 #ifndef NDEBUG
760   if( yyTraceFILE ){
761     fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
762   }
763 #endif
764   while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
765   /* Here code is inserted which will be executed whenever the
766   ** parser fails */
767 #line 14 "./mod_ssi_exprparser.y"
768 
769   ctx->ok = 0;
770 
771 #line 771 "mod_ssi_exprparser.c"
772   ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
773 }
774 
775 /*
776 ** The following code executes when a syntax error first occurs.
777 */
778 static void yy_syntax_error(
779   yyParser *yypParser,           /* The parser */
780   int yymajor,                   /* The major type of the error token */
781   YYMINORTYPE yyminor            /* The minor type of the error token */
782 ){
783   ssiexprparserARG_FETCH;
784   UNUSED(yymajor);
785   UNUSED(yyminor);
786 #define TOKEN (yyminor.yy0)
787   ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
788 }
789 
790 /*
791 ** The following is executed when the parser accepts
792 */
793 static void yy_accept(
794   yyParser *yypParser           /* The parser */
795 ){
796   ssiexprparserARG_FETCH;
797 #ifndef NDEBUG
798   if( yyTraceFILE ){
799     fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
800   }
801 #endif
802   while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
803   /* Here code is inserted which will be executed whenever the
804   ** parser accepts */
805   ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
806 }
807 
808 /* The main parser program.
809 ** The first argument is a pointer to a structure obtained from
810 ** "ssiexprparserAlloc" which describes the current state of the parser.
811 ** The second argument is the major token number.  The third is
812 ** the minor token.  The fourth optional argument is whatever the
813 ** user wants (and specified in the grammar) and is available for
814 ** use by the action routines.
815 **
816 ** Inputs:
817 ** <ul>
818 ** <li> A pointer to the parser (an opaque structure.)
819 ** <li> The major token number.
820 ** <li> The minor token number.
821 ** <li> An option argument of a grammar-specified type.
822 ** </ul>
823 **
824 ** Outputs:
825 ** None.
826 */
827 void ssiexprparser(
828   void *yyp,                   /* The parser */
829   int yymajor,                 /* The major token code number */
830   ssiexprparserTOKENTYPE yyminor       /* The value for the token */
831   ssiexprparserARG_PDECL               /* Optional %extra_argument parameter */
832 ){
833   YYMINORTYPE yyminorunion;
834   int yyact;            /* The parser action. */
835   int yyendofinput;     /* True if we are at the end of input */
836   int yyerrorhit = 0;   /* True if yymajor has invoked an error */
837   yyParser *yypParser;  /* The parser */
838 
839   /* (re)initialize the parser, if necessary */
840   yypParser = (yyParser*)yyp;
841   if( yypParser->yyidx<0 ){
842     if( yymajor==0 ) return;
843     yypParser->yyidx = 0;
844     yypParser->yyerrcnt = -1;
845     yypParser->yystack[0].stateno = 0;
846     yypParser->yystack[0].major = 0;
847   }
848   yyminorunion.yy0 = yyminor;
849   yyendofinput = (yymajor==0);
850   ssiexprparserARG_STORE;
851 
852 #ifndef NDEBUG
853   if( yyTraceFILE ){
854     fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
855   }
856 #endif
857 
858   do{
859     yyact = yy_find_shift_action(yypParser,yymajor);
860     if( yyact<YYNSTATE ){
861       yy_shift(yypParser,yyact,yymajor,&yyminorunion);
862       yypParser->yyerrcnt--;
863       if( yyendofinput && yypParser->yyidx>=0 ){
864         yymajor = 0;
865       }else{
866         yymajor = YYNOCODE;
867       }
868     }else if( yyact < YYNSTATE + YYNRULE ){
869       yy_reduce(yypParser,yyact-YYNSTATE);
870     }else if( yyact == YY_ERROR_ACTION ){
871       int yymx;
872 #ifndef NDEBUG
873       if( yyTraceFILE ){
874         fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
875       }
876 #endif
877 #ifdef YYERRORSYMBOL
878       /* A syntax error has occurred.
879       ** The response to an error depends upon whether or not the
880       ** grammar defines an error token "ERROR".
881       **
882       ** This is what we do if the grammar does define ERROR:
883       **
884       **  * Call the %syntax_error function.
885       **
886       **  * Begin popping the stack until we enter a state where
887       **    it is legal to shift the error symbol, then shift
888       **    the error symbol.
889       **
890       **  * Set the error count to three.
891       **
892       **  * Begin accepting and shifting new tokens.  No new error
893       **    processing will occur until three tokens have been
894       **    shifted successfully.
895       **
896       */
897       if( yypParser->yyerrcnt<0 ){
898         yy_syntax_error(yypParser,yymajor,yyminorunion);
899       }
900       yymx = yypParser->yystack[yypParser->yyidx].major;
901       if( yymx==YYERRORSYMBOL || yyerrorhit ){
902 #ifndef NDEBUG
903         if( yyTraceFILE ){
904           fprintf(yyTraceFILE,"%sDiscard input token %s\n",
905              yyTracePrompt,yyTokenName[yymajor]);
906         }
907 #endif
908         yy_destructor(yymajor,&yyminorunion);
909         yymajor = YYNOCODE;
910       }else{
911          while(
912           yypParser->yyidx >= 0 &&
913           yymx != YYERRORSYMBOL &&
914           (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
915         ){
916           yy_pop_parser_stack(yypParser);
917         }
918         if( yypParser->yyidx < 0 || yymajor==0 ){
919           yy_destructor(yymajor,&yyminorunion);
920           yy_parse_failed(yypParser);
921           yymajor = YYNOCODE;
922         }else if( yymx!=YYERRORSYMBOL ){
923           YYMINORTYPE u2;
924           u2.YYERRSYMDT = 0;
925           yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
926         }
927       }
928       yypParser->yyerrcnt = 3;
929       yyerrorhit = 1;
930 #else  /* YYERRORSYMBOL is not defined */
931       /* This is what we do if the grammar does not define ERROR:
932       **
933       **  * Report an error message, and throw away the input token.
934       **
935       **  * If the input token is $, then fail the parse.
936       **
937       ** As before, subsequent error messages are suppressed until
938       ** three input tokens have been successfully shifted.
939       */
940       if( yypParser->yyerrcnt<=0 ){
941         yy_syntax_error(yypParser,yymajor,yyminorunion);
942       }
943       yypParser->yyerrcnt = 3;
944       yy_destructor(yymajor,&yyminorunion);
945       if( yyendofinput ){
946         yy_parse_failed(yypParser);
947       }
948       yymajor = YYNOCODE;
949 #endif
950     }else{
951       yy_accept(yypParser);
952       yymajor = YYNOCODE;
953     }
954   }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
955   return;
956 }
957