Classes are good in this case at least.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Tue, 03 Jun 2008 17:28:51 -0400
changeset 4 c5b0dfdbfa52
parent 3 45605d017f1c
child 5 9608c862313a
push id5
push userbsmedberg@mozilla.com
push dateThu, 05 Jun 2008 20:10:01 +0000
Classes are good in this case at least.
xpidl.py
--- a/xpidl.py
+++ b/xpidl.py
@@ -1,315 +1,321 @@
 #!/usr/bin/env python
 
 """A parser for cross-platform IDL (XPIDL) files."""
 
 from optparse import OptionParser
 import lex, yacc, sys
 
-keywords = {
-    'interface': 'INTERFACE',
-    'ref': 'REF',
-    'ptr': 'PTR',
-    'nsid': 'NSID',
-    'domstring': 'DOMSTRING',
-    'utfstring': 'UTFSTRING',
-    'cstring': 'CSTRING',
-    'astring': 'ASTRING',
-    'in': 'IN',
-    'inout': 'INOUT',
-    'out': 'OUT',
-    'const': 'CONST',
-    'shared': 'SHARED',
-    'array': 'ARRAY',
-    'size_is': 'SIZE_IS',
-    'iid_is': 'IID_IS',
-    'retval': 'RETVAL',
-    'uuid_is':  'UUID_IS',
-    'noscript': 'NOSCRIPT',
-    'notxpcom': 'NOTXPCOM',
-    'scriptable': 'SCRIPTABLE',
-    'attribute': 'ATTRIBUTE',
-    'readonly': 'READONLY',
-    'function': 'FUNCTION',
-    'object': 'OBJECT',
-    'native': 'NATIVE',
-    'typedef': 'TYPEDEF'
-}
-
-tokens = [
-    'IDENTIFIER',
-    'CDATA',
-    'INCLUDE',
-    'FILENAME',
-    'IID',
-]
-
-tokens.extend(keywords.values())
-
-def t_multilinecomment(t):
-    r'/\*(?s).*?\*/'
-    t.lexer.lineno += t.value.count('\n')
-
-def t_singlelinecomment(t):
-    r'(?m)//.*$'
-
-hexchar = r'[a-fA-F0-9]'
-def t_IID(t):
-    return t
-t_IID.__doc__ = r'%(c)s{8}-%(c)s{4}-%(c)s{4}-%(c)s{4}-%(c)s{12}' % {'c': hexchar}
-
-def t_IDENTIFIER(t):
-    r'unsigned\ long\ long|unsigned\ short|unsigned\ long|long\ long|[A-Za-z][A-Za-z_0-9]*'
-    t.type = keywords.get(t.value, 'IDENTIFIER')
-    return t
-
-def t_LCDATA(t):
-    r'%\{C\+\+(?s).*?%\}'
-    t.type = 'CDATA'
-    t.value = t.value[5:-2]
-    t.lexer.lineno += t.value.count('\n')
-    return t
-
-def t_INCLUDE(t):
-    r'\#include[ \t]+"[^"\n]+"'
-    inc, value, end = t.value.split('"')
-    t.value = value
-    return t
-
-literals = '"(){}[],;:'
-
-t_ignore = ' \t'
-
-def t_newline(t):
-    r'\n+'
-    t.lexer.lineno += len(t.value)
-
 def pointerline(colno):
     for i in xrange(0, colno):
         yield " "
     yield "^"
 
-def finderror(token, lexer):
-    """Given a token and a lexer, return (colno, badline, pointerline)"""
-    startofline = lexer.lexdata.rfind('\n', 0, token.lexpos) + 1
-    endofline = lexer.lexdata.find('\n', token.lexpos, token.lexpos + 80)
-    line = lexer.lexdata[startofline:endofline]
-    colno = token.lexpos - startofline
-    return (colno, line, "".join(pointerline(colno)))
-
-def t_error(t):
-    colno, line, pointerline = finderror(t, t.lexer)
-    raise Exception("Error: line %i column %i: unrecognized input.\n%s\n%s" % (t.lineno, colno, line, pointerline))
-
-def p_idlfile(p):
-    """idlfile : includes productions"""
-    p[0] = {'includes': p[1],
-            'productions': p[2]}
+class XPIDLParser(object):
+    keywords = {
+        'interface': 'INTERFACE',
+        'in': 'IN',
+        'inout': 'INOUT',
+        'out': 'OUT',
+        'const': 'CONST',
+        'shared': 'SHARED',
+        'array': 'ARRAY',
+        'size_is': 'SIZE_IS',
+        'iid_is': 'IID_IS',
+        'retval': 'RETVAL',
+        'uuid_is':  'UUID_IS',
+        'noscript': 'NOSCRIPT',
+        'notxpcom': 'NOTXPCOM',
+        'scriptable': 'SCRIPTABLE',
+        'attribute': 'ATTRIBUTE',
+        'readonly': 'READONLY',
+        'function': 'FUNCTION',
+        'object': 'OBJECT',
+        'native': 'NATIVE',
+        'typedef': 'TYPEDEF'
+        }
 
-def p_includes_start(p):
-    """includes : """
-    p[0] = []
+    tokens = [
+        'IDENTIFIER',
+        'CDATA',
+        'INCLUDE',
+        'FILENAME',
+        'IID',
+        ]
 
-def p_includes_continue(p):
-    """includes : INCLUDE includes"""
-    p[0] = list(p[2])
-    p[0].insert(0, p[1])
+    tokens.extend(keywords.values())
 
-def p_productions_start(p):
-    """productions : """
-    p[0] = []
+    def t_multilinecomment(self, t):
+        r'/\*(?s).*?\*/'
+        t.lexer.lineno += t.value.count('\n')
 
-def p_productions_cdata(p):
-    """productions : CDATA productions"""
-    p[0] = list(p[2])
-    p[0].insert(0, {'kind': 'cdata',
-                    'data': p[1]})
+    def t_singlelinecomment(self, t):
+        r'(?m)//.*?$'
+
+    hexchar = r'[a-fA-F0-9]'
+    def t_IID(self, t):
+        return t
+    t_IID.__doc__ = r'%(c)s{8}-%(c)s{4}-%(c)s{4}-%(c)s{4}-%(c)s{12}' % {'c': hexchar}
 
-def p_productions_interface(p):
-    """productions : interface productions
-                   | typedef productions
-                   | native productions"""
-    p[0] = list(p[2])
-    p[0].insert(0, p[1])
+    def t_IDENTIFIER(self, t):
+        r'unsigned\ long\ long|unsigned\ short|unsigned\ long|long\ long|[A-Za-z][A-Za-z_0-9]*'
+        t.type = self.keywords.get(t.value, 'IDENTIFIER')
+        return t
 
-def p_typedef(p):
-    """typedef : TYPEDEF IDENTIFIER IDENTIFIER ';'"""
+    def t_LCDATA(self, t):
+        r'%\{C\+\+(?s).*?%\}'
+        t.type = 'CDATA'
+        t.value = t.value[5:-2]
+        t.lexer.lineno += t.value.count('\n')
+        return t
 
-def p_native(p):
-    """native : '[' nativetype nativemodifier ']' NATIVE IDENTIFIER '(' IDENTIFIER ')' ';'"""
+    def t_INCLUDE(self, t):
+        r'\#include[ \t]+"[^"\n]+"'
+        inc, value, end = t.value.split('"')
+        t.value = value
+        return t
 
-def p_nativeattlist(p):
-    """nativetype : PTR
-                  | REF"""
+    literals = '"(){}[],;:'
+
+    t_ignore = ' \t'
 
-def p_nativemodifier(p):
-    """nativemodifier : ',' IDENTIFIER
-                      | """
+    def t_newline(self, t):
+        r'\n+'
+        t.lexer.lineno += len(t.value)
+
+    def finderror(self, token):
+        """Given a token and a lexer, return (colno, badline, pointerline)"""
+        lexer = self.lexer
 
-def p_interface(p):
-    """interface : ifaceatts INTERFACE IDENTIFIER ifacebase '{' members '}' ';'"""
-    p[0] = {'kind': 'interface',
-            'name': p[3],
-            'atts': p[1],
-            'members': p[6]}
+        startofline = lexer.lexdata.rfind('\n', 0, token.lexpos) + 1
+        endofline = lexer.lexdata.find('\n', token.lexpos, token.lexpos + 80)
+        line = lexer.lexdata[startofline:endofline]
+        colno = token.lexpos - startofline
+        return (colno, line, "".join(pointerline(colno)))
 
-def p_ifaceatts(p):
-    """ifaceatts : '[' ifaceattlist ']'
-                 | '[' ']'
-                 | """
-    if len(p) == 4:
-        p[0] = p[2]
-    else:
+    def t_error(self, t):
+        colno, line, pointerline = self.finderror(t)
+        raise Exception("Error: line %i column %i: unrecognized input.\n%s\n%s" % (t.lineno, colno, line, pointerline))
+
+    def p_idlfile(self, p):
+        """idlfile : includes productions"""
+        p[0] = {'includes': p[1],
+                'productions': p[2]}
+
+    def p_includes_start(self, p):
+        """includes : """
         p[0] = []
 
-def p_ifaceattlist_start(p):
-    """ifaceattlist : ifaceatt"""
-    p[0] = [p[1]]
-
-def p_ifaceattlist_continue(p):
-    """ifaceattlist : ifaceatt ',' ifaceattlist"""
-    p[0] = list(p[3])
-    p[0].insert(0, p[1])
-
-def p_ifaceatt_uuid(p):
-    """ifaceatt : IDENTIFIER '(' IID ')'"""
-    if p[1] != 'uuid':
-        raise Exception("unexpected keyword '%s', expected 'uuid'" % p[1])
-
-    p[0] = {'name': 'uuid',
-            'value': p[3]}
+    def p_includes_continue(self, p):
+        """includes : INCLUDE includes"""
+        p[0] = list(p[2])
+        p[0].insert(0, p[1])
 
-def p_ifacatt_scriptable(p):
-    """ifaceatt : SCRIPTABLE"""
-    p[0] = {'name': 'scriptable'}
-
-def p_ifacebase(p):
-    """ifacebase : ':' IDENTIFIER
-                 | """
-    if len(p) == 3:
-        p[0] = p[2]
-
-def p_members_start(p):
-    """members : """
-    p[0] = []
-
-def p_members_continue(p):
-    """members : member members"""
-    p[0] = list(p[2])
-    p[0].insert(0, p[1])
+    def p_productions_start(self, p):
+        """productions : """
+        p[0] = []
 
-def p_member_att(p):
-    """member : memberatts optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ';'"""
-    p[0] = {'kind': 'attribute',
-            'attributes': p[1],
-            'readonly': p[2],
-            'type': p[4],
-            'name': p[5]}
-
-def p_memberatts(p):
-    """memberatts : '[' memberatt memberattlist ']'
-                  | """
-    if len(p) == 1:
-        p[0] = []
-    else:
-        p[0] = p[2]
-
-def p_memberattlist_start(p):
-    """memberattlist : """
-    p[0] = []
+    def p_productions_cdata(self, p):
+        """productions : CDATA productions"""
+        p[0] = list(p[2])
+        p[0].insert(0, {'kind': 'cdata',
+                        'data': p[1]})
 
-def p_memberattlist_continue(p):
-    """memberattlist : ',' memberatt memberattlist"""
-    p[0] = list(p[3])
-    p[0].insert(0, p[2])
-
-def p_memberatt(p):
-    """memberatt : NOSCRIPT
-                 | NOTXPCOM"""
-    p[0] = p[1]
-
-def p_member_method(p):
-    """member : memberatts IDENTIFIER IDENTIFIER '(' paramlist ')' ';'"""
-    p[0] = {'kind': 'method',
-            'attributes': p[1],
-            'type': p[2],
-            'name': p[3],
-            'parameters': p[5]}
-
-def p_paramlist(p):
-    """paramlist : param moreparams
-                 | """
-    if len(p) == 1:
-        p[0] = []
-    else:
+    def p_productions_interface(self, p):
+        """productions : interface productions
+                       | typedef productions
+                       | native productions"""
         p[0] = list(p[2])
         p[0].insert(0, p[1])
 
-def p_moreparams_start(p):
-    """moreparams :"""
-    p[0] = []
+    def p_typedef(self, p):
+        """typedef : TYPEDEF IDENTIFIER IDENTIFIER ';'"""
+        p[0] = {'kind': 'typedef',
+                'name': p[3],
+                'type': p[2]}
+
+    def p_native(self, p):
+        """native : '[' nativemodifiers ']' NATIVE IDENTIFIER '(' IDENTIFIER ')' ';'"""
+        p[0] = {'kind': 'native',
+                'name': p[5],
+                'modifiers': p[2],
+                'identifier': p[7]}
+
+    def p_nativemodifiers_start(self, p):
+        """nativemodifiers : IDENTIFIER"""
+        p[0] = [p[1]]
+
+    def p_nativemodifiers_continue(self, p):
+        """nativemodifiers : IDENTIFIER ',' nativemodifiers"""
+        p[0] = list(p[3])
+        p[0].insert(0, p[1])
 
-def p_moreparams_continue(p):
-    """moreparams : ',' param moreparams"""
-    p[0] = list(p[3])
-    p[0].insert(0, p[2])
+    def p_interface(self, p):
+        """interface : ifaceatts INTERFACE IDENTIFIER ifacebase '{' members '}' ';'"""
+        p[0] = {'kind': 'interface',
+                'name': p[3],
+                'atts': p[1],
+                'members': p[6]}
 
-def p_param(p):
-    """param : paramatts paramtype IDENTIFIER IDENTIFIER"""
-    p[0] = {'modifiers': p[1],
-            'paramtype': p[2],
-            'type': p[3],
-            'name': p[4]}
+    def p_ifaceatts(self, p):
+        """ifaceatts : '[' ifaceattlist ']'
+                     | '[' ']'
+                     | """
+        if len(p) == 4:
+            p[0] = p[2]
+        else:
+            p[0] = []
+
+    def p_ifaceattlist_start(self, p):
+        """ifaceattlist : ifaceatt"""
+        p[0] = [p[1]]
+
+    def p_ifaceattlist_continue(self, p):
+        """ifaceattlist : ifaceatt ',' ifaceattlist"""
+        p[0] = list(p[3])
+        p[0].insert(0, p[1])
 
-def p_paramatts(p):
-    """paramatts : '[' paramattlist ']'
-                 | """
-    if len(p) == 1:
+    def p_ifaceatt_uuid(self, p):
+        """ifaceatt : IDENTIFIER '(' IID ')'"""
+        if p[1] != 'uuid':
+            raise Exception("unexpected keyword '%s', expected 'uuid'" % p[1])
+    
+        p[0] = {'name': 'uuid',
+                'value': p[3]}
+
+    def p_ifacatt_scriptable(self, p):
+        """ifaceatt : SCRIPTABLE"""
+        p[0] = {'name': 'scriptable'}
+
+    def p_ifacebase(self, p):
+        """ifacebase : ':' IDENTIFIER
+                     | """
+        if len(p) == 3:
+            p[0] = p[2]
+
+    def p_members_start(self, p):
+        """members : """
         p[0] = []
-    else:
-        p[0] = p[2]
 
-def p_paramattlist_start(p):
-    """paramattlist : paramatt"""
-    p[0] = [p[1]]
+    def p_members_continue(self, p):
+        """members : member members"""
+        p[0] = list(p[2])
+        p[0].insert(0, p[1])
 
-def p_paramattlist_continue(p):
-    """paramattlist : paramatt ',' paramattlist"""
-    p[0] = list(p[3])
-    p[0].insert(0, p[1])
+    def p_member_att(self, p):
+        """member : memberatts optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ';'"""
+        p[0] = {'kind': 'attribute',
+                'attributes': p[1],
+                'readonly': p[2],
+                'type': p[4],
+                'name': p[5]}
+
+    def p_memberatts(self, p):
+        """memberatts : '[' memberatt memberattlist ']'
+                      | """
+        if len(p) == 1:
+            p[0] = []
+        else:
+            p[0] = p[2]
+
+    def p_memberattlist_start(self, p):
+        """memberattlist : """
+        p[0] = []
 
-def p_paramatt(p):
-    """paramatt : RETVAL
-                | ARRAY"""
-    p[0] = {'name': p[1]}
+    def p_memberattlist_continue(self, p):
+        """memberattlist : ',' memberatt memberattlist"""
+        p[0] = list(p[3])
+        p[0].insert(0, p[2])
+
+    def p_memberatt(self, p):
+        """memberatt : NOSCRIPT
+                     | NOTXPCOM"""
+        p[0] = p[1]
+
+    def p_member_method(self, p):
+        """member : memberatts IDENTIFIER IDENTIFIER '(' paramlist ')' ';'"""
+        p[0] = {'kind': 'method',
+                'attributes': p[1],
+                'type': p[2],
+                'name': p[3],
+                'parameters': p[5]}
 
-def p_paramatt_withval(p):
-    """paramatt : paramattnamewithval '(' IDENTIFIER ')'"""
-    p[0] = {'name': p[1],
-            'value': p[3]}
+    def p_paramlist(self, p):
+        """paramlist : param moreparams
+                     | """
+        if len(p) == 1:
+            p[0] = []
+        else:
+            p[0] = list(p[2])
+            p[0].insert(0, p[1])
 
-def p_paramattnamewithval(p):
-    """paramattnamewithval : IID_IS
-                           | SIZE_IS"""
-    p[0] = p[1]
+    def p_moreparams_start(self, p):
+        """moreparams :"""
+        p[0] = []
+
+    def p_moreparams_continue(self, p):
+        """moreparams : ',' param moreparams"""
+        p[0] = list(p[3])
+        p[0].insert(0, p[2])
+
+    def p_param(self, p):
+        """param : paramatts paramtype IDENTIFIER IDENTIFIER"""
+        p[0] = {'modifiers': p[1],
+                'paramtype': p[2],
+                'type': p[3],
+                'name': p[4]}
 
-def p_paramtype(p):
-    """paramtype : IN
-                 | INOUT
-                 | OUT"""
-    p[0] = p[1]
+    def p_paramatts(self, p):
+        """paramatts : '[' paramattlist ']'
+                     | """
+        if len(p) == 1:
+            p[0] = []
+        else:
+            p[0] = p[2]
+
+    def p_paramattlist_start(self, p):
+        """paramattlist : paramatt"""
+        p[0] = [p[1]]
 
-def p_optreadonly(p):
-    """optreadonly : READONLY
-                   | """
-    p[0] = len(p) > 1
+    def p_paramattlist_continue(self, p):
+        """paramattlist : paramatt ',' paramattlist"""
+        p[0] = list(p[3])
+        p[0].insert(0, p[1])
+
+    def p_paramatt(self, p):
+        """paramatt : RETVAL
+                    | ARRAY"""
+        p[0] = {'name': p[1]}
+
+    def p_paramatt_withval(self, p):
+        """paramatt : paramattnamewithval '(' IDENTIFIER ')'"""
+        p[0] = {'name': p[1],
+                'value': p[3]}
 
-def p_error(p):
-    print >>sys.stderr, "p_error: %r" % p.lexer
-    colno, line, pointerline = finderror(p, l)
-    raise Exception("Error: invalid syntax, line %i column %i.\n%s\n%s" % (p.lineno, colno, line, pointerline))
+    def p_paramattnamewithval(self, p):
+        """paramattnamewithval : IID_IS
+                               | SIZE_IS"""
+        p[0] = p[1]
+
+    def p_paramtype(self, p):
+        """paramtype : IN
+                     | INOUT
+                     | OUT"""
+        p[0] = p[1]
 
-l = lex.lex()
-y = yacc.yacc()
+    def p_optreadonly(self, p):
+        """optreadonly : READONLY
+                       | """
+        p[0] = len(p) > 1
+
+    def p_error(self, p):
+        colno, line, pointerline = self.finderror(p)
+        raise Exception("Error: invalid syntax, line %i column %i.\n%s\n%s" % (p.lineno, colno, line, pointerline))
 
-r = y.parse(lexer=l, input=sys.stdin.read(), debug=True)
-print r
+    def __init__(self):
+        self.lexer = lex.lex(object=self)
+        self.parser = yacc.yacc(module=self)
+
+    def parse(self, data):
+        return self.parser.parse(lexer=self.lexer, input=data)
+
+print XPIDLParser().parse(sys.stdin.read())