1 /*
2 * Copyright (c) 2016, Szymon Tomasz Stefanek
3 *
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
6 *
7 * This module contains functions for parsing and scanning C++ source files
8 */
9
10 #include "general.h"
11
12 #include "cxx_debug.h"
13 #include "cxx_keyword.h"
14 #include "cxx_token.h"
15 #include "cxx_token_chain.h"
16 #include "cxx_parser.h"
17 #include "cxx_scope.h"
18 #include "cxx_tag.h"
19
20 #include "dependency.h"
21 #include "selectors.h"
22
23 //
24 // ----------------------------------------------------------------------------
25 // Assumptions.
26 // ----------------------------------------------------------------------------
27 //
28 // - Parsing C/C++ is hard. Parsing C/C++ correctly without includes and
29 // without a complete preprocessor is close to impossible in the general
30 // case. Also ctags is not a compiler. This means that our parser must be
31 // a "guessing" parser. It's hopeless to try to decode the syntax of the
32 // language down to the last bit.
33 //
34 // - The input may contain syntax errors. This is because we don't have a full
35 // preprocessor and also because ctags is often used "online" in editors,
36 // while the user is typing. ctags should be tolerant and try to do its best
37 // even with syntax errors but:
38 // - Syntax errors that break the scope hierarchy should be detected and tag
39 // emission should probably be stopped. Correct tags in a broken hierarchy
40 // are useless (well, unless the hierarchy itself is ignored by the ctags
41 // user).
42 // - CTags should try to avoid emitting tags which involve syntax errors
43 //
44 // - There will always be pathologic cases. Don't cry, live with it.
45 //
46 // ----------------------------------------------------------------------------
47 // TODO LIST
48 // ----------------------------------------------------------------------------
49 //
50 // - In case of simple syntax error try to recover:
51 // Skip to the next ; without entering or exiting scopes.
52 // If this can be done then recovery is feasible.
53 // - Extension of each block/scope.
54 // - Unnamed blocks/scopes?
55 // - Handle syntax errors:
56 // - If a special switch is used then stop on detecting a syntax error
57 // (this is useful for code editors that frequently update tags for
58 // single files)
59 // - If the switch is not used then do NOT emit tags for a file on a syntax
60 // error [but do not stop execution of the whole program and continue on
61 // other files]
62 // For this purpose:
63 // - Do not emit tags until the end of the file, if scopes do not match we
64 // either screwed up something or the programmer did
65 // Maybe the cork api can be used for this?
66 //
67 // Handle variable declarations inside things like while() foreach() FOR() etc..
68 //
69 // - Friend classes.
70 // - Template parameters as field
71 // - Template specialisations (another field?)
72 // - Forward declarations might become tags
73
74
CParser(void)75 parserDefinition * CParser (void)
76 {
77 static const char * const extensions [] =
78 {
79 "c",
80 NULL
81 };
82
83 static selectLanguage selectors[] = { selectByObjectiveCKeywords, NULL };
84
85 parserDefinition* def = parserNew("C");
86
87 def->kindTable = cxxTagGetCKindDefinitions();
88 def->kindCount = cxxTagGetCKindDefinitionCount();
89 def->fieldTable = cxxTagGetCFieldDefinitionifiers();
90 def->fieldCount = cxxTagGetCFieldDefinitionifierCount();
91 def->extensions = extensions;
92 def->parser2 = cxxCParserMain;
93 def->initialize = cxxCParserInitialize;
94 def->finalize = cxxParserCleanup;
95 def->selectLanguage = selectors;
96 def->useCork = CORK_QUEUE|CORK_SYMTAB; // We use corking to block output until the end of file
97
98 return def;
99 }
100
CppParser(void)101 parserDefinition * CppParser (void)
102 {
103 static const char * const extensions [] =
104 {
105 "c++", "cc", "cp", "cpp", "cxx",
106 "h", "h++", "hh", "hp", "hpp", "hxx", "inl",
107 #ifndef CASE_INSENSITIVE_FILENAMES
108 "C", "H", "CPP", "CXX",
109 #endif
110 NULL
111 };
112 static parserDependency dependencies [] = {
113 { DEPTYPE_KIND_OWNER, "C" },
114 };
115
116 static selectLanguage selectors[] = { selectByObjectiveCKeywords, NULL };
117
118 parserDefinition* def = parserNew("C++");
119
120 def->dependencies = dependencies;
121 def->dependencyCount = ARRAY_SIZE (dependencies);
122 def->kindTable = cxxTagGetCPPKindDefinitions();
123 def->kindCount = cxxTagGetCPPKindDefinitionCount();
124 def->fieldTable = cxxTagGetCPPFieldDefinitionifiers();
125 def->fieldCount = cxxTagGetCPPFieldDefinitionifierCount();
126 def->extensions = extensions;
127 def->parser2 = cxxCppParserMain;
128 def->initialize = cxxCppParserInitialize;
129 def->finalize = cxxParserCleanup;
130 def->selectLanguage = selectors;
131 def->useCork = CORK_QUEUE|CORK_SYMTAB; // We use corking to block output until the end of file
132
133 return def;
134 }
135
CUDAParser(void)136 parserDefinition * CUDAParser (void)
137 {
138 static const char * const extensions [] =
139 {
140 "cu", "cuh",
141 NULL
142 };
143 static parserDependency dependencies [] = {
144 { DEPTYPE_KIND_OWNER, "C" },
145 };
146
147 parserDefinition* def = parserNew("CUDA");
148
149 def->dependencies = dependencies;
150 def->dependencyCount = ARRAY_SIZE (dependencies);
151 def->kindTable = cxxTagGetCUDAKindDefinitions();
152 def->kindCount = cxxTagGetCUDAKindDefinitionCount();
153 def->fieldTable = cxxTagGetCUDAFieldDefinitionifiers();
154 def->fieldCount = cxxTagGetCUDAFieldDefinitionifierCount();
155 def->extensions = extensions;
156 def->parser2 = cxxCUDAParserMain;
157 def->initialize = cxxCUDAParserInitialize;
158 def->finalize = cxxParserCleanup;
159 def->selectLanguage = NULL;
160 def->useCork = CORK_QUEUE|CORK_SYMTAB; // We use corking to block output until the end of file
161
162 return def;
163 }
164