1 /****************************************************************************** 2 * 3 * 4 * 5 * Copyright (C) 1997-2015 by Dimitri van Heesch. 6 * 7 * Permission to use, copy, modify, and distribute this software and its 8 * documentation under the terms of the GNU General Public License is hereby 9 * granted. No representations are made about the suitability of this software 10 * for any purpose. It is provided "as is" without express or implied warranty. 11 * See the GNU General Public License for more details. 12 * 13 * Documents produced by Doxygen are derivative works derived from the 14 * input used in their production; they are not affected by this license. 15 * 16 */ 17 18 #ifndef PARSERINTF_H 19 #define PARSERINTF_H 20 21 #include <functional> 22 #include <memory> 23 #include <map> 24 #include <string> 25 26 #include "types.h" 27 #include "containers.h" 28 29 class Entry; 30 class FileDef; 31 class CodeOutputInterface; 32 class MemberDef; 33 class Definition; 34 class ClangTUParser; 35 36 /** \brief Abstract interface for outline parsers. 37 * 38 * By implementing the methods of this interface one can add 39 * a new language parser to doxygen. The parser implementation can make use of the 40 * comment block parser to parse the contents of special comment blocks. 41 */ 42 class OutlineParserInterface 43 { 44 public: ~OutlineParserInterface()45 virtual ~OutlineParserInterface() {} 46 47 /** Parses a single input file with the goal to build an Entry tree. 48 * @param[in] fileName The full name of the file. 49 * @param[in] fileBuf The contents of the file (zero terminated). 50 * @param[in,out] root The root of the tree of Entry *nodes 51 * representing the information extracted from the file. 52 * @param[in] clangParser The clang translation unit parser object 53 * or nullptr if disabled. 54 */ 55 virtual void parseInput(const QCString &fileName, 56 const char *fileBuf, 57 const std::shared_ptr<Entry> &root, 58 ClangTUParser *clangParser) = 0; 59 60 /** Returns TRUE if the language identified by \a extension needs 61 * the C preprocessor to be run before feed the result to the input 62 * parser. 63 * @see parseInput() 64 */ 65 virtual bool needsPreprocessing(const QCString &extension) const = 0; 66 67 /** Callback function called by the comment block scanner. 68 * It provides a string \a text containing the prototype of a function 69 * or variable. The parser should parse this and store the information 70 * in the Entry node that corresponds with the node for which the 71 * comment block parser was invoked. 72 */ 73 virtual void parsePrototype(const QCString &text) = 0; 74 75 }; 76 77 /** \brief Abstract interface for code parsers. 78 * 79 * By implementing the methods of this interface one can add 80 * a new language parser to doxygen. This interface is used for 81 * syntax highlighting, but also to extract cross references and call graphs. 82 */ 83 class CodeParserInterface 84 { 85 public: ~CodeParserInterface()86 virtual ~CodeParserInterface() {} 87 88 /** Parses a source file or fragment with the goal to produce 89 * highlighted and cross-referenced output. 90 * @param[in] codeOutIntf Abstract interface for writing the result. 91 * @param[in] scopeName Name of scope to which the code belongs. 92 * @param[in] input Actual code in the form of a string 93 * @param[in] lang The programming language of the code fragment. 94 * @param[in] isExampleBlock TRUE iff the code is part of an example. 95 * @param[in] exampleName Name of the example. 96 * @param[in] fileDef File definition to which the code 97 * is associated. 98 * @param[in] startLine Starting line in case of a code fragment. 99 * @param[in] endLine Ending line of the code fragment. 100 * @param[in] inlineFragment Code fragment that is to be shown inline 101 * as part of the documentation. 102 * @param[in] memberDef Member definition to which the code 103 * is associated (non null in case of an inline fragment 104 * for a member). 105 * @param[in] showLineNumbers if set to TRUE and also fileDef is not 0, 106 * line numbers will be added to the source fragment 107 * @param[in] searchCtx context under which search data has to be stored. 108 * @param[in] collectXRefs collect cross-reference relations. 109 */ 110 virtual void parseCode(CodeOutputInterface &codeOutIntf, 111 const QCString &scopeName, 112 const QCString &input, 113 SrcLangExt lang, 114 bool isExampleBlock, 115 const QCString &exampleName=QCString(), 116 const FileDef *fileDef=0, 117 int startLine=-1, 118 int endLine=-1, 119 bool inlineFragment=FALSE, 120 const MemberDef *memberDef=0, 121 bool showLineNumbers=TRUE, 122 const Definition *searchCtx=0, 123 bool collectXRefs=TRUE 124 ) = 0; 125 126 /** Resets the state of the code parser. 127 * Since multiple code fragments can together form a single example, an 128 * explicit function is used to reset the code parser state. 129 * @see parseCode() 130 */ 131 virtual void resetCodeParserState() = 0; 132 133 }; 134 135 //----------------------------------------------------------------------------- 136 137 using OutlineParserFactory = std::function<std::unique_ptr<OutlineParserInterface>()>; 138 using CodeParserFactory = std::function<std::unique_ptr<CodeParserInterface>()>; 139 140 /** \brief Manages programming language parsers. 141 * 142 * This class manages the language parsers in the system. One can 143 * register parsers, and obtain a parser given a file extension. 144 */ 145 class ParserManager 146 { 147 148 struct ParserPair 149 { ParserPairParserPair150 ParserPair(OutlineParserFactory opf, CodeParserFactory cpf, const QCString &pn) 151 : outlineParserFactory(opf), codeParserFactory(cpf), parserName(pn) 152 { 153 } 154 155 OutlineParserFactory outlineParserFactory; 156 CodeParserFactory codeParserFactory; 157 QCString parserName; 158 }; 159 160 public: 161 /** Create the parser manager 162 * @param outlineParserFactory the fallback outline parser factory to use for unknown extensions 163 * @param codeParserFactory the fallback code parser factory to use for unknown extensions 164 */ ParserManager(OutlineParserFactory outlineParserFactory,CodeParserFactory codeParserFactory)165 ParserManager(OutlineParserFactory outlineParserFactory, 166 CodeParserFactory codeParserFactory) 167 : m_defaultParsers(outlineParserFactory,codeParserFactory, QCString()) 168 { 169 } 170 171 /** Registers an additional parser. 172 * @param[in] name A symbolic name of the parser, i.e. "c", 173 * "python", "fortran", "vhdl", ... 174 * @param[in] outlineParserFactory A factory method to create a language parser (scanner) that 175 * is to be used for the given name. 176 * @param[in] codeParserFactory A factory method to create a code parser that is to be used 177 * for the given name. 178 */ registerParser(const QCString & name,OutlineParserFactory outlineParserFactory,CodeParserFactory codeParserFactory)179 void registerParser(const QCString &name,OutlineParserFactory outlineParserFactory, 180 CodeParserFactory codeParserFactory) 181 { 182 m_parsers.emplace(name.str(),ParserPair(outlineParserFactory,codeParserFactory,name)); 183 } 184 185 /** Registers a file \a extension with a parser with name \a parserName. 186 * Returns TRUE if the extension was successfully registered. 187 */ registerExtension(const QCString & extension,const QCString & parserName)188 bool registerExtension(const QCString &extension, const QCString &parserName) 189 { 190 if (parserName.isEmpty() || extension.isEmpty()) return FALSE; 191 192 const auto &parserIt = m_parsers.find(parserName.str()); 193 if (parserIt == m_parsers.end()) return FALSE; 194 195 auto extensionIt = m_extensions.find(extension.str()); 196 if (extensionIt != m_extensions.end()) // extension already exists 197 { 198 m_extensions.erase(extensionIt); // remove it (e.g. user specified extension overrules built in one) 199 } 200 m_extensions.emplace(extension.str(),parserIt->second); // add new mapping 201 return TRUE; 202 } 203 204 /** Gets the interface to the parser associated with a given \a extension. 205 * If there is no parser explicitly registered for the supplied extension, 206 * the interface to the default parser will be returned. 207 */ getOutlineParser(const QCString & extension)208 std::unique_ptr<OutlineParserInterface> getOutlineParser(const QCString &extension) 209 { 210 return getParsers(extension).outlineParserFactory(); 211 } 212 213 /** Gets the interface to the parser associated with a given \a extension. 214 * If there is no parser explicitly registered for the supplied extension, 215 * the interface to the default parser will be returned. 216 */ getCodeParser(const QCString & extension)217 std::unique_ptr<CodeParserInterface> getCodeParser(const QCString &extension) 218 { 219 auto factory = getCodeParserFactory(extension); 220 return factory(); 221 } 222 223 /** Get the factory for create code parser objects with a given \a extension. */ getCodeParserFactory(const QCString & extension)224 CodeParserFactory &getCodeParserFactory(const QCString &extension) 225 { 226 return getParsers(extension).codeParserFactory; 227 } 228 229 /** Gets the name of the parser associated with given \a extension. 230 * If there is no parser explicitly registered for the supplied extension, 231 * te empty string will be reurned. 232 */ getParserName(const QCString & extension)233 QCString getParserName(const QCString &extension) 234 { 235 return getParsers(extension).parserName; 236 } 237 238 private: getParsers(const QCString & extension)239 ParserPair &getParsers(const QCString &extension) 240 { 241 QCString ext = extension.lower(); 242 if (ext.isEmpty()) ext=".no_extension"; 243 auto it = m_extensions.find(ext.data()); 244 if (it==m_extensions.end() && ext.length()>4) 245 { 246 it = m_extensions.find(ext.left(4).data()); 247 } 248 return it!=m_extensions.end() ? it->second : m_defaultParsers; 249 } 250 251 std::map<std::string,ParserPair> m_parsers; 252 std::map<std::string,ParserPair &> m_extensions; 253 ParserPair m_defaultParsers; 254 }; 255 256 #endif 257