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