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;
	}
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;
	}
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 ; }
Factory method, ensures unique rules
@param mixed scalar non-terminal symbol
@param array list of symbols in right hand side
@return array
Factory method ensures unique rules