diff options
author | Joakim Sindholt <opensource@zhasha.com> | 2009-10-15 03:55:38 +0200 |
---|---|---|
committer | Joakim Sindholt <opensource@zhasha.com> | 2009-10-15 03:55:38 +0200 |
commit | 5ddb8d65093f5d7974da646c6055211cb61169e1 (patch) | |
tree | 0319fea06366645a14a4f08fec381eefa148bd71 | |
parent | bcdc0c6501d22d5041d57cc47d289e7943bf4639 (diff) |
Add parsers directory for future parsers
-rw-r--r-- | parsers/rules-ng.xsd | 413 | ||||
-rwxr-xr-x | parsers/rulesng.py | 158 | ||||
-rwxr-xr-x | parsers/rulesngCollectors.py | 281 |
3 files changed, 852 insertions, 0 deletions
diff --git a/parsers/rules-ng.xsd b/parsers/rules-ng.xsd new file mode 100644 index 0000000..c387afd --- /dev/null +++ b/parsers/rules-ng.xsd @@ -0,0 +1,413 @@ +<?xml version="1.0" encoding="UTF-8"?> +<schema xmlns="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://nouveau.freedesktop.org/" + xmlns:rng="http://nouveau.freedesktop.org/" + elementFormDefault="qualified"> + + <annotation> + <documentation> + An updated version of the old rules.xml file from the + RivaTV project. Specifications by Pekka Paalanen, + preliminary attempt by KoalaBR, + first working version by Jakob Bornecrantz. + For specifications, see the file rules-ng-format.txt + in Nouveau CVS module 'rules-ng'. + </documentation> + <documentation>Version 0.1</documentation> + </annotation> + + + <!-- Elements --> + + <element name="value" type="rng:valueType" /> + <element name="bitfield" type="rng:bitfieldType" /> + <element name="bitset" type="rng:bitsetType" /> + <element name="reg32" type="rng:registerType" /> + <element name="reg8" type="rng:registerType" /> + <element name="array" type="rng:arrayType" /> + <element name="stripe" type="rng:stripeType" /> + <element name="enum" type="rng:enumType" /> + <element name="database" type="rng:databaseType" /> + <element name="group" type="rng:groupType" /> + <element name="variant" type="rng:variantType" /> + <element name="domain" type="rng:domainType" /> + <element name="translation" type="rng:translationType" /> + <element name="use-bitset" type="rng:refType" /> + <element name="use-group" type="rng:refType" /> + <element name="use-enum" type="rng:refType" /> + + <!-- Documentation elements --> + + <!-- FIXME: allowed only one per parent element --> + <element name="brief" type="rng:briefType" /> + + <element name="doc" type="rng:docType" /> + <element name="b" type="rng:textformatType" /> + <element name="i" type="rng:textformatType" /> + <element name="u" type="rng:textformatType" /> + <element name="code" type="rng:textcodeType" /> + <element name="ul" type="rng:listType" /> + <element name="ol" type="rng:listType" /> + <element name="li" type="rng:listitemType" /> + + + + <!-- Database element types --> + + <complexType name="databaseType"> + <annotation> + <documentation>databaseType</documentation> + </annotation> + <sequence> + <element ref="rng:domain" /> + <choice minOccurs="0" maxOccurs="unbounded"> + <group ref="rng:regarrayGroup" /> + <group ref="rng:docGroup" /> + <element ref="rng:variant" /> + <element ref="rng:enum" /> + <element ref="rng:group" /> + <element ref="rng:bitset" /> + </choice> + </sequence> + </complexType> + + <complexType name="variantType"> + <annotation> + <documentation>variantType</documentation> + </annotation> + <choice minOccurs="0" maxOccurs="unbounded"> + <group ref="rng:regarrayGroup" /> + <group ref="rng:docGroup" /> + <element ref="rng:variant" /> + <element ref="rng:use-group" /> + </choice> + <attribute name="id" type="NMTOKENS" use="required" /> + </complexType> + + <complexType name="enumType"> + <annotation> + <documentation>enumType</documentation> + </annotation> + <choice maxOccurs="unbounded"> + <element ref="rng:value" /> + <group ref="rng:docGroup" /> + </choice> + <attribute name="name" type="rng:Cname" use="required" /> + </complexType> + + <complexType name="valueType"> + <annotation> + <documentation>valueType</documentation> + </annotation> + <choice minOccurs="0" maxOccurs="unbounded"> + <group ref="rng:docGroup" /> + </choice> + <attribute name="name" type="rng:objName" use="required" /> + <attribute name="value" type="string" use="required" /> + </complexType> + + <complexType name="arrayType"> + <annotation> + <documentation>arrayType</documentation> + </annotation> + <choice minOccurs="0" maxOccurs="unbounded"> + <group ref="rng:regarrayGroup" minOccurs="0" /> + <group ref="rng:docGroup" /> + <element ref="rng:use-group" /> + </choice> + <attribute name="name" type="rng:objName" use="required" /> + <attributeGroup ref="rng:basicArrayAttributes" /> + <attribute name="type" type="rng:Type" default="hex" /> + </complexType> + + <complexType name="stripeType"> + <annotation> + <documentation>stripeType</documentation> + </annotation> + <choice minOccurs="0" maxOccurs="unbounded"> + <group ref="rng:regarrayGroup" minOccurs="0" /> + <group ref="rng:docGroup" /> + <element ref="rng:use-group" /> + </choice> + <attribute name="name" type="rng:objName" use="optional" /> + <attributeGroup ref="rng:basicArrayAttributes" /> + </complexType> + + <complexType name="bitfieldType"> + <annotation> + <documentation>bitfieldType</documentation> + </annotation> + <choice minOccurs="0" maxOccurs="unbounded"> + <group ref="rng:docGroup" /> + <element ref="rng:use-enum" /> + <element ref="rng:value" maxOccurs="unbounded" /> + </choice> + <attribute name="name" type="rng:objName" use="required" /> + <attribute name="high" type="nonNegativeInteger" + use="required" /> + <attribute name="low" type="nonNegativeInteger" + use="required" /> + <attribute name="type" type="rng:Type" default="hex" /> + </complexType> + + <complexType name="bitsetType"> + <annotation> + <documentation>bitsetType</documentation> + </annotation> + <choice maxOccurs="unbounded"> + <element ref="rng:bitfield" /> + <group ref="rng:docGroup" /> + </choice> + <attribute name="name" type="rng:Cname" use="required" /> + </complexType> + + <complexType name="groupType"> + <annotation> + <documentation>groupType</documentation> + </annotation> + <choice maxOccurs="unbounded"> + <group ref="rng:regarrayGroup" /> + <group ref="rng:docGroup" /> + <element ref="rng:use-group" /> + </choice> + <attribute name="name" type="rng:Cname" use="required" /> + <attribute name="prepend" type="rng:objName" /> + </complexType> + + <complexType name="refType"> + <annotation> + <documentation>refType</documentation> + </annotation> + <attribute name="ref" type="rng:Cname" use="required" /> + </complexType> + + <complexType name="domainType"> + <annotation> + <documentation>domainType</documentation> + </annotation> + <attribute name="name" type="rng:Cname" use="required" /> + </complexType> + + <complexType name="registerType"> + <annotation> + <documentation> + registerType used by both reg8 and reg32 + </documentation> + </annotation> + <choice minOccurs="0" maxOccurs="1"> + <choice minOccurs="0" maxOccurs="unbounded"> + <element ref="rng:value" /> + <element ref="rng:use-enum" /> + <group ref="rng:docGroup" /> + </choice> + <choice minOccurs="0" maxOccurs="unbounded"> + <element ref="rng:bitfield" /> + <element ref="rng:use-bitset" /> + <group ref="rng:docGroup" /> + </choice> + </choice> + <attribute name="name" type="rng:objName" use="required" /> + <attribute name="offset" type="rng:Hexadecimal" + use="required" /> + <attribute name="access" type="rng:Access" default="rw" /> + <attribute name="type" type="rng:Type" default="hex" /> + </complexType> + + <complexType name="translationType"> + <annotation> + <documentation>translationType</documentation> + </annotation> + <choice maxOccurs="unbounded"> + <element ref="rng:reg8" /> + <element ref="rng:reg32" /> + <group ref="rng:docGroup" /> + </choice> + <attribute name="domain" type="rng:Cname" use="required" /> + <attribute name="variant" type="NMTOKEN" /> + </complexType> + + + + <!-- Documentation element types --> + + <complexType name="briefType"> + <annotation> + <documentation> + brief documentation, no markup + </documentation> + </annotation> + <simpleContent> + <extension base="string" /> + </simpleContent> + </complexType> + + <complexType name="docType" mixed="true"> + <annotation> + <documentation> + root element of documentation sub-tree + </documentation> + </annotation> + <choice minOccurs="0" maxOccurs="unbounded"> + <group ref="rng:textformatGroup" /> + <group ref="rng:listGroup" /> + <element ref="rng:code" /> + </choice> + </complexType> + + <complexType name="textformatType" mixed="true"> + <annotation> + <documentation> + for bold, underline, italics + </documentation> + </annotation> + <choice minOccurs="0" maxOccurs="unbounded"> + <group ref="rng:textformatGroup" /> + </choice> + </complexType> + + <complexType name="textcodeType"> + <simpleContent> + <extension base="string"> + <attribute name="title" type="string" /> + </extension> + </simpleContent> + </complexType> + + <complexType name="listType"> + <annotation> + <documentation> + definition of a list, ordered or unordered + </documentation> + </annotation> + <choice minOccurs="0" maxOccurs="unbounded"> + <element ref="rng:li" /> + </choice> + </complexType> + + <complexType name="listitemType" mixed="true"> + <annotation> + <documentation> + items of a list + </documentation> + </annotation> + <choice minOccurs="0" maxOccurs="unbounded"> + <group ref="rng:textformatGroup" /> + <group ref="rng:listGroup" /> + <element ref="rng:code" /> + </choice> + </complexType> + + + + <!-- Attribute value types --> + + <simpleType name="Cname"> + <annotation> + <documentation> + C language identifier or macro name. + The C99 standard seems to allow non-ASCII-7 + letters in names, but we do not. Or do we? + </documentation> + </annotation> + <restriction base="token"> + <pattern value="[a-zA-Z_][0-9a-zA-Z_]*" /> + </restriction> + </simpleType> + + <simpleType name="objName"> + <annotation> + <documentation> + This is either a (normal) prefixed name, + or an absolute name with a leading slash. + The absolute name is the same as slash and + Cname concatenated. + </documentation> + </annotation> + <restriction base="token"> + <pattern value="/[a-zA-Z_][0-9a-zA-Z_]*" /> + <pattern value="[0-9a-zA-Z_]+" /> + </restriction> + </simpleType> + + <simpleType name="Hexadecimal"> + <restriction base="string"> + <pattern value="0x[0-9a-f]+" /> + <pattern value="0x[0-9A-F]+" /> + </restriction> + </simpleType> + + <simpleType name="HexOrNumber"> + <annotation> + <documentation>HexOrNumber</documentation> + </annotation> + <union memberTypes="rng:Hexadecimal nonNegativeInteger" /> + </simpleType> + + <simpleType name="Type"> + <annotation> + <documentation>Type</documentation> + </annotation> + <restriction base="NMTOKENS" /> + </simpleType> + + <simpleType name="Access"> + <annotation> + <documentation>Access</documentation> + </annotation> + <restriction base="string"> + <enumeration value="r" /> + <enumeration value="w" /> + <enumeration value="rw" /> + </restriction> + </simpleType> + + + + <!-- Attribute groups --> + + <attributeGroup name="basicArrayAttributes"> + <attribute name="offset" type="rng:Hexadecimal" + use="required" /> + <attribute name="stride" type="rng:HexOrNumber" + use="required" /> + <attribute name="length" type="rng:HexOrNumber" + use="required" /> + </attributeGroup> + + + <!-- Element groups --> + + <group name="regarrayGroup"> + <choice> + <element ref="rng:reg32" /> + <element ref="rng:reg8" /> + <element ref="rng:array" /> + <element ref="rng:stripe" /> + <element ref="rng:translation" /> + </choice> + </group> + + <group name="docGroup"> + <choice> + <element ref="rng:brief" /> + <element ref="rng:doc" /> + </choice> + </group> + + <group name="textformatGroup"> + <choice> + <element ref="rng:b" /> + <element ref="rng:i" /> + <element ref="rng:u" /> + </choice> + </group> + + <group name="listGroup"> + <choice> + <element ref="rng:ul" /> + <element ref="rng:ol" /> + </choice> + </group> + +</schema> + diff --git a/parsers/rulesng.py b/parsers/rulesng.py new file mode 100755 index 0000000..13ceea9 --- /dev/null +++ b/parsers/rulesng.py @@ -0,0 +1,158 @@ +import sys +try: + from lxml import etree +except ImportError: + sys.stderr.write("You need the lxml python module installed. " + "Preferably version 1.2.1 or later.\n" + "See http://codespeak.net/lxml/\n\n") + raise + + +rules_ns_ = '{http://nouveau.freedesktop.org/}' + +# This really should not be here, but libxml2 does not load +# attribute defaults from the Schema. +rules_defaults_ = { + 'reg8:type':'hex', + 'reg8:access':'rw', + 'reg32:type':'hex', + 'reg32:access':'rw', + 'array:type':'hex', + 'bitfield:type':'hex', + 'translation:variant':None + } + +def load_xmlfile(fname): + src = open(fname, "r") + doc = etree.parse(src) + src.close() + return doc + +def load_schema(fname): + return etree.XMLSchema(load_xmlfile(fname)) + +def getatt(elem, attrib): + val = elem.get(attrib) + if val is not None: + return val + name = "%s:%s" % ( elem.tag.replace(rules_ns_, ''), attrib ) + try: + val = rules_defaults_[name] + except KeyError: + sys.stderr.write("Default value not found for %s.\n" % name) + val = None + return val + + +class RulesngHandler: + def __init__(self): + self._domain = "" + self._idcnt = 0 + + def process_children(self, root): + """For the given element 'root', call dispatch_elem() for its + every child element and collect the return values into a + list, filtering out Nones.""" + outs = map(self.dispatch_elem, root.getchildren()) + return filter(lambda x: x is not None, outs) + + def dispatch_elem(self, elem): + """Determine the element type and call the proper function, + returning the functions return value.""" + if type(elem) == etree._Comment: + return + elname = elem.tag.replace(rules_ns_, "elem_").replace('-', '_') + if hasattr(self, elname): + return getattr(self, elname)(elem) + + def temp_array_name(self, oname): + """Create a unique name for a temporary array. + The returned name can be different on each call.""" + self._idcnt += 1 + name = oname.replace('/', 's') + return "__%s_%03d" % (name, self._idcnt) + + def def_name(self, oname): + """Mangle object name to create a known private name in C.""" + name = oname.replace('/', 's') + return "__%s_def" % name + + +class RulesngElement: + """Object to store the complete identity of a register, array + or stripe from Rules-ng. Complete identity includes absolute + address and full name, with applicable variants. + + Attributes: + variants a set of variant id strings + base the absolute base address, integer + arrinfo list of (stride, len) tuples from arrays/stripes + prefix name prefix string + elem reference to the lxml element object + parent reference to the parent RulesngElement object + children list of references to child Rulesnglement objects + containers list of container names; groups, bitsets, enums + translation reference to the translation RulesngElement, or None + idnum an arbitrary id number + """ + + _id_base = 1000 + + def __init__(self, elem): + self.variants = set() + self.base = 0 + self.arrinfo = [] + self.prefix = "" + self.elem = elem + self.parent = None + self.children = [] + self.containers = [] + self.translation = None + self.idnum = RulesngElement._id_base + RulesngElement._id_base += 1 + + def copy(self): + """Create a proper semideep copy; do a deep copy, except for + references to other RulesngElements.""" + re = RulesngElement(self.elem) + re.variants = set(self.variants) + re.base = self.base + re.arrinfo = list(self.arrinfo) + re.prefix = self.prefix + re.parent = self.parent + re.children = list(self.children) + re.containers = list(self.containers) + re.translation = self.translation + return re + + def getType(self): + """Returns the name of the XML element as string.""" + return self.elem.tag.replace(rules_ns_, '') + + def getAddress(self): + """Returns the absolute address (related to offset + attribute). + """ + return self.base + int(self.elem.get("offset"), 0) + + def getStride(self): + return int(self.elem.get("stride"), 0) + + def getLength(self): + return int(self.elem.get("length"), 0) + + def getName(self): + """Returns the complete name with prefixes.""" + myname = self.elem.get("name") + if myname is not None: + if myname[0] == '/': + return myname[1:] + return self.prefix + myname + else: + return self.prefix + def getAtt(self, attribute): + """Returns the value of the requested attribute, using + Rules-ng specified defaults if the attribute is not + defined in the lxml object.""" + + return getatt(self.elem, attribute) diff --git a/parsers/rulesngCollectors.py b/parsers/rulesngCollectors.py new file mode 100755 index 0000000..017946d --- /dev/null +++ b/parsers/rulesngCollectors.py @@ -0,0 +1,281 @@ +from rulesng import * +import sys + +class GroupCollector(RulesngHandler): + """Collector object only goes through the <database> element + and collects references to all <enum>, <bitset> and <group> + elements into a dictionary. + Traverses the lxml object tree according to Rules-ng specs.""" + + def __init__(self): + RulesngHandler.__init__(self) + self.enumTable = {} + self.groupTable = {} + self.bitsetTable = {} + + def elem_enum(self, elem): + self.enumTable[elem.get("name")] = elem + + def elem_group(self, elem): + self.groupTable[elem.get("name")] = elem + + def elem_bitset(self, elem): + self.bitsetTable[elem.get("name")] = elem + + def elem_database(self, elem): + self.process_children(elem) + + +class NameCollector(RulesngHandler): + """Collect all names into a dictionary.""" + + def __init__(self, options={}): + """As parameter, provide a reference to executed + GroupCollector object, so that <use-foo> elements can work.""" + + RulesngHandler.__init__(self) + self.groups = None + + # process optional features + self.options = { + # no optional features + } + self.options.update(options) + + # Context stacks for different aspects + self.variants = [] # set + self.base = [0] # integer + self.arrinfo = [] # (stride, len) tuples + self.prefix = [""] # string + self.parents = [] # RulesngElement + self.containers = [] # string (group etc. name) + + # Current translation in effect + self.translation = None + + # dictionary for all register-like symbols, + # keys are full names, values are lists of RulesngElement refs. + self.symbols = {}; + + def processXMLTree(self, rootnode): + self.groups = GroupCollector() + self.groups.dispatch_elem(rootnode) + self.dispatch_elem(rootnode) + self.combineElements() + + def addToSymbolList(self, re): + name = re.getName() + if len(name) == 0: + eprint("Warning: nameless symbol found.") + try: + lst = self.symbols[name] + # Check for duplicate names, accounting for variants + for item in lst: + ids = item.variants.intersection(re.variants) + if len(ids) > 0: + eprint("Warning: name %s multiply " + "defined for variants %s" + % (name, ", ".join(ids)) ) + if len(item.variants) == 0 and \ + len(re.variants) == 0: + eprint("Warning: name %s multiply " + "defined" % name) + lst.append(re) + except KeyError: + self.symbols[name] = [re] + + def newRElem(self, elem): + re = RulesngElement(elem) + if len(self.variants) > 0: + re.variants = self.variants[-1] + re.base = self.base[-1] + re.arrinfo = list(self.arrinfo) + re.prefix = self.prefix[-1] + if len(self.parents) > 0: + re.parent = self.parents[-1] + re.containers = list(self.containers) + re.translation = self.translation + return re + + def combineElements(self): + """Call combineRulesngElements for each object list in + NameCollector.symbols.""" + + for k in self.symbols.keys(): + combineRulesngElements(self.symbols[k]) + + + def elem_database(self, elem): + self.process_children(elem) + + def elem_domain(self, elem): + self._domain = elem.get("name") + + def elem_variant(self, elem): + ids = set(elem.get("id").split(' ')) + if len(self.variants) > 0: + valids = ids.intersection(self.variants[-1]) + if valids != ids: + eprint("variant error: " + str(ids) + + " != " + str(valids) ) + self.variants.append(ids) + self.process_children(elem) + self.variants.pop() + + def elem_reg32(self, elem): + re = self.newRElem(elem) + self.addToSymbolList(re) + self.prefix.append(re.getName() + "_") + self.base.append(re.getAddress()) + self.parents.append(re) + re.children = flatten( self.process_children(elem) ) + self.parents.pop() + self.base.pop() + self.prefix.pop() + return re + + def elem_reg8(self, elem): + return self.elem_reg32(elem) + + def elem_array(self, elem): + re = self.newRElem(elem) + self.addToSymbolList(re) + nameless = elem.get("name") is None + if not nameless: + self.prefix.append(re.getName() + "_") + self.base.append(re.getAddress()) + self.arrinfo.append( (re.getStride(), re.getLength()) ) + self.parents.append(re) + re.children = flatten(self.process_children(elem)) + self.parents.pop() + self.arrinfo.pop() + self.base.pop() + if not nameless: + self.prefix.pop() + return re + + def elem_stripe(self, elem): + re = self.newRElem(elem) + nameless = elem.get("name") is None + if not nameless: + self.prefix.append(re.getName() + "_") + self.base.append(re.getAddress()) + self.arrinfo.append( (re.getStride(), re.getLength()) ) + ret = self.process_children(elem) + self.arrinfo.pop() + self.base.pop() + if not nameless: + self.prefix.pop() + return flatten(ret) + + def elem_bitfield(self, elem): + re = self.newRElem(elem) + self.prefix.append(re.getName() + "_") + self.parents.append(re) + re.children = flatten( self.process_children(elem) ) + self.parents.pop() + self.prefix.pop() + return re + + def elem_value(self, elem): + re = self.newRElem(elem) + return re + + def elem_translation(self, elem): + re = self.newRElem(elem) + self.translation = re + re.children = flatten(self.process_children(elem)) + self.translation = None + return re + + def elem_use_bitset(self, elem): + ref = elem.get("ref") + bitset = self.groups.bitsetTable[ref] + self.containers.append(ref) + ret = self.process_children(bitset) + self.containers.pop() + return ret + + def elem_use_enum(self, elem): + ref = elem.get("ref") + enum = self.groups.enumTable[ref] + self.containers.append(ref) + ret = self.process_children(enum) + self.containers.pop() + return ret + + def elem_use_group(self, elem): + ref = elem.get("ref") + group = self.groups.groupTable[ref] + self.containers.append(ref) + ret = self.process_children(group) + self.containers.pop() + return ret + +def eprint(msg): + sys.stderr.write(msg + "\n") + +def flatten(lst): + ret = [] + for i in lst: + if type(i) == list: + ret.extend(i) + else: + ret.append(i) + return ret + +def countTailMatch(lst1, lst2): + """Return the number of equivalent elements between two lists, + counting fron the end.""" + m = min(len(lst1), len(lst2)) + for i in range(1, m+1): + if lst1[-i] != lst2[-i]: + return i-1 + return m + +def combineRulesngElements(elemlist): + """Many time the same registers are included from the same groups + under many different variants. This function combines all those + different instances into single RulesngElement objects. + + After successful processing, elemlist is modified IN PLACE.""" + + addr_cmp = lambda a, b: a.getAddress() != b.getAddress() + value_cmp = lambda a, b: False + cmp_switch = { + 'reg8' : addr_cmp, + 'reg32' : addr_cmp, + 'array' : addr_cmp, + 'stripe' : addr_cmp, + 'value' : value_cmp, + 'bitfield' : value_cmp + } + + newlist = [] + for re in elemlist: + for nre in newlist: + ctm = countTailMatch(re.containers, nre.containers) + # Can re be combined into nre? + if ctm == 0: + continue + if re.getType() != nre.getType(): + continue + if cmp_switch[re.getType()](re, nre): + continue + + # update variant set + nre.variants.update(re.variants) + # cut containers list to only the common part + l = len(nre.containers) + del nre.containers[1:(l-ctm+1)] + # fix all references to the old object + for child in re.children: + child.parent = nre + if re.parent: + re.parent.child = nre + break + else: + newlist.append(re) + # modify elemlist in place + del elemlist[:] + elemlist.extend(newlist) |