firstprev=array("state"=>0,"word"=>"");
$this->secondprev=array("state"=>0,"word"=>"");
$this->line=0;
$this->pos=0;
$this->errors=array();
$this->errpos=-1;
$this->incomment=-1;
$this->allreadyparsed=0;
$this->pg=array();
$this->pgpos=-1;
$this->quotstate=-1;
$this->iseof=false;
$this->firststate=0;
$this->secondstate=0;
$this->mode=1;
if(gettype($this->data)=="array") {
$this->pg=&$data;
$this->allreadyparsed=1;
return;
}
clearstatcache();
$this->name=$data;
if (!file_exists($this->name)) {
$this->SetError(1,"File $this->name not exists.",0,0,"Error");
return;
}
if (!$fp=fopen($this->name,"r")) {
$this->SetError(1,"Can't open file $this->name.",0,0,"Error");
return;
}
flock($fp,1);
$this->data=fread($fp,filesize($this->name));
flock($fp,3);
fclose($fp);
$this->length=strlen($this->data);
}
/********************************************************************************************
* Store parser's errors and warnings
********************************************************************************************/
function SetError($e,$str,$line=0,$column=0,$errtype="Warning") {
$this->errors[++$this->errpos]["type"]=$errtype;
$this->errors[$this->errpos]["code"]=$e;
$this->err=$e;
$this->errstr="$errtype: $e, $str";
if ($line) {
if (strlen($this->name))
$this->errstr.="object $this->name";
$this->errstr.=" Line $line, Column $column";
}
$this->errors[$this->errpos]["str"]=$this->errstr."
\r\n";
}
/********************************************************************************************
* Print parser's errors and warnings
********************************************************************************************/
function PrintErrors() {
for ($i=0;$i<=$this->errpos;$i++)
print $this->errors[$i]["str"];
}
/********************************************************************************************
* Get word from data
********************************************************************************************/
function GetWord($word) {
$word="";
$found=0;
$iter=0;
if ($this->pos>$this->length)
return false;
while (!$found) {
if ($this->pos>$this->length)
return false;
if ($this->pos==$this->length) {
$this->pos++;
return $word;
}
switch($this->data[$this->pos]) {
case "*":
if ($this->quotstate==1) {
$word.=$this->data[$this->pos++];
$this->column++;
break;
}
$this->column++;
$this->pos++;
if ($word[0]=="/")
$found=1;
$word.=$this->data[$this->pos-1];
break;
case "/":
if ($this->quotstate==1) {
$word.=$this->data[$this->pos++];
$this->column++;
break;
}
$this->column++;
$this->pos++;
if ($word[0]=="*")
$found=1;
$word.=$this->data[$this->pos-1];
break;
case " ":
case "\r":
case "\t":
if ($this->quotstate==1) {
$word.=$this->data[$this->pos++];
$this->column++;
break;
}
$this->column++;
$this->pos++;
if (strlen($word))
$found=1;
break;
case "\n":
if ($this->quotstate==1) {
$word.=$this->data[$this->pos++];
$this->column++;
break;
}
$this->column=0;
$this->line++;
$this->pos++;
if (strlen($word))
$found=1;
break;
case ">":
case "<":
case "=":
if ($this->quotstate==1) {
$word.=$this->data[$this->pos++];
$this->column++;
} else {
if (!strlen($word)) {
$word=$this->data[$this->pos++];
$this->column++;
}
$found=1;
}
break;
case "\"":
if ($this->pos) {
if ($this->data[$this->pos-1]=="\\") {
$word.=$this->data[$this->pos++];
$this->column++;
} else {
if (!strlen($word)) {
$this->quotstate*=-1;
$word=$this->data[$this->pos++];
$this->column++;
}
$found=1;
}
} else {
$word=$this->data[$this->pos++];
$this->column++;
$found=1;
}
break;
default:
$this->column++;
$word.=$this->data[$this->pos++];
}
}
return true;
}
/********************************************************************************************
* Parse grammar first step
********************************************************************************************
Parse
< [] [] >
in/state 0 1 2 3
< 1 -1 -1 1
[ -1 2 -1 -1
] -1 -1 1 -1
> -1 3 -1 -1
word -1 1 2 -1
EOF -1 -1 -1 -2
-2 end parse
0 begin parse, waiting '<'
1 got '<' need to parse parameters, or wait '>' or wait '['
2 got '[' or ']' need to parse parameters
3 got '>', waiting eof or '<'
********************************************************************************************/
function ParseFirst($word) {
if ($this->iseof) {
$this->firstprev["state"]=0;
$this->firstprev["word"]="";
return true;
}
$automat=array(
"0"=>array( 1, -1, -1, 1),
"1"=>array(-1, 2, -1, -1),
"2"=>array(-1, -1, 1, -1),
"3"=>array(-1, 3, -1, -1),
"4"=>array(-1, 1, 2, -1),
"5"=>array(-1, -1, -1, -2)
);
switch($word) {
case "<":
$instate=0;
$this->pgpos++;
$this->parpos=-1;
break;
case "[":
$this->parpos++;
$instate=1;
break;
case "]":
$instate=2;
break;
case ">":
$instate=3;
break;
default:
$instate=4;
break;
}
$this->firststate=$automat[$instate][$this->firststate];
if ($this->firststate==-1) return false;
switch ($this->firststate) {
case 1:
$this->mode=1;
if ($this->firstprev["state"]==1)
if (!$this->ParseSecond($word)) return false;
break;
case 2:
switch($this->firstprev["state"]) {
case 1:
$this->mode=2;
break;
case 3:
case 2:
if ($this->firstprev["state"]==2)
$this->mode=2;
else
$this->mode=1;
break;
}
if ($this->firstprev["state"]==2)
if (!$this->ParseSecond($word)) return false;
break;
case 3:
if (isset($this->pg[$this->pgpos]["tag"]["nohavesametag"]))
$this->pg[$this->pgpos]["tag"]["closeon"]["in"][]=$this->tagname;
break;
}
$this->firstprev["state"]=$this->firststate;
$this->firstprev["word"]=$word;
return true;
}
/********************************************************************************************
* Parse grammar second step
********************************************************************************************
Parse
par1="value" par2=value
in/state 0 1 2 3 4
= -1 2 -1 3 -1
" -1 -1 3 4 -1
word 1 -1 4 3 1
EOF -1 -1 -1 -1 -1
-3 end parse by '>'
-2 end parse by ']'
0 begin parse waiting parname
1 got parname, waiting '=' or new parname
2 got '=' waiting any word as value or first '"'
3 collect words to next '"'
4 got parvalue, waiting new parname
********************************************************************************************/
function ParseSecond($word) {
if ($this->iseof) return false;
$automat=array(
"0"=>array(-1, 2, -1, 3, -1),
"1"=>array(-1, -1, 3, 4, -1),
"2"=>array( 1, 1, 4, 3, 1),
"3"=>array(-1, -1, -1, -1, -1)
);
switch($word) {
case "=":
$instate=0;
break;
case "\"":
$instate=1;
break;
default:
$instate=2;
break;
}
$this->secondstate=$automat[$instate][$this->secondstate];
if ($this->secondstate==-1) return false;
switch ($this->secondstate) {
case 1:
$this->parname=$word;
if (!ereg("[a-zA-Z_-]+([0-9]+)?",$word)) {
$this->SetError(1,"Fatal error.",$this->line,$this->column,"Error");
return false;
}
switch($this->mode) {
case 1:
$this->pg[$this->pgpos]["tag"][$this->parname]="";
break;
case 2:
$this->pg[$this->pgpos]["pars"][$this->parpos][$this->parname]="";
break;
}
break;
case 4:
switch($this->mode) {
case 1:
if ($this->secondprev["state"]==3)
$this->pg[$this->pgpos]["tag"][$this->parname]=$this->secondprev["word"];
else
$this->pg[$this->pgpos]["tag"][$this->parname]=$word;
if ($this->parname=="closeon") {
$notexists=array();
$exists=array();
$this->ParseCloseOn($this->pg[$this->pgpos]["tag"][$this->parname],&$notexists,&$exists);
$this->pg[$this->pgpos]["tag"][$this->parname]=array();
$this->pg[$this->pgpos]["tag"][$this->parname]["notin"]=$notexists;
$this->pg[$this->pgpos]["tag"][$this->parname]["in"]=$exists;
} elseif ($this->parname=="tag")
$this->tagname=$this->pg[$this->pgpos]["tag"]["tag"];
break;
case 2:
if ($this->secondprev["state"]==3)
$this->pg[$this->pgpos]["pars"][$this->parpos][$this->parname]=$this->secondprev["word"];
else
$this->pg[$this->pgpos]["pars"][$this->parpos][$this->parname]=$word;
break;
}
break;
}
$this->secondprev["state"]=$this->secondstate;
$this->secondprev["word"]=$word;
return true;
}
/********************************************************************************************
* Parse closeon structure
********************************************************************************************/
function ParseCloseOn($str,$notexists,$exists) {
$arr=explode("|",$str);
if (!is_array($arr)) {
if (!strlen($str))
return;
else
$arr[]=$str;
}
for ($i=0;$iallreadyparsed) return true;
$this->line=1;
while(1) {
$isword=$this->GetWord(&$word);
if (!$isword) $this->iseof=true;
switch (strtolower($word)) {
case "/*";
$this->incomment*=-1;
break;
case "*/";
if ($this->incomment!=1) {
$this->SetError(1,"Not found begin of comment operator.",$this->line,$this->column,"Error");
return;
}
$this->incomment*=-1;
break;
default:
if ($this->incomment==1) break;
if (!$this->ParseFirst($word)) {
$this->SetError(1,"Fatal error",$this->line,$this->column,"Error");
return false;
}
break;
}
if ($this->iseof) break;
}
if ($this->incomment==1) {
$this->SetError(1,"Not found end of comment operator.",$this->line,$this->column,"Error");
return false;
}
$this->PrepareGrammar();
return true;
}
/********************************************************************************************
* Prepare grammar for future using
********************************************************************************************/
function PrepareGrammar() {
$edittagsaftertable=$this->ScanGrammar();
$l=sizeof($this->pg);
for ($i=0;$i<$l;$i++) {
$this->pg[$this->pg[$i]["tag"]["tag"]]=$this->pg[$i]["tag"];
if (isset($this->pg[$i]["pars"])) {
$n=sizeof($this->pg[$i]["pars"]);
for ($j=0;$j<$n;$j++)
$this->pg[$this->pg[$i]["tag"]["tag"]]["pars"][$this->pg[$i]["pars"][$j]["par"]]=$this->pg[$i]["pars"][$j];
} else
$this->pg[$this->pg[$i]["tag"]["tag"]]["pars"]=array();
unset($this->pg["$i"]);
}
$this->pg["EDIT_TAGS_AFTER_TABLE"]=$edittagsaftertable;
}
/********************************************************************************************
* Scan grammar for creating edittagsafter table
********************************************************************************************/
function ScanGrammar() {
$edittagsaftertable=array();
for ($i=0;$ipg);$i++)
if (isset($this->pg[$i]["tag"]["edittagsafter"]))
if (!in_array($this->pg[$i]["tag"]["edittagsafter"],$edittagsaftertable)) $edittagsaftertable[]=$this->pg[$i]["tag"]["edittagsafter"];
return $edittagsaftertable;
}
/********************************************************************************************
* Save precompiled grammar in file
********************************************************************************************/
function SaveGrammar($name) {
$str=serialize($this->pg);
if (!$fp=fopen($name,"w"))
print "
Error: Can't create file $name. Unable to save grammar.
";
flock($fp,2);
fwrite($fp,$str,strlen($str));
flock($fp,3);
fclose($fp);
}
}
} //_ECHOSERVER_HTML_GRAMMARPARSER
?>