コード例 #1
0
 public function parse($code)
 {
     static $regex;
     if (count($this->tpl->codeFilters['pre']) > 0) {
         foreach ($this->tpl->codeFilters['pre'] as $name) {
             // @ used because of stupid notice
             // "Object of class opt_template to string conversion".
             // Whatever it means, I couldn't recognize, why PHP does such things.
             $this->code = @$name($code, $this->tpl);
         }
     }
     if ($regex == NULL) {
         if ($this->tpl->xmlsyntaxMode == 1) {
             $regex = '\\<\\!\\-\\-.+\\-\\-\\>|<\\!\\[CDATA\\[|\\]\\]>|' . $regex;
             $this->tpl->delimiters[] = '\\<(\\/?)opt\\:(.*?)()\\>';
             $this->tpl->delimiters[] = '\\<()opt\\:(.*?)(\\/)\\>';
             $this->tpl->delimiters[] = 'opt\\:put\\=\\"(.*?[^\\\\])\\"';
         }
         $regex = implode('|', $this->tpl->delimiters);
     }
     // tokenizer
     preg_match_all('#({\\*.+?\\*\\}|' . $regex . '|(.?))#si', $code, $result, PREG_PATTERN_ORDER);
     foreach ($result as $i => &$void) {
         if ($i != 0) {
             unset($result[$i]);
         }
     }
     $output = $this->tpl->captureTo . ' \'';
     if (!$this->parseRun) {
         // register output
         foreach ($this->processors as $name => $processor) {
             $processor->setOutput($output);
         }
         $this->parseRun = 1;
     } else {
         $this->parseRun = 2;
     }
     // initialize the tree
     $root = $current = new optNode(NULL, OPT_ROOT, NULL);
     $rootBlock = $currentBlock = new optBlock(NULL);
     $root->addItem($rootBlock);
     $textAssign = 0;
     $commented = 0;
     $literal = 0;
     foreach ($result[0] as $i => $item) {
         // comment usage
         if (strlen($item) > 1) {
             if (preg_match('/{\\*.+?\\*\\}/s', trim($item)) || preg_match('/\\<\\!\\-\\-.+\\-\\-\\>/s', $item)) {
                 continue;
             }
             // a command
             // literal processing
             if ($literal == 1) {
                 if ($item != '{/literal}') {
                     $item = str_replace(array('\\', '\''), array('\\\\', '\\\''), $item);
                     $text->addItem($item);
                     $textAssign = 1;
                 } else {
                     $literal = 0;
                 }
                 continue;
             }
             if ($item == '{literal}' && $literal == 0) {
                 $literal = 1;
                 continue;
             }
             $textAssign = 0;
             // grep the data
             $sortMatches = array(0 => '', 1 => '', 2 => '');
             preg_match('/' . $regex . '/', $item, $matches);
             $foundCommand = 0;
             foreach ($matches as $id => $val) {
                 $val = trim($val);
                 if ($val != '') {
                     if ($val == '/') {
                         if (!$foundCommand) {
                             $sortMatches[0] = '/';
                         } else {
                             $sortMatches[2] = '/';
                         }
                     } elseif ($id != 0) {
                         $sortMatches[1] = $val;
                         $foundCommand = 1;
                     }
                 }
             }
             if (preg_match('/^(([a-zA-Z0-9\\_]+)([= ]{1}(.*))?)$/', $sortMatches[1], $found)) {
                 // we have an instruction
                 $realname = $found[2];
                 if ($sortMatches[0] == '/') {
                     $found[2] = '/' . $found[2];
                 }
                 $found[6] = $item;
                 // general instructions
                 if (isset($this->translator[$found[2]])) {
                     switch ($this->translator[$found[2]]) {
                         case OPT_COMMAND:
                             $node = new optNode($found[2], OPT_INSTRUCTION, $current);
                             $node->addItem(new optBlock($found[2], $found, OPT_COMMAND));
                             $currentBlock->addNode($node);
                             break;
                         case OPT_MASTER:
                             $current->storeBlock($currentBlock);
                             $current = new optNode($found[2], OPT_INSTRUCTION, $current);
                             $currentBlock->addNode($current);
                             $currentBlock = new optBlock($found[2], $found, OPT_MASTER);
                             $current->addItem($currentBlock);
                             break;
                         case OPT_ALT:
                             $currentBlock = new optBlock($found[2], $found, OPT_ALT);
                             $current->addItem($currentBlock);
                             break;
                         case OPT_ENDER:
                             $currentBlock = new optBlock($found[2], $found, OPT_ENDER);
                             $current->addItem($currentBlock);
                             $current = $current->getParent();
                             if (!is_object($current)) {
                                 $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: `' . $found[2] . '`!', 113);
                             }
                             $currentBlock = $current->restoreBlock();
                             break;
                     }
                 } elseif ($realname == 'component' || isset($this->tpl->components[$realname])) {
                     if ($sortMatches[0] == '/') {
                         $currentBlock = new optBlock($found[2], $found);
                         $current->addItem($currentBlock);
                         $current = $current->getParent();
                         if (!is_object($current)) {
                             $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: `' . $found[2] . '`!', 113);
                         }
                         $currentBlock = $current->restoreBlock();
                     } else {
                         $current->storeBlock($currentBlock);
                         $current = new optNode($realname, OPT_COMPONENT, $current);
                         $currentBlock->addNode($current);
                         $currentBlock = new optBlock($realname, $found);
                         $current->addItem($currentBlock);
                     }
                 } else {
                     // here come the undefined command. The instruction programmer may do with them whatever he wants
                     // the compiler is going to recognize, what sort of command is it.
                     $ending = substr($found[2], strlen($found[2]) - 4, 4);
                     if ($sortMatches[0] == '/') {
                         // ending command, like in XML: /command
                         $currentBlock = new optBlock($found[2], $found, OPT_ENDER);
                         $current->addItem($currentBlock);
                         $current = $current->getParent();
                         if (!is_object($current)) {
                             $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: `' . $found[2] . '`!', 113);
                         }
                         $currentBlock = $current->restoreBlock();
                     } elseif ($sortMatches[2] == '/') {
                         // standalone command, like XML: command/
                         $node = new optNode($found[2], OPT_UNKNOWN, $current);
                         $node->addItem(new optBlock($found[2], $found, OPT_COMMAND));
                         $currentBlock->addNode($node);
                     } elseif ($ending == 'else') {
                         // alternative command, doesn't exist in XML: commandelse
                         $currentBlock = new optBlock($found[2], $found, OPT_ALT);
                         $current->addItem($currentBlock);
                     } else {
                         // beginning command: command
                         $current->storeBlock($currentBlock);
                         $current = new optNode($realname, OPT_UNKNOWN, $current);
                         $currentBlock->addNode($current);
                         $currentBlock = new optBlock($realname, $found, OPT_MASTER);
                         $current->addItem($currentBlock);
                     }
                 }
             } else {
                 // we have an expression
                 $node = new optNode(NULL, OPT_EXPRESSION, $current);
                 $node->addItem(new optBlock(NULL, $sortMatches[1]));
                 $currentBlock->addNode($node);
             }
         } else {
             // text item
             if ($textAssign == 0) {
                 $text = new optTextNode(NULL, OPT_TEXT, $current);
                 $currentBlock->addNode($text);
             }
             // character escaping
             if ($item == '\'') {
                 $item = '\\\'';
             }
             if ($item == '\\') {
                 $item = '\\\\';
             }
             $text->addItem($item);
             $textAssign = 1;
         }
     }
     // execute the tree
     $this->processors['generic']->nodeProcess($root);
     if ($this->parseRun < 2) {
         $code = $output . '\';';
     }
     // apply postfilters
     if (count($this->tpl->codeFilters['post']) > 0) {
         foreach ($this->tpl->codeFilters['post'] as $name) {
             $code = $name($code, $this->tpl);
         }
     }
     $this->parseRun--;
     return $code;
 }
コード例 #2
0
 public function parse($filename, $code, $master = false)
 {
     static $regex;
     static $blockRegex;
     $this->master = false;
     $this->dynamic = false;
     $this->dynamicEnabled = false;
     $this->dynamicSeg = array(0 => '');
     $this->di = 0;
     $pre = 'pre';
     if ($master) {
         $this->master = true;
         $pre = 'preMaster';
     }
     foreach ($this->tpl->filters[$pre] as $name) {
         // @ used because of stupid notice
         // "Object of class optClass to string conversion".
         // Whatever it means, I couldn't recognize, why PHP does such things.
         $code = @$name($this->tpl, $code);
     }
     $code = str_replace(array('<' . '?'), array('<?php echo \'<?\'; ?' . '>'), $code);
     if ($regex == NULL || $this->tpl->nschange) {
         $nslist = implode('|', $this->tpl->namespaces);
         $blockRegex = '\\{literal\\}|\\{\\/literal\\}|\\{php\\}|\\{\\/php\\}';
         if ($this->tpl->xmlsyntaxMode == 1) {
             $regex = '';
             $this->tpl->delimiters[] = '\\<(\\/?)(' . $nslist . ')\\:(.*?)(\\/?)\\>';
             $this->tpl->delimiters[] = '\\<()(' . $nslist . ')\\:(.*?)(\\/)\\>';
             $this->tpl->delimiters[] = '(' . $nslist . ')\\:put\\=\\"(.*?[^\\\\])\\"';
             $blockRegex = '\\<opt\\:literal\\>|\\<\\/opt\\:literal\\>|\\<opt\\:php\\>|\\<\\/opt\\:php\\>|' . $blockRegex;
         }
         $regex = str_replace('$$NS$$', $nslist, implode('|', $this->tpl->delimiters));
     }
     $this->output = '';
     // initialize the tree
     $root = $current = new optNode(NULL, OPT_ROOT, NULL);
     $rootBlock = $currentBlock = new optBlock(NULL);
     $root->addItem($rootBlock);
     $textAssign = 0;
     $commented = 0;
     $literal = false;
     $php = false;
     $textBlocks = preg_split('/(' . $blockRegex . ')/si', $code, 0, PREG_SPLIT_DELIM_CAPTURE);
     foreach ($textBlocks as $bid => $bval) {
         if (preg_match('/' . $blockRegex . '/si', $bval)) {
             // Escape the OPT namespace, if in XML Syntax mode
             if ($this->tpl->xmlsyntaxMode == 1) {
                 $bval = str_replace('opt:', '', $bval);
             }
             // Check, what we have here
             if (strpos($bval, '/literal') !== false || $bval == ']]>') {
                 $literal = false;
             } elseif (strpos($bval, 'literal') !== false || strpos($bval, 'CDATA') !== false) {
                 if ($textAssign == 0) {
                     $text = new optTextNode(NULL, OPT_TEXT, $current);
                     $currentBlock->addNode($text);
                 }
                 $textAssign = 1;
                 $literal = true;
             } elseif (strpos($bval, '/php') !== false) {
                 $php = false;
                 $text->addItem('?' . '>');
             } elseif (strpos($bval, 'php') !== false) {
                 $php = true;
                 if ($textAssign == 0) {
                     $text = new optTextNode(NULL, OPT_TEXT, $current);
                     $currentBlock->addNode($text);
                 }
                 $textAssign = 1;
                 $text->addItem('<' . '?php');
             }
         } elseif ($literal == true || $php == true) {
             // Static literal/php text
             $text->addItem($bval);
         } elseif ($literal == false && $php == false) {
             // tokenizer
             preg_match_all('#({\\*.+?\\*\\}|' . $regex . ')#si', $bval, $result, PREG_PATTERN_ORDER);
             $resolution = sizeof($result);
             $offset = 0;
             foreach ($result[0] as $i => &$item) {
                 // Copy static text
                 $id = strpos($bval, $item, $offset);
                 $staticText = substr($bval, $offset, $id - $offset);
                 if ($textAssign == 0) {
                     $text = new optTextNode(NULL, OPT_TEXT, $current);
                     $currentBlock->addNode($text);
                 }
                 $text->addItem($staticText);
                 $textAssign = 1;
                 // Move to the end of the current token
                 $offset = $id + strlen($item);
                 // Process the token
                 if (preg_match('/{\\*.+?\\*\\}/s', trim($item))) {
                     continue;
                 }
                 // an attribute
                 if ($result[8][$i] == ':') {
                     // namespace checking
                     $fakeAttribute = false;
                     if ($result[7][$i] == 'opt') {
                         $attribute = $result[9][$i];
                     } elseif (in_array($result[7][$i], $this->tpl->namespaces)) {
                         $attribute = $result[7][$i] . ':' . $result[9][$i];
                     } else {
                         $fakeAttribute = true;
                     }
                     if (!$fakeAttribute) {
                         if (isset($this->translator[$attribute])) {
                             if ($this->translator[$attribute] == OPT_ATTRIBUTE) {
                                 $node = new optNode($attribute, OPT_ATTRIBUTE, $current);
                                 $node->addItem(new optBlock($attribute, $result[10][$i]));
                                 $currentBlock->addNode($node);
                                 $textAssign = 0;
                             } else {
                                 $fakeAttribute = true;
                             }
                         } else {
                             $fakeAttribute = true;
                         }
                     }
                     if ($fakeAttribute) {
                         // text item
                         if ($textAssign == 0) {
                             $text = new optTextNode(NULL, OPT_TEXT, $current);
                             $currentBlock->addNode($text);
                         }
                         $text->addItem($item);
                         $textAssign = 1;
                     }
                     continue;
                 }
                 // a command
                 $textAssign = 0;
                 $sortMatches = array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL);
                 $foundCommand = false;
                 for ($id = 1; $id < $resolution; $id++) {
                     $val = trim($result[$id][$i]);
                     if ($val != '') {
                         if ($val[strlen($val) - 1] == ':') {
                             continue;
                         }
                         if ($val == '/') {
                             if (!$foundCommand) {
                                 $sortMatches[0] = '/';
                             } else {
                                 $sortMatches[2] = '/';
                             }
                         } elseif ($id != 1) {
                             // Namespace support
                             if (!is_null($sortMatches[1])) {
                                 if ($sortMatches[1] == 'opt') {
                                     $sortMatches[1] = $val;
                                 } else {
                                     $sortMatches[3] = $sortMatches[1];
                                     $sortMatches[1] .= ':' . $val;
                                 }
                             } else {
                                 $sortMatches[3] = 'opt';
                                 $sortMatches[1] = $val;
                             }
                             $foundCommand = true;
                         }
                     }
                 }
                 $sortMatches[1] = $this->parseEntities($sortMatches[1]);
                 if (preg_match('/^(([a-zA-Z0-9\\_\\:]+)([= \\t]{1}(.*))?)$/s', $sortMatches[1], $found)) {
                     // we have an instruction
                     $realname = $found[2];
                     if ($sortMatches[0] == '/') {
                         $found[2] = '/' . $found[2];
                     }
                     $found[6] = $item;
                     // general instructions
                     if (isset($this->translator[$found[2]])) {
                         switch ($this->translator[$found[2]]) {
                             case OPT_COMMAND:
                                 $node = new optNode($found[2], OPT_INSTRUCTION, $current);
                                 $node->addItem(new optBlock($found[2], $found, OPT_COMMAND));
                                 $currentBlock->addNode($node);
                                 break;
                             case OPT_MASTER:
                                 $current->storeBlock($currentBlock);
                                 $current = new optNode($found[2], OPT_INSTRUCTION, $current);
                                 $currentBlock->addNode($current);
                                 $currentBlock = new optBlock($found[2], $found, OPT_MASTER);
                                 $current->addItem($currentBlock, $this->tpl);
                                 break;
                             case OPT_ALT:
                                 $currentBlock = new optBlock($found[2], $found, OPT_ALT);
                                 $current->addItem($currentBlock);
                                 break;
                             case OPT_ENDER:
                                 $currentBlock = new optBlock($found[2], $found, OPT_ENDER);
                                 $current->addItem($currentBlock, $this->tpl);
                                 $current = $current->getParent();
                                 if (!is_object($current)) {
                                     $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '".', OPT_E_ENCLOSING_STATEMENT);
                                 }
                                 $currentBlock = $current->restoreBlock();
                                 break;
                         }
                     } elseif ($realname == 'component' || isset($this->tpl->components[$realname])) {
                         if ($sortMatches[0] == '/') {
                             $currentBlock = new optBlock($found[2], $found);
                             $current->addItem($currentBlock, $this->tpl);
                             $current = $current->getParent();
                             if (!is_object($current)) {
                                 $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '".', OPT_E_ENCLOSING_STATEMENT);
                             }
                             $currentBlock = $current->restoreBlock();
                         } else {
                             $current->storeBlock($currentBlock);
                             $current = new optNode($realname, OPT_COMPONENT, $current);
                             $currentBlock->addNode($current);
                             $currentBlock = new optBlock($realname, $found);
                             $current->addItem($currentBlock, $this->tpl);
                         }
                     } else {
                         // here comes the undefined command. The instruction programmer may do with them whatever he wants
                         // the compiler is going to recognize, what sort of command is it. But first - a small check. The
                         // command must belong to the "opt" namespace. Otherwise it will be simply displayed.
                         if ($sortMatches[3] == 'opt' || in_array($sortMatches[3], $this->tpl->namespaces)) {
                             $ending = substr($found[2], strlen($found[2]) - 4, 4);
                             if ($sortMatches[0] == '/') {
                                 // ending command, like in XML: /command
                                 $currentBlock = new optBlock($found[2], $found, OPT_ENDER);
                                 $current->addItem($currentBlock, $this->tpl);
                                 $current = $current->getParent();
                                 if (!$current instanceof ioptNode) {
                                     $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '"!', OPT_E_ENCLOSING_STATEMENT);
                                 }
                                 $currentBlock = $current->restoreBlock();
                             } elseif ($sortMatches[2] == '/') {
                                 // standalone command, like XML: command/
                                 $node = new optNode($found[2], OPT_UNKNOWN, $current);
                                 $node->addItem(new optBlock($found[2], $found, OPT_COMMAND), $this->tpl);
                                 $currentBlock->addNode($node);
                             } elseif ($ending == 'else') {
                                 // alternative command, doesn't exist in XML: commandelse
                                 $currentBlock = new optBlock($found[2], $found, OPT_ALT);
                                 $current->addItem($currentBlock, $this->tpl);
                             } else {
                                 // beginning command: command
                                 $current->storeBlock($currentBlock);
                                 $current = new optNode($realname, OPT_UNKNOWN, $current);
                                 $currentBlock->addNode($current);
                                 $currentBlock = new optBlock($realname, $found, OPT_MASTER);
                                 $current->addItem($currentBlock, $this->tpl);
                             }
                         } else {
                             // Display the undefined command that doesn't belong to the "opt" namespace
                             if ($textAssign == 0) {
                                 $text = new optTextNode(NULL, OPT_TEXT, $current);
                                 $currentBlock->addNode($text);
                             }
                             $text->addItem($item);
                             $textAssign = 1;
                         }
                     }
                 } else {
                     // we have an expression
                     $node = new optNode(NULL, OPT_EXPRESSION, $current);
                     $node->addItem(new optBlock(NULL, $sortMatches[1]));
                     $currentBlock->addNode($node);
                 }
             }
             // No tokens left, copy just the rest of the $bval
             if ($textAssign == 0) {
                 $text = new optTextNode(NULL, OPT_TEXT, $current);
                 $currentBlock->addNode($text);
             }
             $text->addItem(substr($bval, $offset, strlen($bval) - $offset));
             $textAssign = 1;
         }
     }
     if ($current->getType() != OPT_ROOT) {
         $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "NULL"!', OPT_E_ENCLOSING_STATEMENT);
     }
     // execute the tree
     $this->processors['generic']->nodeProcess($root);
     $this->output = str_replace('?><' . '?php', '', $this->output);
     if (!$master) {
         // apply postfilters
         foreach ($this->tpl->filters['post'] as $name) {
             $this->output = $name($this->tpl, $this->output);
         }
         if (!is_null($filename)) {
             if (!is_writeable($this->tpl->compile)) {
                 $this->tpl->error(E_USER_ERROR, $this->tpl->compile . ' is not a writeable directory.', OPT_E_WRITEABLE);
             }
             file_put_contents($filename, $this->output);
             if ($this->dynamicEnabled) {
                 file_put_contents($filename . '.dyn', serialize($this->dynamicSeg));
             }
         }
         return $this->output;
     }
     return true;
 }
コード例 #3
0
 public function parse($filename, $code)
 {
     static $regex;
     static $blockRegex;
     $this->dynamic = false;
     $this->dynamicEnabled = false;
     $this->dynamicSeg = array(0 => '');
     $this->di = 0;
     foreach ($this->tpl->filters['pre'] as $name) {
         // @ used because of stupid notice
         // "Object of class opt_template to string conversion".
         // Whatever it means, I couldn't recognize, why PHP does such things.
         $code = @$name($this->tpl, $code);
     }
     $code = str_replace(array('<' . '?'), array('<?php echo \'<?\'; ?' . '>'), $code);
     if ($regex == NULL) {
         $blockRegex = '\\{literal\\}|\\{\\/literal\\}|\\{php\\}|\\{\\/php\\}';
         if ($this->tpl->xmlsyntaxMode == 1) {
             $regex = '';
             $this->tpl->delimiters[] = '\\<(\\/?)opt\\:(.*?)(\\/?)\\>';
             $this->tpl->delimiters[] = '\\<()opt\\:(.*?)(\\/)\\>';
             $this->tpl->delimiters[] = 'opt\\:put\\=\\"(.*?[^\\\\])\\"';
             $blockRegex = '\\<opt\\:literal\\>|\\<\\/opt\\:literal\\>|\\<opt\\:php\\>|\\<\\/opt\\:php\\>|' . $blockRegex;
         }
         $regex = implode('|', $this->tpl->delimiters);
     }
     $this->output = '';
     // initialize the tree
     $root = $current = new optNode(NULL, OPT_ROOT, NULL);
     $rootBlock = $currentBlock = new optBlock(NULL);
     $root->addItem($rootBlock);
     $textAssign = 0;
     $commented = 0;
     $literal = false;
     $php = false;
     $textBlocks = preg_split('/(' . $blockRegex . ')/ms', $code, 0, PREG_SPLIT_DELIM_CAPTURE);
     foreach ($textBlocks as $bid => $bval) {
         if (preg_match('/' . $blockRegex . '/ms', $bval)) {
             // Escape the OPT namespace, if in XML Syntax mode
             if ($this->tpl->xmlsyntaxMode == 1) {
                 $bval = str_replace('opt:', '', $bval);
             }
             // Check, what we have here
             if (strpos($bval, '/literal') !== false || $bval == ']]>') {
                 $literal = false;
             } elseif (strpos($bval, 'literal') !== false || strpos($bval, 'CDATA') !== false) {
                 if ($textAssign == 0) {
                     $text = new optTextNode(NULL, OPT_TEXT, $current);
                     $currentBlock->addNode($text);
                 }
                 $textAssign = 1;
                 $literal = true;
             } elseif (strpos($bval, '/php') !== false) {
                 $php = false;
                 $text->addItem('?' . '>');
             } elseif (strpos($bval, 'php') !== false) {
                 $php = true;
                 if ($textAssign == 0) {
                     $text = new optTextNode(NULL, OPT_TEXT, $current);
                     $currentBlock->addNode($text);
                 }
                 $textAssign = 1;
                 $text->addItem('<' . '?php');
             }
         } elseif ($literal == true || $php == true) {
             // Static literal/php text
             $text->addItem($bval);
         } elseif ($literal == false && $php == false) {
             // tokenizer
             preg_match_all('#({\\*.+?\\*\\}|' . $regex . '|(.?))#msi', $bval, $result, PREG_PATTERN_ORDER);
             foreach ($result as $i => &$void) {
                 if ($i != 0) {
                     unset($result[$i]);
                 }
             }
             foreach ($result[0] as $i => $item) {
                 // comment usage
                 if (strlen($item) > 1) {
                     if (preg_match('/{\\*.+?\\*\\}/ms', trim($item))) {
                         continue;
                     }
                     // a command
                     $textAssign = 0;
                     // grep the data
                     $sortMatches = array(0 => '', 1 => '', 2 => '');
                     preg_match('/' . $regex . '/ms', $item, $matches);
                     $foundCommand = false;
                     foreach ($matches as $id => $val) {
                         $val = trim($val);
                         if ($val != '') {
                             if ($val == '/') {
                                 if (!$foundCommand) {
                                     $sortMatches[0] = '/';
                                 } else {
                                     $sortMatches[2] = '/';
                                 }
                             } elseif ($id != 0) {
                                 $sortMatches[1] = $val;
                                 $foundCommand = true;
                             }
                         }
                     }
                     $sortMatches[1] = $this->parseEntities($sortMatches[1]);
                     if (preg_match('/^(([a-zA-Z0-9\\_]+)([= ]{1}(.*))?)$/ms', $sortMatches[1], $found)) {
                         // we have an instruction
                         $realname = $found[2];
                         if ($sortMatches[0] == '/') {
                             $found[2] = '/' . $found[2];
                         }
                         $found[6] = $item;
                         // general instructions
                         if (isset($this->translator[$found[2]])) {
                             switch ($this->translator[$found[2]]) {
                                 case OPT_COMMAND:
                                     $node = new optNode($found[2], OPT_INSTRUCTION, $current);
                                     $node->addItem(new optBlock($found[2], $found, OPT_COMMAND));
                                     $currentBlock->addNode($node);
                                     break;
                                 case OPT_MASTER:
                                     $current->storeBlock($currentBlock);
                                     $current = new optNode($found[2], OPT_INSTRUCTION, $current);
                                     $currentBlock->addNode($current);
                                     $currentBlock = new optBlock($found[2], $found, OPT_MASTER);
                                     $current->addItem($currentBlock, $this->tpl);
                                     break;
                                 case OPT_ALT:
                                     $currentBlock = new optBlock($found[2], $found, OPT_ALT);
                                     $current->addItem($currentBlock);
                                     break;
                                 case OPT_ENDER:
                                     $currentBlock = new optBlock($found[2], $found, OPT_ENDER);
                                     $current->addItem($currentBlock, $this->tpl);
                                     $current = $current->getParent();
                                     if (!is_object($current)) {
                                         $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '".', OPT_E_ENCLOSING_STATEMENT);
                                     }
                                     $currentBlock = $current->restoreBlock();
                                     break;
                             }
                         } elseif ($realname == 'component' || isset($this->tpl->components[$realname])) {
                             if ($sortMatches[0] == '/') {
                                 $currentBlock = new optBlock($found[2], $found);
                                 $current->addItem($currentBlock, $this->tpl);
                                 $current = $current->getParent();
                                 if (!is_object($current)) {
                                     $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '".', OPT_E_ENCLOSING_STATEMENT);
                                 }
                                 $currentBlock = $current->restoreBlock();
                             } else {
                                 $current->storeBlock($currentBlock);
                                 $current = new optNode($realname, OPT_COMPONENT, $current);
                                 $currentBlock->addNode($current);
                                 $currentBlock = new optBlock($realname, $found);
                                 $current->addItem($currentBlock, $this->tpl);
                             }
                         } else {
                             // here comes the undefined command. The instruction programmer may do with them whatever he wants
                             // the compiler is going to recognize, what sort of command is it.
                             $ending = substr($found[2], strlen($found[2]) - 4, 4);
                             if ($sortMatches[0] == '/') {
                                 // ending command, like in XML: /command
                                 $currentBlock = new optBlock($found[2], $found, OPT_ENDER);
                                 $current->addItem($currentBlock, $this->tpl);
                                 $current = $current->getParent();
                                 if (!$current instanceof ioptNode) {
                                     $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '"!', OPT_E_ENCLOSING_STATEMENT);
                                 }
                                 $currentBlock = $current->restoreBlock();
                             } elseif ($sortMatches[2] == '/') {
                                 // standalone command, like XML: command/
                                 $node = new optNode($found[2], OPT_UNKNOWN, $current);
                                 $node->addItem(new optBlock($found[2], $found, OPT_COMMAND), $this->tpl);
                                 $currentBlock->addNode($node);
                             } elseif ($ending == 'else') {
                                 // alternative command, doesn't exist in XML: commandelse
                                 $currentBlock = new optBlock($found[2], $found, OPT_ALT);
                                 $current->addItem($currentBlock, $this->tpl);
                             } else {
                                 // beginning command: command
                                 $current->storeBlock($currentBlock);
                                 $current = new optNode($realname, OPT_UNKNOWN, $current);
                                 $currentBlock->addNode($current);
                                 $currentBlock = new optBlock($realname, $found, OPT_MASTER);
                                 $current->addItem($currentBlock, $this->tpl);
                             }
                         }
                     } else {
                         // we have an expression
                         $node = new optNode(NULL, OPT_EXPRESSION, $current);
                         $node->addItem(new optBlock(NULL, $sortMatches[1]));
                         $currentBlock->addNode($node);
                     }
                 } else {
                     // text item
                     if ($textAssign == 0) {
                         $text = new optTextNode(NULL, OPT_TEXT, $current);
                         $currentBlock->addNode($text);
                     }
                     $text->addItem($item);
                     $textAssign = 1;
                 }
             }
         }
     }
     // execute the tree
     $this->processors['generic']->nodeProcess($root);
     // apply postfilters
     foreach ($this->tpl->filters['post'] as $name) {
         $this->output = $name($this->tpl, $this->output);
     }
     if (!is_null($filename)) {
         if (!is_writeable($this->tpl->compile)) {
             $this->tpl->error(E_USER_ERROR, $this->tpl->compile . ' is not a writeable directory.', OPT_E_WRITEABLE);
         }
         file_put_contents($filename, $this->output);
         if ($this->dynamicEnabled) {
             file_put_contents($filename . '.dyn', serialize($this->dynamicSeg));
         }
     }
     return $this->output;
 }