<?php
// License: GNU General Public License (GPL)
// class.logo.parser.php
// @ver 0.1
// Author: Zhihua Lai
// Example URL: http://www.zhihua-lai.com/?do=Crap.Logo
// Include necessary files
@include_once("logo.php");
@include_once("util.php");
@include_once("class.storage.php");
// Constants Definition
define("LOGO_OK_PROC_RETURN",-1);
define("LOGO_OK",0);
define("LOGO_ERROR_UNFINISHED_COMMENTS",1);
define("LOGO_ERROR_MISSING_COMMAND",2);
define("LOGO_WARNING_NOT_FULLY_IMPLEMENTED",3);
define("LOGO_WARNING_NUMBER_ROUNDED",4);
define("LOGO_ERROR_MISSING_ARG",5);
define("LOGO_ERROR_BAD_COMMAND",6);
define("LOGO_WARNING_UNSUPPORTED_BG_CHANGE",7);
define("LOGO_ERROR_NO_REPEAT_TIME",8);
define("LOGO_ERROR_UNSUPPORTED_GROUP_ACTION",9);
define("LOGO_ERROR_TOO_MANY_LEFT",10);
define("LOGO_ERROR_TOO_MANY_RIGHT",11);
define("LOGO_INFORMATION_TOO_MANY_WARNING",12);
define("LOGO_ERROR_TIME_OUT",13);
define("LOGO_WARNING_MISSING_REPEAT_BODY",14);
define("LOGO_ERROR_STOP_NOT_IN_PROC",15);
define("LOGO_ERROR_END_NOT_FOUND",16);
define("LOGO_ERROR_KEYWORD_IN_USE",17);
define("LOGO_ERROR_NESTED_PROCEDURE_NOT_ALLOWED",18);
define("LOGO_ERROR_INVALID_PROC_NAME",19);
define("LOGO_ERROR_PROC_DEFINED",20);
define("LOGO_ERROR_NO_TO",21);
define("LOGO_ERROR_INVALID_SYMBOL",22);
define("LOGO_ERROR_TOO_MANY_PROC",23);
define("LOGO_WARNING_TURTLE_OUT",24);
define("LOGO_ERROR_REPEAT_PROC_ARG",25);
define("LOGO_ERROR_TOO_MANY_LEVELS",26);
define("LOGO_WARNING_LOCAL_MAKE_GLOBALUSE",27);
define("LOGO_ERROR_MAKE_NEED_QUOTE",28);
define("LOGO_ERROR_MAKE_INVALID_NAME",29);
define("LOGO_ERROR_MAKE_INVALID_VALUE",30);
define("LOGO_ERROR_UNKNOWN_GROUP",31);
define("LOGO_ERROR_MISSING_BOOLEAN",32);
// Interpreter Class
class LogoParser
{
var $_logo;
var $_s;
var $_vars;
var $_makevars;
var $_localmake=array();
var $_coms=array();
var $_args=array();
var $_lineX;
var $_lineY;
var $_warnings=array();
var $_lineW;
var $_maxW;
var $_repeat=array();
var $_repeatT=array();
var $_maxT;
var $_runningT;
var $_maxProcLevel;
var $_endT;
var $_maxProc;
var $_inProc;
var $_rlvl;
var $_to_names=array();
var $_to_start=array();
var $_to_end=array();
var $_to_args=array();
var $_to_counting_args;
var $_var_stack=array();
var $_src_line;
var $_runningProc=array();
var $Logo_Color_R=array(0,0,0,0,255,255,255,255,155,197,100,120,255,144,255,183);
var $Logo_Color_G=array(0,0,255,255,0,0,255,255,96,136,162,187,149,113,163,183);
var $Logo_Color_B=array(0,255,0,255,0,255,0,255,59,18,64,187,119,208,0,183);
var $_keywords_args=array(
"FORWARD","FD",
"BACK","BK",
"RIGHT","RT",
"LEFT","LT",
"SETPC","SETPENCOLOR","SETPENCOLOUR",
"SETSCREENCOLOR","SETSC","SETSCREENCOLOUR",
"REPEAT",
"SETXY","SETPOS",
"SETX",
"SETY",
"TO",
"ARC",
"MAKE",
"LOCALMAKE",
"LOCAL",
"IF",
//"IFELSE",
"SETFC","SETFLOODCOLOR","SETFLOODCOLOUR"
);
var $_keywords=array(
"HT","HIDETURTLE",
"ST","SHOWTURTLE",
"PU","PENUP",
"PD","PENDOWN",
"CS","CLEANSCREEN",
"HOME",
"FENCE",
"WINDOW",
"WRAP",
"FILL",
"END",
"STOP"
);
/* Constructor */
function LogoParser(&$lgo, $s="")
{
$this->_logo=&$lgo;
$this->_lineX=0;
$this->_lineY=0;
$this->_lineW="";
$this->_maxW=5;
$this->_maxT=3;
$this->_maxProcLevel=200;
$this->_maxProc=200;
$this->_inProc=false;
$this->_rlvl=0;
$this->_to_counting_args=false;
$this->_makevars=new Storage();
$this->_vars=new Storage();
$this->_vars->_setVar("SCREENCOLOUR",($lgo->getSC()));
$this->_vars->_setVar("FLOODCOLOUR",($lgo->getFC()));
$this->_vars->_setVar("PENCOLOUR",($lgo->getPC()));
$this->_vars->_setVar("SCREENCOLOR",($lgo->getSC()));
$this->_vars->_setVar("FLOODCOLOR",($lgo->getFC()));
$this->_vars->_setVar("PENCOLOR",($lgo->getPC()));
$this->_vars->_setVar("PI",pi());
$this->_vars->_setVar("WIDTH", $lgo->getImageX());
$this->_vars->_setVar("HEIGHT", $lgo->getImageY());
$this->_vars->_setVar("MAXX", $lgo->getImageHX());
$this->_vars->_setVar("MAXY", $lgo->getImageHY());
$this->_vars->_setVar("MINX", -$lgo->getImageHX());
$this->_vars->_setVar("MINY", -$lgo->getImageHY());
$this->_vars->_setVar("ISTRUECOLOR", $lgo->isTrueColor()?1:0);
$this->_vars->_setVar("LOGO_BLACK",0);
$this->_vars->_setVar("LOGO_BLUE",1);
$this->_vars->_setVar("LOGO_GREEN",2);
$this->_vars->_setVar("LOGO_CYAN",3);
$this->_vars->_setVar("LOGO_RED",4);
$this->_vars->_setVar("LOGO_MAGENTA",5);
$this->_vars->_setVar("LOGO_YELLOW",6);
$this->_vars->_setVar("LOGO_WHITE",7);
$this->_vars->_setVar("LOGO_BROWN",8);
$this->_vars->_setVar("LOGO_LIGHT_BROWN",9);
$this->_vars->_setVar("LOGO_MID_GREEN",10);
$this->_vars->_setVar("LOGO_BLUE_GREEN",11);
$this->_vars->_setVar("LOGO_SALMON",12);
$this->_vars->_setVar("LOGO_BLUE_ISH",13);
$this->_vars->_setVar("LOGO_ORANGE",14);
$this->_vars->_setVar("LOGO_SILVER",15);
$this->_vars->_setVar("POSX",0);
$this->_vars->_setVar("POSY",0);
$this->_vars->_setVar("DEGREE",0);
}
function setMaxTimeout($d)
{
$d=(integer)$d;
if ($d<1) $d=1;
if ($d>5) $d=5;
$this->_maxT=$d;
}
function getMaxTimeout()
{
return ($this->_maxT);
}
function getMsg($code, $x=0, $y=0, $w="")
{
$code=(integer)$code;
$m="";
switch ($code)
{
case LOGO_OK:
case LOGO_OK_PROC_RETURN: $m="OK - EXECUTED"; break;
case LOGO_ERROR_UNFINISHED_COMMENTS: $m="ERROR - UNFINISHED COMMENTS"; break;
case LOGO_ERROR_MISSING_COMMAND: $m="ERROR - MISSING COMMAND"; break;
case LOGO_WARNING_NUMBER_ROUNDED: $m="WARNING - FLOAT ROUNDED AS INTEGER"; break;
case LOGO_ERROR_MISSING_ARG: $m="ERROR - MISSING ARGUMENTS"; break;
case LOGO_ERROR_BAD_COMMAND: $m="ERROR - UNKNOWN COMMAND OR PROCEDURE"; break;
case LOGO_WARNING_UNSUPPORTED_BG_CHANGE: $m="WARNING - UNABLE TO CHANGE SCREEN COLOR IN PROCESS"; break;
case LOGO_ERROR_TOO_MANY_LEFT: $m="ERROR - MISSING ']'"; break;
case LOGO_ERROR_TOO_MANY_RIGHT: $m="ERROR - MISSING '['"; break;
case LOGO_INFORMATION_TOO_MANY_WARNING: $m="MSG - TOO MANY WARNINGS, THE REST IGNORED"; break;
case LOGO_ERROR_TIME_OUT: $m="ERROR - TIME OUT"; break;
case LOGO_WARNING_MISSING_REPEAT_BODY: $m="WARNING - MISSING A GROUP STATMENT"; break;
case LOGO_WARNING_NOT_FULLY_IMPLEMENTED: $m="WARNING - NOT FULLY IMPLEMENTED"; break;
case LOGO_ERROR_STOP_NOT_IN_PROC: $m="ERROR - CAN ONLY USE STOP IN PROCEDURE"; break;
case LOGO_ERROR_END_NOT_FOUND: $m="ERROR - NEED A 'END' TO FINISH DEFINITION OF 'TO'";break;
case LOGO_ERROR_KEYWORD_IN_USE: $m="ERROR - PROCEDURE NAME IS A RESERVED KEYWORD"; break;
case LOGO_ERROR_NESTED_PROCEDURE_NOT_ALLOWED: $m="ERROR - NESTED PROCEDURE NOT ALLOWED"; break;
case LOGO_ERROR_INVALID_PROC_NAME: $m="ERROR - INVALID PROCEDURE NAME"; break;
case LOGO_ERROR_PROC_DEFINED: $m="ERROR - PROCEDURE CAN NOT BE RE-DEFINED"; break;
case LOGO_ERROR_NO_TO: $m="ERROR - CANNOT FIND 'TO' TO START DEFINING PROCEDURE"; break;
case LOGO_ERROR_INVALID_SYMBOL: $m="ERROR - NOT A VALID PROCEDURE NAME"; break;
case LOGO_ERROR_TOO_MANY_PROC: $m="ERROR - EXCEED MAXIMUM ".$this->_maxProc." DEFINED PROCEDURES "; break;
case LOGO_WARNING_TURTLE_OUT: $m="WARNING - TURTLE IS OUT OF BOUND"; break;
case LOGO_ERROR_REPEAT_PROC_ARG: $m="ERROR - DUPLICATION OF PROCEDURE ARGUMENTS"; break;
case LOGO_ERROR_TOO_MANY_LEVELS: $m="ERROR - TOO MANY LEVELS OF PROCEDURE"; break;
case LOGO_WARNING_LOCAL_MAKE_GLOBALUSE: $m="WARNING - LOCALMAKE GLOBALLY USE (NOT DELETED)"; break;
case LOGO_ERROR_MAKE_NEED_QUOTE: $m="ERROR - MAKE VARIABLE NEEDS DOUBLE QUOTA"; break;
case LOGO_ERROR_MAKE_INVALID_NAME: $m="ERROR - MAKE VARIABLE IS NOT A VALID KEYWORD"; break;
case LOGO_ERROR_MAKE_INVALID_VALUE: $m="ERROR - MAKE DOES NOT HAVE A VALID VALUE"; break;
case LOGO_ERROR_UNKNOWN_GROUP: $m="ERROR - UNKNOWN ACTION TO START A GROUP '['"; break;
case LOGO_ERROR_NO_REPEAT_TIME: $m="ERROR - NO ENOUGH INPUT TO REPEAT"; break;
case LOGO_ERROR_UNSUPPORTED_GROUP_ACTION: $m="ERROR - UNSUPPORTED GROUP ACTION"; break;
case LOGO_ERROR_MISSING_BOOLEAN: $m="ERROR - IF STATEMENT MISSING BOOLEAN EXPRESSION"; break;
default: $m="ERROR - UNKNOWN REASONS FAILED THE PROCESS";break;
}
$s="";
$extra="";
if (strlen($w)>8) $w=substr($w,0,8).'[..]';
if ($x&&$y)
{
if ($w)
{
$extra=" - ('".$w."')";
}
$s=$m."$extra AT ROW ".$y." COL ".$x;
}
else
{
if ($this->_lineW)
{
$extra=" - ( '".$this->_lineW."' )";
}
$s=$m."$extra AT ROW ".$this->_lineY." COL ".$this->_lineX;
}
if (($this->_src_line)&&($code!=LOGO_OK))
{
$extra=" (__LINE__:".$this->_src_line.")";
}
return ($s.$extra);
}
function getMemAndTime()
{
return ("[IN ".$this->_endT." SECONDS, ".(memory_get_usage())." BYTES ALLOCATED]");
}
function isSymbol($s)
{
if (strlen($s)==0) return (false);
if (isDigit($s{0})) return (false);
if (($s{0}=="'")||($s{0}=='"')||($s{0}==":")) return (false);
$i=1;
while ((isChar($s{$i}))||(isDigit($s{$i}))||($s{$i}=='_')) { $i++; }
return ($i>=strlen($s));
}
function isGood($s)
{
return ( ($this->isSymbol($s)) && (!in_array($s, $this->_keywords))
&&(!in_array($s, $this->_keywords_args))
&&(!in_array($s, $this->_to_names))
);
}
function str2num($str, &$changes)
{
$t=$str;
$changes=true;
$str = preg_replace('`([^+\-*=/\(\)0-9<>&|\.%]*)`','',$str);
if (strlen($str)==0)
{
$str = '0';
}
else
{
if (strlen($t)==strlen($str))
{
eval("\$str = $str;");
$changes=false;
}
else
{
$str = '0';
}
}
return $str;
}
function isNumber($s, &$realnum, &$value)
{
if (strpos($s, "==")===false)
{
$s=str_replace("=","==",$s);
}
foreach ($this->_vars->keys() as $keys)
{
$s=str_replace(":".$keys, $this->_vars->getVar($keys), $s);
}
$s=str_replace($this->_vars->keys(), $this->_vars->values(), $s);
if (count($this->_runningProc))
{
$procVarIdx=array_search($this->_runningProc[count($this->_runningProc)-1], $this->_to_names);
foreach ($this->_to_args[$procVarIdx]->keys() as $key)
{
$s=str_replace(":".$key, $this->_to_args[$procVarIdx]->getVar($key), $s);
}
}
foreach ($this->_makevars->keys() as $keys)
{
$s=str_replace(":".$keys, $this->_makevars->getVar($keys), $s);
}
$s=str_replace("RANDOMNUMBER0_100",mt_rand(0,100), $s);
$value=$this->str2num($s, &$c);
$realnum=false;
if (!$c)
{
$realnum=is_float($value);
//$value=$value;
return (true);
}
$value=(integer)$value;
return (false);
}
function getNextWord(&$s, $i, $U, &$j)
{
$t="";
while (isSpace($s{$i})) { $i++; }
if ($i>=$U)
{
$j=$i;
return ("");
}
if (($s{$i}=="[") || ($s{$i}=="]"))
{
$j=$i;
return ($s{$i});
}
if ($s{$i}==";")
{
$j=$i;
return ($s{$i});
}
while ( ( (!isSpace($s{$i})) && ($i<$U) ) &&
($s{$i}!="[") && ($s{$i}!="]") &&
($s{$i}!=";") &&
( !(($s{$i}=="/")&&($s{$i+1}=="/")) ) &&
( !(($s{$i}=="/")&&($s{$i+1}=="*")) )
)
{
$t.=$s{$i};
$i++;
}
$j=$i-1;
if ($i>=$U) $j=$i;
return ($t);
}
function printWarnings()
{
$i=0;
$j=-$this->_logo->getImageHY();
$t=1;
while ($i<count($this->_warnings))
{
$j+=$this->_logo->printText(-$this->_logo->getImageHX(), $j,
$this->getMsg($this->_warnings[$i],
$this->_warnings[$i+1],
$this->_warnings[$i+2],
$this->_warnings[$i+3])
);
$t++;
if ($t>$this->_maxW)
{
$j+=$this->_logo->printText(-$this->_logo->getImageHX(), $j,
$this->getMsg(LOGO_INFORMATION_TOO_MANY_WARNING)
);
break;
}
$i+=4;
}
return ($this->_logo->getIYd($j));
}
function pushWarn($code, $x, $y, $w)
{
$t=(integer)(((count($this->_warnings)+1)/4)-1);
if ($t>$this->_maxW)
{
return;
}
$same=false;
for ($i=0;$i<count($this->_warnings);$i+=4)
{
if ( ($code==$this->_warnings[$i]) &&
($x==$this->_warnings[$i+1]) &&
($y==$this->_warnings[$i+2])
)
{
$same=true;
break;
}
}
if (!$same)
{
array_push($this->_warnings, $code, $x, $y, $w);
}
}
function getX()
{
return ($this->_lineX);
}
function getY()
{
return ($this->_lineY);
}
function getW()
{
return ($this->_lineW);
}
function _getXY(&$s, $d, $w="")
{
$i=0;
$x=0;
$j=1;
while ($i<$d)
{
$x++;
if (($s{$i}=="\n"))
{
$j++;
$x=0;
}
$i++;
}
$this->_lineX=$x+1;
$this->_lineY=$j;
$this->_lineW=$w;
}
function removeLocalVars()
{
$k=array_search($this->_runningProc[count($this->_runningProc)-1], $this->_to_names);
$s=$this->_localmake;
foreach ($s as $key=>$v)
{
if ($v[0]==$this->_to_names[$k])
{
$this->_to_args[$k]->delVar($v[1]);
unset($this->_localmake[$key]);
}
}
}
function _parse(&$s, $i=0, $U=0)
{
if ($U<=0)
{
$U=strlen($s);
}
if ($i>=$U) return (LOGO_OK);
$i--;
while ($i<$U)
{
/* Check if Time Out */
$this->_endT=abs(round(microtime()-$this->_runningT,5));
if ($this->_endT>$this->_maxT)
{
$this->_getXY(&$s, $i+1);
$this->_src_line=__LINE__;
return (LOGO_ERROR_TIME_OUT);
}
$i++;
if ($i>=$U)
{
break;
}
/* Skip Spaces */
if (isSpace($s{$i})) continue;
/* Comments Start */
if (($s{$i}=="/")&&($s{$i+1}=="*"))
{
$i+=2;
while ( ($i<$U) &&
!(($s{$i}=="*")&&($s{$i+1}=="/"))
)
{
$i++;
}
if (($s{$i}=="*")&&($s{$i+1}=="/"))
{
$i+=1;
continue;
}
else
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_UNFINISHED_COMMENTS);
}
}
if (($s{$i}=="/")&&($s{$i+1}=="/"))
{
$i+=2;
while (($i<$U)&&($s{$i}!="\n")) { $i++; }
if ($s{$i}=="\n")
{
continue;
}
break;
}
if (($s{$i}==";")||($s{$i}=="#"))
{
$i++;
while (($i<$U)&&($s{$i}!="\n")) { $i++; }
if ($s{$i}=="\n")
{
continue;
}
break;
}
/* Coments Ends */
/* Group */
if (!$this->_inProc)
{
if ($s{$i}=="[")
{
if (count($this->_coms)==0)
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_UNKNOWN_GROUP);
}
array_push($this->_repeat, $i);
continue;
}
if ($s{$i}=="]")
{
if (count($this->_repeat)==0)
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_TOO_MANY_RIGHT);
}
$groupstart=array_pop($this->_repeat);
if (count($this->_repeat))
{
continue;
}
$k=array_pop($this->_coms);
if (($k=="REPEAT"))
{
if (count($this->_repeatT)==0)
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_NO_REPEAT_TIME);
}
$lastRT=array_pop($this->_repeatT);
for ($tt=0;$tt<round($lastRT);$tt++)
{
$t=$this->_parse(&$s, $groupstart+1, $i);
if ($t!=LOGO_OK) break;
}
if ($t==LOGO_OK_PROC_RETURN)
{
if ($this->_rlvl==0)
{
$this->_rlvl=1;
return ($t);
}
continue;
}
if (($t==LOGO_OK))
continue;
else
return ($t);
}
else
if ($k=="IF")
{
if (count($this->_repeatT)==0)
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_BOOLEAN);
}
$lastRT=array_pop($this->_repeatT);
if ($lastRT>0)
{
$lastRT=1;
}
else
{
$lastRT=0;
}
for ($tt=0;$tt<round($lastRT);$tt++)
{
$t=$this->_parse(&$s, $groupstart+1, $i);
if ($t!=LOGO_OK) break;
}
if ($t==LOGO_OK_PROC_RETURN)
{
if ($this->_rlvl==0)
{
$this->_rlvl=1;
return ($t);
}
continue;
}
if (($t==LOGO_OK))
continue;
else
return ($t);
}
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_UNSUPPORTED_GROUP_ACTION);
}
/* Skip parsing until complete group statement */
if (count($this->_repeat))
{
continue;
}
} // Not _inProc
/* Get a word */
$w=(strtoupper($this->getNextWord(&$s, $i, $U, &$j)));
if (strlen($w)==0)
{
break;
}
if ($this->_inProc)
{
if ($w=="TO")
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_NESTED_PROCEDURE_NOT_ALLOWED);
}
else
if ($w=="END")
{
$this->_inProc=false;
array_push($this->_to_end,$i);
$i=$j;
$this->_to_counting_args=false;
continue;
}
else
{
if ($this->_to_counting_args)
{
if (($w{0}==":")&&($this->isGood(substr($w,1))))
{
if (count($this->_to_args)==0)
{
array_push($this->_to_args, new Storage());
}
if ($this->_to_args[count($this->_to_args)-1]->isVar(substr($w,1)))
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_REPEAT_PROC_ARG);
}
else
{
$this->_to_args[count($this->_to_args)-1]->_setVar(substr($w,1), 0);
}
}
else
{
$this->_to_counting_args=false;
}
}
$i=$j;
continue;
}
} // Not _inProc
else
{
if ($w=="END")
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_NO_TO);
}
}
/*
if (count($this->_repeatT)>0)
{
if (($w=="REPEAT")||($w=="IF"))
{
array_push($this->_repeatT,-1);
}
$i=$j;
continue;
}
*/
if (count($this->_coms)>0)
{
$k=array_pop($this->_coms);
if ($k=="TO")
{
if ( in_array($w, $this->_keywords) ||
in_array($w, $this->_keywords_args) )
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_KEYWORD_IN_USE);
}
if ( in_array($w, $this->_to_names))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_PROC_DEFINED);
}
if (!$this->isSymbol($w))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_INVALID_SYMBOL);
}
if (count($this->_to_names)+1>$this->_maxProc)
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_TOO_MANY_PROC);
}
$this->_inProc=true;
array_push($this->_to_names, $w);
array_push($this->_to_start, $i+strlen($w));
$this->_to_counting_args=true;
array_push($this->_to_args, new Storage());
$i=$j;
continue;
}
array_push($this->_coms, $k);
}
// Commands with at least one arg
if (in_array($w, $this->_keywords_args))
{
if (count($this->_coms)>0)
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
array_push($this->_coms, $w);
$i=$j;
continue;
}
if (in_array($w, $this->_to_names))
{
$procpos=array_search($w, $this->_to_names);
$argnum=$this->_to_args[$procpos]->getSize();
if ($argnum>0)
{
array_push($this->_coms, $w);
$i=$j;
continue;
}
/* Procedure with no arguments */
array_push($this->_runningProc, $w);
if (count($this->_runningProc)>$this->_maxProcLevel)
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_TOO_MANY_LEVELS);
}
array_push($this->_var_stack, $this->_to_args[$procpos]);
$this->removeLocalVars();
$ret=$this->_parse($s, $this->_to_start[$procpos], $this->_to_end[$procpos]);
$this->_to_args[$procpos]=array_pop($this->_var_stack);
array_pop($this->_runningProc);
/*if ($ret==LOGO_OK_PROC_RETURN)
{
if ($this->_rlvl==0)
{
$this->_rlvl=1;
return ($ret);
}
$i=$j;
continue;
}*/
if (($ret==LOGO_OK)||($ret==LOGO_OK_PROC_RETURN))
{
$i=$j;
continue;
}
else
{
return ($ret);
}
}
// Commands with no args
if (in_array($w, $this->_keywords))
{
if ($w=="STOP")
{
if (($this->_inProc)||(count($this->_runningProc)))
{
$this->_rlvl=0;
return (LOGO_OK_PROC_RETURN);
}
else
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_STOP_NOT_IN_PROC);
}
}
if (($w=="PU")||($w=="PENUP"))
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->pu();
$i=$j;
continue;
}
if (($w=="PD")||($w=="PENDOWN"))
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->pd();
$i=$j;
continue;
}
if (($w=="ST")||($w=="SHOWTURTLE"))
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->st();
$i=$j;
continue;
}
if ($w=="FILL")
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->fill();
$i=$j;
continue;
}
if ($w=="HOME")
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->home();
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
$this->_vars->_setVar("DEGREE", $this->_logo->getD());
$i=$j;
continue;
}
if (($w=="HT")||($w=="HIDETURTLE"))
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->ht();
$i=$j;
continue;
}
if (($w=="WINDOW"))
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->setWrap(LOGO_WINDOW);
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
$this->_vars->_setVar("DEGREE", $this->_logo->getD());
$i=$j;
continue;
}
if (($w=="FENCE"))
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->setWrap(LOGO_FENCE);
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
$this->_vars->_setVar("DEGREE", $this->_logo->getD());
$i=$j;
continue;
}
if (($w=="WRAP"))
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->setWrap(LOGO_WRAP);
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
$this->_vars->_setVar("DEGREE", $this->_logo->getD());
$i=$j;
continue;
}
if (($w=="CS")||($w=="CLEANSCREEN"))
{
if (count($this->_coms))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
$this->_logo->cs();
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_NOT_FULLY_IMPLEMENTED,
$this->_lineX,
$this->_lineY,
$w
);
$i=$j;
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
$this->_vars->_setVar("DEGREE", $this->_logo->getD());
continue;
}
} // end of Commands with no args
if (count($this->_coms))
{
$k=array_pop($this->_coms);
if ($k=="LOCAL")
{
if (($w{0}!='"'))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MAKE_NEED_QUOTE);
}
if (!$this->isGood(substr($w,1)))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MAKE_INVALID_NAME);
}
if (!(($this->_inProc)||(count($this->_runningProc))))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_LOCAL_MAKE_GLOBALUSE,
$this->_lineX,
$this->_lineY,
$w
);
}
else
{
array_push($this->_localmake, array($this->_runningProc[count($this->_runningProc)-1],substr($w,1)));
}
$i=$j;
continue;
}
else
if (($k=="MAKE")||($k=="LOCALMAKE"))
{
if (count($this->_args)==0)
{
if (($w{0}!='"'))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MAKE_NEED_QUOTE);
}
if (!$this->isGood(substr($w,1)))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MAKE_INVALID_NAME);
}
array_push($this->_coms, $k);
array_push($this->_args, substr($w,1));
$i=$j;
continue;
}
else
{
$t=array_pop($this->_args);
if ($w{0}=="\"")
{
if ($k=="MAKE")
{
$this->_makevars->_setVar($t, substr($w,1));
$i=$j;
continue;
}
else
{
if (!(($this->_inProc)||(count($this->_runningProc))))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_LOCAL_MAKE_GLOBALUSE,
$this->_lineX,
$this->_lineY,
$w
);
$this->_makevars->_setVar($t, substr($w,1));
$i=$j;
continue;
}
else
{
array_push($this->_localmake, array(
$this->_runningProc[count($this->_runningProc)-1],
$t
));
$procpos=array_search($this->_runningProc[count($this->_runningProc)-1], $this->_to_names);
$this->_to_args[$procpos]->_setVar($t, substr($w,1));
$i=$j;
continue;
}
}
}
else
{
if ($this->isNumber($w, &$_real, &$value))
{
if ($k=="MAKE")
{
$this->_makevars->_setVar($t, $value);
$i=$j;
continue;
}
else
{
if (!(($this->_inProc)||(count($this->_runningProc))))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_LOCAL_MAKE_GLOBALUSE,
$this->_lineX,
$this->_lineY,
$w
);
$this->_makevars->_setVar($t, $value);
$i=$j;
continue;
}
else
{
array_push($this->_localmake, array(
$this->_runningProc[count($this->_runningProc)-1],
$t
));
$procpos=array_search($this->_runningProc[count($this->_runningProc)-1], $this->_to_names);
$this->_to_args[$procpos]->_setVar($t, $value);
$i=$j;
continue;
}
}
}
else
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MAKE_INVALID_VALUE);
}
}
}
}// end of make, local make
array_push($this->_coms, $k);
}
if ($this->isNumber($w,&$realnum,&$value))
{
if (count($this->_coms)==0)
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_COMMAND);
}
/*
if ($realnum)
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_NUMBER_ROUNDED,
$this->_lineX,
$this->_lineY,
$w
);
}
*/
$k=array_pop($this->_coms);
if (in_array($k, $this->_to_names))
{
$procpos=array_search($k, $this->_to_names);
$argnum=$this->_to_args[$procpos]->getSize();
if ($argnum>count($this->_args)+1)
{
array_push($this->_coms, $k);
array_push($this->_args, $w);
$i=$j;
continue;
}
array_push($this->_args, $w);
$u=0;
array_push($this->_var_stack, $this->_to_args[$procpos]);
$this->removeLocalVars();
$varlist=$this->_to_args[$procpos]->keys();
foreach ($varlist as $key)
{
$this->isNumber($this->_args[$u++],&$real, &$value);
$this->_to_args[$procpos]->_setVar($key,$value);
}
$usa=$this->_to_start[$procpos]+1;
for ($sk=0;$sk<$argnum;$sk++)
{
$t=$this->getNextWord(&$s, $usa, $this->_to_end[$procpos], &$usa);
$usa++;
}
array_push($this->_runningProc, $k);
if (count($this->_runningProc)>$this->_maxProcLevel)
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_TOO_MANY_LEVELS);
}
for (; $u>0; $u--)
{
array_pop($this->_args);
}
$ret=$this->_parse($s, $usa, $this->_to_end[$procpos]);
$this->_to_args[$procpos]=array_pop($this->_var_stack);
array_pop($this->_runningProc);
/* if ($ret==LOGO_OK_PROC_RETURN)
{
if ($this->_rlvl==0)
{
$this->_rlvl=1;
return ($ret);
}
$i=$j;
continue;
} */
if (($ret==LOGO_OK)||($ret==LOGO_OK_PROC_RETURN))
{
$i=$j;
continue;
}
else
{
return ($ret);
}
}
else
if (($k=="FD")||($k=="FORWARD"))
{
if ($this->_logo->isWrap()==LOGO_FENCE)
{
$x1=$this->_logo->getX();
$y1=$this->_logo->getY();
$x2=round($x1+$value*sin($this->_logo->getD()*pi()/180));
$y2=round($y1-$value*cos($this->_logo->getD()*pi()/180));
if ($this->_logo->isOutXY($x2,$y2))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_TURTLE_OUT,
$this->_lineX,
$this->_lineY,
$w
);
}
}
$this->_logo->fd($value);
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
}
else
if (($k=="BK")||($k=="BACK"))
{
if ($this->_logo->isWrap()==LOGO_FENCE)
{
$x1=$this->_logo->getX();
$y1=$this->_logo->getY();
$x2=round($x1+$value*sin($this->_logo->getD()*pi()/180));
$y2=round($y1-$value*cos($this->_logo->getD()*pi()/180));
if ($this->_logo->isOutXY($x2,$y2))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_TURTLE_OUT,
$this->_lineX,
$this->_lineY,
$w
);
}
}
$this->_logo->bk($value);
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
}
else
if (($k=="RT")||($k=="RIGHT"))
{
$this->_logo->rt($value);
$this->_vars->_setVar("DEGREE", $this->_logo->getD());
}
else
if (($k=="LT")||($k=="LEFT"))
{
$this->_logo->lt($value);
$this->_vars->_setVar("DEGREE", $this->_logo->getD());
}
else
if (($k=="SETPC")||($k=="SETPENCOLOR")||($k=="SETPENCOLOUR"))
{
$value=(integer)$value;
if (($value>=0)&&($value<=15))
{
$this->_logo->setPCrgb($this->Logo_Color_R[$value],
$this->Logo_Color_G[$value],
$this->Logo_Color_B[$value]);
}
else
{
$this->_logo->setPC($value);
}
$this->_vars->_setVar("PENCOLOR",$value);
$this->_vars->_setVar("PENCOLOUR",$value);
}
else
if (($k=="SETFC")||($k=="SETFLOODCOLOR")||($k=="SETFLOODCOLOUR"))
{
$value=(integer)$value;
if (($value>=0)&&($value<=15))
{
$this->_logo->setFCrgb($this->Logo_Color_R[$value],
$this->Logo_Color_G[$value],
$this->Logo_Color_B[$value]);
}
else
{
$this->_logo->setFC($value);
}
$this->_vars->_setVar("FLOODCOLOR",$value);
$this->_vars->_setVar("FLOODCOLOUR",$value);
}
else
if (($k=="SETSC")||($k=="SETSCREENCOLOR")||($k=="SETSCREENCOLOUR"))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_UNSUPPORTED_BG_CHANGE,
$this->_lineX,
$this->_lineY,
$w
);
if (($value>=0)&&($value<=15))
{
$this->_logo->setSCrgb($this->Logo_Color_R[$value],
$this->Logo_Color_G[$value],
$this->Logo_Color_B[$value]);
}
else
{
$this->_logo->setSC($value);
}
$this->_vars->_setVar("SCREENCOLOR",$value);
$this->_vars->_setVar("SCREENCOLOUR",$value);
}
else
if (($k=="REPEAT")||($k=="IF"))
{
array_push($this->_repeatT, round($value));
array_push($this->_coms, $k);
}
else
if (($k=="SETXY")||($k=="SETPOS"))
{
if (count($this->_args)==0)
{
array_push($this->_coms, $k);
array_push($this->_args, $value);
}
else
{
$t=array_pop($this->_args);
$this->_logo->lineTo($t, -$value, true);
if ($this->_logo->isWrap()==LOGO_FENCE)
{
if ($this->_logo->isOutXY($t, -$value))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_TURTLE_OUT,
$this->_lineX,
$this->_lineY,
$w
);
}
}
}
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
}
else
if (($k=="ARC"))
{
if (count($this->_args)==0)
{
array_push($this->_coms, $k);
array_push($this->_args, $value);
}
else
{
$t=array_pop($this->_args);
$this->_logo->arc($t, $value);
}
}
else
if ($k=="SETX")
{
$this->_logo->lineTo($value, $this->_logo->getY(), true);
if ($this->_logo->isWrap()==LOGO_FENCE)
{
if (($value>$this->_logo->getImageHX())||($value<-$this->_logo->getImageHX()))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_TURTLE_OUT,
$this->_lineX,
$this->_lineY,
$w
);
}
}
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
}
else
if ($k=="SETY")
{
$this->_logo->lineTo($this->_logo->getX(), -$value, true);
if ($this->_logo->isWrap()==LOGO_FENCE)
{
if ((-$value>$this->_logo->getImageHY())||(-$value<-$this->_logo->getImageHY()))
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_TURTLE_OUT,
$this->_lineX,
$this->_lineY,
$w
);
}
}
$this->_vars->_setVar("POSX", $this->_logo->getX());
$this->_vars->_setVar("POSY", $this->_logo->getY());
}
else
if ($k=="TO")
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_INVALID_PROC_NAME);
}
else
if (in_array($w, $this->_to_names))
{
$procpos=array_search($w, $this->_to_names);
$argnum=$this->_to_args[$procpos]->getSize();
if ($argnum>0)
{
array_push($this->_coms, $w);
$i=$j;
continue;
}
array_push($this->_runningProc, $w);
if (count($this->_runningProc)>$this->_maxProcLevel)
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_TOO_MANY_LEVELS);
}
array_push($this->_var_stack, $this->_to_args[$procpos]);
$this->removeLocalVars();
$ret=$this->_parse($s, $this->_to_start[$procpos], $this->_to_end[$procpos]);
$this->_to_args[$procpos]=array_pop($this->_var_stack);
array_pop($this->_runningProc);
/* if ($ret==LOGO_OK_PROC_RETURN)
{
if ($this->_rlvl==0)
{
$this->_rlvl=1;
return ($ret);
}
$i=$j;
continue;
}*/
if (($ret==LOGO_OK)||($ret==LOGO_OK_PROC_RETURN))
{
$i=$j;
continue;
}
else
{
return ($ret);
}
}
$i=$j;
continue;
} // end of isNumber
/* The word is Not Recongized */
if ($w)
{
$this->_getXY(&$s, $i, $w);
$this->_src_line=__LINE__;
return (LOGO_ERROR_BAD_COMMAND);
}
}// end of processing
/* Error Handling */
$this->_getXY(&$s, $U);
if ($this->_inProc)
{
$this->_src_line=__LINE__;
return (LOGO_ERROR_END_NOT_FOUND);
}
else
if (count($this->_repeat))
{
$this->_src_line=__LINE__;
return (LOGO_ERROR_TOO_MANY_LEFT);
}
else
if (count($this->_repeatT))
{
$this->_getXY(&$s, $i);
$this->_src_line=__LINE__;
$this->pushWarn( LOGO_WARNING_MISSING_REPEAT_BODY,
$this->_lineX,
$this->_lineY,
"");
}
else
if (count($this->_coms))
{
$this->_src_line=__LINE__;
return (LOGO_ERROR_MISSING_ARG);
}
// Return OK
return (LOGO_OK);
}
function parse($s="")
{
$this->_runningT=microtime();
if (strlen($s))
{
$t=($this->_parse(&$s));
}
else
{
$t=($this->_parse(&$this->_s));
}
$this->_logo->drawTurtle();
return ($t);
}
}
?>