Parse nsrootidl and nsISupports.idl without errors (that doesn't mean "correctly"!)
authorBenjamin Smedberg <benjamin@smedbergs.us>
Tue, 03 Jun 2008 16:53:30 -0400
changeset 3 45605d017f1c
parent 2 0e9e86907aa6
child 4 c5b0dfdbfa52
push id4
push userbsmedberg@mozilla.com
push dateTue, 03 Jun 2008 20:53:47 +0000
Parse nsrootidl and nsISupports.idl without errors (that doesn't mean "correctly"!)
xpidl.py
--- a/xpidl.py
+++ b/xpidl.py
@@ -2,17 +2,16 @@
 
 """A parser for cross-platform IDL (XPIDL) files."""
 
 from optparse import OptionParser
 import lex, yacc, sys
 
 keywords = {
     'interface': 'INTERFACE',
-    'uuid': 'UUID',
     'ref': 'REF',
     'ptr': 'PTR',
     'nsid': 'NSID',
     'domstring': 'DOMSTRING',
     'utfstring': 'UTFSTRING',
     'cstring': 'CSTRING',
     'astring': 'ASTRING',
     'in': 'IN',
@@ -79,31 +78,32 @@ def t_INCLUDE(t):
 literals = '"(){}[],;:'
 
 t_ignore = ' \t'
 
 def t_newline(t):
     r'\n+'
     t.lexer.lineno += len(t.value)
 
-#def t_ws(t):
-#  r'[ \t]+'
-#  pass
-
 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):
-    startofline = t.lexer.lexdata.rfind('\n', 0, t.lexer.lexpos) + 1
-    endofline = t.lexer.lexdata.find('\n', t.lexer.lexpos, t.lexer.lexpos + 80)
-    line = t.lexer.lexdata[startofline:endofline]
-    colno = t.lexer.lexpos - startofline
-    raise Exception("Error: line %i column %i: unrecognized input.\n%s\n%s" % (t.lexer.lineno, colno + 1, line, "".join(pointerline(colno))))
+    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]}
 
 def p_includes_start(p):
     """includes : """
@@ -166,17 +166,20 @@ def p_ifaceattlist_start(p):
     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 : UUID '(' IID ')'"""
+    """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(p):
     """ifaceatt : SCRIPTABLE"""
     p[0] = {'name': 'scriptable'}
 
 def p_ifacebase(p):
@@ -190,70 +193,97 @@ def p_members_start(p):
     p[0] = []
 
 def p_members_continue(p):
     """members : member members"""
     p[0] = list(p[2])
     p[0].insert(0, p[1])
 
 def p_member_att(p):
-    """member : optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ';'"""
+    """member : memberatts optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ';'"""
     p[0] = {'kind': 'attribute',
-            'readonly': p[1],
-            'type': p[3],
-            'name': p[4]}
+            '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_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 : IDENTIFIER IDENTIFIER '(' paramlist ')' ';'"""
+    """member : memberatts IDENTIFIER IDENTIFIER '(' paramlist ')' ';'"""
     p[0] = {'kind': 'method',
-            'type': p[1],
-            'name': p[2],
-            'parameters': p[4]}
+            '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] = []
-
-    p[0] = list(p[2])
-    p[0].insert(0, p[1])
+    else:
+        p[0] = list(p[2])
+        p[0].insert(0, p[1])
 
 def p_moreparams_start(p):
-    """moreparams : """
+    """moreparams :"""
     p[0] = []
 
 def p_moreparams_continue(p):
-    """moreparams : param ',' moreparams"""
-    p[0] = list(p[2])
-    p[0].insert(0, p[1])
+    """moreparams : ',' param moreparams"""
+    p[0] = list(p[3])
+    p[0].insert(0, p[2])
 
 def p_param(p):
     """param : paramatts paramtype IDENTIFIER IDENTIFIER"""
-    p[0] = {'parameters': p[1],
+    p[0] = {'modifiers': p[1],
             'paramtype': p[2],
             'type': p[3],
             'name': p[4]}
 
 def p_paramatts(p):
     """paramatts : '[' paramattlist ']'
                  | """
+    if len(p) == 1:
+        p[0] = []
+    else:
+        p[0] = p[2]
 
 def p_paramattlist_start(p):
     """paramattlist : paramatt"""
     p[0] = [p[1]]
 
 def p_paramattlist_continue(p):
     """paramattlist : paramatt ',' paramattlist"""
-    p[0] = list(p[2])
-    p[0].insert(p[1])
+    p[0] = list(p[3])
+    p[0].insert(0, p[1])
 
 def p_paramatt(p):
-    """paramatt : NOSCRIPT
-                | NOTXPCOM
+    """paramatt : RETVAL
                 | ARRAY"""
     p[0] = {'name': p[1]}
 
 def p_paramatt_withval(p):
     """paramatt : paramattnamewithval '(' IDENTIFIER ')'"""
     p[0] = {'name': p[1],
             'value': p[3]}
 
@@ -266,19 +296,20 @@ def p_paramtype(p):
     """paramtype : IN
                  | INOUT
                  | OUT"""
     p[0] = p[1]
 
 def p_optreadonly(p):
     """optreadonly : READONLY
                    | """
-    return len(p) > 1
+    p[0] = len(p) > 1
 
 def p_error(p):
-    print >>sys.stderr, "p_error: %r" % p
-    raise Exception("Error: invalid syntax, line %i" % p.lineno)
+    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))
 
-l = lex.lex(debug=True)
+l = lex.lex()
 y = yacc.yacc()
 
 r = y.parse(lexer=l, input=sys.stdin.read(), debug=True)
 print r