summaryrefslogtreecommitdiffstats
path: root/distrib/android-emugl/host/tools/emugen/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'distrib/android-emugl/host/tools/emugen/Parser.cpp')
-rw-r--r--distrib/android-emugl/host/tools/emugen/Parser.cpp191
1 files changed, 191 insertions, 0 deletions
diff --git a/distrib/android-emugl/host/tools/emugen/Parser.cpp b/distrib/android-emugl/host/tools/emugen/Parser.cpp
new file mode 100644
index 000000000..0839f2023
--- /dev/null
+++ b/distrib/android-emugl/host/tools/emugen/Parser.cpp
@@ -0,0 +1,191 @@
+/*
+* 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 <vector>
+
+#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<std::string>* 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<std::string>& 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<std::string> 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<std::string> 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<std::string> 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;
+}