/**
  * Extract macros from a string.
  *
  * @param array  $texts
  * @param array  $types
  * @param bool   $types['usermacros']
  * @param array  $types['macros'][][<macro_patterns>]
  * @param array  $types['macros_n'][][<macro_patterns>]
  * @param bool   $types['references']
  * @param bool   $types['lldmacros']
  * @param bool   $types['functionids']
  *
  * @return array
  */
 protected function extractMacros(array $texts, array $types)
 {
     $macros = [];
     $extract_usermacros = array_key_exists('usermacros', $types);
     $extract_macros = array_key_exists('macros', $types);
     $extract_macros_n = array_key_exists('macros_n', $types);
     $extract_references = array_key_exists('references', $types);
     $extract_lldmacros = array_key_exists('lldmacros', $types);
     $extract_functionids = array_key_exists('functionids', $types);
     if ($extract_usermacros) {
         $macros['usermacros'] = [];
         $user_macro_parser = new CUserMacroParser();
     }
     if ($extract_macros) {
         $macros['macros'] = [];
         foreach ($types['macros'] as $key => $macro_patterns) {
             $types['macros'][$key] = new CMacroParser($macro_patterns);
             $macros['macros'][$key] = [];
         }
     }
     if ($extract_macros_n) {
         $macros['macros_n'] = [];
         foreach ($types['macros_n'] as $key => $macro_patterns) {
             $types['macros_n'][$key] = new CMacroParser($macro_patterns, ['allow_reference' => true]);
             $macros['macros_n'][$key] = [];
         }
     }
     if ($extract_references) {
         $macros['references'] = [];
         $reference_parser = new CReferenceParser();
     }
     if ($extract_lldmacros) {
         $macros['lldmacros'] = [];
         $lld_macro_parser = new CLLDMacroParser();
     }
     if ($extract_functionids) {
         $macros['functionids'] = [];
         $functionid_parser = new CFunctionIdParser();
     }
     foreach ($texts as $text) {
         for ($pos = 0; isset($text[$pos]); $pos++) {
             if ($extract_usermacros && $user_macro_parser->parse($text, $pos) != CParser::PARSE_FAIL) {
                 $macros['usermacros'][$user_macro_parser->getMatch()] = null;
                 $pos += $user_macro_parser->getLength() - 1;
                 continue;
             }
             if ($extract_macros) {
                 foreach ($types['macros'] as $key => $macro_parser) {
                     if ($macro_parser->parse($text, $pos) != CParser::PARSE_FAIL) {
                         $macros['macros'][$key][$macro_parser->getMatch()] = true;
                         $pos += $macro_parser->getLength() - 1;
                         continue 2;
                     }
                 }
             }
             if ($extract_macros_n) {
                 foreach ($types['macros_n'] as $key => $macro_n_parser) {
                     if ($macro_n_parser->parse($text, $pos) != CParser::PARSE_FAIL) {
                         $macros['macros_n'][$key][$macro_n_parser->getMacro()][] = $macro_n_parser->getN();
                         $pos += $macro_n_parser->getLength() - 1;
                         continue 2;
                     }
                 }
             }
             if ($extract_references && $reference_parser->parse($text, $pos) != CParser::PARSE_FAIL) {
                 $macros['references'][$reference_parser->getMatch()] = null;
                 $pos += $reference_parser->getLength() - 1;
                 continue;
             }
             if ($extract_lldmacros && $lld_macro_parser->parse($text, $pos) != CParser::PARSE_FAIL) {
                 $macros['lldmacros'][$lld_macro_parser->getMatch()] = null;
                 $pos += $lld_macro_parser->getLength() - 1;
                 continue;
             }
             if ($extract_functionids && $functionid_parser->parse($text, $pos) != CParser::PARSE_FAIL) {
                 $macros['functionids'][$functionid_parser->getMatch()] = null;
                 $pos += $functionid_parser->getLength() - 1;
                 continue;
             }
         }
     }
     if ($extract_macros) {
         foreach ($types['macros'] as $key => $macro_parser) {
             $macros['macros'][$key] = array_keys($macros['macros'][$key]);
         }
     }
     return $macros;
 }