1 /*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "Parser.h"
17
18 #include <vector>
19
20 #define WHITESPACE " \t\n"
21
22 // Parse the |input| string as a list of type-specific tokens.
23 // This tokenizes the input, using whitespace as separators and '*' as
24 // a single token too. On success, return true and sets |*out| to the
25 // list of tokens. On failure, return false.
26 //
27 // Example: 'const char**foo' -> ['const', 'char', '*', '*', 'foo']
28 //
parseTypeTokens(const std::string & input,std::vector<std::string> * out,std::string * error)29 static bool parseTypeTokens(const std::string& input,
30 std::vector<std::string>* out,
31 std::string* error) {
32 out->clear();
33 size_t pos = 0U;
34
35 // Parse all tokens in the input, treat '*' as a single token.
36 // I.e.
37 for (;;) {
38 // skip leading whitespace.
39 pos = input.find_first_not_of(WHITESPACE, pos);
40 if (pos == std::string::npos) {
41 break; // end of parse.
42 }
43
44 // If this is a star, ensure it follows a type name.
45 // otherwise treat it as part of the final type.
46 if (input[pos] == '*') {
47 out->push_back(std::string("*"));
48 pos += 1U;
49 continue;
50 }
51
52 // find end of type/token.
53 size_t end = input.find_first_of(WHITESPACE "*", pos);
54 if (end == std::string::npos) {
55 end = input.size();
56 }
57
58 std::string str = input.substr(pos, end - pos);
59 if (str.size() == 0) {
60 // Sanity check: should not happen.
61 if (error != NULL) {
62 *error = "Unexpected empty token !?";
63 }
64 return false;
65 }
66
67 out->push_back(str);
68 pos = end;
69 }
70
71 if (error != NULL) {
72 // Sanity check: require non-empty input
73 if (out->empty()) {
74 *error = "Empty parameter declaration!";
75 return false;
76 }
77
78 // Sanity check: There must be base type name before any '*'
79 for (size_t n = 0; n < out->size(); ++n) {
80 std::string& token = (*out)[n];
81 if (token == "*") {
82 *error = "Unexpected '*' before type name";
83 return false;
84 } else if (token != "const") {
85 break;
86 }
87 }
88 }
89
90 return true;
91 }
92
93 // Given |tokens|, an input vector of strings, join the first |count| items
94 // into a normalized type string, and return it.
buildTypeString(const std::vector<std::string> & tokens,size_t count)95 static std::string buildTypeString(const std::vector<std::string>& tokens,
96 size_t count) {
97 std::string result;
98
99 for (size_t n = 0; n < count; ++n) {
100 const std::string& token = tokens[n];
101 if (n > 0 && token != "*") {
102 result.append(" ");
103 }
104 result.append(token);
105 }
106 return result;
107 }
108
109
normalizeTypeDeclaration(const std::string & input)110 std::string normalizeTypeDeclaration(const std::string& input) {
111 std::vector<std::string> tokens;
112 if (!parseTypeTokens(input, &tokens, NULL)) {
113 return "";
114 }
115 return buildTypeString(tokens, tokens.size());
116 }
117
parseTypeDeclaration(const std::string & input,std::string * typeName,std::string * error)118 bool parseTypeDeclaration(const std::string& input,
119 std::string* typeName,
120 std::string* error) {
121 // The type name can be made of several tokens, e.g. 'unsigned int'
122 // use an array to store them, and a count variable. Each item can be
123 // one of '*', 'const' or a type name component (e.g. 'struct', 'unsigned')
124 std::vector<std::string> tokens;
125
126 if (!parseTypeTokens(input, &tokens, error)) {
127 return false;
128 }
129
130 // Sanity check, there must be a least one non-special tokens.
131 size_t nonSpecialCount = 0;
132 for (size_t n = 0; n < tokens.size(); ++n) {
133 if (tokens[n] != "*" && tokens[n] != "const") {
134 nonSpecialCount++;
135 }
136 }
137 if (nonSpecialCount == 0) {
138 *error = "Missing type name";
139 return false;
140 }
141 // Build the type name from all tokens before it.
142 *typeName = buildTypeString(tokens, tokens.size());
143 return true;
144 }
145
146
parseParameterDeclaration(const std::string & param,std::string * typeName,std::string * variableName,std::string * error)147 bool parseParameterDeclaration(const std::string& param,
148 std::string* typeName,
149 std::string* variableName,
150 std::string* error) {
151 std::vector<std::string> tokens;
152
153 if (!parseTypeTokens(param, &tokens, error)) {
154 return false;
155 }
156
157 // Sanity check, there must be a least two non-special tokens.
158 size_t nonSpecialCount = 0;
159 for (size_t n = 0; n < tokens.size(); ++n) {
160 if (tokens[n] != "*" && tokens[n] != "const") {
161 nonSpecialCount++;
162 }
163 }
164 if (nonSpecialCount == 0) {
165 *error = "Missing type name";
166 return false;
167 }
168 if (nonSpecialCount == 1) {
169 *error = "Missing variable name";
170 return false;
171 }
172
173 // Sanity check: variable name must not be followed by 'const' or '*'
174 const std::string& lastToken = tokens[tokens.size() - 1U];
175 if (lastToken == "*") {
176 *error = "Extra '*' after variable name";
177 return false;
178 }
179 if (lastToken == "const") {
180 *error = "Extra 'const' after variable name";
181 return false;
182 }
183
184 // Extract the variable name as the last token.
185 if (variableName) {
186 *variableName = lastToken;
187 }
188 // Build the type name from all tokens before it.
189 *typeName = buildTypeString(tokens, tokens.size() - 1U);
190 return true;
191 }
192