<?PHP
define(CATEGORY_MIXED, 'Mixed');
class Compiler
{
var $compiled;
var $html;
// Constructor
function Compiler()
{
}
function CompileRankingPage($page)
{
global $PHPSTART, $PHPEND;
#$map = array('DEFINE' => 'ProcessDefine', 'MEMBERS' => 'ProcessMembers', 'TEMPLATE' => 'ProcessTemplate', 'FEATURED' => 'ProcessFeatured');
$map = array('DEFINE' => 'ProcessDefine', 'MEMBERS' => 'ProcessMembers', 'TEMPLATE' => 'ProcessTemplate');
$directive = '';
$stack = array();
$buffer = '';
$this->html = array();
$this->compiled = '';
UnixFormat($page);
foreach(explode("\n", $page) as $line)
{
// Skip blank lines
if( IsEmptyString($line) )
{
continue;
}
if( preg_match('/^\s*<%([A-Z]+)\s*/', $line, $matches) )
{
$directive = $matches[1];
$stack[] = $directive;
}
else if( preg_match('/^\s*%>\s*/', $line, $matches) )
{
// Process directive with buffer
$this->$map[$directive]($buffer);
array_pop($stack);
$buffer = '';
$directive = '';
}
else
{
if( count($stack) > 0 )
{
$buffer .= "$line\n";
}
else
{
$line = preg_replace('/##(.*?)##/', "$PHPSTART echo \$T"."['$1']; $PHPEND", $line);
$this->compiled .= "$line\n";
}
}
}
Format($this->compiled);
return $this->compiled;
}
// Process the MEMBERS directive
function ProcessMembers(&$buffer)
{
global $PHPSTART, $PHPEND;
$options = array('RANKS' => '1-50', 'HTML' => 'Default');
$subdirectives = array();
$rank_qualifier = 'Overall_Rank';
// Extract and process INSERT sub-directives
$insert = '';
$this->ExtractSubDirectives($buffer, $subdirectives);
foreach($subdirectives as $subdirective)
{
$statement = $this->ProcessLocation($subdirective['LOCATION']);
$insert .= "if( $statement )\n" .
"{\n" .
"$PHPEND\n" .
"{$subdirective['HTML']}\n" .
"$PHPSTART\n" .
"}\n";
}
// Extract MEMBERS directive options
$this->ExtractOptions($buffer, $options);
// Process HTML option
$this->ProcessHTML($options['HTML'], '$account');
// Get the ranks to display
list($start_rank, $end_rank) = explode('-', $options['RANKS']);
// Process FILLTER option
$this->ProcessHTML($options['FILLER'], '$T');
$filler_code = "if( \$displayed < \$expected )\n" .
"{\n" .
"for( \$i = \$displayed + 1; \$i <= \$expected; \$i++ )\n" .
"{\n" .
"\$row_color = \$row_color == \$color_1 ? \$color_2 : \$color_1;\n" .
"\$T['Row_Color'] = \$row_color;\n" .
"\$T['Rank'] = \$i + " . ($start_rank - 1) . ";\n" .
"\$position = \$T['Rank'];\n" .
"$PHPEND\n" .
"{$options['FILLER']}\n" .
"$PHPSTART\n" .
"$insert" .
"}\n" .
"}\n";
// Begin creation of PHP code
$this->compiled .= "$PHPSTART\n" .
"list(\$color_1, \$color_2) = explode(',', '{$options['COLORS']}');\n" .
"\$start_rank = $start_rank;\n" .
"\$end_rank = $end_rank;\n" .
"\$expected = " . ($end_rank - $start_rank + 1) . ";\n" .
"\$displayed = 0;\n" .
"\$result = \$DB->Query(\"SELECT * FROM topsites_Snapshot WHERE \$L_MIN_HITS_QUALIFIER $rank_qualifier BETWEEN $start_rank AND $end_rank ORDER BY $rank_qualifier\");\n" .
"while( \$account = \$DB->NextRow(\$result) )\n" .
"{\n" .
"AccountData(\$account, \$GLOBALS['LANGUAGE']);\n" .
"\$row_color = \$row_color == \$color_1 ? \$color_2 : \$color_1;\n" .
"\$account['Row_Color'] = \$row_color;\n" .
"\$account['Movement_Overall'] = \$L_MOVEMENT[\$account['Movement_Overall']];\n" .
"$PHPEND\n" .
"{$options['HTML']}\n" .
"$PHPSTART\n" .
"\$position = \$start_rank + \$displayed;\n" .
"\$displayed++;\n" .
"$insert" .
"}\n" .
"$filler_code" .
"\$DB->Free(\$result);\n" .
"$PHPEND\n";
}
// Process the HTML directive option
function ProcessHTML(&$html, $namespace)
{
global $PHPSTART, $PHPEND;
if( isset($this->html[$html]) )
{
$html = $this->html[$html];
}
$html = preg_replace('/##(.*?)##/', "$PHPSTART echo $namespace"."['$1']; $PHPEND", $html);
}
// Process the LOCATION sub-directive option
function ProcessLocation($location)
{
$this->ProcessCommaSeparatedList($location);
// Format: +5
if( preg_match('/\+(\d+)/', $location, $matches) )
{
$statement = "\$position % $matches[1] == 0 && \$position != \$end_rank";
}
// Format: 5,10,15
else if( preg_match('/,/', $location) )
{
$statement = "strstr(\",$location,\", \",\$position,\")";
}
// Format: 5
else
{
$statement = "\$position == $location";
}
return $statement;
}
// Correct any errors in a comma separated list
function ProcessCommaSeparatedList(&$list)
{
// Remove whitespace at the beginning of the string
$list = preg_replace('/^\s+/', '', $list);
// Remove whitespace at the end of the string
$list = preg_replace('/\s+$/', '', $list);
// Remove whitespace before or after a comma
$list = preg_replace('/\s+$/', ',', $list);
}
// Extract the options from a directive or sub-directive
function ExtractOptions(&$buffer, &$options)
{
if( preg_match_all('/^\s*([A-Z]+)\s+(.+)$/mU', $buffer, $matches, PREG_SET_ORDER) )
{
foreach($matches as $match)
{
$options[$match[1]] = $match[2];
}
}
}
#REPLACE
// Extract sub-directives from a directive
function ExtractSubDirectives(&$buffer, &$subdirectives)
{
if( preg_match_all('/^([A-Z]+)\s+{\s+([^}]+)}\s+/mU', $buffer, $matches, PREG_SET_ORDER) )
{
foreach($matches as $match)
{
$this->ExtractOptions($match[2], $subdirectives[$match[1]]);
}
}
$buffer = preg_replace('/^([A-Z]+)\s+{\s+([^}]+)}\s+/mU', '', $buffer);
}
}
?>