/* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Parser.h" #include #define WHITESPACE " \t\n" // Parse the |input| string as a list of type-specific tokens. // This tokenizes the input, using whitespace as separators and '*' as // a single token too. On success, return true and sets |*out| to the // list of tokens. On failure, return false. // // Example: 'const char**foo' -> ['const', 'char', '*', '*', 'foo'] // static bool parseTypeTokens(const std::string& input, std::vector* out, std::string* error) { out->clear(); size_t pos = 0U; // Parse all tokens in the input, treat '*' as a single token. // I.e. for (;;) { // skip leading whitespace. pos = input.find_first_not_of(WHITESPACE, pos); if (pos == std::string::npos) { break; // end of parse. } // If this is a star, ensure it follows a type name. // otherwise treat it as part of the final type. if (input[pos] == '*') { out->push_back(std::string("*")); pos += 1U; continue; } // find end of type/token. size_t end = input.find_first_of(WHITESPACE "*", pos); if (end == std::string::npos) { end = input.size(); } std::string str = input.substr(pos, end - pos); if (str.size() == 0) { // Sanity check: should not happen. if (error != NULL) { *error = "Unexpected empty token !?"; } return false; } out->push_back(str); pos = end; } if (error != NULL) { // Sanity check: require non-empty input if (out->empty()) { *error = "Empty parameter declaration!"; return false; } // Sanity check: There must be base type name before any '*' for (size_t n = 0; n < out->size(); ++n) { std::string& token = (*out)[n]; if (token == "*") { *error = "Unexpected '*' before type name"; return false; } else if (token != "const") { break; } } } return true; } // Given |tokens|, an input vector of strings, join the first |count| items // into a normalized type string, and return it. static std::string buildTypeString(const std::vector& tokens, size_t count) { std::string result; for (size_t n = 0; n < count; ++n) { const std::string& token = tokens[n]; if (n > 0 && token != "*") { result.append(" "); } result.append(token); } return result; } std::string normalizeTypeDeclaration(const std::string& input) { std::vector tokens; if (!parseTypeTokens(input, &tokens, NULL)) { return ""; } return buildTypeString(tokens, tokens.size()); } bool parseTypeDeclaration(const std::string& input, std::string* typeName, std::string* error) { // The type name can be made of several tokens, e.g. 'unsigned int' // use an array to store them, and a count variable. Each item can be // one of '*', 'const' or a type name component (e.g. 'struct', 'unsigned') std::vector tokens; if (!parseTypeTokens(input, &tokens, error)) { return false; } // Sanity check, there must be a least one non-special tokens. size_t nonSpecialCount = 0; for (size_t n = 0; n < tokens.size(); ++n) { if (tokens[n] != "*" && tokens[n] != "const") { nonSpecialCount++; } } if (nonSpecialCount == 0) { *error = "Missing type name"; return false; } // Build the type name from all tokens before it. *typeName = buildTypeString(tokens, tokens.size()); return true; } bool parseParameterDeclaration(const std::string& param, std::string* typeName, std::string* variableName, std::string* error) { std::vector tokens; if (!parseTypeTokens(param, &tokens, error)) { return false; } // Sanity check, there must be a least two non-special tokens. size_t nonSpecialCount = 0; for (size_t n = 0; n < tokens.size(); ++n) { if (tokens[n] != "*" && tokens[n] != "const") { nonSpecialCount++; } } if (nonSpecialCount == 0) { *error = "Missing type name"; return false; } if (nonSpecialCount == 1) { *error = "Missing variable name"; return false; } // Sanity check: variable name must not be followed by 'const' or '*' const std::string& lastToken = tokens[tokens.size() - 1U]; if (lastToken == "*") { *error = "Extra '*' after variable name"; return false; } if (lastToken == "const") { *error = "Extra 'const' after variable name"; return false; } // Extract the variable name as the last token. if (variableName) { *variableName = lastToken; } // Build the type name from all tokens before it. *typeName = buildTypeString(tokens, tokens.size() - 1U); return true; }