1 /*
2  * This file is part of Smarty.
3  *
4  * (c) 2015 Uwe Tews
5  *
6  * For the full copyright and license information, please view the LICENSE
7  * file that was distributed with this source code.
8  */
9 %stack_size 500
10 %name TP_
11 %declare_class {
12 /**
13 * Smarty Template Parser Class
14 *
15 * This is the template parser.
16 * It is generated from the smarty_internal_templateparser.y file
17 *
18 * @author Uwe Tews <uwe.tews@googlemail.com>
19 */
20 class Smarty_Internal_Templateparser
21 }
22 %include_class
23 {
24     const ERR1 = 'Security error: Call to private object member not allowed';
25     const ERR2 = 'Security error: Call to dynamic object member not allowed';
26     const ERR3 = 'PHP in template not allowed. Use SmartyBC to enable it';
27 
28     /**
29      * result status
30      *
31      * @var bool
32      */
33     public $successful = true;
34 
35     /**
36      * return value
37      *
38      * @var mixed
39      */
40     public $retvalue = 0;
41 
42     /**
43      * @var
44      */
45     public $yymajor;
46 
47     /**
48      * last index of array variable
49      *
50      * @var mixed
51      */
52     public $last_index;
53 
54     /**
55      * last variable name
56      *
57      * @var string
58      */
59     public $last_variable;
60 
61     /**
62      * root parse tree buffer
63      *
64      * @var Smarty_Internal_ParseTree_Template
65      */
66     public $root_buffer;
67 
68     /**
69      * current parse tree object
70      *
71      * @var Smarty_Internal_ParseTree
72      */
73     public $current_buffer;
74 
75     /**
76      * lexer object
77      *
78      * @var Smarty_Internal_Templatelexer
79      */
80     public $lex;
81 
82     /**
83      * internal error flag
84      *
85      * @var bool
86      */
87     private $internalError = false;
88 
89     /**
90      * {strip} status
91      *
92      * @var bool
93      */
94     public $strip = false;
95     /**
96      * compiler object
97      *
98      * @var Smarty_Internal_TemplateCompilerBase
99      */
100     public $compiler = null;
101 
102     /**
103      * smarty object
104      *
105      * @var Smarty
106      */
107     public $smarty = null;
108 
109     /**
110      * template object
111      *
112      * @var Smarty_Internal_Template
113      */
114     public $template = null;
115 
116     /**
117      * block nesting level
118      *
119      * @var int
120      */
121     public $block_nesting_level = 0;
122 
123     /**
124      * security object
125      *
126      * @var Smarty_Security
127      */
128     public $security = null;
129 
130     /**
131      * template prefix array
132      *
133      * @var \Smarty_Internal_ParseTree[]
134      */
135     public $template_prefix = array();
136 
137     /**
138      * template prefix array
139      *
140      * @var \Smarty_Internal_ParseTree[]
141      */
142     public $template_postfix = array();
143 
144     /**
145      * constructor
146      *
147      * @param Smarty_Internal_Templatelexer        $lex
148      * @param Smarty_Internal_TemplateCompilerBase $compiler
149      */
__construct(Smarty_Internal_Templatelexer $lex,Smarty_Internal_TemplateCompilerBase $compiler)150     public function __construct(Smarty_Internal_Templatelexer $lex, Smarty_Internal_TemplateCompilerBase $compiler)
151     {
152         $this->lex = $lex;
153         $this->compiler = $compiler;
154         $this->template = $this->compiler->template;
155         $this->smarty = $this->template->smarty;
156         $this->security = isset($this->smarty->security_policy) ? $this->smarty->security_policy : false;
157         $this->current_buffer = $this->root_buffer = new Smarty_Internal_ParseTree_Template();
158     }
159 
160      /**
161      * insert PHP code in current buffer
162      *
163      * @param string $code
164      */
insertPhpCode($code)165     public function insertPhpCode($code)
166     {
167         $this->current_buffer->append_subtree($this, new Smarty_Internal_ParseTree_Tag($this, $code));
168     }
169 
170     /**
171      * error rundown
172      *
173      */
errorRunDown()174     public function errorRunDown()
175     {
176         while ($this->yystack !== array()) {
177             $this->yy_pop_parser_stack();
178         }
179         if (is_resource($this->yyTraceFILE)) {
180             fclose($this->yyTraceFILE);
181         }
182     }
183 
184     /**
185      *  merge PHP code with prefix code and return parse tree tag object
186      *
187      * @param string $code
188      *
189      * @return Smarty_Internal_ParseTree_Tag
190      */
mergePrefixCode($code)191     public function mergePrefixCode($code)
192     {
193         $tmp = '';
194         foreach ($this->compiler->prefix_code as $preCode) {
195             $tmp .= $preCode;
196         }
197         $this->compiler->prefix_code = array();
198         $tmp .= $code;
199         return new Smarty_Internal_ParseTree_Tag($this, $this->compiler->processNocacheCode($tmp, true));
200     }
201 
202 }
203 
204 %token_prefix TP_
205 
206 %parse_accept
207 {
208     $this->successful = !$this->internalError;
209     $this->internalError = false;
210     $this->retvalue = $this->_retvalue;
211 }
212 
213 %syntax_error
214 {
215     $this->internalError = true;
216     $this->yymajor = $yymajor;
217     $this->compiler->trigger_template_error();
218 }
219 
220 %stack_overflow
221 {
222     $this->internalError = true;
223     $this->compiler->trigger_template_error('Stack overflow in template parser');
224 }
225 
226 
227 %right VERT.
228 %left COLON.
229 
230 
231     //
232     // complete template
233     //
234 start(res)       ::= template. {
235     $this->root_buffer->prepend_array($this, $this->template_prefix);
236     $this->root_buffer->append_array($this, $this->template_postfix);
237     res = $this->root_buffer->to_smarty_php($this);
238 }
239 
240 
241                       // php tags
PHP(B)242 template       ::= template PHP(B). {
243     $code = $this->compiler->compileTag('private_php',array(array('code' => B), array('type' => $this->lex->phpType )),array());
244     if ($this->compiler->has_code && !empty($code)) {
245         $tmp =''; foreach ($this->compiler->prefix_code as $code) {$tmp.=$code;} $this->compiler->prefix_code=array();
246          $this->current_buffer->append_subtree($this,  new Smarty_Internal_ParseTree_Tag($this, $this->compiler->processNocacheCode($tmp.$code,true)));
247     }
248 }
249 
250                       // template text
TEXT(B)251 template       ::= template  TEXT(B). {
252          $this->current_buffer->append_subtree($this, $this->compiler->processText(B));
253 }
254                       // strip on
255 template       ::= template  STRIPON. {
256     $this->strip = true;
257 }
258                       // strip off
259 template       ::= template STRIPOFF. {
260     $this->strip = false;
261 }
262 
263                      // Literal
literal_e2(B)264 template       ::= template LITERALSTART literal_e2(B) LITERALEND. {
265        $this->current_buffer->append_subtree($this, new Smarty_Internal_ParseTree_Text(B));
266 }
267 
268 
literal_e2(A)269 literal_e2(A) ::= literal_e1(B) LITERALSTART literal_e1(C) LITERALEND. {
270     A = B.C;
271 }
literal_e2(A)272 literal_e2(A) ::= literal_e1(B). {
273     A = B;
274 }
275 
literal_e1(A)276 literal_e1(A) ::= literal_e1(B) LITERAL(C). {
277         A = B.C;
278 
279 }
280 
literal_e1(A)281 literal_e1(A) ::= . {
282     A = '';
283 }
284                       // Smarty tag
smartytag(B)285 template       ::= template smartytag(B). {
286       if ($this->compiler->has_code) {
287           $this->current_buffer->append_subtree($this, $this->mergePrefixCode(B));
288       }
289      $this->compiler->has_variable_string = false;
290      $this->block_nesting_level = count($this->compiler->_tag_stack);
291 }
292 
293 
294                       // empty template
295 template       ::= .
296 
smartytag(A)297 smartytag(A)   ::= SIMPELOUTPUT(B). {
298     $var = trim(substr(B, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $');
299     if (preg_match('/^(.*)(\s+nocache)$/', $var, $match)) {
300         A = $this->compiler->compileTag('private_print_expression',array('nocache'),array('value'=>$this->compiler->compileVariable('\''.$match[1].'\'')));
301     } else {
302         A = $this->compiler->compileTag('private_print_expression',array(),array('value'=>$this->compiler->compileVariable('\''.$var.'\'')));
303     }
304 }
305 
306 // simple tag like {name}
smartytag(A)307 smartytag(A)::= SIMPLETAG(B). {
308     $tag = trim(substr(B, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()));
309     if ($tag == 'strip') {
310         $this->strip = true;
311         A = null;;
312     } else {
313         if (defined($tag)) {
314             if ($this->security) {
315                $this->security->isTrustedConstant($tag, $this->compiler);
316             }
317             A = $this->compiler->compileTag('private_print_expression',array(),array('value'=>$tag));
318         } else {
319             if (preg_match('/^(.*)(\s+nocache)$/', $tag, $match)) {
320                 A = $this->compiler->compileTag($match[1],array('\'nocache\''));
321             } else {
322                 A = $this->compiler->compileTag($tag,array());
323             }
324         }
325     }
326 }
327                   // {$smarty.block.child} or {$smarty.block.parent}
smartytag(A)328 smartytag(A)   ::= SMARTYBLOCKCHILDPARENT(i). {
329     $j = strrpos(i,'.');
330     if (i[$j+1] == 'c') {
331         // {$smarty.block.child}
332         A = $this->compiler->compileTag('child',array(),array(i));
333     } else {
334         // {$smarty.block.parent}
335        A = $this->compiler->compileTag('parent',array(),array(i));
336      }
337 }
338 
smartytag(A)339 smartytag(A)   ::= LDEL tagbody(B) RDEL. {
340     A  = B;
341 }
342 
smartytag(A)343  smartytag(A)   ::=  tag(B) RDEL. {
344      A  = B;
345  }
346                   // output with optional attributes
tagbody(A)347 tagbody(A) ::= outattr(B). {
348     A = $this->compiler->compileTag('private_print_expression',B[1],array('value'=>B[0]));
349 }
350 
351 //
352 // Smarty tags start here
353 //
354 
355                   // assign new style
tagbody(A)356 tagbody(A) ::= DOLLARID(B) eqoutattr(C). {
357     A = $this->compiler->compileTag('assign',array_merge(array(array('value'=>C[0]),array('var'=>'\''.substr(B,1).'\'')),C[1]));
358 }
359 
tagbody(A)360 tagbody(A) ::= varindexed(B) eqoutattr(C). {
361     A = $this->compiler->compileTag('assign',array_merge(array(array('value'=>C[0]),array('var'=>B['var'])),C[1]),array('smarty_internal_index'=>B['smarty_internal_index']));
362 }
363 
eqoutattr(A)364 eqoutattr(A) ::= EQUAL outattr(B). {
365        A = B;
366 }
367 
outattr(A)368 outattr(A) ::= output(B) attributes(C). {
369     A = array(B,C);
370 }
371 
output(A)372 output(A) ::= variable(B). {
373     A = B;
374 }
output(A)375 output(A) ::= value(B). {
376     A = B;
377 }
output(A)378 output(A) ::= expr(B). {
379     A = B;
380 }
381 
382                   // tag with optional Smarty2 style attributes
tag(res)383 tag(res)   ::= LDEL ID(i) attributes(a). {
384         if (defined(i)) {
385             if ($this->security) {
386                 $this->security->isTrustedConstant(i, $this->compiler);
387             }
388             res = $this->compiler->compileTag('private_print_expression',a,array('value'=>i));
389         } else {
390             res = $this->compiler->compileTag(i,a);
391         }
392 }
tag(res)393 tag(res)   ::= LDEL ID(i). {
394         if (defined(i)) {
395             if ($this->security) {
396                 $this->security->isTrustedConstant(i, $this->compiler);
397             }
398             res = $this->compiler->compileTag('private_print_expression',array(),array('value'=>i));
399         } else {
400             res = $this->compiler->compileTag(i,array());
401         }
402 }
403 
404 
405                   // tag with modifier and optional Smarty2 style attributes
tag(res)406 tag(res)   ::= LDEL ID(i) modifierlist(l)attributes(a). {
407         if (defined(i)) {
408             if ($this->security) {
409                 $this->security->isTrustedConstant(i, $this->compiler);
410             }
411             res = $this->compiler->compileTag('private_print_expression',a,array('value'=>i, 'modifierlist'=>l));
412         } else {
413             res = $this->compiler->compileTag(i,a, array('modifierlist'=>l));
414         }
415 }
416 
417                   // registered object tag
tag(res)418 tag(res)   ::= LDEL ID(i) PTR ID(m) attributes(a). {
419     res = $this->compiler->compileTag(i,a,array('object_method'=>m));
420 }
421 
422                   // registered object tag with modifiers
tag(res)423 tag(res)   ::= LDEL ID(i) PTR ID(me) modifierlist(l) attributes(a). {
424     res = $this->compiler->compileTag(i,a,array('modifierlist'=>l, 'object_method'=>me));
425 }
426 
427                   // nocache tag
tag(res)428 tag(res)   ::= LDELMAKENOCACHE DOLLARID(i). {
429     res = $this->compiler->compileTag('make_nocache',array(array('var'=>'\''.substr(i,1).'\'')));
430 }
431 
432                   // {if}, {elseif} and {while} tag
tag(res)433 tag(res)   ::= LDELIF(i) expr(ie). {
434     $tag = trim(substr(i,$this->compiler->getLdelLength()));
435     res = $this->compiler->compileTag(($tag === 'else if')? 'elseif' : $tag,array(),array('if condition'=>ie));
436 }
437 
tag(res)438 tag(res)   ::= LDELIF(i) expr(ie) attributes(a). {
439     $tag = trim(substr(i,$this->compiler->getLdelLength()));
440     res = $this->compiler->compileTag(($tag === 'else if')? 'elseif' : $tag,a,array('if condition'=>ie));
441 }
442 
tag(res)443 tag(res)   ::= LDELIF(i) statement(ie). {
444     $tag = trim(substr(i,$this->compiler->getLdelLength()));
445     res = $this->compiler->compileTag(($tag === 'else if')? 'elseif' : $tag,array(),array('if condition'=>ie));
446 }
447 
tag(res)448 tag(res)   ::= LDELIF(i) statement(ie)  attributes(a). {
449     $tag = trim(substr(i,$this->compiler->getLdelLength()));
450     res = $this->compiler->compileTag(($tag === 'else if')? 'elseif' : $tag,a,array('if condition'=>ie));
451 }
452 
453                   // {for} tag
tag(res)454 tag(res)   ::= LDELFOR statements(st) SEMICOLON expr(ie) SEMICOLON varindexed(v2) foraction(e2) attributes(a). {
455     res = $this->compiler->compileTag('for',array_merge(a,array(array('start'=>st),array('ifexp'=>ie),array('var'=>v2),array('step'=>e2))),1);
456 }
457 
foraction(res)458   foraction(res)   ::= EQUAL expr(e). {
459     res = '='.e;
460 }
461 
foraction(res)462   foraction(res)   ::= INCDEC(e). {
463     res = e;
464 }
465 
tag(res)466 tag(res)   ::= LDELFOR statement(st) TO expr(v) attributes(a). {
467     res = $this->compiler->compileTag('for',array_merge(a,array(array('start'=>st),array('to'=>v))),0);
468 }
469 
tag(res)470 tag(res)   ::= LDELFOR statement(st) TO expr(v) STEP expr(v2) attributes(a). {
471     res = $this->compiler->compileTag('for',array_merge(a,array(array('start'=>st),array('to'=>v),array('step'=>v2))),0);
472 }
473 
474                   // {foreach} tag
tag(res)475 tag(res)   ::= LDELFOREACH SPACE expr(e) AS varvar(v0) attributes(a). {
476     res = $this->compiler->compileTag('foreach',array_merge(a,array(array('from'=>e),array('item'=>v0))));
477 }
478 
tag(res)479 tag(res)   ::= LDELFOREACH SPACE expr(e) AS varvar(v1) APTR varvar(v0) attributes(a). {
480     res = $this->compiler->compileTag('foreach',array_merge(a,array(array('from'=>e),array('item'=>v0),array('key'=>v1))));
481 }
tag(res)482 tag(res)   ::= LDELFOREACH attributes(a). {
483     res = $this->compiler->compileTag('foreach',a);
484 }
485 
486                   // {setfilter}
tag(res)487 tag(res)   ::= LDELSETFILTER ID(m) modparameters(p). {
488     res = $this->compiler->compileTag('setfilter',array(),array('modifier_list'=>array(array_merge(array(m),p))));
489 }
490 
tag(res)491 tag(res)   ::= LDELSETFILTER ID(m) modparameters(p) modifierlist(l). {
492     res = $this->compiler->compileTag('setfilter',array(),array('modifier_list'=>array_merge(array(array_merge(array(m),p)),l)));
493 }
494 
495 
496                   // end of block tag  {/....}
smartytag(res)497 smartytag(res)::= CLOSETAG(t). {
498     $tag = trim(substr(t, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' /');
499     if ($tag === 'strip') {
500         $this->strip = false;
501         res = null;
502     } else {
503        res = $this->compiler->compileTag($tag.'close',array());
504     }
505  }
tag(res)506 tag(res)   ::= LDELSLASH ID(i). {
507     res = $this->compiler->compileTag(i.'close',array());
508 }
509 
tag(res)510 tag(res)   ::= LDELSLASH ID(i) modifierlist(l). {
511     res = $this->compiler->compileTag(i.'close',array(),array('modifier_list'=>l));
512 }
513 
514                   // end of block object tag  {/....}
tag(res)515 tag(res)   ::= LDELSLASH ID(i) PTR ID(m). {
516     res = $this->compiler->compileTag(i.'close',array(),array('object_method'=>m));
517 }
518 
tag(res)519 tag(res)   ::= LDELSLASH ID(i) PTR ID(m) modifierlist(l). {
520     res = $this->compiler->compileTag(i.'close',array(),array('object_method'=>m, 'modifier_list'=>l));
521 }
522 
523 //
524 //Attributes of Smarty tags
525 //
526                   // list of attributes
attributes(res)527 attributes(res)  ::= attributes(a1) attribute(a2). {
528     res = a1;
529     res[] = a2;
530 }
531 
532                   // single attribute
attributes(res)533 attributes(res)  ::= attribute(a). {
534     res = array(a);
535 }
536 
537                   // no attributes
attributes(res)538 attributes(res)  ::= . {
539     res = array();
540 }
541 
542                   // attribute
attribute(res)543 attribute(res)   ::= SPACE ID(v) EQUAL ID(id). {
544     if (defined(id)) {
545         if ($this->security) {
546             $this->security->isTrustedConstant(id, $this->compiler);
547         }
548         res = array(v=>id);
549     } else {
550         res = array(v=>'\''.id.'\'');
551     }
552 }
553 
attribute(res)554 attribute(res)   ::= ATTR(v) expr(e). {
555     res = array(trim(v," =\n\r\t")=>e);
556 }
557 
attribute(res)558 attribute(res)   ::= ATTR(v) value(e). {
559     res = array(trim(v," =\n\r\t")=>e);
560 }
561 
attribute(res)562 attribute(res)   ::= SPACE ID(v). {
563     res = '\''.v.'\'';
564 }
565 
attribute(res)566 attribute(res)   ::= SPACE expr(e). {
567     res = e;
568 }
569 
attribute(res)570 attribute(res)   ::= SPACE value(v). {
571     res = v;
572 }
573 
attribute(res)574 attribute(res)   ::= SPACE INTEGER(i) EQUAL expr(e). {
575     res = array(i=>e);
576 }
577 
578 
579 
580 //
581 // statement
582 //
statements(res)583 statements(res)   ::= statement(s). {
584     res = array(s);
585 }
586 
statements(res)587 statements(res)   ::= statements(s1) COMMA statement(s). {
588     s1[]=s;
589     res = s1;
590 }
591 
statement(res)592 statement(res)    ::= DOLLARID(i) EQUAL INTEGER(e). {
593     res = array('var' => '\''.substr(i,1).'\'', 'value'=>e);
594 }
statement(res)595 statement(res)    ::= DOLLARID(i) EQUAL expr(e). {
596     res = array('var' => '\''.substr(i,1).'\'', 'value'=>e);
597 }
598 
statement(res)599 statement(res)    ::= varindexed(vi) EQUAL expr(e). {
600     res = array('var' => vi, 'value'=>e);
601 }
602 
statement(res)603 statement(res)    ::= OPENP statement(st) CLOSEP. {
604     res = st;
605 }
606 
607 
608 //
609 // expressions
610 //
611 
612                   // single value
expr(res)613 expr(res)        ::= value(v). {
614     res = v;
615 }
616 
617                  // ternary
expr(res)618 expr(res)        ::= ternary(v). {
619     res = v;
620 }
621 
622                  // resources/streams
expr(res)623 expr(res)        ::= DOLLARID(i) COLON ID(i2). {
624     res = '$_smarty_tpl->getStreamVariable(\''.substr(i,1).'://' . i2 . '\')';
625 }
626 
627                   // arithmetic expression
expr(res)628 expr(res)        ::= expr(e) MATH(m) value(v). {
629     res = e . trim(m) . v;
630 }
631 
expr(res)632 expr(res)        ::= expr(e) UNIMATH(m) value(v). {
633     res = e . trim(m) . v;
634 }
635 
636 // if expression
637                     // special conditions
expr(res)638 expr(res)        ::= expr(e1) tlop(c) value(e2). {
639     res = c['pre']. e1.c['op'].e2 .')';
640 }
641                     // simple expression
expr(res)642 expr(res)        ::= expr(e1) lop(c) expr(e2). {
643     res = e1.c.e2;
644 }
645 
expr(res)646 expr(res)        ::= expr(e1) scond(c). {
647     res = c . e1 . ')';
648 }
649 
expr(res)650 expr(res)        ::= expr(e1) ISIN array(a).  {
651     res = 'in_array('.e1.','.a.')';
652 }
653 
expr(res)654 expr(res)        ::= expr(e1) ISIN value(v).  {
655     res = 'in_array('.e1.',(array)'.v.')';
656 }
657 
658 
659 //
660 // ternary
661 //
ternary(res)662 ternary(res)        ::= OPENP expr(v) CLOSEP  QMARK DOLLARID(e1) COLON  expr(e2). {
663     res = v.' ? '. $this->compiler->compileVariable('\''.substr(e1,1).'\'') . ' : '.e2;
664 }
665 
ternary(res)666 ternary(res)        ::= OPENP expr(v) CLOSEP  QMARK  expr(e1) COLON  expr(e2). {
667     res = v.' ? '.e1.' : '.e2;
668 }
669 
670                  // value
value(res)671 value(res)       ::= variable(v). {
672     res = v;
673 }
674 
675                   // +/- value
value(res)676 value(res)        ::= UNIMATH(m) value(v). {
677     res = m.v;
678 }
679 
680                   // logical negation
value(res)681 value(res)       ::= NOT value(v). {
682     res = '!'.v;
683 }
684 
value(res)685 value(res)       ::= TYPECAST(t) value(v). {
686     res = t.v;
687 }
688 
value(res)689 value(res)       ::= variable(v) INCDEC(o). {
690     res = v.o;
691 }
692 
693                  // numeric
value(res)694 value(res)       ::= HEX(n). {
695     res = n;
696 }
697 
value(res)698 value(res)       ::= INTEGER(n). {
699     res = n;
700 }
701 
value(res)702 value(res)       ::= INTEGER(n1) DOT INTEGER(n2). {
703     res = n1.'.'.n2;
704 }
705 
value(res)706 value(res)       ::= INTEGER(n1) DOT. {
707     res = n1.'.';
708 }
709 
value(res)710 value(res)       ::= DOT INTEGER(n1). {
711     res = '.'.n1;
712 }
713 
714                  // ID, true, false, null
value(res)715 value(res)       ::= ID(id). {
716     if (defined(id)) {
717         if ($this->security) {
718              $this->security->isTrustedConstant(id, $this->compiler);
719         }
720         res = id;
721     } else {
722         res = '\''.id.'\'';
723     }
724 }
725 
726                   // function call
value(res)727 value(res)       ::= function(f). {
728     res = f;
729 }
730 
731                   // expression
value(res)732 value(res)       ::= OPENP expr(e) CLOSEP. {
733     res = '('. e .')';
734 }
735 
value(res)736 value(res)        ::= variable(v1) INSTANCEOF(i) ns1(v2). {
737       res = v1.i.v2;
738 }
value(res)739 value(res)        ::= variable(v1) INSTANCEOF(i) variable(v2). {
740       res = v1.i.v2;
741 }
742 
743                   // singele quoted string
value(res)744 value(res)       ::= SINGLEQUOTESTRING(t). {
745     res = t;
746 }
747 
748                   // double quoted string
value(res)749 value(res)       ::= doublequoted_with_quotes(s). {
750     res = s;
751 }
752 
753 
value(res)754 value(res)    ::= varindexed(vi) DOUBLECOLON static_class_access(r). {
755     $prefixVar = $this->compiler->getNewPrefixVariable();
756     if (vi['var'] === '\'smarty\'') {
757         $this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileTag('private_special_variable',array(),vi['smarty_internal_index']).';?>');
758      } else {
759         $this->compiler->appendPrefixCode("<?php  {$prefixVar} = ". $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'].';?>');
760     }
761     res = $prefixVar .'::'.r[0].r[1];
762 }
763 
764                   // Smarty tag
value(res)765 value(res)       ::= smartytag(st). {
766     $prefixVar = $this->compiler->getNewPrefixVariable();
767     $tmp = $this->compiler->appendCode('<?php ob_start();?>', st);
768     $this->compiler->appendPrefixCode($this->compiler->appendCode($tmp, "<?php {$prefixVar} = ob_get_clean();?>"));
769     res = $prefixVar;
770 }
771 
value(res)772 value(res)       ::= value(v) modifierlist(l). {
773     res = $this->compiler->compileTag('private_modifier',array(),array('value'=>v,'modifierlist'=>l));
774 }
775                   // name space constant
value(res)776 value(res)       ::= NAMESPACE(c). {
777     res = c;
778 }
779 
780                   // array
value(res)781 value(res)       ::= arraydef(a). {
782     res = a;
783 }
784                   // static class access
value(res)785 value(res)       ::= ns1(c)DOUBLECOLON static_class_access(s). {
786     if (!in_array(strtolower(c), array('self', 'parent')) && (!$this->security || $this->security->isTrustedStaticClassAccess(c, s, $this->compiler))) {
787         if (isset($this->smarty->registered_classes[c])) {
788             res = $this->smarty->registered_classes[c].'::'.s[0].s[1];
789         } else {
790             res = c.'::'.s[0].s[1];
791         }
792     } else {
793         $this->compiler->trigger_template_error ('static class \''.c.'\' is undefined or not allowed by security setting');
794     }
795 }
796 //
797 // namespace stuff
798 //
799 
ns1(res)800 ns1(res)           ::= ID(i). {
801     res = i;
802 }
803 
ns1(res)804 ns1(res)           ::= NAMESPACE(i). {
805     res = i;
806     }
807 
808 
809 
810 
811 //
812 // variables
813 //
814                   // Smarty variable (optional array)
variable(res)815 variable(res)    ::= DOLLARID(i). {
816    res = $this->compiler->compileVariable('\''.substr(i,1).'\'');
817 }
variable(res)818 variable(res)    ::= varindexed(vi). {
819     if (vi['var'] === '\'smarty\'') {
820         $smarty_var = $this->compiler->compileTag('private_special_variable',array(),vi['smarty_internal_index']);
821         res = $smarty_var;
822     } else {
823         // used for array reset,next,prev,end,current
824         $this->last_variable = vi['var'];
825         $this->last_index = vi['smarty_internal_index'];
826         res = $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'];
827     }
828 }
829 
830                   // variable with property
variable(res)831 variable(res)    ::= varvar(v) AT ID(p). {
832     res = '$_smarty_tpl->tpl_vars['. v .']->'.p;
833 }
834 
835                   // object
variable(res)836 variable(res)    ::= object(o). {
837     res = o;
838 }
839 
840                   // config variable
variable(res)841 variable(res)    ::= HATCH ID(i) HATCH. {
842     res = $this->compiler->compileConfigVariable('\'' . i . '\'');
843 }
844 
variable(res)845 variable(res)    ::= HATCH ID(i) HATCH arrayindex(a). {
846     res = '(is_array($tmp = ' . $this->compiler->compileConfigVariable('\'' . i . '\'') . ') ? $tmp'.a.' :null)';
847 }
848 
variable(res)849 variable(res)    ::= HATCH variable(v) HATCH. {
850     res = $this->compiler->compileConfigVariable(v);
851 }
852 
variable(res)853 variable(res)    ::= HATCH variable(v) HATCH arrayindex(a). {
854     res = '(is_array($tmp = ' . $this->compiler->compileConfigVariable(v) . ') ? $tmp'.a.' : null)';
855 }
856 
varindexed(res)857 varindexed(res)  ::= DOLLARID(i) arrayindex(a). {
858     res = array('var'=>'\''.substr(i,1).'\'', 'smarty_internal_index'=>a);
859 }
varindexed(res)860 varindexed(res)  ::= varvar(v) arrayindex(a). {
861     res = array('var'=>v, 'smarty_internal_index'=>a);
862 }
863 
864 //
865 // array index
866 //
867                     // multiple array index
arrayindex(res)868 arrayindex(res)  ::= arrayindex(a1) indexdef(a2). {
869     res = a1.a2;
870 }
871 
872                     // no array index
873 arrayindex        ::= . {
874     return;
875 }
876 
877 // single index definition
878                     // Smarty2 style index
indexdef(res)879 indexdef(res)    ::= DOT DOLLARID(i).  {
880     res = '['.$this->compiler->compileVariable('\''.substr(i,1).'\'').']';
881 }
indexdef(res)882 indexdef(res)    ::= DOT varvar(v).  {
883     res = '['.$this->compiler->compileVariable(v).']';
884 }
885 
indexdef(res)886 indexdef(res)    ::= DOT varvar(v) AT ID(p). {
887     res = '['.$this->compiler->compileVariable(v).'->'.p.']';
888 }
889 
indexdef(res)890 indexdef(res)   ::= DOT ID(i). {
891     res = '[\''. i .'\']';
892 }
893 
indexdef(res)894 indexdef(res)   ::= DOT INTEGER(n). {
895     res = '['. n .']';
896 }
897 
898 
indexdef(res)899 indexdef(res)   ::= DOT LDEL expr(e) RDEL. {
900     res = '['. e .']';
901 }
902 
903                     // section tag index
indexdef(res)904 indexdef(res)   ::= OPENB ID(i)CLOSEB. {
905     res = '['.$this->compiler->compileTag('private_special_variable',array(),'[\'section\'][\''.i.'\'][\'index\']').']';
906 }
907 
indexdef(res)908 indexdef(res)   ::= OPENB ID(i) DOT ID(i2) CLOSEB. {
909     res = '['.$this->compiler->compileTag('private_special_variable',array(),'[\'section\'][\''.i.'\'][\''.i2.'\']').']';
910 }
indexdef(res)911 indexdef(res)   ::= OPENB SINGLEQUOTESTRING(s) CLOSEB. {
912     res = '['.s.']';
913 }
indexdef(res)914 indexdef(res)   ::= OPENB INTEGER(n) CLOSEB. {
915     res = '['.n.']';
916 }
indexdef(res)917 indexdef(res)   ::= OPENB DOLLARID(i) CLOSEB. {
918     res = '['.$this->compiler->compileVariable('\''.substr(i,1).'\'').']';
919 }
indexdef(res)920 indexdef(res)   ::= OPENB variable(v) CLOSEB. {
921     res = '['.v.']';
922 }
indexdef(res)923 indexdef(res)   ::= OPENB value(v) CLOSEB. {
924     res = '['.v.']';
925 }
926 
927                     // PHP style index
indexdef(res)928 indexdef(res)   ::= OPENB expr(e) CLOSEB. {
929     res = '['. e .']';
930 }
931 
932                     // for assign append array
indexdef(res)933 indexdef(res)  ::= OPENB CLOSEB. {
934     res = '[]';
935 }
936 
937 
938 //
939 // variable variable names
940 //
941 
942                     // singel identifier element
varvar(res)943 varvar(res)      ::= DOLLARID(i). {
944     res = '\''.substr(i,1).'\'';
945 }
946                     // single $
varvar(res)947 varvar(res)      ::= DOLLAR. {
948     res = '\'\'';
949 }
950 
951                     // sequence of identifier elements
varvar(res)952 varvar(res)      ::= varvar(v1) varvarele(v2). {
953     res = v1.'.'.v2;
954 }
955 
956                     // fix sections of element
varvarele(res)957 varvarele(res)   ::= ID(s). {
958     res = '\''.s.'\'';
959 }
varvarele(res)960 varvarele(res)   ::= SIMPELOUTPUT(i). {
961     $var = trim(substr(i, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $');
962     res = $this->compiler->compileVariable('\''.$var.'\'');
963 }
964 
965                     // variable sections of element
varvarele(res)966 varvarele(res)   ::= LDEL expr(e) RDEL. {
967     res = '('.e.')';
968 }
969 
970 //
971 // objects
972 //
object(res)973 object(res)    ::= varindexed(vi) objectchain(oc). {
974     if (vi['var'] === '\'smarty\'') {
975         res =  $this->compiler->compileTag('private_special_variable',array(),vi['smarty_internal_index']).oc;
976     } else {
977         res = $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'].oc;
978     }
979 }
980 
981                     // single element
objectchain(res)982 objectchain(res) ::= objectelement(oe). {
983     res  = oe;
984 }
985 
986                     // chain of elements
objectchain(res)987 objectchain(res) ::= objectchain(oc) objectelement(oe). {
988     res  = oc.oe;
989 }
990 
991                     // variable
objectelement(res)992 objectelement(res)::= PTR ID(i) arrayindex(a). {
993     if ($this->security && substr(i,0,1) === '_') {
994         $this->compiler->trigger_template_error (self::ERR1);
995     }
996     res = '->'.i.a;
997 }
998 
objectelement(res)999 objectelement(res)::= PTR varvar(v) arrayindex(a). {
1000     if ($this->security) {
1001         $this->compiler->trigger_template_error (self::ERR2);
1002     }
1003     res = '->{'.$this->compiler->compileVariable(v).a.'}';
1004 }
1005 
objectelement(res)1006 objectelement(res)::= PTR LDEL expr(e) RDEL arrayindex(a). {
1007     if ($this->security) {
1008         $this->compiler->trigger_template_error (self::ERR2);
1009     }
1010     res = '->{'.e.a.'}';
1011 }
1012 
objectelement(res)1013 objectelement(res)::= PTR ID(ii) LDEL expr(e) RDEL arrayindex(a). {
1014     if ($this->security) {
1015         $this->compiler->trigger_template_error (self::ERR2);
1016     }
1017     res = '->{\''.ii.'\'.'.e.a.'}';
1018 }
1019 
1020                     // method
objectelement(res)1021 objectelement(res)::= PTR method(f).  {
1022     res = '->'.f;
1023 }
1024 
1025 
1026 //
1027 // function
1028 //
function(res)1029 function(res)     ::= ns1(f) OPENP params(p) CLOSEP. {
1030     res = $this->compiler->compilePHPFunctionCall(f, p);
1031 }
1032 
1033 
1034 //
1035 // method
1036 //
method(res)1037 method(res)     ::= ID(f) OPENP params(p) CLOSEP. {
1038     if ($this->security && substr(f,0,1) === '_') {
1039         $this->compiler->trigger_template_error (self::ERR1);
1040     }
1041     res = f . '('. implode(',',p) .')';
1042 }
1043 
method(res)1044 method(res)     ::= DOLLARID(f) OPENP params(p) CLOSEP.  {
1045     if ($this->security) {
1046         $this->compiler->trigger_template_error (self::ERR2);
1047     }
1048     $prefixVar = $this->compiler->getNewPrefixVariable();
1049     $this->compiler->appendPrefixCode("<?php {$prefixVar} = ".$this->compiler->compileVariable('\''.substr(f,1).'\'').';?>');
1050     res = $prefixVar .'('. implode(',',p) .')';
1051 }
1052 
1053 // function/method parameter
1054                     // multiple parameters
params(res)1055 params(res)       ::= params(p) COMMA expr(e). {
1056     res = array_merge(p,array(e));
1057 }
1058 
1059                     // single parameter
params(res)1060 params(res)       ::= expr(e). {
1061     res = array(e);
1062 }
1063 
1064                     // kein parameter
params(res)1065 params(res)       ::= . {
1066     res = array();
1067 }
1068 
1069 //
1070 // modifier
1071 //
modifierlist(res)1072 modifierlist(res) ::= modifierlist(l) modifier(m) modparameters(p). {
1073     res = array_merge(l,array(array_merge(m,p)));
1074 }
1075 
modifierlist(res)1076 modifierlist(res) ::= modifier(m) modparameters(p). {
1077     res = array(array_merge(m,p));
1078 }
1079 
modifier(res)1080 modifier(res)    ::= VERT AT ID(m). {
1081     res = array(m);
1082 }
1083 
modifier(res)1084 modifier(res)    ::= VERT ID(m). {
1085     res =  array(m);
1086 }
1087 
1088 //
1089 // modifier parameter
1090 //
1091                     // multiple parameter
modparameters(res)1092 modparameters(res) ::= modparameters(mps) modparameter(mp). {
1093     res = array_merge(mps,mp);
1094 }
1095 
1096                     // no parameter
modparameters(res)1097 modparameters(res)      ::= . {
1098     res = array();
1099 }
1100 
1101                     // parameter expression
modparameter(res)1102 modparameter(res) ::= COLON value(mp). {
1103     res = array(mp);
1104 }
modparameter(res)1105 modparameter(res) ::= COLON UNIMATH(m) value(mp). {
1106     res = array(trim(m).mp);
1107 }
1108 
modparameter(res)1109 modparameter(res) ::= COLON array(mp). {
1110     res = array(mp);
1111 }
1112 
1113                   // static class methode call
static_class_access(res)1114 static_class_access(res)       ::= method(m). {
1115     res = array(m, '', 'method');
1116 }
1117 
1118                   // static class methode call with object chainig
static_class_access(res)1119 static_class_access(res)       ::= method(m) objectchain(oc). {
1120     res = array(m, oc, 'method');
1121 }
1122 
1123                   // static class constant
static_class_access(res)1124 static_class_access(res)       ::= ID(v). {
1125     res = array(v, '');
1126 }
1127 
1128                   // static class variables
static_class_access(res)1129 static_class_access(res)       ::=  DOLLARID(v) arrayindex(a). {
1130     res = array(v, a, 'property');
1131 }
1132 
1133                   // static class variables with object chain
static_class_access(res)1134 static_class_access(res)       ::= DOLLARID(v) arrayindex(a) objectchain(oc). {
1135     res = array(v, a.oc, 'property');
1136 }
1137 
1138 
1139 // if conditions and operators
lop(res)1140 lop(res)        ::= LOGOP(o). {
1141     res = ' '. trim(o) . ' ';
1142 }
1143 
lop(res)1144 lop(res)        ::= SLOGOP(o). {
1145     static $lops = array(
1146         'eq' => ' == ',
1147         'ne' => ' != ',
1148         'neq' => ' != ',
1149         'gt' => ' > ',
1150         'ge' => ' >= ',
1151         'gte' => ' >= ',
1152         'lt' =>  ' < ',
1153         'le' =>  ' <= ',
1154         'lte' => ' <= ',
1155         'mod' =>  ' % ',
1156         'and' => ' && ',
1157         'or' => ' || ',
1158         'xor' => ' xor ',
1159          );
1160     $op = strtolower(preg_replace('/\s*/', '', o));
1161     res = $lops[$op];
1162 }
tlop(res)1163 tlop(res)        ::= TLOGOP(o). {
1164      static $tlops = array(
1165          'isdivby' => array('op' => ' % ', 'pre' => '!('),
1166          'isnotdivby' => array('op' => ' % ', 'pre' => '('),
1167          'isevenby' => array('op' => ' / ', 'pre' => '!(1 & '),
1168          'isnotevenby' => array('op' => ' / ', 'pre' => '(1 & '),
1169          'isoddby' => array('op' => ' / ', 'pre' => '(1 & '),
1170          'isnotoddby' => array('op' => ' / ', 'pre' => '!(1 & '),
1171          );
1172      $op = strtolower(preg_replace('/\s*/', '', o));
1173      res = $tlops[$op];
1174  }
1175 
scond(res)1176 scond(res)  ::= SINGLECOND(o). {
1177         static $scond = array (
1178             'iseven' => '!(1 & ',
1179             'isnoteven' => '(1 & ',
1180             'isodd' => '(1 & ',
1181             'isnotodd' => '!(1 & ',
1182         );
1183    $op = strtolower(str_replace(' ', '', o));
1184    res = $scond[$op];
1185 }
1186 
1187 //
1188 // ARRAY element assignment
1189 //
arraydef(res)1190 arraydef(res)           ::=  OPENB arrayelements(a) CLOSEB.  {
1191     res = 'array('.a.')';
1192 }
arraydef(res)1193 arraydef(res)           ::=  ARRAYOPEN arrayelements(a) CLOSEP.  {
1194     res = 'array('.a.')';
1195 }
1196 
arrayelements(res)1197 arrayelements(res)   ::=  arrayelement(a).  {
1198     res = a;
1199 }
1200 
arrayelements(res)1201 arrayelements(res)   ::=  arrayelements(a1) COMMA arrayelement(a).  {
1202     res = a1.','.a;
1203 }
1204 
1205 arrayelements        ::=  .  {
1206     return;
1207 }
1208 
arrayelement(res)1209 arrayelement(res)    ::=  value(e1) APTR expr(e2). {
1210     res = e1.'=>'.e2;
1211 }
1212 
arrayelement(res)1213 arrayelement(res)    ::=  ID(i) APTR expr(e2). {
1214     res = '\''.i.'\'=>'.e2;
1215 }
1216 
arrayelement(res)1217 arrayelement(res)    ::=  expr(e). {
1218     res = e;
1219 }
1220 
1221 
1222 //
1223 // double quoted strings
1224 //
doublequoted_with_quotes(res)1225 doublequoted_with_quotes(res) ::= QUOTE QUOTE. {
1226     res = '\'\'';
1227 }
1228 
doublequoted_with_quotes(res)1229 doublequoted_with_quotes(res) ::= QUOTE doublequoted(s) QUOTE. {
1230     $this->compiler->leaveDoubleQuote();
1231     res = s->to_smarty_php($this);
1232 }
1233 
1234 
doublequoted(res)1235 doublequoted(res)          ::= doublequoted(o1) doublequotedcontent(o2). {
1236     o1->append_subtree($this, o2);
1237     res = o1;
1238 }
1239 
doublequoted(res)1240 doublequoted(res)          ::= doublequotedcontent(o). {
1241     res = new Smarty_Internal_ParseTree_Dq($this, o);
1242 }
1243 
doublequotedcontent(res)1244 doublequotedcontent(res)           ::=  BACKTICK variable(v) BACKTICK. {
1245     res = new Smarty_Internal_ParseTree_Code('(string)'.v);
1246 }
1247 
doublequotedcontent(res)1248 doublequotedcontent(res)           ::=  BACKTICK expr(e) BACKTICK. {
1249     res = new Smarty_Internal_ParseTree_Code('(string)('.e.')');
1250 }
1251 
doublequotedcontent(res)1252 doublequotedcontent(res)           ::=  DOLLARID(i). {
1253     res = new Smarty_Internal_ParseTree_Code('(string)$_smarty_tpl->tpl_vars[\''. substr(i,1) .'\']->value');
1254 }
1255 
doublequotedcontent(res)1256 doublequotedcontent(res)           ::=  LDEL variable(v) RDEL. {
1257     res = new Smarty_Internal_ParseTree_Code('(string)'.v);
1258 }
1259 
doublequotedcontent(res)1260 doublequotedcontent(res)           ::=  LDEL expr(e) RDEL. {
1261     res = new Smarty_Internal_ParseTree_Code('(string)('.e.')');
1262 }
1263 
doublequotedcontent(res)1264 doublequotedcontent(res)     ::=  smartytag(st). {
1265     res = new Smarty_Internal_ParseTree_Tag($this, st);
1266 }
1267 
doublequotedcontent(res)1268 doublequotedcontent(res)           ::=  TEXT(o). {
1269     res = new Smarty_Internal_ParseTree_DqContent(o);
1270 }
1271 
1272