diff --git a/change_log.txt b/change_log.txt
index ac182246..7e76866a 100644
--- a/change_log.txt
+++ b/change_log.txt
@@ -1,4 +1,9 @@
===== 3.1.24.dev ===== (xx.xx.2015)
+ 16.05.2015
+ - bugfix {php}{/php} did work just for single lines https://github.com/smarty-php/smarty/issues/33
+ - improvement remove not needed ?>]{2})\s*/
comment = /SMARTYldel\*([\S\s]*?)\*SMARTYrdel/
incdec = /\+\+|\-\-/
unimath = /\s*(\+|\-)\s*/
@@ -276,25 +276,9 @@ class Smarty_Internal_Templatelexer
id = /[0-9]*[a-zA-Z_]\w*/
literal = /literal/
strip = /strip/
- equals = /\s*==\s*|\s+eq\s+/
- notequals = /\s*!=\s*|\s*<>\s*|\s+(ne|neq)\s+/
- greaterthan = /\s*>\s*|\s+gt\s+/
- lessthan = /\s*<\s*|\s+lt\s+/
- greaterequal = /\s*>=\s*|\s+(ge|gte)\s+/
- lessequal = /\s*<=\s*|\s+(le|lte)\s+/
- mod = /\s+mod\s+/
- identity = /\s*===\s*/
- noneidentity = /\s*!==\s*/
- isoddby = /\s+is\s+odd\s+by\s+/
- isnotoddby = /\s+is\s+not\s+odd\s+by\s+/
- isodd = /\s+is\s+odd/
- isnotodd = /\s+is\s+not\s+odd/
- isevenby = /\s+is\s+even\s+by\s+/
- isnotevenby = /\s+is\s+not\s+even\s+by\s+/
- iseven = /\s+is\s+even/
- isnoteven = /\s+is\s+not\s+even/
- isdivby = /\s+is\s+div\s+by\s+/
- isnotdivby = /\s+is\s+not\s+div\s+by\s+/
+ lop = /\s*(([!=][=]{1,2})|([<][=>]?)|([>][=]?)|[&|]{2})\s*/
+ tlop = /\s+(eq|ne|neg|gt|ge|gte|lt|le|lte|mod|and|or|xor|(is\s+(not\s+)?(odd|even|div)\s+by))\s+/
+ scond = /\s+is\s+(not\s+)?(odd|even)/
isin = /\s+is\s+in\s+/
as = /\s+as\s+/
to = /\s+to\s+/
@@ -306,9 +290,6 @@ class Smarty_Internal_Templatelexer
setfilter = /setfilter\s+/
instanceof = /\s+instanceof\s+/
not = /!\s*|not\s+/
- land = /\s*\&\&\s*|\s*and\s+/
- lor = /\s*\|\|\s*|\s*or\s+/
- lxor = /\s*xor\s+/
typecast = /\((int(eger)?|bool(ean)?|float|double|real|string|binary|array|object)\)\s*/
double_quote = /"/
single_quote = /'/
@@ -480,76 +461,18 @@ class Smarty_Internal_Templatelexer
instanceof {
$this->token = Smarty_Internal_Templateparser::TP_INSTANCEOF;
}
- identity{
- $this->token = Smarty_Internal_Templateparser::TP_IDENTITY;
+ lop {
+ $this->token = Smarty_Internal_Templateparser::TP_LOGOP;
}
- noneidentity{
- $this->token = Smarty_Internal_Templateparser::TP_NONEIDENTITY;
+ tlop {
+ $this->token = Smarty_Internal_Templateparser::TP_TLOGOP;
}
- equals{
- $this->token = Smarty_Internal_Templateparser::TP_EQUALS;
- }
- notequals{
- $this->token = Smarty_Internal_Templateparser::TP_NOTEQUALS;
- }
- greaterequal{
- $this->token = Smarty_Internal_Templateparser::TP_GREATEREQUAL;
- }
- lessequal{
- $this->token = Smarty_Internal_Templateparser::TP_LESSEQUAL;
- }
- greaterthan{
- $this->token = Smarty_Internal_Templateparser::TP_GREATERTHAN;
- }
- lessthan{
- $this->token = Smarty_Internal_Templateparser::TP_LESSTHAN;
- }
- mod{
- $this->token = Smarty_Internal_Templateparser::TP_MOD;
+ scond {
+ $this->token = Smarty_Internal_Templateparser::TP_SINGLECOND;
}
not{
$this->token = Smarty_Internal_Templateparser::TP_NOT;
}
- land {
- $this->token = Smarty_Internal_Templateparser::TP_LAND;
- }
- lor {
- $this->token = Smarty_Internal_Templateparser::TP_LOR;
- }
- lxor {
- $this->token = Smarty_Internal_Templateparser::TP_LXOR;
- }
- isoddby {
- $this->token = Smarty_Internal_Templateparser::TP_ISODDBY;
- }
- isnotoddby {
- $this->token = Smarty_Internal_Templateparser::TP_ISNOTODDBY;
- }
-
- isodd {
- $this->token = Smarty_Internal_Templateparser::TP_ISODD;
- }
- isnotodd {
- $this->token = Smarty_Internal_Templateparser::TP_ISNOTODD;
- }
- isevenby {
- $this->token = Smarty_Internal_Templateparser::TP_ISEVENBY;
- }
- isnotevenby {
- $this->token = Smarty_Internal_Templateparser::TP_ISNOTEVENBY;
- }
- iseven{
- $this->token = Smarty_Internal_Templateparser::TP_ISEVEN;
- }
- isnoteven {
- $this->token = Smarty_Internal_Templateparser::TP_ISNOTEVEN;
- }
- isdivby {
- $this->token = Smarty_Internal_Templateparser::TP_ISDIVBY;
- }
- isnotdivby {
- $this->token = Smarty_Internal_Templateparser::TP_ISNOTDIVBY;
- }
typecast {
$this->token = Smarty_Internal_Templateparser::TP_TYPECAST;
}
@@ -562,7 +485,6 @@ class Smarty_Internal_Templatelexer
openB {
$this->token = Smarty_Internal_Templateparser::TP_OPENB;
}
-
closeB {
$this->token = Smarty_Internal_Templateparser::TP_CLOSEB;
}
diff --git a/lexer/smarty_internal_templateparser.y b/lexer/smarty_internal_templateparser.y
index f155efe3..77b3e84d 100644
--- a/lexer/smarty_internal_templateparser.y
+++ b/lexer/smarty_internal_templateparser.y
@@ -660,8 +660,11 @@ expr(res) ::= expr(e) modifierlist(l). {
// if expression
// simple expression
-expr(res) ::= expr(e1) ifcond(c) expr(e2). {
- res = e1.c.e2;
+expr(res) ::= expr(e1) lop(c) expr(e2). {
+ res = (isset(c['pre']) ? c['pre'] : '') . e1.c['op'].e2 . (isset(c['pre']) ? ')' : '');
+}
+expr(res) ::= expr(e1) scond(c). {
+ res = c . e1 . ')';
}
expr(res) ::= expr(e1) ISIN array(a). {
@@ -672,53 +675,9 @@ expr(res) ::= expr(e1) ISIN value(v). {
res = 'in_array('.e1.',(array)'.v.')';
}
-expr(res) ::= expr(e1) lop(o) expr(e2). {
- res = e1.o.e2;
-}
-
-expr(res) ::= expr(e1) ISDIVBY expr(e2). {
- res = '!('.e1.' % '.e2.')';
-}
-
-expr(res) ::= expr(e1) ISNOTDIVBY expr(e2). {
- res = '('.e1.' % '.e2.')';
-}
-
-expr(res) ::= expr(e1) ISEVEN. {
- res = '!(1 & '.e1.')';
-}
-
-expr(res) ::= expr(e1) ISNOTEVEN. {
- res = '(1 & '.e1.')';
-}
-
-expr(res) ::= expr(e1) ISEVENBY expr(e2). {
- res = '!(1 & '.e1.' / '.e2.')';
-}
-
-expr(res) ::= expr(e1) ISNOTEVENBY expr(e2). {
- res = '(1 & '.e1.' / '.e2.')';
-}
-
-expr(res) ::= expr(e1) ISODD. {
- res = '(1 & '.e1.')';
-}
-
-expr(res) ::= expr(e1) ISNOTODD. {
- res = '!(1 & '.e1.')';
-}
-
-expr(res) ::= expr(e1) ISODDBY expr(e2). {
- res = '(1 & '.e1.' / '.e2.')';
-}
-
-expr(res) ::= expr(e1) ISNOTODDBY expr(e2). {
- res = '!(1 & '.e1.' / '.e2.')';
-}
-
expr(res) ::= variable(v1) INSTANCEOF(i) ns1(v2). {
res = v1.i.v2;
- }
+}
//
@@ -1199,52 +1158,45 @@ static_class_access(res) ::= DOLLAR ID(v) arrayindex(a) objectchain(oc). {
// if conditions and operators
-ifcond(res) ::= EQUALS. {
- res = '==';
+lop(res) ::= LOGOP(o). {
+ res['op'] = ' '. trim(o) . ' ';
}
-ifcond(res) ::= NOTEQUALS. {
- res = '!=';
+lop(res) ::= TLOGOP(o). {
+ static $lops = array(
+ 'eq' => array('op' => ' == ', 'pre' => null),
+ 'ne' => array('op' => ' != ', 'pre' => null),
+ 'neq' => array('op' => ' != ', 'pre' => null),
+ 'gt' => array('op' => ' > ', 'pre' => null),
+ 'ge' => array('op' => ' >= ', 'pre' => null),
+ 'gte' => array('op' => ' >= ', 'pre' => null),
+ 'lt' => array('op' => ' < ', 'pre' => null),
+ 'le' => array('op' => ' <= ', 'pre' => null),
+ 'lte' => array('op' => ' <= ', 'pre' => null),
+ 'mod' => array('op' => ' % ', 'pre' => null),
+ 'and' => array('op' => ' && ', 'pre' => null),
+ 'or' => array('op' => ' || ', 'pre' => null),
+ 'xor' => array('op' => ' xor ', 'pre' => null),
+ 'isdivby' => array('op' => ' % ', 'pre' => '!('),
+ 'isnotdivby' => array('op' => ' % ', 'pre' => '('),
+ 'isevenby' => array('op' => ' / ', 'pre' => '!(1 & '),
+ 'isnotevenby' => array('op' => ' / ', 'pre' => '(1 & '),
+ 'isoddby' => array('op' => ' / ', 'pre' => '(1 & '),
+ 'isnotoddby' => array('op' => ' / ', 'pre' => '!(1 & '),
+ );
+ $op = strtolower(str_replace(' ', '', o));
+ res = $lops[$op];
}
-ifcond(res) ::= GREATERTHAN. {
- res = '>';
-}
-
-ifcond(res) ::= LESSTHAN. {
- res = '<';
-}
-
-ifcond(res) ::= GREATEREQUAL. {
- res = '>=';
-}
-
-ifcond(res) ::= LESSEQUAL. {
- res = '<=';
-}
-
-ifcond(res) ::= IDENTITY. {
- res = '===';
-}
-
-ifcond(res) ::= NONEIDENTITY. {
- res = '!==';
-}
-
-ifcond(res) ::= MOD. {
- res = '%';
-}
-
-lop(res) ::= LAND. {
- res = '&&';
-}
-
-lop(res) ::= LOR. {
- res = '||';
-}
-
-lop(res) ::= LXOR. {
- res = ' XOR ';
+scond(res) ::= SINGLECOND(o). {
+ static $scond = array (
+ 'iseven' => '!(1 & ',
+ 'isnoteven' => '(1 & ',
+ 'isodd' => '(1 & ',
+ 'isnotodd' => '!(1 & ',
+ );
+ $op = strtolower(str_replace(' ', '', o));
+ res = $scond[$op];
}
//
diff --git a/libs/sysplugins/smarty_internal_templatelexer.php b/libs/sysplugins/smarty_internal_templatelexer.php
index 724e43a0..1240e0e5 100644
--- a/libs/sysplugins/smarty_internal_templatelexer.php
+++ b/libs/sysplugins/smarty_internal_templatelexer.php
@@ -19,147 +19,176 @@
*/
class Smarty_Internal_Templatelexer
{
-
/**
* Source
*
* @var string
*/
public $data;
-
/**
* byte counter
*
* @var int
*/
public $counter;
-
/**
* token number
*
* @var int
*/
public $token;
-
/**
* token value
*
* @var string
*/
public $value;
-
/**
* current line
*
* @var int
*/
public $line;
-
/**
* tag start line
*
* @var
*/
public $taglineno;
-
/**
* flag if parsing php script
*
* @var bool
*/
public $is_phpScript = false;
-
- /**
+ /**
* php code type
*
* @var string
*/
public $phpType = '';
-
/**
* escaped left delimiter
*
* @var string
*/
public $ldel = '';
-
/**
* escaped left delimiter length
*
* @var int
*/
public $ldel_length = 0;
-
/**
* escaped right delimiter
*
* @var string
*/
public $rdel = '';
-
/**
* escaped right delimiter length
*
* @var int
*/
public $rdel_length = 0;
-
/**
* state number
*
* @var int
*/
public $state = 1;
-
/**
* Smarty object
*
* @var Smarty
*/
public $smarty = null;
-
/**
* compiler object
*
* @var Smarty_Internal_TemplateCompilerBase
*/
private $compiler = null;
-
/**
* literal tag nesting level
*
* @var int
*/
private $literal_cnt = 0;
-
/**
* trace file
*
* @var resource
*/
public $yyTraceFILE;
-
/**
* trace prompt
*
* @var string
*/
public $yyTracePrompt;
-
/**
* state names
*
* @var array
*/
public $state_name = array(1 => 'TEXT', 2 => 'SMARTY', 3 => 'LITERAL', 4 => 'DOUBLEQUOTEDSTRING', 5 => 'CHILDBODY');
-
/**
* token names
*
* @var array
*/
public $smarty_token_names = array( // Text for parser error messages
- 'IDENTITY' => '===', 'NONEIDENTITY' => '!==', 'EQUALS' => '==', 'NOTEQUALS' => '!=', 'GREATEREQUAL' => '(>=,ge)', 'LESSEQUAL' => '(<=,le)', 'GREATERTHAN' => '(>,gt)', 'LESSTHAN' => '(<,lt)', 'MOD' => '(%,mod)', 'NOT' => '(!,not)', 'LAND' => '(&&,and)', 'LOR' => '(||,or)', 'LXOR' => 'xor', 'OPENP' => '(', 'CLOSEP' => ')', 'OPENB' => '[', 'CLOSEB' => ']', 'PTR' => '->', 'APTR' => '=>', 'EQUAL' => '=', 'NUMBER' => 'number', 'UNIMATH' => '+" , "-', 'MATH' => '*" , "/" , "%', 'INCDEC' => '++" , "--', 'SPACE' => ' ', 'DOLLAR' => '$', 'SEMICOLON' => ';', 'COLON' => ':', 'DOUBLECOLON' => '::', 'AT' => '@', 'HATCH' => '#', 'QUOTE' => '"', 'BACKTICK' => '`', 'VERT' => '|', 'DOT' => '.', 'COMMA' => '","', 'ANDSYM' => '"&"', 'QMARK' => '"?"', 'ID' => 'identifier', 'TEXT' => 'text', 'FAKEPHPSTARTTAG' => 'Fake PHP start tag', 'PHPSTARTTAG' => 'PHP start tag', 'PHPENDTAG' => 'PHP end tag', 'LITERALSTART' => 'Literal start', 'LITERALEND' => 'Literal end', 'LDELSLASH' => 'closing tag', 'COMMENT' => 'comment', 'AS' => 'as', 'TO' => 'to',);
+ 'IDENTITY' => '===',
+ 'NONEIDENTITY' => '!==',
+ 'EQUALS' => '==',
+ 'NOTEQUALS' => '!=',
+ 'GREATEREQUAL' => '(>=,ge)',
+ 'LESSEQUAL' => '(<=,le)',
+ 'GREATERTHAN' => '(>,gt)',
+ 'LESSTHAN' => '(<,lt)',
+ 'MOD' => '(%,mod)',
+ 'NOT' => '(!,not)',
+ 'LAND' => '(&&,and)',
+ 'LOR' => '(||,or)',
+ 'LXOR' => 'xor',
+ 'OPENP' => '(',
+ 'CLOSEP' => ')',
+ 'OPENB' => '[',
+ 'CLOSEB' => ']',
+ 'PTR' => '->',
+ 'APTR' => '=>',
+ 'EQUAL' => '=',
+ 'NUMBER' => 'number',
+ 'UNIMATH' => '+" , "-',
+ 'MATH' => '*" , "/" , "%',
+ 'INCDEC' => '++" , "--',
+ 'SPACE' => ' ',
+ 'DOLLAR' => '$',
+ 'SEMICOLON' => ';',
+ 'COLON' => ':',
+ 'DOUBLECOLON' => '::',
+ 'AT' => '@',
+ 'HATCH' => '#',
+ 'QUOTE' => '"',
+ 'BACKTICK' => '`',
+ 'VERT' => '|',
+ 'DOT' => '.',
+ 'COMMA' => '","',
+ 'ANDSYM' => '"&"',
+ 'QMARK' => '"?"',
+ 'ID' => 'identifier',
+ 'TEXT' => 'text',
+ 'FAKEPHPSTARTTAG' => 'Fake PHP start tag',
+ 'PHPSTARTTAG' => 'PHP start tag',
+ 'PHPENDTAG' => 'PHP end tag',
+ 'LITERALSTART' => 'Literal start',
+ 'LITERALEND' => 'Literal end',
+ 'LDELSLASH' => 'closing tag',
+ 'COMMENT' => 'comment',
+ 'AS' => 'as',
+ 'TO' => 'to',
+ );
/**
* constructor
@@ -191,8 +220,8 @@ class Smarty_Internal_Templatelexer
$this->yyTracePrompt = '
';
}
+
private $_yy_state = 1;
-
private $_yy_stack = array();
public function yylex()
@@ -203,54 +232,80 @@ class Smarty_Internal_Templatelexer
public function yypushstate($state)
{
if ($this->yyTraceFILE) {
- fprintf($this->yyTraceFILE, "%sState push %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
+ fprintf($this->yyTraceFILE, "%sState push %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
}
array_push($this->_yy_stack, $this->_yy_state);
$this->_yy_state = $state;
if ($this->yyTraceFILE) {
- fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
+ fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
}
}
public function yypopstate()
{
- if ($this->yyTraceFILE) {
- fprintf($this->yyTraceFILE, "%sState pop %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
+ if ($this->yyTraceFILE) {
+ fprintf($this->yyTraceFILE, "%sState pop %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
}
- $this->_yy_state = array_pop($this->_yy_stack);
+ $this->_yy_state = array_pop($this->_yy_stack);
if ($this->yyTraceFILE) {
- fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
+ fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
}
+
}
public function yybegin($state)
{
- $this->_yy_state = $state;
+ $this->_yy_state = $state;
if ($this->yyTraceFILE) {
- fprintf($this->yyTraceFILE, "%sState set %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
+ fprintf($this->yyTraceFILE, "%sState set %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state);
}
}
+
+
public function yylex1()
{
- $tokenMap = array(1 => 0, 2 => 1, 4 => 0, 5 => 0, 6 => 0, 7 => 1, 9 => 0, 10 => 0, 11 => 0, 12 => 5, 18 => 0, 19 => 0, 20 => 0, 21 => 1, 23 => 5, 29 => 6, 36 => 5, 42 => 3, 46 => 0,);
- if ($this->counter >= strlen($this->data)) {
+ $tokenMap = array (
+ 1 => 0,
+ 2 => 1,
+ 4 => 0,
+ 5 => 0,
+ 6 => 0,
+ 7 => 1,
+ 9 => 0,
+ 10 => 0,
+ 11 => 0,
+ 12 => 5,
+ 18 => 0,
+ 19 => 0,
+ 20 => 0,
+ 21 => 1,
+ 23 => 5,
+ 29 => 6,
+ 36 => 5,
+ 42 => 3,
+ 46 => 0,
+ );
+ if ($this->counter >= strlen($this->data)) {
return false; // end of input
}
- $yy_global_pattern = "/\G(\\{\\})|\G(" . $this->ldel . "\\*([\S\s]*?)\\*" . $this->rdel . ")|\G(" . $this->ldel . "\\s*strip\\s*" . $this->rdel . ")|\G(" . $this->ldel . "\\s*\/strip\\s*" . $this->rdel . ")|\G(" . $this->ldel . "\\s*literal\\s*" . $this->rdel . ")|\G(" . $this->ldel . "\\s*(if|elseif|else if|while)\\s+)|\G(" . $this->ldel . "\\s*for\\s+)|\G(" . $this->ldel . "\\s*foreach(?![^\s]))|\G(" . $this->ldel . "\\s*setfilter\\s+)|\G((" . $this->ldel . "\\s*php\\s*(.)*?" . $this->rdel . "([\S\s]*?)" . $this->ldel . "\\s*\/php\\s*" . $this->rdel . ")|(" . $this->ldel . "\\s*[\/]?php\\s*(.)*?" . $this->rdel . "))|\G(" . $this->ldel . "\\s*\/)|\G(" . $this->ldel . "\\s*)|\G(\\s*" . $this->rdel . ")|\G(<\\?xml\\s+([\S\s]*?)\\?>)|\G(<%((('[^'\\\\]*(?:\\\\.[^'\\\\]*)*')|(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|(\/\\*[\S\s]*?\\*\/)|[\S\s])*?)%>)|\G((<\\?(?:php\\s+|=)?)((('[^'\\\\]*(?:\\\\.[^'\\\\]*)*')|(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|(\/\\*[\S\s]*?\\*\/)|[\S\s])*?)\\?>)|\G(