major revamp, fully qualified names (FQName) used throughout lexer/parser.
diff --git a/FQName.cpp b/FQName.cpp
new file mode 100644
index 0000000..cabe503
--- /dev/null
+++ b/FQName.cpp
@@ -0,0 +1,93 @@
+#include "FQName.h"
+
+#include <android-base/logging.h>
+#include <regex>
+
+#define RE_COMPONENT    "[a-zA-Z_][a-zA-Z_0-9]*"
+#define RE_PATH         RE_COMPONENT "([.]" RE_COMPONENT ")*"
+#define RE_VERSION      "@[0-9]+[.][0-9]+"
+
+static const std::regex kRE1("(" RE_PATH ")(" RE_VERSION ")?::(" RE_PATH ")");
+static const std::regex kRE2("(" RE_VERSION ")::(" RE_PATH ")");
+static const std::regex kRE3(RE_PATH);
+
+namespace android {
+
+FQName::FQName(const std::string &s)
+    : mValid(false) {
+    setTo(s);
+}
+
+bool FQName::isValid() const {
+    return mValid;
+}
+
+bool FQName::setTo(const std::string &s) {
+    mPackage.clear();
+    mVersion.clear();
+    mName.clear();
+
+    mValid = true;
+
+    std::smatch match;
+    if (std::regex_match(s, match, kRE1)) {
+        CHECK_EQ(match.size(), 6u);
+
+        mPackage = match.str(1);
+        mVersion = match.str(3);
+        mName = match.str(4);
+    } else if (std::regex_match(s, match, kRE2)) {
+        CHECK_EQ(match.size(), 4u);
+
+        mVersion = match.str(1);
+        mName = match.str(2);
+    } else if (std::regex_match(s, match, kRE3)) {
+        mName = match.str(0);
+    } else {
+        mValid = false;
+    }
+
+    return isValid();
+}
+
+std::string FQName::package() const {
+    return mPackage;
+}
+
+std::string FQName::version() const {
+    return mVersion;
+}
+
+std::string FQName::name() const {
+    return mName;
+}
+
+void FQName::applyDefaults(
+        const std::string &defaultPackage,
+        const std::string &defaultVersion) {
+    if (mPackage.empty()) {
+        mPackage = defaultPackage;
+    }
+
+    if (mVersion.empty()) {
+        mVersion = defaultVersion;
+    }
+}
+
+std::string FQName::debugString() const {
+    CHECK(mValid);
+
+    std::string out = "FQName(";
+    out.append(mPackage);
+    out.append(mVersion);
+    if (!mPackage.empty() || !mVersion.empty()) {
+        out.append("::");
+    }
+    out.append(mName);
+    out.append(")");
+
+    return out;
+}
+
+}  // namespace android
+