# File lib/chronic/chronic.rb, line 41
    def parse(text, specified_options = {})
      # get options and set defaults if necessary
      default_options = {:context => :future,
                         :now => Time.now,
                         :guess => true,
                         :ambiguous_time_range => 6}
      options = default_options.merge specified_options
            
      # ensure the specified options are valid
      specified_options.keys.each do |key|
        default_options.keys.include?(key) || raise(InvalidArgumentException, "#{key} is not a valid option key.")
      end
      [:past, :future].include?(options[:context]) || raise(InvalidArgumentException, "Invalid value '#{options[:context]}' for :context specified. Valid values are :past and :future.")
      
      # store now for later =)
      @now = options[:now]
      
      # put the text into a normal format to ease scanning
      text = self.pre_normalize(text)
          
      # get base tokens for each word
      @tokens = self.base_tokenize(text)
    
      # scan the tokens with each token scanner
      [Repeater].each do |tokenizer|
        @tokens = tokenizer.scan(@tokens, options)
      end
      
      [Grabber, Pointer, Scalar, Ordinal, Separator].each do |tokenizer|
        @tokens = tokenizer.scan(@tokens)
      end
      
      # strip any non-tagged tokens
      @tokens = @tokens.select { |token| token.tagged? }
      
      if @debug
        puts "+---------------------------------------------------"
        puts "| " + @tokens.to_s
        puts "+---------------------------------------------------"
      end
      
      # do the heavy lifting
      begin
        span = self.tokens_to_span(@tokens, options)
      rescue
        raise
        return nil
      end
      
      # guess a time within a span if required
      if options[:guess]
        return self.guess(span)
      else
        return span
      end
    end