'Parse a spec out of the input. If a spec is supplied, initialize
and return it instead of creating a new one.'

def spec(self, name):

    if name:
        (spec_namespace, dot, spec_name) = name.rpartition('.')
        if (not spec_namespace):
            spec_namespace = None
        self.check_identifier(spec_name)
    else:
        spec_namespace = None
        spec_name = None
    spec = Spec.__new__(Spec)
    spec.name = spec_name
    spec.versions = VersionList()
    spec.variants = VariantMap(spec)
    spec.architecture = None
    spec.compiler = None
    spec.external_path = None
    spec.external_module = None
    spec.compiler_flags = FlagMap(spec)
    spec._dependents = DependencyMap(spec)
    spec._dependencies = DependencyMap(spec)
    spec.namespace = spec_namespace
    spec._hash = None
    spec._cmp_key_cache = None
    spec._normal = False
    spec._concrete = False
    added_version = False
    while self.next:
        if self.accept(AT):
            vlist = self.version_list()
            for version in vlist:
                spec._add_version(version)
            added_version = True
        elif self.accept(ON):
            name = self.variant()
            spec.variants[name] = BoolValuedVariant(name, True)
        elif self.accept(OFF):
            name = self.variant()
            spec.variants[name] = BoolValuedVariant(name, False)
        elif self.accept(PCT):
            spec._set_compiler(self.compiler())
        elif self.accept(ID):
            self.previous = self.token
            if self.accept(EQ):
                self.expect(VAL)
                spec._add_flag(self.previous.value, self.token.value)
                self.previous = None
            else:
                self.push_tokens([self.token])
                self.previous = None
                break
        elif self.accept(HASH):
            hash_spec = self.spec_by_hash()
            if hash_spec.satisfies(spec):
                spec = hash_spec
                break
            else:
                raise InvalidHashError(spec, hash_spec.dag_hash())
        else:
            break
    if ((not added_version) and (not spec._hash)):
        spec.versions = VersionList(':')
    return spec
