function make_rule( $nt, array $rhs ){
		
		if( ! isset($this->uindex) || ! isset($this->ntindex) ){
			$this->rebuild_index();
		}
		
		// explicit goal rule ??
		if( end($rhs) === P_EOF ){
			// trigger_error("Do not specify P_EOF explicitly in grammar", E_USER_WARNING );
			$this->goal = $nt;
			$this->rules[ -2 ] = array( P_GOAL, array( $nt ) );
			$this->rebuild_index();
		}
		// guess start symbol as first in grammar
		else if( is_null( $this->start_symbol() ) ){
			$this->start_symbol( $nt );
		}
		
		reset( $rhs );
		$sig = self::rule_signature( $nt, $rhs );
		
		// return existing if possible
		if( isset($this->uindex[$sig]) ){
			return $this->rules[ $this->uindex[$sig] ];
		}
		// else create new rule
		$rule = array( $nt, $rhs );
	
		// register globally
		$this->rules[ $this->i ] = $rule;
		$this->uindex[$sig] = $this->i;
		$this->ntindex[$nt][] = $this->i;
		$this->i += 2;
	
		// register symbols
		if( isset($this->ts[$nt] ) ){
			// not terminal after all
			unset( $this->ts[$nt] );
		}
		$this->nts[ $nt ] = $nt;
		// assume rhs all terminals until identified as not
		foreach( $rhs as $s ){
			is_array( $s ) and $s = $s[0];
			if( !isset($this->nts[$s]) ){
				$this->ts[ $s ] = $s;
			}
		}
		return $rule;
	}