error = false;
$this->language = $language;
$this->langname = $language."_lang";
$lang_filename = FSHL_LANG."$this->langname.php";
$this->inject_statistic_code = $options & P_STATISTIC;
if(file_exists($lang_filename)) {
require_once ($lang_filename);
$this->lang = new $this->langname;
$this->options = $options;
$this->groups = &$group_delimiters;
$this->signature = $this->lang->signature;
$this->version = $this->lang->version;
if(!in_array($this->signature,$fshl_signatures))
{
$this->print_error("Unknown signature '$this->signature'.");
return;
}
if($this->language_array_optimise()) {
return;
}
$this->make();
} else {
$this->print_error("Language file '$lang_filename' not found.");
}
}
function get_source()
{
if($this->is_error())
return null;
else
return $this->out;
}
function is_error()
{
return $this->error;
}
function write($filename=null)
{
if($filename==null)
$filename=FSHL_CACHE."$this->langname.php";
if($this->is_error())
{
$this->print_error("File '$filename' not saved.");
return;
}
$filedes = fopen($filename,"w");
fwrite($filedes,$this->out,strlen($this->out));
fclose($filedes);
}
//
// LOW LEVEL FUNCTIONS
//
function print_error($text)
{
print ("fshl-generator: ".FSHL_LANG."$this->langname.php: $text\n");
$this->error = true;
}
function make()
{
$this->out = null;
// make source
$this->out.="out.="/* --------------------------------------------------------------- *\n";
$this->out.=" * WARNING: ALL CHANGES IN THIS FILE WILL BE LOST\n *\n";
$this->out.=" * Source language file: ".FSHL_LANG.$this->langname.".php\n";
$this->out.=" * Language version: $this->version (Sign:$this->signature)\n *\n";
$this->out.=" * Target file: ".FSHL_CACHE.$this->langname.".php\n";
$this->out.=" * Build date: ".date("D j.n.Y H:i:s")."\n *\n";
$this->out.=" * Generator version: ".FSHL_GENERATOR_VERSION."\n";
$this->out.=" * --------------------------------------------------------------- */\n";
// make class
$this->out.="class $this->langname";
if($this->signature=="TW")
$this->out.=" extends ".$this->language."_base";
$this->out.="\n{\n";
$this->out.='var $trans,$flags,$data,$delim,$class,$keywords;'."\n";
$this->out.='var $version,$signature,$initial_state,$ret,$quit;'."\n";
$this->out.='var $pt,$pti,$generator_version;'."\n";
$this->out.='var $names;'."\n";
if($this->inject_statistic_code) {
$this->out.='var $statistic, $total_statistic;'."\n";
}
$this->out.="\n";
// make constructor
$this->out.=get_fnc_source($this->langname);
// make class variables
$this->out.="\t".get_var_source("this->version",$this->version);
$this->out.="\t".get_var_source("this->signature",$this->signature);
$this->out.="\t".get_var_source("this->generator_version",FSHL_GENERATOR_VERSION);
$this->out.="\t".get_var_source("this->initial_state",$this->lang->initial_state);
$this->out.="\t".get_var_source("this->trans",$this->_trans);
$this->out.="\t".get_var_source("this->flags",$this->_flags);
$this->out.="\t".get_var_source("this->delim",$this->_delim);
$this->out.="\t".get_var_source("this->ret",$this->_ret);
$this->out.="\t".get_var_source("this->quit",$this->_quit);
$this->out.="\t".get_var_source("this->names",$this->_names);
if($this->signature!="TW") {
$this->out.="\t".get_var_source("this->data",$this->_data);
$this->out.="\t".get_var_source("this->class",$this->_class);
$this->out.="\t".get_var_source("this->keywords",$this->lang->keywords);
}
if($this->inject_statistic_code) {
$this->out.="\t".get_var_source("this->statistic",array());
$this->out.="\t".get_var_source("this->total_statistic",array());
}
//end constructor
$this->out.="}\n\n";
// make ISDx() functions
foreach($this->_delim as $state=>$delim)
if($delim==null)
continue;
else
$this->make_state_code($state);
$this->out.="}\n"; //end class
$this->out.="?>"; //end source (hack for PSpad :))
}
function inject_statistic_code($state, $hit, $tab = true) {
if($this->inject_statistic_code) {
$tab = $tab ? "\t\t\t" : "\t\t";
$code_piece = '$this->statistic['.$state.']['.$hit.']';
$this->out .= $tab."if(isset($code_piece)) { $code_piece++; }else{ $code_piece=1; }\n";
} else {
return;
}
}
/*
// code template
function getw4 (&$s, $i, $l) {
$o = null;
while($i < $l) {
$c1=$s[$i++];
if(!ctype_xdigit($c1)){
return array(0,$c1,$o);
}
$o.=$c1;
}
return array(-1,-1,$o);
}
*/
function make_state_code($state)
{
$statename=array_keys($this->_states,$state);
$tab = "\t"; $tab2 = "\t\t"; $tab3 = "\t\t\t";
$nl = "\n";
$this->out.="// $statename[0]\n";
$this->out.=fshlHelper::getFncSource("getw$state", '&$s, $i, $l');
//
// generate local variables initialization
//
$max = 1;
$var_init = null;
$transitions = 0;
$all_break = false;
foreach($this->_delim[$state] as $del)
{
$transitions++;
if(in_array($del,$this->groups)) {
if($del == '_ALL') {
$all_break = true;
$tab3 = $tab2;
$tab2 = $tab;
}
continue;
}
if($max 1)
{
$var_init.= $tab2.'$p=$i;'.$nl; // p - stream pointer
if($transitions > 1)
{
$var_init.= $tab2.'$c1=$s[$p++];'.$nl;
for($x=2;$x<=$max;$x++)
{
$xx=$x-1;
if($x!=$max) {
$var_init.= $tab2."\$c$x=\$c$xx.\$s[\$p++];".$nl;
} else {
$var_init.= $tab2."\$c$x=\$c$xx.\$s[\$p];".$nl;
}
}
}
else
{
// only one transition
$var_init.= $tab2.'$c1=';
for($x=1;$x<=$max;$x++)
{
if($x!=$max) {
$var_init.= '$s[$p++].';
} else {
$var_init.= '$s[$p];'.$nl;
}
}
}
}
else
{
$var_init.= $tab2.'$c1=$s[$i];'.$nl;
}
$this->out.= $tab.'$o = false;'. $nl;
$this->out.= $tab.'$start = $i;'. $nl;
if(!$all_break) {
$this->out.= $tab.'while($i<$l) {'. $nl;
}
$this->out.= $var_init;
//
// generate conditions and transitions
//
$this->inject_statistic_code($state, -1, false);
$cond = null;
$i = 0;
foreach($this->_delim[$state] as $del)
{
$size = strlen($del);
$delstring=get_string_source($del);
if(in_array($del,$this->groups))
{
// delimiter is group delimiter
// make condition
if( FSHL_USE_CTYPE ) $cond = $this->get_ctype_condition($del);
else $cond = $this->get_older_condition($del);
if($cond == "1") break;
$this->out.= $tab2."if($cond){".$nl;
$this->inject_statistic_code($state, $i);
$this->out.= $tab3."return array($i,\$c1,\$o,1,\$i-\$start);".$nl;
$this->out.= $tab2.'}'.$nl;
}
else
{
// delimiter is not group delimiter
//$i_str = $size == 1 ? '$i' : '$i+'.($size-1);
$this->out.= $tab2."if(\$c$size==$delstring){".$nl;
$this->inject_statistic_code($state, $i);
//$this->out.= $tab3."return array($i,$delstring,\$o,$i_str);".$nl;
$this->out.= $tab3."return array($i,$delstring,\$o,$size,\$i-\$start);".$nl;
$this->out.= $tab2.'}'.$nl;
}
$i++;
} // END foreach()
$this->inject_statistic_code($state, $i, false);
if($cond == "1") {
$this->out.= $tab2."return array($i,\$c1,false,\$i-\$start);".$nl;
} else {
$this->out.= $tab2.'$o.=$c1;'.$nl;
$this->out.= $tab2.'$i++;'.$nl;
}
if(!$all_break) {
$this->out.= $tab."}".$nl; //end while()
$this->out.= $tab.'return array(-1,-1,$o,-1,-1);'.$nl;
}
$this->out.= "}".$nl.$nl; //end getw() function
} // END make_state_code()
// condition generator for older PHP's
//
function get_older_condition($del)
{
switch ($del)
{
case "SPACE": $cond= "strchr(\" \\t\\n\\r\",\$c1)"; break;
case "!SPACE": $cond= "!strchr(\" \\t\\n\\r\",\$c1)"; break;
case "NUMBER": $cond= "strchr('0123456789',\$c1)"; break;
case "!NUMBER": $cond= "!strchr('0123456789',\$c1)"; break;
case "ALPHA": $cond= "stristr('eaoinltsrvdukzmcpyhjbfgxwq',\$c1)"; break;
case "!ALPHA": $cond= "!stristr('eaoinltsrvdukzmcpyhjbfgxwq',\$c1)"; break;
case "ALNUM": $cond= "stristr('eaoinltsrvdukzmcpyhjbfgxwq0123456789',\$c1)"; break;
case "!ALNUM": $cond= "!stristr('eaoinltsrvdukzmcpyhjbfgxwq0123456789',\$c1)"; break;
case "HEXNUM": $cond= "stristr('0123456789abcdef',\$c1)"; break;
case "!HEXNUM": $cond= "!stristr('0123456789abcdef',\$c1)"; break;
case "_ALL": $cond= "1"; break;
case "_COUNTAB": $cond= "strchr(\"\\t\\n\",\$c1)"; break;
case "SAFECHAR": $cond= "stristr('eaoinltsrvdukzmcpyhjbfgxwq_0123456789',\$c1)"; break;
case "!SAFECHAR": $cond= "!stristr('eaoinltsrvdukzmcpyhjbfgxwq_0123456789',\$c1)"; break;
// Special group delimiters
case "PHP_DELIM": $cond= "strchr(\" \\t\\n\\r;,:(){}[]!=%&|+-*/\",\$c1)"; break;
default: $cond = "BAD_FSHL_GENERATOR_VERSION__check_older";
$this->print_error("Group delimiter '$del' is not implemented.");
break;
} // END switch($del)
return $cond;
}
// new ctype condition generator (is really faster?)
//
function get_ctype_condition($del)
{
switch ($del)
{
case "SPACE": $cond= 'ctype_space($c1)'; break;
case "!SPACE": $cond= '!ctype_space($c1)'; break;
case "NUMBER": $cond= 'ctype_digit($c1)'; break;
case "!NUMBER": $cond= '!ctype_digit($c1)'; break;
case "ALPHA": $cond= 'ctype_alpha($c1)'; break;
case "!ALPHA": $cond= '!ctype_alpha($c1)'; break;
case "ALNUM": $cond= 'ctype_alnum($c1)'; break;
case "!ALNUM": $cond= '!ctype_alnum($c1)'; break;
case "HEXNUM": $cond= 'ctype_xdigit($c1)'; break;
case "!HEXNUM": $cond= '!ctype_xdigit($c1)'; break;
case "_ALL": $cond= "1"; break;
case "_COUNTAB": $cond= "(\$c1==\"\\t\" || \$c1==\"\\n\")"; break;
case "SAFECHAR": $cond= "ctype_alnum(\$c1) || \$c1=='_'"; break;
case "!SAFECHAR": $cond= "!(ctype_alnum(\$c1) || \$c1=='_')"; break;
// Special group delimiters
case "PHP_DELIM": $cond= "strchr(\" \\t\\n\\r;,:(){}[]!=%&|+-*/\",\$c1)"; break;
default: $cond = "BAD_FSHL_GENERATOR_VERSION";
$this->print_error("Group delimiter '$del' is not implemented.");
break;
} // END switch($del)
return $cond;
}
function language_array_optimise()
{
// internal language structures initialization
$j=0;
foreach ($this->lang->states as $state => $state_array)
{
if($state==P_QUIT_STATE)
continue;
$this->_states[$state]=$j;
$this->_names[$j++]=$state;
}
$this->_states[P_RET_STATE] = $this->_ret = $j++;
$this->_states[P_QUIT_STATE] = $this->_quit = $j++;
$this->_names[$this->_ret] = P_RET_STATE;
$this->_names[$this->_quit] = P_QUIT_STATE;
foreach ($this->lang->states as $statename => $state_array)
{
$state = $this->_states[$statename];
$this->_flags[$state] = $state_array[XL_FLAGS];
$this->_data[$state] = $state_array[XL_DATA];
$this->_class[$state] = $state_array[XL_CLASS];
if(is_array($state_array[XL_DIAGR]))
{
$i=0;
foreach ($state_array[XL_DIAGR] as $delimiter => $trans_array )
{
$transname=$trans_array[XL_DSTATE];
if(!isset($this->_states[$transname]))
{
$delimiter=str_replace("<","<",$delimiter);
$this->print_error("Unknown state in transition '$statename [$delimiter] => $transname'.");
return $this->error = true;
}
// V 0.4.5
$this->_delim[$state][$i]=$delimiter;
$trans_array[XL_DSTATE]=$this->_states[$transname];
$this->_trans[$state][$i]=$trans_array;
$i++;
}
}
else
{
$this->_delim[$state]=null;
$this->_trans[$state]=null;
}
}
$initial = $this->lang->initial_state;
if(!isset($this->_states[$initial]))
{
$this->print_error("Unknown initial state '$initial'.");
return $this->error = true;
}
$this->lang->initial_state=$this->_states[$initial];
return false;
}
} // END class fshlGenerator
?>