2563 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			2563 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			PHP
		
	
	
	
<?
 | 
						|
function author()
 | 
						|
{
 | 
						|
?>
 | 
						|
<HR>
 | 
						|
 | 
						|
By Marko Riedel, 
 | 
						|
<A HREF=mailto:mriedel@neuearbeit.de>
 | 
						|
mriedel@neuearbeit.de</A>,
 | 
						|
<A HREF=http://www.geocities.com/markoriedelde/index.html TARGET=_top>
 | 
						|
http://www.geocities.com/markoriedelde/index.html.</A>
 | 
						|
<?
 | 
						|
}
 | 
						|
 | 
						|
session_start();
 | 
						|
 | 
						|
session_register("images");
 | 
						|
 | 
						|
if(empty($images)){
 | 
						|
    $images = array();
 | 
						|
}
 | 
						|
 | 
						|
if(isset($genImage)){
 | 
						|
    if(empty($images[$genImage])){
 | 
						|
	exit;
 | 
						|
    }
 | 
						|
 | 
						|
    $imagedata = $images[$genImage];
 | 
						|
 | 
						|
    Header("Content-type: image/jpeg");
 | 
						|
    
 | 
						|
    $offsx = -(int)$imagedata[0]+3;
 | 
						|
    $offsy = -(int)$imagedata[1]+3;
 | 
						|
 | 
						|
    $dimx   = (int)($imagedata[2]-$imagedata[0])+6;
 | 
						|
    $dimy   = (int)($imagedata[3]-$imagedata[1])+6;
 | 
						|
 | 
						|
    $im    = ImageCreate($dimx, $dimy);
 | 
						|
    $black = ImageColorAllocate($im, 0, 0, 0);
 | 
						|
    $white = ImageColorAllocate($im, 255, 255, 255);
 | 
						|
    ImageFill($im, 0, 0, $white);
 | 
						|
 | 
						|
    $currentx   = -$offsx;
 | 
						|
    $currenty   = -$offsy;
 | 
						|
    $currentcol = $black;
 | 
						|
 | 
						|
    for($ind=0, $data=$imagedata[4]; $ind<count($data); $ind++){
 | 
						|
	$cmd = $data[$ind];
 | 
						|
 | 
						|
	if($cmd[0]==2){
 | 
						|
	    $currentcol = 
 | 
						|
		 ImageColorAllocate($im, $cmd[1], $cmd[2], $cmd[3]); 
 | 
						|
	}
 | 
						|
	else{
 | 
						|
	    if($cmd[0]==1){
 | 
						|
		ImageLine($im, $currentx+$offsx, $dimy-($currenty+$offsy), 
 | 
						|
		          $cmd[1]+$offsx, $dimy-($cmd[2]+$offsy), 
 | 
						|
		          $currentcol);
 | 
						|
 | 
						|
	    }
 | 
						|
	    $currentx = $cmd[1];
 | 
						|
	    $currenty = $cmd[2];
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    ImageJPEG($im);
 | 
						|
    ImageDestroy($im);
 | 
						|
 | 
						|
    exit;
 | 
						|
}
 | 
						|
 | 
						|
function tokenize($text)
 | 
						|
{
 | 
						|
    global $tokens, $base;
 | 
						|
 | 
						|
    $tokens=array(); $base=0;
 | 
						|
    $lines=explode("\n", $text);
 | 
						|
 | 
						|
    for($lind=0; $lind<count($lines); $lind++){
 | 
						|
	if(preg_match("/^([^;]*);/", $lines[$lind], $parts)){
 | 
						|
	    $lines[$lind]=$parts[1];
 | 
						|
	}
 | 
						|
	for($current=$lines[$lind], $ltokens=array(); 
 | 
						|
	     preg_match("/([^\"]*)\"([^\"]*)\"(.*)$/", 
 | 
						|
			$current, $parts);
 | 
						|
	    $current=$parts[3]){
 | 
						|
	    if(strlen($parts[1])>0){
 | 
						|
		$ltokens[]=$parts[1];
 | 
						|
	    }
 | 
						|
	    $ltokens[]=array('string', $parts[2]);
 | 
						|
	}
 | 
						|
	if(strlen($current)){
 | 
						|
	    $ltokens[]=$current;
 | 
						|
	}
 | 
						|
 | 
						|
	for($tok=0; $tok<count($ltokens); $tok++){
 | 
						|
	    if(is_array($ltokens[$tok])){
 | 
						|
		$tokens[] = $ltokens[$tok];
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		for($tok1=0, $nosp=preg_split("/\s+/", $ltokens[$tok]);
 | 
						|
		    $tok1<count($nosp); $tok1++){
 | 
						|
		    for($current=$nosp[$tok1]; 
 | 
						|
			preg_match("/([^\(\)\']*)(\(|\)|\')(.*)$/", 
 | 
						|
				   $current, $parts);
 | 
						|
			$current=$parts[3]){
 | 
						|
			if(strlen($parts[1])>0){
 | 
						|
			    $tokens[]=array('text', $parts[1]);
 | 
						|
			}
 | 
						|
			if($parts[2]=='('){
 | 
						|
			    $tokens[]=array('left');
 | 
						|
			}
 | 
						|
			else if($parts[2]==')'){
 | 
						|
			    $tokens[]=array('right');
 | 
						|
			}
 | 
						|
			else{
 | 
						|
			    $tokens[]=array('quote');
 | 
						|
			}
 | 
						|
		    }
 | 
						|
		    if(strlen($current)){
 | 
						|
			$tokens[]=array('text', $current);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
$envindex = 0;
 | 
						|
$environments = array();
 | 
						|
 | 
						|
function newenv($table)
 | 
						|
{
 | 
						|
  global $envindex, $environments;
 | 
						|
 | 
						|
  $environments[$envindex++] = $table;
 | 
						|
  return ($envindex-1);
 | 
						|
}
 | 
						|
 | 
						|
function writetoenv($tag, $sym, $val)
 | 
						|
{
 | 
						|
  global $environments;
 | 
						|
 | 
						|
  $environments[$tag][$sym] = $val;
 | 
						|
}
 | 
						|
 | 
						|
function readfromenv($tag, $sym)
 | 
						|
{
 | 
						|
  global $environments;
 | 
						|
 | 
						|
  $val = $environments[$tag][$sym];
 | 
						|
  if(isset($val)){
 | 
						|
    return $val;
 | 
						|
  }
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
function newval($type, $val)
 | 
						|
{
 | 
						|
  return array($type, $val);
 | 
						|
}
 | 
						|
 | 
						|
function valtype($v)
 | 
						|
{
 | 
						|
  return $v[0];
 | 
						|
}
 | 
						|
 | 
						|
function valdata($v)
 | 
						|
{
 | 
						|
  return $v[1];
 | 
						|
}
 | 
						|
 | 
						|
$thunkindex = 0;
 | 
						|
$thunks = array();
 | 
						|
 | 
						|
function newthunk()
 | 
						|
{
 | 
						|
  global $thunkindex, $thunks;
 | 
						|
 | 
						|
  $thunks[$thunkindex++] = array(-1, -1);
 | 
						|
  return array('thunk', $thunkindex-1);
 | 
						|
}
 | 
						|
 | 
						|
function writeargptothunk($t, $argp)
 | 
						|
{
 | 
						|
  global $thunks;
 | 
						|
  $thunks[$t[1]][0] = $argp;
 | 
						|
}
 | 
						|
 | 
						|
function readargpfromthunk($t)
 | 
						|
{
 | 
						|
  global $thunks;
 | 
						|
  return $thunks[$t[1]][0];
 | 
						|
}
 | 
						|
 | 
						|
function writeenvptothunk($t, $envp)
 | 
						|
{
 | 
						|
  global $thunks;
 | 
						|
  $thunks[$t[1]][1] = $envp;
 | 
						|
}
 | 
						|
 | 
						|
function readenvpfromthunk($t)
 | 
						|
{
 | 
						|
  global $thunks;
 | 
						|
  return $thunks[$t[1]][1];
 | 
						|
}
 | 
						|
 | 
						|
$closureindex = 0;
 | 
						|
$closures = array();
 | 
						|
 | 
						|
function newclosure($args, $code, $argtype, $env)
 | 
						|
{
 | 
						|
  global $closureindex, $closures;
 | 
						|
 | 
						|
  $closures[$closureindex++] = array($args, $code, $argtype, $env);
 | 
						|
  return array('closure', $closureindex-1);
 | 
						|
}
 | 
						|
 | 
						|
function closuretag($c)
 | 
						|
{
 | 
						|
  return $c[1];
 | 
						|
}
 | 
						|
 | 
						|
function closureargs($c)
 | 
						|
{
 | 
						|
  global $closures;
 | 
						|
  return $closures[$c[1]][0];
 | 
						|
}
 | 
						|
 | 
						|
function closurebody($c)
 | 
						|
{
 | 
						|
  global $closures;
 | 
						|
  return $closures[$c[1]][1];
 | 
						|
}
 | 
						|
 | 
						|
function closureargtype($c)
 | 
						|
{
 | 
						|
  global $closures;
 | 
						|
  return $closures[$c[1]][2];
 | 
						|
}
 | 
						|
 | 
						|
function closureenv($c)
 | 
						|
{
 | 
						|
  global $closures;
 | 
						|
  return $closures[$c[1]][3];
 | 
						|
}
 | 
						|
 | 
						|
$pairindex = 0;
 | 
						|
$pairs = array();
 | 
						|
 | 
						|
function cons($a, $b)
 | 
						|
{
 | 
						|
  global $pairindex, $pairs;
 | 
						|
  
 | 
						|
  $pairs[$pairindex++] = array($a, $b);
 | 
						|
  return array('pair', $pairindex-1);
 | 
						|
}
 | 
						|
 | 
						|
function car($p)
 | 
						|
{
 | 
						|
  global $pairs;
 | 
						|
  return $pairs[$p[1]][0];
 | 
						|
}
 | 
						|
 | 
						|
function cdr($p)
 | 
						|
{
 | 
						|
  global $pairs;
 | 
						|
  return $pairs[$p[1]][1];
 | 
						|
}
 | 
						|
 | 
						|
function setcar($p, $v)
 | 
						|
{
 | 
						|
  global $pairs;
 | 
						|
  $pairs[$p[1]][0] = $v;
 | 
						|
}
 | 
						|
 | 
						|
function setcdr($p, $v)
 | 
						|
{
 | 
						|
  global $pairs;
 | 
						|
  $pairs[$p[1]][1] = $v;
 | 
						|
}
 | 
						|
 | 
						|
$nullunique = array('empty');
 | 
						|
function null()
 | 
						|
{
 | 
						|
    global $nullunique;
 | 
						|
    return $nullunique;
 | 
						|
}
 | 
						|
 | 
						|
function array2list($items)
 | 
						|
{
 | 
						|
    $res = null();
 | 
						|
 | 
						|
    for($p=count($items)-1; $p>=0; $p--){
 | 
						|
	$res = cons($items[$p], $res);
 | 
						|
    }
 | 
						|
 | 
						|
    return $res;
 | 
						|
}
 | 
						|
 | 
						|
function btrue()
 | 
						|
{
 | 
						|
  return newval('boolean', '#t');
 | 
						|
}
 | 
						|
 | 
						|
function bfalse()
 | 
						|
{
 | 
						|
  return newval('boolean', '#f');
 | 
						|
}
 | 
						|
 | 
						|
function isfalse($val)
 | 
						|
{
 | 
						|
  if($val[0]=='empty' ||
 | 
						|
     ($val[0]=='boolean' && $val[1]=='#f')){
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
function readexp()
 | 
						|
{
 | 
						|
    global $tokens, $base, $errmsg;
 | 
						|
 | 
						|
    while(isset($tokens[$base])){
 | 
						|
	$tok = $tokens[$base++];
 | 
						|
	
 | 
						|
	if($tok[0]=='string'){
 | 
						|
	    return $tok;
 | 
						|
	}
 | 
						|
 | 
						|
	if($tok[0]=='text'){
 | 
						|
	    if(preg_match("/^[+-]?\d+(\.\d+)?([eE][+-]?\d+)?$/", $tok[1]) ||
 | 
						|
	       preg_match("/^[+-]?\d+$/", $tok[1])){
 | 
						|
		return newval('number', $tok[1]);
 | 
						|
	    }
 | 
						|
 | 
						|
	    if(preg_match("/^[\+\-\*\/\=\>\<]|<=|>=$/", $tok[1]) ||
 | 
						|
	       preg_match("/^[a-zA-Z\?][a-zA-Z0-9\-\?\!\*]*$/", $tok[1])){
 | 
						|
		return newval('symbol', $tok[1]);
 | 
						|
	    }
 | 
						|
	    
 | 
						|
	    if(preg_match("/^\#[tf]$/", $tok[1])){
 | 
						|
		return newval('boolean', $tok[1]);
 | 
						|
	    }
 | 
						|
 | 
						|
	    if(preg_match("/^\#\\\\(\w+|\.|\,|\+|\-|\*|\/)$/", 
 | 
						|
			  $tok[1], $parts)){
 | 
						|
	        return newval('character', $parts[1]);
 | 
						|
	    }
 | 
						|
 | 
						|
	    if($tok[1]=='.'){
 | 
						|
		return newval('improper', $tok[1]);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	else if($tok[0]=='quote'){
 | 
						|
	    $quoted = readexp();
 | 
						|
	    if(is_array($quoted)){
 | 
						|
		return cons(newval('symbol', 'quote'), cons($quoted, null()));
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		$errmsg = 'quote missing an item';
 | 
						|
		return -1;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	else if($tok[0]=='left'){
 | 
						|
	    $items = array(); $isimproper = 0;
 | 
						|
	    while(isset($tokens[$base]) &&
 | 
						|
		  $tokens[$base][0]!='right'){
 | 
						|
		$item = readexp();
 | 
						|
		if(is_array($item)){
 | 
						|
		    if($item[0]=='improper'){
 | 
						|
			$isimproper = 1;
 | 
						|
			break;
 | 
						|
		    }
 | 
						|
		    else{
 | 
						|
			$items[] = $item;
 | 
						|
		    }
 | 
						|
		}
 | 
						|
		else{
 | 
						|
		    return -1;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    if(!isset($tokens[$base])){
 | 
						|
		$errmsg = 'ran out of list items';
 | 
						|
		return -1;
 | 
						|
	    }
 | 
						|
	    if($isimproper){
 | 
						|
		$item = readexp();
 | 
						|
		if(is_array($item)){
 | 
						|
		    if(!isset($tokens[$base])){
 | 
						|
			$errmsg = 'improper list missing closing parenthesis';
 | 
						|
			return -1;
 | 
						|
		    }
 | 
						|
		    if($tokens[$base][0]!='right'){
 | 
						|
			$errmsg = 'improper list not closed by parenthesis';
 | 
						|
			return -1;
 | 
						|
		    }
 | 
						|
		    $base++;
 | 
						|
 | 
						|
		    $result = $item;
 | 
						|
		}
 | 
						|
		else{
 | 
						|
		    $errmsg = 'improper list missing last item';
 | 
						|
		    return -1;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		$base++;
 | 
						|
		$result = null();
 | 
						|
	    }
 | 
						|
 | 
						|
	    for($ind=count($items)-1; $ind>=0; $ind--){
 | 
						|
		$result = cons($items[$ind], $result);
 | 
						|
	    }
 | 
						|
 | 
						|
	    return $result;
 | 
						|
	}
 | 
						|
	else if($tok[0]=='right'){
 | 
						|
	    $errmsg = 'missing open parenthesis';
 | 
						|
	    return -1;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    $errmsg = 'parse error';
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
$chartable = array();
 | 
						|
$chartable["newline"] = "\n";
 | 
						|
$chartable["tab"]     = "\t";
 | 
						|
$chartable["space"]   = " ";
 | 
						|
 | 
						|
function tostring($exp, $expchars)
 | 
						|
{
 | 
						|
    global $chartable;
 | 
						|
 | 
						|
    if(valtype($exp)=='pair'){
 | 
						|
	$result  = '(';
 | 
						|
	$result .= tostring(car($exp), $expchars);
 | 
						|
	
 | 
						|
	for($rest=cdr($exp); valtype($rest)=='pair'; $rest=cdr($rest)){
 | 
						|
	  $result .= ' ' . tostring(car($rest), $expchars);
 | 
						|
	}
 | 
						|
	if(valtype($rest)!='empty'){
 | 
						|
	    $result .= ' . ' . tostring($rest, $expchars);
 | 
						|
	}
 | 
						|
 | 
						|
	$result .= ')';
 | 
						|
 | 
						|
	return $result;
 | 
						|
    }
 | 
						|
    else if(valtype($exp)=='empty'){
 | 
						|
	return '()';
 | 
						|
    }
 | 
						|
    else if(valtype($exp)=='closure'){
 | 
						|
	return '<closure: ' . 
 | 
						|
	  tostring(closureargs($exp), 'noexpchars') . '>';
 | 
						|
    }
 | 
						|
    else if(valtype($exp)=='bcode'){
 | 
						|
        return '<byte codes: ' . count(valdata($exp)) . '>';
 | 
						|
    }
 | 
						|
    else if(valtype($exp)=='thunk'){
 | 
						|
        return '<thunk: #' . valdata($exp) . '>';
 | 
						|
    }
 | 
						|
    else if(valtype($exp)=='primitive'){
 | 
						|
	return '<primitive: ' . valdata($exp) . '>';
 | 
						|
    }
 | 
						|
    else if(valtype($exp)=='string'){
 | 
						|
	if($expchars=='expchars'){
 | 
						|
	    return valdata($exp);
 | 
						|
	}
 | 
						|
	return '"' . valdata($exp) . '"';
 | 
						|
    }
 | 
						|
    else if(valtype($exp)=='character'){
 | 
						|
	if($expchars=='expchars'){
 | 
						|
	    $expanded = $chartable[valdata($exp)];
 | 
						|
	    if(!empty($expanded)){
 | 
						|
		return $expanded;
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
	      $str = valdata($exp);
 | 
						|
	      return $str[0];
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	else{
 | 
						|
	    return "#\\" . valdata($exp);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else{
 | 
						|
	return valdata($exp);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
function tohtmlstring($exp, $expchars)
 | 
						|
{
 | 
						|
  return htmlspecialchars(tostring($exp, $expchars));
 | 
						|
}
 | 
						|
 | 
						|
function tostring2($exp, $depth)
 | 
						|
{
 | 
						|
    if(valtype($exp)=='pair'){
 | 
						|
        if(!$depth){
 | 
						|
	  return '...';
 | 
						|
	}
 | 
						|
 | 
						|
	$result  = '(';
 | 
						|
	$result .= tostring2(car($exp), $depth-1);
 | 
						|
	
 | 
						|
	for($rest=cdr($exp); $rest[0]=='pair'; $rest=cdr($rest)){
 | 
						|
	  $result .= ' ' . tostring2(car($rest), $depth-1);
 | 
						|
	}
 | 
						|
	if($rest[0]!='empty'){
 | 
						|
	    $result .= ' . ' . tostring($rest, 'noexpchars');
 | 
						|
	}
 | 
						|
 | 
						|
	$result .= ')';
 | 
						|
 | 
						|
	return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    return tostring($exp, 'noexpchars');
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
function tohtmlstring2($exp)
 | 
						|
{
 | 
						|
  $stringdepth = 3;
 | 
						|
  return htmlspecialchars(tostring2($exp, $stringdepth));
 | 
						|
}
 | 
						|
 | 
						|
function lookup($symbol, $layers)
 | 
						|
{
 | 
						|
    if($layers[0]=='empty'){
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    $layer = car($layers);
 | 
						|
    $val   = readfromenv($layer, $symbol);
 | 
						|
    if(is_array($val)){
 | 
						|
      return array($layer, $val);
 | 
						|
    }
 | 
						|
 | 
						|
    return lookup($symbol, cdr($layers));
 | 
						|
}
 | 
						|
 | 
						|
function sequence($seq)
 | 
						|
{
 | 
						|
    global $bcode, $bc;
 | 
						|
 | 
						|
    $count=0;
 | 
						|
    while(valtype($seq)=='pair'){
 | 
						|
      compile(car($seq));
 | 
						|
      $seq=cdr($seq);
 | 
						|
      if(valtype($seq)=='pair'){
 | 
						|
	  $bcode[$bc++] = array('popargs', 1);
 | 
						|
      }
 | 
						|
      $count++;
 | 
						|
    }
 | 
						|
 | 
						|
    if($seq[0]!='empty'){
 | 
						|
      $bcode[$bc++] = array('error', 'parse error in sequence term ' . $count);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
$specialforms = array("define" => 1, "set!"  => 1, "lambda" => 1, 
 | 
						|
		      "if"     => 1, "and"   => 1, "or"     => 1,
 | 
						|
		      "begin"  => 1, "apply" => 1,
 | 
						|
		      "quote"  => 1, "case"  => 1, "cond"   => 1,
 | 
						|
                      "let"    => 1, "let*"  => 1, "letrec" => 1,
 | 
						|
		      "call-with-current-continuation" => 1);
 | 
						|
 | 
						|
function codesegment($current)
 | 
						|
{
 | 
						|
  global $bcode, $bc;
 | 
						|
	
 | 
						|
  $codeseg = array();
 | 
						|
  for($c = $current; $c<$bc; $c++){
 | 
						|
    $codeseg[] = $bcode[$c];
 | 
						|
  }
 | 
						|
  $bc = $current;
 | 
						|
 | 
						|
  return $codeseg;
 | 
						|
}
 | 
						|
 | 
						|
function handlespecial($name, $args)
 | 
						|
{
 | 
						|
    global $bcode, $bc;
 | 
						|
 | 
						|
    switch($name){
 | 
						|
        case 'apply':
 | 
						|
	if(valtype($args)!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', "bad first arg to $name");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	if(valtype(cdr($args))!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', "bad second arg to $name");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	if(valtype(cdr(cdr($args)))!='empty'){
 | 
						|
	  $bcode[$bc++] = array('error', "too many args to $name");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	compile(car($args));
 | 
						|
	$bcode[$bc++] = array('checkptc');
 | 
						|
	compile(car(cdr($args)));
 | 
						|
	$bcode[$bc++] = array('listapplication');
 | 
						|
        break;
 | 
						|
 | 
						|
        case  'call-with-current-continuation':
 | 
						|
	if(valtype($args)!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', "bad first arg to $name");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
 | 
						|
	$t = newthunk();
 | 
						|
 | 
						|
	$bcode[$bc++] = array('argptothunk', $t);
 | 
						|
	$bcode[$bc++] = array('envptothunk', $t);
 | 
						|
	compile(car($args));
 | 
						|
	$bcode[$bc++] = array('checkptc');
 | 
						|
	$bcode[$bc++] = array('toargs', $t);
 | 
						|
	$bcode[$bc++] = array('application', 1);
 | 
						|
	$bcode[$bc++] = $t;
 | 
						|
        break;
 | 
						|
 | 
						|
	case 'define': 
 | 
						|
        case 'set!':
 | 
						|
	if(valtype($args)!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', "bad first arg to $name");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	if(valtype(car($args))!='symbol'){
 | 
						|
	  $bcode[$bc++] = array('error', "first arg to $name not a symbol");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	$bcode[$bc++] = array('toargs', car($args));
 | 
						|
	if(valtype(cdr($args))!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', "bad second arg to $name");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	if($name=='define'){
 | 
						|
	  $bcode[$bc++] = array('globalenv');
 | 
						|
	  compile(car(cdr($args)));
 | 
						|
	  $bcode[$bc++] = array('popenv', 1);
 | 
						|
	}
 | 
						|
	else{
 | 
						|
	  compile(car(cdr($args)));
 | 
						|
	}
 | 
						|
	$bcode[$bc++] = array($name);
 | 
						|
	break;
 | 
						|
 | 
						|
	case 'lambda':
 | 
						|
	if(valtype($args)!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', 'bad first arg to lambda');
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	$argstr = car($args);
 | 
						|
	$argtype = -1;
 | 
						|
	if(valtype($argstr)=='symbol'){
 | 
						|
	    $argtype = 0;
 | 
						|
	}
 | 
						|
	else if(valtype($argstr)=='pair' || 
 | 
						|
		valtype($argstr)=='empty'){
 | 
						|
	    for($tocheck = $argstr, $count=1; 
 | 
						|
		valtype($tocheck)=='pair'; 
 | 
						|
		$tocheck = cdr($tocheck), $count++){
 | 
						|
		if(valtype(car($tocheck))!='symbol'){
 | 
						|
		    $msg = 'lambda arg ' . $count . ' not a symbol';
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    if(valtype($tocheck)=='symbol'){
 | 
						|
		$argtype = 1;
 | 
						|
	    }
 | 
						|
	    else if(valtype($tocheck)=='empty'){
 | 
						|
		$argtype = 2;
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		$msg = 'lambda arg not symbol or null terminator:';
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	else{
 | 
						|
	    $msg = 'lambda single arg not a symbol';
 | 
						|
	}
 | 
						|
	if($argtype==-1){
 | 
						|
	    $bcode[$bc++] = array('error', $msg);
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
 | 
						|
	if(valtype(cdr($args))=='empty'){
 | 
						|
	  $bcode[$bc++] = array('error', 'lambda body is empty');
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
 | 
						|
	$current = $bc;
 | 
						|
	sequence(cdr($args));
 | 
						|
	$lcode = codesegment($current);
 | 
						|
 | 
						|
	$bcode[$bc++] = array('toargs', car($args));  
 | 
						|
	$bcode[$bc++] = array('toargs', newval('bcode', $lcode));
 | 
						|
	$bcode[$bc++] = array('toargs', newval('number', $argtype));
 | 
						|
	$bcode[$bc++] = array('closure');
 | 
						|
	break;
 | 
						|
 | 
						|
        case 'begin':
 | 
						|
	if(valtype($args)=='empty'){
 | 
						|
	  $bcode[$bc++] = array('toargs', null());
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
 | 
						|
	sequence($args);
 | 
						|
        break;
 | 
						|
 | 
						|
	case 'cond':
 | 
						|
	for($clauses = array(), $elseclause = 0;
 | 
						|
	    valtype($args)=='pair'; $args = cdr($args)){
 | 
						|
	    $clause = car($args);
 | 
						|
 | 
						|
	    if(valtype($clause)!='pair'){
 | 
						|
		$bcode[$bc++] = array('error', 'bad cond clause');
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
	    $test  = car($clause);
 | 
						|
	    $ccode = cdr($clause);
 | 
						|
	    if(valtype($ccode)!='pair'){
 | 
						|
		$bcode[$bc++] = array('error', 'empty cond clause');
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
 | 
						|
	    if(valtype($test)=='symbol' &&
 | 
						|
	       valdata($test)=='else'){
 | 
						|
		if(is_array($elseclause)){
 | 
						|
		    $bcode[$bc++] = 
 | 
						|
			 array('error', 'cond: more than one else clause');
 | 
						|
		    return;
 | 
						|
		}
 | 
						|
		$elseclause = $clause;
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		if(is_array($elseclause)){
 | 
						|
		    $bcode[$bc++] = 
 | 
						|
			 array('error', 'cond: else clause must be last');
 | 
						|
		    return;
 | 
						|
		}
 | 
						|
		$type = 'seq';
 | 
						|
		$first = car($ccode);
 | 
						|
		if(valtype($first)=='symbol' &&
 | 
						|
		   valdata($first)=='=>'){
 | 
						|
		    $expr = cdr($ccode);
 | 
						|
		    if(valtype($expr)=='empty'){
 | 
						|
			$bcode[$bc++] = 
 | 
						|
			     array('error', 'cond: empty => clause');
 | 
						|
			return;
 | 
						|
		    }
 | 
						|
		    if(valtype(cdr($expr))!='empty'){
 | 
						|
			$bcode[$bc++] = 
 | 
						|
			     array('error', 
 | 
						|
				   'cond: more than one expr in => clause');
 | 
						|
			return;
 | 
						|
		    }
 | 
						|
		    $type = 'proc';
 | 
						|
		}
 | 
						|
 | 
						|
		$clauses[] = array($clause, $type);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	
 | 
						|
	$count = 0;
 | 
						|
 | 
						|
	$current = $bc;
 | 
						|
	if(is_array($elseclause)){
 | 
						|
	    sequence(cdr($elseclause));
 | 
						|
	    $elsecode = codesegment($current);
 | 
						|
	    
 | 
						|
	    $bcode[$bc++] = array('toargs', newval('string', 'else'));
 | 
						|
	    $bcode[$bc++] = array('toargs', newval('bcode', $elsecode));
 | 
						|
	    $count+=2;
 | 
						|
	}
 | 
						|
 | 
						|
	for($c=count($clauses)-1; $c>=0; $c--){
 | 
						|
	    $clause = $clauses[$c][0];
 | 
						|
	    $type   = $clauses[$c][1];
 | 
						|
 | 
						|
	    $current = $bc;
 | 
						|
	    compile(car($clause));
 | 
						|
	    $tcode = codesegment($current);
 | 
						|
 | 
						|
	    if($type=='proc'){
 | 
						|
		compile(car(cdr(cdr($clause))));
 | 
						|
		$code = codesegment($current);
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		sequence(cdr($clause));
 | 
						|
		$code = codesegment($current);
 | 
						|
	    }
 | 
						|
	    
 | 
						|
	    $bcode[$bc++] = array('toargs', newval('bcode', $tcode));
 | 
						|
	    $bcode[$bc++] = array('toargs', newval('string', $type));
 | 
						|
	    $bcode[$bc++] = array('toargs', newval('bcode', $code));
 | 
						|
	    $count+=3;
 | 
						|
	}
 | 
						|
 | 
						|
	$bcode[$bc++] = array('cond', $count);
 | 
						|
	break;
 | 
						|
	
 | 
						|
	case 'case':
 | 
						|
	if(valtype($args)!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', 'case value missing');
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	$caseval = car($args);
 | 
						|
	compile($caseval);
 | 
						|
 | 
						|
	for($clauses = array(), $elseclause = 0, 
 | 
						|
		$count=0, $cl = cdr($args);
 | 
						|
	    valtype($cl)=='pair'; $cl = cdr($cl)){
 | 
						|
	    $clause = car($cl);
 | 
						|
 | 
						|
	    if(valtype($clause)!='pair'){
 | 
						|
		$bcode[$bc++] = array('error', 'bad case clause');
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
	    $data = car($clause);
 | 
						|
	    if(valtype($data)!='pair' &&
 | 
						|
	       !(valtype($data)=='symbol' &&
 | 
						|
		 valdata($data)=='else')){
 | 
						|
		$bcode[$bc++] = 
 | 
						|
		     array('error', 'bad case data: ' . tostring($data, 0));
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
	    $ccode = cdr($clause);
 | 
						|
	    if(valtype($ccode)!='pair'){
 | 
						|
		$bcode[$bc++] = array('error', 'empty case clause');
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
 | 
						|
	    if(valtype($data)=='symbol' &&
 | 
						|
	       valdata($data)=='else'){
 | 
						|
		if(is_array($elseclause)){
 | 
						|
		    $bcode[$bc++] = 
 | 
						|
			 array('error', 'case: more than one else clause');
 | 
						|
		    return;
 | 
						|
		}
 | 
						|
		$elseclause = $clause;
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		if(is_array($elseclause)){
 | 
						|
		    $bcode[$bc++] = 
 | 
						|
			 array('error', 'case: else clause must be last');
 | 
						|
		    return;
 | 
						|
		}
 | 
						|
		$clauses[] = $clause;
 | 
						|
	    }
 | 
						|
 | 
						|
	    $count++;
 | 
						|
	}
 | 
						|
	
 | 
						|
	$current = $bc;
 | 
						|
	if(is_array($elseclause)){
 | 
						|
	    sequence(cdr($elseclause));
 | 
						|
	    $elsecode = codesegment($current);
 | 
						|
	    
 | 
						|
	    $bcode[$bc++] = array('toargs', car($elseclause));
 | 
						|
	    $bcode[$bc++] = array('toargs', newval('bcode', $elsecode));
 | 
						|
	}
 | 
						|
 | 
						|
	for($c=count($clauses)-1; $c>=0; $c--){
 | 
						|
	    $clause = $clauses[$c];
 | 
						|
 | 
						|
	    $current = $bc;
 | 
						|
	    sequence(cdr($clause));
 | 
						|
	    $ccode = codesegment($current);
 | 
						|
	    
 | 
						|
	    $bcode[$bc++] = array('toargs', car($clause));
 | 
						|
	    $bcode[$bc++] = array('toargs', newval('bcode', $ccode));
 | 
						|
	}
 | 
						|
 | 
						|
	$bcode[$bc++] = array('case', $count);
 | 
						|
	break;
 | 
						|
 | 
						|
        case 'if':
 | 
						|
	if(valtype($args)!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', 'bad if condition');
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	$ifcond = car($args);
 | 
						|
	if(valtype(cdr($args))!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', 'true clause missing from if');
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	$iftrue = car(cdr($args));
 | 
						|
	if(valtype(cdr(cdr($args)))!='pair'){
 | 
						|
	  $iffalse = cons(newval('symbol', 'quote'), cons(null(), null()));
 | 
						|
	}
 | 
						|
	else{
 | 
						|
	  $iffalse = car(cdr(cdr($args)));
 | 
						|
	}
 | 
						|
 | 
						|
	compile($ifcond);
 | 
						|
 | 
						|
	$current = $bc;
 | 
						|
	compile($iftrue);
 | 
						|
	$tcode = codesegment($current);
 | 
						|
	compile($iffalse);
 | 
						|
	$fcode = codesegment($current);
 | 
						|
 | 
						|
	$bcode[$bc++] = array('toargs', newval('bcode', $tcode));
 | 
						|
	$bcode[$bc++] = array('toargs', newval('bcode', $fcode));
 | 
						|
	$bcode[$bc++] = array('if');
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
        case 'and':
 | 
						|
        case 'or':
 | 
						|
	$count = 0;
 | 
						|
	$current = $bc;
 | 
						|
	$terms = array();
 | 
						|
 | 
						|
	while(valtype($args)=='pair'){
 | 
						|
	  compile(car($args));
 | 
						|
 | 
						|
	  $terms[] = codesegment($current);
 | 
						|
 | 
						|
	  $count++; $args = cdr($args);
 | 
						|
	}
 | 
						|
	for($tind = $count-1; $tind>=0; $tind--){
 | 
						|
	  $tcode = $terms[$tind];
 | 
						|
	  $bcode[$bc++] = array('toargs', newval('bcode', $tcode));
 | 
						|
	}
 | 
						|
 | 
						|
	$bcode[$bc++] = array('toargs', ($name=='and' ? btrue() : bfalse()));
 | 
						|
	$bcode[$bc++] = array($name, $count);
 | 
						|
        break;
 | 
						|
 | 
						|
        case 'quote':
 | 
						|
	if(valtype($args)!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', 'quote missing an item');
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	if(valtype(cdr($args))!='empty'){
 | 
						|
	  $bcode[$bc++] = array('error', 'quote takes a single argument');
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	$bcode[$bc++] = array('toargs', car($args));
 | 
						|
        break;
 | 
						|
	
 | 
						|
	case 'let':
 | 
						|
        case 'let*':
 | 
						|
        case 'letrec':
 | 
						|
	if(valtype($args)!='pair'){
 | 
						|
	  $bcode[$bc++] = array('error', "bad first arg to $name");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	if($name=='letrec'){
 | 
						|
	  $bcode[$bc++] = array('layer', 0);
 | 
						|
	}
 | 
						|
	for($bindings=car($args), $count=0; valtype($bindings)=='pair';
 | 
						|
	    $bindings=cdr($bindings)){
 | 
						|
	    $binding=car($bindings);
 | 
						|
	    if(valtype($binding)!='pair'){
 | 
						|
	      $bcode[$bc++] = 
 | 
						|
		   array('error', '$name binding ' . ($count+1) . ' bad');
 | 
						|
	      return;
 | 
						|
	    }
 | 
						|
 | 
						|
	    if(valtype(car($binding))!='symbol'){
 | 
						|
		$bcode[$bc++] = array('error', "first arg to $name binding " . 
 | 
						|
				 ($count+1) . ' not a symbol');
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
	    $bcode[$bc++] = array('toargs', car($binding));
 | 
						|
	    $count++;
 | 
						|
	    compile(car(cdr($binding)));
 | 
						|
	    if($name=='let*'){
 | 
						|
	      $bcode[$bc++] = array('layer', 1);
 | 
						|
	    }
 | 
						|
	    else if($name=='letrec'){
 | 
						|
	      $bcode[$bc++] = array('define', 1);
 | 
						|
	      $bcode[$bc++] = array('popargs', 1);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	if(valtype($bindings)!='empty'){
 | 
						|
	  $bcode[$bc++] = 
 | 
						|
	       array('error', "parse error at $name binding " . ($count+1));
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	if($name=='let'){
 | 
						|
	  $bcode[$bc++] = array('layer', $count);
 | 
						|
	}
 | 
						|
 | 
						|
	if(valtype(cdr($args))=='empty'){
 | 
						|
	  $bcode[$bc++] = array('error', "$name body is empty");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
	sequence(cdr($args));
 | 
						|
 | 
						|
	if($name=='let' || $name=='letrec'){
 | 
						|
	  $bcode[$bc++] = array('popenv', 1);
 | 
						|
	}
 | 
						|
	else{
 | 
						|
	  $bcode[$bc++] = array('popenv', $count);
 | 
						|
	}
 | 
						|
	break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
$primtable = 
 | 
						|
array("+", "*", "-", "/", "=", ">", "<",
 | 
						|
      "draw-move", "draw-line", "draw-color",
 | 
						|
      "sin", "cos", "sqrt",
 | 
						|
        "quotient", "remainder", "not",
 | 
						|
	"zero?", "pair?", "number?", "eqv?", "eq?",
 | 
						|
	"cons", "car", "cdr", "list", "null?",
 | 
						|
	"set-car!", "set-cdr!",
 | 
						|
	"display", "newline");
 | 
						|
 | 
						|
function drawcmd($name, $x, $y)
 | 
						|
{
 | 
						|
  global $imagedata;
 | 
						|
 | 
						|
  if($x<$imagedata[0]){
 | 
						|
      $imagedata[0] = $x;
 | 
						|
  }
 | 
						|
  if($y<$imagedata[1]){
 | 
						|
      $imagedata[1] = $y;
 | 
						|
  }
 | 
						|
  if($x>$imagedata[2]){
 | 
						|
      $imagedata[2] = $x;
 | 
						|
  }
 | 
						|
  if($y>$imagedata[3]){
 | 
						|
      $imagedata[3] = $y;
 | 
						|
  }
 | 
						|
 | 
						|
  if($name=='draw-move'){
 | 
						|
      $imagedata[4][] = array(0, $x, $y);
 | 
						|
  }
 | 
						|
  else{
 | 
						|
      $imagedata[4][] = array(1, $x, $y);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function len($l)
 | 
						|
{
 | 
						|
    $len = 0; 
 | 
						|
    while(valtype($l)=='pair'){
 | 
						|
	$len++;
 | 
						|
	$l = cdr($l);
 | 
						|
    }
 | 
						|
    return $len;
 | 
						|
}
 | 
						|
 | 
						|
function applyprimitive($name, $argc)
 | 
						|
{
 | 
						|
  global $argstack, $argp, $errmsg;
 | 
						|
  global $outputstr;
 | 
						|
  global $imagedata;
 | 
						|
 | 
						|
 | 
						|
  switch($name){
 | 
						|
  case 'sin':
 | 
						|
  case 'cos':
 | 
						|
  case 'sqrt':
 | 
						|
      if($argc!=1){
 | 
						|
	  $errmsg = "$name requires one argument";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $a = $argstack[$argp-1];
 | 
						|
      if(valtype($a)!='number'){
 | 
						|
	  $errmsg = "first arg to $name not a number";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      $av = valdata($a);
 | 
						|
 | 
						|
      if($name=='sin'){
 | 
						|
	  return newval('number', sin($av));
 | 
						|
      }
 | 
						|
      else if($name=='cos'){
 | 
						|
	  return newval('number', cos($av));
 | 
						|
      }
 | 
						|
      
 | 
						|
      if($av<0){
 | 
						|
	  $errmsg = "arg to $name must not be negative";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      return newval('number', sqrt($av));
 | 
						|
  break;
 | 
						|
 | 
						|
  case 'draw-move':
 | 
						|
  case 'draw-line':
 | 
						|
      if($argc!=2){
 | 
						|
	  $errmsg = "$name requires two arguments";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $a = $argstack[$argp-2];
 | 
						|
      if(valtype($a)!='number'){
 | 
						|
	  $errmsg = "first arg to $name not a number";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $b = $argstack[$argp-1];
 | 
						|
      if(valtype($b)!='number'){
 | 
						|
	  $errmsg = "second arg to $name not a number";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      $av = valdata($a);
 | 
						|
      $bv = valdata($b);
 | 
						|
 | 
						|
      if(!count($imagedata[4])){
 | 
						|
	  if($name=='draw-line'){
 | 
						|
	      $imagedata[0] = 0;
 | 
						|
	      $imagedata[1] = 0;
 | 
						|
	      $imagedata[2] = 0;
 | 
						|
	      $imagedata[3] = 0;
 | 
						|
	  }
 | 
						|
	  else{
 | 
						|
	      $imagedata[0] = $av;
 | 
						|
	      $imagedata[1] = $bv;
 | 
						|
	      $imagedata[2] = $av;
 | 
						|
	      $imagedata[3] = $bv;
 | 
						|
	  }
 | 
						|
      }
 | 
						|
      drawcmd($name, $av, $bv);
 | 
						|
      return null();
 | 
						|
  break;
 | 
						|
  case 'draw-color':
 | 
						|
      if($argc!=1){
 | 
						|
	  $errmsg = "$name requires one argument";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $c = $argstack[$argp-1];
 | 
						|
      if(len($c)!=3){
 | 
						|
	  $errmsg = "$name requires a list; form: (R, G, B)";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $red = car($c);
 | 
						|
      if(valtype($red)!='number'){
 | 
						|
	  $errmsg = "$name: red component not a number";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $green = car(cdr($c));
 | 
						|
      if(valtype($green)!='number'){
 | 
						|
	  $errmsg = "$name: green component not a number";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $blue = car(cdr(cdr($c)));
 | 
						|
      if(valtype($blue)!='number'){
 | 
						|
	  $errmsg = "$name: blue component not a number";
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $imagedata[4][] =
 | 
						|
	   array(2, valdata($red), valdata($green), valdata($blue));
 | 
						|
      return null();
 | 
						|
  break;
 | 
						|
  case 'quotient':
 | 
						|
      if($argc!=2){
 | 
						|
	  $errmsg = 'quotient requires two arguments';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $a = $argstack[$argp-2];
 | 
						|
      if(valtype($a)!='number'){
 | 
						|
	  $errmsg = 'first arg to quotient not a number';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $p = (int)valdata($a);
 | 
						|
      if($p!=valdata($a)){
 | 
						|
	  $errmsg = 'first arg to quotient not an integer';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      $b = $argstack[$argp-1];
 | 
						|
      if(valtype($a)!='number'){
 | 
						|
	  $errmsg = 'second arg to quotient not a number';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $q = (int)valdata($b);
 | 
						|
      if($q!=valdata($b)){
 | 
						|
	  $errmsg = 'second arg to quotient not an integer';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      if(!$q){
 | 
						|
	  $errmsg = 'second arg to quotient must not be zero';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      return newval('number', (int)($p / $q));
 | 
						|
  break;
 | 
						|
  case 'remainder':
 | 
						|
      if($argc!=2){
 | 
						|
	  $errmsg = 'remainder requires two arguments';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $a = $argstack[$argp-2];
 | 
						|
      if(valtype($a)!='number'){
 | 
						|
	  $errmsg = 'first arg to remainder not a number';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $p = (int)valdata($a);
 | 
						|
      if($p!=valdata($a)){
 | 
						|
	  $errmsg = 'first arg to remainder not an integer';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      $b = $argstack[$argp-1];
 | 
						|
      if(valtype($a)!='number'){
 | 
						|
	  $errmsg = 'second arg to remainder not a number';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      $q = (int)valdata($b);
 | 
						|
      if($q!=valdata($b)){
 | 
						|
	  $errmsg = 'second arg to remainder not an integer';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
      if(!$q){
 | 
						|
	  $errmsg = 'second arg to remainder must not be zero';
 | 
						|
	  return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      return newval('number', $p % $q);
 | 
						|
  break;
 | 
						|
  case 'eqv?':
 | 
						|
  case 'eq?':
 | 
						|
    if($argc!=2){
 | 
						|
      $errmsg = '$name requires two arguments';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $itema = $argstack[$argp-2];
 | 
						|
    $itemb = $argstack[$argp-1];
 | 
						|
    
 | 
						|
    if(valtype($itema)!=valtype($itemb)){
 | 
						|
      return bfalse();
 | 
						|
    }
 | 
						|
 | 
						|
    return (valdata($itema)==valdata($itemb) ? 
 | 
						|
	      btrue() : bfalse());
 | 
						|
  case 'pair?':
 | 
						|
    if($argc!=1){
 | 
						|
      $errmsg = 'pair? requires one argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
    return 
 | 
						|
      (valtype($item)=='pair' ? btrue() : bfalse());
 | 
						|
  case 'number?':
 | 
						|
    if($argc!=1){
 | 
						|
      $errmsg = 'number? requires one argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
    return
 | 
						|
      (valtype($item)=='number' ? btrue() : bfalse());
 | 
						|
  case 'zero?':
 | 
						|
    if($argc!=1){
 | 
						|
      $errmsg = 'zero? requires one argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
    if(valtype($item)!='number'){
 | 
						|
      $errmsg = 'zero? requires a numeric argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    return (valdata($item) ? bfalse() : btrue());
 | 
						|
  case 'not':
 | 
						|
    if($argc!=1){
 | 
						|
      $errmsg = 'not requires one argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
 | 
						|
    if(valtype($item)=='boolean' &&
 | 
						|
       valdata($item)=='#f'){
 | 
						|
      return btrue();
 | 
						|
    }
 | 
						|
    return bfalse();
 | 
						|
  case 'list':
 | 
						|
    for($res=null(), $c=1; $c<=$argc; $c++){
 | 
						|
      $res = cons($argstack[$argp-$c], $res);
 | 
						|
    }
 | 
						|
    return $res;
 | 
						|
  case 'cons':
 | 
						|
    if($argc!=2){
 | 
						|
      $errmsg = 'cons requires two arguments';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $a = $argstack[$argp-2];
 | 
						|
    $b = $argstack[$argp-1];
 | 
						|
    return cons($a, $b);
 | 
						|
  case 'set-car!':
 | 
						|
    if($argc!=2){
 | 
						|
      $errmsg = 'set-car! requires two arguments';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $p = $argstack[$argp-2];
 | 
						|
    if(valtype($p)!='pair'){
 | 
						|
      $errmsg = 'first argument to set-car! must be a pair';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $v = $argstack[$argp-1];
 | 
						|
    setcar($p, $v);
 | 
						|
    return $v;
 | 
						|
  case 'set-cdr!':
 | 
						|
    if($argc!=2){
 | 
						|
      $errmsg = 'set-cdr! requires two arguments';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $p = $argstack[$argp-2];
 | 
						|
    if(valtype($p)!='pair'){
 | 
						|
      $errmsg = 'first argument to set-cdr! must be a pair';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $v = $argstack[$argp-1];
 | 
						|
    setcdr($p, $v);
 | 
						|
    return $v;
 | 
						|
  case 'car':
 | 
						|
    if($argc!=1){
 | 
						|
      $errmsg = 'car takes a single argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $p = $argstack[$argp-1];
 | 
						|
    if(valtype($p)!='pair'){
 | 
						|
      $errmsg = 'argument to car must be a pair';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    return car($p);
 | 
						|
  case 'cdr':
 | 
						|
    if($argc!=1){
 | 
						|
      $errmsg = 'cdr takes a single argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $p = $argstack[$argp-1];
 | 
						|
    if(valtype($p)!='pair'){
 | 
						|
      $errmsg = 'argument to cdr must be a pair';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    return cdr($p);
 | 
						|
  case 'null?':
 | 
						|
    if($argc!=1){
 | 
						|
      $errmsg = 'null takes a single argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $p = $argstack[$argp-1];
 | 
						|
    if(valtype($p)=='empty'){
 | 
						|
      return newval('boolean', '#t');
 | 
						|
    }
 | 
						|
    return newval('boolean', '#f');
 | 
						|
  case 'display':
 | 
						|
    if($argc!=1){
 | 
						|
      $errmsg = 'display requires one argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
    $outputstr .= tohtmlstring($item, 'expchars');
 | 
						|
    return null();
 | 
						|
  case 'newline':
 | 
						|
    if($argc){
 | 
						|
      $errmsg = 'newline takes no arguments';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $outputstr .= "\n";
 | 
						|
    return null();
 | 
						|
  case '+':
 | 
						|
    if(!$argc){
 | 
						|
      return newval('number', 0);
 | 
						|
    }
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
    if(valtype($item)!='number'){
 | 
						|
      $errmsg = 'first arg to + not a number';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    for($res = valdata($item), $c=1; $c<$argc; $c++){
 | 
						|
      $item = $argstack[$argp-$argc+$c];
 | 
						|
      if(valtype($item)!='number'){
 | 
						|
	$errmsg = 'arg ' . ($c+1)  . ' to + not a number';
 | 
						|
	return -1;
 | 
						|
      }
 | 
						|
      $res += valdata($item);
 | 
						|
    }
 | 
						|
    return newval('number', $res);
 | 
						|
  case '*':
 | 
						|
    if(!$argc){
 | 
						|
      return newval('number', 1);
 | 
						|
    }
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
    if(valtype($item)!='number'){
 | 
						|
      $errmsg = 'first arg to * not a number';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    for($res = valdata($item), $c=1; $c<$argc; $c++){
 | 
						|
      $item = $argstack[$argp-$argc+$c];
 | 
						|
      if(valtype($item)!='number'){
 | 
						|
	$errmsg = 'arg ' . ($c+1)  . ' to * not a number';
 | 
						|
	return -1;
 | 
						|
      }
 | 
						|
      $res *= valdata($item);
 | 
						|
    }
 | 
						|
    return newval('number', $res);
 | 
						|
  case '-':
 | 
						|
    if(!$argc){
 | 
						|
      $errmsg = '- requires at least one argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
    if(valtype($item)!='number'){
 | 
						|
      $errmsg = 'first arg to - not a number';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    for($res = valdata($item), $c=1; $c<$argc; $c++){
 | 
						|
      $item = $argstack[$argp-$argc+$c];
 | 
						|
      if(valtype($item)!='number'){
 | 
						|
	$errmsg = 'arg ' . ($c+1)  . ' to - not a number';
 | 
						|
	return -1;
 | 
						|
      }
 | 
						|
      $res -= valdata($item);
 | 
						|
    }
 | 
						|
    return newval('number', ($argc==1 ? -$res : $res));
 | 
						|
  case '/':
 | 
						|
    if(!$argc){
 | 
						|
      $errmsg = '/ requires at least one argument';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
    if(valtype($item)!='number'){
 | 
						|
      $errmsg = 'first arg to - not a number';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    for($res = valdata($item), $c=1; $c<$argc; $c++){
 | 
						|
      $item = $argstack[$argp-$argc+$c];
 | 
						|
      if(valtype($item)!='number'){
 | 
						|
	$errmsg = 'arg ' . ($c+1)  . ' to - not a number';
 | 
						|
	return -1;
 | 
						|
      }
 | 
						|
      $res /= valdata($item);
 | 
						|
    }
 | 
						|
    return newval('number', ($argc==1 ? 1/$res : $res));
 | 
						|
  case '=':
 | 
						|
    $item = $argstack[$argp-$argc];
 | 
						|
    if(valtype($item)!='number'){
 | 
						|
      $errmsg = 'first arg to = not a number';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    for($res = valdata($item), $c=1; $c<$argc; $c++){
 | 
						|
      $item = $argstack[$argp-$argc+$c];
 | 
						|
      if(valtype($item)!='number'){
 | 
						|
	$errmsg = 'arg ' . ($c+1)  . ' to = not a number';
 | 
						|
	return -1;
 | 
						|
      }
 | 
						|
      if($res != valdata($item)){
 | 
						|
	return newval('boolean', '#f');
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return newval('boolean', '#t');
 | 
						|
  case '>':
 | 
						|
    if($argc<2){
 | 
						|
      $errmsg = '> requires at least two arguments';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $current = $argstack[$argp-$argc];
 | 
						|
    if(valtype($current)!='number'){
 | 
						|
      $errmsg = 'first arg to - not a number';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    for($c=1; $c<$argc; $c++){
 | 
						|
      $item = $argstack[$argp-$argc+$c];
 | 
						|
      if(valtype($item)!='number'){
 | 
						|
	$errmsg = 'arg ' . ($c+1)  . ' to > not a number';
 | 
						|
	return -1;
 | 
						|
      }
 | 
						|
      if(valdata($current) <= valdata($item)){
 | 
						|
	  return bfalse();
 | 
						|
      }
 | 
						|
      $current = $item;
 | 
						|
    }
 | 
						|
    return btrue();
 | 
						|
  case '<':
 | 
						|
    if($argc<2){
 | 
						|
      $errmsg = '< requires at least two arguments';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    $current = $argstack[$argp-$argc];
 | 
						|
    if(valtype($current)!='number'){
 | 
						|
      $errmsg = 'first arg to - not a number';
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    for($c=1; $c<$argc; $c++){
 | 
						|
      $item = $argstack[$argp-$argc+$c];
 | 
						|
      if(valtype($item)!='number'){
 | 
						|
	$errmsg = 'arg ' . ($c+1)  . ' to < not a number';
 | 
						|
	return -1;
 | 
						|
      }
 | 
						|
      if(valdata($current) >= valdata($item)){
 | 
						|
	  return bfalse();
 | 
						|
      }
 | 
						|
      $current = $item;
 | 
						|
    }
 | 
						|
    return btrue();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function init()
 | 
						|
{
 | 
						|
    global $primtable, $initialenv;
 | 
						|
 | 
						|
    $prim = array();
 | 
						|
    for($p=0; $p<count($primtable); $p++){
 | 
						|
	$prim[$primtable[$p]] = newval('primitive', $primtable[$p]);
 | 
						|
    }
 | 
						|
 | 
						|
    $initialenv = cons(newenv(array()), cons(newenv($prim), null()));
 | 
						|
}
 | 
						|
 | 
						|
function printargstack()
 | 
						|
{
 | 
						|
  global $argstack, $argp;
 | 
						|
 | 
						|
  for($p=0; $p<$argp; $p++){
 | 
						|
    echo tohtmlstring($argstack[$p], 'noexpchars') . " ";
 | 
						|
  }
 | 
						|
  echo "\n";
 | 
						|
}
 | 
						|
 | 
						|
function insertcode($prev, $code, $tag)
 | 
						|
{
 | 
						|
    global $codestack, $codep;
 | 
						|
 | 
						|
    $codestack[$codep-1][1] = $prev;
 | 
						|
    $codestack[$codep] = array($code, -1, count($code), $tag);
 | 
						|
    $codep++;
 | 
						|
}
 | 
						|
 | 
						|
function findmarkforward($obj)
 | 
						|
{
 | 
						|
    global $codestack, $codep;
 | 
						|
 | 
						|
    $type = valtype($obj); $tag = valdata($obj);
 | 
						|
 | 
						|
    while($codep>0){
 | 
						|
	$bcode     = $codestack[$codep-1][0];
 | 
						|
	$searchpos = $codestack[$codep-1][1]; 
 | 
						|
	$mx        = $codestack[$codep-1][2];
 | 
						|
	while($searchpos<$mx){
 | 
						|
	    if(valtype($bcode[$searchpos])!=$type ||
 | 
						|
	       valdata($bcode[$searchpos])!=$tag){
 | 
						|
		$searchpos++;
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		return $searchpos;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	$codep--;
 | 
						|
    }
 | 
						|
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
function run()
 | 
						|
{
 | 
						|
    global $initialenv, $bcode, $bc, $errmsg;
 | 
						|
    global $envstack, $argstack, $envp, $argp;
 | 
						|
    global $stacktrace;
 | 
						|
 | 
						|
    global $codestack, $codep;
 | 
						|
 | 
						|
    $codestack = array(array($bcode, 0, $bc, -1, 0)); 
 | 
						|
    $codep = 1;
 | 
						|
 | 
						|
    $argstack = array();
 | 
						|
    $argp = 0;
 | 
						|
 | 
						|
    $b = 0;
 | 
						|
    while(1){
 | 
						|
	$instr = $codestack[$codep-1][0][$b];
 | 
						|
 | 
						|
	// echo $b . ' ' . $instr[0] . "<BR>\n";
 | 
						|
	if($stacktrace && $instr[0]!='start'){
 | 
						|
	  echo "<B>></B> ";
 | 
						|
	  printargstack();
 | 
						|
	}
 | 
						|
 | 
						|
	switch($instr[0]){
 | 
						|
	    case 'cond':
 | 
						|
            $count  = $instr[1];
 | 
						|
 | 
						|
            $type   = valdata($argstack[$argp-2]);
 | 
						|
	    $code   = valdata($argstack[$argp-1]);
 | 
						|
 | 
						|
	    if($type=='else'){
 | 
						|
		insertcode($b, $code, -1);
 | 
						|
		$b = -1;
 | 
						|
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		$tcode = valdata($argstack[$argp-3]);
 | 
						|
		
 | 
						|
		insertcode($b, array(array('cond1', $count)), -1);
 | 
						|
		insertcode(-1, $tcode, -1);
 | 
						|
		$b = -1;
 | 
						|
	    }
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'cond1':
 | 
						|
	    $count  = $instr[1];
 | 
						|
 | 
						|
            $type    = valdata($argstack[$argp-3]);
 | 
						|
	    $code    = valdata($argstack[$argp-2]);
 | 
						|
	    $tres    = $argstack[$argp-1];
 | 
						|
	    
 | 
						|
	    if(!isfalse($tres)){
 | 
						|
		if($type=='proc'){
 | 
						|
		    $pcode = array();
 | 
						|
		    $pcode[] = array('checkptc', $tres);
 | 
						|
		    $pcode[] = array('toargs', $tres);
 | 
						|
		    $pcode[] = array('application', 1);
 | 
						|
		    insertcode($b, $pcode, -1);
 | 
						|
		    insertcode(-1, $code, -1);
 | 
						|
		}
 | 
						|
		else{
 | 
						|
		    insertcode($b, $code, -1);
 | 
						|
		}
 | 
						|
		$b = -1;
 | 
						|
 | 
						|
		$topop = $count+1;
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
		if($count>=3){
 | 
						|
		    insertcode($b, array(array('cond', $count-3)), -1);
 | 
						|
		    $b = -1;
 | 
						|
		}
 | 
						|
 | 
						|
		$topop = 4;
 | 
						|
	    }
 | 
						|
 | 
						|
	    for($c=0; $c<$topop; $c++){
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
	    }
 | 
						|
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'case':
 | 
						|
            $count = $instr[1];
 | 
						|
            $caseval = $argstack[$argp-1-2*$count];
 | 
						|
	    $casevaltype = valtype($caseval);
 | 
						|
	    $casevaldata = valdata($caseval);
 | 
						|
 | 
						|
 | 
						|
	    for($c=0; $c<$count; $c++){
 | 
						|
		$cases = $argstack[$argp-2];
 | 
						|
		$code  = $argstack[$argp-1];
 | 
						|
 | 
						|
		$match = 0;
 | 
						|
		if(valtype($cases)=='symbol'){
 | 
						|
		    $match = 1;
 | 
						|
		}
 | 
						|
		else{
 | 
						|
		    while(valtype($cases)=='pair'){
 | 
						|
			$item = car($cases);
 | 
						|
			if(valtype($item)==$casevaltype &&
 | 
						|
			   valdata($item)==$casevaldata){
 | 
						|
			    $match = 1;
 | 
						|
			    break;
 | 
						|
			}
 | 
						|
			$cases = cdr($cases);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
		
 | 
						|
		if($match){
 | 
						|
		    insertcode($b, valdata($code), -1);
 | 
						|
		    $b = -1;
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
	    }
 | 
						|
 | 
						|
	    while($c<$count){
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
		$c++;
 | 
						|
	    }
 | 
						|
 | 
						|
	    unset($argstack[$argp-1]); $argp--;
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'thunk':
 | 
						|
	    writeargptothunk($instr, -1);
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'argptothunk':
 | 
						|
	    writeargptothunk($instr[1], $argp);
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'envptothunk':
 | 
						|
	    writeenvptothunk($instr[1], $envp);
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'error':
 | 
						|
	    $errmsg = $instr[1];
 | 
						|
	    return -1;
 | 
						|
 | 
						|
	    case 'start':
 | 
						|
	    $envstack = array($initialenv);
 | 
						|
	    $envp = 1;
 | 
						|
	    break;
 | 
						|
	    
 | 
						|
	    case 'if':
 | 
						|
	    if(isfalse($argstack[$argp-3])){
 | 
						|
	      $icode = $argstack[$argp-1];
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
	      $icode = $argstack[$argp-2];
 | 
						|
	    }
 | 
						|
 | 
						|
	    insertcode($b, valdata($icode), -1);
 | 
						|
	    $b = -1;
 | 
						|
 | 
						|
	    unset($argstack[$argp-1]);
 | 
						|
	    unset($argstack[$argp-2]);
 | 
						|
	    unset($argstack[$argp-3]);
 | 
						|
	    $argp -= 3;
 | 
						|
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'and':
 | 
						|
	    case  'or':
 | 
						|
	    $op = $instr[0];
 | 
						|
 | 
						|
	    $count = $instr[1];
 | 
						|
	    if(valtype($argstack[$argp-1])!='boolean'){
 | 
						|
	      $errmsg = 'boolean required in ' . $op .
 | 
						|
		'; got ' . valtype($argstack[$argp-1]);
 | 
						|
	      return -1;
 | 
						|
	    }
 | 
						|
 | 
						|
	    $bool = $argstack[$argp-1];
 | 
						|
	    if(($op=='and' && valdata($bool)=='#t') ||
 | 
						|
	       ($op=='or'  && valdata($bool)=='#f')){
 | 
						|
	      if($count){
 | 
						|
		$tcode = valdata($argstack[$argp-2]);
 | 
						|
		insertcode($b, array(array($op, $count-1)), -1);
 | 
						|
		insertcode(-1, $tcode, -1);
 | 
						|
		$b = -1;
 | 
						|
		
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
	      }
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
	      unset($argstack[$argp-1]); $argp--; // boolean
 | 
						|
	      while($count>0){
 | 
						|
		unset($argstack[$argp-1]); $argp--;
 | 
						|
		$count--;
 | 
						|
	      }
 | 
						|
	      $argstack[$argp++] = $bool;
 | 
						|
	    }
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'closure':
 | 
						|
	    $cl = newclosure($argstack[$argp-3],
 | 
						|
			     $argstack[$argp-2],
 | 
						|
			     $argstack[$argp-1],
 | 
						|
			     $envstack[$envp-1]);
 | 
						|
 | 
						|
	    unset($argstack[$argp-1]);
 | 
						|
	    unset($argstack[$argp-2]);
 | 
						|
	    $argp -= 2;
 | 
						|
	    $argstack[$argp-1] = $cl;
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'layer':
 | 
						|
	    $newlayer = array();
 | 
						|
 | 
						|
            for($p=$argp-2; $p>=$argp-2*$instr[1]; $p-=2){
 | 
						|
	      $newlayer[$argstack[$p][1]]  = $argstack[$p+1];
 | 
						|
	      unset($argstack[$p]); unset($argstack[$p+1]);
 | 
						|
	    }
 | 
						|
	    $argp -= 2*$instr[1];
 | 
						|
 | 
						|
	    $envstack[$envp] = cons(newenv($newlayer), $envstack[$envp-1]);
 | 
						|
	    $envp++;
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case  'listapplication':
 | 
						|
            $argl = $argstack[$argp-1];
 | 
						|
	    if(valtype($argl)!='empty' && 
 | 
						|
	       valtype($argl)!='pair'){
 | 
						|
	      $errmsg = 'second arg to apply not a list';
 | 
						|
	      return -1;
 | 
						|
	    }
 | 
						|
	    unset($argstack[--$argp]);
 | 
						|
 | 
						|
	    $argc = 0;
 | 
						|
	    while(valtype($argl)=='pair'){
 | 
						|
	      $argstack[$argp++] = car($argl);
 | 
						|
	      $argc++;
 | 
						|
	      $argl = cdr($argl);
 | 
						|
	    }
 | 
						|
	    // pass through to application
 | 
						|
	    case  'application':
 | 
						|
	    if($instr[0]=='application'){
 | 
						|
	      $argc = $instr[1];
 | 
						|
	    }
 | 
						|
 | 
						|
	    $op=$argstack[$argp-1-$argc];
 | 
						|
	    if(valtype($op)=='primitive'){
 | 
						|
	      $res = applyprimitive(valdata($op), $argc);
 | 
						|
	      if(!is_array($res)){
 | 
						|
		return -1;
 | 
						|
	      }
 | 
						|
	      $newargp = $argp-$argc-1;
 | 
						|
	    }
 | 
						|
	    else if(valtype($op)=='thunk'){
 | 
						|
	      if($argc!=1){
 | 
						|
		$errmsg = 'continuation requires a single argument';
 | 
						|
		return -1;
 | 
						|
	      }
 | 
						|
	      if(readargpfromthunk($op)==-1){
 | 
						|
		$errmsg = 'thunk #' . valdata($op) . ' has expired';
 | 
						|
		return -1;
 | 
						|
	      }
 | 
						|
 | 
						|
	      $codestack[$codep-1][1] = $b;
 | 
						|
	      $b = findmarkforward($op);
 | 
						|
 | 
						|
	      $newenvp = readenvpfromthunk($op);
 | 
						|
	      while($envp>$newenvp){
 | 
						|
		unset($envstack[--$envp]);
 | 
						|
	      }
 | 
						|
 | 
						|
	      $res = $argstack[$argp-1];
 | 
						|
	      $newargp = readargpfromthunk($op);
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
	      $newlayer = array();
 | 
						|
	      $argl = closureargs($op);
 | 
						|
	      if(valdata(closureargtype($op))>0){
 | 
						|
		for($p=$argp-$argc;
 | 
						|
		    valtype($argl)=='pair'; $p++, $argl=cdr($argl)){
 | 
						|
		  if($p>=$argp){
 | 
						|
		    $errmsg = 'not enough arguments';
 | 
						|
		    return -1;
 | 
						|
		  }
 | 
						|
		  $newlayer[valdata(car($argl))] = $argstack[$p];
 | 
						|
		}
 | 
						|
		if(valdata(closureargtype($op))==1){
 | 
						|
		  $items = array();
 | 
						|
		  while($p<$argp){
 | 
						|
		    $items[] = $argstack[$p];
 | 
						|
		    $p++;
 | 
						|
		  }
 | 
						|
		  $newlayer[valdata($argl)] = array2list($items);
 | 
						|
		}
 | 
						|
		else if($p<$argp){
 | 
						|
		  $errmsg = 'too many arguments';
 | 
						|
		  return -1;
 | 
						|
		}
 | 
						|
	      }
 | 
						|
	      else{
 | 
						|
		for($p=$argp-$argc, $items=array(); $p<$argp; $p++){
 | 
						|
		  $items[] = $argstack[$p];
 | 
						|
		}
 | 
						|
		$newlayer[valdata($argl)] = array2list($items);
 | 
						|
	      }
 | 
						|
 | 
						|
	      $tag = closuretag($op);
 | 
						|
 | 
						|
	      $tailrec  = 0; $codestack[$codep-1][1] = $b;
 | 
						|
	      $popcount = 0;
 | 
						|
	      for($cp=$codep-1; $cp>=0; $cp--){
 | 
						|
		  $pos = $codestack[$cp][1]+1;
 | 
						|
		  $mx  = $codestack[$cp][2];
 | 
						|
		  while($pos<$mx){
 | 
						|
		      $instr = $codestack[$cp][0][$pos];
 | 
						|
		      if(valtype($instr)=='popenv'){
 | 
						|
			  $popcount += valdata($instr);
 | 
						|
			  $pos++;
 | 
						|
		      }
 | 
						|
		      else{
 | 
						|
			  break;
 | 
						|
		      }
 | 
						|
		  }
 | 
						|
		  if($pos<$mx){
 | 
						|
		      break;
 | 
						|
		  }
 | 
						|
		  if($codestack[$cp][3]==$tag){
 | 
						|
		      $tailrec = 1;
 | 
						|
		      break;
 | 
						|
		  }
 | 
						|
	      }
 | 
						|
 | 
						|
	      if($tailrec){
 | 
						|
		  $envp -= $popcount;
 | 
						|
		  $envstack[$envp-1] = 
 | 
						|
		       cons(newenv($newlayer), closureenv($op));
 | 
						|
		  $codep = $cp+1;
 | 
						|
	      }
 | 
						|
	      else{
 | 
						|
		  $envstack[$envp] = 
 | 
						|
		       cons(newenv($newlayer), closureenv($op));
 | 
						|
		  $envp++;
 | 
						|
 | 
						|
		  $lcode = valdata(closurebody($op));
 | 
						|
		  insertcode($b, array(array('popenv', 1)), -1);
 | 
						|
		  insertcode(-1, $lcode, $tag);
 | 
						|
	      }
 | 
						|
	      $b = -1;
 | 
						|
 | 
						|
	      $newargp = $argp-$argc-1;
 | 
						|
	    }
 | 
						|
 | 
						|
	    while($argp>$newargp){
 | 
						|
	      unset($argstack[--$argp]);
 | 
						|
	    }
 | 
						|
 | 
						|
	    if(valtype($op)=='primitive' ||
 | 
						|
	       valtype($op)=='thunk'){
 | 
						|
	      $argstack[$argp] = $res;
 | 
						|
	      $argp++;
 | 
						|
	    }
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'toargs':
 | 
						|
	    $argstack[$argp] = $instr[1];
 | 
						|
	    $argp++;
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'popargs':
 | 
						|
	    unset($argstack[$argp-1]);
 | 
						|
	    $argp--;
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'popenv':
 | 
						|
            $count = $instr[1];
 | 
						|
	    while($count>0){
 | 
						|
	      unset($envstack[$envp-1]);
 | 
						|
	      $envp--;
 | 
						|
	      $count--;
 | 
						|
	    }
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'globalenv':
 | 
						|
	    $envstack[$envp] = $envstack[0];
 | 
						|
	    $envp++;
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'checkptc':
 | 
						|
	    $item = $argstack[$argp-1];
 | 
						|
	    if(valtype($item)!='primitive' && 
 | 
						|
	       valtype($item)!='closure'   &&
 | 
						|
	       valtype($item)!='thunk'){
 | 
						|
		$errmsg = 'primitive, closure or thunk required';
 | 
						|
		return -1;
 | 
						|
	    }
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'lookup':
 | 
						|
	    $item = $argstack[$argp-1];
 | 
						|
	    $res = lookup(valdata($item), $envstack[$envp-1]);
 | 
						|
	    if(!is_array($res)){
 | 
						|
		$errmsg = "symbol " . valdata($item) . " not bound";
 | 
						|
		return -1;
 | 
						|
	    }
 | 
						|
	    $argstack[$argp-1] = $res[1];
 | 
						|
	    break;
 | 
						|
 | 
						|
	    case 'define':
 | 
						|
	    case 'set!':
 | 
						|
            $val = $argstack[--$argp]; unset($argstack[$argp]);
 | 
						|
	    $sym = $argstack[$argp-1];
 | 
						|
 | 
						|
	    $env = car($envstack[$envp-1]);
 | 
						|
	    if($instr[0]=='set!'){
 | 
						|
	      $res = lookup(valdata($sym), $envstack[$envp-1]);
 | 
						|
	      if(is_array($res)){
 | 
						|
		$env = $res[0];
 | 
						|
	      }
 | 
						|
	    }
 | 
						|
	    writetoenv($env, valdata($sym), $val);
 | 
						|
	    break;
 | 
						|
 | 
						|
	    default:
 | 
						|
	    $errmsg = 
 | 
						|
		 "instruction $instr[0] unknown " .
 | 
						|
		 "(codestack: $codep, position: $b)<BR>\n";
 | 
						|
	    return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	$b++;
 | 
						|
	while($b==$codestack[$codep-1][2]){
 | 
						|
	    $codep--;
 | 
						|
	    if(!$codep){
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	    $b   = $codestack[$codep-1][1]+1;
 | 
						|
	}
 | 
						|
 | 
						|
	if(!$codep){
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
function compile($exp)
 | 
						|
{
 | 
						|
    global $specialforms;
 | 
						|
    global $bcode, $bc;
 | 
						|
 | 
						|
    if($exp[0]=='pair'){
 | 
						|
	$toapply = car($exp);
 | 
						|
	if($toapply[0]=='symbol'){
 | 
						|
	    if(isset($specialforms[$toapply[1]])){
 | 
						|
		handlespecial($toapply[1], cdr($exp));
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	for($item=$exp, $count=0; valtype($item)=='pair'; $item=cdr($item)){
 | 
						|
	    $count++;
 | 
						|
	    compile(car($item));
 | 
						|
	    if($count==1){
 | 
						|
		$bcode[$bc++] = array('checkptc');
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	if(valtype($item)!='empty'){
 | 
						|
	    $bcode[$bc++] = array('error', 'application not a proper list');
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
	$bcode[$bc++] = array('application', $count-1);
 | 
						|
    }
 | 
						|
    else if($exp[0]=='symbol'){
 | 
						|
	$bcode[$bc++] = array('toargs', $exp);
 | 
						|
	$bcode[$bc++] = array('lookup');
 | 
						|
    }
 | 
						|
    else{
 | 
						|
	$bcode[$bc++] = array('toargs', $exp);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
?>
 | 
						|
<HTML>
 | 
						|
<HEAD>
 | 
						|
<TITLE>Scheme</TITLE>
 | 
						|
<SCRIPT TYPE="text/javascript">
 | 
						|
 | 
						|
progs      = new Array();
 | 
						|
needslib   = new Array();
 | 
						|
 | 
						|
p =
 | 
						|
"(case (* 2 3)\n" +
 | 
						|
"  ((2 3 5 7) 'prime)\n" +
 | 
						|
"  ((1 4 6 8 9) 'composite))\n" +
 | 
						|
"(case (car '(c d))\n" +
 | 
						|
"  ((a) 'a)\n" +
 | 
						|
"  ((b) 'b))\n" +
 | 
						|
"(case (car '(c d))\n" +
 | 
						|
"  ((a e i o u) 'vowel)\n" +
 | 
						|
"  ((w y) 'semivowel)\n" +
 | 
						|
"  (else 'consonant))\n" +
 | 
						|
"(case 'a\n" +
 | 
						|
"  ((b c) (display \"not reached\") (newline) 'b)\n" +
 | 
						|
"  ((a d) (display \"reached\") (newline) 'a))\n";
 | 
						|
 | 
						|
progs["case"] = p;
 | 
						|
 | 
						|
p =
 | 
						|
"(define primes\n" +
 | 
						|
"  ;;; check for composite numbers by testing the\n" +
 | 
						|
"  ;;; most probable divisors first\n" +
 | 
						|
"  (let* ((start (list 2))\n" +
 | 
						|
"         (end start))\n" +
 | 
						|
"    (letrec\n" +
 | 
						|
"	((composite?\n" +
 | 
						|
"	  (lambda (v l)\n" +
 | 
						|
"	    (let ((d (car l)))\n" +
 | 
						|
"	      (if (> (* d d) v) #f\n" +
 | 
						|
"		  (if (zero? (remainder v d)) #t\n" +
 | 
						|
"		      (composite? v (cdr l)))))))\n" +
 | 
						|
"	 (findnext\n" +
 | 
						|
"	  (lambda (v)\n" +
 | 
						|
"	    (if (composite? v start)\n" +
 | 
						|
"		(findnext (+ v 1)) v))))\n" +
 | 
						|
"      (lambda ()\n" +
 | 
						|
"	(let* ((current (car end))\n" +
 | 
						|
"	       (next (findnext (+ current 1)))\n" +
 | 
						|
"	       (p (cons next '())))\n" +
 | 
						|
"	  (set-cdr! end p)\n" +
 | 
						|
"	  (set! end p)\n" +
 | 
						|
"	  current)))))\n" +
 | 
						|
"\n" +
 | 
						|
"(define displayprimes\n" +
 | 
						|
"  (lambda (n)\n" +
 | 
						|
"    (if (not (zero? n))\n" +
 | 
						|
"	(begin\n" +
 | 
						|
"	  (display (primes)) (newline)\n" +
 | 
						|
"	  (displayprimes (- n 1))))))\n" +
 | 
						|
"\n" +
 | 
						|
"(displayprimes 14)\n";
 | 
						|
 | 
						|
progs["primes"] = p;
 | 
						|
 | 
						|
 | 
						|
p =
 | 
						|
"(define count\n" + 
 | 
						|
" (let ((c 0)) (lambda () (set! c (+ 1 c)) c)))\n" +
 | 
						|
"(count) (count) (count)\n";
 | 
						|
 | 
						|
progs["let-over-lambda"] = p;
 | 
						|
 | 
						|
p = 
 | 
						|
"(define reduce\n" +
 | 
						|
" (lambda (op base l)\n" +
 | 
						|
"  (if (null? l) base\n" +
 | 
						|
"   (op (car l) (reduce op base (cdr l))))))\n" +
 | 
						|
"(reduce + 0 '(2 3 4))\n" +
 | 
						|
"(reduce * 1 '(2 3 4))\n" +
 | 
						|
"(reduce cons '() '(2 3 4))\n";
 | 
						|
 | 
						|
progs["reduce"] = p;
 | 
						|
 | 
						|
p = 
 | 
						|
"(define factorial\n" +
 | 
						|
" (lambda (n)\n" +
 | 
						|
"  (if (= 0 n) 1\n" +
 | 
						|
"   (* n (factorial (- n 1))))))\n\n" +
 | 
						|
"(factorial 6)\n\n" +
 | 
						|
"(define factit\n" +
 | 
						|
" (lambda (n)\n" +
 | 
						|
"  (letrec\n" +
 | 
						|
"    ((fit\n" +
 | 
						|
"      (lambda (n acc)\n" +
 | 
						|
"        (if (= n 0) acc (fit (- n 1) (* n acc))))))\n" +
 | 
						|
"   (fit n 1))))\n\n" +
 | 
						|
"(factit 6)\n";
 | 
						|
 | 
						|
progs["factorial"] = p;
 | 
						|
 | 
						|
p =
 | 
						|
"(define rec\n" +
 | 
						|
" (lambda (n stop)\n" +
 | 
						|
"  (display n) (newline)\n" +
 | 
						|
"  (if (= n 0) (stop 0)\n" +
 | 
						|
"   (begin\n" +
 | 
						|
"     (rec (- n 1) stop)\n" +
 | 
						|
"     (display n) (newline)))))\n" +
 | 
						|
"(rec 6 (lambda (x) '()))\n" +
 | 
						|
"(call-with-current-continuation\n" +
 | 
						|
" (lambda (t) (rec 6 t)))\n";
 | 
						|
 | 
						|
progs["call-cc"] = p;
 | 
						|
 | 
						|
p =
 | 
						|
"(define jumper\n" +
 | 
						|
"  (lambda (n m)\n" +
 | 
						|
"    (letrec\n" +
 | 
						|
"	((rec\n" +
 | 
						|
"	  (lambda (n m jump)\n" +
 | 
						|
"	    (if (= n 0) (jump '())\n" +
 | 
						|
"		(if (= n m)\n" +
 | 
						|
"		    (call-with-current-continuation\n" +
 | 
						|
"		     (lambda (t) (rec (- n 1) m t)))\n" +
 | 
						|
"		    (rec (- n 1) m jump)))\n" +
 | 
						|
"	     (display n) (newline))))\n" +
 | 
						|
"      (rec n m (lambda (v) v)))))\n" +
 | 
						|
"(jumper 10 3)\n" +
 | 
						|
"(jumper 6 4)\n";
 | 
						|
 | 
						|
progs["call-cc1"] = p;
 | 
						|
 | 
						|
p =
 | 
						|
"(define tailrec\n" +
 | 
						|
"  (lambda (n)\n" +
 | 
						|
"    (display n) (newline)\n" +
 | 
						|
"    (if (= n 0) '()\n" +
 | 
						|
"	(tailrec (- n 1)))))\n" +
 | 
						|
"(tailrec 5)\n";
 | 
						|
 | 
						|
progs["tail-recursion"] = p;
 | 
						|
 | 
						|
p =
 | 
						|
"(and) (and #t #f)\n" +
 | 
						|
"(and\n" +
 | 
						|
"  (begin (display 1) #t)\n" +
 | 
						|
"  (begin (display 2) #f)\n" +
 | 
						|
"  (begin (display 3) #f))\n" +
 | 
						|
"(or) (or #f #t)\n" +
 | 
						|
"(or\n" +
 | 
						|
"  (begin (display 1) #f)\n" +
 | 
						|
"  (begin (display 2) #t)\n" +
 | 
						|
"  (begin (display 3) #t))\n";
 | 
						|
 | 
						|
progs["and-or"] = p;
 | 
						|
 | 
						|
 | 
						|
p =
 | 
						|
"(define rootfinder\n" +
 | 
						|
"  (let ((epsilon 1e-8))\n" +
 | 
						|
"    (lambda (p a b)\n" +
 | 
						|
"      (let ((mid (/ (+ a b) 2)))\n" +
 | 
						|
"	(if (< (- b a) epsilon) mid\n" +
 | 
						|
"	    (let \n" +
 | 
						|
"		((s1 (if (> (p a) 0)   'pos 'neg))\n" +
 | 
						|
"		 (s2 (if (> (p mid) 0) 'pos 'neg)))\n" +
 | 
						|
"	      (if (eq? s1 s2)\n" +
 | 
						|
"		  (rootfinder p mid b)\n" +
 | 
						|
"		  (rootfinder p a mid))))))))\n" +
 | 
						|
"\n" +
 | 
						|
"(define sqrteq\n" +
 | 
						|
"  (lambda (a)\n" +
 | 
						|
"    (lambda (x)\n" +
 | 
						|
"      (- (* x x) a))))\n" +
 | 
						|
"\n" +
 | 
						|
"(define r5 (rootfinder (sqrteq 5) 0 5))\n" +
 | 
						|
"r5\n" +
 | 
						|
"(* r5 r5)\n" +
 | 
						|
"\n" +
 | 
						|
"(define cbrteq\n" +
 | 
						|
"  (lambda (a)\n" +
 | 
						|
"    (lambda (x)\n" +
 | 
						|
"      (- (* x x x) a))))\n" +
 | 
						|
"\n" +
 | 
						|
"(define cr7 (rootfinder (cbrteq 7) 0 7))\n" +
 | 
						|
"cr7\n" +
 | 
						|
"(* cr7 cr7 cr7)\n";
 | 
						|
 | 
						|
 | 
						|
progs["rootfinder"] = p;
 | 
						|
 | 
						|
p =
 | 
						|
"(define plotter\n" +
 | 
						|
"  (lambda (f res x1 x2 y1 y2)\n" +
 | 
						|
"    (let* ((dx (- x2 x1)) (dy (- y2 y1)) (delta (/ dx res)))\n" +
 | 
						|
"      (letrec\n" +
 | 
						|
"	  ((scaled\n" +
 | 
						|
"	    (lambda (f x y) \n" +
 | 
						|
"	      (f\n" +
 | 
						|
"	       (* res (/ (- x x1) dx))\n" +
 | 
						|
"	       (* res (/ (- y y1) dy)))))\n" +
 | 
						|
"	   (plotit\n" +
 | 
						|
"	    (lambda (x)\n" +
 | 
						|
"	      (scaled draw-line x (f x))\n" +
 | 
						|
"	      (if (< x x2) (plotit (+ x delta))))))\n" +
 | 
						|
"	(scaled draw-move 0 y1)\n" +
 | 
						|
"	(scaled draw-line 0 y2)\n" +
 | 
						|
"	(scaled draw-move x1 0)\n" +
 | 
						|
"	(scaled draw-line x2 0)\n" +
 | 
						|
"	(draw-color '(255 0 0))\n" +
 | 
						|
"	(scaled draw-move x1 (f x1))\n" +
 | 
						|
"	(plotit x1)))))\n" +
 | 
						|
"\n" +
 | 
						|
"(plotter (lambda (x) (* x x x)) 70 -5 5 -50 50)\n" +
 | 
						|
"(plotter sin 50 -5 5 -1 1)\n" +
 | 
						|
"(plotter (lambda (x) (* x (sin x))) 100 -25 25 -25 25)\n" +
 | 
						|
"(plotter (lambda (x) (+ (* x x) (* -5 x) 6)) 80 -1 5 -3 10)\n";
 | 
						|
 | 
						|
progs["plotter"] = p;
 | 
						|
 | 
						|
p =
 | 
						|
"(define koch\n" +
 | 
						|
"  (let ((s (/ (sqrt 3) 2 3)))\n" +
 | 
						|
"    (lambda (res depth)\n" +
 | 
						|
"      (letrec\n" +
 | 
						|
"	  ((iter\n" +
 | 
						|
"	    (lambda (x1 y1 x2 y2 d)\n" +
 | 
						|
"	      (if (zero? d) \n" +
 | 
						|
"		  (draw-line x2 y2)\n" +
 | 
						|
"		  (let* ((dx (- x2 x1)) \n" +
 | 
						|
"			 (dy (- y2 y1))\n" +
 | 
						|
"			 (thx (+ x1 (/ dx 3))) \n" +
 | 
						|
"			 (thy (+ y1 (/ dy 3)))\n" +
 | 
						|
"			 (thx2 (+ x1 (* 2 (/ dx 3)))) \n" +
 | 
						|
"			 (thy2 (+ y1 (* 2 (/ dy 3))))\n" +
 | 
						|
"			 (mx (/ (+ x1 x2) 2)) \n" +
 | 
						|
"			 (my (/ (+ y1 y2) 2))\n" +
 | 
						|
"			 (midx (+ mx (* (- dy) s))) \n" +
 | 
						|
"			 (midy (+ my (* dx s))))\n" +
 | 
						|
"		    (iter x1 y1 thx thy (- d 1))\n" +
 | 
						|
"		    (iter thx thy midx midy (- d 1))\n" +
 | 
						|
"		    (iter midx midy thx2 thy2 (- d 1))\n" +
 | 
						|
"		    (iter thx2 thy2 x2 y2 (- d 1)))))))\n" +
 | 
						|
"	(draw-move 0 0)\n" +
 | 
						|
"	(draw-color '(0 255 0))\n" +
 | 
						|
"	(iter 0 0 res 0 depth)))))\n" +
 | 
						|
"\n" +
 | 
						|
"(koch 200 4)\n";
 | 
						|
 | 
						|
progs["koch-curve"] = p;
 | 
						|
 | 
						|
 | 
						|
p =
 | 
						|
";;; library required\n\n" +
 | 
						|
"(reverse '(a b c d e f))\n\n" +
 | 
						|
"(filter '(1 2 a b 3 c 4 5 d e f) number?)\n\n" +
 | 
						|
"(define l '(1 2 3 4 5))\n" +
 | 
						|
"(append l '(6 7 8))\n" +
 | 
						|
"(append l '(6 7 8) '(9 10 11))\n" +
 | 
						|
"(append l '(6 7 8 (9 10 11)))\n" +
 | 
						|
"(append l 6)\n";
 | 
						|
 | 
						|
progs["list-misc"] = p;
 | 
						|
needslib["list-misc"] = 1;
 | 
						|
 | 
						|
p =
 | 
						|
";;; library required\n" +
 | 
						|
"\n" +
 | 
						|
"(cond ((> 3 2) (display 'here)  (newline) 'greater)\n" +
 | 
						|
"      ((< 3 2) (display 'there) (newline) 'less))\n" +
 | 
						|
"(cond ((> 3 3) 'greater)\n" +
 | 
						|
"      ((< 3 3) 'less)\n" +
 | 
						|
"      (else 'equal))\n" +
 | 
						|
"(cond\n" +
 | 
						|
" (#f 'not-reached)\n" +
 | 
						|
" ((assq 'c '((a 1) (b 2) (c 3))) => cdr))\n" +
 | 
						|
"\n" +
 | 
						|
";;; syntax errors\n" +
 | 
						|
"(cond ())\n" +
 | 
						|
"(cond (else 'a) (else 'b))\n" +
 | 
						|
"(cond (#t =>))\n" +
 | 
						|
"\n" +
 | 
						|
"(define testcond\n" +
 | 
						|
"  (lambda (l)\n" +
 | 
						|
"    (cond\n" +
 | 
						|
"     ((assq 'a l) => (lambda (p) (set-car! p 'd)))\n" +
 | 
						|
"     ((assq 'b l) => (lambda (p) (set-car! p 'e)))\n" +
 | 
						|
"     ((assq 'c l) => (lambda (p) (set-car! p 'f))))))\n" +
 | 
						|
"\n" +
 | 
						|
"(define l '((a 1) (b 2) (c 3)))\n" +
 | 
						|
"(testcond l)\n" +
 | 
						|
"(testcond l)\n" +
 | 
						|
"(testcond l)\n" +
 | 
						|
"l\n";
 | 
						|
 | 
						|
progs["cond"] = p;
 | 
						|
needslib["cond"] = 1;
 | 
						|
 | 
						|
 | 
						|
p =
 | 
						|
";;; library required\n\n" +
 | 
						|
"(define l '(a (1 2 (3 4) 5) b))\n" +
 | 
						|
"(memv 'a l) \n" +
 | 
						|
"(memv '(1 2 (3 4) 5) l) \n" +
 | 
						|
"(member '(1 2 (3 4) 5) l)\n" +
 | 
						|
"(define k '((a 1) (b 2) ((((a))) 3)))\n" +
 | 
						|
"(assq 'a k)\n" +
 | 
						|
"(assq '(((a))) k)\n" +
 | 
						|
"(assoc '(((a))) k)\n";
 | 
						|
 | 
						|
progs["eq-mem-association"] = p;
 | 
						|
needslib["eq-mem-association"] = 1;
 | 
						|
 | 
						|
function setprog()
 | 
						|
{
 | 
						|
  var form = document.forms["mainform"];
 | 
						|
  var ind  = form.progs.selectedIndex;
 | 
						|
  var name = form.progs.options[ind].value;
 | 
						|
 | 
						|
  if(name=="--menu--"){
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 
 | 
						|
  form.program.value = progs[name];
 | 
						|
  if(needslib[name]){
 | 
						|
    form.loadlibrary.checked = true;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
</SCRIPT>
 | 
						|
</HEAD>
 | 
						|
 | 
						|
<FONT SIZE=24><B>Scheme</B></FONT><P><P>
 | 
						|
<?
 | 
						|
if(isset($program)){
 | 
						|
  if(!strcmp(strtoupper($showbytecodes), "ON")){
 | 
						|
    $showbytecodes=1; $sbc='CHECKED';
 | 
						|
  }
 | 
						|
  else{
 | 
						|
    $showbytecodes=0; $sbc='';
 | 
						|
  }
 | 
						|
 | 
						|
  if(!strcmp(strtoupper($stacktrace), "ON")){
 | 
						|
    $stacktrace=1; $stacktr='CHECKED';
 | 
						|
  }
 | 
						|
  else{
 | 
						|
    $stacktrace=0; $stacktr='';
 | 
						|
  }
 | 
						|
 | 
						|
  if(!strcmp(strtoupper($loadlibrary), "ON")){
 | 
						|
    $loadlibrary=1; $loadlib='CHECKED';
 | 
						|
  }
 | 
						|
  else{
 | 
						|
    $loadlibrary=0; $loadlib='';
 | 
						|
  }
 | 
						|
 | 
						|
  init();
 | 
						|
 | 
						|
  if($loadlibrary){
 | 
						|
    $stflag = $stacktrace; $stacktrace = 0;
 | 
						|
    $lname = "library.scm";
 | 
						|
 | 
						|
    $fp = @fopen($lname, "r");
 | 
						|
    if($fp){
 | 
						|
      $library = fread($fp, filesize($lname));
 | 
						|
      fclose($fp);
 | 
						|
 | 
						|
      tokenize($library);
 | 
						|
      $form = 1; $successes = 0;
 | 
						|
      while(isset($tokens[$base])){
 | 
						|
	$exp = readexp();
 | 
						|
	if(is_array($exp)){
 | 
						|
	  $bcode = array(array('start')); $bc=1;
 | 
						|
	  compile($exp);
 | 
						|
 | 
						|
	  $outputstr = '';
 | 
						|
	  if(run()){
 | 
						|
	    echo 
 | 
						|
	      "<EM>Library: form $form: " . 
 | 
						|
	      $errmsg  . 
 | 
						|
	      "</EM><BR>\n";
 | 
						|
	  }
 | 
						|
	  else{
 | 
						|
	    $successes++;
 | 
						|
	  }
 | 
						|
	}
 | 
						|
	else{
 | 
						|
	  echo 
 | 
						|
	    "<EM>Library: form $form: " . 
 | 
						|
	    $errmsg  . 
 | 
						|
	    "</EM><BR>\n";
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
	$form++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else{
 | 
						|
      echo 
 | 
						|
	"<FONT COLOR=red>" .
 | 
						|
	"Couldn't load library: $lname" . 
 | 
						|
	"</FONT><BR>\n";
 | 
						|
    }
 | 
						|
 | 
						|
    if($successes){
 | 
						|
      echo 
 | 
						|
	"<FONT COLOR=red>" .
 | 
						|
	"Library: $lname: loaded $successes " . 
 | 
						|
	"form" . ($succeses==1 ? '' : 's') . "." .
 | 
						|
	"</FONT><BR>\n";
 | 
						|
    }
 | 
						|
    $stacktrace = $stflag;
 | 
						|
  }
 | 
						|
 | 
						|
  $program = stripslashes($program);
 | 
						|
  tokenize($program);
 | 
						|
    
 | 
						|
  $form = 1; $imageindex = 0;
 | 
						|
  while(isset($tokens[$base])){
 | 
						|
    $exp = readexp();
 | 
						|
    if(is_array($exp)){
 | 
						|
      echo "<H2>Form $form</H2>\n"; $form++;
 | 
						|
 | 
						|
      $str = tohtmlstring2($exp);
 | 
						|
      echo "<TT>\n";
 | 
						|
      echo $str;
 | 
						|
      echo "</TT><HR>\n";
 | 
						|
 | 
						|
      $bcode = array(array('start')); $bc=1;
 | 
						|
      compile($exp);
 | 
						|
 | 
						|
      if($showbytecodes){
 | 
						|
	for($b=0; $b<count($bcode); $b++){
 | 
						|
	  $instr = $bcode[$b];
 | 
						|
	  echo "$instr[0] ";
 | 
						|
	  for($arg=1; $arg<count($instr); $arg++){
 | 
						|
	    if(is_array($instr[$arg])){
 | 
						|
	      echo tohtmlstring($instr[$arg], 'noexpchars') . " ";
 | 
						|
	    }
 | 
						|
	    else{
 | 
						|
	      echo $instr[$arg] . " ";
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	  echo "<BR>\n";
 | 
						|
	}
 | 
						|
	echo "<HR>\n";
 | 
						|
      }
 | 
						|
 | 
						|
      $imagedata = array(0, 0, 0, 0, array());
 | 
						|
	    
 | 
						|
      echo "<TT><PRE>";
 | 
						|
      $outputstr = '';
 | 
						|
      if(run()){
 | 
						|
	echo "<EM>" . $errmsg  . "</EM><BR>\n";
 | 
						|
      }
 | 
						|
      printargstack();
 | 
						|
      echo "</PRE></TT>\n";
 | 
						|
 | 
						|
      if(strlen($outputstr)>0){
 | 
						|
	echo "<P><B>Output</B>\n";
 | 
						|
	echo 
 | 
						|
	  "<PRE><TT>" . 
 | 
						|
	  htmlspecialchars($outputstr) . 
 | 
						|
	  "</TT></PRE>\n";
 | 
						|
      }
 | 
						|
      echo "<P>\n";
 | 
						|
 | 
						|
      if(count($imagedata[4])>0){
 | 
						|
	  $images[$imageindex] = $imagedata;
 | 
						|
 | 
						|
	  echo "<TABLE BORDER=5><TR><TD ALIGN=CENTER VALIGN=CENTER>\n";
 | 
						|
	  echo "<IMG SRC=\"scheme.php?";
 | 
						|
	  echo SID;
 | 
						|
	  echo "&genImage=$imageindex";
 | 
						|
	  echo "&time=" . time() . "\">\n";
 | 
						|
	  echo "</TD></TR></TABLE>\n";
 | 
						|
          $imageindex++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else{
 | 
						|
      echo "<EM>" . $errmsg  . "</EM><BR>\n";
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
?>
 | 
						|
<FORM NAME=mainform METHOD=POST ACTION="scheme.php">
 | 
						|
<SELECT NAME=progs onChange="setprog()">
 | 
						|
<OPTION VALUE="--menu--" SELECTED>TEST CASES
 | 
						|
<OPTION VALUE=reduce>reduce
 | 
						|
<OPTION VALUE=factorial>factorial
 | 
						|
<OPTION VALUE=call-cc>call-cc
 | 
						|
<OPTION VALUE=call-cc1>call-cc1
 | 
						|
<OPTION VALUE=tail-recursion>tail-recursion
 | 
						|
<OPTION VALUE=let-over-lambda>let-over-lambda
 | 
						|
<OPTION VALUE=list-misc>list-misc
 | 
						|
<OPTION VALUE=and-or>and-or
 | 
						|
<OPTION VALUE=primes>primes
 | 
						|
<OPTION VALUE=case>case
 | 
						|
<OPTION VALUE=cond>cond
 | 
						|
<OPTION VALUE=rootfinder>rootfinder
 | 
						|
<OPTION VALUE=plotter>plotter
 | 
						|
<OPTION VALUE=koch-curve>koch-curve
 | 
						|
<OPTION VALUE=eq-mem-association>eq-mem-association
 | 
						|
</SELECT>
 | 
						|
<BR>
 | 
						|
<TEXTAREA NAME=program ROWS=12 COLS=80>
 | 
						|
<? echo $program; ?>
 | 
						|
</TEXTAREA>
 | 
						|
<BR>
 | 
						|
<INPUT TYPE=SUBMIT VALUE="Evaluate">
 | 
						|
Show byte codes
 | 
						|
<INPUT TYPE=CHECKBOX  NAME=showbytecodes  <? echo $sbc; ?>>
 | 
						|
Show stack trace
 | 
						|
<INPUT TYPE=CHECKBOX  NAME=stacktrace     <? echo $stacktr; ?>>
 | 
						|
Load library
 | 
						|
<INPUT TYPE=CHECKBOX  NAME=loadlibrary    <? echo $loadlib; ?>>
 | 
						|
</FORM>
 | 
						|
 | 
						|
<? author(); ?>
 | 
						|
</BODY>
 | 
						|
</HTML>
 | 
						|
 |