function collect_symbols(){
		if( ! $this->length ){
			return null;
		}
		$Rule = $this->reset();
		do {
			if( $Rule->length !== 6 ){
				// empty rule most likely
				continue;
			}
			// collect rule name - guaranteed to be nontermainal
			$Name = $Rule->get_child( 1 );
			$n = $Name->evaluate();
			$nts[ $n ] = $n;
			
			// assume first nt is start symbol
			if( is_null( $this->startsymbol ) ){
				$this->startsymbol = $n;
			}
			
			$Expr = $Rule->get_child( 4 );
			// lists in Expression
			$List = $Expr->reset();
			do {
				// terms in list - may be terminal or nonterminal
				$Term = $List->reset();
				do {
					$s = $Term->evaluate();
					switch( $Term->length ){
					case 1:
						// "terminal" or terminal
						if( $s === P_EPSILON || $s === P_EOF ){
							// mandatory symbols already known
							break;
						}
						$ts[ $s ] = (string) $Term;
						break;
					case 3:
						// angle-bracketed <nonterminal>
						$nts[ $s ] = (string) $Term;
						break;
					}
				}
				while(
					$Term = $List->next()
				);
			}
			while( 
				$Expr->next() && $List = $Expr->next()
			);
			
		}
		while(
			$Rule = $this->next()
		);

		return array( $ts, $nts );
	}