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