public function parse($str)
	{
		$str      = str_replace("\r", "", $str);
		$len      = strlen($str);
		$tag_open = false;
		$tag_text = '';
		$tag      = '';

		// set the document as the current tag.
		$this->current_tag = $this;

		for($i=0; $i<$len; ++$i)
		{
			if($str[$i] === '[')
			{
				if($tag_open)
					$tag_text .= '[' . $tag;

				$tag_open = true;
				$tag      = '';
			}
			else if($str[$i] === ']' && $tag_open)
			{
				if($tag !== '')
				{
					$bits        = preg_split('/([ =])/', trim($tag), 2, PREG_SPLIT_DELIM_CAPTURE);
					$tag_attrs   = (isset($bits[2]) ? $bits[1] . $bits[2] : '');
					$tag_closing = ($bits[0][0] === '/');
					$tag_name    = ($bits[0][0] === '/' ? substr($bits[0], 1) : $bits[0]);

					if(isset($this->bbcodes[$tag_name]))
					{
						$this->tag_text($tag_text);
						$tag_text = '';

						if($tag_closing)
						{
							if(!$this->tag_close($tag_name))
								$tag_text = "[{$tag}]";
						}
						else
						{
							if(!$this->tag_open($tag_name, $this->parse_attribs($tag_attrs)))
								$tag_text = "[{$tag}]";
						}
					}
					else
						$tag_text .= "[{$tag}]";
				}
				else
					$tag_text .= '[]';

				$tag_open = false;
				$tag      = '';
			}
			else if($tag_open)
				$tag .= $str[$i];
			else
				$tag_text .= $str[$i];
		}

		$this->tag_text($tag_text);

		if($this->throw_errors && !$this->current_tag instanceof Node_Container_Document)
			throw new Exception_MissingEndTag("Missing closing tag for tag [{$this->current_tag->tag()}]");

		return $this;
	}