rearrange things into distribution and development directories

This commit is contained in:
monte.ohrt
2009-03-22 16:09:05 +00:00
commit dcaa96a9f8
189 changed files with 32300 additions and 0 deletions

22
demo/configs/test.conf Normal file
View File

@@ -0,0 +1,22 @@
title = Welcome to Smarty!
cutoff_size = 40
bold = false
pageTitle = "This is mine"
bodyBgColor = '#eeeeee'
tableBorderSize = 3
tableBgColor = "#bbbbbb"
rowBgColor = #cccccc
Intro = """This is a value that spans more
than one line. you must enclose
it in triple quotes."""
Quote1 = """'value should contain a
sigle quote'"""
Quote2 = """ "value should contain a " double quote" """
[setup]
bold = true
[params]

48
demo/index.php Normal file
View File

@@ -0,0 +1,48 @@
<?php
/**
* Test script for PHP template
* @author Monte Ohrt <monte at ohrt dot com>
* @package SmartyTestScripts
*/
require('./libs/Smarty.class.php');
ini_set('short_open_tag','1');
class Person
{
private $m_szName;
private $m_iAge;
public function setName($szName)
{
$this->m_szName = $szName;
return $this; // We now return $this (the Person)
}
public function setAge($iAge)
{
$this->m_iAge = $iAge;
return $this; // Again, return our Person
}
public function introduce()
{
return 'Hello my name is '.$this->m_szName.' and I am '.$this->m_iAge.' years old.';
}
}
$smarty = new Smarty();
$smarty->force_compile = false;
$smarty->caching = false;
$smarty->caching_lifetime = 10;
$smarty->assign('foo','<bar>');
$person = new Person;
$smarty->assign('person',$person);
$smarty->assign('array',array('a'=>array('aa'=>'This is a long string'),'b'=>2));
$smarty->display('php:index_view.php');
?>

View File

@@ -0,0 +1,5 @@
This is the header
gee is {$gee} foo is {$foo}
done with header

View File

@@ -0,0 +1,3 @@
Include file
<br>{assign var=inc value='assign include'}{$inc}

10
demo/templates/index.tpl Normal file
View File

@@ -0,0 +1,10 @@
This is an example of a compiled template.
$foo = {$foo}
$foo[0] = {$foo[0]}
$foo[1] = {$foo[1]}
$foo[2] = {$foo[2]}
function:
End Test

View File

@@ -0,0 +1,11 @@
PHP file test
$foo is <?=$foo?>
<br> Test modifier chaining
<?=$foo->trim()->escape('html')?>
<br>Test objects
<?=$person->setName('Paul')->setAge(39)->introduce()->trim()->truncate(10)?>
<br>Arrays
<?=$array['a']['aa']->truncate(5)?><?=$array['b']?>
<br>Function
<?=$_f->trim($array['a']['aa'])->truncate(10)?>
DONE

View File

@@ -0,0 +1,2 @@
<br>This is from nocache_inc.tpl
<br>cached time is {time()}

View File

@@ -0,0 +1,3 @@
Test debug
{debug}

View File

@@ -0,0 +1,5 @@
Test of if tags <br>
{foreach item=value from=$values}
Value of {$value} is {if $value<10} less then 10 {elseif ($value GT 100) AND ($value <= 500)} something between 100 and 500 {else} somthing else {/if}<br>
{/foreach}

View File

@@ -0,0 +1,25 @@
Test of { include } and local/global variable scope
<br>the original value of $foo = {$foo}
<br>
{assign var=foo2 value='yzx'}
<br> foo2 before { include } = {$foo2}
{include file='test_inc2.tpl'}
<br>
<br>Here we are back in test_inc.tpl
<br>$foo has its old value = {$foo}
<br>this is $foo2 a global variable created in test_inc2.tpl = {$foo2}
<br>{if isset($foo3)} $foo3 must be unknow here {/if}
<br>
<br>Test include with parent scope
{include file='test_inc2.tpl' scope='parent'}
<br>Here we are back in test_inc.tpl
<br>$foo has its new value = {$foo}
<br>this is $foo2 a global variable created in test_inc2.tpl = {$foo2}
<br>this is $foo3 a normal variable created in test_inc2.tpl = {$foo3}
<br>
<br>Test include with root scope
{include file='test_inc2.tpl' scope='root'}
<br>Here we are back in test_inc.tpl
<br>$foo has its new value = {$foo}
<br>this is $foo2 a global variable created in test_inc2.tpl = {$foo2}
<br>this is $foo3 a normal variable created in test_inc2.tpl = {$foo3}

View File

@@ -0,0 +1,6 @@
<br>Here starts test_inc2.tpl
<br>$foo in test_inc2 before changing = {$foo}
{assign var=foo value="bah"}
<br>$foo in test_inc2 after changing = {$foo}
{assign var=foo2 value="bla" global=true}
{assign var=foo3 value="foo3 was set"}

View File

@@ -0,0 +1,3 @@
Test of { insert }
<br>{insert name='test' foo='bar'}
<br>insert with assign {insert name='test' foo='bar' assign=var}{$var}

View File

@@ -0,0 +1,11 @@
Test caching and nocache attribute
<br>cached time is {time()}
<br>nocached time by '{time() nocache=true}' {time() nocache=true}
<br>
<br>calling '{include file="nocache_inc.tpl" caching_lifetime=25}' {include file="nocache_inc.tpl" caching_lifetime=25}
<br>
<br>calling '{include file="nocache_inc.tpl" nocache=true}' {include file="nocache_inc.tpl" nocache=true}
{nocache}
{assign var=a value=1}
<br>{if $a < 5}{$a|truncate} lt 5{else}a ge 5{/if}
{/nocache}

View File

@@ -0,0 +1,9 @@
Test caching and nocache attribute
<br>cached time is {$t1}
<br>nocached time is {$t2}
<br>
{$t1+$t1} {$t1+$t2}
<br>
{nocache}
{for $i=0;$i<10;$i++}{$i}{/for}
{/nocache}

View File

@@ -0,0 +1,6 @@
Test methode chaining
{assign var=x value=33}
<br>{assign var=x2 value=10}{$person->object->setName('peter')->setAge($x+4)->introduce()}
<br>{$person->object->setAge($x+$x2)->setName('paul')->introduce()}

View File

@@ -0,0 +1,5 @@
Test registered object
<br>{/test->hello}
<br>{/test->hello p1=1 p2=2}

View File

@@ -0,0 +1,7 @@
Input form for parser testing <BR>
<form name="Testparser" action="test_parser.php" method="post">
<strong>Template input</strong>
<textarea name="template" rows="10" cols="60">{$template|escape}</textarea>
<input name="Update" type="submit" value="Update">
</form >

View File

@@ -0,0 +1,7 @@
Test of function plugin
{nocache}
{counter assign=foo start=10 skip=5}
<br>{$foo}
{counter}
<br>{$foo}
{/nocache}

View File

@@ -0,0 +1,7 @@
Test of function plugin
{nocache}
{counter assign=foo start=10 skip=5}
<br>{$foo}
{counter}
<br>{$foo}
{/nocache}

View File

@@ -0,0 +1,159 @@
<pre>SMARTY SMOKE TEST
VARIABLE TESTS:
$foo is {$foo}
$baz[1] is {$baz[1]}
$blah['b'] is {$blah['b']}
$blah[$baz[1]] is {$blah[$baz[1]]}
$foo.$baz[1] is {$foo.$baz[1]}
$foo.$foo is {$foo.$foo}
{"foo"}
OBJECT TESTS:
$myobj->foo is {$myobj->foo}
$myobj->test is {$myobj->test}
$myobj->test() is {$myobj->test()}
$myobj->test(1) is {$myobj->test(1)}
$myobj->test(1,'two') is {$myobj->test(1,'two')}
$myobj->test(count($baz)) is {$myobj->test(count($baz))}
$myobj->test($myobj->test(count($baz))) is {$myobj->test($myobj->test(count($baz)))}
$myobj->test($foo|escape) is {$myobj->test($foo|escape)}
PHP TESTS:
COMMENT TESTS:
{* this is a comment *}
{* another $foo comment *}
{* another <?=$foo?> comment *}
{* multi line
comment *}
{* /* foo */ *}
A{* comment *}B
C
D{* comment *}
{* comment *}E
F
G{* multi
line *}H
I{* multi
line *}
J
ASSIGN:
A
{assign var=zoo value="blah"}
B
C{assign var=zoo value="blah"}D
E{assign var=zoo value="blah"}
F
G
{assign var=zoo value="blah"}H
{assign var=zoo value="joe{$myobj->test(1)}bar"}
zoo is {$zoo}
SPACING TESTS:
{$foo}
{$foo}{$foo}
A{$foo}
A{$foo}B
{$foo}B
IF TESTS:
{if $foo eq "baz"}
IS BAZ
{elseif $foo == "lala"}
IS LALA
{else}
IS NONE
{/if}
{if $myint+5 EQ 9}
IS NINE
{else}
IS NOT NINE
{/if}
{if $myint + 5 eq 9}
IS NINE
{else}
IS NOT NINE
{/if}
{if count($baz)-2 eq 1}
IS ONE
{else}
IS NOT ONE
{/if}
{if $foo.$foo2 eq "barbar2"}
IS BARBAR2
{else}
IS NOT BARBAR2
{/if}
{if $not_logged}
NOT LOGGED
{/if}
{if "joe{$myobj->test(1)}bar"}
FOO
{/if}
TEST INCLUDE:
{include file="header.tpl" gee="joe"}
{include file="header.tpl" gee="joe $foo bar"}
{include file="header.tpl" gee="joe{$foo}bar"}
{include file="header.tpl" gee="joe{$foo.$foo}bar"}
{include file="header.tpl" gee="joe{$myobj->test(1)}bar"}
{include file=$includeme}
{include file=$includeme gee="joe"}
{include file="{$top}.tpl"}
JAVSCRIPT TEST
<script language="javascript">
function sayhi()
{
alert('hi there!');
}
function foobar() { alert('foobar'); }
</script>
MATH TESTS:
$one+2 is {$one+2}
$one + 2 - $one is {$one + 2 - $one}
$one*$one is {$one*$one}
$one/$one is {$one/$one}
abs(-$one) is {abs(-$one)}
$footest is {$footest}
FOREACH TESTS:
{foreach from=$blah key="idx" item="val"}
$idx/$val is {$idx}/{$val}
{/foreach}
TEST FINISHED
</pre>

423
libs/Smarty.class.php Normal file
View File

@@ -0,0 +1,423 @@
<?php
/**
* Project: Smarty: the PHP compiling template engine
* File: Smarty.class.php
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* For questions, help, comments, discussion, etc., please join the
* Smarty mailing list. Send a blank e-mail to
* smarty-discussion-subscribe@googlegroups.com
*
* @link http://www.smarty.net/
* @copyright 2008 New Digital Group, Inc.
* @author Monte Ohrt <monte at ohrt dot com>
* @author Uwe Tews
* @package Smarty
* @version 3.0-alpha1
*/
/**
* set SMARTY_DIR to absolute path to Smarty library files.
* if not defined, include_path will be used. Sets SMARTY_DIR only if user
* application has not already defined it.
*/
if (!defined('SMARTY_DIR')) {
define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR);
}
/**
* load required base class for creation of the smarty object
*/
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'sysplugins' . DIRECTORY_SEPARATOR . 'internal.templatebase.php');
/**
* This is the main Smarty class
*/
class Smarty extends Smarty_Internal_TemplateBase {
// smarty version
static $_version = 'Smarty3Alpha';
// class used for templates
public $template_class = 'Smarty_Internal_Template';
// display error on not assigned variabled
static $error_unassigned = false;
// template directory
public $template_dir = null;
// compile directory
public $compile_dir = null;
// plugins directory
public $plugins_dir = null;
// cache directory
public $cache_dir = null;
// config directory
public $config_dir = null;
// force template compiling?
public $force_compile = false;
// use sub dirs for compiled/cached files?
public $use_sub_dirs = false;
// php file extention
public $php_ext = '.php';
// compile_error?
public $compile_error = false;
// caching enabled
public $caching = false;
// caching lifetime
public $caching_lifetime = 0;
// cache_id
public $cache_id = null;
// compile_id
public $compile_id = null;
// template delimiters
public $left_delimiter = "{";
public $right_delimiter = "}";
// security
public $security = false;
public $security_policy = null;
public $security_handler = null;
public $direct_access_security = true;
// debug mode
public $debugging = false;
public $debugging_ctrl = 'URL';
public $smarty_debug_id = 'SMARTY_DEBUG';
public $request_use_auto_globals = true;
public $debug_tpl = null;
// When set, smarty does uses this value as error_reporting-level.
public $error_reporting = null;
// config var settings
public $config_overwrite = true; //Controls whether variables with the same name overwrite each other.
public $config_booleanize = true; //Controls whether config values of on/true/yes and off/false/no get converted to boolean
public $config_read_hidden = true; //Controls whether hidden config sections/vars are read from the file.
// config vars
public $config_vars = array();
// assigned tpl vars
public $tpl_vars = array();
// assigned global tpl vars
public $global_tpl_vars = array();
// dummy parent object
public $parent = null;
// system plugins directory
private $sysplugins_dir = null;
// resource type used if none given
public $default_resource_type = 'file';
// charset of template
public $resource_char_set = 'UTF-8';
// caching type
public $default_caching_type = 'file';
// internal cache resource types
public $cache_resorce_types = array('file');
// config type
public $default_config_type = 'file';
// class used for cacher
public $cacher_class = 'Smarty_Internal_Cacher_InlineCode';
// exception handler: set null to disable
public $exception_handler = array('SmartyException', 'getStaticException');
// cached template objects
static $template_objects = null;
// autoload filter
public $autoload_filters = array();
// check If-Modified-Since headers
public $cache_modified_check = false;
// registered plugins
public $registered_plugins = array();
// plugin search order
public $plugin_search_order = array('function', 'block', 'compiler', 'class');
// plugin handler object
public $plugin_handler = null;
// registered objects
public $registered_objects = array();
// registered filters
public $registered_filters = array();
// filter handler
public $filter_handler = null;
// cache resorce objects
public $cache_resource_objects = array();
// write file object
public $write_file_object = null;
// global smarty vars
public $_smarty_vars = array();
// start time for execution time calculation
public $start_time = 0;
/**
* Class constructor, initializes basic smarty properties
*/
public function __construct()
{
mb_internal_encoding($this->resource_char_set);
$this->start_time = $this->_get_time();
// set exception handler
if (!empty($this->exception_handler))
set_exception_handler($this->exception_handler);
// set default dirs
$this->template_dir = '.' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR;
$this->compile_dir = '.' . DIRECTORY_SEPARATOR . 'templates_c' . DIRECTORY_SEPARATOR;
$this->plugins_dir = array(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR);
$this->cache_dir = '.' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR;
$this->config_dir = '.' . DIRECTORY_SEPARATOR . 'configs' . DIRECTORY_SEPARATOR;
$this->sysplugins_dir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'sysplugins' . DIRECTORY_SEPARATOR;
// set instance object
self::instance($this);
// load base plugins
$this->loadPlugin('Smarty_Internal_Base');
$this->loadPlugin('Smarty_Internal_PluginBase');
$this->loadPlugin($this->template_class);
$this->loadPlugin('Smarty_Internal_Plugin_Handler');
$this->plugin_handler = new Smarty_Internal_Plugin_Handler;
if (!$this->debugging && $this->debugging_ctrl == 'URL') {
$_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'];
if (false !== strpos($_query_string, $this->smarty_debug_id)) {
if (false !== strpos($_query_string, $this->smarty_debug_id . '=on')) {
// enable debugging for this browser session
setcookie('SMARTY_DEBUG', true);
$this->debugging = true;
} elseif (false !== strpos($_query_string, $this->smarty_debug_id . '=off')) {
// disable debugging for this browser session
setcookie('SMARTY_DEBUG', false);
$this->debugging = false;
} else {
// enable debugging for this page
$this->debugging = true;
}
} else {
if ($this->request_use_auto_globals && isset($_COOKIE['SMARTY_DEBUG'])) {
$this->debugging = true;
} elseif (!$this->request_use_auto_globals && isset($GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG'])) {
$this->debugging = true;
}
}
}
}
/**
* Class destructor
*/
public function __destruct()
{
// restore to previous exception handler, if any
if (!empty($this->exception_handler))
restore_exception_handler();
}
/**
* Sets a static instance of the smarty object. Retrieve with:
* $smarty = Smarty::instance();
*
* @param object $new_instance the Smarty object when setting
* @return object reference to Smarty object
*/
public static function &instance($new_instance = null)
{
static $instance = null;
if (isset($new_instance) && is_object($new_instance))
$instance = $new_instance;
return $instance;
}
/**
* fetches a rendered Smarty template
*
* @param string $template the resource handle of the template file or template object
* @param object $ |null $parent next higher level of Smarty variables
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @return string rendered template output
*/
public function fetch($template, $parent = null, $cache_id = null, $compile_id = null)
{
if ($parent === null) {
// get default Smarty data object
$parent = $this;
}
// create template object if necessary
($template instanceof $this->template_class)? $_template = $template :
$_template = $this->createTemplate ($template, $parent , $cache_id, $compile_id);
// $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting)
// ? $this->error_reporting : error_reporting() &~E_NOTICE);
// return redered template
$_output = $_template->getRenderedTemplate();
$_template->rendered_content = null;
// error_reporting($_smarty_old_error_level);
return $_output;
}
/**
* displays a Smarty template
*
* @param string $ |object $template the resource handle of the template file or template object
* @param object $parent next higher level of Smarty variables
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
*/
public function display($template, $parent = null, $cache_id = null, $compile_id = null)
{
// display template
echo $this->fetch ($template, $parent , $cache_id, $compile_id);
// debug output?
if ($this->debugging) {
$this->loadPlugin('Smarty_Internal_Debug');
Smarty_Internal_Debug::display_debug();
}
return true;
}
/**
* test if cache i valid
*
* @param string $ |object $template the resource handle of the template file or template object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @return boolean cache status
*/
public function is_cached($template, $cache_id = null, $compile_id = null)
{
if (!($template instanceof $this->template_class)) {
$template = $this->createTemplate ($template, $this, $cache_id, $compile_id);
}
// return cache status of template
return $template->isCached();
}
/**
* Load the plugin with securty definition and enables security
*
* @param string $security_policy plugin to load
*/
public function enableSecurity($security_policy = 'Smarty_SecurityPolicy_Default')
{
if ($this->loadPlugin($security_policy)) {
if (!class_exists('Smarty_Security_Policy')) {
throw new Exception("Security policy must define class 'Smarty_Security_Policy'");
}
$this->security_policy = new Smarty_Security_Policy();
$this->loadPlugin('Smarty_Internal_Security_Handler');
$this->security_handler = new Smarty_Internal_Security_Handler();
$this->security = true;
} else {
throw new Exception("Security policy {$security_definition} not found");
}
}
/**
* Takes unknown classes and loads plugin files for them
* class name format: Smarty_PluginType_PluginName
* plugin filename format: plugintype.pluginname.php
*
* @param string $plugin_name class plugin name to load
* @return boolean
*/
public function loadPlugin($plugin_name)
{
// if class exists, exit silently (already loaded)
if (class_exists($plugin_name, false))
return true;
// if callable as function, exit silently (already loaded)
if (is_callable($plugin_name))
return true;
// Plugin name is expected to be: Smarty_[Type]_[Name]
$plugin_name = strtolower($plugin_name);
$name_parts = explode('_', $plugin_name, 3);
// class name must have three parts to be valid plugin
if (count($name_parts) < 3 || $name_parts[0] !== 'smarty') {
throw new Exception("plugin {$plugin_name} is not a valid name format");
return false;
}
// plugin filename is expected to be: [type].[name].php
$plugin_filename = "{$name_parts[1]}.{$name_parts[2]}{$this->php_ext}";
// if type is "internal", get plugin from sysplugins
if ($name_parts[1] == 'internal') {
if (file_exists($this->sysplugins_dir . $plugin_filename)) {
require_once($this->sysplugins_dir . $plugin_filename);
return true;
} else {
return false;
}
}
// loop through plugin dirs and find the plugin
foreach((array)$this->plugins_dir as $plugin_dir) {
if (file_exists($plugin_dir . $plugin_filename)) {
require_once($plugin_dir . $plugin_filename);
return true;
}
}
// no plugin loaded
return false;
}
/**
* Sets the exception handler for Smarty.
*
* @param mixed $handler function name or array with object/method names
* @return string previous exception handler
*/
public function setExceptionHandler($handler)
{
$this->exception_handler = $handler;
return set_exception_handler($handler);
}
/**
* Takes unknown class methods and lazy loads sysplugin files for them
* class name format: Smarty_Method_MethodName
* plugin filename format: method.methodname.php
*
* @param string $name unknown methode name
* @param array $args aurgument array
*/
public function __call($name, $args)
{
$class_name = "Smarty_Method_{$name}";
if (!class_exists($class_name, false)) {
$plugin_filename = strtolower('method.' . $name . $this->php_ext);
if (!file_exists($this->sysplugins_dir . $plugin_filename)) {
throw new Exception("Sysplugin file " . $plugin_filename . " does not exist");
die();
}
require_once($this->sysplugins_dir . $plugin_filename);
if (!class_exists($class_name, false)) {
throw new Exception ("Sysplugin file " . $plugin_filename . " does not define class " . $class_name);
die();
}
}
$method = new $class_name;
return call_user_func_array(array($method, 'execute'), $args);
}
}
/**
* Smarty Exception Handler
*
* All errors thrown in Smarty will be handled here.
*
* @param string $message the error message
* @param string $code the error code
*/
class SmartyException {
public function printException($e)
{
echo "Code: " . $e->getCode() . "<br />Error: " . htmlentities($e->getMessage()) . "<br />"
. "File: " . $e->getFile() . "<br />"
. "Line: " . $e->getLine() . "<br />"
. "\n";
}
public static function getStaticException($e)
{
self::printException($e);
}
}
?>

135
libs/debug.tpl Normal file
View File

@@ -0,0 +1,135 @@
{capture assign=debug_output}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Smarty Debug Console</title>
<style type="text/css">
body, h1, h2, td, th, p {
font-family: sans-serif;
font-weight: normal;
font-size: 0.9em;
margin: 1px;
padding: 0;
}
h1 {
margin: 0;
text-align: left;
padding: 2px;
background-color: #f0c040;
color: black;
font-weight: bold;
font-size: 1.2em;
}
h2 {
background-color: #9B410E;
color: white;
text-align: left;
font-weight: bold;
padding: 2px;
border-top: 1px solid black;
}
body {
background: black;
}
p, table, div {
background: #f0ead8;
}
p {
margin: 0;
font-style: italic;
text-align: center;
}
table {
width: 100%;
}
th, td {
font-family: monospace;
vertical-align: top;
text-align: left;
width: 50%;
}
td {
color: green;
}
.odd {
background-color: #eeeeee;
}
.even {
background-color: #fafafa;
}
.exectime {
font-size: 0.8em;
font-style: italic;
}
#table_assigned_vars th {
color: blue;
}
#table_config_vars th {
color: maroon;
}
</style>
</head>
<body>
<h1>Smarty Debug Console - Total Time {$execution_time|string_format:"%.5f"}</h1>
<h2>included templates &amp; config files (load time in seconds)</h2>
<div>
{for $template in $template_data}
<font color=brown>{$template.name}</font>
<span class="exectime">
(compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"})
</span>
<br>
{/for}
</div>
<h2>assigned template variables</h2>
<table id="table_assigned_vars">
{for $vars in $assigned_vars}
<tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
<th>${$vars@key|escape:'html'}</th>
<td>{$vars|debug_print_var}</td></tr>
{/for}
</table>
<h2>assigned config file variables (outer template scope)</h2>
<table id="table_config_vars">
{for $vars in $config_vars}
<tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
<th>{$vars@key|escape:'html'}</th>
<td>{$vars|debug_print_var}</td></tr>
{/for}
</table>
</body>
</html>
{/capture}
<script type="text/javascript">
if ( self.name == '' ) {
var title = 'Console';
}
else {
var title = 'Console_' + self.name;
}
_smarty_console = window.open("",title.value,"width=680,height=600,resizable,scrollbars=yes");
_smarty_console.document.write("{$debug_output|escape:'javascript'}");
_smarty_console.document.close();
</script>

View File

@@ -0,0 +1,11 @@
<?php
// Create Parser
passthru('C:\wamp\bin\php\php5.2.8\php ./ParserGenerator/cli.php internal.configfileparser.y');
// Create Lexer
require_once './LexerGenerator.php';
$lex = new PHP_LexerGenerator('internal.configfilelexer.plex');
copy('internal.configfilelexer.php','../sysplugins/internal.configfilelexer.php');
copy('internal.configfileparser.php','../sysplugins/internal.configfileparser.php');
?>

View File

@@ -0,0 +1,20 @@
<?php
// Create Parser
passthru('C:\wamp\bin\php\php5.2.8\php ./ParserGenerator/cli.php internal.templateparser.y');
// Create Lexer
require_once './LexerGenerator.php';
$lex = new PHP_LexerGenerator('internal.templatelexer.plex');
$contents = file_get_contents('internal.templatelexer.php');
$contents = str_replace(array('SMARTYldel','SMARTYrdel'),array('".$this->ldel."','".$this->rdel."'),$contents);
//$contents = preg_replace('%/\*[\s\S]+?\*/|(?://|#).*(?:\r\n|\n)%m', '', $contents);
file_put_contents('internal.templatelexer.php', $contents);
//$contents = file_get_contents('internal.templateparser.php');
//$contents = preg_replace('%/\*[\s\S]+?\*/|(?://|#).*(?:\r\n|\n)%m', '', $contents);
//file_put_contents('internal.templateparser.php', $contents);
copy('internal.templatelexer.php','../sysplugins/internal.templatelexer.php');
copy('internal.templateparser.php','../sysplugins/internal.templateparser.php');
//unlink('internal.templatelexer.php');
//unlink('internal.templateparser.php');
?>

397
libs/lexer/Exception.php Normal file
View File

@@ -0,0 +1,397 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
/**
* PEAR_Exception
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category pear
* @package PEAR
* @author Tomas V. V. Cox <cox@idecnet.com>
* @author Hans Lellelid <hans@velum.net>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @author Greg Beaver <cellog@php.net>
* @copyright 1997-2008 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Exception.php,v 1.29 2008/01/03 20:26:35 cellog Exp $
* @link http://pear.php.net/package/PEAR
* @since File available since Release 1.3.3
*/
/**
* Base PEAR_Exception Class
*
* 1) Features:
*
* - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception))
* - Definable triggers, shot when exceptions occur
* - Pretty and informative error messages
* - Added more context info available (like class, method or cause)
* - cause can be a PEAR_Exception or an array of mixed
* PEAR_Exceptions/PEAR_ErrorStack warnings
* - callbacks for specific exception classes and their children
*
* 2) Ideas:
*
* - Maybe a way to define a 'template' for the output
*
* 3) Inherited properties from PHP Exception Class:
*
* protected $message
* protected $code
* protected $line
* protected $file
* private $trace
*
* 4) Inherited methods from PHP Exception Class:
*
* __clone
* __construct
* getMessage
* getCode
* getFile
* getLine
* getTraceSafe
* getTraceSafeAsString
* __toString
*
* 5) Usage example
*
* <code>
* require_once 'PEAR/Exception.php';
*
* class Test {
* function foo() {
* throw new PEAR_Exception('Error Message', ERROR_CODE);
* }
* }
*
* function myLogger($pear_exception) {
* echo $pear_exception->getMessage();
* }
* // each time a exception is thrown the 'myLogger' will be called
* // (its use is completely optional)
* PEAR_Exception::addObserver('myLogger');
* $test = new Test;
* try {
* $test->foo();
* } catch (PEAR_Exception $e) {
* print $e;
* }
* </code>
*
* @category pear
* @package PEAR
* @author Tomas V.V.Cox <cox@idecnet.com>
* @author Hans Lellelid <hans@velum.net>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @author Greg Beaver <cellog@php.net>
* @copyright 1997-2008 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.7.2
* @link http://pear.php.net/package/PEAR
* @since Class available since Release 1.3.3
*
*/
class PEAR_Exception extends Exception
{
const OBSERVER_PRINT = -2;
const OBSERVER_TRIGGER = -4;
const OBSERVER_DIE = -8;
protected $cause;
private static $_observers = array();
private static $_uniqueid = 0;
private $_trace;
/**
* Supported signatures:
* - PEAR_Exception(string $message);
* - PEAR_Exception(string $message, int $code);
* - PEAR_Exception(string $message, Exception $cause);
* - PEAR_Exception(string $message, Exception $cause, int $code);
* - PEAR_Exception(string $message, PEAR_Error $cause);
* - PEAR_Exception(string $message, PEAR_Error $cause, int $code);
* - PEAR_Exception(string $message, array $causes);
* - PEAR_Exception(string $message, array $causes, int $code);
* @param string exception message
* @param int|Exception|PEAR_Error|array|null exception cause
* @param int|null exception code or null
*/
public function __construct($message, $p2 = null, $p3 = null)
{
if (is_int($p2)) {
$code = $p2;
$this->cause = null;
} elseif (is_object($p2) || is_array($p2)) {
// using is_object allows both Exception and PEAR_Error
if (is_object($p2) && !($p2 instanceof Exception)) {
if (!class_exists('PEAR_Error',false) || !($p2 instanceof PEAR_Error)) {
throw new PEAR_Exception('exception cause must be Exception, ' .
'array, or PEAR_Error');
}
}
$code = $p3;
if (is_array($p2) && isset($p2['message'])) {
// fix potential problem of passing in a single warning
$p2 = array($p2);
}
$this->cause = $p2;
} else {
$code = null;
$this->cause = null;
}
parent::__construct($message, $code);
$this->signal();
}
/**
* @param mixed $callback - A valid php callback, see php func is_callable()
* - A PEAR_Exception::OBSERVER_* constant
* - An array(const PEAR_Exception::OBSERVER_*,
* mixed $options)
* @param string $label The name of the observer. Use this if you want
* to remove it later with removeObserver()
*/
public static function addObserver($callback, $label = 'default')
{
self::$_observers[$label] = $callback;
}
public static function removeObserver($label = 'default')
{
unset(self::$_observers[$label]);
}
/**
* @return int unique identifier for an observer
*/
public static function getUniqueId()
{
return self::$_uniqueid++;
}
private function signal()
{
foreach (self::$_observers as $func) {
if (is_callable($func)) {
call_user_func($func, $this);
continue;
}
settype($func, 'array');
switch ($func[0]) {
case self::OBSERVER_PRINT :
$f = (isset($func[1])) ? $func[1] : '%s';
printf($f, $this->getMessage());
break;
case self::OBSERVER_TRIGGER :
$f = (isset($func[1])) ? $func[1] : E_USER_NOTICE;
trigger_error($this->getMessage(), $f);
break;
case self::OBSERVER_DIE :
$f = (isset($func[1])) ? $func[1] : '%s';
die(printf($f, $this->getMessage()));
break;
default:
trigger_error('invalid observer type', E_USER_WARNING);
}
}
}
/**
* Return specific error information that can be used for more detailed
* error messages or translation.
*
* This method may be overridden in child exception classes in order
* to add functionality not present in PEAR_Exception and is a placeholder
* to define API
*
* The returned array must be an associative array of parameter => value like so:
* <pre>
* array('name' => $name, 'context' => array(...))
* </pre>
* @return array
*/
public function getErrorData()
{
return array();
}
/**
* Returns the exception that caused this exception to be thrown
* @access public
* @return Exception|array The context of the exception
*/
public function getCause()
{
return $this->cause;
}
/**
* Function must be public to call on caused exceptions
* @param array
*/
public function getCauseMessage(&$causes)
{
$trace = $this->getTraceSafe();
$cause = array('class' => get_class($this),
'message' => $this->message,
'file' => 'unknown',
'line' => 'unknown');
if (isset($trace[0])) {
if (isset($trace[0]['file'])) {
$cause['file'] = $trace[0]['file'];
$cause['line'] = $trace[0]['line'];
}
}
$causes[] = $cause;
if ($this->cause instanceof PEAR_Exception) {
$this->cause->getCauseMessage($causes);
} elseif ($this->cause instanceof Exception) {
$causes[] = array('class' => get_class($this->cause),
'message' => $this->cause->getMessage(),
'file' => $this->cause->getFile(),
'line' => $this->cause->getLine());
} elseif (class_exists('PEAR_Error',false) && $this->cause instanceof PEAR_Error) {
$causes[] = array('class' => get_class($this->cause),
'message' => $this->cause->getMessage(),
'file' => 'unknown',
'line' => 'unknown');
} elseif (is_array($this->cause)) {
foreach ($this->cause as $cause) {
if ($cause instanceof PEAR_Exception) {
$cause->getCauseMessage($causes);
} elseif ($cause instanceof Exception) {
$causes[] = array('class' => get_class($cause),
'message' => $cause->getMessage(),
'file' => $cause->getFile(),
'line' => $cause->getLine());
} elseif (class_exists('PEAR_Error',false) && $cause instanceof PEAR_Error) {
$causes[] = array('class' => get_class($cause),
'message' => $cause->getMessage(),
'file' => 'unknown',
'line' => 'unknown');
} elseif (is_array($cause) && isset($cause['message'])) {
// PEAR_ErrorStack warning
$causes[] = array(
'class' => $cause['package'],
'message' => $cause['message'],
'file' => isset($cause['context']['file']) ?
$cause['context']['file'] :
'unknown',
'line' => isset($cause['context']['line']) ?
$cause['context']['line'] :
'unknown',
);
}
}
}
}
public function getTraceSafe()
{
if (!isset($this->_trace)) {
$this->_trace = $this->getTrace();
if (empty($this->_trace)) {
$backtrace = debug_backtrace();
$this->_trace = array($backtrace[count($backtrace)-1]);
}
}
return $this->_trace;
}
public function getErrorClass()
{
$trace = $this->getTraceSafe();
return $trace[0]['class'];
}
public function getErrorMethod()
{
$trace = $this->getTraceSafe();
return $trace[0]['function'];
}
public function __toString()
{
if (isset($_SERVER['REQUEST_URI'])) {
return $this->toHtml();
}
return $this->toText();
}
public function toHtml()
{
$trace = $this->getTraceSafe();
$causes = array();
$this->getCauseMessage($causes);
$html = '<table border="1" cellspacing="0">' . "\n";
foreach ($causes as $i => $cause) {
$html .= '<tr><td colspan="3" bgcolor="#ff9999">'
. str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
. htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
. 'on line <b>' . $cause['line'] . '</b>'
. "</td></tr>\n";
}
$html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</b></td></tr>' . "\n"
. '<tr><td align="center" bgcolor="#cccccc" width="20"><b>#</b></td>'
. '<td align="center" bgcolor="#cccccc"><b>Function</b></td>'
. '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n";
foreach ($trace as $k => $v) {
$html .= '<tr><td align="center">' . $k . '</td>'
. '<td>';
if (!empty($v['class'])) {
$html .= $v['class'] . $v['type'];
}
$html .= $v['function'];
$args = array();
if (!empty($v['args'])) {
foreach ($v['args'] as $arg) {
if (is_null($arg)) $args[] = 'null';
elseif (is_array($arg)) $args[] = 'Array';
elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')';
elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false';
elseif (is_int($arg) || is_double($arg)) $args[] = $arg;
else {
$arg = (string)$arg;
$str = htmlspecialchars(substr($arg, 0, 16));
if (strlen($arg) > 16) $str .= '&hellip;';
$args[] = "'" . $str . "'";
}
}
}
$html .= '(' . implode(', ',$args) . ')'
. '</td>'
. '<td>' . (isset($v['file']) ? $v['file'] : 'unknown')
. ':' . (isset($v['line']) ? $v['line'] : 'unknown')
. '</td></tr>' . "\n";
}
$html .= '<tr><td align="center">' . ($k+1) . '</td>'
. '<td>{main}</td>'
. '<td>&nbsp;</td></tr>' . "\n"
. '</table>';
return $html;
}
public function toText()
{
$causes = array();
$this->getCauseMessage($causes);
$causeMsg = '';
foreach ($causes as $i => $cause) {
$causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': '
. $cause['message'] . ' in ' . $cause['file']
. ' on line ' . $cause['line'] . "\n";
}
return $causeMsg . $this->getTraceAsString();
}
}
?>

930
libs/lexer/Lempar.php Normal file
View File

@@ -0,0 +1,930 @@
<?php
/**
* Smarty Internal Plugin Templateparser
*
* This is the template parser.
* It is generated from the internal.templateparser.y file
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* This can be used to store both the string representation of
* a token, and any useful meta-data associated with the token.
*
* meta-data should be stored as an array
*/
class ParseyyToken implements ArrayAccess
{
public $string = '';
public $metadata = array();
function __construct($s, $m = array())
{
if ($s instanceof ParseyyToken) {
$this->string = $s->string;
$this->metadata = $s->metadata;
} else {
$this->string = (string) $s;
if ($m instanceof ParseyyToken) {
$this->metadata = $m->metadata;
} elseif (is_array($m)) {
$this->metadata = $m;
}
}
}
function __toString()
{
return $this->_string;
}
function offsetExists($offset)
{
return isset($this->metadata[$offset]);
}
function offsetGet($offset)
{
return $this->metadata[$offset];
}
function offsetSet($offset, $value)
{
if ($offset === null) {
if (isset($value[0])) {
$x = ($value instanceof ParseyyToken) ?
$value->metadata : $value;
$this->metadata = array_merge($this->metadata, $x);
return;
}
$offset = count($this->metadata);
}
if ($value === null) {
return;
}
if ($value instanceof ParseyyToken) {
if ($value->metadata) {
$this->metadata[$offset] = $value->metadata;
}
} elseif ($value) {
$this->metadata[$offset] = $value;
}
}
function offsetUnset($offset)
{
unset($this->metadata[$offset]);
}
}
/** The following structure represents a single element of the
* parser's stack. Information stored includes:
*
* + The state number for the parser at this level of the stack.
*
* + The value of the token stored at this level of the stack.
* (In other words, the "major" token.)
*
* + The semantic value stored at this level of the stack. This is
* the information used by the action routines in the grammar.
* It is sometimes called the "minor" token.
*/
class ParseyyStackEntry
{
public $stateno; /* The state-number */
public $major; /* The major token value. This is the code
** number for the token at this stack level */
public $minor; /* The user-supplied minor token value. This
** is the value of the token */
};
// code external to the class is included here
%%
// declare_class is output here
%%
{
/* First off, code is included which follows the "include_class" declaration
** in the input file. */
%%
/* Next is all token values, as class constants
*/
/*
** These constants (all generated automatically by the parser generator)
** specify the various kinds of tokens (terminals) that the parser
** understands.
**
** Each symbol here is a terminal symbol in the grammar.
*/
%%
/* Next are that tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
** functions that take a state number and lookahead value and return an
** action integer.
**
** Suppose the action integer is N. Then the action is determined as
** follows
**
** 0 <= N < self::YYNSTATE Shift N. That is,
** push the lookahead
** token onto the stack
** and goto state N.
**
** self::YYNSTATE <= N < self::YYNSTATE+self::YYNRULE Reduce by rule N-YYNSTATE.
**
** N == self::YYNSTATE+self::YYNRULE A syntax error has occurred.
**
** N == self::YYNSTATE+self::YYNRULE+1 The parser accepts its
** input. (and concludes parsing)
**
** N == self::YYNSTATE+self::YYNRULE+2 No such action. Denotes unused
** slots in the yy_action[] table.
**
** The action table is constructed as a single large static array $yy_action.
** Given state S and lookahead X, the action is computed as
**
** self::$yy_action[self::$yy_shift_ofst[S] + X ]
**
** If the index value self::$yy_shift_ofst[S]+X is out of range or if the value
** self::$yy_lookahead[self::$yy_shift_ofst[S]+X] is not equal to X or if
** self::$yy_shift_ofst[S] is equal to self::YY_SHIFT_USE_DFLT, it means that
** the action is not in the table and that self::$yy_default[S] should be used instead.
**
** The formula above is for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
** a reduce action) then the static $yy_reduce_ofst array is used in place of
** the static $yy_shift_ofst array and self::YY_REDUCE_USE_DFLT is used in place of
** self::YY_SHIFT_USE_DFLT.
**
** The following are the tables generated in this section:
**
** self::$yy_action A single table containing all actions.
** self::$yy_lookahead A table containing the lookahead for each entry in
** yy_action. Used to detect hash collisions.
** self::$yy_shift_ofst For each state, the offset into self::$yy_action for
** shifting terminals.
** self::$yy_reduce_ofst For each state, the offset into self::$yy_action for
** shifting non-terminals after a reduce.
** self::$yy_default Default action for each state.
*/
%%
/* The next thing included is series of defines which control
** various aspects of the generated parser.
** self::YYNOCODE is a number which corresponds
** to no legal terminal or nonterminal number. This
** number is used to fill in empty slots of the hash
** table.
** self::YYFALLBACK If defined, this indicates that one or more tokens
** have fall-back values which should be used if the
** original value of the token will not parse.
** self::YYSTACKDEPTH is the maximum depth of the parser's stack.
** self::YYNSTATE the combined number of states.
** self::YYNRULE the number of rules in the grammar
** self::YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
*/
%%
/** The next table maps tokens into fallback tokens. If a construct
* like the following:
*
* %fallback ID X Y Z.
*
* appears in the grammer, then ID becomes a fallback token for X, Y,
* and Z. Whenever one of the tokens X, Y, or Z is input to the parser
* but it does not parse, the type of the token is changed to ID and
* the parse is retried before an error is thrown.
*/
static public $yyFallback = array(
%%
);
/**
* Turn parser tracing on by giving a stream to which to write the trace
* and a prompt to preface each trace message. Tracing is turned off
* by making either argument NULL
*
* Inputs:
*
* - A stream resource to which trace output should be written.
* If NULL, then tracing is turned off.
* - A prefix string written at the beginning of every
* line of trace output. If NULL, then tracing is
* turned off.
*
* Outputs:
*
* - None.
* @param resource
* @param string
*/
static function Trace($TraceFILE, $zTracePrompt)
{
if (!$TraceFILE) {
$zTracePrompt = 0;
} elseif (!$zTracePrompt) {
$TraceFILE = 0;
}
self::$yyTraceFILE = $TraceFILE;
self::$yyTracePrompt = $zTracePrompt;
}
/**
* Output debug information to output (php://output stream)
*/
static function PrintTrace()
{
self::$yyTraceFILE = fopen('php://output', 'w');
self::$yyTracePrompt = '<br>';
}
/**
* @var resource|0
*/
static public $yyTraceFILE;
/**
* String to prepend to debug output
* @var string|0
*/
static public $yyTracePrompt;
/**
* @var int
*/
public $yyidx; /* Index of top element in stack */
/**
* @var int
*/
public $yyerrcnt; /* Shifts left before out of the error */
/**
* @var array
*/
public $yystack = array(); /* The parser's stack */
/**
* For tracing shifts, the names of all terminals and nonterminals
* are required. The following table supplies these names
* @var array
*/
public $yyTokenName = array(
%%
);
/**
* For tracing reduce actions, the names of all rules are required.
* @var array
*/
static public $yyRuleName = array(
%%
);
/**
* This function returns the symbolic name associated with a token
* value.
* @param int
* @return string
*/
function tokenName($tokenType)
{
if ($tokenType === 0) {
return 'End of Input';
}
if ($tokenType > 0 && $tokenType < count($this->yyTokenName)) {
return $this->yyTokenName[$tokenType];
} else {
return "Unknown";
}
}
/**
* The following function deletes the value associated with a
* symbol. The symbol can be either a terminal or nonterminal.
* @param int the symbol code
* @param mixed the symbol's value
*/
static function yy_destructor($yymajor, $yypminor)
{
switch ($yymajor) {
/* Here is inserted the actions which take place when a
** terminal or non-terminal is destroyed. This can happen
** when the symbol is popped from the stack during a
** reduce or during error processing or when a parser is
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
** which appear on the RHS of the rule, but which are not used
** inside the C code.
*/
%%
default: break; /* If no destructor action specified: do nothing */
}
}
/**
* Pop the parser's stack once.
*
* If there is a destructor routine associated with the token which
* is popped from the stack, then call it.
*
* Return the major token number for the symbol popped.
* @param ParseyyParser
* @return int
*/
function yy_pop_parser_stack()
{
if (!count($this->yystack)) {
return;
}
$yytos = array_pop($this->yystack);
if (self::$yyTraceFILE && $this->yyidx >= 0) {
fwrite(self::$yyTraceFILE,
self::$yyTracePrompt . 'Popping ' . $this->yyTokenName[$yytos->major] .
"\n");
}
$yymajor = $yytos->major;
self::yy_destructor($yymajor, $yytos->minor);
$this->yyidx--;
return $yymajor;
}
/**
* Deallocate and destroy a parser. Destructors are all called for
* all stack elements before shutting the parser down.
*/
function __destruct()
{
while ($this->yyidx >= 0) {
$this->yy_pop_parser_stack();
}
if (is_resource(self::$yyTraceFILE)) {
fclose(self::$yyTraceFILE);
}
}
/**
* Based on the current state and parser stack, get a list of all
* possible lookahead tokens
* @param int
* @return array
*/
function yy_get_expected_tokens($token)
{
$state = $this->yystack[$this->yyidx]->stateno;
$expected = self::$yyExpectedTokens[$state];
if (in_array($token, self::$yyExpectedTokens[$state], true)) {
return $expected;
}
$stack = $this->yystack;
$yyidx = $this->yyidx;
do {
$yyact = $this->yy_find_shift_action($token);
if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) {
// reduce action
$done = 0;
do {
if ($done++ == 100) {
$this->yyidx = $yyidx;
$this->yystack = $stack;
// too much recursion prevents proper detection
// so give up
return array_unique($expected);
}
$yyruleno = $yyact - self::YYNSTATE;
$this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs'];
$nextstate = $this->yy_find_reduce_action(
$this->yystack[$this->yyidx]->stateno,
self::$yyRuleInfo[$yyruleno]['lhs']);
if (isset(self::$yyExpectedTokens[$nextstate])) {
$expected += self::$yyExpectedTokens[$nextstate];
if (in_array($token,
self::$yyExpectedTokens[$nextstate], true)) {
$this->yyidx = $yyidx;
$this->yystack = $stack;
return array_unique($expected);
}
}
if ($nextstate < self::YYNSTATE) {
// we need to shift a non-terminal
$this->yyidx++;
$x = new ParseyyStackEntry;
$x->stateno = $nextstate;
$x->major = self::$yyRuleInfo[$yyruleno]['lhs'];
$this->yystack[$this->yyidx] = $x;
continue 2;
} elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) {
$this->yyidx = $yyidx;
$this->yystack = $stack;
// the last token was just ignored, we can't accept
// by ignoring input, this is in essence ignoring a
// syntax error!
return array_unique($expected);
} elseif ($nextstate === self::YY_NO_ACTION) {
$this->yyidx = $yyidx;
$this->yystack = $stack;
// input accepted, but not shifted (I guess)
return $expected;
} else {
$yyact = $nextstate;
}
} while (true);
}
break;
} while (true);
return array_unique($expected);
}
/**
* Based on the parser state and current parser stack, determine whether
* the lookahead token is possible.
*
* The parser will convert the token value to an error token if not. This
* catches some unusual edge cases where the parser would fail.
* @param int
* @return bool
*/
function yy_is_expected_token($token)
{
if ($token === 0) {
return true; // 0 is not part of this
}
$state = $this->yystack[$this->yyidx]->stateno;
if (in_array($token, self::$yyExpectedTokens[$state], true)) {
return true;
}
$stack = $this->yystack;
$yyidx = $this->yyidx;
do {
$yyact = $this->yy_find_shift_action($token);
if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) {
// reduce action
$done = 0;
do {
if ($done++ == 100) {
$this->yyidx = $yyidx;
$this->yystack = $stack;
// too much recursion prevents proper detection
// so give up
return true;
}
$yyruleno = $yyact - self::YYNSTATE;
$this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs'];
$nextstate = $this->yy_find_reduce_action(
$this->yystack[$this->yyidx]->stateno,
self::$yyRuleInfo[$yyruleno]['lhs']);
if (isset(self::$yyExpectedTokens[$nextstate]) &&
in_array($token, self::$yyExpectedTokens[$nextstate], true)) {
$this->yyidx = $yyidx;
$this->yystack = $stack;
return true;
}
if ($nextstate < self::YYNSTATE) {
// we need to shift a non-terminal
$this->yyidx++;
$x = new ParseyyStackEntry;
$x->stateno = $nextstate;
$x->major = self::$yyRuleInfo[$yyruleno]['lhs'];
$this->yystack[$this->yyidx] = $x;
continue 2;
} elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) {
$this->yyidx = $yyidx;
$this->yystack = $stack;
if (!$token) {
// end of input: this is valid
return true;
}
// the last token was just ignored, we can't accept
// by ignoring input, this is in essence ignoring a
// syntax error!
return false;
} elseif ($nextstate === self::YY_NO_ACTION) {
$this->yyidx = $yyidx;
$this->yystack = $stack;
// input accepted, but not shifted (I guess)
return true;
} else {
$yyact = $nextstate;
}
} while (true);
}
break;
} while (true);
$this->yyidx = $yyidx;
$this->yystack = $stack;
return true;
}
/**
* Find the appropriate action for a parser given the terminal
* look-ahead token iLookAhead.
*
* If the look-ahead token is YYNOCODE, then check to see if the action is
* independent of the look-ahead. If it is, return the action, otherwise
* return YY_NO_ACTION.
* @param int The look-ahead token
*/
function yy_find_shift_action($iLookAhead)
{
$stateno = $this->yystack[$this->yyidx]->stateno;
/* if ($this->yyidx < 0) return self::YY_NO_ACTION; */
if (!isset(self::$yy_shift_ofst[$stateno])) {
// no shift actions
return self::$yy_default[$stateno];
}
$i = self::$yy_shift_ofst[$stateno];
if ($i === self::YY_SHIFT_USE_DFLT) {
return self::$yy_default[$stateno];
}
if ($iLookAhead == self::YYNOCODE) {
return self::YY_NO_ACTION;
}
$i += $iLookAhead;
if ($i < 0 || $i >= self::YY_SZ_ACTTAB ||
self::$yy_lookahead[$i] != $iLookAhead) {
if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback)
&& ($iFallback = self::$yyFallback[$iLookAhead]) != 0) {
if (self::$yyTraceFILE) {
fwrite(self::$yyTraceFILE, self::$yyTracePrompt . "FALLBACK " .
$this->yyTokenName[$iLookAhead] . " => " .
$this->yyTokenName[$iFallback] . "\n");
}
return $this->yy_find_shift_action($iFallback);
}
return self::$yy_default[$stateno];
} else {
return self::$yy_action[$i];
}
}
/**
* Find the appropriate action for a parser given the non-terminal
* look-ahead token $iLookAhead.
*
* If the look-ahead token is self::YYNOCODE, then check to see if the action is
* independent of the look-ahead. If it is, return the action, otherwise
* return self::YY_NO_ACTION.
* @param int Current state number
* @param int The look-ahead token
*/
function yy_find_reduce_action($stateno, $iLookAhead)
{
/* $stateno = $this->yystack[$this->yyidx]->stateno; */
if (!isset(self::$yy_reduce_ofst[$stateno])) {
return self::$yy_default[$stateno];
}
$i = self::$yy_reduce_ofst[$stateno];
if ($i == self::YY_REDUCE_USE_DFLT) {
return self::$yy_default[$stateno];
}
if ($iLookAhead == self::YYNOCODE) {
return self::YY_NO_ACTION;
}
$i += $iLookAhead;
if ($i < 0 || $i >= self::YY_SZ_ACTTAB ||
self::$yy_lookahead[$i] != $iLookAhead) {
return self::$yy_default[$stateno];
} else {
return self::$yy_action[$i];
}
}
/**
* Perform a shift action.
* @param int The new state to shift in
* @param int The major token to shift in
* @param mixed the minor token to shift in
*/
function yy_shift($yyNewState, $yyMajor, $yypMinor)
{
$this->yyidx++;
if ($this->yyidx >= self::YYSTACKDEPTH) {
$this->yyidx--;
if (self::$yyTraceFILE) {
fprintf(self::$yyTraceFILE, "%sStack Overflow!\n", self::$yyTracePrompt);
}
while ($this->yyidx >= 0) {
$this->yy_pop_parser_stack();
}
/* Here code is inserted which will execute if the parser
** stack ever overflows */
%%
return;
}
$yytos = new ParseyyStackEntry;
$yytos->stateno = $yyNewState;
$yytos->major = $yyMajor;
$yytos->minor = $yypMinor;
array_push($this->yystack, $yytos);
if (self::$yyTraceFILE && $this->yyidx > 0) {
fprintf(self::$yyTraceFILE, "%sShift %d\n", self::$yyTracePrompt,
$yyNewState);
fprintf(self::$yyTraceFILE, "%sStack:", self::$yyTracePrompt);
for($i = 1; $i <= $this->yyidx; $i++) {
fprintf(self::$yyTraceFILE, " %s",
$this->yyTokenName[$this->yystack[$i]->major]);
}
fwrite(self::$yyTraceFILE,"\n");
}
}
/**
* The following table contains information about every rule that
* is used during the reduce.
*
* <pre>
* array(
* array(
* int $lhs; Symbol on the left-hand side of the rule
* int $nrhs; Number of right-hand side symbols in the rule
* ),...
* );
* </pre>
*/
static public $yyRuleInfo = array(
%%
);
/**
* The following table contains a mapping of reduce action to method name
* that handles the reduction.
*
* If a rule is not set, it has no handler.
*/
static public $yyReduceMap = array(
%%
);
/* Beginning here are the reduction cases. A typical example
** follows:
** #line <lineno> <grammarfile>
** function yy_r0($yymsp){ ... } // User supplied code
** #line <lineno> <thisfile>
*/
%%
/**
* placeholder for the left hand side in a reduce operation.
*
* For a parser with a rule like this:
* <pre>
* rule(A) ::= B. { A = 1; }
* </pre>
*
* The parser will translate to something like:
*
* <code>
* function yy_r0(){$this->_retvalue = 1;}
* </code>
*/
private $_retvalue;
/**
* Perform a reduce action and the shift that must immediately
* follow the reduce.
*
* For a rule such as:
*
* <pre>
* A ::= B blah C. { dosomething(); }
* </pre>
*
* This function will first call the action, if any, ("dosomething();" in our
* example), and then it will pop three states from the stack,
* one for each entry on the right-hand side of the expression
* (B, blah, and C in our example rule), and then push the result of the action
* back on to the stack with the resulting state reduced to (as described in the .out
* file)
* @param int Number of the rule by which to reduce
*/
function yy_reduce($yyruleno)
{
//int $yygoto; /* The next state */
//int $yyact; /* The next action */
//mixed $yygotominor; /* The LHS of the rule reduced */
//ParseyyStackEntry $yymsp; /* The top of the parser's stack */
//int $yysize; /* Amount to pop the stack */
$yymsp = $this->yystack[$this->yyidx];
if (self::$yyTraceFILE && $yyruleno >= 0
&& $yyruleno < count(self::$yyRuleName)) {
fprintf(self::$yyTraceFILE, "%sReduce (%d) [%s].\n",
self::$yyTracePrompt, $yyruleno,
self::$yyRuleName[$yyruleno]);
}
$this->_retvalue = $yy_lefthand_side = null;
if (array_key_exists($yyruleno, self::$yyReduceMap)) {
// call the action
$this->_retvalue = null;
$this->{'yy_r' . self::$yyReduceMap[$yyruleno]}();
$yy_lefthand_side = $this->_retvalue;
}
$yygoto = self::$yyRuleInfo[$yyruleno]['lhs'];
$yysize = self::$yyRuleInfo[$yyruleno]['rhs'];
$this->yyidx -= $yysize;
for($i = $yysize; $i; $i--) {
// pop all of the right-hand side parameters
array_pop($this->yystack);
}
$yyact = $this->yy_find_reduce_action($this->yystack[$this->yyidx]->stateno, $yygoto);
if ($yyact < self::YYNSTATE) {
/* If we are not debugging and the reduce action popped at least
** one element off the stack, then we can push the new element back
** onto the stack here, and skip the stack overflow test in yy_shift().
** That gives a significant speed improvement. */
if (!self::$yyTraceFILE && $yysize) {
$this->yyidx++;
$x = new ParseyyStackEntry;
$x->stateno = $yyact;
$x->major = $yygoto;
$x->minor = $yy_lefthand_side;
$this->yystack[$this->yyidx] = $x;
} else {
$this->yy_shift($yyact, $yygoto, $yy_lefthand_side);
}
} elseif ($yyact == self::YYNSTATE + self::YYNRULE + 1) {
$this->yy_accept();
}
}
/**
* The following code executes when the parse fails
*
* Code from %parse_fail is inserted here
*/
function yy_parse_failed()
{
if (self::$yyTraceFILE) {
fprintf(self::$yyTraceFILE, "%sFail!\n", self::$yyTracePrompt);
}
while ($this->yyidx >= 0) {
$this->yy_pop_parser_stack();
}
/* Here code is inserted which will be executed whenever the
** parser fails */
%%
}
/**
* The following code executes when a syntax error first occurs.
*
* %syntax_error code is inserted here
* @param int The major type of the error token
* @param mixed The minor type of the error token
*/
function yy_syntax_error($yymajor, $TOKEN)
{
%%
}
/**
* The following is executed when the parser accepts
*
* %parse_accept code is inserted here
*/
function yy_accept()
{
if (self::$yyTraceFILE) {
fprintf(self::$yyTraceFILE, "%sAccept!\n", self::$yyTracePrompt);
}
while ($this->yyidx >= 0) {
$stack = $this->yy_pop_parser_stack();
}
/* Here code is inserted which will be executed whenever the
** parser accepts */
%%
}
/**
* The main parser program.
*
* The first argument is the major token number. The second is
* the token value string as scanned from the input.
*
* @param int the token number
* @param mixed the token value
* @param mixed any extra arguments that should be passed to handlers
*/
function doParse($yymajor, $yytokenvalue)
{
// $yyact; /* The parser action. */
// $yyendofinput; /* True if we are at the end of input */
$yyerrorhit = 0; /* True if yymajor has invoked an error */
/* (re)initialize the parser, if necessary */
if ($this->yyidx === null || $this->yyidx < 0) {
/* if ($yymajor == 0) return; // not sure why this was here... */
$this->yyidx = 0;
$this->yyerrcnt = -1;
$x = new ParseyyStackEntry;
$x->stateno = 0;
$x->major = 0;
$this->yystack = array();
array_push($this->yystack, $x);
}
$yyendofinput = ($yymajor==0);
if (self::$yyTraceFILE) {
fprintf(self::$yyTraceFILE, "%sInput %s\n",
self::$yyTracePrompt, $this->yyTokenName[$yymajor]);
}
do {
$yyact = $this->yy_find_shift_action($yymajor);
if ($yymajor < self::YYERRORSYMBOL &&
!$this->yy_is_expected_token($yymajor)) {
// force a syntax error
$yyact = self::YY_ERROR_ACTION;
}
if ($yyact < self::YYNSTATE) {
$this->yy_shift($yyact, $yymajor, $yytokenvalue);
$this->yyerrcnt--;
if ($yyendofinput && $this->yyidx >= 0) {
$yymajor = 0;
} else {
$yymajor = self::YYNOCODE;
}
} elseif ($yyact < self::YYNSTATE + self::YYNRULE) {
$this->yy_reduce($yyact - self::YYNSTATE);
} elseif ($yyact == self::YY_ERROR_ACTION) {
if (self::$yyTraceFILE) {
fprintf(self::$yyTraceFILE, "%sSyntax Error!\n",
self::$yyTracePrompt);
}
if (self::YYERRORSYMBOL) {
/* A syntax error has occurred.
** The response to an error depends upon whether or not the
** grammar defines an error token "ERROR".
**
** This is what we do if the grammar does define ERROR:
**
** * Call the %syntax_error function.
**
** * Begin popping the stack until we enter a state where
** it is legal to shift the error symbol, then shift
** the error symbol.
**
** * Set the error count to three.
**
** * Begin accepting and shifting new tokens. No new error
** processing will occur until three tokens have been
** shifted successfully.
**
*/
if ($this->yyerrcnt < 0) {
$this->yy_syntax_error($yymajor, $yytokenvalue);
}
$yymx = $this->yystack[$this->yyidx]->major;
if ($yymx == self::YYERRORSYMBOL || $yyerrorhit ){
if (self::$yyTraceFILE) {
fprintf(self::$yyTraceFILE, "%sDiscard input token %s\n",
self::$yyTracePrompt, $this->yyTokenName[$yymajor]);
}
$this->yy_destructor($yymajor, $yytokenvalue);
$yymajor = self::YYNOCODE;
} else {
while ($this->yyidx >= 0 &&
$yymx != self::YYERRORSYMBOL &&
($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE
){
$this->yy_pop_parser_stack();
}
if ($this->yyidx < 0 || $yymajor==0) {
$this->yy_destructor($yymajor, $yytokenvalue);
$this->yy_parse_failed();
$yymajor = self::YYNOCODE;
} elseif ($yymx != self::YYERRORSYMBOL) {
$u2 = 0;
$this->yy_shift($yyact, self::YYERRORSYMBOL, $u2);
}
}
$this->yyerrcnt = 3;
$yyerrorhit = 1;
} else {
/* YYERRORSYMBOL is not defined */
/* This is what we do if the grammar does not define ERROR:
**
** * Report an error message, and throw away the input token.
**
** * If the input token is $, then fail the parse.
**
** As before, subsequent error messages are suppressed until
** three input tokens have been successfully shifted.
*/
if ($this->yyerrcnt <= 0) {
$this->yy_syntax_error($yymajor, $yytokenvalue);
}
$this->yyerrcnt = 3;
$this->yy_destructor($yymajor, $yytokenvalue);
if ($yyendofinput) {
$this->yy_parse_failed();
}
$yymajor = self::YYNOCODE;
}
} else {
$this->yy_accept();
$yymajor = self::YYNOCODE;
}
} while ($yymajor != self::YYNOCODE && $this->yyidx >= 0);
}
}

View File

@@ -0,0 +1,289 @@
<?php
/**
* PHP_LexerGenerator, a php 5 lexer generator.
*
* This lexer generator translates a file in a format similar to
* re2c ({@link http://re2c.org}) and translates it into a PHP 5-based lexer
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_LexerGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_LexerGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: LexerGenerator.php,v 1.1 2006/07/18 00:47:06 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
* The Lexer generation parser
*/
require_once './LexerGenerator/Parser.php';
/**
* Hand-written lexer for lex2php format files
*/
require_once './LexerGenerator/Lexer.php';
/**
* The basic home class for the lexer generator. A lexer scans text and
* organizes it into tokens for usage by a parser.
*
* Sample Usage:
* <code>
* require_once 'PHP/LexerGenerator.php';
* $lex = new PHP_LexerGenerator('/path/to/lexerfile.plex');
* </code>
*
* A file named "/path/to/lexerfile.php" will be created.
*
* File format consists of a PHP file containing specially
* formatted comments like so:
*
* <code>
* /*!lex2php
* {@*}
* </code>
*
* All lexer definition files must contain at least two lex2php comment blocks:
* - 1 regex declaration block
* - 1 or more rule declaration blocks
*
* The first lex2php comment is the regex declaration block and must contain
* several processor instruction as well as defining a name for all
* regular expressions. Processor instructions start with
* a "%" symbol and must be:
*
* - %counter
* - %input
* - %token
* - %value
* - %line
*
* token and counter should define the class variables used to define lexer input
* and the index into the input. token and value should be used to define the class
* variables used to store the token number and its textual value. Finally, line
* should be used to define the class variable used to define the current line number
* of scanning.
*
* For example:
* <code>
* /*!lex2php
* %counter {$this->N}
* %input {$this->data}
* %token {$this->token}
* %value {$this->value}
* %line {%this->linenumber}
* {@*}
* </code>
*
* Patterns consist of an identifier containing an letters or an underscore, and
* a descriptive match pattern.
*
* Descriptive match patterns may either be regular expressions (regexes) or
* quoted literal strings. Here are some examples:
*
* <pre>
* pattern = "quoted literal"
* ANOTHER = /[a-zA-Z_]+/
* COMPLEX = @<([a-zA-Z_]+)( +(([a-zA-Z_]+)=((["\'])([^\6]*)\6))+){0,1}>[^<]*</\1>@
* </pre>
*
* Quoted strings must escape the \ and " characters with \" and \\.
*
* Regex patterns must be in Perl-compatible regular expression format (preg).
* special characters (like \t \n or \x3H) can only be used in regexes, all
* \ will be escaped in literal strings.
*
* Sub-patterns may be defined and back-references (like \1) may be used. Any sub-
* patterns detected will be passed to the token handler in the variable
* $yysubmatches.
*
* In addition, lookahead expressions, and once-only expressions are allowed.
* Lookbehind expressions are impossible (scanning always occurs from the
* current position forward), and recursion (?R) can't work and is not allowed.
*
* <code>
* /*!lex2php
* %counter {$this->N}
* %input {$this->data}
* %token {$this->token}
* %value {$this->value}
* %line {%this->linenumber}
* alpha = /[a-zA-Z]/
* alphaplus = /[a-zA-Z]+/
* number = /[0-9]/
* numerals = /[0-9]+/
* whitespace = /[ \t\n]+/
* blah = "$\""
* blahblah = /a\$/
* GAMEEND = @(?:1\-0|0\-1|1/2\-1/2)@
* PAWNMOVE = /P?[a-h]([2-7]|[18]\=(Q|R|B|N))|P?[a-h]x[a-h]([2-7]|[18]\=(Q|R|B|N))/
* {@*}
* </code>
*
* All regexes must be delimited. Any legal preg delimiter can be used (as in @ or / in
* the example above)
*
* Rule lex2php blocks each define a lexer state. You can optionally name the state
* with the %statename processor instruction. State names can be used to transfer to
* a new lexer state with the yybegin() method
*
* <code>
* /*!lexphp
* %statename INITIAL
* blah {
* $this->yybegin(self::INBLAH);
* // note - $this->yybegin(2) would also work
* }
* {@*}
* /*!lex2php
* %statename INBLAH
* ANYTHING {
* $this->yybegin(self::INITIAL);
* // note - $this->yybegin(1) would also work
* }
* {@*}
* </code>
*
* You can maintain a parser state stack simply by using yypushstate() and
* yypopstate() instead of yybegin():
*
* <code>
* /*!lexphp
* %statename INITIAL
* blah {
* $this->yypushstate(self::INBLAH);
* }
* {@*}
* /*!lex2php
* %statename INBLAH
* ANYTHING {
* $this->yypopstate();
* // now INBLAH doesn't care where it was called from
* }
* {@*}
* </code>
*
* Code blocks can choose to skip the current token and cycle to the next token by
* returning "false"
*
* <code>
* /*!lex2php
* WHITESPACE {
* return false;
* }
* {@*}
* </code>
*
* If you wish to re-process the current token in a new state, simply return true.
* If you forget to change lexer state, this will cause an unterminated loop,
* so be careful!
*
* <code>
* /*!lex2php
* "(" {
* $this->yypushstate(self::INPARAMS);
* return true;
* }
* {@*}
* </code>
*
* Lastly, if you wish to cycle to the next matching rule, return any value other than
* true, false or null:
*
* <code>
* /*!lex2php
* "{@" ALPHA {
* if ($this->value == '{@internal') {
* return 'more';
* }
* ...
* }
* "{@internal" {
* ...
* }
* {@*}
* </code>
*
* Note that this procedure is exceptionally inefficient, and it would be far better
* to take advantage of PHP_LexerGenerator's top-down precedence and instead code:
*
* <code>
* /*!lex2php
* "{@internal" {
* ...
* }
* "{@" ALPHA {
* ...
* }
* {@*}
* </code>
* @package PHP_LexerGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version 0.3.4
* @since Class available since Release 0.1.0
* @example TestLexer.plex Example lexer source
* @example TestLexer.php Example lexer generated php code
* @example usage.php Example usage of PHP_LexerGenerator
* @example Lexer.plex File_ChessPGN lexer source (complex)
* @example Lexer.php File_ChessPGN lexer generated php code
*/
class PHP_LexerGenerator
{
private $lex;
private $parser;
private $outfile;
/**
* Create a lexer file from its skeleton plex file.
*
* @param string $lexerfile path to the plex file
*/
function __construct($lexerfile)
{
$this->lex = new PHP_LexerGenerator_Lexer(file_get_contents($lexerfile));
$info = pathinfo($lexerfile);
$this->outfile = $info['dirname'] . DIRECTORY_SEPARATOR .
substr($info['basename'], 0,
strlen($info['basename']) - strlen($info['extension'])) . 'php';
$this->parser = new PHP_LexerGenerator_Parser($this->outfile, $this->lex);
// $this->parser->PrintTrace();
while ($this->lex->advance($this->parser)) {
$this->parser->doParse($this->lex->token, $this->lex->value);
}
$this->parser->doParse(0, 0);
}
}
//$a = new PHP_LexerGenerator('/development/File_ChessPGN/ChessPGN/Lexer.plex');
?>

View File

@@ -0,0 +1,55 @@
<?php
/**
* PHP_LexerGenerator, a php 5 lexer generator.
*
* Exception classes for the lexer generator
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_LexerGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_LexerGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
require_once './Exception.php';
/**
* @package PHP_LexerGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version @package_version@
* @since File available since Release 0.1.0
*/
class PHP_LexerGenerator_Exception extends PEAR_Exception {}
?>

View File

@@ -0,0 +1,470 @@
<?php
/**
* PHP_LexerGenerator, a php 5 lexer generator.
*
* This lexer generator translates a file in a format similar to
* re2c ({@link http://re2c.org}) and translates it into a PHP 5-based lexer
*
* PHP version 5
*
* LICENSE: This source file is subject to version 3.01 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_01.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category php
* @package PHP_LexerGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version CVS: $Id: Lexer.php,v 1.1 2006/07/18 00:47:06 cellog Exp $
* @since File available since Release 0.1.0
*/
require_once './LexerGenerator/Parser.php';
/**
* Token scanner for plex files.
*
* This scanner detects comments beginning with "/*!lex2php" and
* then returns their components (processing instructions, patterns, strings
* action code, and regexes)
* @package PHP_LexerGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version 0.3.4
* @since Class available since Release 0.1.0
*/
class PHP_LexerGenerator_Lexer
{
private $data;
private $N;
private $state;
/**
* Current line number in input
* @var int
*/
public $line;
/**
* Number of scanning errors detected
* @var int
*/
public $errors = 0;
/**
* integer identifier of the current token
* @var int
*/
public $token;
/**
* string content of current token
* @var string
*/
public $value;
const PHPCODE = PHP_LexerGenerator_Parser::PHPCODE;
const COMMENTSTART = PHP_LexerGenerator_Parser::COMMENTSTART;
const COMMENTEND = PHP_LexerGenerator_Parser::COMMENTEND;
const QUOTE = PHP_LexerGenerator_Parser::QUOTE;
const PATTERN = PHP_LexerGenerator_Parser::PATTERN;
const CODE = PHP_LexerGenerator_Parser::CODE;
const SUBPATTERN = PHP_LexerGenerator_Parser::SUBPATTERN;
const PI = PHP_LexerGenerator_Parser::PI;
/**
* prepare scanning
* @param string the input
*/
function __construct($data)
{
$this->data = str_replace("\r\n", "\n", $data);
$this->N = 0;
$this->line = 1;
$this->state = 'Start';
$this->errors = 0;
}
/**
* Output an error message
* @param string
*/
private function error($msg)
{
echo 'Error on line ' . $this->line . ': ' . $msg;
$this->errors++;
}
/**
* Initial scanning state lexer
* @return boolean
*/
private function lexStart()
{
if ($this->N >= strlen($this->data)) {
return false;
}
$a = strpos($this->data, '/*!lex2php' . "\n", $this->N);
if ($a === false) {
$this->value = substr($this->data, $this->N);
$this->N = strlen($this->data);
$this->token = self::PHPCODE;
return true;
}
if ($a > $this->N) {
$this->value = substr($this->data, $this->N, $a - $this->N);
$this->N = $a;
$this->token = self::PHPCODE;
return true;
}
$this->value = '/*!lex2php' . "\n";
$this->N += 11; // strlen("/*lex2php\n")
$this->token = self::COMMENTSTART;
$this->state = 'Declare';
return true;
}
/**
* lexer for top-level canning state after the initial declaration comment
* @return boolean
*/
private function lexStartNonDeclare()
{
if ($this->N >= strlen($this->data)) {
return false;
}
$a = strpos($this->data, '/*!lex2php' . "\n", $this->N);
if ($a === false) {
$this->value = substr($this->data, $this->N);
$this->N = strlen($this->data);
$this->token = self::PHPCODE;
return true;
}
if ($a > $this->N) {
$this->value = substr($this->data, $this->N, $a - $this->N);
$this->N = $a;
$this->token = self::PHPCODE;
return true;
}
$this->value = '/*!lex2php' . "\n";
$this->N += 11; // strlen("/*lex2php\n")
$this->token = self::COMMENTSTART;
$this->state = 'Rule';
return true;
}
/**
* lexer for declaration comment state
* @return boolean
*/
private function lexDeclare()
{
if ($this->data[$this->N] == '*' && $this->data[$this->N + 1] == '/') {
$this->state = 'StartNonDeclare';
$this->value = '*/';
$this->N += 2;
$this->token = self::COMMENTEND;
return true;
}
if (preg_match('/^%([a-z]+)/', substr($this->data, $this->N), $token)) {
$this->value = $token[1];
$this->N += strlen($token[1]) + 1;
$this->state = 'DeclarePI';
$this->token = self::PI;
return true;
}
if (preg_match('/^[a-zA-Z_]+/', substr($this->data, $this->N), $token)) {
$this->value = $token[0];
$this->token = self::PATTERN;
$this->N += strlen($token[0]);
$this->state = 'DeclareEquals';
return true;
} else {
$this->error('expecting declaration of sub-patterns');
return false;
}
}
/**
* lexer for processor instructions within declaration comment
* @return boolean
*/
private function lexDeclarePI()
{
while ($this->N < strlen($this->data) &&
($this->data[$this->N] == ' ' ||
$this->data[$this->N] == "\t")) {
$this->N++; // skip whitespace
}
if ($this->data[$this->N] == "\n") {
$this->N++;
$this->state = 'Declare';
$this->line++;
return $this->lexDeclare();
}
if ($this->data[$this->N] == '{') {
return $this->lexCode();
}
if (!preg_match("/[^\n]+/", substr($this->data, $this->N), $token)) {
$this->error('Unexpected end of file');
return false;
}
$this->value = $token[0];
$this->N += strlen($this->value);
$this->token = self::SUBPATTERN;
return true;
}
/**
* lexer for processor instructions inside rule comments
* @return boolean
*/
private function lexDeclarePIRule()
{
while ($this->N < strlen($this->data) &&
($this->data[$this->N] == ' ' ||
$this->data[$this->N] == "\t")) {
$this->N++; // skip whitespace
}
if ($this->data[$this->N] == "\n") {
$this->N++;
$this->state = 'Rule';
$this->line++;
return $this->lexRule();
}
if ($this->data[$this->N] == '{') {
return $this->lexCode();
}
if (!preg_match("/[^\n]+/", substr($this->data, $this->N), $token)) {
$this->error('Unexpected end of file');
return false;
}
$this->value = $token[0];
$this->N += strlen($this->value);
$this->token = self::SUBPATTERN;
return true;
}
/**
* lexer for the state representing scanning between a pattern and the "=" sign
* @return boolean
*/
private function lexDeclareEquals()
{
while ($this->N < strlen($this->data) &&
($this->data[$this->N] == ' ' || $this->data[$this->N] == "\t")) {
$this->N++; // skip whitespace
}
if ($this->N >= strlen($this->data)) {
$this->error('unexpected end of input, expecting "=" for sub-pattern declaration');
}
if ($this->data[$this->N] != '=') {
$this->error('expecting "=" for sub-pattern declaration');
return false;
}
$this->N++;
$this->state = 'DeclareRightside';
while ($this->N < strlen($this->data) &&
($this->data[$this->N] == ' ' || $this->data[$this->N] == "\t")) {
$this->N++; // skip whitespace
}
if ($this->N >= strlen($this->data)) {
$this->error('unexpected end of file, expecting right side of sub-pattern declaration');
return false;
}
return $this->lexDeclareRightside();
}
/**
* lexer for the right side of a pattern, detects quotes or regexes
* @return boolean
*/
private function lexDeclareRightside()
{
if ($this->data[$this->N] == "\n") {
$this->state = 'lexDeclare';
$this->N++;
$this->line++;
return $this->lexDeclare();
}
if ($this->data[$this->N] == '"') {
return $this->lexQuote();
}
while ($this->N < strlen($this->data) &&
($this->data[$this->N] == ' ' ||
$this->data[$this->N] == "\t")) {
$this->N++; // skip all whitespace
}
// match a pattern
$test = $this->data[$this->N];
$token = $this->N + 1;
$a = 0;
do {
if ($a++) {
$token++;
}
$token = strpos($this->data, $test, $token);
} while ($token !== false && ($this->data[$token - 1] == '\\'
&& $this->data[$token - 2] != '\\'));
if ($token === false) {
$this->error('Unterminated regex pattern (started with "' . $test . '"');
return false;
}
if (substr_count($this->data, "\n", $this->N, $token - $this->N)) {
$this->error('Regex pattern extends over multiple lines');
return false;
}
$this->value = substr($this->data, $this->N + 1, $token - $this->N - 1);
// unescape the regex marker
// we will re-escape when creating the final regex
$this->value = str_replace('\\' . $test, $test, $this->value);
$this->N = $token + 1;
$this->token = self::SUBPATTERN;
return true;
}
/**
* lexer for quoted literals
* @return boolean
*/
private function lexQuote()
{
$token = $this->N + 1;
$a = 0;
do {
if ($a++) {
$token++;
}
$token = strpos($this->data, '"', $token);
} while ($token !== false && $token < strlen($this->data) &&
($this->data[$token - 1] == '\\' && $this->data[$token - 2] != '\\'));
if ($token === false) {
$this->error('unterminated quote');
return false;
}
if (substr_count($this->data, "\n", $this->N, $token - $this->N)) {
$this->error('quote extends over multiple lines');
return false;
}
$this->value = substr($this->data, $this->N + 1, $token - $this->N - 1);
$this->value = str_replace('\\"', '"', $this->value);
$this->value = str_replace('\\\\', '\\', $this->value);
$this->N = $token + 1;
$this->token = self::QUOTE;
return true;
}
/**
* lexer for rules
* @return boolean
*/
private function lexRule()
{
while ($this->N < strlen($this->data) &&
($this->data[$this->N] == ' ' ||
$this->data[$this->N] == "\t" ||
$this->data[$this->N] == "\n")) {
if ($this->data[$this->N] == "\n") {
$this->line++;
}
$this->N++; // skip all whitespace
}
if ($this->N >= strlen($this->data)) {
$this->error('unexpected end of input, expecting rule declaration');
}
if ($this->data[$this->N] == '*' && $this->data[$this->N + 1] == '/') {
$this->state = 'StartNonDeclare';
$this->value = '*/';
$this->N += 2;
$this->token = self::COMMENTEND;
return true;
}
if (preg_match('/^%([a-z]+)/', substr($this->data, $this->N), $token)) {
$this->value = $token[1];
$this->N += strlen($token[1]) + 1;
$this->state = 'DeclarePIRule';
$this->token = self::PI;
return true;
}
if ($this->data[$this->N] == "{") {
return $this->lexCode();
}
if ($this->data[$this->N] == '"') {
return $this->lexQuote();
}
if (preg_match('/^[a-zA-Z_]+/', substr($this->data, $this->N), $token)) {
$this->value = $token[0];
$this->N += strlen($token[0]);
$this->token = self::SUBPATTERN;
return true;
} else {
$this->error('expecting token rule (quotes or sub-patterns)');
return false;
}
}
/**
* lexer for php code blocks
* @return boolean
*/
private function lexCode()
{
$cp = $this->N + 1;
for ($level = 1; $cp < strlen($this->data) && ($level > 1 || $this->data[$cp] != '}'); $cp++) {
if ($this->data[$cp] == '{') {
$level++;
} elseif ($this->data[$cp] == '}') {
$level--;
} elseif ($this->data[$cp] == '/' && $this->data[$cp + 1] == '/') {
/* Skip C++ style comments */
$cp += 2;
$z = strpos($this->data, "\n", $cp);
if ($z === false) {
$cp = strlen($this->data);
break;
}
$cp = $z;
} elseif ($this->data[$cp] == "'" || $this->data[$cp] == '"') {
/* String a character literals */
$startchar = $this->data[$cp];
$prevc = 0;
for ($cp++; $cp < strlen($this->data) && ($this->data[$cp] != $startchar || $prevc === '\\'); $cp++) {
if ($prevc === '\\') {
$prevc = 0;
} else {
$prevc = $this->data[$cp];
}
}
}
}
if ($cp >= strlen($this->data)) {
$this->error("PHP code starting on this line is not terminated before the end of the file.");
$this->error++;
return false;
} else {
$this->value = substr($this->data, $this->N + 1, $cp - $this->N - 1);
$this->token = self::CODE;
$this->N = $cp + 1;
return true;
}
}
/**
* Primary scanner
*
* In addition to lexing, this properly increments the line number of lexing.
* This calls the proper sub-lexer based on the parser state
* @param unknown_type $parser
* @return unknown
*/
public function advance($parser)
{
if ($this->N >= strlen($this->data)) {
return false;
}
if ($this->{'lex' . $this->state}()) {
$this->line += substr_count($this->value, "\n");
return true;
}
return false;
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,768 @@
%name PHP_LexerGenerator_Parser
%declare_class {class PHP_LexerGenerator_Parser}
%include {
/* ?><?php {//*/
/**
* PHP_LexerGenerator, a php 5 lexer generator.
*
* This lexer generator translates a file in a format similar to
* re2c ({@link http://re2c.org}) and translates it into a PHP 5-based lexer
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_LexerGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_LexerGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: Parser.y,v 1.8 2007/08/18 23:50:28 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
* For regular expression validation
*/
require_once 'PHP/LexerGenerator/Regex/Lexer.php';
require_once 'PHP/LexerGenerator/Regex/Parser.php';
require_once 'PHP/LexerGenerator/Exception.php';
/**
* Token parser for plex files.
*
* This parser converts tokens pulled from {@link PHP_LexerGenerator_Lexer}
* into abstract patterns and rules, then creates the output file
* @package PHP_LexerGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version 0.3.4
* @since Class available since Release 0.1.0
*/
}
%syntax_error {
echo "Syntax Error on line " . $this->lex->line . ": token '" .
$this->lex->value . "' while parsing rule:";
foreach ($this->yystack as $entry) {
echo $this->tokenName($entry->major) . ' ';
}
foreach ($this->yy_get_expected_tokens($yymajor) as $token) {
$expect[] = self::$yyTokenName[$token];
}
throw new Exception('Unexpected ' . $this->tokenName($yymajor) . '(' . $TOKEN
. '), expected one of: ' . implode(',', $expect));
}
%include_class {
private $patterns;
private $out;
private $lex;
private $input;
private $counter;
private $token;
private $value;
private $line;
private $matchlongest;
private $_regexLexer;
private $_regexParser;
private $_patternIndex = 0;
public $transTable = array(
1 => self::PHPCODE,
2 => self::COMMENTSTART,
3 => self::COMMENTEND,
4 => self::QUOTE,
5 => self::PATTERN,
6 => self::CODE,
7 => self::SUBPATTERN,
8 => self::PI,
);
function __construct($outfile, $lex)
{
$this->out = fopen($outfile, 'wb');
if (!$this->out) {
throw new Exception('unable to open lexer output file "' . $outfile . '"');
}
$this->lex = $lex;
$this->_regexLexer = new PHP_LexerGenerator_Regex_Lexer('');
$this->_regexParser = new PHP_LexerGenerator_Regex_Parser($this->_regexLexer);
}
function doLongestMatch($rules, $statename, $ruleindex)
{
fwrite($this->out, '
if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
return false; // end of input
}
do {
$rules = array(');
foreach ($rules as $rule) {
fwrite($this->out, '
\'/^' . $rule['pattern'] . '/\',');
}
fwrite($this->out, '
);
$match = false;
foreach ($rules as $index => $rule) {
if (preg_match($rule, substr(' . $this->input . ', ' .
$this->counter . '), $yymatches)) {
if ($match) {
if (strlen($yymatches[0]) > strlen($match[0][0])) {
$match = array($yymatches, $index); // matches, token
}
} else {
$match = array($yymatches, $index);
}
}
}
if (!$match) {
throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' .
\': \' . ' . $this->input . '[' . $this->counter . ']);
}
' . $this->token . ' = $match[1];
' . $this->value . ' = $match[0][0];
$yysubmatches = $match[0];
array_shift($yysubmatches);
if (!$yysubmatches) {
$yysubmatches = array();
}
$r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches);
if ($r === null) {
' . $this->counter . ' += strlen($this->value);
' . $this->line . ' += substr_count(' . $this->value . ', "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
' . $this->counter . ' += strlen($this->value);
' . $this->line . ' += substr_count(' . $this->value . ', "\n");
if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
return false; // end of input
}
// skip this token
continue;
} else {');
fwrite($this->out, '
$yy_yymore_patterns = array_slice($rules, $this->token, true);
// yymore is needed
do {
if (!isset($yy_yymore_patterns[' . $this->token . '])) {
throw new Exception(\'cannot do yymore for the last token\');
}
$match = false;
foreach ($yy_yymore_patterns[' . $this->token . '] as $index => $rule) {
if (preg_match(\'/\' . $rule . \'/\',
substr(' . $this->input . ', ' . $this->counter . '), $yymatches)) {
$yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns
if ($match) {
if (strlen($yymatches[0]) > strlen($match[0][0])) {
$match = array($yymatches, $index); // matches, token
}
} else {
$match = array($yymatches, $index);
}
}
}
if (!$match) {
throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' .
\': \' . ' . $this->input . '[' . $this->counter . ']);
}
' . $this->token . ' = $match[1];
' . $this->value . ' = $match[0][0];
$yysubmatches = $match[0];
array_shift($yysubmatches);
if (!$yysubmatches) {
$yysubmatches = array();
}
' . $this->line . ' += substr_count(' . $this->value . ', "\n");
$r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}();
} while ($r !== null || !$r);
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} else {
// accept
' . $this->counter . ' += strlen($this->value);
' . $this->line . ' += substr_count(' . $this->value . ', "\n");
return true;
}
}
} while (true);
');
}
function doFirstMatch($rules, $statename, $ruleindex)
{
$patterns = array();
$pattern = '/';
$ruleMap = array();
$tokenindex = array();
$actualindex = 1;
$i = 0;
foreach ($rules as $rule) {
$ruleMap[$i++] = $actualindex;
$tokenindex[$actualindex] = $rule['subpatterns'];
$actualindex += $rule['subpatterns'] + 1;
$patterns[] = '^(' . $rule['pattern'] . ')';
}
$tokencount = $tokenindex;
$tokenindex = var_export($tokenindex, true);
$tokenindex = explode("\n", $tokenindex);
// indent for prettiness
$tokenindex = implode("\n ", $tokenindex);
$pattern .= implode('|', $patterns);
$pattern .= '/';
fwrite($this->out, '
$tokenMap = ' . $tokenindex . ';
if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
return false; // end of input
}
');
fwrite($this->out, '$yy_global_pattern = "' .
$pattern . '";' . "\n");
fwrite($this->out, '
do {
if (preg_match($yy_global_pattern, substr(' . $this->input . ', ' .
$this->counter .
'), $yymatches)) {
$yysubmatches = $yymatches;
$yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns
if (!count($yymatches)) {
throw new Exception(\'Error: lexing failed because a rule matched\' .
\'an empty string. Input "\' . substr(' . $this->input . ',
' . $this->counter . ', 5) . \'... state ' . $statename . '\');
}
next($yymatches); // skip global match
' . $this->token . ' = key($yymatches); // token number
if ($tokenMap[' . $this->token . ']) {
// extract sub-patterns for passing to lex function
$yysubmatches = array_slice($yysubmatches, ' . $this->token . ' + 1,
$tokenMap[' . $this->token . ']);
} else {
$yysubmatches = array();
}
' . $this->value . ' = current($yymatches); // token value
$r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches);
if ($r === null) {
' . $this->counter . ' += strlen($this->value);
' . $this->line . ' += substr_count(' . $this->value . ', "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
' . $this->counter . ' += strlen($this->value);
' . $this->line . ' += substr_count(' . $this->value . ', "\n");
if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
return false; // end of input
}
// skip this token
continue;
} else {');
fwrite($this->out, ' $yy_yymore_patterns = array(' . "\n");
$extra = 0;
for($i = 0; count($patterns); $i++) {
unset($patterns[$i]);
$extra += $tokencount[0];
array_shift($tokencount);
fwrite($this->out, ' ' . $ruleMap[$i] . ' => array(' . $extra . ', "' .
implode('|', $patterns) . "\"),\n");
}
fwrite($this->out, ' );' . "\n");
fwrite($this->out, '
// yymore is needed
do {
if (!strlen($yy_yymore_patterns[' . $this->token . '][1])) {
throw new Exception(\'cannot do yymore for the last token\');
}
$yysubmatches = array();
if (preg_match(\'/\' . $yy_yymore_patterns[' . $this->token . '][1] . \'/\',
substr(' . $this->input . ', ' . $this->counter . '), $yymatches)) {
$yysubmatches = $yymatches;
$yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns
next($yymatches); // skip global match
' . $this->token . ' += key($yymatches) + $yy_yymore_patterns[' . $this->token . '][0]; // token number
' . $this->value . ' = current($yymatches); // token value
' . $this->line . ' = substr_count(' . $this->value . ', "\n");
if ($tokenMap[' . $this->token . ']) {
// extract sub-patterns for passing to lex function
$yysubmatches = array_slice($yysubmatches, ' . $this->token . ' + 1,
$tokenMap[' . $this->token . ']);
} else {
$yysubmatches = array();
}
}
$r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches);
} while ($r !== null && !is_bool($r));
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
' . $this->counter . ' += strlen($this->value);
' . $this->line . ' += substr_count(' . $this->value . ', "\n");
if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
return false; // end of input
}
// skip this token
continue;
} else {
// accept
' . $this->counter . ' += strlen($this->value);
' . $this->line . ' += substr_count(' . $this->value . ', "\n");
return true;
}
}
} else {
throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' .
\': \' . ' . $this->input . '[' . $this->counter . ']);
}
break;
} while (true);
');
}
function outputRules($rules, $statename)
{
static $ruleindex = 1;
if (!$statename) {
$statename = $ruleindex;
}
fwrite($this->out, '
function yylex' . $ruleindex . '()
{');
if ($this->matchlongest) {
$ruleMap = array();
foreach ($rules as $i => $rule) {
$ruleMap[$i] = $i;
}
$this->doLongestMatch($rules, $statename, $ruleindex);
} else {
$ruleMap = array();
$actualindex = 1;
$i = 0;
foreach ($rules as $rule) {
$ruleMap[$i++] = $actualindex;
$actualindex += $rule['subpatterns'] + 1;
}
$this->doFirstMatch($rules, $statename, $ruleindex);
}
fwrite($this->out, '
} // end function
');
if (is_string($statename)) {
fwrite($this->out, '
const ' . $statename . ' = ' . $ruleindex . ';
');
}
foreach ($rules as $i => $rule) {
fwrite($this->out, ' function yy_r' . $ruleindex . '_' . $ruleMap[$i] . '($yy_subpatterns)
{
' . $rule['code'] .
' }
');
}
$ruleindex++; // for next set of rules
}
function error($msg)
{
echo 'Error on line ' . $this->lex->line . ': ' , $msg;
}
function _validatePattern($pattern, $update = false)
{
$this->_regexLexer->reset($pattern, $this->lex->line);
$this->_regexParser->reset($this->_patternIndex, $update);
try {
while ($this->_regexLexer->yylex()) {
$this->_regexParser->doParse(
$this->_regexLexer->token, $this->_regexLexer->value);
}
$this->_regexParser->doParse(0, 0);
} catch (PHP_LexerGenerator_Exception $e) {
$this->error($e->getMessage());
throw new PHP_LexerGenerator_Exception('Invalid pattern "' . $pattern . '"');
}
return $this->_regexParser->result;
}
}
start ::= lexfile.
lexfile ::= declare rules(B). {
fwrite($this->out, '
private $_yy_state = 1;
private $_yy_stack = array();
function yylex()
{
return $this->{\'yylex\' . $this->_yy_state}();
}
function yypushstate($state)
{
array_push($this->_yy_stack, $this->_yy_state);
$this->_yy_state = $state;
}
function yypopstate()
{
$this->_yy_state = array_pop($this->_yy_stack);
}
function yybegin($state)
{
$this->_yy_state = $state;
}
');
foreach (B as $rule) {
$this->outputRules($rule['rules'], $rule['statename']);
if ($rule['code']) {
fwrite($this->out, $rule['code']);
}
}
}
lexfile ::= declare(D) PHPCODE(B) rules(C). {
fwrite($this->out, '
private $_yy_state = 1;
private $_yy_stack = array();
function yylex()
{
return $this->{\'yylex\' . $this->_yy_state}();
}
function yypushstate($state)
{
array_push($this->_yy_stack, $this->_yy_state);
$this->_yy_state = $state;
}
function yypopstate()
{
$this->_yy_state = array_pop($this->_yy_stack);
}
function yybegin($state)
{
$this->_yy_state = $state;
}
');
if (strlen(B)) {
fwrite($this->out, B);
}
foreach (C as $rule) {
$this->outputRules($rule['rules'], $rule['statename']);
if ($rule['code']) {
fwrite($this->out, $rule['code']);
}
}
}
lexfile ::= PHPCODE(B) declare(D) rules(C). {
if (strlen(B)) {
fwrite($this->out, B);
}
fwrite($this->out, '
private $_yy_state = 1;
private $_yy_stack = array();
function yylex()
{
return $this->{\'yylex\' . $this->_yy_state}();
}
function yypushstate($state)
{
array_push($this->_yy_stack, $this->_yy_state);
$this->_yy_state = $state;
}
function yypopstate()
{
$this->_yy_state = array_pop($this->_yy_stack);
}
function yybegin($state)
{
$this->_yy_state = $state;
}
');
foreach (C as $rule) {
$this->outputRules($rule['rules'], $rule['statename']);
if ($rule['code']) {
fwrite($this->out, $rule['code']);
}
}
}
lexfile ::= PHPCODE(A) declare(D) PHPCODE(B) rules(C). {
if (strlen(A)) {
fwrite($this->out, A);
}
fwrite($this->out, '
private $_yy_state = 1;
private $_yy_stack = array();
function yylex()
{
return $this->{\'yylex\' . $this->_yy_state}();
}
function yypushstate($state)
{
array_push($this->_yy_stack, $this->_yy_state);
$this->_yy_state = $state;
}
function yypopstate()
{
$this->_yy_state = array_pop($this->_yy_stack);
}
function yybegin($state)
{
$this->_yy_state = $state;
}
');
if (strlen(B)) {
fwrite($this->out, B);
}
foreach (C as $rule) {
$this->outputRules($rule['rules'], $rule['statename']);
if ($rule['code']) {
fwrite($this->out, $rule['code']);
}
}
}
declare(A) ::= COMMENTSTART declarations(B) COMMENTEND. {
A = B;
$this->patterns = B['patterns'];
$this->_patternIndex = 1;
}
declarations(A) ::= processing_instructions(B) pattern_declarations(C). {
$expected = array(
'counter' => true,
'input' => true,
'token' => true,
'value' => true,
'line' => true,
);
foreach (B as $pi) {
if (isset($expected[$pi['pi']])) {
unset($expected[$pi['pi']]);
continue;
}
if (count($expected)) {
throw new Exception('Processing Instructions "' .
implode(', ', array_keys($expected)) . '" must be defined');
}
}
$expected = array(
'counter' => true,
'input' => true,
'token' => true,
'value' => true,
'line' => true,
'matchlongest' => true,
);
foreach (B as $pi) {
if (isset($expected[$pi['pi']])) {
$this->{$pi['pi']} = $pi['definition'];
if ($pi['pi'] == 'matchlongest') {
$this->matchlongest = true;
}
continue;
}
$this->error('Unknown processing instruction %' . $pi['pi'] .
', should be one of "' . implode(', ', array_keys($expected)) . '"');
}
A = array('patterns' => C, 'pis' => B);
$this->_patternIndex = 1;
}
processing_instructions(A) ::= PI(B) SUBPATTERN(C). {
A = array(array('pi' => B, 'definition' => C));
}
processing_instructions(A) ::= PI(B) CODE(C). {
A = array(array('pi' => B, 'definition' => C));
}
processing_instructions(A) ::= processing_instructions(P) PI(B) SUBPATTERN(C). {
A = P;
A[] = array('pi' => B, 'definition' => C);
}
processing_instructions(A) ::= processing_instructions(P) PI(B) CODE(C). {
A = P;
A[] = array('pi' => B, 'definition' => C);
}
pattern_declarations(A) ::= PATTERN(B) subpattern(C). {
A = array(B => C);
// reset internal indicator of where we are in a pattern
$this->_patternIndex = 0;
}
pattern_declarations(A) ::= pattern_declarations(B) PATTERN(C) subpattern(D). {
A = B;
if (isset(A[C])) {
throw new Exception('Pattern "' . C . '" is already defined as "' .
A[C] . '", cannot redefine as "' . D->string . '"');
}
A[C] = D;
// reset internal indicator of where we are in a pattern declaration
$this->_patternIndex = 0;
}
rules(A) ::= COMMENTSTART rule(B) COMMENTEND. {
A = array(array('rules' => B, 'code' => '', 'statename' => ''));
}
rules(A) ::= COMMENTSTART PI(P) SUBPATTERN(S) rule(B) COMMENTEND. {
if (P != 'statename') {
throw new Exception('Error: only %statename processing instruction ' .
'is allowed in rule sections');
}
A = array(array('rules' => B, 'code' => '', 'statename' => S));
}
rules(A) ::= COMMENTSTART rule(B) COMMENTEND PHPCODE(C). {
A = array(array('rules' => B, 'code' => C, 'statename' => ''));
}
rules(A) ::= COMMENTSTART PI(P) SUBPATTERN(S) rule(B) COMMENTEND PHPCODE(C). {
if (P != 'statename') {
throw new Exception('Error: only %statename processing instruction ' .
'is allowed in rule sections');
}
A = array(array('rules' => B, 'code' => C, 'statename' => S));
$this->_patternIndex = 1;
}
rules(A) ::= reset_rules(R) rule(B) COMMENTEND. {
A = R;
A[] = array('rules' => B, 'code' => '', 'statename' => '');
$this->_patternIndex = 1;
}
rules(A) ::= reset_rules(R) PI(P) SUBPATTERN(S) rule(B) COMMENTEND. {
if (P != 'statename') {
throw new Exception('Error: only %statename processing instruction ' .
'is allowed in rule sections');
}
A = R;
A[] = array('rules' => B, 'code' => '', 'statename' => S);
}
rules(A) ::= reset_rules(R) rule(B) COMMENTEND PHPCODE(C). {
A = R;
A[] = array('rules' => B, 'code' => C, 'statename' => '');
}
rules(A) ::= reset_rules(R) PI(P) SUBPATTERN(S) rule(B) COMMENTEND PHPCODE(C). {
if (P != 'statename') {
throw new Exception('Error: only %statename processing instruction ' .
'is allowed in rule sections');
}
A = R;
A[] = array('rules' => B, 'code' => C, 'statename' => S);
}
reset_rules(A) ::= rules(R) COMMENTSTART. {
A = R;
$this->_patternIndex = 1;
}
rule(A) ::= rule_subpattern(B) CODE(C). {
$name = B[1];
B = B[0];
B = $this->_validatePattern(B);
$this->_patternIndex += B['subpatterns'] + 1;
if (@preg_match('/' . str_replace('/', '\\/', B['pattern']) . '/', '')) {
$this->error('Rule "' . $name . '" can match the empty string, this will break lexing');
}
A = array(array('pattern' => str_replace('/', '\\/', B->string), 'code' => C, 'subpatterns' => B['subpatterns']));
}
rule(A) ::= rule(R) rule_subpattern(B) CODE(C).{
A = R;
$name = B[1];
B = B[0];
B = $this->_validatePattern(B);
$this->_patternIndex += B['subpatterns'] + 1;
if (@preg_match('/' . str_replace('/', '\\/', B['pattern']) . '/', '')) {
$this->error('Rule "' . $name . '" can match the empty string, this will break lexing');
}
A[] = array('pattern' => str_replace('/', '\\/', B->string), 'code' => C, 'subpatterns' => B['subpatterns']);
}
rule_subpattern(A) ::= QUOTE(B). {
A = array(preg_quote(B, '/'), B);
}
rule_subpattern(A) ::= SUBPATTERN(B). {
if (!isset($this->patterns[B])) {
$this->error('Undefined pattern "' . B . '" used in rules');
throw new Exception('Undefined pattern "' . B . '" used in rules');
}
A = array($this->patterns[B], B);
}
rule_subpattern(A) ::= rule_subpattern(B) QUOTE(C). {
A = array(B[0] . preg_quote(C, '/'), B[1] . ' ' . C);
}
rule_subpattern(A) ::= rule_subpattern(B) SUBPATTERN(C). {
if (!isset($this->patterns[C])) {
$this->error('Undefined pattern "' . C . '" used in rules');
throw new Exception('Undefined pattern "' . C . '" used in rules');
}
A = array(B[0] . $this->patterns[C], B[1] . ' ' . C);
}
subpattern(A) ::= QUOTE(B). {
A = preg_quote(B, '/');
}
subpattern(A) ::= SUBPATTERN(B). {
// increment internal sub-pattern counter
// adjust back-references in pattern based on previous pattern
$test = $this->_validatePattern(B, true);
$this->_patternIndex += $test['subpatterns'];
A = $test['pattern'];
}
subpattern(A) ::= subpattern(B) QUOTE(C). {
A = B . preg_quote(C, '/');
}
subpattern(A) ::= subpattern(B) SUBPATTERN(C). {
// increment internal sub-pattern counter
// adjust back-references in pattern based on previous pattern
$test = $this->_validatePattern(C, true);
$this->_patternIndex += $test['subpatterns'];
A = B . $test['pattern'];
}

View File

@@ -0,0 +1,938 @@
<?php
require_once './LexerGenerator/Regex/Parser.php';
class PHP_LexerGenerator_Regex_Lexer
{
const MATCHSTART = PHP_LexerGenerator_Regex_Parser::MATCHSTART;
const MATCHEND = PHP_LexerGenerator_Regex_Parser::MATCHEND;
const CONTROLCHAR = PHP_LexerGenerator_Regex_Parser::CONTROLCHAR;
const OPENCHARCLASS = PHP_LexerGenerator_Regex_Parser::OPENCHARCLASS;
const FULLSTOP = PHP_LexerGenerator_Regex_Parser::FULLSTOP;
const TEXT = PHP_LexerGenerator_Regex_Parser::TEXT;
const BACKREFERENCE = PHP_LexerGenerator_Regex_Parser::BACKREFERENCE;
const OPENASSERTION = PHP_LexerGenerator_Regex_Parser::OPENASSERTION;
const COULDBEBACKREF = PHP_LexerGenerator_Regex_Parser::COULDBEBACKREF;
const NEGATE = PHP_LexerGenerator_Regex_Parser::NEGATE;
const HYPHEN = PHP_LexerGenerator_Regex_Parser::HYPHEN;
const CLOSECHARCLASS = PHP_LexerGenerator_Regex_Parser::CLOSECHARCLASS;
const BAR = PHP_LexerGenerator_Regex_Parser::BAR;
const MULTIPLIER = PHP_LexerGenerator_Regex_Parser::MULTIPLIER;
const INTERNALOPTIONS = PHP_LexerGenerator_Regex_Parser::INTERNALOPTIONS;
const COLON = PHP_LexerGenerator_Regex_Parser::COLON;
const OPENPAREN = PHP_LexerGenerator_Regex_Parser::OPENPAREN;
const CLOSEPAREN = PHP_LexerGenerator_Regex_Parser::CLOSEPAREN;
const PATTERNNAME = PHP_LexerGenerator_Regex_Parser::PATTERNNAME;
const POSITIVELOOKBEHIND = PHP_LexerGenerator_Regex_Parser::POSITIVELOOKBEHIND;
const NEGATIVELOOKBEHIND = PHP_LexerGenerator_Regex_Parser::NEGATIVELOOKBEHIND;
const POSITIVELOOKAHEAD = PHP_LexerGenerator_Regex_Parser::POSITIVELOOKAHEAD;
const NEGATIVELOOKAHEAD = PHP_LexerGenerator_Regex_Parser::NEGATIVELOOKAHEAD;
const ONCEONLY = PHP_LexerGenerator_Regex_Parser::ONCEONLY;
const COMMENT = PHP_LexerGenerator_Regex_Parser::COMMENT;
const RECUR = PHP_LexerGenerator_Regex_Parser::RECUR;
const ESCAPEDBACKSLASH = PHP_LexerGenerator_Regex_Parser::ESCAPEDBACKSLASH;
private $input;
private $N;
public $token;
public $value;
public $line;
function __construct($data)
{
$this->input = $data;
$this->N = 0;
}
function reset($data, $line)
{
$this->input = $data;
$this->N = 0;
// passed in from parent parser
$this->line = $line;
$this->yybegin(self::INITIAL);
}
private $_yy_state = 1;
private $_yy_stack = array();
function yylex()
{
return $this->{'yylex' . $this->_yy_state}();
}
function yypushstate($state)
{
array_push($this->_yy_stack, $this->_yy_state);
$this->_yy_state = $state;
}
function yypopstate()
{
$this->_yy_state = array_pop($this->_yy_stack);
}
function yybegin($state)
{
$this->_yy_state = $state;
}
function yylex1()
{
$tokenMap = array (
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 0,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
14 => 0,
15 => 0,
16 => 0,
17 => 0,
18 => 0,
19 => 0,
20 => 0,
21 => 0,
22 => 0,
23 => 0,
);
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
$yy_global_pattern = "/^(\\\\\\\\)|^([^[\\\\^$.|()?*+{}]+)|^(\\\\[][{}*.^$|?()+])|^(\\[)|^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)/";
do {
if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) {
$yysubmatches = $yymatches;
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
if (!count($yymatches)) {
throw new Exception('Error: lexing failed because a rule matched' .
'an empty string. Input "' . substr($this->input,
$this->N, 5) . '... state INITIAL');
}
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
if ($tokenMap[$this->token]) {
// extract sub-patterns for passing to lex function
$yysubmatches = array_slice($yysubmatches, $this->token + 1,
$tokenMap[$this->token]);
} else {
$yysubmatches = array();
}
$this->value = current($yymatches); // token value
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
if ($r === null) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
// skip this token
continue;
} else { $yy_yymore_patterns = array(
1 => "^([^[\\\\^$.|()?*+{}]+)|^(\\\\[][{}*.^$|?()+])|^(\\[)|^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
2 => "^(\\\\[][{}*.^$|?()+])|^(\\[)|^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
3 => "^(\\[)|^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
4 => "^(\\|)|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
5 => "^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
6 => "^(\\\\[0-9][0-9])|^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
7 => "^(\\\\[abBGcedDsSwW0C]|\\\\c\\\\)|^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
8 => "^(\\^)|^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
9 => "^(\\\\A)|^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
10 => "^(\\))|^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
11 => "^(\\$)|^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
12 => "^(\\*\\?|\\+\\?|[*?+]|\\{[0-9]+\\}|\\{[0-9]+,\\}|\\{[0-9]+,[0-9]+\\})|^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
13 => "^(\\\\[zZ])|^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
14 => "^(\\(\\?)|^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
15 => "^(\\()|^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
16 => "^(\\.)|^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
17 => "^(\\\\[1-9])|^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
18 => "^(\\\\p\\{\\^?..?\\}|\\\\P\\{..?\\}|\\\\X)|^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
19 => "^(\\\\p\\{C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
20 => "^(\\\\p\\{\\^C[cfnos]?|L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|S[ckmo]?|Z[lps]?\\})|^(\\\\p[CLMNPSZ])|^(\\\\)",
21 => "^(\\\\p[CLMNPSZ])|^(\\\\)",
22 => "^(\\\\)",
23 => "",
);
// yymore is needed
do {
if (!strlen($yy_yymore_patterns[$this->token])) {
throw new Exception('cannot do yymore for the last token');
}
if (preg_match($yy_yymore_patterns[$this->token],
substr($this->input, $this->N), $yymatches)) {
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
$this->value = current($yymatches); // token value
$this->line = substr_count($this->value, "\n");
}
$r = $this->{'yy_r1_' . $this->token}();
} while ($r !== null || !$r);
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} else {
// accept
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
return true;
}
}
} else {
throw new Exception('Unexpected input at line' . $this->line .
': ' . $this->input[$this->N]);
}
break;
} while (true);
} // end function
const INITIAL = 1;
function yy_r1_1($yy_subpatterns)
{
$this->token = self::ESCAPEDBACKSLASH;
}
function yy_r1_2($yy_subpatterns)
{
$this->token = self::TEXT;
}
function yy_r1_3($yy_subpatterns)
{
$this->token = self::CONTROLCHAR;
}
function yy_r1_4($yy_subpatterns)
{
$this->token = self::OPENCHARCLASS;
$this->yybegin(self::CHARACTERCLASSSTART);
}
function yy_r1_5($yy_subpatterns)
{
$this->token = self::BAR;
}
function yy_r1_6($yy_subpatterns)
{
$this->token = self::TEXT;
}
function yy_r1_7($yy_subpatterns)
{
$this->token = self::COULDBEBACKREF;
}
function yy_r1_8($yy_subpatterns)
{
$this->token = self::CONTROLCHAR;
}
function yy_r1_9($yy_subpatterns)
{
$this->token = self::MATCHSTART;
}
function yy_r1_10($yy_subpatterns)
{
$this->token = self::MATCHSTART;
}
function yy_r1_11($yy_subpatterns)
{
$this->token = self::CLOSEPAREN;
$this->yybegin(self::INITIAL);
}
function yy_r1_12($yy_subpatterns)
{
$this->token = self::MATCHEND;
}
function yy_r1_13($yy_subpatterns)
{
$this->token = self::MULTIPLIER;
}
function yy_r1_14($yy_subpatterns)
{
$this->token = self::MATCHEND;
}
function yy_r1_15($yy_subpatterns)
{
$this->token = self::OPENASSERTION;
$this->yybegin(self::ASSERTION);
}
function yy_r1_16($yy_subpatterns)
{
$this->token = self::OPENPAREN;
}
function yy_r1_17($yy_subpatterns)
{
$this->token = self::FULLSTOP;
}
function yy_r1_18($yy_subpatterns)
{
$this->token = self::BACKREFERENCE;
}
function yy_r1_19($yy_subpatterns)
{
$this->token = self::CONTROLCHAR;
}
function yy_r1_20($yy_subpatterns)
{
$this->token = self::CONTROLCHAR;
}
function yy_r1_21($yy_subpatterns)
{
$this->token = self::CONTROLCHAR;
}
function yy_r1_22($yy_subpatterns)
{
$this->token = self::CONTROLCHAR;
}
function yy_r1_23($yy_subpatterns)
{
return false;
}
function yylex2()
{
$tokenMap = array (
1 => 0,
2 => 0,
3 => 0,
);
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
$yy_global_pattern = "/^(\\^)|^(\\])|^(.)/";
do {
if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) {
$yysubmatches = $yymatches;
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
if (!count($yymatches)) {
throw new Exception('Error: lexing failed because a rule matched' .
'an empty string. Input "' . substr($this->input,
$this->N, 5) . '... state CHARACTERCLASSSTART');
}
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
if ($tokenMap[$this->token]) {
// extract sub-patterns for passing to lex function
$yysubmatches = array_slice($yysubmatches, $this->token + 1,
$tokenMap[$this->token]);
} else {
$yysubmatches = array();
}
$this->value = current($yymatches); // token value
$r = $this->{'yy_r2_' . $this->token}($yysubmatches);
if ($r === null) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
// skip this token
continue;
} else { $yy_yymore_patterns = array(
1 => "^(\\])|^(.)",
2 => "^(.)",
3 => "",
);
// yymore is needed
do {
if (!strlen($yy_yymore_patterns[$this->token])) {
throw new Exception('cannot do yymore for the last token');
}
if (preg_match($yy_yymore_patterns[$this->token],
substr($this->input, $this->N), $yymatches)) {
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
$this->value = current($yymatches); // token value
$this->line = substr_count($this->value, "\n");
}
$r = $this->{'yy_r2_' . $this->token}();
} while ($r !== null || !$r);
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} else {
// accept
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
return true;
}
}
} else {
throw new Exception('Unexpected input at line' . $this->line .
': ' . $this->input[$this->N]);
}
break;
} while (true);
} // end function
const CHARACTERCLASSSTART = 2;
function yy_r2_1($yy_subpatterns)
{
$this->token = self::NEGATE;
}
function yy_r2_2($yy_subpatterns)
{
$this->yybegin(self::CHARACTERCLASS);
$this->token = self::TEXT;
}
function yy_r2_3($yy_subpatterns)
{
$this->yybegin(self::CHARACTERCLASS);
return true;
}
function yylex3()
{
$tokenMap = array (
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 0,
9 => 0,
10 => 0,
11 => 0,
);
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
$yy_global_pattern = "/^(\\\\\\\\)|^(\\])|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)/";
do {
if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) {
$yysubmatches = $yymatches;
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
if (!count($yymatches)) {
throw new Exception('Error: lexing failed because a rule matched' .
'an empty string. Input "' . substr($this->input,
$this->N, 5) . '... state CHARACTERCLASS');
}
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
if ($tokenMap[$this->token]) {
// extract sub-patterns for passing to lex function
$yysubmatches = array_slice($yysubmatches, $this->token + 1,
$tokenMap[$this->token]);
} else {
$yysubmatches = array();
}
$this->value = current($yymatches); // token value
$r = $this->{'yy_r3_' . $this->token}($yysubmatches);
if ($r === null) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
// skip this token
continue;
} else { $yy_yymore_patterns = array(
1 => "^(\\])|^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)",
2 => "^(\\\\[frnt]|\\\\x[0-9a-fA-F][0-9a-fA-F]?|\\\\[0-7][0-7][0-7]|\\\\x\\{[0-9a-fA-F]+\\})|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)",
3 => "^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)",
4 => "^(\\\\[0-9][0-9])|^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)",
5 => "^(\\\\[1-9])|^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)",
6 => "^(\\\\[]\.\-\^])|^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)",
7 => "^(-(?!]))|^([^\-\\\\])|^(\\\\)|^(.)",
8 => "^([^\-\\\\])|^(\\\\)|^(.)",
9 => "^(\\\\)|^(.)",
10 => "^(.)",
11 => "",
);
// yymore is needed
do {
if (!strlen($yy_yymore_patterns[$this->token])) {
throw new Exception('cannot do yymore for the last token');
}
if (preg_match($yy_yymore_patterns[$this->token],
substr($this->input, $this->N), $yymatches)) {
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
$this->value = current($yymatches); // token value
$this->line = substr_count($this->value, "\n");
}
$r = $this->{'yy_r3_' . $this->token}();
} while ($r !== null || !$r);
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} else {
// accept
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
return true;
}
}
} else {
throw new Exception('Unexpected input at line' . $this->line .
': ' . $this->input[$this->N]);
}
break;
} while (true);
} // end function
const CHARACTERCLASS = 3;
function yy_r3_1($yy_subpatterns)
{
$this->token = self::ESCAPEDBACKSLASH;
}
function yy_r3_2($yy_subpatterns)
{
$this->yybegin(self::INITIAL);
$this->token = self::CLOSECHARCLASS;
}
function yy_r3_3($yy_subpatterns)
{
$this->token = self::TEXT;
}
function yy_r3_4($yy_subpatterns)
{
$this->token = self::TEXT;
}
function yy_r3_5($yy_subpatterns)
{
$this->token = self::COULDBEBACKREF;
}
function yy_r3_6($yy_subpatterns)
{
$this->token = self::BACKREFERENCE;
}
function yy_r3_7($yy_subpatterns)
{
$this->token = self::TEXT;
}
function yy_r3_8($yy_subpatterns)
{
$this->token = self::HYPHEN;
$this->yybegin(self::RANGE);
}
function yy_r3_9($yy_subpatterns)
{
$this->token = self::TEXT;
}
function yy_r3_10($yy_subpatterns)
{
return false; // ignore escaping of normal text
}
function yy_r3_11($yy_subpatterns)
{
$this->token = self::TEXT;
}
function yylex4()
{
$tokenMap = array (
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
);
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
$yy_global_pattern = "/^(\\\\\\\\)|^(\\\\\\])|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)/";
do {
if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) {
$yysubmatches = $yymatches;
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
if (!count($yymatches)) {
throw new Exception('Error: lexing failed because a rule matched' .
'an empty string. Input "' . substr($this->input,
$this->N, 5) . '... state RANGE');
}
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
if ($tokenMap[$this->token]) {
// extract sub-patterns for passing to lex function
$yysubmatches = array_slice($yysubmatches, $this->token + 1,
$tokenMap[$this->token]);
} else {
$yysubmatches = array();
}
$this->value = current($yymatches); // token value
$r = $this->{'yy_r4_' . $this->token}($yysubmatches);
if ($r === null) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
// skip this token
continue;
} else { $yy_yymore_patterns = array(
1 => "^(\\\\\\])|^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)",
2 => "^(\\\\[bacedDsSwW0C]|\\\\c\\\\|\\\\x\\{[0-9a-fA-F]+\\}|\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]?)|^(\\\\[0-9][0-9])|^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)",
3 => "^(\\\\[0-9][0-9])|^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)",
4 => "^(\\\\[1-9])|^([^\-\\\\])|^(\\\\)",
5 => "^([^\-\\\\])|^(\\\\)",
6 => "^(\\\\)",
7 => "",
);
// yymore is needed
do {
if (!strlen($yy_yymore_patterns[$this->token])) {
throw new Exception('cannot do yymore for the last token');
}
if (preg_match($yy_yymore_patterns[$this->token],
substr($this->input, $this->N), $yymatches)) {
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
$this->value = current($yymatches); // token value
$this->line = substr_count($this->value, "\n");
}
$r = $this->{'yy_r4_' . $this->token}();
} while ($r !== null || !$r);
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} else {
// accept
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
return true;
}
}
} else {
throw new Exception('Unexpected input at line' . $this->line .
': ' . $this->input[$this->N]);
}
break;
} while (true);
} // end function
const RANGE = 4;
function yy_r4_1($yy_subpatterns)
{
$this->token = self::ESCAPEDBACKSLASH;
}
function yy_r4_2($yy_subpatterns)
{
$this->token = self::TEXT;
$this->yybegin(self::CHARACTERCLASS);
}
function yy_r4_3($yy_subpatterns)
{
$this->token = self::TEXT;
$this->yybegin(self::CHARACTERCLASS);
}
function yy_r4_4($yy_subpatterns)
{
$this->token = self::COULDBEBACKREF;
}
function yy_r4_5($yy_subpatterns)
{
$this->token = self::BACKREFERENCE;
}
function yy_r4_6($yy_subpatterns)
{
$this->token = self::TEXT;
$this->yybegin(self::CHARACTERCLASS);
}
function yy_r4_7($yy_subpatterns)
{
return false; // ignore escaping of normal text
}
function yylex5()
{
$tokenMap = array (
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 0,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
);
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
$yy_global_pattern = "/^([imsxUX]+-[imsxUX]+|[imsxUX]+|-[imsxUX]+)|^(:)|^(\\))|^(P<[^>]+>)|^(<=)|^(<!)|^(=)|^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)/";
do {
if (preg_match($yy_global_pattern, substr($this->input, $this->N), $yymatches)) {
$yysubmatches = $yymatches;
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
if (!count($yymatches)) {
throw new Exception('Error: lexing failed because a rule matched' .
'an empty string. Input "' . substr($this->input,
$this->N, 5) . '... state ASSERTION');
}
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
if ($tokenMap[$this->token]) {
// extract sub-patterns for passing to lex function
$yysubmatches = array_slice($yysubmatches, $this->token + 1,
$tokenMap[$this->token]);
} else {
$yysubmatches = array();
}
$this->value = current($yymatches); // token value
$r = $this->{'yy_r5_' . $this->token}($yysubmatches);
if ($r === null) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
if ($this->N >= strlen($this->input)) {
return false; // end of input
}
// skip this token
continue;
} else { $yy_yymore_patterns = array(
1 => "^(:)|^(\\))|^(P<[^>]+>)|^(<=)|^(<!)|^(=)|^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)",
2 => "^(\\))|^(P<[^>]+>)|^(<=)|^(<!)|^(=)|^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)",
3 => "^(P<[^>]+>)|^(<=)|^(<!)|^(=)|^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)",
4 => "^(<=)|^(<!)|^(=)|^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)",
5 => "^(<!)|^(=)|^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)",
6 => "^(=)|^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)",
7 => "^(!)|^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)",
8 => "^(>)|^(\\(\\?)|^(#[^)]+)|^(R)|^(.)",
9 => "^(\\(\\?)|^(#[^)]+)|^(R)|^(.)",
10 => "^(#[^)]+)|^(R)|^(.)",
11 => "^(R)|^(.)",
12 => "^(.)",
13 => "",
);
// yymore is needed
do {
if (!strlen($yy_yymore_patterns[$this->token])) {
throw new Exception('cannot do yymore for the last token');
}
if (preg_match($yy_yymore_patterns[$this->token],
substr($this->input, $this->N), $yymatches)) {
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
$this->value = current($yymatches); // token value
$this->line = substr_count($this->value, "\n");
}
$r = $this->{'yy_r5_' . $this->token}();
} while ($r !== null || !$r);
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} else {
// accept
$this->N += strlen($this->value);
$this->line += substr_count($this->value, "\n");
return true;
}
}
} else {
throw new Exception('Unexpected input at line' . $this->line .
': ' . $this->input[$this->N]);
}
break;
} while (true);
} // end function
const ASSERTION = 5;
function yy_r5_1($yy_subpatterns)
{
$this->token = self::INTERNALOPTIONS;
}
function yy_r5_2($yy_subpatterns)
{
$this->token = self::COLON;
$this->yybegin(self::INITIAL);
}
function yy_r5_3($yy_subpatterns)
{
$this->token = self::CLOSEPAREN;
$this->yybegin(self::INITIAL);
}
function yy_r5_4($yy_subpatterns)
{
$this->token = self::PATTERNNAME;
$this->yybegin(self::INITIAL);
}
function yy_r5_5($yy_subpatterns)
{
$this->token = self::POSITIVELOOKBEHIND;
$this->yybegin(self::INITIAL);
}
function yy_r5_6($yy_subpatterns)
{
$this->token = self::NEGATIVELOOKBEHIND;
$this->yybegin(self::INITIAL);
}
function yy_r5_7($yy_subpatterns)
{
$this->token = self::POSITIVELOOKAHEAD;
$this->yybegin(self::INITIAL);
}
function yy_r5_8($yy_subpatterns)
{
$this->token = self::NEGATIVELOOKAHEAD;
$this->yybegin(self::INITIAL);
}
function yy_r5_9($yy_subpatterns)
{
$this->token = self::ONCEONLY;
$this->yybegin(self::INITIAL);
}
function yy_r5_10($yy_subpatterns)
{
$this->token = self::OPENASSERTION;
}
function yy_r5_11($yy_subpatterns)
{
$this->token = self::COMMENT;
$this->yybegin(self::INITIAL);
}
function yy_r5_12($yy_subpatterns)
{
$this->token = self::RECUR;
}
function yy_r5_13($yy_subpatterns)
{
$this->yybegin(self::INITIAL);
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
<?php
require_once './LexerGenerator.php';
$a = new PHP_LexerGenerator($_SERVER['argv'][1]);
?>

View File

@@ -0,0 +1,760 @@
<?php
/**
* PHP_ParserGenerator, a php 5 parser generator.
*
* This is a direct port of the Lemon parser generator, found at
* {@link http://www.hwaci.com/sw/lemon/}
*
* There are a few PHP-specific changes to the lemon parser generator.
*
* - %extra_argument is removed, as class constructor can be used to
* pass in extra information
* - %token_type and company are irrelevant in PHP, and so are removed
* - %declare_class is added to define the parser class name and any
* implements/extends information
* - %include_class is added to allow insertion of extra class information
* such as constants, a class constructor, etc.
*
* Other changes make the parser more robust, and also make reporting
* syntax errors simpler. Detection of expected tokens eliminates some
* problematic edge cases where an unexpected token could cause the parser
* to simply accept input.
*
* Otherwise, the file format is identical to the Lemon parser generator
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_ParserGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: ParserGenerator.php,v 1.2 2006/12/16 04:01:58 cellog Exp $
* @since File available since Release 0.1.0
*/
/**#@+
* Basic components of the parser generator
*/
require_once './ParserGenerator/Action.php';
require_once './ParserGenerator/ActionTable.php';
require_once './ParserGenerator/Config.php';
require_once './ParserGenerator/Data.php';
require_once './ParserGenerator/Symbol.php';
require_once './ParserGenerator/Rule.php';
require_once './ParserGenerator/Parser.php';
require_once './ParserGenerator/PropagationLink.php';
require_once './ParserGenerator/State.php';
/**#@-*/
/**
* The basic home class for the parser generator
*
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version 0.1.5
* @since Class available since Release 0.1.0
* @example Lempar.php
* @example examples/Parser.y Sample parser file format (PHP_LexerGenerator's parser)
* @example examples/Parser.php Sample parser file format PHP code (PHP_LexerGenerator's parser)
*/
class PHP_ParserGenerator
{
/**
* Set this to 1 to turn on debugging of Lemon's parsing of
* grammar files.
*/
const DEBUG = 0;
const MAXRHS = 1000;
const OPT_FLAG = 1, OPT_INT = 2, OPT_DBL = 3, OPT_STR = 4,
OPT_FFLAG = 5, OPT_FINT = 6, OPT_FDBL = 7, OPT_FSTR = 8;
public $azDefine = array();
private static $options = array(
'b' => array(
'type' => self::OPT_FLAG,
'arg' => 'basisflag',
'message' => 'Print only the basis in report.'
),
'c' => array(
'type' => self::OPT_FLAG,
'arg' => 'compress',
'message' => 'Don\'t compress the action table.'
),
'D' => array(
'type' => self::OPT_FSTR,
'arg' => 'handle_D_option',
'message' => 'Define an %ifdef macro.'
),
'g' => array(
'type' => self::OPT_FLAG,
'arg' => 'rpflag',
'message' => 'Print grammar without actions.'
),
'm' => array(
'type' => self::OPT_FLAG,
'arg' => 'mhflag',
'message' => 'Output a makeheaders compatible file'
),
'q' => array(
'type' => self::OPT_FLAG,
'arg' => 'quiet',
'message' => '(Quiet) Don\'t print the report file.'
),
's' => array(
'type' => self::OPT_FLAG,
'arg' => 'statistics',
'message' => 'Print parser stats to standard output.'
),
'x' => array(
'type' => self::OPT_FLAG,
'arg' => 'version',
'message' => 'Print the version number.'
)
);
private $basisflag = 0;
private $compress = 0;
private $rpflag = 0;
private $mhflag = 0;
private $quiet = 0;
private $statistics = 0;
private $version = 0;
private $size;
/**
* Process a flag command line argument.
* @param int
* @param array
* @return int
*/
function handleflags($i, $argv)
{
if (!isset($argv[1]) || !isset(self::$options[$argv[$i][1]])) {
throw new Exception('Command line syntax error: undefined option "' . $argv[$i] . '"');
}
$v = self::$options[$argv[$i][1]] == '-';
if (self::$options[$argv[$i][1]]['type'] == self::OPT_FLAG) {
$this->{self::$options[$argv[$i][1]]['arg']} = 1;
} elseif (self::$options[$argv[$i][1]]['type'] == self::OPT_FFLAG) {
$this->{self::$options[$argv[$i][1]]['arg']}($v);
} elseif (self::$options[$argv[$i][1]]['type'] == self::OPT_FSTR) {
$this->{self::$options[$argv[$i][1]]['arg']}(substr($v, 2));
} else {
throw new Exception('Command line syntax error: missing argument on switch: "' . $argv[$i] . '"');
}
return 0;
}
/**
* Process a command line switch which has an argument.
* @param int
* @param array
* @param array
* @return int
*/
function handleswitch($i, $argv)
{
$lv = 0;
$dv = 0.0;
$sv = $end = $cp = '';
$j; // int
$errcnt = 0;
$cp = strstr($argv[$i],'=');
if (!$cp) {
throw new Exception('INTERNAL ERROR: handleswitch passed bad argument, no "=" in arg');
}
$argv[$i] = substr($argv[$i], 0, strlen($argv[$i]) - strlen($cp));
if (!isset(self::$options[$argv[$i]])) {
throw new Exception('Command line syntax error: undefined option "' . $argv[$i] .
$cp . '"');
}
$cp = substr($cp, 1);
switch (self::$options[$argv[$i]]['type']) {
case self::OPT_FLAG:
case self::OPT_FFLAG:
throw new Exception('Command line syntax error: option requires an argument "' .
$argv[$i] . '=' . $cp . '"');
case self::OPT_DBL:
case self::OPT_FDBL:
$dv = (double) $cp;
break;
case self::OPT_INT:
case self::OPT_FINT:
$lv = (int) $cp;
break;
case self::OPT_STR:
case self::OPT_FSTR:
$sv = $cp;
break;
}
switch(self::$options[$argv[$i]]['type']) {
case self::OPT_FLAG:
case self::OPT_FFLAG:
break;
case self::OPT_DBL:
$this->{self::$options[$argv[$i]]['arg']} = $dv;
break;
case self::OPT_FDBL:
$this->{self::$options[$argv[$i]]['arg']}($dv);
break;
case self::OPT_INT:
$this->{self::$options[$argv[$i]]['arg']} = $lv;
break;
case self::OPT_FINT:
$this->{self::$options[$argv[$i]]['arg']}($lv);
break;
case self::OPT_STR:
$this->{self::$options[$argv[$i]]['arg']} = $sv;
break;
case self::OPT_FSTR:
$this->{self::$options[$argv[$i]]['arg']}($sv);
break;
}
return 0;
}
/**
* @param array arguments
* @param array valid options
* @return int
*/
function OptInit($a)
{
$errcnt = 0;
$argv = $a;
try {
if (is_array($argv) && count($argv) && self::$options) {
for($i = 1; $i < count($argv); $i++) {
if ($argv[$i][0] == '+' || $argv[$i][0] == '-') {
$errcnt += $this->handleflags($i, $argv);
} elseif (strstr($argv[$i],'=')) {
$errcnt += $this->handleswitch($i, $argv);
}
}
}
} catch (Exception $e) {
OptPrint();
echo $e->getMessage();
exit(1);
}
return 0;
}
/**
* Return the index of the N-th non-switch argument. Return -1
* if N is out of range.
* @param int
* @return int
*/
private function argindex($n, $a)
{
$dashdash = 0;
if (!is_array($a) || !count($a)) {
return -1;
}
for ($i=1; $i < count($a); $i++) {
if ($dashdash || !($a[$i][0] == '-' || $a[$i][0] == '+' ||
strchr($a[$i], '='))) {
if ($n == 0) {
return $i;
}
$n--;
}
if ($_SERVER['argv'][$i] == '--') {
$dashdash = 1;
}
}
return -1;
}
/**
* Return the value of the non-option argument as indexed by $i
*
* @param int
* @param array the value of $argv
* @return 0|string
*/
private function OptArg($i, $a)
{
if (-1 == ($ind = $this->argindex($i, $a))) {
return 0;
}
return $a[$ind];
}
/**
* @return int number of arguments
*/
function OptNArgs($a)
{
$cnt = $dashdash = 0;
if (is_array($a) && count($a)) {
for($i = 1; $i < count($a); $i++) {
if ($dashdash || !($a[$i][0] == '-' || $a[$i][0] == '+' ||
strchr($a[$i], '='))) {
$cnt++;
}
if ($a[$i] == "--") {
$dashdash = 1;
}
}
}
return $cnt;
}
/**
* Print out command-line options
*/
function OptPrint()
{
$max = 0;
foreach (self::$options as $label => $info) {
$len = strlen($label) + 1;
switch ($info['type']) {
case self::OPT_FLAG:
case self::OPT_FFLAG:
break;
case self::OPT_INT:
case self::OPT_FINT:
$len += 9; /* length of "<integer>" */
break;
case self::OPT_DBL:
case self::OPT_FDBL:
$len += 6; /* length of "<real>" */
break;
case self::OPT_STR:
case self::OPT_FSTR:
$len += 8; /* length of "<string>" */
break;
}
if ($len > $max) {
$max = $len;
}
}
foreach (self::$options as $label => $info) {
switch ($info['type']) {
case self::OPT_FLAG:
case self::OPT_FFLAG:
echo " -$label";
echo str_repeat(' ', $max - strlen($label));
echo " $info[message]\n";
break;
case self::OPT_INT:
case self::OPT_FINT:
echo " $label=<integer>" . str_repeat(' ', $max - strlen($label) - 9);
echo " $info[message]\n";
break;
case self::OPT_DBL:
case self::OPT_FDBL:
echo " $label=<real>" . str_repeat(' ', $max - strlen($label) - 6);
echo " $info[message]\n";
break;
case self::OPT_STR:
case self::OPT_FSTR:
echo " $label=<string>" . str_repeat(' ', $max - strlen($label) - 8);
echo " $info[message]\n";
break;
}
}
}
/**
* This routine is called with the argument to each -D command-line option.
* Add the macro defined to the azDefine array.
* @param string
*/
private function handle_D_option($z)
{
if ($a = strstr($z, '=')) {
$z = substr($a, 1); // strip first =
}
$this->azDefine[] = $z;
}
/**************** From the file "main.c" ************************************/
/*
** Main program file for the LEMON parser generator.
*/
/* The main program. Parse the command line and do it... */
function main()
{
$lem = new PHP_ParserGenerator_Data;
$this->OptInit($_SERVER['argv']);
if ($this->version) {
echo "Lemon version 1.0/PHP_ParserGenerator port version 0.1.5\n";
exit(0);
}
if ($this->OptNArgs($_SERVER['argv']) != 1) {
echo "Exactly one filename argument is required.\n";
exit(1);
}
$lem->errorcnt = 0;
/* Initialize the machine */
$lem->argv0 = $_SERVER['argv'][0];
$lem->filename = $this->OptArg(0, $_SERVER['argv']);
$a = pathinfo($lem->filename);
if (isset($a['extension'])) {
$ext = '.' . $a['extension'];
$lem->filenosuffix = substr($lem->filename, 0, strlen($lem->filename) - strlen($ext));
} else {
$lem->filenosuffix = $lem->filename;
}
$lem->basisflag = $this->basisflag;
$lem->has_fallback = 0;
$lem->nconflict = 0;
$lem->name = $lem->include_code = $lem->include_classcode = $lem->arg =
$lem->tokentype = $lem->start = 0;
$lem->vartype = 0;
$lem->stacksize = 0;
$lem->error = $lem->overflow = $lem->failure = $lem->accept = $lem->tokendest =
$lem->tokenprefix = $lem->outname = $lem->extracode = 0;
$lem->vardest = 0;
$lem->tablesize = 0;
PHP_ParserGenerator_Symbol::Symbol_new("$");
$lem->errsym = PHP_ParserGenerator_Symbol::Symbol_new("error");
/* Parse the input file */
$parser = new PHP_ParserGenerator_Parser($this);
$parser->Parse($lem);
if ($lem->errorcnt) {
exit($lem->errorcnt);
}
if ($lem->rule === 0) {
printf("Empty grammar.\n");
exit(1);
}
/* Count and index the symbols of the grammar */
$lem->nsymbol = PHP_ParserGenerator_Symbol::Symbol_count();
PHP_ParserGenerator_Symbol::Symbol_new("{default}");
$lem->symbols = PHP_ParserGenerator_Symbol::Symbol_arrayof();
for ($i = 0; $i <= $lem->nsymbol; $i++) {
$lem->symbols[$i]->index = $i;
}
usort($lem->symbols, array('PHP_ParserGenerator_Symbol', 'sortSymbols'));
for ($i = 0; $i <= $lem->nsymbol; $i++) {
$lem->symbols[$i]->index = $i;
}
// find the first lower-case symbol
for($i = 1; ord($lem->symbols[$i]->name[0]) < ord ('Z'); $i++);
$lem->nterminal = $i;
/* Generate a reprint of the grammar, if requested on the command line */
if ($this->rpflag) {
$this->Reprint();
} else {
/* Initialize the size for all follow and first sets */
$this->SetSize($lem->nterminal);
/* Find the precedence for every production rule (that has one) */
$lem->FindRulePrecedences();
/* Compute the lambda-nonterminals and the first-sets for every
** nonterminal */
$lem->FindFirstSets();
/* Compute all LR(0) states. Also record follow-set propagation
** links so that the follow-set can be computed later */
$lem->nstate = 0;
$lem->FindStates();
$lem->sorted = PHP_ParserGenerator_State::State_arrayof();
/* Tie up loose ends on the propagation links */
$lem->FindLinks();
/* Compute the follow set of every reducible configuration */
$lem->FindFollowSets();
/* Compute the action tables */
$lem->FindActions();
/* Compress the action tables */
if ($this->compress===0) {
$lem->CompressTables();
}
/* Reorder and renumber the states so that states with fewer choices
** occur at the end. */
$lem->ResortStates();
/* Generate a report of the parser generated. (the "y.output" file) */
if (!$this->quiet) {
$lem->ReportOutput();
}
/* Generate the source code for the parser */
$lem->ReportTable($this->mhflag);
/* Produce a header file for use by the scanner. (This step is
** omitted if the "-m" option is used because makeheaders will
** generate the file for us.) */
// if (!$this->mhflag) {
// $this->ReportHeader();
// }
}
if ($this->statistics) {
printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n",
$lem->nterminal, $lem->nsymbol - $lem->nterminal, $lem->nrule);
printf(" %d states, %d parser table entries, %d conflicts\n",
$lem->nstate, $lem->tablesize, $lem->nconflict);
}
if ($lem->nconflict) {
printf("%d parsing conflicts.\n", $lem->nconflict);
}
exit($lem->errorcnt + $lem->nconflict);
return ($lem->errorcnt + $lem->nconflict);
}
function SetSize($n)
{
$this->size = $n + 1;
}
/**
* Merge in a merge sort for a linked list
* Inputs:
* - a: A sorted, null-terminated linked list. (May be null).
* - b: A sorted, null-terminated linked list. (May be null).
* - cmp: A pointer to the comparison function.
* - offset: Offset in the structure to the "next" field.
*
* Return Value:
* A pointer to the head of a sorted list containing the elements
* of both a and b.
*
* Side effects:
* The "next" pointers for elements in the lists a and b are
* changed.
*/
static function merge($a, $b, $cmp, $offset)
{
if($a === 0) {
$head = $b;
} elseif ($b === 0) {
$head = $a;
} else {
if (call_user_func($cmp, $a, $b) < 0) {
$ptr = $a;
$a = $a->$offset;
} else {
$ptr = $b;
$b = $b->$offset;
}
$head = $ptr;
while ($a && $b) {
if (call_user_func($cmp, $a, $b) < 0) {
$ptr->$offset = $a;
$ptr = $a;
$a = $a->$offset;
} else {
$ptr->$offset = $b;
$ptr = $b;
$b = $b->$offset;
}
}
if ($a !== 0) {
$ptr->$offset = $a;
} else {
$ptr->$offset = $b;
}
}
return $head;
}
/*
** Inputs:
** list: Pointer to a singly-linked list of structures.
** next: Pointer to pointer to the second element of the list.
** cmp: A comparison function.
**
** Return Value:
** A pointer to the head of a sorted list containing the elements
** orginally in list.
**
** Side effects:
** The "next" pointers for elements in list are changed.
*/
#define LISTSIZE 30
static function msort($list, $next, $cmp)
{
if ($list === 0) {
return $list;
}
if ($list->$next === 0) {
return $list;
}
$set = array_fill(0, 30, 0);
while ($list) {
$ep = $list;
$list = $list->$next;
$ep->$next = 0;
for ($i = 0; $i < 29 && $set[$i] !== 0; $i++) {
$ep = self::merge($ep, $set[$i], $cmp, $next);
$set[$i] = 0;
}
$set[$i] = $ep;
}
$ep = 0;
for ($i = 0; $i < 30; $i++) {
if ($set[$i] !== 0) {
$ep = self::merge($ep, $set[$i], $cmp, $next);
}
}
return $ep;
}
/* Find a good place to break "msg" so that its length is at least "min"
** but no more than "max". Make the point as close to max as possible.
*/
static function findbreak($msg, $min, $max)
{
if ($min >= strlen($msg)) {
return strlen($msg);
}
for ($i = $spot = $min; $i <= $max && $i < strlen($msg); $i++) {
$c = $msg[$i];
if ($c == '-' && $i < $max - 1) {
$spot = $i + 1;
}
if ($c == ' ') {
$spot = $i;
}
}
return $spot;
}
static function ErrorMsg($filename, $lineno, $format)
{
/* Prepare a prefix to be prepended to every output line */
if ($lineno > 0) {
$prefix = sprintf("%20s:%d: ", $filename, $lineno);
} else {
$prefix = sprintf("%20s: ", $filename);
}
$prefixsize = strlen($prefix);
$availablewidth = 79 - $prefixsize;
/* Generate the error message */
$ap = func_get_args();
array_shift($ap); // $filename
array_shift($ap); // $lineno
array_shift($ap); // $format
$errmsg = vsprintf($format, $ap);
$linewidth = strlen($errmsg);
/* Remove trailing "\n"s from the error message. */
while ($linewidth > 0 && in_array($errmsg[$linewidth-1], array("\n", "\r"), true)) {
--$linewidth;
$errmsg = substr($errmsg, 0, strlen($errmsg) - 1);
}
/* Print the error message */
$base = 0;
$errmsg = str_replace(array("\r", "\n", "\t"), array(' ', ' ', ' '), $errmsg);
while (strlen($errmsg)) {
$end = $restart = self::findbreak($errmsg, 0, $availablewidth);
if (strlen($errmsg) <= 79 && $end < strlen($errmsg) && $end <= 79) {
$end = $restart = strlen($errmsg);
}
while (isset($errmsg[$restart]) && $errmsg[$restart] == ' ') {
$restart++;
}
printf("%s%.${end}s\n", $prefix, $errmsg);
$errmsg = substr($errmsg, $restart);
}
}
/**
* Duplicate the input file without comments and without actions
* on rules
*/
function Reprint()
{
printf("// Reprint of input file \"%s\".\n// Symbols:\n", $this->filename);
$maxlen = 10;
for ($i = 0; $i < $this->nsymbol; $i++) {
$sp = $this->symbols[$i];
$len = strlen($sp->name);
if ($len > $maxlen ) {
$maxlen = $len;
}
}
$ncolumns = 76 / ($maxlen + 5);
if ($ncolumns < 1) {
$ncolumns = 1;
}
$skip = ($this->nsymbol + $ncolumns - 1) / $ncolumns;
for ($i = 0; $i < $skip; $i++) {
print "//";
for ($j = $i; $j < $this->nsymbol; $j += $skip) {
$sp = $this->symbols[$j];
//assert( sp->index==j );
printf(" %3d %-${maxlen}.${maxlen}s", $j, $sp->name);
}
print "\n";
}
for ($rp = $this->rule; $rp; $rp = $rp->next) {
printf("%s", $rp->lhs->name);
/* if ($rp->lhsalias) {
printf("(%s)", $rp->lhsalias);
}*/
print " ::=";
for ($i = 0; $i < $rp->nrhs; $i++) {
$sp = $rp->rhs[$i];
printf(" %s", $sp->name);
if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) {
for ($j = 1; $j < $sp->nsubsym; $j++) {
printf("|%s", $sp->subsym[$j]->name);
}
}
/* if ($rp->rhsalias[$i]) {
printf("(%s)", $rp->rhsalias[$i]);
}*/
}
print ".";
if ($rp->precsym) {
printf(" [%s]", $rp->precsym->name);
}
/* if ($rp->code) {
print "\n " . $rp->code);
}*/
print "\n";
}
}
}
//$a = new PHP_ParserGenerator;
//$_SERVER['argv'] = array('lemon', '-s', '/development/lemon/PHP_Parser.y');
//$_SERVER['argv'] = array('lemon', '-s', '/development/File_ChessPGN/ChessPGN/Parser.y');
//$a->main();

View File

@@ -0,0 +1,240 @@
<?php
/**
* PHP_ParserGenerator, a php 5 parser generator.
*
* This is a direct port of the Lemon parser generator, found at
* {@link http://www.hwaci.com/sw/lemon/}
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_ParserGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: Action.php,v 1.2 2007/03/04 17:52:05 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
* Every shift or reduce operation is stored as one of the following objects.
*
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version 0.1.5
* @since Class available since Release 0.1.0
*/
class PHP_ParserGenerator_Action {
const SHIFT = 1,
ACCEPT = 2,
REDUCE = 3,
ERROR = 4,
/**
* Was a reduce, but part of a conflict
*/
CONFLICT = 5,
/**
* Was a shift. Precedence resolved conflict
*/
SH_RESOLVED = 6,
/**
* Was a reduce. Precedence resolved conflict
*/
RD_RESOLVED = 7,
/**
* Deleted by compression
* @see PHP_ParserGenerator::CompressTables()
*/
NOT_USED = 8;
/**
* The look-ahead symbol that triggers this action
* @var PHP_ParserGenerator_Symbol
*/
public $sp; /* The look-ahead symbol */
/**
* This defines the kind of action, and must be one
* of the class constants.
*
* - {@link PHP_ParserGenerator_Action::SHIFT}
* - {@link PHP_ParserGenerator_Action::ACCEPT}
* - {@link PHP_ParserGenerator_Action::REDUCE}
* - {@link PHP_ParserGenerator_Action::ERROR}
* - {@link PHP_ParserGenerator_Action::CONFLICT}
* - {@link PHP_ParserGenerator_Action::SH_RESOLVED}
* - {@link PHP_ParserGenerator_Action:: RD_RESOLVED}
* - {@link PHP_ParserGenerator_Action::NOT_USED}
*/
public $type;
/**
* The new state, if this is a shift,
* the parser rule index, if this is a reduce.
*
* @var PHP_ParserGenerator_State|PHP_ParserGenerator_Rule
*/
public $x;
/**
* The next action for this state.
* @var PHP_ParserGenerator_Action
*/
public $next;
/**
* Compare two actions
*
* This is used by {@link Action_sort()} to compare actions
*/
static function actioncmp(PHP_ParserGenerator_Action $ap1,
PHP_ParserGenerator_Action $ap2)
{
$rc = $ap1->sp->index - $ap2->sp->index;
if ($rc === 0) {
$rc = $ap1->type - $ap2->type;
}
if ($rc === 0) {
if ($ap1->type == self::SHIFT) {
if ($ap1->x->statenum != $ap2->x->statenum) {
throw new Exception('Shift conflict: ' . $ap1->sp->name .
' shifts both to state ' . $ap1->x->statenum . ' (rule ' .
$ap1->x->cfp->rp->lhs->name . ' on line ' .
$ap1->x->cfp->rp->ruleline . ') and to state ' .
$ap2->x->statenum . ' (rule ' .
$ap2->x->cfp->rp->lhs->name . ' on line ' .
$ap2->x->cfp->rp->ruleline . ')');
}
}
if ($ap1->type != self::REDUCE &&
$ap1->type != self::RD_RESOLVED &&
$ap1->type != self::CONFLICT) {
throw new Exception('action has not been processed: ' .
$ap1->sp->name . ' on line ' . $ap1->x->cfp->rp->ruleline .
', rule ' . $ap1->x->cfp->rp->lhs->name);
}
if ($ap2->type != self::REDUCE &&
$ap2->type != self::RD_RESOLVED &&
$ap2->type != self::CONFLICT) {
throw new Exception('action has not been processed: ' .
$ap2->sp->name . ' on line ' . $ap2->x->cfp->rp->ruleline .
', rule ' . $ap2->x->cfp->rp->lhs->name);
}
$rc = $ap1->x->index - $ap2->x->index;
}
return $rc;
}
function display($processed = false)
{
$map = array(
self::ACCEPT => 'ACCEPT',
self::CONFLICT => 'CONFLICT',
self::REDUCE => 'REDUCE',
self::SHIFT => 'SHIFT'
);
echo $map[$this->type] . ' for ' . $this->sp->name;
if ($this->type == self::REDUCE) {
echo ' - rule ' . $this->x->lhs->name . "<br>";
} elseif ($this->type == self::SHIFT) {
echo ' - state ' . $this->x->statenum . ', basis ' . $this->x->cfp->rp->lhs->name . "<br>";
} else {
echo "<br>";
}
}
/**
* create linked list of PHP_ParserGenerator_Actions
*
* @param PHP_ParserGenerator_Action|null
* @param int one of the class constants from PHP_ParserGenerator_Action
* @param PHP_ParserGenerator_Symbol
* @param PHP_ParserGenerator_State|PHP_ParserGenerator_Rule
*/
static function Action_add(&$app, $type, PHP_ParserGenerator_Symbol $sp, $arg)
{
$new = new PHP_ParserGenerator_Action;
$new->next = $app;
$app = $new;
$new->type = $type;
$new->sp = $sp;
$new->x = $arg;
echo ' Adding ';
$new->display();
}
/**
* Sort parser actions
* @see PHP_ParserGenerator_Data::FindActions()
*/
static function Action_sort(PHP_ParserGenerator_Action $ap)
{
$ap = PHP_ParserGenerator::msort($ap, 'next', array('PHP_ParserGenerator_Action', 'actioncmp'));
return $ap;
}
/**
* Print an action to the given file descriptor. Return FALSE if
* nothing was actually printed.
* @see PHP_ParserGenerator_Data::ReportOutput()
*/
function PrintAction($fp, $indent)
{
if (!$fp) {
$fp = STDOUT;
}
$result = 1;
switch ($this->type)
{
case self::SHIFT:
fprintf($fp, "%${indent}s shift %d", $this->sp->name, $this->x->statenum);
break;
case self::REDUCE:
fprintf($fp, "%${indent}s reduce %d", $this->sp->name, $this->x->index);
break;
case self::ACCEPT:
fprintf($fp, "%${indent}s accept", $this->sp->name);
break;
case self::ERROR:
fprintf($fp, "%${indent}s error", $this->sp->name);
break;
case self::CONFLICT:
fprintf($fp, "%${indent}s reduce %-3d ** Parsing conflict **", $this->sp->name, $this->x->index);
break;
case self::SH_RESOLVED:
case self::RD_RESOLVED:
case self::NOT_USED:
$result = 0;
break;
}
return $result;
}
}
?>

View File

@@ -0,0 +1,293 @@
<?php
/**
* PHP_ParserGenerator, a php 5 parser generator.
*
* This is a direct port of the Lemon parser generator, found at
* {@link http://www.hwaci.com/sw/lemon/}
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_ParserGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: ActionTable.php,v 1.1 2006/07/18 00:53:10 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
* The state of the yy_action table under construction is an instance of
* the following structure
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version 0.1.5
* @since Class available since Release 0.1.0
*/
class PHP_ParserGenerator_ActionTable
{
/**
* Number of used slots in {@link $aAction}
* @var int
*/
public $nAction = 0;
/**
* The $yy_action table under construction.
*
* Each entry is of format:
* <code>
* array(
* 'lookahead' => -1, // Value of the lookahead token (symbol index)
* 'action' => -1 // Action to take on the given lookahead (action index)
* );
* </code>
* @see PHP_ParserGenerator_Data::compute_action()
* @var array
*/
public $aAction =
array(array(
'lookahead' => -1,
'action' => -1
));
/**
* A single new transaction set.
*
* @see $aAction format of the internal array is described here
* @var array
*/
public $aLookahead =
array(array(
'lookahead' => 0,
'action' => 0
));
/**
* The smallest (minimum) value of any lookahead token in {@link $aLookahead}
*
* The lowest non-terminal is always introduced earlier in the parser file,
* and is therefore a more significant token.
* @var int
*/
public $mnLookahead = 0;
/**
* The action associated with the smallest lookahead token.
* @see $mnLookahead
* @var int
*/
public $mnAction = 0;
/**
* The largest (maximum) value of any lookahead token in {@link $aLookahead}
* @var int
*/
public $mxLookahead = 0;
/**
* The number of slots used in {@link $aLookahead}.
*
* This is the same as count($aLookahead), but there was no pressing reason
* to change this when porting from C.
* @see $mnLookahead
* @var int
*/
public $nLookahead = 0;
/**
* Add a new action to the current transaction set
* @param int
* @param int
*/
function acttab_action($lookahead, $action)
{
if ($this->nLookahead === 0) {
$this->aLookahead = array();
$this->mxLookahead = $lookahead;
$this->mnLookahead = $lookahead;
$this->mnAction = $action;
} else {
if ($this->mxLookahead < $lookahead) {
$this->mxLookahead = $lookahead;
}
if ($this->mnLookahead > $lookahead) {
$this->mnLookahead = $lookahead;
$this->mnAction = $action;
}
}
$this->aLookahead[$this->nLookahead] = array(
'lookahead' => $lookahead,
'action' => $action);
$this->nLookahead++;
}
/**
* Add the transaction set built up with prior calls to acttab_action()
* into the current action table. Then reset the transaction set back
* to an empty set in preparation for a new round of acttab_action() calls.
*
* Return the offset into the action table of the new transaction.
* @return int Return the offset that should be added to the lookahead in
* order to get the index into $yy_action of the action. This will be used
* in generation of $yy_ofst tables (reduce and shift)
* @throws Exception
*/
function acttab_insert()
{
if ($this->nLookahead <= 0) {
throw new Exception('nLookahead is not set up?');
}
/* Scan the existing action table looking for an offset where we can
** insert the current transaction set. Fall out of the loop when that
** offset is found. In the worst case, we fall out of the loop when
** i reaches $this->nAction, which means we append the new transaction set.
**
** i is the index in $this->aAction[] where $this->mnLookahead is inserted.
*/
for ($i = 0; $i < $this->nAction + $this->mnLookahead; $i++) {
if (!isset($this->aAction[$i])) {
$this->aAction[$i] = array(
'lookahead' => -1,
'action' => -1,
);
}
if ($this->aAction[$i]['lookahead'] < 0) {
for ($j = 0; $j < $this->nLookahead; $j++) {
if (!isset($this->aLookahead[$j])) {
$this->aLookahead[$j] = array(
'lookahead' => 0,
'action' => 0,
);
}
$k = $this->aLookahead[$j]['lookahead'] -
$this->mnLookahead + $i;
if ($k < 0) {
break;
}
if (!isset($this->aAction[$k])) {
$this->aAction[$k] = array(
'lookahead' => -1,
'action' => -1,
);
}
if ($this->aAction[$k]['lookahead'] >= 0) {
break;
}
}
if ($j < $this->nLookahead ) {
continue;
}
for ($j = 0; $j < $this->nAction; $j++) {
if (!isset($this->aAction[$j])) {
$this->aAction[$j] = array(
'lookahead' => -1,
'action' => -1,
);
}
if ($this->aAction[$j]['lookahead'] == $j +
$this->mnLookahead - $i) {
break;
}
}
if ($j == $this->nAction) {
break; /* Fits in empty slots */
}
} elseif ($this->aAction[$i]['lookahead'] == $this->mnLookahead) {
if ($this->aAction[$i]['action'] != $this->mnAction) {
continue;
}
for ($j = 0; $j < $this->nLookahead; $j++) {
$k = $this->aLookahead[$j]['lookahead'] -
$this->mnLookahead + $i;
if ($k < 0 || $k >= $this->nAction) {
break;
}
if (!isset($this->aAction[$k])) {
$this->aAction[$k] = array(
'lookahead' => -1,
'action' => -1,
);
}
if ($this->aLookahead[$j]['lookahead'] !=
$this->aAction[$k]['lookahead']) {
break;
}
if ($this->aLookahead[$j]['action'] !=
$this->aAction[$k]['action']) {
break;
}
}
if ($j < $this->nLookahead) {
continue;
}
$n = 0;
for ($j = 0; $j < $this->nAction; $j++) {
if (!isset($this->aAction[$j])) {
$this->aAction[$j] = array(
'lookahead' => -1,
'action' => -1,
);
}
if ($this->aAction[$j]['lookahead'] < 0) {
continue;
}
if ($this->aAction[$j]['lookahead'] == $j +
$this->mnLookahead - $i) {
$n++;
}
}
if ($n == $this->nLookahead) {
break; /* Same as a prior transaction set */
}
}
}
/* Insert transaction set at index i. */
for ($j = 0; $j < $this->nLookahead; $j++) {
if (!isset($this->aLookahead[$j])) {
$this->aLookahead[$j] = array(
'lookahead' => 0,
'action' => 0,
);
}
$k = $this->aLookahead[$j]['lookahead'] - $this->mnLookahead + $i;
$this->aAction[$k] = $this->aLookahead[$j];
if ($k >= $this->nAction) {
$this->nAction = $k + 1;
}
}
$this->nLookahead = 0;
$this->aLookahead = array();
/* Return the offset that is added to the lookahead in order to get the
** index into yy_action of the action */
return $i - $this->mnLookahead;
}
}
?>

View File

@@ -0,0 +1,570 @@
<?php
/**
* PHP_ParserGenerator, a php 5 parser generator.
*
* This is a direct port of the Lemon parser generator, found at
* {@link http://www.hwaci.com/sw/lemon/}
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_ParserGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: Config.php,v 1.1 2006/07/18 00:53:10 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
/** A configuration is a production rule of the grammar together with
* a mark (dot) showing how much of that rule has been processed so far.
*
* Configurations also contain a follow-set which is a list of terminal
* symbols which are allowed to immediately follow the end of the rule.
* Every configuration is recorded as an instance of the following class.
*
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version 0.1.5
* @since Class available since Release 0.1.0
*/
class PHP_ParserGenerator_Config {
const COMPLETE = 1;
const INCOMPLETE = 2;
/**
* The parser rule upon with the configuration is based.
*
* A parser rule is something like:
* <pre>
* blah ::= FOO bar.
* </pre>
* @var PHP_ParserGenerator_Rule
*/
public $rp;
/**
* The parse point.
*
* This is the index into the right-hand side of a rule that is
* represented by this configuration. In other words, possible
* dots for this rule:
*
* <pre>
* blah ::= FOO bar.
* </pre>
*
* are (represented by "[here]"):
*
* <pre>
* blah ::= [here] FOO bar.
* blah ::= FOO [here] bar.
* blah ::= FOO bar [here].
* </pre>
* @var int
*/
public $dot;
/**
* Follow-set for this configuration only
*
* This is the list of terminals and non-terminals that
* can follow this configuration.
* @var array
*/
public $fws;
/**
* Follow-set forward propagation links.
* @var PHP_ParserGenerator_PropagationLink
*/
public $fplp;
/**
* Follow-set backwards propagation links
* @var PHP_ParserGenerator_PropagationLink
*/
public $bplp;
/**
* State that contains this configuration
* @var PHP_ParserGenerator_State
*/
public $stp;
/* enum {
COMPLETE, /* The status is used during followset and
INCOMPLETE /* shift computations
} */
/**
* Status during followset and shift computations.
*
* One of PHP_ParserGenerator_Config::COMPLETE or
* PHP_ParserGenerator_Config::INCOMPLETE.
* @var int
*/
public $status;
/**
* Next configuration in the state.
*
* Index of next PHP_ParserGenerator_Config object.
* @var int
*/
public $next;
/**
* Index of the next basis configuration PHP_ParserGenerator_Config object
* @var int
*/
public $bp;
/**
* Top of the list of configurations for the current state.
* @var PHP_ParserGenerator_Config
*/
static public $current;
/**
* Last on the list of configurations for the current state.
* @var PHP_ParserGenerator_Config
*/
static public $currentend;
/**
* Top of the list of basis configurations for the current state.
* @var PHP_ParserGenerator_Config
*/
static public $basis;
/**
* Last on the list of basis configurations for the current state.
* @var PHP_ParserGenerator_Config
*/
static public $basisend;
/**
* Associative array representation of the linked list of configurations
* found in {@link $current}
*
* @var array
*/
static public $x4a = array();
/**
* Return a pointer to a new configuration
* @return PHP_ParserGenerator_Config
*/
private static function newconfig()
{
return new PHP_ParserGenerator_Config;
}
/**
* Display the current configuration for the .out file
*
* @param PHP_ParserGenerator_Config $cfp
* @see PHP_ParserGenerator_Data::ReportOutput()
*/
static function Configshow(PHP_ParserGenerator_Config $cfp)
{
$fp = fopen('php://output', 'w');
while ($cfp) {
if ($cfp->dot == $cfp->rp->nrhs) {
$buf = sprintf('(%d)', $cfp->rp->index);
fprintf($fp, ' %5s ', $buf);
} else {
fwrite($fp,' ');
}
$cfp->ConfigPrint($fp);
fwrite($fp, "\n");
if (0) {
//SetPrint(fp,cfp->fws,$this);
//PlinkPrint(fp,cfp->fplp,"To ");
//PlinkPrint(fp,cfp->bplp,"From");
}
$cfp = $cfp->next;
}
fwrite($fp, "\n");
fclose($fp);
}
/**
* Initialize the configuration list builder for a new state.
*/
static function Configlist_init()
{
self::$current = 0;
self::$currentend = &self::$current;
self::$basis = 0;
self::$basisend = &self::$basis;
self::$x4a = array();
}
/**
* Remove all data from the table.
*
* Pass each data to the function $f as it is removed if
* $f is a valid callback.
* @param callback|null
* @see Configtable_clear()
*/
static function Configtable_reset($f)
{
self::$current = 0;
self::$currentend = &self::$current;
self::$basis = 0;
self::$basisend = &self::$basis;
self::Configtable_clear(0);
}
/**
* Remove all data from the associative array representation
* of configurations.
*
* Pass each data to the function $f as it is removed if
* $f is a valid callback.
* @param callback|null
*/
static function Configtable_clear($f)
{
if (!count(self::$x4a)) {
return;
}
if ($f) {
for ($i = 0; $i < count(self::$x4a); $i++) {
call_user_func($f, self::$x4a[$i]->data);
}
}
self::$x4a = array();
}
/**
* Reset the configuration list builder for a new state.
* @see Configtable_clear()
*/
static function Configlist_reset()
{
self::Configtable_clear(0);
}
/**
* Add another configuration to the configuration list for this parser state.
* @param PHP_ParserGenerator_Rule the rule
* @param int Index into the right-hand side of the rule where the dot goes
* @return PHP_ParserGenerator_Config
*/
static function Configlist_add($rp, $dot)
{
$model = new PHP_ParserGenerator_Config;
$model->rp = $rp;
$model->dot = $dot;
$cfp = self::Configtable_find($model);
if ($cfp === 0) {
$cfp = self::newconfig();
$cfp->rp = $rp;
$cfp->dot = $dot;
$cfp->fws = array();
$cfp->stp = 0;
$cfp->fplp = $cfp->bplp = 0;
$cfp->next = 0;
$cfp->bp = 0;
self::$currentend = $cfp;
self::$currentend = &$cfp->next;
self::Configtable_insert($cfp);
}
return $cfp;
}
/**
* Add a basis configuration to the configuration list for this parser state.
*
* Basis configurations are the root for a configuration. This method also
* inserts the configuration into the regular list of configurations for this
* reason.
* @param PHP_ParserGenerator_Rule the rule
* @param int Index into the right-hand side of the rule where the dot goes
* @return PHP_ParserGenerator_Config
*/
static function Configlist_addbasis($rp, $dot)
{
$model = new PHP_ParserGenerator_Config;
$model->rp = $rp;
$model->dot = $dot;
$cfp = self::Configtable_find($model);
if ($cfp === 0) {
$cfp = self::newconfig();
$cfp->rp = $rp;
$cfp->dot = $dot;
$cfp->fws = array();
$cfp->stp = 0;
$cfp->fplp = $cfp->bplp = 0;
$cfp->next = 0;
$cfp->bp = 0;
self::$currentend = $cfp;
self::$currentend = &$cfp->next;
self::$basisend = $cfp;
self::$basisend = &$cfp->bp;
self::Configtable_insert($cfp);
}
return $cfp;
}
/**
* Compute the closure of the configuration list.
*
* This calculates all of the possible continuations of
* each configuration, ensuring that each state accounts
* for every configuration that could arrive at that state.
*/
static function Configlist_closure(PHP_ParserGenerator_Data $lemp)
{
for ($cfp = self::$current; $cfp; $cfp = $cfp->next) {
$rp = $cfp->rp;
$dot = $cfp->dot;
if ($dot >= $rp->nrhs) {
continue;
}
$sp = $rp->rhs[$dot];
if ($sp->type == PHP_ParserGenerator_Symbol::NONTERMINAL) {
if ($sp->rule === 0 && $sp !== $lemp->errsym) {
PHP_ParserGenerator::ErrorMsg($lemp->filename, $rp->line,
"Nonterminal \"%s\" has no rules.", $sp->name);
$lemp->errorcnt++;
}
for ($newrp = $sp->rule; $newrp; $newrp = $newrp->nextlhs) {
$newcfp = self::Configlist_add($newrp, 0);
for ($i = $dot + 1; $i < $rp->nrhs; $i++) {
$xsp = $rp->rhs[$i];
if ($xsp->type == PHP_ParserGenerator_Symbol::TERMINAL) {
$newcfp->fws[$xsp->index] = 1;
break;
} elseif ($xsp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) {
for ($k = 0; $k < $xsp->nsubsym; $k++) {
$newcfp->fws[$xsp->subsym[$k]->index] = 1;
}
break;
} else {
$a = array_diff_key($xsp->firstset, $newcfp->fws);
$newcfp->fws += $a;
if ($xsp->lambda === false) {
break;
}
}
}
if ($i == $rp->nrhs) {
PHP_ParserGenerator_PropagationLink::Plink_add($cfp->fplp, $newcfp);
}
}
}
}
}
/**
* Sort the configuration list
* @uses Configcmp()
*/
static function Configlist_sort()
{
$a = 0;
//self::Configshow(self::$current);
self::$current = PHP_ParserGenerator::msort(self::$current,'next', array('PHP_ParserGenerator_Config', 'Configcmp'));
//self::Configshow(self::$current);
self::$currentend = &$a;
self::$currentend = 0;
}
/**
* Sort the configuration list
* @uses Configcmp
*/
static function Configlist_sortbasis()
{
$a = 0;
self::$basis = PHP_ParserGenerator::msort(self::$current,'bp', array('PHP_ParserGenerator_Config', 'Configcmp'));
self::$basisend = &$a;
self::$basisend = 0;
}
/**
* Return a pointer to the head of the configuration list and
* reset the list
* @see $current
* @return PHP_ParserGenerator_Config
*/
static function Configlist_return()
{
$old = self::$current;
self::$current = 0;
self::$currentend = &self::$current;
return $old;
}
/**
* Return a pointer to the head of the basis list and
* reset the list
* @see $basis
* @return PHP_ParserGenerator_Config
*/
static function Configlist_basis()
{
$old = self::$basis;
self::$basis = 0;
self::$basisend = &self::$basis;
return $old;
}
/**
* Free all elements of the given configuration list
* @param PHP_ParserGenerator_Config
*/
static function Configlist_eat($cfp)
{
for(; $cfp; $cfp = $nextcfp){
$nextcfp = $cfp->next;
if ($cfp->fplp !=0) {
throw new Exception('fplp of configuration non-zero?');
}
if ($cfp->bplp !=0) {
throw new Exception('bplp of configuration non-zero?');
}
if ($cfp->fws) {
$cfp->fws = array();
}
}
}
/**
* Compare two configurations for sorting purposes.
*
* Configurations based on higher precedence rules
* (those earlier in the file) are chosen first. Two
* configurations that are the same rule are sorted by
* dot (see {@link $dot}), and those configurations
* with a dot closer to the left-hand side are chosen first.
* @param unknown_type $a
* @param unknown_type $b
* @return unknown
*/
static function Configcmp($a, $b)
{
$x = $a->rp->index - $b->rp->index;
if (!$x) {
$x = $a->dot - $b->dot;
}
return $x;
}
/**
* Print out information on this configuration.
*
* @param resource $fp
* @see PHP_ParserGenerator_Data::ReportOutput()
*/
function ConfigPrint($fp)
{
$rp = $this->rp;
fprintf($fp, "%s ::=", $rp->lhs->name);
for ($i = 0; $i <= $rp->nrhs; $i++) {
if ($i === $this->dot) {
fwrite($fp,' *');
}
if ($i === $rp->nrhs) {
break;
}
$sp = $rp->rhs[$i];
fprintf($fp,' %s', $sp->name);
if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) {
for ($j = 1; $j < $sp->nsubsym; $j++) {
fprintf($fp, '|%s', $sp->subsym[$j]->name);
}
}
}
}
/**
* Hash a configuration for the associative array {@link $x4a}
*/
private static function confighash(PHP_ParserGenerator_Config $a)
{
$h = 0;
$h = $h * 571 + $a->rp->index * 37 + $a->dot;
return $h;
}
/**
* Insert a new record into the array. Return TRUE if successful.
* Prior data with the same key is NOT overwritten
*/
static function Configtable_insert(PHP_ParserGenerator_Config $data)
{
$h = self::confighash($data);
if (isset(self::$x4a[$h])) {
$np = self::$x4a[$h];
} else {
$np = 0;
}
while ($np) {
if (self::Configcmp($np->data, $data) == 0) {
/* An existing entry with the same key is found. */
/* Fail because overwrite is not allows. */
return 0;
}
$np = $np->next;
}
/* Insert the new data */
$np = array('data' => $data, 'next' => 0, 'from' => 0);
$np = new PHP_ParserGenerator_StateNode;
$np->data = $data;
if (isset(self::$x4a[$h])) {
self::$x4a[$h]->from = $np->next;
$np->next = self::$x4a[$h];
}
$np->from = $np;
self::$x4a[$h] = $np;
return 1;
}
/**
* Return a pointer to data assigned to the given key. Return NULL
* if no such key.
* @return PHP_ParserGenerator_Config|0
*/
static function Configtable_find(PHP_ParserGenerator_Config $key)
{
$h = self::confighash($key);
if (!isset(self::$x4a[$h])) {
return 0;
}
$np = self::$x4a[$h];
while ($np) {
if (self::Configcmp($np->data, $key) == 0) {
break;
}
$np = $np->next;
}
return $np ? $np->data : 0;
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,844 @@
<?php
/**
* PHP_ParserGenerator, a php 5 parser generator.
*
* This is a direct port of the Lemon parser generator, found at
* {@link http://www.hwaci.com/sw/lemon/}
*
* PHP version 5
*
* LICENSE: This source file is subject to version 3.01 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_01.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category php
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version CVS: $Id: Parser.php,v 1.2 2007/03/02 16:36:24 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
* The grammar parser for lemon grammar files.
*
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.php.net/license/3_01.txt PHP License 3.01
* @since Class available since Release 0.1.0
*/
class PHP_ParserGenerator_Parser
{
const INITIALIZE = 1;
const WAITING_FOR_DECL_OR_RULE = 2;
const WAITING_FOR_DECL_KEYWORD = 3;
const WAITING_FOR_DECL_ARG = 4;
const WAITING_FOR_PRECEDENCE_SYMBOL = 5;
const WAITING_FOR_ARROW = 6;
const IN_RHS = 7;
const LHS_ALIAS_1 = 8;
const LHS_ALIAS_2 = 9;
const LHS_ALIAS_3 = 10;
const RHS_ALIAS_1 = 11;
const RHS_ALIAS_2 = 12;
const PRECEDENCE_MARK_1 = 13;
const PRECEDENCE_MARK_2 = 14;
const RESYNC_AFTER_RULE_ERROR = 15;
const RESYNC_AFTER_DECL_ERROR = 16;
const WAITING_FOR_DESTRUCTOR_SYMBOL = 17;
const WAITING_FOR_DATATYPE_SYMBOL = 18;
const WAITING_FOR_FALLBACK_ID = 19;
/**
* Name of the input file
*
* @var string
*/
public $filename;
/**
* Linenumber at which current token starts
* @var int
*/
public $tokenlineno;
/**
* Number of parsing errors so far
* @var int
*/
public $errorcnt;
/**
* Index of current token within the input string
* @var int
*/
public $tokenstart;
/**
* Global state vector
* @var PHP_ParserGenerator_Data
*/
public $gp;
/**
* Parser state (one of the class constants for this class)
*
* - PHP_ParserGenerator_Parser::INITIALIZE,
* - PHP_ParserGenerator_Parser::WAITING_FOR_DECL_OR_RULE,
* - PHP_ParserGenerator_Parser::WAITING_FOR_DECL_KEYWORD,
* - PHP_ParserGenerator_Parser::WAITING_FOR_DECL_ARG,
* - PHP_ParserGenerator_Parser::WAITING_FOR_PRECEDENCE_SYMBOL,
* - PHP_ParserGenerator_Parser::WAITING_FOR_ARROW,
* - PHP_ParserGenerator_Parser::IN_RHS,
* - PHP_ParserGenerator_Parser::LHS_ALIAS_1,
* - PHP_ParserGenerator_Parser::LHS_ALIAS_2,
* - PHP_ParserGenerator_Parser::LHS_ALIAS_3,
* - PHP_ParserGenerator_Parser::RHS_ALIAS_1,
* - PHP_ParserGenerator_Parser::RHS_ALIAS_2,
* - PHP_ParserGenerator_Parser::PRECEDENCE_MARK_1,
* - PHP_ParserGenerator_Parser::PRECEDENCE_MARK_2,
* - PHP_ParserGenerator_Parser::RESYNC_AFTER_RULE_ERROR,
* - PHP_ParserGenerator_Parser::RESYNC_AFTER_DECL_ERROR,
* - PHP_ParserGenerator_Parser::WAITING_FOR_DESTRUCTOR_SYMBOL,
* - PHP_ParserGenerator_Parser::WAITING_FOR_DATATYPE_SYMBOL,
* - PHP_ParserGenerator_Parser::WAITING_FOR_FALLBACK_ID
* @var int
*/
public $state;
/**
* The fallback token
* @var PHP_ParserGenerator_Symbol
*/
public $fallback;
/**
* Left-hand side of the current rule
* @var PHP_ParserGenerator_Symbol
*/
public $lhs;
/**
* Alias for the LHS
* @var string
*/
public $lhsalias;
/**
* Number of right-hand side symbols seen
* @var int
*/
public $nrhs;
/**
* Right-hand side symbols
* @var array array of {@link PHP_ParserGenerator_Symbol} objects
*/
public $rhs = array();
/**
* Aliases for each RHS symbol name (or NULL)
* @var array array of strings
*/
public $alias = array();
/**
* Previous rule parsed
* @var PHP_ParserGenerator_Rule
*/
public $prevrule;
/**
* Keyword of a declaration
*
* This is one of the %keyword keywords in the grammar file
* @var string
*/
public $declkeyword;
/**
* Where the declaration argument should be put
*
* This is assigned as a reference to an internal variable
* @var mixed
*/
public $declargslot = array();
/**
* Where the declaration linenumber is put
*
* This is assigned as a reference to an internal variable
* @var mixed
*/
public $decllnslot;
/*enum e_assoc*/
public $declassoc; /* Assign this association to decl arguments */
public $preccounter; /* Assign this precedence to decl arguments */
/**
* @var PHP_ParserGenerator_Rule
*/
public $firstrule; /* Pointer to first rule in the grammar */
/**
* @var PHP_ParserGenerator_Rule
*/
public $lastrule; /* Pointer to the most recently parsed rule */
/**
* @var PHP_ParserGenerator
*/
private $lemon;
function __construct(PHP_ParserGenerator $lem)
{
$this->lemon = $lem;
}
/**
* Run the preprocessor over the input file text. The Lemon variable
* $azDefine contains the names of all defined
* macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and
* comments them out. Text in between is also commented out as appropriate.
* @param string
*/
private function preprocess_input(&$z)
{
$lineno = $exclude = 0;
for ($i=0; $i < strlen($z); $i++) {
if ($z[$i] == "\n") {
$lineno++;
}
if ($z[$i] != '%' || ($i > 0 && $z[$i-1] != "\n")) {
continue;
}
if (substr($z, $i, 6) === "%endif" && trim($z[$i+6]) === '') {
if ($exclude) {
$exclude--;
if ($exclude === 0) {
for ($j = $start; $j < $i; $j++) {
if ($z[$j] != "\n") $z[$j] = ' ';
}
}
}
for ($j = $i; $j < strlen($z) && $z[$j] != "\n"; $j++) {
$z[$j] = ' ';
}
} elseif (substr($z, $i, 6) === "%ifdef" && trim($z[$i+6]) === '' ||
substr($z, $i, 7) === "%ifndef" && trim($z[$i+7]) === '') {
if ($exclude) {
$exclude++;
} else {
$j = $i;
$n = strtok(substr($z, $j), " \t");
$exclude = 1;
if (isset($this->lemon->azDefine[$n])) {
$exclude = 0;
}
if ($z[$i + 3]=='n') {
// this is a rather obtuse way of checking whether this is %ifndef
$exclude = !$exclude;
}
if ($exclude) {
$start = $i;
$start_lineno = $lineno;
}
}
//for ($j = $i; $j < strlen($z) && $z[$j] != "\n"; $j++) $z[$j] = ' ';
$j = strpos(substr($z, $i), "\n");
if ($j === false) {
$z = substr($z, 0, $i); // remove instead of adding ' '
} else {
$z = substr($z, 0, $i) . substr($z, $i + $j); // remove instead of adding ' '
}
}
}
if ($exclude) {
throw new Exception("unterminated %ifdef starting on line $start_lineno\n");
}
}
/**
* In spite of its name, this function is really a scanner.
*
* It reads in the entire input file (all at once) then tokenizes it.
* Each token is passed to the function "parseonetoken" which builds all
* the appropriate data structures in the global state vector "gp".
* @param PHP_ParserGenerator_Data
*/
function Parse(PHP_ParserGenerator_Data $gp)
{
$startline = 0;
$this->gp = $gp;
$this->filename = $gp->filename;
$this->errorcnt = 0;
$this->state = self::INITIALIZE;
/* Begin by reading the input file */
$filebuf = file_get_contents($this->filename);
if (!$filebuf) {
PHP_ParserGenerator::ErrorMsg($this->filename, 0, "Can't open this file for reading.");
$gp->errorcnt++;
return;
}
if (filesize($this->filename) != strlen($filebuf)) {
ErrorMsg($this->filename, 0, "Can't read in all %d bytes of this file.",
filesize($this->filename));
$gp->errorcnt++;
return;
}
/* Make an initial pass through the file to handle %ifdef and %ifndef */
$this->preprocess_input($filebuf);
/* Now scan the text of the input file */
$lineno = 1;
for ($cp = 0, $c = $filebuf[0]; $cp < strlen($filebuf); $cp++) {
$c = $filebuf[$cp];
if ($c == "\n") $lineno++; /* Keep track of the line number */
if (trim($c) === '') {
continue;
} /* Skip all white space */
if ($filebuf[$cp] == '/' && ($cp + 1 < strlen($filebuf)) && $filebuf[$cp + 1] == '/') {
/* Skip C++ style comments */
$cp += 2;
$z = strpos(substr($filebuf, $cp), "\n");
if ($z === false) {
$cp = strlen($filebuf);
break;
}
$lineno++;
$cp += $z;
continue;
}
if ($filebuf[$cp] == '/' && ($cp + 1 < strlen($filebuf)) && $filebuf[$cp + 1] == '*') {
/* Skip C style comments */
$cp += 2;
$z = strpos(substr($filebuf, $cp), '*/');
if ($z !== false) {
$lineno += count(explode("\n", substr($filebuf, $cp, $z))) - 1;
}
$cp += $z + 1;
continue;
}
$this->tokenstart = $cp; /* Mark the beginning of the token */
$this->tokenlineno = $lineno; /* Linenumber on which token begins */
if ($filebuf[$cp] == '"') { /* String literals */
$cp++;
$oldcp = $cp;
$test = strpos(substr($filebuf, $cp), '"');
if ($test === false) {
PHP_ParserGenerator::ErrorMsg($this->filename, $startline,
"String starting on this line is not terminated before the end of the file.");
$this->errorcnt++;
$nextcp = $cp = strlen($filebuf);
} else {
$cp += $test;
$nextcp = $cp + 1;
}
$lineno += count(explode("\n", substr($filebuf, $oldcp, $cp - $oldcp))) - 1;
} elseif ($filebuf[$cp] == '{') { /* A block of C code */
$cp++;
for ($level = 1; $cp < strlen($filebuf) && ($level > 1 || $filebuf[$cp] != '}'); $cp++) {
if ($filebuf[$cp] == "\n") {
$lineno++;
} elseif ($filebuf[$cp] == '{') {
$level++;
} elseif ($filebuf[$cp] == '}') {
$level--;
} elseif ($filebuf[$cp] == '/' && $filebuf[$cp + 1] == '*') {
/* Skip comments */
$cp += 2;
$z = strpos(substr($filebuf, $cp), '*/');
if ($z !== false) {
$lineno += count(explode("\n", substr($filebuf, $cp, $z))) - 1;
}
$cp += $z + 2;
} elseif ($filebuf[$cp] == '/' && $filebuf[$cp + 1] == '/') {
/* Skip C++ style comments too */
$cp += 2;
$z = strpos(substr($filebuf, $cp), "\n");
if ($z === false) {
$cp = strlen($filebuf);
break;
} else {
$lineno++;
}
$cp += $z;
} elseif ($filebuf[$cp] == "'" || $filebuf[$cp] == '"') {
/* String a character literals */
$startchar = $filebuf[$cp];
$prevc = 0;
for ($cp++; $cp < strlen($filebuf) && ($filebuf[$cp] != $startchar || $prevc === '\\'); $cp++) {
if ($filebuf[$cp] == "\n") {
$lineno++;
}
if ($prevc === '\\') {
$prevc = 0;
} else {
$prevc = $filebuf[$cp];
}
}
}
}
if ($cp >= strlen($filebuf)) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"PHP code starting on this line is not terminated before the end of the file.");
$this->errorcnt++;
$nextcp = $cp;
} else {
$nextcp = $cp + 1;
}
} elseif (preg_match('/[a-zA-Z0-9]/', $filebuf[$cp])) {
/* Identifiers */
preg_match('/[a-zA-Z0-9_]+/', substr($filebuf, $cp), $preg_results);
$cp += strlen($preg_results[0]);
$nextcp = $cp;
} elseif ($filebuf[$cp] == ':' && $filebuf[$cp + 1] == ':' &&
$filebuf[$cp + 2] == '=') {
/* The operator "::=" */
$cp += 3;
$nextcp = $cp;
} elseif (($filebuf[$cp] == '/' || $filebuf[$cp] == '|') &&
preg_match('/[a-zA-Z]/', $filebuf[$cp + 1])) {
$cp += 2;
preg_match('/[a-zA-Z0-9_]+/', substr($filebuf, $cp), $preg_results);
$cp += strlen($preg_results[0]);
$nextcp = $cp;
} else {
/* All other (one character) operators */
$cp ++;
$nextcp = $cp;
}
$this->parseonetoken(substr($filebuf, $this->tokenstart,
$cp - $this->tokenstart)); /* Parse the token */
$cp = $nextcp - 1;
}
$gp->rule = $this->firstrule;
$gp->errorcnt = $this->errorcnt;
}
/**
* Parse a single token
* @param string token
*/
function parseonetoken($token)
{
$x = $token;
$this->a = 0; // for referencing in WAITING_FOR_DECL_KEYWORD
if (PHP_ParserGenerator::DEBUG) {
printf("%s:%d: Token=[%s] state=%d\n",
$this->filename, $this->tokenlineno, $token, $this->state);
}
switch ($this->state) {
case self::INITIALIZE:
$this->prevrule = 0;
$this->preccounter = 0;
$this->firstrule = $this->lastrule = 0;
$this->gp->nrule = 0;
/* Fall thru to next case */
case self::WAITING_FOR_DECL_OR_RULE:
if ($x[0] == '%') {
$this->state = self::WAITING_FOR_DECL_KEYWORD;
} elseif (preg_match('/[a-z]/', $x[0])) {
$this->lhs = PHP_ParserGenerator_Symbol::Symbol_new($x);
$this->nrhs = 0;
$this->lhsalias = 0;
$this->state = self::WAITING_FOR_ARROW;
} elseif ($x[0] == '{') {
if ($this->prevrule === 0) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"There is no prior rule opon which to attach the code
fragment which begins on this line.");
$this->errorcnt++;
} elseif ($this->prevrule->code != 0) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Code fragment beginning on this line is not the first \
to follow the previous rule.");
$this->errorcnt++;
} else {
$this->prevrule->line = $this->tokenlineno;
$this->prevrule->code = substr($x, 1);
}
} elseif ($x[0] == '[') {
$this->state = self::PRECEDENCE_MARK_1;
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Token \"%s\" should be either \"%%\" or a nonterminal name.",
$x);
$this->errorcnt++;
}
break;
case self::PRECEDENCE_MARK_1:
if (!preg_match('/[A-Z]/', $x[0])) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"The precedence symbol must be a terminal.");
$this->errorcnt++;
} elseif ($this->prevrule === 0) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"There is no prior rule to assign precedence \"[%s]\".", $x);
$this->errorcnt++;
} elseif ($this->prevrule->precsym != 0) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Precedence mark on this line is not the first to follow the previous rule.");
$this->errorcnt++;
} else {
$this->prevrule->precsym = PHP_ParserGenerator_Symbol::Symbol_new($x);
}
$this->state = self::PRECEDENCE_MARK_2;
break;
case self::PRECEDENCE_MARK_2:
if ($x[0] != ']') {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Missing \"]\" on precedence mark.");
$this->errorcnt++;
}
$this->state = self::WAITING_FOR_DECL_OR_RULE;
break;
case self::WAITING_FOR_ARROW:
if ($x[0] == ':' && $x[1] == ':' && $x[2] == '=') {
$this->state = self::IN_RHS;
} elseif ($x[0] == '(') {
$this->state = self::LHS_ALIAS_1;
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Expected to see a \":\" following the LHS symbol \"%s\".",
$this->lhs->name);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_RULE_ERROR;
}
break;
case self::LHS_ALIAS_1:
if (preg_match('/[A-Za-z]/', $x[0])) {
$this->lhsalias = $x;
$this->state = self::LHS_ALIAS_2;
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"\"%s\" is not a valid alias for the LHS \"%s\"\n",
$x, $this->lhs->name);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_RULE_ERROR;
}
break;
case self::LHS_ALIAS_2:
if ($x[0] == ')') {
$this->state = self::LHS_ALIAS_3;
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Missing \")\" following LHS alias name \"%s\".",$this->lhsalias);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_RULE_ERROR;
}
break;
case self::LHS_ALIAS_3:
if ($x == '::=') {
$this->state = self::IN_RHS;
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Missing \"->\" following: \"%s(%s)\".",
$this->lhs->name, $this->lhsalias);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_RULE_ERROR;
}
break;
case self::IN_RHS:
if ($x[0] == '.') {
$rp = new PHP_ParserGenerator_Rule;
$rp->ruleline = $this->tokenlineno;
for ($i = 0; $i < $this->nrhs; $i++) {
$rp->rhs[$i] = $this->rhs[$i];
$rp->rhsalias[$i] = $this->alias[$i];
}
if (count(array_unique($rp->rhsalias)) != count($rp->rhsalias)) {
$used = array();
foreach ($rp->rhsalias as $i => $symbol) {
if (!is_string($symbol)) {
continue;
}
if (isset($used[$symbol])) {
PHP_ParserGenerator::ErrorMsg($this->filename,
$this->tokenlineno,
"RHS symbol \"%s\" used multiple times.",
$symbol);
$this->errorcnt++;
} else {
$used[$symbol] = $i;
}
}
}
$rp->lhs = $this->lhs;
$rp->lhsalias = $this->lhsalias;
$rp->nrhs = $this->nrhs;
$rp->code = 0;
$rp->precsym = 0;
$rp->index = $this->gp->nrule++;
$rp->nextlhs = $rp->lhs->rule;
$rp->lhs->rule = $rp;
$rp->next = 0;
if ($this->firstrule === 0) {
$this->firstrule = $this->lastrule = $rp;
} else {
$this->lastrule->next = $rp;
$this->lastrule = $rp;
}
$this->prevrule = $rp;
$this->state = self::WAITING_FOR_DECL_OR_RULE;
} elseif (preg_match('/[a-zA-Z]/', $x[0])) {
if ($this->nrhs >= PHP_ParserGenerator::MAXRHS) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Too many symbols on RHS or rule beginning at \"%s\".",
$x);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_RULE_ERROR;
} else {
if (isset($this->rhs[$this->nrhs - 1])) {
$msp = $this->rhs[$this->nrhs - 1];
if ($msp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) {
$inf = array_reduce($msp->subsym,
array($this, '_printmulti'), '');
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
'WARNING: symbol ' . $x . ' will not' .
' be part of previous multiterminal %s',
substr($inf, 0, strlen($inf) - 1)
);
}
}
$this->rhs[$this->nrhs] = PHP_ParserGenerator_Symbol::Symbol_new($x);
$this->alias[$this->nrhs] = 0;
$this->nrhs++;
}
} elseif (($x[0] == '|' || $x[0] == '/') && $this->nrhs > 0) {
$msp = $this->rhs[$this->nrhs - 1];
if ($msp->type != PHP_ParserGenerator_Symbol::MULTITERMINAL) {
$origsp = $msp;
$msp = new PHP_ParserGenerator_Symbol;
$msp->type = PHP_ParserGenerator_Symbol::MULTITERMINAL;
$msp->nsubsym = 1;
$msp->subsym = array($origsp);
$msp->name = $origsp->name;
$this->rhs[$this->nrhs - 1] = $msp;
}
$msp->nsubsym++;
$msp->subsym[$msp->nsubsym - 1] = PHP_ParserGenerator_Symbol::Symbol_new(substr($x, 1));
if (preg_match('/[a-z]/', $x[1]) ||
preg_match('/[a-z]/', $msp->subsym[0]->name[0])) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Cannot form a compound containing a non-terminal");
$this->errorcnt++;
}
} elseif ($x[0] == '(' && $this->nrhs > 0) {
$this->state = self::RHS_ALIAS_1;
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Illegal character on RHS of rule: \"%s\".", $x);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_RULE_ERROR;
}
break;
case self::RHS_ALIAS_1:
if (preg_match('/[A-Za-z]/', $x[0])) {
$this->alias[$this->nrhs - 1] = $x;
$this->state = self::RHS_ALIAS_2;
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"\"%s\" is not a valid alias for the RHS symbol \"%s\"\n",
$x, $this->rhs[$this->nrhs - 1]->name);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_RULE_ERROR;
}
break;
case self::RHS_ALIAS_2:
if ($x[0] == ')') {
$this->state = self::IN_RHS;
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Missing \")\" following LHS alias name \"%s\".", $this->lhsalias);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_RULE_ERROR;
}
break;
case self::WAITING_FOR_DECL_KEYWORD:
if(preg_match('/[A-Za-z]/', $x[0])) {
$this->declkeyword = $x;
$this->declargslot = &$this->a;
$this->decllnslot = &$this->a;
$this->state = self::WAITING_FOR_DECL_ARG;
if ('name' == $x) {
$this->declargslot = &$this->gp->name;
} elseif ('include' == $x) {
$this->declargslot = &$this->gp->include_code;
$this->decllnslot = &$this->gp->includeln;
} elseif ('include_class' == $x) {
$this->declargslot = &$this->gp->include_classcode;
$this->decllnslot = &$this->gp->include_classln;
} elseif ('declare_class' == $x) {
$this->declargslot = &$this->gp->declare_classcode;
$this->decllnslot = &$this->gp->declare_classln;
} elseif ('code' == $x) {
$this->declargslot = &$this->gp->extracode;
$this->decllnslot = &$this->gp->extracodeln;
} elseif ('token_destructor' == $x) {
$this->declargslot = &$this->gp->tokendest;
$this->decllnslot = &$this->gp->tokendestln;
} elseif ('default_destructor' == $x) {
$this->declargslot = &$this->gp->vardest;
$this->decllnslot = &$this->gp->vardestln;
} elseif ('token_prefix' == $x) {
$this->declargslot = &$this->gp->tokenprefix;
} elseif ('syntax_error' == $x) {
$this->declargslot = &$this->gp->error;
$this->decllnslot = &$this->gp->errorln;
} elseif ('parse_accept' == $x) {
$this->declargslot = &$this->gp->accept;
$this->decllnslot = &$this->gp->acceptln;
} elseif ('parse_failure' == $x) {
$this->declargslot = &$this->gp->failure;
$this->decllnslot = &$this->gp->failureln;
} elseif ('stack_overflow' == $x) {
$this->declargslot = &$this->gp->overflow;
$this->decllnslot = &$this->gp->overflowln;
} elseif ('token_type' == $x) {
$this->declargslot = &$this->gp->tokentype;
} elseif ('default_type' == $x) {
$this->declargslot = &$this->gp->vartype;
} elseif ('stack_size' == $x) {
$this->declargslot = &$this->gp->stacksize;
} elseif ('start_symbol' == $x) {
$this->declargslot = &$this->gp->start;
} elseif ('left' == $x) {
$this->preccounter++;
$this->declassoc = PHP_ParserGenerator_Symbol::LEFT;
$this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL;
} elseif ('right' == $x) {
$this->preccounter++;
$this->declassoc = PHP_ParserGenerator_Symbol::RIGHT;
$this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL;
} elseif ('nonassoc' == $x) {
$this->preccounter++;
$this->declassoc = PHP_ParserGenerator_Symbol::NONE;
$this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL;
} elseif ('destructor' == $x) {
$this->state = self::WAITING_FOR_DESTRUCTOR_SYMBOL;
} elseif ('type' == $x) {
$this->state = self::WAITING_FOR_DATATYPE_SYMBOL;
} elseif ('fallback' == $x) {
$this->fallback = 0;
$this->state = self::WAITING_FOR_FALLBACK_ID;
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Unknown declaration keyword: \"%%%s\".", $x);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_DECL_ERROR;
}
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Illegal declaration keyword: \"%s\".", $x);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_DECL_ERROR;
}
break;
case self::WAITING_FOR_DESTRUCTOR_SYMBOL:
if (!preg_match('/[A-Za-z]/', $x[0])) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Symbol name missing after %destructor keyword");
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_DECL_ERROR;
} else {
$sp = PHP_ParserGenerator_Symbol::Symbol_new($x);
$this->declargslot = &$sp->destructor;
$this->decllnslot = &$sp->destructorln;
$this->state = self::WAITING_FOR_DECL_ARG;
}
break;
case self::WAITING_FOR_DATATYPE_SYMBOL:
if (!preg_match('/[A-Za-z]/', $x[0])) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Symbol name missing after %destructor keyword");
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_DECL_ERROR;
} else {
$sp = PHP_ParserGenerator_Symbol::Symbol_new($x);
$this->declargslot = &$sp->datatype;
$this->state = self::WAITING_FOR_DECL_ARG;
}
break;
case self::WAITING_FOR_PRECEDENCE_SYMBOL:
if ($x[0] == '.') {
$this->state = self::WAITING_FOR_DECL_OR_RULE;
} elseif (preg_match('/[A-Z]/', $x[0])) {
$sp = PHP_ParserGenerator_Symbol::Symbol_new($x);
if ($sp->prec >= 0) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Symbol \"%s\" has already been given a precedence.", $x);
$this->errorcnt++;
} else {
$sp->prec = $this->preccounter;
$sp->assoc = $this->declassoc;
}
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Can't assign a precedence to \"%s\".", $x);
$this->errorcnt++;
}
break;
case self::WAITING_FOR_DECL_ARG:
if (preg_match('/[A-Za-z0-9{"]/', $x[0])) {
if ($this->declargslot != 0) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"The argument \"%s\" to declaration \"%%%s\" is not the first.",
$x[0] == '"' ? substr($x, 1) : $x, $this->declkeyword);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_DECL_ERROR;
} else {
$this->declargslot = ($x[0] == '"' || $x[0] == '{') ? substr($x, 1) : $x;
$this->a = 1;
if (!$this->decllnslot) {
$this->decllnslot = $this->tokenlineno;
}
$this->state = self::WAITING_FOR_DECL_OR_RULE;
}
} else {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"Illegal argument to %%%s: %s",$this->declkeyword, $x);
$this->errorcnt++;
$this->state = self::RESYNC_AFTER_DECL_ERROR;
}
break;
case self::WAITING_FOR_FALLBACK_ID:
if ($x[0] == '.') {
$this->state = self::WAITING_FOR_DECL_OR_RULE;
} elseif (!preg_match('/[A-Z]/', $x[0])) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"%%fallback argument \"%s\" should be a token", $x);
$this->errorcnt++;
} else {
$sp = PHP_ParserGenerator_Symbol::Symbol_new($x);
if ($this->fallback === 0) {
$this->fallback = $sp;
} elseif (is_object($sp->fallback)) {
PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
"More than one fallback assigned to token %s", $x);
$this->errorcnt++;
} else {
$sp->fallback = $this->fallback;
$this->gp->has_fallback = 1;
}
}
break;
case self::RESYNC_AFTER_RULE_ERROR:
/* if ($x[0] == '.') $this->state = self::WAITING_FOR_DECL_OR_RULE;
** break; */
case self::RESYNC_AFTER_DECL_ERROR:
if ($x[0] == '.') {
$this->state = self::WAITING_FOR_DECL_OR_RULE;
}
if ($x[0] == '%') {
$this->state = self::WAITING_FOR_DECL_KEYWORD;
}
break;
}
}
/**
* return a descriptive string for a multi-terminal token.
*
* @param string $a
* @param string $b
* @return string
*/
private function _printmulti($a, $b)
{
if (!$a) {
$a = '';
}
$a .= $b->name . '|';
return $a;
}
}

View File

@@ -0,0 +1,117 @@
<?php
/**
* PHP_ParserGenerator, a php 5 parser generator.
*
* This is a direct port of the Lemon parser generator, found at
* {@link http://www.hwaci.com/sw/lemon/}
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_ParserGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: PropagationLink.php,v 1.1 2006/07/18 00:53:10 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
* A followset propagation link indicates that the contents of one
* configuration followset should be propagated to another whenever
* the first changes.
*
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version 0.1.5
* @since Class available since Release 0.1.0
*/
class PHP_ParserGenerator_PropagationLink {
/**
* The configuration that defines this propagation link
* @var PHP_ParserGenerator_Config
*/
public $cfp;
/**
* The next propagation link
* @var PHP_ParserGenerator_PropagationLink|0
*/
public $next = 0;
/**
* Add a propagation link to the current list
*
* This prepends the configuration passed in to the first parameter
* which is either 0 or a PHP_ParserGenerator_PropagationLink defining
* an existing list.
* @param PHP_ParserGenerator_PropagationLink|null
* @param PHP_ParserGenerator_Config
*/
static function Plink_add(&$plpp, PHP_ParserGenerator_Config $cfp)
{
$new = new PHP_ParserGenerator_PropagationLink;
$new->next = $plpp;
$plpp = $new;
$new->cfp = $cfp;
}
/**
* Transfer every propagation link on the list "from" to the list "to"
*/
static function Plink_copy(PHP_ParserGenerator_PropagationLink &$to,
PHP_ParserGenerator_PropagationLink $from)
{
while ($from) {
$nextpl = $from->next;
$from->next = $to;
$to = $from;
$from = $nextpl;
}
}
/**
* Delete every propagation link on the list
* @param PHP_ParserGenerator_PropagationLink|0
*/
static function Plink_delete($plp)
{
while ($plp) {
$nextpl = $plp->next;
$plp->next = 0;
$plp = $nextpl;
}
}
}

View File

@@ -0,0 +1,140 @@
<?php
/**
* PHP_ParserGenerator, a php 5 parser generator.
*
* This is a direct port of the Lemon parser generator, found at
* {@link http://www.hwaci.com/sw/lemon/}
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_ParserGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: Rule.php,v 1.1 2006/07/18 00:53:10 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
* Each production rule in the grammar is stored in this class
*
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version 0.1.5
* @since Class available since Release 0.1.0
*/
class PHP_ParserGenerator_Rule {
/**
* Left-hand side of the rule
* @var array an array of {@link PHP_ParserGenerator_Symbol} objects
*/
public $lhs;
/**
* Alias for the LHS (NULL if none)
*
* @var array
*/
public $lhsalias = array();
/**
* Line number for the rule
* @var int
*/
public $ruleline;
/**
* Number of right-hand side symbols
*/
public $nrhs;
/**
* The right-hand side symbols
* @var array an array of {@link PHP_ParserGenerator_Symbol} objects
*/
public $rhs;
/**
* Aliases for each right-hand side symbol, or null if no alis.
*
* In this rule:
* <pre>
* foo ::= BAR(A) baz(B).
* </pre>
*
* The right-hand side aliases are A for BAR, and B for baz.
* @var array aliases are indexed by the right-hand side symbol index.
*/
public $rhsalias = array();
/**
* Line number at which code begins
* @var int
*/
public $line;
/**
* The code executed when this rule is reduced
*
* <pre>
* foo(R) ::= BAR(A) baz(B). {R = A + B;}
* </pre>
*
* In the rule above, the code is "R = A + B;"
* @var string|0
*/
public $code;
/**
* Precedence symbol for this rule
* @var PHP_ParserGenerator_Symbol
*/
public $precsym;
/**
* An index number for this rule
*
* Used in both naming of reduce functions and determining which rule code
* to use for reduce actions
* @var int
*/
public $index;
/**
* True if this rule is ever reduced
* @var boolean
*/
public $canReduce;
/**
* Next rule with the same left-hand side
* @var PHP_ParserGenerator_Rule|0
*/
public $nextlhs;
/**
* Next rule in the global list
* @var PHP_ParserGenerator_Rule|0
*/
public $next;
}

View File

@@ -0,0 +1,277 @@
<?php
/**
* PHP_ParserGenerator, a php 5 parser generator.
*
* This is a direct port of the Lemon parser generator, found at
* {@link http://www.hwaci.com/sw/lemon/}
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_ParserGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: State.php,v 1.1 2006/07/18 00:53:10 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
* The structure used to represent a state in the associative array
* for a PHP_ParserGenerator_Config.
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version 0.1.5
* @since Class available since Release 0.1.0
*/
class PHP_ParserGenerator_StateNode
{
public $key;
public $data;
public $from = 0;
public $next = 0;
}
/**
* Each state of the generated parser's finite state machine
* is encoded as an instance of this class
*
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version 0.1.5
* @since Class available since Release 0.1.0
*/
class PHP_ParserGenerator_State {
/**
* The basis configurations for this state
* @var PHP_ParserGenerator_Config
*/
public $bp;
/**
* All configurations in this state
* @var PHP_ParserGenerator_Config
*/
public $cfp;
/**
* Sequential number for this state
*
* @var int
*/
public $statenum;
/**
* Linked list of actions for this state.
* @var PHP_ParserGenerator_Action
*/
public $ap;
/**
* Number of terminal (token) actions
*
* @var int
*/
public $nTknAct,
/**
* Number of non-terminal actions
*
* @var int
*/
$nNtAct;
/**
* The offset into the $yy_action table for terminal tokens.
*
* @var int
*/
public $iTknOfst,
/**
* The offset into the $yy_action table for non-terminals.
*
* @var int
*/
$iNtOfst;
/**
* Default action
*
* @var int
*/
public $iDflt;
/**
* Associative array of PHP_ParserGenerator_State objects
*
* @var array
*/
public static $x3a = array();
/**
* Array of PHP_ParserGenerator_State objects
*
* @var array
*/
public static $states = array();
/**
* Compare two states for sorting purposes. The smaller state is the
* one with the most non-terminal actions. If they have the same number
* of non-terminal actions, then the smaller is the one with the most
* token actions.
*/
static function stateResortCompare($a, $b)
{
$n = $b->nNtAct - $a->nNtAct;
if ($n === 0) {
$n = $b->nTknAct - $a->nTknAct;
}
return $n;
}
/**
* Compare two states based on their configurations
*
* @param PHP_ParserGenerator_Config|0 $a
* @param PHP_ParserGenerator_Config|0 $b
* @return int
*/
static function statecmp($a, $b)
{
for ($rc = 0; $rc == 0 && $a && $b; $a = $a->bp, $b = $b->bp) {
$rc = $a->rp->index - $b->rp->index;
if ($rc === 0) {
$rc = $a->dot - $b->dot;
}
}
if ($rc == 0) {
if ($a) {
$rc = 1;
}
if ($b) {
$rc = -1;
}
}
return $rc;
}
/**
* Hash a state based on its configuration
* @return int
*/
private static function statehash(PHP_ParserGenerator_Config $a)
{
$h = 0;
while ($a) {
$h = $h * 571 + $a->rp->index * 37 + $a->dot;
$a = $a->bp;
}
return (int) $h;
}
/**
* Return a pointer to data assigned to the given key. Return NULL
* if no such key.
* @param PHP_ParserGenerator_Config
* @return null|PHP_ParserGenerator_State
*/
static function State_find(PHP_ParserGenerator_Config $key)
{
if (!count(self::$x3a)) {
return 0;
}
$h = self::statehash($key);
if (!isset(self::$x3a[$h])) {
return 0;
}
$np = self::$x3a[$h];
while ($np) {
if (self::statecmp($np->key, $key) == 0) {
break;
}
$np = $np->next;
}
return $np ? $np->data : 0;
}
/**
* Insert a new record into the array. Return TRUE if successful.
* Prior data with the same key is NOT overwritten
*
* @param PHP_ParserGenerator_State $state
* @param PHP_ParserGenerator_Config $key
* @return unknown
*/
static function State_insert(PHP_ParserGenerator_State $state,
PHP_ParserGenerator_Config $key)
{
$h = self::statehash($key);
if (isset(self::$x3a[$h])) {
$np = self::$x3a[$h];
} else {
$np = 0;
}
while ($np) {
if (self::statecmp($np->key, $key) == 0) {
/* An existing entry with the same key is found. */
/* Fail because overwrite is not allows. */
return 0;
}
$np = $np->next;
}
/* Insert the new data */
$np = new PHP_ParserGenerator_StateNode;
$np->key = $key;
$np->data = $state;
self::$states[] = $np;
// the original lemon code sets the from link always to itself
// setting up a faulty double-linked list
// however, the from links are never used, so I suspect a copy/paste
// error from a standard algorithm that was never caught
if (isset(self::$x3a[$h])) {
self::$x3a[$h]->from = $np; // lemon has $np->next here
} else {
self::$x3a[$h] = 0; // dummy to avoid notice
}
$np->next = self::$x3a[$h];
self::$x3a[$h] = $np;
$np->from = self::$x3a[$h];
return 1;
}
/**
* Get an array indexed by state number
*
* @return array
*/
static function State_arrayof()
{
return self::$states;
}
}

View File

@@ -0,0 +1,284 @@
<?php
/**
* PHP_ParserGenerator, a php 5 parser generator.
*
* This is a direct port of the Lemon parser generator, found at
* {@link http://www.hwaci.com/sw/lemon/}
*
* PHP version 5
*
* LICENSE:
*
* Copyright (c) 2006, Gregory Beaver <cellog@php.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* * Neither the name of the PHP_ParserGenerator nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category php
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: Symbol.php,v 1.1 2006/07/18 00:53:10 cellog Exp $
* @since File available since Release 0.1.0
*/
/**
* Symbols (terminals and nonterminals) of the grammar are stored in this class
*
* @package PHP_ParserGenerator
* @author Gregory Beaver <cellog@php.net>
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version 0.1.5
* @since Class available since Release 0.1.0
*/
class PHP_ParserGenerator_Symbol
{
/**
* Symbols that start with a capital letter like FOO.
*
* These are tokens directly from the lexer
*/
const TERMINAL = 1;
/**
* Symbols that start with a lower-case letter like foo.
*
* These are grammar rules like "foo ::= BLAH."
*/
const NONTERMINAL = 2;
/**
* Multiple terminal symbols.
*
* These are a grammar rule that consists of several terminals like
* FOO|BAR|BAZ. Note that non-terminals cannot be in a multi-terminal,
* and a multi-terminal acts like a single terminal.
*
* "FOO|BAR FOO|BAZ" is actually two multi-terminals, FOO|BAR and FOO|BAZ.
*/
const MULTITERMINAL = 3;
const LEFT = 1;
const RIGHT = 2;
const NONE = 3;
const UNK = 4;
/**
* Name of the symbol
*
* @var string
*/
public $name;
/**
* Index of this symbol.
*
* This will ultimately end up representing the symbol in the generated
* parser
* @var int
*/
public $index;
/**
* Symbol type
*
* One of PHP_ParserGenerator_Symbol::TERMINAL,
* PHP_ParserGenerator_Symbol::NONTERMINAL or
* PHP_ParserGenerator_Symbol::MULTITERMINAL
* @var int
*/
public $type;
/**
* Linked list of rules that use this symbol, if it is a non-terminal.
* @var PHP_ParserGenerator_Rule
*/
public $rule;
/**
* Fallback token in case this token doesn't parse
* @var PHP_ParserGenerator_Symbol
*/
public $fallback;
/**
* Precendence, if defined.
*
* -1 if no unusual precedence
* @var int
*/
public $prec = -1;
/**
* Associativity if precedence is defined.
*
* One of PHP_ParserGenerator_Symbol::LEFT,
* PHP_ParserGenerator_Symbol::RIGHT, PHP_ParserGenerator_Symbol::NONE
* or PHP_ParserGenerator_Symbol::UNK
* @var unknown_type
*/
public $assoc;
/**
* First-set for all rules of this symbol
*
* @var array
*/
public $firstset;
/**
* True if this symbol is a non-terminal and can generate an empty
* result.
*
* For instance "foo ::= ."
* @var boolean
*/
public $lambda;
/**
* Code that executes whenever this symbol is popped from the stack during
* error processing.
*
* @var string|0
*/
public $destructor = 0;
/**
* Line number of destructor code
* @var int
*/
public $destructorln;
/**
* Unused relic of the C version of Lemon.
*
* The data type of information held by this object. Only used
* if this is a non-terminal
* @var string
*/
public $datatype;
/**
* Unused relic of the C version of Lemon.
*
* The data type number. In the parser, the value
* stack is a union. The .yy%d element of this
* union is the correct data type for this object
* @var string
*/
public $dtnum;
/**#@+
* The following fields are used by MULTITERMINALs only
*/
/**
* Number of terminal symbols in the MULTITERMINAL
*
* This is of course the same as count($this->subsym)
* @var int
*/
public $nsubsym;
/**
* Array of terminal symbols in the MULTITERMINAL
* @var array an array of {@link PHP_ParserGenerator_Symbol} objects
*/
public $subsym = array();
/**#@-*/
/**
* Singleton storage of symbols
*
* @var array an array of PHP_ParserGenerator_Symbol objects
*/
private static $symbol_table = array();
/**
* Return a pointer to the (terminal or nonterminal) symbol "x".
* Create a new symbol if this is the first time "x" has been seen.
* (this is a singleton)
* @param string
* @return PHP_ParserGenerator_Symbol
*/
public static function Symbol_new($x)
{
if (isset(self::$symbol_table[$x])) {
return self::$symbol_table[$x];
}
$sp = new PHP_ParserGenerator_Symbol;
$sp->name = $x;
$sp->type = preg_match('/[A-Z]/', $x[0]) ? self::TERMINAL : self::NONTERMINAL;
$sp->rule = 0;
$sp->fallback = 0;
$sp->prec = -1;
$sp->assoc = self::UNK;
$sp->firstset = array();
$sp->lambda = false;
$sp->destructor = 0;
$sp->datatype = 0;
self::$symbol_table[$sp->name] = $sp;
return $sp;
}
/**
* Return the number of unique symbols
* @return int
*/
public static function Symbol_count()
{
return count(self::$symbol_table);
}
public static function Symbol_arrayof()
{
return array_values(self::$symbol_table);
}
public static function Symbol_find($x)
{
if (isset(self::$symbol_table[$x])) {
return self::$symbol_table[$x];
}
return 0;
}
/**
* Sort function helper for symbols
*
* Symbols that begin with upper case letters (terminals or tokens)
* must sort before symbols that begin with lower case letters
* (non-terminals). Other than that, the order does not matter.
*
* We find experimentally that leaving the symbols in their original
* order (the order they appeared in the grammar file) gives the
* smallest parser tables in SQLite.
* @param PHP_ParserGenerator_Symbol
* @param PHP_ParserGenerator_Symbol
*/
public static function sortSymbols($a, $b)
{
$i1 = $a->index + 10000000*(ord($a->name[0]) > ord('Z'));
$i2 = $b->index + 10000000*(ord($b->name[0]) > ord('Z'));
return $i1 - $i2;
}
/**
* Return true if two symbols are the same.
*/
public static function same_symbol(PHP_ParserGenerator_Symbol $a, PHP_ParserGenerator_Symbol $b)
{
if ($a === $b) return 1;
if ($a->type != self::MULTITERMINAL) return 0;
if ($b->type != self::MULTITERMINAL) return 0;
if ($a->nsubsym != $b->nsubsym) return 0;
for ($i = 0; $i < $a->nsubsym; $i++) {
if ($a->subsym[$i] != $b->subsym[$i]) return 0;
}
return 1;
}
}

View File

@@ -0,0 +1,5 @@
<?php
require_once './ParserGenerator.php';
$me = new PHP_ParserGenerator;
$me->main();
?>

View File

@@ -0,0 +1,108 @@
<?php
/**
* Smarty Internal Plugin Configfilelexer
*
* This is the lexer to break the config file source into tokens
* @package Smarty
* @subpackage Config
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Templatelexer
*/
class Smarty_Internal_Configfilelexer
{
public $data;
public $counter;
public $token;
public $value;
public $node;
public $line;
private $state = 1;
public $smarty_token_names = array ( // Text for parser error messages
);
function __construct($data)
{
// set instance object
self::instance($this);
$this->data = $data;
$this->counter = 0;
$this->line = 1;
$this->smarty = Smarty::instance();
}
public static function &instance($new_instance = null)
{
static $instance = null;
if (isset($new_instance) && is_object($new_instance))
$instance = $new_instance;
return $instance;
}
/*!lex2php
%input $this->data
%counter $this->counter
%token $this->token
%value $this->value
%line $this->line
commentstart = /#/
openB = /\[/
closeB = /]/
number = /\d+(\.\d+)?/
dot = /\./
equal = /\s*\=\s*/
eol = /(\n|\r\n)/
space = /[\s]+/
id = /\w+/
si_qstr = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''
ml_qstr = '\"\"\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"\"\"'
do_qstr = '\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"'
other = /./
*/
/*!lex2php
%statename START
commentstart {
$this->token = Smarty_Internal_Configfileparser::TPC_COMMENTSTART;
}
si_qstr {
$this->token = Smarty_Internal_Configfileparser::TPC_SI_QSTR;
}
ml_qstr {
$this->token = Smarty_Internal_Configfileparser::TPC_ML_QSTR;
}
do_qstr {
$this->token = Smarty_Internal_Configfileparser::TPC_DO_QSTR;
}
openB {
$this->token = Smarty_Internal_Configfileparser::TPC_OPENB;
}
closeB {
$this->token = Smarty_Internal_Configfileparser::TPC_CLOSEB;
}
equal {
$this->token = Smarty_Internal_Configfileparser::TPC_EQUAL;
}
number {
$this->token = Smarty_Internal_Configfileparser::TPC_NUMBER;
}
eol {
$this->token = Smarty_Internal_Configfileparser::TPC_EOL;
}
space {
$this->token = Smarty_Internal_Configfileparser::TPC_SPACE;
}
dot {
$this->token = Smarty_Internal_Configfileparser::TPC_DOT;
}
id {
$this->token = Smarty_Internal_Configfileparser::TPC_ID;
}
other {
$this->token = Smarty_Internal_Configfileparser::TPC_OTHER;
}
*/
}

View File

@@ -0,0 +1,123 @@
/**
* Smarty Internal Plugin Configfileparser
*
* This is the config file parser
*
*
* @package Smarty
* @subpackage Config
* @author Uwe Tews
*/
%name TPC_
%declare_class {class Smarty_Internal_Configfileparser}
%include_class
{
// states whether the parse was successful or not
public $successful = true;
public $retvalue = 0;
private $lex;
private $internalError = false;
function __construct($lex, $compiler) {
// set instance object
self::instance($this);
$this->lex = $lex;
$this->smarty = Smarty::instance();
$this->compiler = $compiler;
$this->current_section = null;
$this->hidden_section = false;
}
public static function &instance($new_instance = null)
{
static $instance = null;
if (isset($new_instance) && is_object($new_instance))
$instance = $new_instance;
return $instance;
}
}
%token_prefix TPC_
%parse_accept
{
$this->successful = !$this->internalError;
$this->internalError = false;
$this->retvalue = $this->_retvalue;
//echo $this->retvalue."\n\n";
}
%syntax_error
{
$this->internalError = true;
$this->yymajor = $yymajor;
$this->compiler->trigger_config_file_error();
}
//
// fallback definition to catch all non Smarty template text
//
%fallback OTHER COMMENTSTART NUMBER OPENB CLOSEB DOT BOOLEANTRUE BOOLEANFALSE SI_QSTR DO_QSTR EQUAL SPACE ID.
//
// complete config file
//
start(res) ::= config(r). { res = r; }
//
// loop over config file elements
//
// single config element
config(res) ::= config_element(e). {res = e;}
// loop of elements
config(res) ::= config(c) config_element(e). {res = c.e;}
//
// config elements
//
// Section defifinition
config_element(res) ::= OPENB ID(i) CLOSEB EOL. { $this->hidden_section = false; $this->current_section = i; res ='';}
// Hidden section defifinition
config_element(res) ::= OPENB DOT ID(i) CLOSEB EOL. { if ($this->smarty->config_read_hidden) {
$this->hidden_section = false; $this->current_section = i;
} else {$this->hidden_section = true; } res ='';}
// variable assignment
config_element(res) ::= ID(i) EQUAL value(v) EOL. {if (!$this->hidden_section) {
$value=v;
if ($this->smarty->config_booleanize) {
if (in_array(strtolower($value),array('on','yes','true')))
$value = true;
else if (in_array(strtolower($value),array('off','no','false')))
$value = false;
}
if ($this->current_section == null) {
if ($this->smarty->config_overwrite) {
$this->compiler->config_data['vars'][i]=$value;
} else {
settype($this->compiler->config_data['vars'][i], 'array');
$this->compiler->config_data['vars'][i][]=$value;
}
} else {
if ($this->smarty->config_overwrite) {
$this->compiler->config_data['sections'][$this->current_section]['vars'][i]=$value;
} else {
settype($this->compiler->config_data['sections'][$this->current_section]['vars'][i], 'array');
$this->compiler->config_data['sections'][$this->current_section]['vars'][i][]=$value;
}
}} res ='';}
// empty and comment lines
config_element(res) ::= EOL. { res ='';}
config_element(res) ::= COMMENTSTART text(t) EOL. { res ='';}
value(res) ::= text(t). {res = t;}
value(res) ::= SI_QSTR(s). {res = trim(s,"'");}
value(res) ::= DO_QSTR(s). {res = trim(s,'"');}
value(res) ::= ML_QSTR(s). {res = trim(s,'"');}
value(res) ::= NUMBER(n). {res = (int)n;}
text(res) ::= text(t) textelement(e). {res = t.e;}
text(res) ::= textelement(e). {res = e;}
textelement(res) ::= OTHER(o). {res = o;}

View File

@@ -0,0 +1,708 @@
<?php
/**
* Smarty Internal Plugin Templatelexer
*
* This is the lexer to break the template source into tokens
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Templatelexer
*/
class Smarty_Internal_Templatelexer
{
public $data;
public $counter;
public $token;
public $value;
public $node;
public $line;
private $state = 1;
public $smarty_token_names = array ( // Text for parser error messages
'LDEL' => '{',
'RDEL' => '}',
'IDENTITY' => '===',
'NONEIDENTITY' => '!==',
'EQUALS' => '==',
'NOTEQUALS' => '!=',
'GREATEREQUAL' => '(>=,GE)',
'LESSEQUAL' => '(<=,LE)',
'GREATERTHAN' => '(>,GT)',
'LESSTHAN' => '(<,LT)',
'NOT' => '(!,NOT)',
'LAND' => '(&&,AND)',
'LOR' => '(||,OR)',
'OPENP' => '(',
'CLOSEP' => ')',
'OPENB' => '[',
'CLOSEB' => ']',
'PTR' => '->',
'APTR' => '=>',
'EQUAL' => '=',
'NUMBER' => 'number',
'UNIMATH' => '+" , "-',
'MATH' => '*" , "/" , "%',
'INCDEC' => '++" , "--',
'SPACE' => ' ',
'DOLLAR' => '$',
'SEMICOLON' => ';',
'COLON' => ':',
'DOUBLECOLON' => '::',
'AT' => '@',
'HATCH' => '#',
'QUOTE' => '"',
'SINGLEQUOTE' => "'",
'BACKTICK' => '`',
'VERT' => '|',
'DOT' => '.',
'COMMA' => '","',
'ANDSYM' => '"&"',
'ID' => 'identifier',
'OTHER' => 'text',
'PHP' => 'PHP code',
'LDELSLASH' => 'closing tag',
'COMMENTSTART' => '{*',
'COMMENTEND' => '*}',
'LITERALEND' => 'literal close',
'IN' => 'in',
'NULL' => 'null',
'BOOLEAN' => 'boolean'
);
function __construct($data)
{
// set instance object
self::instance($this);
$this->data = $data;
$this->counter = 0;
$this->line = 1;
$this->smarty = Smarty::instance();
$this->ldel = preg_quote($this->smarty->left_delimiter);
$this->rdel = preg_quote($this->smarty->right_delimiter);
}
public static function &instance($new_instance = null)
{
static $instance = null;
if (isset($new_instance) && is_object($new_instance))
$instance = $new_instance;
return $instance;
}
private $_yy_state = 1;
private $_yy_stack = array();
function yylex()
{
return $this->{'yylex' . $this->_yy_state}();
}
function yypushstate($state)
{
array_push($this->_yy_stack, $this->_yy_state);
$this->_yy_state = $state;
}
function yypopstate()
{
$this->_yy_state = array_pop($this->_yy_stack);
}
function yybegin($state)
{
$this->_yy_state = $state;
}
function yylex1()
{
$tokenMap = array (
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 0,
9 => 1,
11 => 0,
12 => 0,
13 => 0,
14 => 0,
15 => 0,
16 => 0,
17 => 0,
18 => 0,
19 => 0,
20 => 0,
21 => 1,
23 => 0,
24 => 0,
25 => 0,
26 => 0,
27 => 1,
29 => 1,
31 => 1,
33 => 1,
35 => 1,
37 => 1,
39 => 1,
41 => 1,
43 => 1,
45 => 0,
46 => 0,
47 => 0,
48 => 0,
49 => 0,
50 => 0,
51 => 0,
52 => 0,
53 => 0,
54 => 0,
55 => 0,
56 => 0,
57 => 0,
58 => 0,
59 => 0,
60 => 0,
61 => 0,
62 => 1,
64 => 1,
66 => 1,
68 => 1,
70 => 0,
71 => 0,
72 => 0,
73 => 0,
74 => 0,
75 => 0,
76 => 0,
77 => 0,
78 => 0,
79 => 0,
80 => 0,
81 => 0,
82 => 0,
83 => 0,
84 => 0,
);
if ($this->counter >= strlen($this->data)) {
return false; // end of input
}
$yy_global_pattern = "/^(<\\?xml.*\\?>)|^(<\\?php.*\\?>)|^(<\\?=)|^(\\?>)|^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)/";
do {
if (preg_match($yy_global_pattern, substr($this->data, $this->counter), $yymatches)) {
$yysubmatches = $yymatches;
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
if (!count($yymatches)) {
throw new Exception('Error: lexing failed because a rule matched' .
'an empty string. Input "' . substr($this->data,
$this->counter, 5) . '... state START');
}
next($yymatches); // skip global match
$this->token = key($yymatches); // token number
if ($tokenMap[$this->token]) {
// extract sub-patterns for passing to lex function
$yysubmatches = array_slice($yysubmatches, $this->token + 1,
$tokenMap[$this->token]);
} else {
$yysubmatches = array();
}
$this->value = current($yymatches); // token value
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
if ($r === null) {
$this->counter += strlen($this->value);
$this->line += substr_count($this->value, "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
$this->counter += strlen($this->value);
$this->line += substr_count($this->value, "\n");
if ($this->counter >= strlen($this->data)) {
return false; // end of input
}
// skip this token
continue;
} else { $yy_yymore_patterns = array(
1 => array(0, "^(<\\?php.*\\?>)|^(<\\?=)|^(\\?>)|^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
2 => array(0, "^(<\\?=)|^(\\?>)|^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
3 => array(0, "^(\\?>)|^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
4 => array(0, "^(".$this->ldel."php".$this->rdel.")|^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
5 => array(0, "^(".$this->ldel."\/php".$this->rdel.")|^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
6 => array(0, "^(\\*".$this->rdel.")|^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
7 => array(0, "^(".$this->ldel."\\*)|^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
8 => array(0, "^((\\\\\"|\\\\'))|^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
9 => array(1, "^(')|^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
11 => array(1, "^(".$this->ldel."literal".$this->rdel.")|^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
12 => array(1, "^(".$this->ldel."\/literal".$this->rdel.")|^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
13 => array(1, "^(".$this->ldel."ldelim".$this->rdel.")|^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
14 => array(1, "^(".$this->ldel."rdelim".$this->rdel.")|^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
15 => array(1, "^(".$this->ldel."\\s{1,})|^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
16 => array(1, "^(\\s{1,}".$this->rdel.")|^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
17 => array(1, "^(".$this->ldel."\/)|^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
18 => array(1, "^(".$this->ldel.")|^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
19 => array(1, "^(".$this->rdel.")|^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
20 => array(1, "^(\\s+(IN|in)\\s+)|^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
21 => array(2, "^(true|TRUE|True|false|FALSE|False)|^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
23 => array(2, "^(null|NULL|Null)|^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
24 => array(2, "^(\\s*===\\s*)|^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
25 => array(2, "^(\\s*!==\\s*)|^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
26 => array(2, "^(\\s*==\\s*|\\s+(EQ|eq)\\s+)|^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
27 => array(3, "^(\\s*!=\\s*|\\s+(NE|ne)\\s+)|^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
29 => array(4, "^(\\s*>=\\s*|\\s+(GE|ge)\\s+)|^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
31 => array(5, "^(\\s*<=\\s*|\\s+(LE|le)\\s+)|^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
33 => array(6, "^(\\s*>\\s*|\\s+(GT|gt)\\s+)|^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
35 => array(7, "^(\\s*<\\s*|\\s+(LT|lt)\\s+)|^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
37 => array(8, "^(!|(NOT|not)\\s+)|^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
39 => array(9, "^(\\s*&&\\s*|\\s+(AND|and)\\s+)|^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
41 => array(10, "^(\\s*\\|\\|\\s*|\\s+(OR|or)\\s+)|^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
43 => array(11, "^(\\s+is\\s+odd\\s+by\\s+)|^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
45 => array(11, "^(\\s+is\\s+not\\s+odd\\s+by\\s+)|^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
46 => array(11, "^(\\s+is\\s+odd)|^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
47 => array(11, "^(\\s+is\\s+not\\s+odd)|^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
48 => array(11, "^(\\s+is\\s+even\\s+by\\s+)|^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
49 => array(11, "^(\\s+is\\s+not\\s+even\\s+by\\s+)|^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
50 => array(11, "^(\\s+is\\s+even)|^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
51 => array(11, "^(\\s+is\\s+not\\s+even)|^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
52 => array(11, "^(\\s+is\\s+div\\s+by\\s+)|^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
53 => array(11, "^(\\s+is\\s+not\\s+div\\s+by\\s+)|^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
54 => array(11, "^(\\()|^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
55 => array(11, "^(\\))|^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
56 => array(11, "^(\\[)|^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
57 => array(11, "^(])|^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
58 => array(11, "^(\\s*->)|^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
59 => array(11, "^(\\s*=>\\s*)|^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
60 => array(11, "^(\\s*=\\s*)|^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
61 => array(11, "^(\\d+(\\.\\d+)?)|^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
62 => array(12, "^((\\+\\+|--)\\s*)|^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
64 => array(13, "^(\\s*(\\+|-)\\s*)|^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
66 => array(14, "^(\\s*\\*(?!\\})\\s*|\\s*(\/|%)\\s*)|^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
68 => array(15, "^([\s]+)|^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
70 => array(15, "^(\\$)|^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
71 => array(15, "^(\\s*;\\s*)|^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
72 => array(15, "^(::)|^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
73 => array(15, "^(:)|^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
74 => array(15, "^(@)|^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
75 => array(15, "^(#)|^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
76 => array(15, "^(\")|^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
77 => array(15, "^(`)|^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
78 => array(15, "^(\\s*\\|)|^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
79 => array(15, "^(\\.)|^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
80 => array(15, "^(\\s*,\\s*)|^(\\s?&\\s?)|^(\\w+)|^(.)"),
81 => array(15, "^(\\s?&\\s?)|^(\\w+)|^(.)"),
82 => array(15, "^(\\w+)|^(.)"),
83 => array(15, "^(.)"),
84 => array(15, ""),
);
// yymore is needed
do {
if (!strlen($yy_yymore_patterns[$this->token][1])) {
throw new Exception('cannot do yymore for the last token');
}
$yysubmatches = array();
if (preg_match('/' . $yy_yymore_patterns[$this->token][1] . '/',
substr($this->data, $this->counter), $yymatches)) {
$yysubmatches = $yymatches;
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
next($yymatches); // skip global match
$this->token += key($yymatches) + $yy_yymore_patterns[$this->token][0]; // token number
$this->value = current($yymatches); // token value
$this->line = substr_count($this->value, "\n");
if ($tokenMap[$this->token]) {
// extract sub-patterns for passing to lex function
$yysubmatches = array_slice($yysubmatches, $this->token + 1,
$tokenMap[$this->token]);
} else {
$yysubmatches = array();
}
}
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
} while ($r !== null && !is_bool($r));
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
$this->counter += strlen($this->value);
$this->line += substr_count($this->value, "\n");
if ($this->counter >= strlen($this->data)) {
return false; // end of input
}
// skip this token
continue;
} else {
// accept
$this->counter += strlen($this->value);
$this->line += substr_count($this->value, "\n");
return true;
}
}
} else {
throw new Exception('Unexpected input at line' . $this->line .
': ' . $this->data[$this->counter]);
}
break;
} while (true);
} // end function
const START = 1;
function yy_r1_1($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_XML;
}
function yy_r1_2($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_PHP;
}
function yy_r1_3($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_SHORTTAGSTART;
}
function yy_r1_4($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_SHORTTAGEND;
}
function yy_r1_5($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_PHPSTART;
}
function yy_r1_6($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_PHPEND;
}
function yy_r1_7($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_COMMENTEND;
}
function yy_r1_8($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_COMMENTSTART;
}
function yy_r1_9($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_OTHER;
}
function yy_r1_11($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTE;
}
function yy_r1_12($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_LITERALSTART;
}
function yy_r1_13($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
}
function yy_r1_14($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_LDELIMTAG;
}
function yy_r1_15($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_RDELIMTAG;
}
function yy_r1_16($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_OTHER;
}
function yy_r1_17($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_OTHER;
}
function yy_r1_18($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_LDELSLASH;
}
function yy_r1_19($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_LDEL;
}
function yy_r1_20($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_RDEL;
}
function yy_r1_21($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_IN;
}
function yy_r1_23($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_BOOLEAN;
}
function yy_r1_24($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_NULL;
}
function yy_r1_25($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_IDENTITY;
}
function yy_r1_26($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_NONEIDENTITY;
}
function yy_r1_27($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_EQUALS;
}
function yy_r1_29($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_NOTEQUALS;
}
function yy_r1_31($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_GREATEREQUAL;
}
function yy_r1_33($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_LESSEQUAL;
}
function yy_r1_35($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_GREATERTHAN;
}
function yy_r1_37($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_LESSTHAN;
}
function yy_r1_39($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_NOT;
}
function yy_r1_41($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_LAND;
}
function yy_r1_43($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_LOR;
}
function yy_r1_45($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISODDBY;
}
function yy_r1_46($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISNOTODDBY;
}
function yy_r1_47($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISODD;
}
function yy_r1_48($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISNOTODD;
}
function yy_r1_49($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISEVENBY;
}
function yy_r1_50($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISNOTEVENBY;
}
function yy_r1_51($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISEVEN;
}
function yy_r1_52($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISNOTEVEN;
}
function yy_r1_53($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISDIVBY;
}
function yy_r1_54($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ISNOTDIVBY;
}
function yy_r1_55($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_OPENP;
}
function yy_r1_56($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_CLOSEP;
}
function yy_r1_57($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_OPENB;
}
function yy_r1_58($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_CLOSEB;
}
function yy_r1_59($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_PTR;
}
function yy_r1_60($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_APTR;
}
function yy_r1_61($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_EQUAL;
}
function yy_r1_62($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_NUMBER;
}
function yy_r1_64($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_INCDEC;
}
function yy_r1_66($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_UNIMATH;
}
function yy_r1_68($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_MATH;
}
function yy_r1_70($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_SPACE;
}
function yy_r1_71($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_DOLLAR;
}
function yy_r1_72($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_SEMICOLON;
}
function yy_r1_73($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON;
}
function yy_r1_74($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_COLON;
}
function yy_r1_75($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_AT;
}
function yy_r1_76($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_HATCH;
}
function yy_r1_77($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_QUOTE;
}
function yy_r1_78($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
}
function yy_r1_79($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_VERT;
}
function yy_r1_80($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_DOT;
}
function yy_r1_81($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_COMMA;
}
function yy_r1_82($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ANDSYM;
}
function yy_r1_83($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_ID;
}
function yy_r1_84($yy_subpatterns)
{
$this->token = Smarty_Internal_Templateparser::TP_OTHER;
}
}

View File

@@ -0,0 +1,382 @@
<?php
/**
* Smarty Internal Plugin Templatelexer
*
* This is the lexer to break the template source into tokens
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Templatelexer
*/
class Smarty_Internal_Templatelexer
{
public $data;
public $counter;
public $token;
public $value;
public $node;
public $line;
private $state = 1;
public $smarty_token_names = array ( // Text for parser error messages
'LDEL' => '{',
'RDEL' => '}',
'IDENTITY' => '===',
'NONEIDENTITY' => '!==',
'EQUALS' => '==',
'NOTEQUALS' => '!=',
'GREATEREQUAL' => '(>=,GE)',
'LESSEQUAL' => '(<=,LE)',
'GREATERTHAN' => '(>,GT)',
'LESSTHAN' => '(<,LT)',
'NOT' => '(!,NOT)',
'LAND' => '(&&,AND)',
'LOR' => '(||,OR)',
'OPENP' => '(',
'CLOSEP' => ')',
'OPENB' => '[',
'CLOSEB' => ']',
'PTR' => '->',
'APTR' => '=>',
'EQUAL' => '=',
'NUMBER' => 'number',
'UNIMATH' => '+" , "-',
'MATH' => '*" , "/" , "%',
'INCDEC' => '++" , "--',
'SPACE' => ' ',
'DOLLAR' => '$',
'SEMICOLON' => ';',
'COLON' => ':',
'DOUBLECOLON' => '::',
'AT' => '@',
'HATCH' => '#',
'QUOTE' => '"',
'SINGLEQUOTE' => "'",
'BACKTICK' => '`',
'VERT' => '|',
'DOT' => '.',
'COMMA' => '","',
'ANDSYM' => '"&"',
'ID' => 'identifier',
'OTHER' => 'text',
'PHP' => 'PHP code',
'LDELSLASH' => 'closing tag',
'COMMENTSTART' => '{*',
'COMMENTEND' => '*}',
'LITERALEND' => 'literal close',
'IN' => 'in',
'NULL' => 'null',
'BOOLEAN' => 'boolean'
);
function __construct($data)
{
// set instance object
self::instance($this);
$this->data = $data;
$this->counter = 0;
$this->line = 1;
$this->smarty = Smarty::instance();
$this->ldel = preg_quote($this->smarty->left_delimiter);
$this->rdel = preg_quote($this->smarty->right_delimiter);
}
public static function &instance($new_instance = null)
{
static $instance = null;
if (isset($new_instance) && is_object($new_instance))
$instance = $new_instance;
return $instance;
}
/*!lex2php
%input $this->data
%counter $this->counter
%token $this->token
%value $this->value
%line $this->line
php = /\<\?php.*\?\>/
xml = /\<\?xml.*\?\>/
shorttagstart = /\<\?=/
shorttagend = /\?\>/
phpstart = /SMARTYldelphpSMARTYrdel/
phpend = /SMARTYldel\/phpSMARTYrdel/
ldels = /SMARTYldel\s{1,}/
rdels = /\s{1,}SMARTYrdel/
ldelslash = /SMARTYldel\//
ldel = /SMARTYldel/
rdel = /SMARTYrdel/
number = /\d+(\.\d+)?/
boolean = /true|TRUE|True|false|FALSE|False/
null = /null|NULL|Null/
math = /\s*\*(?!\})\s*|\s*(\/|\%)\s*/
commentstart = /SMARTYldel\*/
commentend = /\*SMARTYrdel/
escapedquotes = /(\\\"|\\\')/
incdec = /(\+\+|\-\-)\s*/
unimath = /\s*(\+|\-)\s*/
openP = /\(/
closeP = /\)/
openB = /\[/
closeB = /]/
dollar = /\$/
dot = /\./
comma = /\s*\,\s*/
doublecolon = /\:\:/
colon = /\:/
at = /@/
hatch = /#/
semicolon = /\s*\;\s*/
vert = /\s*\|/
equal = /\s*=\s*/
space = /[\s]+/
ptr = /\s*\->/
aptr = /\s*=>\s*/
quote = /\"/
singlequote = /\'/
backtick = /`/
andsym = /\s?\&\s?/
id = /\w+/
literalstart = 'SMARTYldelliteralSMARTYrdel'
literalend = 'SMARTYldel/literalSMARTYrdel'
ldelim = 'SMARTYldelldelimSMARTYrdel'
rdelim = 'SMARTYldelrdelimSMARTYrdel'
equals = /\s*==\s*|\s+(EQ|eq)\s+/
notequals = /\s*\!=\s*|\s+(NE|ne)\s+/
greaterthan = /\s*\>\s*|\s+(GT|gt)\s+/
lessthan = /\s*\<\s*|\s+(LT|lt)\s+/
greaterequal = /\s*\>=\s*|\s+(GE|ge)\s+/
lessequal = /\s*<=\s*|\s+(LE|le)\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+/
in = /\s+(IN|in)\s+/
not = /!|(NOT|not)\s+/
land = /\s*\&\&\s*|\s+(AND|and)\s+/
lor = /\s*\|\|\s*|\s+(OR|or)\s+/
other = /./
*/
/*!lex2php
%statename START
xml {
$this->token = Smarty_Internal_Templateparser::TP_XML;
}
php {
$this->token = Smarty_Internal_Templateparser::TP_PHP;
}
shorttagstart {
$this->token = Smarty_Internal_Templateparser::TP_SHORTTAGSTART;
}
shorttagend {
$this->token = Smarty_Internal_Templateparser::TP_SHORTTAGEND;
}
phpstart {
$this->token = Smarty_Internal_Templateparser::TP_PHPSTART;
}
phpend {
$this->token = Smarty_Internal_Templateparser::TP_PHPEND;
}
commentend {
$this->token = Smarty_Internal_Templateparser::TP_COMMENTEND;
}
commentstart {
$this->token = Smarty_Internal_Templateparser::TP_COMMENTSTART;
}
escapedquotes {
$this->token = Smarty_Internal_Templateparser::TP_OTHER;
}
singlequote {
$this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTE;
}
literalstart {
$this->token = Smarty_Internal_Templateparser::TP_LITERALSTART;
}
literalend {
$this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
}
ldelim {
$this->token = Smarty_Internal_Templateparser::TP_LDELIMTAG;
}
rdelim {
$this->token = Smarty_Internal_Templateparser::TP_RDELIMTAG;
}
ldels {
$this->token = Smarty_Internal_Templateparser::TP_OTHER;
}
rdels {
$this->token = Smarty_Internal_Templateparser::TP_OTHER;
}
ldelslash {
$this->token = Smarty_Internal_Templateparser::TP_LDELSLASH;
}
ldel {
$this->token = Smarty_Internal_Templateparser::TP_LDEL;
}
rdel {
$this->token = Smarty_Internal_Templateparser::TP_RDEL;
}
in {
$this->token = Smarty_Internal_Templateparser::TP_IN;
}
boolean {
$this->token = Smarty_Internal_Templateparser::TP_BOOLEAN;
}
null {
$this->token = Smarty_Internal_Templateparser::TP_NULL;
}
identity{
$this->token = Smarty_Internal_Templateparser::TP_IDENTITY;
}
noneidentity{
$this->token = Smarty_Internal_Templateparser::TP_NONEIDENTITY;
}
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;
}
not{
$this->token = Smarty_Internal_Templateparser::TP_NOT;
}
land {
$this->token = Smarty_Internal_Templateparser::TP_LAND;
}
lor {
$this->token = Smarty_Internal_Templateparser::TP_LOR;
}
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;
}
openP {
$this->token = Smarty_Internal_Templateparser::TP_OPENP;
}
closeP {
$this->token = Smarty_Internal_Templateparser::TP_CLOSEP;
}
openB {
$this->token = Smarty_Internal_Templateparser::TP_OPENB;
}
closeB {
$this->token = Smarty_Internal_Templateparser::TP_CLOSEB;
}
ptr {
$this->token = Smarty_Internal_Templateparser::TP_PTR;
}
aptr {
$this->token = Smarty_Internal_Templateparser::TP_APTR;
}
equal {
$this->token = Smarty_Internal_Templateparser::TP_EQUAL;
}
number {
$this->token = Smarty_Internal_Templateparser::TP_NUMBER;
}
incdec {
$this->token = Smarty_Internal_Templateparser::TP_INCDEC;
}
unimath {
$this->token = Smarty_Internal_Templateparser::TP_UNIMATH;
}
math {
$this->token = Smarty_Internal_Templateparser::TP_MATH;
}
space {
$this->token = Smarty_Internal_Templateparser::TP_SPACE;
}
dollar {
$this->token = Smarty_Internal_Templateparser::TP_DOLLAR;
}
semicolon {
$this->token = Smarty_Internal_Templateparser::TP_SEMICOLON;
}
doublecolon {
$this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON;
}
colon {
$this->token = Smarty_Internal_Templateparser::TP_COLON;
}
at {
$this->token = Smarty_Internal_Templateparser::TP_AT;
}
hatch {
$this->token = Smarty_Internal_Templateparser::TP_HATCH;
}
quote {
$this->token = Smarty_Internal_Templateparser::TP_QUOTE;
}
backtick {
$this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
}
vert {
$this->token = Smarty_Internal_Templateparser::TP_VERT;
}
dot {
$this->token = Smarty_Internal_Templateparser::TP_DOT;
}
comma {
$this->token = Smarty_Internal_Templateparser::TP_COMMA;
}
andsym {
$this->token = Smarty_Internal_Templateparser::TP_ANDSYM;
}
id {
$this->token = Smarty_Internal_Templateparser::TP_ID;
}
other {
$this->token = Smarty_Internal_Templateparser::TP_OTHER;
}
*/
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,452 @@
/**
* Smarty Internal Plugin Templateparser
*
* This is the template parser
*
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
%name TP_
%declare_class {class Smarty_Internal_Templateparser}
%include_class
{
// states whether the parse was successful or not
public $successful = true;
public $retvalue = 0;
private $lex;
private $internalError = false;
function __construct($lex, $compiler) {
// set instance object
self::instance($this);
$this->lex = $lex;
$this->smarty = Smarty::instance();
$this->compiler = $compiler;
$this->template = $this->compiler->template;
$this->cacher = $this->template->cacher_object;
$this->nocache = false;
$this->prefix_code = array();
$this->prefix_number = 0;
}
public static function &instance($new_instance = null)
{
static $instance = null;
if (isset($new_instance) && is_object($new_instance))
$instance = $new_instance;
return $instance;
}
}
%token_prefix TP_
%parse_accept
{
$this->successful = !$this->internalError;
$this->internalError = false;
$this->retvalue = $this->_retvalue;
//echo $this->retvalue."\n\n";
}
%syntax_error
{
$this->internalError = true;
$this->yymajor = $yymajor;
$this->compiler->trigger_template_error();
}
//
// fallback definition to catch all non Smarty template text
//
%fallback OTHER LDELSLASH LDEL RDEL XML PHP SHORTTAGSTART SHORTTAGEND COMMENTEND COMMENTSTART NUMBER MATH UNIMATH INCDEC OPENP CLOSEP OPENB CLOSEB DOLLAR DOT COMMA COLON DOUBLECOLON SEMICOLON
VERT EQUAL SPACE PTR APTR ID EQUALS NOTEQUALS GREATERTHAN LESSTHAN GREATEREQUAL LESSEQUAL IDENTITY NONEIDENTITY
NOT LAND LOR QUOTE SINGLEQUOTE BOOLEAN NULL IN ANDSYM BACKTICK HATCH AT ISODD ISNOTODD ISEVEN ISNOTEVEN ISODDBY ISNOTODDBY
ISEVENBY ISNOTEVENBY ISDIVBY ISNOTDIVBY.
//
// complete template
//
start(res) ::= template(t). { res = t; }
//
// loop over template elements
//
// single template element
template(res) ::= template_element(e). {res = e;}
// loop of elements
template(res) ::= template(t) template_element(e). {res = t.e;}
//
// template elements
//
// Smarty tag
template_element(res)::= smartytag(st). {if ($this->compiler->has_code) {
$tmp =''; foreach ($this->prefix_code as $code) {$tmp.=$code;} $this->prefix_code=array();
res = $this->cacher->processNocacheCode($tmp.st, $this->compiler,$this->nocache,true);
} $this->nocache=false;}
// comments
//template_element(res)::= COMMENT(t). { res = $this->cacher->processNocacheCode('<?php /* comment placeholder */?>', $this->compiler,false,false);}
//template_element(res)::= COMMENTSTART text(t) COMMENTEND. {if ($this->smarty->comment_mode ==0) {
// res = '';
// }elseif ($this->smarty->comment_mode ==1){
// res = $this->cacher->processNocacheCode('<?php /* comment placeholder */?>', $this->compiler,false,false);
// }else{
// res = $this->cacher->processNocacheCode('<?php /* '.str_replace('*/', '', t).'*/?>', $this->compiler,false,false);
// }}
template_element(res)::= COMMENTSTART text(t) COMMENTEND. { res = '';}
// Literal
template_element(res)::= LITERALSTART text(t) LITERALEND. {res = $this->cacher->processNocacheCode(t, $this->compiler,false,false);}
// {ldelim}
template_element(res)::= LDELIMTAG. {res = $this->cacher->processNocacheCode($this->smarty->left_delimiter, $this->compiler,false,false);}
// {rdelim}
template_element(res)::= RDELIMTAG. {res = $this->cacher->processNocacheCode($this->smarty->right_delimiter, $this->compiler,false,false);}
// <?php> tag
template_element(res)::= PHP(phpt). {if (!$this->template->security) {
res = $this->cacher->processNocacheCode(phpt, $this->compiler, false,true);
} elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_QUOTE) {
res = $this->cacher->processNocacheCode(htmlspecialchars(phpt, ENT_QUOTES), $this->compiler, false, false);
}elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_PASSTHRU || $this->smarty->security_policy->php_handling == SMARTY_PHP_ALLOW) {
res = $this->cacher->processNocacheCode("<?php echo '".phpt."';?>\n", $this->compiler, false, false);
}elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_REMOVE) {
res = '';
} }
// {PHP} tag
template_element(res)::= PHPSTART text(t) PHPEND. {if (!$this->template->security) {
res = $this->cacher->processNocacheCode('<?php '.t.' ?>', $this->compiler, false,true);
} elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_QUOTE) {
res = $this->cacher->processNocacheCode(htmlspecialchars('<?php '.t.' ?>', ENT_QUOTES), $this->compiler, false, false);
}elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_PASSTHRU || $this->smarty->security_policy->php_handling == SMARTY_PHP_ALLOW) {
res = $this->cacher->processNocacheCode("<?php echo '<?php ".t." ?>';?>\n", $this->compiler, false, false);
}elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_REMOVE) {
res = '';
} }
template_element(res)::= SHORTTAGSTART variable(v) SHORTTAGEND. {if (!$this->template->security) {
res = $this->cacher->processNocacheCode($this->compiler->compileTag('print_expression',array('value'=>v)), $this->compiler, false,true);
} elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_QUOTE) {
res = $this->cacher->processNocacheCode(htmlspecialchars('<?php '.t.' ?>', ENT_QUOTES), $this->compiler, false, false);
}elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_PASSTHRU || $this->smarty->security_policy->php_handling == SMARTY_PHP_ALLOW) {
res = $this->cacher->processNocacheCode("<?php echo '<?php ".t." ?>';?>\n", $this->compiler, false, false);
}elseif ($this->smarty->security_policy->php_handling == SMARTY_PHP_REMOVE) {
res = '';
} }
// XML tag
template_element(res)::= XML(xml). {res = $this->cacher->processNocacheCode("<?php echo '".xml."';?>\n", $this->compiler, true, true);}
// Other template text
template_element(res)::= OTHER(o). {res = $this->cacher->processNocacheCode(o, $this->compiler,false,false);}
//template_element(res)::= text(t). {res = $this->cacher->processNocacheCode(t, $this->compiler,false,false);}
//
// all Smarty tags start here
//
// output with optional attributes
smartytag(res) ::= LDEL expr(e) attributes(a) RDEL. { res = $this->compiler->compileTag('print_expression',array_merge(array('value'=>e),a));}
// assign new style
smartytag(res) ::= LDEL statement(s) RDEL. { res = $this->compiler->compileTag('assign',s);}
// tag with optional Smarty2 style attributes
smartytag(res) ::= LDEL ID(i) attributes(a) RDEL. { res = $this->compiler->compileTag(i,a);}
// registered object tag
smartytag(res) ::= LDEL ID(i) PTR ID(m) attributes(a) RDEL. { res = $this->compiler->compileTag(i,array_merge(array('object_methode'=>m),a));}
// tag with modifier and optional Smarty2 style attributes
smartytag(res) ::= LDEL ID(i) modifier(m) modparameters(p) attributes(a) RDEL. { res = '<?php ob_start();?>'.$this->compiler->compileTag(i,a).'<?php echo ';
if ($this->smarty->plugin_handler->loadSmartyPlugin(m[0],'modifier')) {
res .= "\$_smarty_tpl->smarty->plugin_handler->".m[0] . "(array(ob_get_clean()". p ."),'modifier');?>";
} else {
if (m[0] == 'isset' || m[0] == 'empty' || is_callable(m[0])) {
if (!$this->template->security || $this->smarty->security_handler->isTrustedModifier(m[0], $this->compiler)) {
res .= m[0] . "(ob_get_clean()". p .");?>";
}
} else {
$this->compiler->trigger_template_error ("unknown modifier \"" . m[0] . "\"");
}
}
}
// end of block tag {/....}
smartytag(res) ::= LDELSLASH ID(i) attributes(a) RDEL. { res = $this->compiler->compileTag(i.'close',a);}
// end of block object tag {/....}
smartytag(res) ::= LDELSLASH ID(i) PTR ID(m) RDEL. { res = $this->compiler->compileTag(i.'close',array('object_methode'=>m));}
// {if}, {elseif} and {while} tag
smartytag(res) ::= LDEL ID(i)SPACE ifexprs(ie) RDEL. { res = $this->compiler->compileTag(i,array('if condition'=>ie));}
// {for} tag
smartytag(res) ::= LDEL ID(i) SPACE statements(s) SEMICOLON ifexprs(ie) SEMICOLON DOLLAR varvar(v2) foraction(e2) RDEL. { res = $this->compiler->compileTag(i,array('start'=>s,'ifexp'=>ie,'varloop'=>v2,'loop'=>e2));}
foraction(res) ::= EQUAL expr(e). { res = '='.e;}
foraction(res) ::= INCDEC(e). { res = e;}
// {for $var in $array} tag
// replaced with next line because config vars could an array!! smartytag(res) ::= LDEL ID(i) SPACE DOLLAR varvar(v0) IN variable(v1) RDEL. { res = $this->compiler->compileTag(i,array('from'=>v1,'item'=>v0));}
smartytag(res) ::= LDEL ID(i) SPACE DOLLAR varvar(v0) IN value(v1) RDEL. { res = $this->compiler->compileTag(i,array('from'=>v1,'item'=>v0));}
smartytag(res) ::= LDEL ID(i) SPACE DOLLAR varvar(v0) IN array(a) RDEL. { res = $this->compiler->compileTag(i,array('from'=>a,'item'=>v0));}
//
//Attributes of Smarty tags
//
// list of attributes
attributes(res) ::= attributes(a1) attribute(a2). { res = array_merge(a1,a2);}
// single attribute
attributes(res) ::= attribute(a). { res = a;}
// no attributes
attributes(res) ::= . { res = array();}
// different formats of attribute
//attribute(res) ::= SPACE ID(v) EQUAL ID(i). { res = array(v=>'\''.i.'\'');}
attribute(res) ::= SPACE ID(v) EQUAL expr(e). { res = array(v=>e);}
//
// statement
//
statements(res) ::= statement(s). { res = array(s);}
statements(res) ::= statements(s1) COMMA statement(s). { s1[]=s; res = s1;}
statement(res) ::= DOLLAR varvar(v) EQUAL expr(e). { res = array('var' => v, 'value'=>e);}
//statement(res) ::= DOLLAR varvar(v) EQUAL ID(i). { res = array('var' => v, 'value'=>'\''.i.'\'');}
//
// expressions
//
// simple expression
expr(res) ::= ID(i). { res = '\''.i.'\''; }
//expr(res) ::= UNQ_STR(s). { res = '\''.s.'\''; }
//expr(res) ::= ID(i). { res = i; }
expr(res) ::= exprs(e). {res = e;}
expr(res) ::= expr(e) modifier(m) modparameters(p). {
if ($this->smarty->plugin_handler->loadSmartyPlugin(m[0],'modifier')) {
res = "\$_smarty_tpl->smarty->plugin_handler->".m[0] . "(array(". e . p ."),'modifier')";
} else {
if (m[0] == 'isset' || m[0] == 'empty' || is_callable(m[0])) {
if (!$this->template->security || $this->smarty->security_handler->isTrustedModifier(m[0], $this->compiler)) {
res = m[0] . "(". e . p .")";
}
} else {
$this->compiler->trigger_template_error ("unknown modifier \"" . m[0] . "\"");
}
}
}
exprs(res) ::= array(a). {res = a;}
// single value
exprs(res) ::= value(v). { res = v; }
// +/- value
exprs(res) ::= UNIMATH(m) value(v). { res = m.v; }
// arithmetic expression
exprs(res) ::= exprs(e) math(m) value(v). { res = e . m . v; }
// catenate
exprs(res) ::= exprs(e) ANDSYM value(v). { res = '('. e . ').(' . v. ')'; }
//
// mathematical operators
//
// +,-
math(res) ::= UNIMATH(m). {res = m;}
// *,/,%
math(res) ::= MATH(m). {res = m;}
// value
value(res) ::= variable(v). { res = v; }
// config variable
value(res) ::= HATCH ID(i) HATCH. {res = '$_smarty_tpl->getConfigVariable(\''. i .'\')';}
// numeric
value(res) ::= NUMBER(n). { res = n; }
// boolean
value(res) ::= BOOLEAN(b). { res = b; }
// null
value(res) ::= NULL(n). { res = n; }
// function call
value(res) ::= function(f). { res = f; }
// expression
value(res) ::= OPENP expr(e) CLOSEP. { res = "(". e .")"; }
// singele quoted string
value(res) ::= SINGLEQUOTE text(t) SINGLEQUOTE. { res = "'".t."'"; }
value(res) ::= SINGLEQUOTE SINGLEQUOTE. { res = "''"; }
// double quoted string
value(res) ::= QUOTE doublequoted(s) QUOTE. { res = "'".str_replace('\"','"',s)."'"; }
//value(res) ::= QUOTE doublequoted(s) QUOTE. { res = "'".addcslashes(str_replace(array('\"'),array('"'),s),"'")."'"; }
//value(res) ::= QUOTE doublequoted(s) QUOTE. { res = "'".s."'"; var_dump(s);}
value(res) ::= QUOTE QUOTE. { res = "''"; }
// static class methode call
value(res) ::= ID(c) DOUBLECOLON method(m). { res = c.'::'.m; }
value(res) ::= ID(c) DOUBLECOLON DOLLAR ID(f) OPENP params(p) CLOSEP. { $this->prefix_number++; $this->prefix_code[] = '<?php $_tmp'.$this->prefix_number.'=$_smarty_tpl->getVariable(\''. f .'\')->value;?>'; res = c.'::$_tmp'.$this->prefix_number.'('. p .')'; }
// static class methode call with object chainig
value(res) ::= ID(c) DOUBLECOLON method(m) objectchain(oc). { res = c.'::'.m.oc; }
value(res) ::= ID(c) DOUBLECOLON DOLLAR ID(f) OPENP params(p) CLOSEP objectchain(oc). { $this->prefix_number++; $this->prefix_code[] = '<?php $_tmp'.$this->prefix_number.'=$_smarty_tpl->getVariable(\''. f .'\')->value;?>'; res = c.'::$_tmp'.$this->prefix_number.'('. p .')'.oc; }
// static class constant
value(res) ::= ID(c) DOUBLECOLON ID(v). { res = c.'::'.v;}
// static class variables
value(res) ::= ID(c) DOUBLECOLON DOLLAR ID(v) arrayindex(a). { res = c.'::$'.v.a;}
// static class variables with object chain
value(res) ::= ID(c) DOUBLECOLON DOLLAR ID(v) arrayindex(a) objectchain(oc). { res = c.'::$'.v.a.oc;}
//
// variables
//
// simple Smarty variable (optional array)
variable(res) ::= DOLLAR varvar(v) arrayindex(a). { if (v == '\'smarty\'') { res = $this->compiler->compileTag(trim(v,"'"),a);} else {
res = '$_smarty_tpl->getVariable('. v .')->value'.a; $this->nocache=$this->template->getVariable(trim(v,"'"))->nocache;}}
// variable with property
variable(res) ::= DOLLAR varvar(v) AT ID(p). { res = '$_smarty_tpl->getVariable('. v .')->'.p; $this->nocache=$this->template->getVariable(trim(v,"'"))->nocache;}
// object
variable(res) ::= object(o). { res = o; }
// config variable
//variable(res) ::= HATCH ID(i) HATCH. {res = '$_smarty_tpl->getConfigVariable(\''. i .'\')';}
//
// array index
//
// multiple array index
arrayindex(res) ::= arrayindex(a1) indexdef(a2). {res = a1.a2;}
// no array index
arrayindex ::= . {return;}
// single index definition
// Smarty2 style index
indexdef(res) ::= DOT ID(i). { res = "['". i ."']";}
indexdef(res) ::= DOT exprs(e). { res = "[". e ."]";}
// section tag index
indexdef(res) ::= OPENB ID(i)CLOSEB. { res = '['.$this->compiler->compileTag('smarty','[\'section\'][\''.i.'\'][\'index\']').']';}
// PHP style index
indexdef(res) ::= OPENB exprs(e) CLOSEB. { res = "[". e ."]";}
//
// variable variable names
//
// singel identifier element
varvar(res) ::= varvarele(v). {res = v;}
// sequence of identifier elements
varvar(res) ::= varvar(v1) varvarele(v2). {res = v1.'.'.v2;}
// fix sections of element
varvarele(res) ::= ID(s). {res = '\''.s.'\'';}
// variable sections of element
varvarele(res) ::= LDEL expr(e) RDEL. {res = '('.e.')';}
//
// objects
//
object(res) ::= DOLLAR varvar(v) arrayindex(a) objectchain(oc). { res = '$_smarty_tpl->getVariable('. v .')->value'.a.oc; $this->nocache=$this->template->getVariable(trim(v,"'"))->nocache;}
// single element
objectchain(res) ::= objectelement(oe). {res = oe; }
// chain of elements
objectchain(res) ::= objectchain(oc) objectelement(oe). {res = oc.oe; }
// variable
objectelement(res)::= PTR ID(i) arrayindex(a). { res = '->'.i.a;}
//objectelement(res)::= PTR varvar(v) arrayindex(a). { res = '->'.v.a;}
// method
objectelement(res)::= PTR method(f). { res = '->'.f;}
//
// function
//
function(res) ::= ID(f) OPENP params(p) CLOSEP. {if (!$this->template->security || $this->smarty->security_handler->isTrustedPhpFunction(f, $this->compiler)) {
if (f == 'isset' || f == 'empty' || is_callable(f)) {
res = f . "(". p .")";
} else {
$this->compiler->trigger_template_error ("unknown function \"" . f . "\"");
}
}}
//
// method
//
method(res) ::= ID(f) OPENP params(p) CLOSEP. { res = f . "(". p .")";}
// function/method parameter
// multiple parameters
params(res) ::= expr(e) COMMA params(p). { res = e.",".p;}
// single parameter
params(res) ::= expr(e). { res = e;}
// kein parameter
params ::= . { return;}
//
// modifier
//
modifier(res) ::= VERT AT ID(m). { res = array(m,true);}
modifier(res) ::= VERT ID(m). { res = array(m,false);}
//
// modifier parameter
//
// multiple parameter
modparameters(res) ::= modparameters(mps) modparameter(mp). { res = mps.mp;}
// no parameter
modparameters ::= . {return;}
// parameter expression
modparameter(res) ::= COLON ID(mp). {res = ',\''.mp.'\'';}
modparameter(res) ::= COLON exprs(mp). {res = ','.mp;}
//
// if expressions
//
// single if expression
ifexprs(res) ::= ifexpr(e). {res = e;}
ifexprs(res) ::= NOT ifexprs(e). {res = '!'.e;}
ifexprs(res) ::= OPENP ifexprs(e) CLOSEP. {res = '('.e.')';}
// if expression
// simple expression
ifexpr(res) ::= expr(e). {res =e;}
ifexpr(res) ::= expr(e1) ifcond(c) expr(e2). {res = e1.c.e2;}
ifexpr(res) ::= ifexprs(e1) lop(o) ifexprs(e2). {res = e1.o.e2;}
ifexpr(res) ::= ifexprs(e1) ISDIVBY ifexprs(e2). {res = '!('.e1.' % '.e2.')';}
ifexpr(res) ::= ifexprs(e1) ISNOTDIVBY ifexprs(e2). {res = '('.e1.' % '.e2.')';}
ifexpr(res) ::= ifexprs(e1) ISEVEN. {res = '!(1 & '.e1.')';}
ifexpr(res) ::= ifexprs(e1) ISNOTEVEN. {res = '(1 & '.e1.')';}
ifexpr(res) ::= ifexprs(e1) ISEVENBY ifexprs(e2). {res = '!(1 & '.e1.' / '.e2.')';}
ifexpr(res) ::= ifexprs(e1) ISNOTEVENBY ifexprs(e2). {res = '(1 & '.e1.' / '.e2.')';}
ifexpr(res) ::= ifexprs(e1) ISODD. {res = '(1 & '.e1.')';}
ifexpr(res) ::= ifexprs(e1) ISNOTODD. {res = '!(1 & '.e1.')';}
ifexpr(res) ::= ifexprs(e1) ISODDBY ifexprs(e2). {res = '(1 & '.e1.' / '.e2.')';}
ifexpr(res) ::= ifexprs(e1) ISNOTODDBY ifexprs(e2). {res = '!(1 & '.e1.' / '.e2.')';}
ifcond(res) ::= EQUALS. {res = '==';}
ifcond(res) ::= NOTEQUALS. {res = '!=';}
ifcond(res) ::= GREATERTHAN. {res = '>';}
ifcond(res) ::= LESSTHAN. {res = '<';}
ifcond(res) ::= GREATEREQUAL. {res = '>=';}
ifcond(res) ::= LESSEQUAL. {res = '<=';}
ifcond(res) ::= IDENTITY. {res = '===';}
ifcond(res) ::= NONEIDENTITY. {res = '!==';}
lop(res) ::= LAND. {res = '&&';}
lop(res) ::= LOR. {res = '||';}
//
// ARRAY element assignment
//
array(res) ::= OPENB arrayelements(a) CLOSEB. { res = 'array('.a.')';}
arrayelements(res) ::= arrayelement(a). { res = a; }
arrayelements(res) ::= arrayelements(a1) COMMA arrayelement(a). { res = a1.','.a; }
arrayelements ::= . { return; }
arrayelement(res) ::= expr(e). { res = e;}
arrayelement(res) ::= expr(e1) APTR expr(e2). { res = e1.'=>'.e2;}
arrayelement(res) ::= ID(i) APTR expr(e2). { res = '\''.i.'\'=>'.e2;}
//
// double qouted strings
//
doublequoted(res) ::= doublequoted(o1) doublequotedcontent(o2). {res = o1.o2;}
doublequoted(res) ::= doublequotedcontent(o). {res = o;}
doublequotedcontent(res) ::= variable(v). {res = "'.".v.".'";}
doublequotedcontent(res) ::= BACKTICK variable(v) BACKTICK. {res = "'.".v.".'";}
doublequotedcontent(res) ::= LDEL expr(e) RDEL. {res = "'.(".e.").'";}
doublequotedcontent(res) ::= OTHER(o). {res = addcslashes(o,"'");}
//doublequotedcontent(res) ::= OTHER(o). {res = o;}
//doublequotedcontent(res) ::= text(t). {res = addcslashes(t,"'");}
//
// text string
//
text(res) ::= text(t) textelement(e). {res = t.e;}
text(res) ::= textelement(e). {res = e;}
textelement(res) ::= OTHER(o). {res = o;}
textelement(res) ::= LDEL(o). {res = o;}

View File

@@ -0,0 +1,103 @@
<?php
/**
* Smarty plugin to format text blocks
*
* @package Smarty
* @subpackage PluginsBlock
*/
/**
* Smarty {textformat}{/textformat} block plugin
*
* Type: block function<br>
* Name: textformat<br>
* Purpose: format text a certain way with preset styles
* or custom wrap/indent settings<br>
*
* @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat}
(Smarty online manual)
* @param array $params parameters
* <pre>
* Params: style: string (email)
* indent: integer (0)
* wrap: integer (80)
* wrap_char string ("\n")
* indent_char: string (" ")
* wrap_boundary: boolean (true)
* </pre>
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $content contents of the block
* @param object $smarty Smarty object
* @param boolean &$repeat repeat flag
* @param object $template template object
* @return string content re-formatted
*/
function smarty_block_textformat($params, $content, $smarty, &$repeat, $template)
{
if (is_null($content)) {
return;
}
$style = null;
$indent = 0;
$indent_first = 0;
$indent_char = ' ';
$wrap = 80;
$wrap_char = "\n";
$wrap_cut = false;
$assign = null;
foreach ($params as $_key => $_val) {
switch ($_key) {
case 'style':
case 'indent_char':
case 'wrap_char':
case 'assign':
$$_key = (string)$_val;
break;
case 'indent':
case 'indent_first':
case 'wrap':
$$_key = (int)$_val;
break;
case 'wrap_cut':
$$_key = (bool)$_val;
break;
default:
$smarty->trigger_error("textformat: unknown attribute '$_key'");
}
}
if ($style == 'email') {
$wrap = 72;
}
// split into paragraphs
$_paragraphs = preg_split('![\r\n][\r\n]!', $content);
$_output = '';
for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) {
if ($_paragraphs[$_x] == '') {
continue;
}
// convert mult. spaces & special chars to single space
$_paragraphs[$_x] = preg_replace(array('!\s+!', '!(^\s+)|(\s+$)!'), array(' ', ''), $_paragraphs[$_x]);
// indent first line
if ($indent_first > 0) {
$_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x];
}
// wordwrap sentences
$_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut);
// indent lines
if ($indent > 0) {
$_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]);
}
}
$_output = implode($wrap_char . $wrap_char, $_paragraphs);
return $assign ? $template->assign($assign, $_output) : $_output;
}
?>

View File

@@ -0,0 +1,78 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {counter} function plugin
*
* Type: function<br>
* Name: counter<br>
* Purpose: print out a counter value
* @author Monte Ohrt <monte at ohrt dot com>
* @link http://smarty.php.net/manual/en/language.function.counter.php {counter}
* (Smarty online manual)
* @param array $params parameters
* @param object $smarty Smarty object
* @param object $template template object
* @return string|null
*/
function smarty_function_counter($params, $smarty, $template)
{
$name = (isset($params['name'])) ? $params['name'] : 'default';
if (!isset($template->plugin_data['counter'][$name])) {
$template->plugin_data['counter'][$name] = array(
'start'=>1,
'skip'=>1,
'direction'=>'up',
'count'=>1
);
}
$counter = &$template->plugin_data['counter'][$name];
if (isset($params['start'])) {
$counter['start'] = $counter['count'] = (int)$params['start'];
}
if (!empty($params['assign'])) {
$counter['assign'] = $params['assign'];
}
if (isset($counter['assign'])) {
$template->assign($counter['assign'], $counter['count']);
}
if (isset($params['print'])) {
$print = (bool)$params['print'];
} else {
$print = empty($counter['assign']);
}
if ($print) {
$retval = $counter['count'];
} else {
$retval = null;
}
if (isset($params['skip'])) {
$counter['skip'] = $params['skip'];
}
if (isset($params['direction'])) {
$counter['direction'] = $params['direction'];
}
if ($counter['direction'] == "down")
$counter['count'] -= $counter['skip'];
else
$counter['count'] += $counter['skip'];
return $retval;
}
?>

View File

@@ -0,0 +1,97 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {cycle} function plugin
*
* Type: function<br>
* Name: cycle<br>
* Date: May 3, 2002<br>
* Purpose: cycle through given values<br>
*
* Examples:<br>
* <pre>
* {cycle values="#eeeeee,#d0d0d0d"}
* {cycle name=row values="one,two,three" reset=true}
* {cycle name=row}
* </pre>
* @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @author credit to Mark Priatel <mpriatel@rogers.com>
* @author credit to Gerard <gerard@interfold.com>
* @author credit to Jason Sweat <jsweat_php@yahoo.com>
* @param array $params parameters
* Input:
* - name = name of cycle (optional)
* - values = comma separated list of values to cycle,
* or an array of values to cycle
* (this can be left out for subsequent calls)
* - reset = boolean - resets given var to true
* - print = boolean - print var or not. default is true
* - advance = boolean - whether or not to advance the cycle
* - delimiter = the value delimiter, default is ","
* - assign = boolean, assigns to template var instead of
* printed.
* @param object $smarty Smarty object
* @param object $template template object
* @return string|null
*/
function smarty_function_cycle($params, $smarty, $template)
{
$name = (empty($params['name'])) ? 'default' : $params['name'];
$print = (isset($params['print'])) ? (bool)$params['print'] : true;
$advance = (isset($params['advance'])) ? (bool)$params['advance'] : true;
$reset = (isset($params['reset'])) ? (bool)$params['reset'] : false;
if (!in_array('values', array_keys($params))) {
if(!isset($template->plugin_data['cycle'][$name]['values'])) {
throw new Exception ("cycle: missing 'values' parameter");
return;
}
} else {
if(isset($template->plugin_data['cycle'][$name]['values'])
&& $template->plugin_data['cycle'][$name]['values'] != $params['values'] ) {
$template->plugin_data['cycle'][$name]['index'] = 0;
}
$template->plugin_data['cycle'][$name]['values'] = $params['values'];
}
$template->plugin_data['cycle'][$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ',';
if(is_array($template->plugin_data['cycle'][$name]['values'])) {
$cycle_array = $template->plugin_data['cycle'][$name]['values'];
} else {
$cycle_array = explode($template->plugin_data['cycle'][$name]['delimiter'],$template->plugin_data['cycle'][$name]['values']);
}
if(!isset($template->plugin_data['cycle'][$name]['index']) || $reset ) {
$template->plugin_data['cycle'][$name]['index'] = 0;
}
if (isset($params['assign'])) {
$print = false;
$template->assign($params['assign'], $cycle_array[$template->plugin_data['cycle'][$name]['index']]);
}
if($print) {
$retval = $cycle_array[$template->plugin_data['cycle'][$name]['index']];
} else {
$retval = null;
}
if($advance) {
if ( $template->plugin_data['cycle'][$name]['index'] >= count($cycle_array) -1 ) {
$template->plugin_data['cycle'][$name]['index'] = 0;
} else {
$template->plugin_data['cycle'][$name]['index']++;
}
}
return $retval;
}
?>

View File

@@ -0,0 +1,217 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {fetch} plugin
*
* Type: function<br>
* Name: fetch<br>
* Purpose: fetch file, web or ftp data and display results
* @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param array $params parameters
* @param object $smarty Smarty object
* @param object $template template object
* @return string|null if the assign parameter is passed, Smarty assigns the
* result to a template variable
*/
function smarty_function_fetch($params, $smarty, $template)
{
if (empty($params['file'])) {
throw new Exception ("[plugin] fetch parameter 'file' cannot be empty");
return;
}
$content = '';
if ($template->security && !preg_match('!^(http|ftp)://!i', $params['file'])) {
if(!$smarty->security_handler->isTrustedResourceDir($params['file'])) {
return;
}
// fetch the file
if($fp = @fopen($params['file'],'r')) {
while(!feof($fp)) {
$content .= fgets ($fp,4096);
}
fclose($fp);
} else {
throw new Exception ('[plugin] fetch cannot read file \'' . $params['file'] . '\'');
return;
}
} else {
// not a local file
if(preg_match('!^http://!i',$params['file'])) {
// http fetch
if($uri_parts = parse_url($params['file'])) {
// set defaults
$host = $server_name = $uri_parts['host'];
$timeout = 30;
$accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
$agent = "Smarty Template Engine ".$smarty->_version;
$referer = "";
$uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/';
$uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : '';
$_is_proxy = false;
if(empty($uri_parts['port'])) {
$port = 80;
} else {
$port = $uri_parts['port'];
}
if(!empty($uri_parts['user'])) {
$user = $uri_parts['user'];
}
if(!empty($uri_parts['pass'])) {
$pass = $uri_parts['pass'];
}
// loop through parameters, setup headers
foreach($params as $param_key => $param_value) {
switch($param_key) {
case "file":
case "assign":
case "assign_headers":
break;
case "user":
if(!empty($param_value)) {
$user = $param_value;
}
break;
case "pass":
if(!empty($param_value)) {
$pass = $param_value;
}
break;
case "accept":
if(!empty($param_value)) {
$accept = $param_value;
}
break;
case "header":
if(!empty($param_value)) {
if(!preg_match('![\w\d-]+: .+!',$param_value)) {
throw new Exception ("[plugin] invalid header format '".$param_value."'");
return;
} else {
$extra_headers[] = $param_value;
}
}
break;
case "proxy_host":
if(!empty($param_value)) {
$proxy_host = $param_value;
}
break;
case "proxy_port":
if(!preg_match('!\D!', $param_value)) {
$proxy_port = (int) $param_value;
} else {
throw new Exception ("[plugin] invalid value for attribute '".$param_key."'");
return;
}
break;
case "agent":
if(!empty($param_value)) {
$agent = $param_value;
}
break;
case "referer":
if(!empty($param_value)) {
$referer = $param_value;
}
break;
case "timeout":
if(!preg_match('!\D!', $param_value)) {
$timeout = (int) $param_value;
} else {
throw new Exception ("[plugin] invalid value for attribute '".$param_key."'");
return;
}
break;
default:
throw new Exception ("[plugin] unrecognized attribute '".$param_key."'");
return;
}
}
if(!empty($proxy_host) && !empty($proxy_port)) {
$_is_proxy = true;
$fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout);
} else {
$fp = fsockopen($server_name,$port,$errno,$errstr,$timeout);
}
if(!$fp) {
throw new Exception ("[plugin] unable to fetch: $errstr ($errno)");
return;
} else {
if($_is_proxy) {
fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n");
} else {
fputs($fp, "GET $uri HTTP/1.0\r\n");
}
if(!empty($host)) {
fputs($fp, "Host: $host\r\n");
}
if(!empty($accept)) {
fputs($fp, "Accept: $accept\r\n");
}
if(!empty($agent)) {
fputs($fp, "User-Agent: $agent\r\n");
}
if(!empty($referer)) {
fputs($fp, "Referer: $referer\r\n");
}
if(isset($extra_headers) && is_array($extra_headers)) {
foreach($extra_headers as $curr_header) {
fputs($fp, $curr_header."\r\n");
}
}
if(!empty($user) && !empty($pass)) {
fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n");
}
fputs($fp, "\r\n");
while(!feof($fp)) {
$content .= fgets($fp,4096);
}
fclose($fp);
$csplit = split("\r\n\r\n",$content,2);
$content = $csplit[1];
if(!empty($params['assign_headers'])) {
$template->assign($params['assign_headers'],split("\r\n",$csplit[0]));
}
}
} else {
throw new Exception ("[plugin] unable to parse URL, check syntax");
return;
}
} else {
// ftp fetch
if($fp = @fopen($params['file'],'r')) {
while(!feof($fp)) {
$content .= fgets ($fp,4096);
}
fclose($fp);
} else {
throw new Exception ('[plugin] fetch cannot read file \'' . $params['file'] .'\'');
return;
}
}
}
if (!empty($params['assign'])) {
$template->assign($params['assign'],$content);
} else {
return $content;
}
}
?>

View File

@@ -0,0 +1,144 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_checkboxes} function plugin
*
* File: function.html_checkboxes.php<br>
* Type: function<br>
* Name: html_checkboxes<br>
* Date: 24.Feb.2003<br>
* Purpose: Prints out a list of checkbox input types<br>
* Examples:
* <pre>
* {html_checkboxes values=$ids output=$names}
* {html_checkboxes values=$ids name='box' separator='<br>' output=$names}
* {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}
* </pre>
* @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes}
* (Smarty online manual)
* @author Christopher Kvarme <christopher.kvarme@flashjab.com>
* @author credits to Monte Ohrt <monte at ohrt dot com>
* @version 1.0
* @param array $params parameters
* Input:<br>
* - name (optional) - string default "checkbox"
* - values (required) - array
* - options (optional) - associative array
* - checked (optional) - array default not set
* - separator (optional) - ie <br> or &nbsp;
* - output (optional) - the output next to each checkbox
* - assign (optional) - assign the output as an array to this variable
* @param object $smarty Smarty object
* @param object $template template object
* @return string
* @uses smarty_function_escape_special_chars()
*/
function smarty_function_html_checkboxes($params, $smarty, $template)
{
$smarty->loadPlugin('Smarty_shared_escape_special_chars');
$name = 'checkbox';
$values = null;
$options = null;
$selected = null;
$separator = '';
$labels = true;
$output = null;
$extra = '';
foreach($params as $_key => $_val) {
switch($_key) {
case 'name':
case 'separator':
$$_key = $_val;
break;
case 'labels':
$$_key = (bool)$_val;
break;
case 'options':
$$_key = (array)$_val;
break;
case 'values':
case 'output':
$$_key = array_values((array)$_val);
break;
case 'checked':
case 'selected':
$selected = array_map('strval', array_values((array)$_val));
break;
case 'checkboxes':
throw new Exception ('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING);
$options = (array)$_val;
break;
case 'assign':
break;
default:
if(!is_array($_val)) {
$extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
} else {
throw new Exception ("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (!isset($options) && !isset($values))
return ''; /* raise error here? */
settype($selected, 'array');
$_html_result = array();
if (isset($options)) {
foreach ($options as $_key=>$_val)
$_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
} else {
foreach ($values as $_i=>$_key) {
$_val = isset($output[$_i]) ? $output[$_i] : '';
$_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
}
}
if(!empty($params['assign'])) {
$template->assign($params['assign'], $_html_result);
} else {
return implode("\n",$_html_result);
}
}
function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) {
$_output = '';
if ($labels) $_output .= '<label>';
$_output .= '<input type="checkbox" name="'
. smarty_function_escape_special_chars($name) . '[]" value="'
. smarty_function_escape_special_chars($value) . '"';
if (in_array((string)$value, $selected)) {
$_output .= ' checked="checked"';
}
$_output .= $extra . ' />' . $output;
if ($labels) $_output .= '</label>';
$_output .= $separator;
return $_output;
}
?>

View File

@@ -0,0 +1,138 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_image} function plugin
*
* Type: function<br>
* Name: html_image<br>
* Date: Feb 24, 2003<br>
* Purpose: format HTML tags for the image<br>
* Examples: {html_image file="/images/masthead.gif"}
* Output: <img src="/images/masthead.gif" width=400 height=23>
*
* @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image}
(Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @author credits to Duda <duda@big.hu>
* @version 1.0
* @param array $params parameters
* Input:<br>
* - file = file (and path) of image (required)
* - height = image height (optional, default actual height)
* - width = image width (optional, default actual width)
* - basedir = base directory for absolute paths, default
* is environment variable DOCUMENT_ROOT
* - path_prefix = prefix for path output (optional, default empty)
* @param object $smarty Smarty object
* @param object $template template object
* @return string
* @uses smarty_function_escape_special_chars()
*/
function smarty_function_html_image($params, $smarty, $template)
{
$smarty->loadPlugin('Smarty_shared_escape_special_chars');
$alt = '';
$file = '';
$height = '';
$width = '';
$extra = '';
$prefix = '';
$suffix = '';
$path_prefix = '';
$server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
$basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : '';
foreach($params as $_key => $_val) {
switch ($_key) {
case 'file':
case 'height':
case 'width':
case 'dpi':
case 'path_prefix':
case 'basedir':
$$_key = $_val;
break;
case 'alt':
if (!is_array($_val)) {
$$_key = smarty_function_escape_special_chars($_val);
} else {
throw new Exception ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
case 'link':
case 'href':
$prefix = '<a href="' . $_val . '">';
$suffix = '</a>';
break;
default:
if (!is_array($_val)) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
} else {
throw new Exception ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (empty($file)) {
throw new Exception ("html_image: missing 'file' parameter", E_USER_NOTICE);
return;
}
if (substr($file, 0, 1) == '/') {
$_image_path = $basedir . $file;
} else {
$_image_path = $file;
}
if (!isset($params['width']) || !isset($params['height'])) {
if (!$_image_data = @getimagesize($_image_path)) {
if (!file_exists($_image_path)) {
throw new Exception ("html_image: unable to find '$_image_path'", E_USER_NOTICE);
return;
} else if (!is_readable($_image_path)) {
throw new Exception ("html_image: unable to read '$_image_path'", E_USER_NOTICE);
return;
} else {
throw new Exception ("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE);
return;
}
}
if ($template->security) {
if (!$smarty->security_handler->isTrustedResourceDir($_image_path)) {
return;
}
}
if (!isset($params['width'])) {
$width = $_image_data[0];
}
if (!isset($params['height'])) {
$height = $_image_data[1];
}
}
if (isset($params['dpi'])) {
if (strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) {
$dpi_default = 72;
} else {
$dpi_default = 96;
}
$_resize = $dpi_default / $params['dpi'];
$width = round($width * $_resize);
$height = round($height * $_resize);
}
return $prefix . '<img src="' . $path_prefix . $file . '" alt="' . $alt . '" width="' . $width . '" height="' . $height . '"' . $extra . ' />' . $suffix;
}
?>

View File

@@ -0,0 +1,121 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_options} function plugin
*
* Type: function<br>
* Name: html_options<br>
* Purpose: Prints the list of <option> tags generated from
* the passed parameters
*
* @link http://smarty.php.net/manual/en/language.function.html.options.php {html_image}
(Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param array $params parameters
* Input:<br>
* - name (optional) - string default "select"
* - values (required if no options supplied) - array
* - options (required if no values supplied) - associative array
* - selected (optional) - string default not set
* - output (required if not options supplied) - array
* @param object $smarty Smarty object
* @param object $template template object
* @return string
* @uses smarty_function_escape_special_chars()
*/
function smarty_function_html_options($params, $smarty, $template)
{
$smarty->loadPlugin('Smarty_shared_escape_special_chars');
$name = null;
$values = null;
$options = null;
$selected = array();
$output = null;
$extra = '';
foreach($params as $_key => $_val) {
switch ($_key) {
case 'name':
$$_key = (string)$_val;
break;
case 'options':
$$_key = (array)$_val;
break;
case 'values':
case 'output':
$$_key = array_values((array)$_val);
break;
case 'selected':
$$_key = array_map('strval', array_values((array)$_val));
break;
default:
if (!is_array($_val)) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
} else {
throw new Exception ("html_options: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (!isset($options) && !isset($values))
return '';
/* raise error here? */
$_html_result = '';
if (isset($options)) {
foreach ($options as $_key => $_val)
$_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected);
} else {
foreach ($values as $_i => $_key) {
$_val = isset($output[$_i]) ? $output[$_i] : '';
$_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected);
}
}
if (!empty($name)) {
$_html_result = '<select name="' . $name . '"' . $extra . '>' . "\n" . $_html_result . '</select>' . "\n";
}
return $_html_result;
}
function smarty_function_html_options_optoutput($key, $value, $selected)
{
if (!is_array($value)) {
$_html_result = '<option label="' . smarty_function_escape_special_chars($value) . '" value="' .
smarty_function_escape_special_chars($key) . '"';
if (in_array((string)$key, $selected))
$_html_result .= ' selected="selected"';
$_html_result .= '>' . smarty_function_escape_special_chars($value) . '</option>' . "\n";
} else {
$_html_result = smarty_function_html_options_optgroup($key, $value, $selected);
}
return $_html_result;
}
function smarty_function_html_options_optgroup($key, $values, $selected)
{
$optgroup_html = '<optgroup label="' . smarty_function_escape_special_chars($key) . '">' . "\n";
foreach ($values as $key => $value) {
$optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected);
}
$optgroup_html .= "</optgroup>\n";
return $optgroup_html;
}
?>

View File

@@ -0,0 +1,155 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_radios} function plugin
*
* File: function.html_radios.php<br>
* Type: function<br>
* Name: html_radios<br>
* Date: 24.Feb.2003<br>
* Purpose: Prints out a list of radio input types<br>
* Examples:
* <pre>
* {html_radios values=$ids output=$names}
* {html_radios values=$ids name='box' separator='<br>' output=$names}
* {html_radios values=$ids checked=$checked separator='<br>' output=$names}
* </pre>
*
* @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios}
(Smarty online manual)
* @author Christopher Kvarme <christopher.kvarme@flashjab.com>
* @author credits to Monte Ohrt <monte at ohrt dot com>
* @version 1.0
* @param array $params parameters
* Input:<br>
* - name (optional) - string default "radio"
* - values (required) - array
* - options (optional) - associative array
* - checked (optional) - array default not set
* - separator (optional) - ie <br> or &nbsp;
* - output (optional) - the output next to each radio button
* - assign (optional) - assign the output as an array to this variable
* @param object $smarty Smarty object
* @param object $template template object
* @return string
* @uses smarty_function_escape_special_chars()
*/
function smarty_function_html_radios($params, $smarty, $template)
{
$smarty->loadPlugin('Smarty_shared_escape_special_chars');
$name = 'radio';
$values = null;
$options = null;
$selected = null;
$separator = '';
$labels = true;
$label_ids = false;
$output = null;
$extra = '';
foreach($params as $_key => $_val) {
switch ($_key) {
case 'name':
case 'separator':
$$_key = (string)$_val;
break;
case 'checked':
case 'selected':
if (is_array($_val)) {
throw new Exception ('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING);
} else {
$selected = (string)$_val;
}
break;
case 'labels':
case 'label_ids':
$$_key = (bool)$_val;
break;
case 'options':
$$_key = (array)$_val;
break;
case 'values':
case 'output':
$$_key = array_values((array)$_val);
break;
case 'radios':
throw new Exception ('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING);
$options = (array)$_val;
break;
case 'assign':
break;
default:
if (!is_array($_val)) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
} else {
throw new Exception ("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (!isset($options) && !isset($values))
return '';
/* raise error here? */
$_html_result = array();
if (isset($options)) {
foreach ($options as $_key => $_val)
$_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids);
} else {
foreach ($values as $_i => $_key) {
$_val = isset($output[$_i]) ? $output[$_i] : '';
$_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids);
}
}
if (!empty($params['assign'])) {
$template->assign($params['assign'], $_html_result);
} else {
return implode("\n", $_html_result);
}
}
function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids)
{
$_output = '';
if ($labels) {
if ($label_ids) {
$_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!', '_', $name . '_' . $value));
$_output .= '<label for="' . $_id . '">';
} else {
$_output .= '<label>';
}
}
$_output .= '<input type="radio" name="'
. smarty_function_escape_special_chars($name) . '" value="'
. smarty_function_escape_special_chars($value) . '"';
if ($labels && $label_ids) $_output .= ' id="' . $_id . '"';
if ((string)$value == $selected) {
$_output .= ' checked="checked"';
}
$_output .= $extra . ' />' . $output;
if ($labels) $_output .= '</label>';
$_output .= $separator;
return $_output;
}
?>

View File

@@ -0,0 +1,330 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_select_date} plugin
*
* Type: function<br>
* Name: html_select_date<br>
* Purpose: Prints the dropdowns for date selection.
*
* ChangeLog:<br>
* - 1.0 initial release
* - 1.1 added support for +/- N syntax for begin
* and end year values. (Monte)
* - 1.2 added support for yyyy-mm-dd syntax for
* time value. (Jan Rosier)
* - 1.3 added support for choosing format for
* month values (Gary Loescher)
* - 1.3.1 added support for choosing format for
* day values (Marcus Bointon)
* - 1.3.2 support negative timestamps, force year
* dropdown to include given date unless explicitly set (Monte)
* - 1.3.4 fix behaviour of 0000-00-00 00:00:00 dates to match that
* of 0000-00-00 dates (cybot, boots)
*
* @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date}
(Smarty online manual)
* @version 1.3.4
* @author Andrei Zmievski
* @author Monte Ohrt <monte at ohrt dot com>
* @param array $params parameters
* @param object $smarty Smarty object
* @param object $template template object
* @return string
*/
function smarty_function_html_select_date($params, $smarty, $template)
{
$smarty->loadPlugin('Smarty_shared_escape_special_chars');
$smarty->loadPlugin('Smarty_shared_make_timestamp');
$smarty->loadPlugin('Smarty_function_html_options');
/* Default values. */
$prefix = "Date_";
$start_year = strftime("%Y");
$end_year = $start_year;
$display_days = true;
$display_months = true;
$display_years = true;
$month_format = "%B";
/* Write months as numbers by default GL */
$month_value_format = "%m";
$day_format = "%02d";
/* Write day values using this format MB */
$day_value_format = "%d";
$year_as_text = false;
/* Display years in reverse order? Ie. 2000,1999,.... */
$reverse_years = false;
/* Should the select boxes be part of an array when returned from PHP?
e.g. setting it to "birthday", would create "birthday[Day]",
"birthday[Month]" & "birthday[Year]". Can be combined with prefix */
$field_array = null;
/* <select size>'s of the different <select> tags.
If not set, uses default dropdown. */
$day_size = null;
$month_size = null;
$year_size = null;
/* Unparsed attributes common to *ALL* the <select>/<input> tags.
An example might be in the template: all_extra ='class ="foo"'. */
$all_extra = null;
/* Separate attributes for the tags. */
$day_extra = null;
$month_extra = null;
$year_extra = null;
/* Order in which to display the fields.
"D" -> day, "M" -> month, "Y" -> year. */
$field_order = 'MDY';
/* String printed between the different fields. */
$field_separator = "\n";
$time = time();
$all_empty = null;
$day_empty = null;
$month_empty = null;
$year_empty = null;
$extra_attrs = '';
foreach ($params as $_key => $_value) {
switch ($_key) {
case 'prefix':
case 'time':
case 'start_year':
case 'end_year':
case 'month_format':
case 'day_format':
case 'day_value_format':
case 'field_array':
case 'day_size':
case 'month_size':
case 'year_size':
case 'all_extra':
case 'day_extra':
case 'month_extra':
case 'year_extra':
case 'field_order':
case 'field_separator':
case 'month_value_format':
case 'month_empty':
case 'day_empty':
case 'year_empty':
$$_key = (string)$_value;
break;
case 'all_empty':
$$_key = (string)$_value;
$day_empty = $month_empty = $year_empty = $all_empty;
break;
case 'display_days':
case 'display_months':
case 'display_years':
case 'year_as_text':
case 'reverse_years':
$$_key = (bool)$_value;
break;
default:
if (!is_array($_value)) {
$extra_attrs .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_value) . '"';
} else {
throw new Exception ("html_select_date: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (preg_match('!^-\d+$!', $time)) {
// negative timestamp, use date()
$time = date('Y-m-d', $time);
}
// If $time is not in format yyyy-mm-dd
if (preg_match('/^(\d{0,4}-\d{0,2}-\d{0,2})/', $time, $found)) {
$time = $found[1];
} else {
// use smarty_make_timestamp to get an unix timestamp and
// strftime to make yyyy-mm-dd
$time = strftime('%Y-%m-%d', smarty_make_timestamp($time));
}
// Now split this in pieces, which later can be used to set the select
$time = explode("-", $time);
// make syntax "+N" or "-N" work with start_year and end_year
if (preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match)) {
if ($match[1] == '+') {
$end_year = strftime('%Y') + $match[2];
} else {
$end_year = strftime('%Y') - $match[2];
}
}
if (preg_match('!^(\+|\-)\s*(\d+)$!', $start_year, $match)) {
if ($match[1] == '+') {
$start_year = strftime('%Y') + $match[2];
} else {
$start_year = strftime('%Y') - $match[2];
}
}
if (strlen($time[0]) > 0) {
if ($start_year > $time[0] && !isset($params['start_year'])) {
// force start year to include given date if not explicitly set
$start_year = $time[0];
}
if ($end_year < $time[0] && !isset($params['end_year'])) {
// force end year to include given date if not explicitly set
$end_year = $time[0];
}
}
$field_order = strtoupper($field_order);
$html_result = $month_result = $day_result = $year_result = "";
$field_separator_count = -1;
if ($display_months) {
$field_separator_count++;
$month_names = array();
$month_values = array();
if (isset($month_empty)) {
$month_names[''] = $month_empty;
$month_values[''] = '';
}
for ($i = 1; $i <= 12; $i++) {
$month_names[$i] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000));
$month_values[$i] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000));
}
$month_result .= '<select name=';
if (null !== $field_array) {
$month_result .= '"' . $field_array . '[' . $prefix . 'Month]"';
} else {
$month_result .= '"' . $prefix . 'Month"';
}
if (null !== $month_size) {
$month_result .= ' size="' . $month_size . '"';
}
if (null !== $month_extra) {
$month_result .= ' ' . $month_extra;
}
if (null !== $all_extra) {
$month_result .= ' ' . $all_extra;
}
$month_result .= $extra_attrs . '>' . "\n";
$month_result .= smarty_function_html_options(array('output' => $month_names,
'values' => $month_values,
'selected' => (int)$time[1] ? strftime($month_value_format, mktime(0, 0, 0, (int)$time[1], 1, 2000)) : '',
'print_result' => false),
$smarty, $template);
$month_result .= '</select>';
}
if ($display_days) {
$field_separator_count++;
$days = array();
if (isset($day_empty)) {
$days[''] = $day_empty;
$day_values[''] = '';
}
for ($i = 1; $i <= 31; $i++) {
$days[] = sprintf($day_format, $i);
$day_values[] = sprintf($day_value_format, $i);
}
$day_result .= '<select name=';
if (null !== $field_array) {
$day_result .= '"' . $field_array . '[' . $prefix . 'Day]"';
} else {
$day_result .= '"' . $prefix . 'Day"';
}
if (null !== $day_size) {
$day_result .= ' size="' . $day_size . '"';
}
if (null !== $all_extra) {
$day_result .= ' ' . $all_extra;
}
if (null !== $day_extra) {
$day_result .= ' ' . $day_extra;
}
$day_result .= $extra_attrs . '>' . "\n";
$day_result .= smarty_function_html_options(array('output' => $days,
'values' => $day_values,
'selected' => $time[2],
'print_result' => false),
$smarty);
$day_result .= '</select>';
}
if ($display_years) {
$field_separator_count++;
if (null !== $field_array) {
$year_name = $field_array . '[' . $prefix . 'Year]';
} else {
$year_name = $prefix . 'Year';
}
if ($year_as_text) {
$year_result .= '<input type="text" name="' . $year_name . '" value="' . $time[0] . '" size="4" maxlength="4"';
if (null !== $all_extra) {
$year_result .= ' ' . $all_extra;
}
if (null !== $year_extra) {
$year_result .= ' ' . $year_extra;
}
$year_result .= ' />';
} else {
$years = range((int)$start_year, (int)$end_year);
if ($reverse_years) {
rsort($years, SORT_NUMERIC);
} else {
sort($years, SORT_NUMERIC);
}
$yearvals = $years;
if (isset($year_empty)) {
array_unshift($years, $year_empty);
array_unshift($yearvals, '');
}
$year_result .= '<select name="' . $year_name . '"';
if (null !== $year_size) {
$year_result .= ' size="' . $year_size . '"';
}
if (null !== $all_extra) {
$year_result .= ' ' . $all_extra;
}
if (null !== $year_extra) {
$year_result .= ' ' . $year_extra;
}
$year_result .= $extra_attrs . '>' . "\n";
$year_result .= smarty_function_html_options(array('output' => $years,
'values' => $yearvals,
'selected' => $time[0],
'print_result' => false),
$smarty);
$year_result .= '</select>';
}
}
// Loop thru the field_order field
for ($i = 0; $i <= 2; $i++) {
$c = substr($field_order, $i, 1);
switch ($c) {
case 'D':
$html_result .= $day_result;
break;
case 'M':
$html_result .= $month_result;
break;
case 'Y':
$html_result .= $year_result;
break;
}
// Add the field seperator
if ($i < $field_separator_count) {
$html_result .= $field_separator;
}
}
return $html_result;
}
?>

View File

@@ -0,0 +1,195 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_select_time} function plugin
*
* Type: function<br>
* Name: html_select_time<br>
* Purpose: Prints the dropdowns for time selection
*
* @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time}
(Smarty online manual)
* @author Roberto Berto <roberto@berto.net>
* @credits Monte Ohrt <monte AT ohrt DOT com>
* @param array $params parameters
* @param object $smarty Smarty object
* @param object $template template object
* @return string
* @uses smarty_make_timestamp()
*/
function smarty_function_html_select_time($params, $smarty, $template)
{
$smarty->loadPlugin('Smarty_shared_make_timestamp');
$smarty->loadPlugin('Smarty_function_html_options');
/* Default values. */
$prefix = "Time_";
$time = time();
$display_hours = true;
$display_minutes = true;
$display_seconds = true;
$display_meridian = true;
$use_24_hours = true;
$minute_interval = 1;
$second_interval = 1;
/* Should the select boxes be part of an array when returned from PHP?
e.g. setting it to "birthday", would create "birthday[Hour]",
"birthday[Minute]", "birthday[Seconds]" & "birthday[Meridian]".
Can be combined with prefix. */
$field_array = null;
$all_extra = null;
$hour_extra = null;
$minute_extra = null;
$second_extra = null;
$meridian_extra = null;
foreach ($params as $_key => $_value) {
switch ($_key) {
case 'prefix':
case 'time':
case 'field_array':
case 'all_extra':
case 'hour_extra':
case 'minute_extra':
case 'second_extra':
case 'meridian_extra':
$$_key = (string)$_value;
break;
case 'display_hours':
case 'display_minutes':
case 'display_seconds':
case 'display_meridian':
case 'use_24_hours':
$$_key = (bool)$_value;
break;
case 'minute_interval':
case 'second_interval':
$$_key = (int)$_value;
break;
default:
throw new Exception ("[html_select_time] unknown parameter $_key", E_USER_WARNING);
}
}
$time = smarty_make_timestamp($time);
$html_result = '';
if ($display_hours) {
$hours = $use_24_hours ? range(0, 23) : range(1, 12);
$hour_fmt = $use_24_hours ? '%H' : '%I';
for ($i = 0, $for_max = count($hours); $i < $for_max; $i++)
$hours[$i] = sprintf('%02d', $hours[$i]);
$html_result .= '<select name=';
if (null !== $field_array) {
$html_result .= '"' . $field_array . '[' . $prefix . 'Hour]"';
} else {
$html_result .= '"' . $prefix . 'Hour"';
}
if (null !== $hour_extra) {
$html_result .= ' ' . $hour_extra;
}
if (null !== $all_extra) {
$html_result .= ' ' . $all_extra;
}
$html_result .= '>' . "\n";
$html_result .= smarty_function_html_options(array('output' => $hours,
'values' => $hours,
'selected' => strftime($hour_fmt, $time),
'print_result' => false),
$smarty, $template);
$html_result .= "</select>\n";
}
if ($display_minutes) {
$all_minutes = range(0, 59);
for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i += $minute_interval)
$minutes[] = sprintf('%02d', $all_minutes[$i]);
$selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval);
$html_result .= '<select name=';
if (null !== $field_array) {
$html_result .= '"' . $field_array . '[' . $prefix . 'Minute]"';
} else {
$html_result .= '"' . $prefix . 'Minute"';
}
if (null !== $minute_extra) {
$html_result .= ' ' . $minute_extra;
}
if (null !== $all_extra) {
$html_result .= ' ' . $all_extra;
}
$html_result .= '>' . "\n";
$html_result .= smarty_function_html_options(array('output' => $minutes,
'values' => $minutes,
'selected' => $selected,
'print_result' => false),
$smarty, $template);
$html_result .= "</select>\n";
}
if ($display_seconds) {
$all_seconds = range(0, 59);
for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i += $second_interval)
$seconds[] = sprintf('%02d', $all_seconds[$i]);
$selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval);
$html_result .= '<select name=';
if (null !== $field_array) {
$html_result .= '"' . $field_array . '[' . $prefix . 'Second]"';
} else {
$html_result .= '"' . $prefix . 'Second"';
}
if (null !== $second_extra) {
$html_result .= ' ' . $second_extra;
}
if (null !== $all_extra) {
$html_result .= ' ' . $all_extra;
}
$html_result .= '>' . "\n";
$html_result .= smarty_function_html_options(array('output' => $seconds,
'values' => $seconds,
'selected' => $selected,
'print_result' => false),
$smarty, $template);
$html_result .= "</select>\n";
}
if ($display_meridian && !$use_24_hours) {
$html_result .= '<select name=';
if (null !== $field_array) {
$html_result .= '"' . $field_array . '[' . $prefix . 'Meridian]"';
} else {
$html_result .= '"' . $prefix . 'Meridian"';
}
if (null !== $meridian_extra) {
$html_result .= ' ' . $meridian_extra;
}
if (null !== $all_extra) {
$html_result .= ' ' . $all_extra;
}
$html_result .= '>' . "\n";
$html_result .= smarty_function_html_options(array('output' => array('AM', 'PM'),
'values' => array('am', 'pm'),
'selected' => strtolower(strftime('%p', $time)),
'print_result' => false),
$smarty, $template);
$html_result .= "</select>\n";
}
return $html_result;
}
?>

View File

@@ -0,0 +1,176 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_table} function plugin
*
* Type: function<br>
* Name: html_table<br>
* Date: Feb 17, 2003<br>
* Purpose: make an html table from an array of data<br>
*
*
* Examples:
* <pre>
* {table loop=$data}
* {table loop=$data cols=4 tr_attr='"bgcolor=red"'}
* {table loop=$data cols="first,second,third" tr_attr=$colors}
* </pre>
*
* @author Monte Ohrt <monte at ohrt dot com>
* @author credit to Messju Mohr <messju at lammfellpuschen dot de>
* @author credit to boots <boots dot smarty at yahoo dot com>
* @version 1.1
* @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table}
(Smarty online manual)
* @param array $params parameters
* Input:<br>
* - loop = array to loop through
* - cols = number of columns, comma separated list of column names
* or array of column names
* - rows = number of rows
* - table_attr = table attributes
* - th_attr = table heading attributes (arrays are cycled)
* - tr_attr = table row attributes (arrays are cycled)
* - td_attr = table cell attributes (arrays are cycled)
* - trailpad = value to pad trailing cells with
* - caption = text for caption element
* - vdir = vertical direction (default: "down", means top-to-bottom)
* - hdir = horizontal direction (default: "right", means left-to-right)
* - inner = inner loop (default "cols": print $loop line by line,
* $loop will be printed column by column otherwise)
* @param object $smarty Smarty object
* @param object $template template object
* @return string
*/
function smarty_function_html_table($params, $smarty, $template)
{
$table_attr = 'border="1"';
$tr_attr = '';
$th_attr = '';
$td_attr = '';
$cols = $cols_count = 3;
$rows = 3;
$trailpad = '&nbsp;';
$vdir = 'down';
$hdir = 'right';
$inner = 'cols';
$caption = '';
if (!isset($params['loop'])) {
throw new Exception ("html_table: missing 'loop' parameter");
return;
}
foreach ($params as $_key => $_value) {
switch ($_key) {
case 'loop':
$$_key = (array)$_value;
break;
case 'cols':
if (is_array($_value) && !empty($_value)) {
$cols = $_value;
$cols_count = count($_value);
} elseif (!is_numeric($_value) && is_string($_value) && !empty($_value)) {
$cols = explode(',', $_value);
$cols_count = count($cols);
} elseif (!empty($_value)) {
$cols_count = (int)$_value;
} else {
$cols_count = $cols;
}
break;
case 'rows':
$$_key = (int)$_value;
break;
case 'table_attr':
case 'trailpad':
case 'hdir':
case 'vdir':
case 'inner':
case 'caption':
$$_key = (string)$_value;
break;
case 'tr_attr':
case 'td_attr':
case 'th_attr':
$$_key = $_value;
break;
}
}
$loop_count = count($loop);
if (empty($params['rows'])) {
/* no rows specified */
$rows = ceil($loop_count / $cols_count);
} elseif (empty($params['cols'])) {
if (!empty($params['rows'])) {
/* no cols specified, but rows */
$cols_count = ceil($loop_count / $rows);
}
}
$output = "<table $table_attr>\n";
if (!empty($caption)) {
$output .= '<caption>' . $caption . "</caption>\n";
}
if (is_array($cols)) {
$cols = ($hdir == 'right') ? $cols : array_reverse($cols);
$output .= "<thead><tr>\n";
for ($r = 0; $r < $cols_count; $r++) {
$output .= '<th' . smarty_function_html_table_cycle('th', $th_attr, $r) . '>';
$output .= $cols[$r];
$output .= "</th>\n";
}
$output .= "</tr></thead>\n";
}
$output .= "<tbody>\n";
for ($r = 0; $r < $rows; $r++) {
$output .= "<tr" . smarty_function_html_table_cycle('tr', $tr_attr, $r) . ">\n";
$rx = ($vdir == 'down') ? $r * $cols_count : ($rows-1 - $r) * $cols_count;
for ($c = 0; $c < $cols_count; $c++) {
$x = ($hdir == 'right') ? $rx + $c : $rx + $cols_count-1 - $c;
if ($inner != 'cols') {
/* shuffle x to loop over rows*/
$x = floor($x / $cols_count) + ($x % $cols_count) * $rows;
}
if ($x < $loop_count) {
$output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">" . $loop[$x] . "</td>\n";
} else {
$output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">$trailpad</td>\n";
}
}
$output .= "</tr>\n";
}
$output .= "</tbody>\n";
$output .= "</table>\n";
return $output;
}
function smarty_function_html_table_cycle($name, $var, $no)
{
if (!is_array($var)) {
$ret = $var;
} else {
$ret = $var[$no % count($var)];
}
return ($ret) ? ' ' . $ret : '';
}
?>

View File

@@ -0,0 +1,157 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {mailto} function plugin
*
* Type: function<br>
* Name: mailto<br>
* Date: May 21, 2002
* Purpose: automate mailto address link creation, and optionally
* encode them.<br>
*
* Examples:
* <pre>
* {mailto address="me@domain.com"}
* {mailto address="me@domain.com" encode="javascript"}
* {mailto address="me@domain.com" encode="hex"}
* {mailto address="me@domain.com" subject="Hello to you!"}
* {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"}
* {mailto address="me@domain.com" extra='class="mailto"'}
* </pre>
*
* @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto}
(Smarty online manual)
* @version 1.2
* @author Monte Ohrt <monte at ohrt dot com>
* @author credits to Jason Sweat (added cc, bcc and subject functionality)
* @param array $params parameters
* Input:<br>
* - address = e-mail address
* - text = (optional) text to display, default is address
* - encode = (optional) can be one of:
* * none : no encoding (default)
* * javascript : encode with javascript
* * javascript_charcode : encode with javascript charcode
* * hex : encode with hexidecimal (no javascript)
* - cc = (optional) address(es) to carbon copy
* - bcc = (optional) address(es) to blind carbon copy
* - subject = (optional) e-mail subject
* - newsgroups = (optional) newsgroup(s) to post to
* - followupto = (optional) address(es) to follow up to
* - extra = (optional) extra tags for the href link
* @param object $smarty Smarty object
* @param object $template template object
* @return string
*/
function smarty_function_mailto($params, $smarty, $template)
{
$extra = '';
if (empty($params['address'])) {
throw new Exception ("mailto: missing 'address' parameter");
return;
} else {
$address = $params['address'];
}
$text = $address;
// netscape and mozilla do not decode %40 (@) in BCC field (bug?)
// so, don't encode it.
$search = array('%40', '%2C');
$replace = array('@', ',');
$mail_parms = array();
foreach ($params as $var => $value) {
switch ($var) {
case 'cc':
case 'bcc':
case 'followupto':
if (!empty($value))
$mail_parms[] = $var . '=' . str_replace($search, $replace, rawurlencode($value));
break;
case 'subject':
case 'newsgroups':
$mail_parms[] = $var . '=' . rawurlencode($value);
break;
case 'extra':
case 'text':
$$var = $value;
default:
}
}
$mail_parm_vals = '';
for ($i = 0; $i < count($mail_parms); $i++) {
$mail_parm_vals .= (0 == $i) ? '?' : '&';
$mail_parm_vals .= $mail_parms[$i];
}
$address .= $mail_parm_vals;
$encode = (empty($params['encode'])) ? 'none' : $params['encode'];
if (!in_array($encode, array('javascript', 'javascript_charcode', 'hex', 'none'))) {
throw new Exception ("mailto: 'encode' parameter must be none, javascript or hex");
return;
}
if ($encode == 'javascript') {
$string = 'document.write(\'<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>\');';
$js_encode = '';
for ($x = 0; $x < strlen($string); $x++) {
$js_encode .= '%' . bin2hex($string[$x]);
}
return '<script type="text/javascript">eval(unescape(\'' . $js_encode . '\'))</script>';
} elseif ($encode == 'javascript_charcode') {
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
for($x = 0, $y = strlen($string); $x < $y; $x++) {
$ord[] = ord($string[$x]);
}
$_ret = "<script type=\"text/javascript\" language=\"javascript\">\n";
$_ret .= "<!--\n";
$_ret .= "{document.write(String.fromCharCode(";
$_ret .= implode(',', $ord);
$_ret .= "))";
$_ret .= "}\n";
$_ret .= "//-->\n";
$_ret .= "</script>\n";
return $_ret;
} elseif ($encode == 'hex') {
preg_match('!^(.*)(\?.*)$!', $address, $match);
if (!empty($match[2])) {
throw new Exception ("mailto: hex encoding does not work with extra attributes. Try javascript.");
return;
}
$address_encode = '';
for ($x = 0; $x < strlen($address); $x++) {
if (preg_match('!\w!', $address[$x])) {
$address_encode .= '%' . bin2hex($address[$x]);
} else {
$address_encode .= $address[$x];
}
}
$text_encode = '';
for ($x = 0; $x < strlen($text); $x++) {
$text_encode .= '&#x' . bin2hex($text[$x]) . ';';
}
$mailto = "&#109;&#97;&#105;&#108;&#116;&#111;&#58;";
return '<a href="' . $mailto . $address_encode . '" ' . $extra . '>' . $text_encode . '</a>';
} else {
// no encoding
return '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
}
}
?>

View File

@@ -0,0 +1,84 @@
<?php
/**
* Smarty plugin
*
* This plugin is only for Smarty2 BC
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {math} function plugin
*
* Type: function<br>
* Name: math<br>
* Purpose: handle math computations in template<br>
* @link http://smarty.php.net/manual/en/language.function.math.php {math}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param array $params parameters
* @param object $smarty Smarty object
* @param object $template template object
* @return string|null
*/
function smarty_function_math($params, $smarty, $template)
{
// be sure equation parameter is present
if (empty($params['equation'])) {
throw new Exception ("math: missing equation parameter");
return;
}
$equation = $params['equation'];
// make sure parenthesis are balanced
if (substr_count($equation,"(") != substr_count($equation,")")) {
throw new Exception ("math: unbalanced parenthesis");
return;
}
// match all vars in equation, make sure all are passed
preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]+)!",$equation, $match);
$allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10',
'max','min','pi','pow','rand','round','sin','sqrt','srand','tan');
foreach($match[1] as $curr_var) {
if ($curr_var && !in_array($curr_var, array_keys($params)) && !in_array($curr_var, $allowed_funcs)) {
throw new Exception ("math: function call $curr_var not allowed");
return;
}
}
foreach($params as $key => $val) {
if ($key != "equation" && $key != "format" && $key != "assign") {
// make sure value is not empty
if (strlen($val)==0) {
throw new Exception ("math: parameter $key is empty");
return;
}
if (!is_numeric($val)) {
throw new Exception ("math: parameter $key: is not numeric");
return;
}
$equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation);
}
}
eval("\$smarty_math_result = ".$equation.";");
if (empty($params['format'])) {
if (empty($params['assign'])) {
return $smarty_math_result;
} else {
$template->assign($params['assign'],$smarty_math_result);
}
} else {
if (empty($params['assign'])){
printf($params['format'],$smarty_math_result);
} else {
$template->assign($params['assign'],sprintf($params['format'],$smarty_math_result));
}
}
}
?>

View File

@@ -0,0 +1,118 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {popup} function plugin
*
* Type: function<br>
* Name: popup<br>
* Purpose: make text pop up in windows via overlib
* @link http://smarty.php.net/manual/en/language.function.popup.php {popup}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param array $params parameters
* @param object $smarty Smarty object
* @param object $template template object
* @return string
*/
function smarty_function_popup($params, $smarty, $template)
{
$append = '';
foreach ($params as $_key=>$_value) {
switch ($_key) {
case 'text':
case 'trigger':
case 'function':
case 'inarray':
$$_key = (string)$_value;
if ($_key == 'function' || $_key == 'inarray')
$append .= ',' . strtoupper($_key) . ",'$_value'";
break;
case 'caption':
case 'closetext':
case 'status':
$append .= ',' . strtoupper($_key) . ",'" . str_replace("'","\'",$_value) . "'";
break;
case 'fgcolor':
case 'bgcolor':
case 'textcolor':
case 'capcolor':
case 'closecolor':
case 'textfont':
case 'captionfont':
case 'closefont':
case 'fgbackground':
case 'bgbackground':
case 'caparray':
case 'capicon':
case 'background':
case 'frame':
$append .= ',' . strtoupper($_key) . ",'$_value'";
break;
case 'textsize':
case 'captionsize':
case 'closesize':
case 'width':
case 'height':
case 'border':
case 'offsetx':
case 'offsety':
case 'snapx':
case 'snapy':
case 'fixx':
case 'fixy':
case 'padx':
case 'pady':
case 'timeout':
case 'delay':
$append .= ',' . strtoupper($_key) . ",$_value";
break;
case 'sticky':
case 'left':
case 'right':
case 'center':
case 'above':
case 'below':
case 'noclose':
case 'autostatus':
case 'autostatuscap':
case 'fullhtml':
case 'hauto':
case 'vauto':
case 'mouseoff':
case 'followmouse':
case 'closeclick':
case 'wrap':
if ($_value) $append .= ',' . strtoupper($_key);
break;
default:
throw new Exception ("[popup] unknown parameter $_key", E_USER_WARNING);
}
}
if (empty($text) && !isset($inarray) && empty($function)) {
throw new Exception ("overlib: attribute 'text' or 'inarray' or 'function' required");
return false;
}
if (empty($trigger)) { $trigger = "onmouseover"; }
$retval = $trigger . '="return overlib(\''.preg_replace(array("!'!",'!"!',"![\r\n]!"),array("\'","\'",'\r'),$text).'\'';
$retval .= $append . ');"';
if ($trigger == 'onmouseover')
$retval .= ' onmouseout="nd();"';
return $retval;
}
?>

View File

@@ -0,0 +1,41 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {popup_init} function plugin
*
* Type: function<br>
* Name: popup_init<br>
* Purpose: initialize overlib
* @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param array $params parameters
* @param object $smarty Smarty object
* @param object $template template object
* @return string
*/
function smarty_function_popup_init($params, $smarty, $template)
{
$zindex = 1000;
if (!empty($params['zindex'])) {
$zindex = $params['zindex'];
}
if (!empty($params['src'])) {
return '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:'.$zindex.';"></div>' . "\n"
. '<script type="text/javascript" language="JavaScript" src="'.$params['src'].'"></script>' . "\n";
} else {
throw new Exception ("popup_init: missing src parameter");
}
}
/* vim: set expandtab: */
?>

View File

@@ -0,0 +1,41 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty capitalize modifier plugin
*
* Type: modifier<br>
* Name: capitalize<br>
* Purpose: capitalize words in the string
* @link http://smarty.php.net/manual/en/language.modifiers.php#LANGUAGE.MODIFIER.CAPITALIZE
* capitalize (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @return string
*/
function smarty_modifier_capitalize($string, $uc_digits = false)
{
smarty_modifier_capitalize_ucfirst(null, $uc_digits);
return preg_replace_callback('!\'?\b\w(\w|\')*\b!', 'smarty_modifier_capitalize_ucfirst', $string);
}
function smarty_modifier_capitalize_ucfirst($string, $uc_digits = null)
{
static $_uc_digits = false;
if(isset($uc_digits)) {
$_uc_digits = $uc_digits;
return;
}
if(substr($string[0],0,1) != "'" && !preg_match("!\d!",$string[0]) || $_uc_digits)
return ucfirst($string[0]);
else
return $string[0];
}
?>

View File

@@ -0,0 +1,31 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty cat modifier plugin
*
* Type: modifier<br>
* Name: cat<br>
* Date: Feb 24, 2003
* Purpose: catenate a value to a variable
* Input: string to catenate
* Example: {$var|cat:"foo"}
* @link http://smarty.php.net/manual/en/language.modifier.cat.php cat
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @version 1.0
* @param string
* @param string
* @return string
*/
function smarty_modifier_cat($string, $cat)
{
return $string . $cat;
}
?>

View File

@@ -0,0 +1,29 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty count_characters modifier plugin
*
* Type: modifier<br>
* Name: count_characteres<br>
* Purpose: count the number of characters in a text
* @link http://smarty.php.net/manual/en/language.modifier.count.characters.php
* count_characters (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string input string
* @param boolean $include_spaces include whitespace in the character count
* @return integer number of characters
*/
function smarty_modifier_count_characters($string, $include_spaces = false)
{
if ($include_spaces)
return(strlen($string));
return preg_match_all("/[^\s]/",$string, $match);
}
?>

View File

@@ -0,0 +1,26 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty count_paragraphs modifier plugin
*
* Type: modifier<br>
* Name: count_paragraphs<br>
* Purpose: count the number of paragraphs in a text
* @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php
* count_paragraphs (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @return integer
*/
function smarty_modifier_count_paragraphs($string)
{
// count \r or \n characters
return count(preg_split('/[\r\n]+/', $string));
}
?>

View File

@@ -0,0 +1,27 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty count_sentences modifier plugin
*
* Type: modifier<br>
* Name: count_sentences
* Purpose: count the number of sentences in a text
* @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php
* count_sentences (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @return integer
*/
function smarty_modifier_count_sentences($string)
{
// find periods with a word before but not after.
return preg_match_all('/[^\s]\.(?!\w)/', $string, $match);
}
?>

View File

@@ -0,0 +1,25 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty count_words modifier plugin
*
* Type: modifier<br>
* Name: count_words<br>
* Purpose: count the number of words in a text
* @link http://smarty.php.net/manual/en/language.modifier.count.words.php
* count_words (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @return integer
*/
function smarty_modifier_count_words($string)
{
return str_word_count($string);
}
?>

View File

@@ -0,0 +1,56 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty date_format modifier plugin
*
* Type: modifier<br>
* Name: date_format<br>
* Purpose: format datestamps via strftime<br>
* Input:<br>
* - string: input date string
* - format: strftime format for output
* - default_date: default date if $string is empty
* @link http://smarty.php.net/manual/en/language.modifier.date.format.php
* date_format (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @param string
* @param string
* @return string|void
* @uses smarty_make_timestamp()
*/
function smarty_modifier_date_format($string, $format = '%b %e, %Y', $default_date = '')
{
/**
* Include the {@link shared.make_timestamp.php} plugin
*/
$smarty = Smarty::instance();
$smarty->loadPlugin('Smarty_shared_make_timestamp');
if ($string != '') {
$timestamp = smarty_make_timestamp($string);
} elseif ($default_date != '') {
$timestamp = smarty_make_timestamp($default_date);
} else {
return;
}
if (DIRECTORY_SEPARATOR == '\\') {
$_win_from = array('%D', '%h', '%n', '%r', '%R', '%t', '%T');
$_win_to = array('%m/%d/%y', '%b', "\n", '%I:%M:%S %p', '%H:%M', "\t", '%H:%M:%S');
if (strpos($format, '%e') !== false) {
$_win_from[] = '%e';
$_win_to[] = sprintf('%\' 2d', date('j', $timestamp));
}
if (strpos($format, '%l') !== false) {
$_win_from[] = '%l';
$_win_to[] = sprintf('%\' 2d', date('h', $timestamp));
}
$format = str_replace($_win_from, $_win_to, $format);
}
return strftime($format, $timestamp);
}
?>

View File

@@ -0,0 +1,89 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage Debug
*/
/**
* Smarty debug_print_var modifier plugin
*
* Type: modifier<br>
* Name: debug_print_var<br>
* Purpose: formats variable contents for display in the console
*
* @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php debug_print_var (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param array $ |object
* @param integer $
* @param integer $
* @return string
*/
class Smarty_Modifier_Debug_Print_Var extends Smarty_Internal_PluginBase {
static function execute ($var, $depth = 0, $length = 40)
{
$_replace = array("\n" => '<i>\n</i>',
"\r" => '<i>\r</i>',
"\t" => '<i>\t</i>'
);
switch (gettype($var)) {
case 'array' :
$results = '<b>Array (' . count($var) . ')</b>';
foreach ($var as $curr_key => $curr_val) {
$results .= '<br>' . str_repeat('&nbsp;', $depth * 2)
. '<b>' . strtr($curr_key, $_replace) . '</b> =&gt; '
. self::execute($curr_val, ++$depth, $length);
$depth--;
}
break;
case 'object' :
$object_vars = get_object_vars($var);
$results = '<b>' . get_class($var) . ' Object (' . count($object_vars) . ')</b>';
foreach ($object_vars as $curr_key => $curr_val) {
$results .= '<br>' . str_repeat('&nbsp;', $depth * 2)
. '<b> -&gt;' . strtr($curr_key, $_replace) . '</b> = '
. self::execute($curr_val, ++$depth, $length);
$depth--;
}
break;
case 'boolean' :
case 'NULL' :
case 'resource' :
if (true === $var) {
$results = 'true';
} elseif (false === $var) {
$results = 'false';
} elseif (null === $var) {
$results = 'null';
} else {
$results = htmlspecialchars((string) $var);
}
$results = '<i>' . $results . '</i>';
break;
case 'integer' :
case 'float' :
$results = htmlspecialchars((string) $var);
break;
case 'string' :
$results = strtr($var, $_replace);
if (strlen($var) > $length) {
$results = substr($var, 0, $length - 3) . '...';
}
$results = htmlspecialchars('"' . $results . '"');
break;
case 'unknown type' :
default :
$results = strtr((string) $var, $_replace);
if (strlen($results) > $length) {
$results = substr($results, 0, $length - 3) . '...';
}
$results = htmlspecialchars($results);
}
return $results;
}
}
?>

View File

@@ -0,0 +1,29 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty default modifier plugin
*
* Type: modifier<br>
* Name: default<br>
* Purpose: designate default value for empty variables
* @link http://smarty.php.net/manual/en/language.modifier.default.php
* default (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @param string
* @return string
*/
function smarty_modifier_default($string, $default = '')
{
if (!isset($string) || $string === '')
return $default;
else
return $string;
}
?>

View File

@@ -0,0 +1,111 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty escape modifier plugin
*
* Type: modifier<br>
* Name: escape<br>
* Purpose: escape string for output
*
* @link http://smarty.php.net/manual/en/language.modifier.count.characters.php count_characters (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string input string
* @param string $esc_type escape type
* @param string $char_set character set
* @return string escaped input string
*/
function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null)
{
if ($char_set === null) {
$smarty = Smarty::instance();
$char_set = $smarty->resource_char_set;
}
switch ($esc_type) {
case 'html':
return htmlspecialchars($string, ENT_QUOTES, $char_set);
case 'htmlall':
return htmlentities($string, ENT_QUOTES, $char_set);
case 'url':
return rawurlencode($string);
case 'urlpathinfo':
return str_replace('%2F', '/', rawurlencode($string));
case 'quotes':
// escape unescaped single quotes
return preg_replace("%(?<!\\\\)'%", "\\'", $string);
case 'hex':
// escape every character into hex
$return = '';
for ($x = 0; $x < strlen($string); $x++) {
$return .= '%' . bin2hex($string[$x]);
}
return $return;
case 'hexentity':
$return = '';
for ($x = 0; $x < strlen($string); $x++) {
$return .= '&#x' . bin2hex($string[$x]) . ';';
}
return $return;
case 'decentity':
$return = '';
for ($x = 0; $x < strlen($string); $x++) {
$return .= '&#' . ord($string[$x]) . ';';
}
return $return;
case 'javascript':
// escape quotes and backslashes, newlines, etc.
return strtr($string, array('\\' => '\\\\', "'" => "\\'", '"' => '\\"', "\r" => '\\r', "\n" => '\\n', '</' => '<\/'));
case 'mail':
// safe way to display e-mail address on a web page
return mb_str_replace(array('@', '.'), array(' [AT] ', ' [DOT] '), $string);
case 'nonstd':
// escape non-standard chars, such as ms document quotes
$_res = '';
for($_i = 0, $_len = strlen($string); $_i < $_len; $_i++) {
$_ord = ord(substr($string, $_i, 1));
// non-standard char, escape it
if ($_ord >= 126) {
$_res .= '&#' . $_ord . ';';
} else {
$_res .= substr($string, $_i, 1);
}
}
return $_res;
default:
return $string;
}
if (!function_exists("mb_str_replace")) {
// simulate the missing PHP mb_str_replace function
function mb_str_replace($needle, $replacement, $haystack)
{
$needle_len = mb_strlen($needle);
$replacement_len = mb_strlen($replacement);
$pos = mb_strpos($haystack, $needle, 0);
while ($pos !== false) {
$haystack = mb_substr($haystack, 0, $pos) . $replacement
. mb_substr($haystack, $pos + $needle_len);
$pos = mb_strpos($haystack, $needle, $pos + $replacement_len);
}
return $haystack;
}
}
}
?>

View File

@@ -0,0 +1,28 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty indent modifier plugin
*
* Type: modifier<br>
* Name: indent<br>
* Purpose: indent lines of text
* @link http://smarty.php.net/manual/en/language.modifier.indent.php
* indent (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @param integer
* @param string
* @return string
*/
function smarty_modifier_indent($string,$chars=4,$char=" ")
{
return preg_replace('!^!m',str_repeat($char,$chars),$string);
}
?>

View File

@@ -0,0 +1,26 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty lower modifier plugin
*
* Type: modifier<br>
* Name: lower<br>
* Purpose: convert string to lowercase
* @link http://smarty.php.net/manual/en/language.modifier.lower.php
* lower (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @return string
*/
function smarty_modifier_lower($string)
{
return mb_strtolower($string);
}
?>

View File

@@ -0,0 +1,35 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty plugin
*
* Type: modifier<br>
* Name: nl2br<br>
* Date: Feb 26, 2003
* Purpose: convert \r\n, \r or \n to <<br>>
* Input:<br>
* - contents = contents to replace
* - preceed_test = if true, includes preceeding break tags
* in replacement
* Example: {$text|nl2br}
* @link http://smarty.php.net/manual/en/language.modifier.nl2br.php
* nl2br (Smarty online manual)
* @version 1.0
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @return string
*/
function smarty_modifier_nl2br($string)
{
return nl2br($string);
}
/* vim: set expandtab: */
?>

View File

@@ -0,0 +1,24 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty noprint modifier plugin
*
* Type: modifier<br>
* Name: noprint<br>
* Purpose: return an empty string
* @author Uwe Tews
* @param string
* @return string
*/
function smarty_modifier_noprint($string)
{
return '';
}
?>

View File

@@ -0,0 +1,46 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty regex_replace modifier plugin
*
* Type: modifier<br>
* Name: regex_replace<br>
* Purpose: regular expression search/replace
* @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php
* regex_replace (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @param string|array
* @param string|array
* @return string
*/
function smarty_modifier_regex_replace($string, $search, $replace)
{
if(is_array($search)) {
foreach($search as $idx => $s)
$search[$idx] = _smarty_regex_replace_check($s);
} else {
$search = _smarty_regex_replace_check($search);
}
return mb_ereg_replace($search, $replace, $string);
}
function _smarty_regex_replace_check($search)
{
if (($pos = mb_strpos($search,"\0")) !== false)
$search = mb_substr($search,0,$pos);
if (mb_preg_match('!([a-zA-Z\s]+)$!s', $search, $match) && (mb_strpos($match[1], 'e') !== false)) {
/* remove eval-modifier from $search */
$search = mb_substr($search, 0, -mb_strlen($match[1])) . mb_ereg_replace('![e\s]+!', '', $match[1]);
}
return $search;
}
?>

View File

@@ -0,0 +1,44 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty replace modifier plugin
*
* Type: modifier<br>
* Name: replace<br>
* Purpose: simple search/replace
*
* @link http://smarty.php.net/manual/en/language.modifier.replace.php replace (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @author Uwe Tews
* @param string $
* @param string $
* @param string $
* @return string
*/
function smarty_modifier_replace($string, $search, $replace)
{
if (!function_exists("mb_str_replace")) {
// simulate the missing PHP mb_str_replace function
function mb_str_replace($needle, $replacement, $haystack)
{
$needle_len = mb_strlen($needle);
$replacement_len = mb_strlen($replacement);
$pos = mb_strpos($haystack, $needle, 0);
while ($pos !== false) {
$haystack = mb_substr($haystack, 0, $pos) . $replacement
. mb_substr($haystack, $pos + $needle_len);
$pos = mb_strpos($haystack, $needle, $pos + $replacement_len);
}
return $haystack;
}
}
return mb_str_replace($search, $replace, $string);
}
?>

View File

@@ -0,0 +1,27 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty spacify modifier plugin
*
* Type: modifier<br>
* Name: spacify<br>
* Purpose: add spaces between characters in a string
* @link http://smarty.php.net/manual/en/language.modifier.spacify.php
* spacify (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @param string
* @return string
*/
function smarty_modifier_spacify($string, $spacify_char = ' ')
{
return implode($spacify_char,
mb_split('//', $string, -1));
}
?>

View File

@@ -0,0 +1,27 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty string_format modifier plugin
*
* Type: modifier<br>
* Name: string_format<br>
* Purpose: format strings via sprintf
*
* @link http://smarty.php.net/manual/en/language.modifier.string.format.php string_format (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string input string
* @param string $format format string
* @return string formatted string
*/
function smarty_modifier_string_format($string, $format)
{
return sprintf($format, $string);
}
?>

View File

@@ -0,0 +1,30 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty strip modifier plugin
*
* Type: modifier<br>
* Name: strip<br>
* Purpose: Replace all repeated spaces, newlines, tabs
* with a single space or supplied replacement string.<br>
* Example: {$var|strip} {$var|strip:"&nbsp;"}
* Date: September 25th, 2002
* @link http://smarty.php.net/manual/en/language.modifier.strip.php
* strip (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @version 1.0
* @param string
* @param string
* @return string
*/
function smarty_modifier_strip($text, $replace = ' ')
{
return mb_ereg_replace('!\s+!', $replace, $text,'p');
}
?>

View File

@@ -0,0 +1,29 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty strip_tags modifier plugin
*
* Type: modifier<br>
* Name: strip_tags<br>
* Purpose: strip html tags from text
* @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php
* strip_tags (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @param boolean
* @return string
*/
function smarty_modifier_strip_tags($string, $replace_with_space = true)
{
if ($replace_with_space)
return mb_ereg_replace('!<[^>]*?>!', ' ', $string,'p');
else
return strip_tags($string);
}
?>

View File

@@ -0,0 +1,48 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty truncate modifier plugin
*
* Type: modifier<br>
* Name: truncate<br>
* Purpose: Truncate a string to a certain length if necessary,
* optionally splitting in the middle of a word, and
* appending the $etc string or inserting $etc into the middle.
*
* @link http://smarty.php.net/manual/en/language.modifier.truncate.php truncate (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string input string
* @param integer $length lenght of truncated text
* @param string $etc end string
* @param boolean $break_words truncate at word boundary
* @param boolean $middle truncate in the middle of text
* @return string truncated string
*/
function smarty_modifier_truncate($string, $length = 80, $etc = '...',
$break_words = false, $middle = false)
{
if ($length == 0)
return '';
if (mb_strlen($string) > $length) {
$length -= min($length, mb_strlen($etc));
if (!$break_words && !$middle) {
$string = mb_ereg_replace('/\s+?(\S+)?$/', '', mb_substr($string, 0, $length + 1),'p');
}
if (!$middle) {
return mb_substr($string, 0, $length) . $etc;
} else {
return mb_substr($string, 0, $length / 2) . $etc . mb_substr($string, - $length / 2);
}
} else {
return $string;
}
}
?>

View File

@@ -0,0 +1,26 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty upper modifier plugin
*
* Type: modifier<br>
* Name: upper<br>
* Purpose: convert string to uppercase
* @link http://smarty.php.net/manual/en/language.modifier.upper.php
* upper (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @return string
*/
function smarty_modifier_upper($string)
{
return mb_strtoupper($string);
}
?>

View File

@@ -0,0 +1,29 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty wordwrap modifier plugin
*
* Type: modifier<br>
* Name: wordwrap<br>
* Purpose: wrap a string of text at a given length
* @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php
* wordwrap (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @param integer
* @param string
* @param boolean
* @return string
*/
function smarty_modifier_wordwrap($string,$length=80,$break="\n",$cut=false)
{
return wordwrap($string,$length,$break,$cut);
}
?>

View File

@@ -0,0 +1,76 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsFilter
*/
/**
* Smarty trimwhitespace outputfilter plugin
*
* File: outputfilter.trimwhitespace.php<br>
* Type: outputfilter<br>
* Name: trimwhitespace<br>
* Date: Jan 25, 2003<br>
* Purpose: trim leading white space and blank lines from
* template source after it gets interpreted, cleaning
* up code and saving bandwidth. Does not affect
* <<PRE>></PRE> and <SCRIPT></SCRIPT> blocks.<br>
* Install: Drop into the plugin directory, call
* <code>$smarty->load_filter('output','trimwhitespace');</code>
* from application.
* @author Monte Ohrt <monte at ohrt dot com>
* @author Contributions from Lars Noschinski <lars@usenet.noschinski.de>
* @version 1.3
* @param string $source input string
* @param object &$smarty Smarty object
* @return string filtered output
*/
function smarty_outputfilter_trimwhitespace($source, &$smarty)
{
// Pull out the script blocks
preg_match_all("!<script[^>]*?>.*?</script>!is", $source, $match);
$_script_blocks = $match[0];
$source = preg_replace("!<script[^>]*?>.*?</script>!is",
'@@@SMARTY:TRIM:SCRIPT@@@', $source);
// Pull out the pre blocks
preg_match_all("!<pre[^>]*?>.*?</pre>!is", $source, $match);
$_pre_blocks = $match[0];
$source = preg_replace("!<pre[^>]*?>.*?</pre>!is",
'@@@SMARTY:TRIM:PRE@@@', $source);
// Pull out the textarea blocks
preg_match_all("!<textarea[^>]*?>.*?</textarea>!is", $source, $match);
$_textarea_blocks = $match[0];
$source = preg_replace("!<textarea[^>]*?>.*?</textarea>!is",
'@@@SMARTY:TRIM:TEXTAREA@@@', $source);
// remove all leading spaces, tabs and carriage returns NOT
// preceeded by a php close tag.
$source = trim(preg_replace('/((?<!\?>)\n)[\s]+/m', '\1', $source));
// replace textarea blocks
smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source);
// replace pre blocks
smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source);
// replace script blocks
smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source);
return $source;
}
function smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) {
$_len = strlen($search_str);
$_pos = 0;
for ($_i=0, $_count=count($replace); $_i<$_count; $_i++)
if (($_pos=strpos($subject, $search_str, $_pos))!==false)
$subject = substr_replace($subject, $replace[$_i], $_pos, $_len);
else
break;
}
?>

View File

@@ -0,0 +1,74 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsConfiguration
* @author Uwe Tews
*/
define('SMARTY_PHP_PASSTHRU', 0);
define('SMARTY_PHP_QUOTE', 1);
define('SMARTY_PHP_REMOVE', 2);
define('SMARTY_PHP_ALLOW', 3);
/**
* This class does contain the security settings
*/
class Smarty_Security_Policy {
/**
* This determines how Smarty handles "<?php ... ?>" tags in templates.
* possible values:
* <ul>
* <li>SMARTY_PHP_PASSTHRU -> echo PHP tags as they are</li>
* <li>SMARTY_PHP_QUOTE -> escape tags as entities</li>
* <li>SMARTY_PHP_REMOVE -> remove php tags</li>
* <li>SMARTY_PHP_ALLOW -> execute php tags</li>
* </ul>
*
* @var integer
*/
public $php_handling = SMARTY_PHP_REMOVE;
/**
* This is the list of template directories that are considered secure.
* One directory per array element.
* $template_dir is in this list implicitly.
*
* @var array
*/
public $secure_dir = array();
/**
* This is an array of directories where trusted php scripts reside.
* {@link $security} is disabled during their inclusion/execution.
*
* @var array
*/
public $trusted_dir = array();
/**
* This is an array of trusted PHP functions.
*
* If empty all functions are allowed.
* If set to 'none' none is allowed.
* @var array
*/
public $php_functions = array('isset', 'empty',
'count', 'sizeof','in_array', 'is_array','time');
/**
* This is an array of trusted modifers.
*
* If empty all modifiers are allowed.
* If set to 'none' none is allowed.
* @var array
*/
public $modifiers = array('escape','count');
/**
+ flag if constants can be accessed from template
*/
public $allow_constants = true;
}
?>

View File

@@ -0,0 +1,31 @@
<?php
/**
* Smarty shared plugin
* @package Smarty
* @subpackage PluginsShared
*/
/**
* escape_special_chars common function
*
* Function: smarty_function_escape_special_chars<br>
* Purpose: used by other smarty functions to escape
* special chars except for already escaped ones
* @author Monte Ohrt <monte at ohrt dot com>
* @param string
* @return string
*/
function smarty_function_escape_special_chars($string)
{
if(!is_array($string)) {
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlspecialchars($string);
$string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string);
}
return $string;
}
/* vim: set expandtab: */
?>

View File

@@ -0,0 +1,43 @@
<?php
/**
* Smarty shared plugin
* @package Smarty
* @subpackage PluginsShared
*/
/**
* Function: smarty_make_timestamp<br>
* Purpose: used by other smarty functions to make a timestamp
* from a string.
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string
* @return string
*/
function smarty_make_timestamp($string)
{
if(empty($string)) {
// use "now":
$time = time();
} elseif (preg_match('/^\d{14}$/', $string)) {
// it is mysql timestamp format of YYYYMMDDHHMMSS?
$time = mktime(substr($string, 8, 2),substr($string, 10, 2),substr($string, 12, 2),
substr($string, 4, 2),substr($string, 6, 2),substr($string, 0, 4));
} elseif (is_numeric($string)) {
// it is a numeric string, we handle it as timestamp
$time = (int)$string;
} else {
// strtotime should handle it
$time = strtotime($string);
if ($time == -1 || $time === false) {
// strtotime() was not able to parse $string, use "now":
$time = time();
}
}
return $time;
}
?>

View File

@@ -0,0 +1,24 @@
<?php
/**
* Smarty Internal Base
*
* @package Smarty
* @subpackage PluginsInternal
* @author Monte Ohrt
*/
/**
/**
* Smarty Internal Base Class
*/
abstract class Smarty_Internal_Base {
/**
* Set up instance of Smarty object
*/
function __construct()
{
$this->smarty = Smarty::instance();
}
}
?>

View File

@@ -0,0 +1,113 @@
<?php
/**
* Smarty Internal Plugin Cacher InlineCode
*
* Process nocached code.
* Version to inject nocache code directly into cache file
* if caching is disabled at render time the code is being evaluated
*
* @package Smarty
* @subpackage Cacher
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Cacher InlineCode Class
*/
class Smarty_Internal_Cacher_InlineCode extends Smarty_Internal_PluginBase {
/**
* Inject inline code for nocache template sections
*
* This method gets the content of each template element from the parser.
* If the content is compiled code and it should be not cached the code is injected
* into the rendered output.
*
* @param string $content content of template element
* @param object $compiler intance of compiler class
* @param boolean $tag_nocache true if the parser detected a nocache situation
* @param boolean $is_code true if content is compiled code
* @return string content
*/
public function processNocacheCode ($content, $compiler, $tag_nocache, $is_code)
{
// If the template is not evaluated and we have a nocache section and or a nocache tag
if ($is_code) {
// generate replacement code
if (!$compiler->template->isEvaluated() && $compiler->template->caching &&
($tag_nocache || $compiler->nocache || $compiler->tag_nocache)) {
$compiler->tag_nocache = false;
$_output = str_replace("'", "\'", $content);
$_output = '<?php echo \'' . $_output . '\';?>';
} else {
$_output = $content;
}
} else {
$_output = $content;
}
// if compiled code shall be grabbed
if ($compiler->template->extract_code == false) {
// return output
return $_output;
} else {
// store code in extract buffer
$compiler->template->extracted_compiled_code .= $_output;
return '';
}
}
/**
* Initialize cacher
*
* Is a noop in current implementation
*
* @param object $compiler intance of compiler class
*/
public function initCacher ($compiler)
{
return;
}
/**
* Close cacher
*
* Hook to perform any post processing on the final compiled template
* Is a noop in current implementation
*
* @param object $compiler intance of compiler class
* @param string $template_code complete compiled template
* @return string compiled template output
*/
public function closeCacher ($compiler, $template_code)
{
return $template_code;
}
/**
* Retrieve cached output
*
* Calls the cache resource according to the caching type
*
* @param object $_template intance of template object
* @return string content from cache
*/
public function getCachedContents ($_template)
{
return $this->smarty->cache_resource_objects[$_template->caching_type]->getCachedContents($_template);
}
/**
* Store cached output
*
* Calls the cache resource according to the caching type
*
* @param object $_template intance of template object
* @return boolean status
*/
public function writeCachedContent ($_template)
{
return $this->smarty->cache_resource_objects[$_template->caching_type]->writeCachedContent($_template);
}
}
?>

View File

@@ -0,0 +1,170 @@
<?php
/**
* Smarty Internal Plugin CacheResource File
*
* Implements the file system as resource for the HTML cache
* Version ussing nocache inserts
*
* @package Smarty
* @subpackage Cacher
* @author Uwe Tews
*/
/**
* This class does contain all necessary methods for the HTML cache on file system
*/
class Smarty_Internal_CacheResource_File extends Smarty_Internal_PluginBase {
/**
* Returns the filepath of the cached template output
*
* @param object $template current template
* @return string the cache filepath
*/
public function getCachedFilepath($template)
{
return $this->buildCachedFilepath ($template->resource_name, $template->cache_id, $template->compile_id);
}
/**
* Returns the timpestamp of the cached template output
*
* @param object $template current template
* @return integer |booelan the template timestamp or false if the file does not exist
*/
public function getCachedTimestamp($template)
{
return ($template->getCachedFilepath() && file_exists($template->getCachedFilepath())) ? filemtime($template->getCachedFilepath()) : false ;
}
/**
* Returns the cached template output
*
* @param object $template current template
* @return string |booelan the template content or false if the file does not exist
*/
public function getCachedContents($template)
{
return file_get_contents($template->getCachedFilepath());
}
/**
* Writes the rendered template output to cache file
*
* @param object $template current template
* @return boolean status
*/
public function writeCachedContent($template)
{
if (!$template->isEvaluated()) {
if (!is_object($this->smarty->write_file_object)) {
$this->smarty->loadPlugin("Smarty_Internal_Write_File");
$this->smarty->write_file_object = new Smarty_Internal_Write_File;
}
return $this->smarty->write_file_object->writeFile($template->getCachedFilepath(), $template->rendered_content);
} else {
return false;
}
}
/**
* Empty cache folder
*
* @param integer $exp_time expiration time
* @return integer number of cache files deleted
*/
public function clearAll($exp_time = null)
{
return $this->clear(null, null, null, $exp_time);
}
/**
* Empty cache for a specific template
*
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param integer $exp_time expiration time
* @return integer number of cache files deleted
*/
public function clear($resource_name, $cache_id, $compile_id, $exp_time)
{
$_dir_sep = $this->smarty->use_sub_dirs ? DIRECTORY_SEPARATOR : '^';
if (isset($resource_name)) {
$_resource_part = md5($resource_name) . '.' . $resource_name . $this->smarty->php_ext;
} else {
$_resource_part = null;
}
$_dir = $this->smarty->cache_dir;
if (substr($_dir, -1) != DIRECTORY_SEPARATOR) {
$_dir .= DIRECTORY_SEPARATOR;
}
if ($this->smarty->use_sub_dirs && isset($cache_id)) {
$_dir .= str_replace('|', $_dir_sep, $cache_id) . $_dir_sep;
}
$_compile_pos = $this->smarty->use_sub_dirs ? 5 : 2;
$_count = 0;
$_cacheDirs = new RecursiveDirectoryIterator($_dir);
$_cache = new RecursiveIteratorIterator($_cacheDirs, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($_cache as $_file) {
if ($_file->isDir()) {
if (!$_cache->isDot()) {
// delete folder if empty
@rmdir($_file->getPathname());
}
} else {
$_parts = explode($_dir_sep, $_file);
$_parts_count = count($_parts);
$_parts_compile_pos = $_parts_count - $_compile_pos;
if ($_parts_compile_pos < 0) {
$_parts_compile_pos = 0;
}
if (substr_compare((string)$_file, $_dir, 0, strlen($_dir)) == 0 &&
(!isset($resource_name) || $_parts[$_parts_count-1] == $_resource_part) &&
(!isset($compile_id) || $_parts[$_parts_compile_pos] == $compile_id)) {
if (isset($exp_time)) {
if (time() - @filemtime($_file) >= $exp_time) {
$_count += unlink((string) $_file) ? 1 : 0;
}
} else {
$_count += unlink((string) $_file) ? 1 : 0;
}
}
}
}
return $_count;
}
/**
* Get system filepath to cached file
*
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @return string filepath of cache file
*/
private function buildCachedFilepath ($resource_name, $cache_id, $compile_id)
{
$_filepath = md5($resource_name);
// if use_sub_dirs, break file into directories
if ($this->smarty->use_sub_dirs) {
$_filepath = substr($_filepath, 0, 2) . DIRECTORY_SEPARATOR
. substr($_filepath, 2, 2) . DIRECTORY_SEPARATOR
. substr($_filepath, 4, 2) . DIRECTORY_SEPARATOR
. $_filepath;
}
$_compile_dir_sep = $this->smarty->use_sub_dirs ? DIRECTORY_SEPARATOR : '^';
if (isset($cache_id)) {
$_cache_id = str_replace('|', $_compile_dir_sep, $cache_id) . $_compile_dir_sep;
} else {
$_cache_id = '';
}
if (isset($compile_id)) {
$_compile_id = $compile_id . $_compile_dir_sep;
} else {
$_compile_id = '';
}
return $this->smarty->cache_dir . $_cache_id . $_compile_id . $_filepath . '.' . $resource_name . $this->smarty->php_ext;
}
}
?>

View File

@@ -0,0 +1,52 @@
<?php
/**
* Smarty Internal Plugin Compile Assign
*
* Compiles the {assign} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Assign Class
*/
class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase {
/**
* Compiles code for the {assign} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @return string compiled code
*/
public function compile($args, $compiler)
{
$this->compiler = $compiler;
$this->required_attributes = array('var', 'value');
$this->optional_attributes = array('global','nocache');
$_nocache = 'null';
$_global = 'null';
// check for nocache attribute before _get_attributes because
// it shall not controll caching of the compiled code, but is a parameter
if (isset($args['nocache'])) {
if ($args['nocache'] == 'true') {
$_nocache = 'true';
$_nocache_boolean = true;
}
unset($args['nocache']);
}
// check and get attributes
$_attr = $this->_get_attributes($args);
if (isset($_attr['global']) && $_attr['global'] == 'true') {
$_global = 'true';
$_global_boolean = true;
}
// compiled output
return "<?php \$_smarty_tpl->assign($_attr[var],$_attr[value],$_nocache,$_global);?>";
}
}
?>

View File

@@ -0,0 +1,47 @@
<?php
/**
* Smarty Internal Plugin Compile Assign
*
* Compiles the {assign} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Assign Global Class
*/
class Smarty_Internal_Compile_Assign_Global extends Smarty_Internal_CompileBase {
/**
* Compiles code for the {assign_global} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @return string compiled code
*/
public function compile($args, $compiler)
{
$this->compiler = $compiler;
$this->required_attributes = array('var', 'value');
$this->optional_attributes = array('nocache');
$_nocache = 'false';
// check for nocache attribute before _get_attributes because
// it shall not controll caching of the compiled code, but is a parameter
if (isset($args['nocache'])) {
if ($args['nocache'] == 'true') {
$_nocache = 'true';
$_nocache_boolean = true;
}
unset($args['nocache']);
}
// check and get attributes
$_attr = $this->_get_attributes($args);
// compiled output
return "<?php \$_smarty_tpl->smarty->assign_global($_attr[var],$_attr[value],$_nocache);?>";
}
}
?>

View File

@@ -0,0 +1,37 @@
<?php
/**
* Smarty Internal Plugin Compile Capture
*
* Compiles the {block} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Block Class
*/
class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase {
/**
* Compiles code for the {block} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @return string compiled code
*/
public function compile($args, $compiler)
{
$this->compiler = $compiler;
$this->required_attributes = array('name');
$this->optional_attributes = array('assign');
// check and get attributes
$_attr = $this->_get_attributes($args);
$this->_open_tag('block', $_attr);
$compiler->template->extract_code = true;
$compiler->template->extracted_compiled_code = '';
$compiler->template->has_code = false;
return true;
}
}
?>

View File

@@ -0,0 +1,57 @@
<?php
/**
* Smarty Internal Plugin Compile Block Plugin
*
* Compiles code for the execution of block plugin
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Block Plugin Class
*/
class Smarty_Internal_Compile_Block_Plugin extends Smarty_Internal_CompileBase {
/**
* Compiles code for the execution of block plugin
*
* @param array $args array with attributes from parser
* @param string $tag name of block function
* @param object $compiler compiler object
* @return string compiled code
*/
public function compile($args, $tag, $compiler)
{
$this->compiler = $compiler;
if (strlen($tag) < 6 || substr_compare($tag, 'close', -5, 5) != 0) {
// opening tag of block plugin
$this->required_attributes = array();
$this->optional_attributes = array('_any');
// check and get attributes
$_attr = $this->_get_attributes($args);
// convert attributes into parameter array string
$_paramsArray = array();
foreach ($_attr as $_key => $_value) {
$_paramsArray[] = "'$_key'=>$_value";
}
$_params = 'array(' . implode(",", $_paramsArray) . ')';
$this->_open_tag($tag, $_params);
// compile code
$output = '<?php $_block_repeat=true;$_smarty_tpl->smarty->plugin_handler->' . $tag . '(array(' . $_params . ', null, $_smarty_tpl->smarty, $_block_repeat, $_smarty_tpl),\'block\');while ($_block_repeat) { ob_start();?>';
} else {
// closing tag of block plugin
$_params = $this->_close_tag(substr($tag,0,-5));
// This tag does create output
$this->compiler->has_output = true;
// compile code
$output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); $_block_repeat=false; echo $_smarty_tpl->smarty->plugin_handler->' . substr($tag,0,-5) . '(array(' . $_params . ', $_block_content, $_smarty_tpl->smarty, $_block_repeat, $_smarty_tpl),\'block\'); }?>';
}
return $output;
}
}
?>

Some files were not shown because too many files have changed in this diff Show More