OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 """Generates a syntax tree from a Mojo IDL file.""" |
| 7 |
| 8 |
| 9 import sys |
| 10 import os.path |
| 11 |
| 12 |
| 13 # Try to load the ply module, if not, then assume it is in the third_party |
| 14 # directory. |
| 15 try: |
| 16 # Disable lint check which fails to find the ply module. |
| 17 # pylint: disable=F0401 |
| 18 from ply import lex |
| 19 from ply import yacc |
| 20 except ImportError: |
| 21 module_path, module_name = os.path.split(__file__) |
| 22 third_party = os.path.join( |
| 23 module_path, os.pardir, os.pardir, os.pardir, os.pardir, 'third_party') |
| 24 sys.path.append(third_party) |
| 25 # pylint: disable=F0401 |
| 26 from ply import lex |
| 27 from ply import yacc |
| 28 |
| 29 |
| 30 def ListFromConcat(*items): |
| 31 """Generate list by concatenating inputs""" |
| 32 itemsout = [] |
| 33 for item in items: |
| 34 if item is None: |
| 35 continue |
| 36 if type(item) is not type([]): |
| 37 itemsout.append(item) |
| 38 else: |
| 39 itemsout.extend(item) |
| 40 |
| 41 return itemsout |
| 42 |
| 43 |
| 44 class Lexer(object): |
| 45 |
| 46 # This field is required by lex to specify the complete list of valid tokens. |
| 47 tokens = ( |
| 48 'NAME', |
| 49 'NUMBER', |
| 50 |
| 51 'ARRAY', |
| 52 'ORDINAL', |
| 53 |
| 54 'MODULE', |
| 55 'STRUCT', |
| 56 'INTERFACE', |
| 57 'VOID', |
| 58 |
| 59 'LCURLY', |
| 60 'RCURLY', |
| 61 'LPAREN', |
| 62 'RPAREN', |
| 63 'LBRACKET', |
| 64 'RBRACKET', |
| 65 'COMMA', |
| 66 'SEMICOLON', |
| 67 'EQUALS', |
| 68 ) |
| 69 |
| 70 t_LCURLY = r'{' |
| 71 t_RCURLY = r'}' |
| 72 t_LPAREN = r'\(' |
| 73 t_RPAREN = r'\)' |
| 74 t_LBRACKET = r'\[' |
| 75 t_RBRACKET = r'\]' |
| 76 t_COMMA = r',' |
| 77 t_SEMICOLON = r';' |
| 78 t_EQUALS = r'=' |
| 79 t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' |
| 80 t_ARRAY = r'[a-zA-Z_][a-zA-Z0-9_]*\[\]' |
| 81 t_NUMBER = r'\d+' |
| 82 t_ORDINAL = r'@[0-9]*' |
| 83 |
| 84 def t_MODULE(self, t): |
| 85 r'module' |
| 86 return t |
| 87 |
| 88 def t_STRUCT(self, t): |
| 89 r'struct' |
| 90 return t |
| 91 |
| 92 def t_INTERFACE(self, t): |
| 93 r'interface' |
| 94 return t |
| 95 |
| 96 def t_VOID(self, t): |
| 97 r'void' |
| 98 return t |
| 99 |
| 100 # Ignore C and C++ style comments |
| 101 def t_COMMENT(self, t): |
| 102 r'(/\*(.|\n)*?\*/)|(//.*(\n[ \t]*//.*)*)' |
| 103 pass |
| 104 |
| 105 # Ignored characters |
| 106 t_ignore = " \t" |
| 107 |
| 108 def t_newline(self, t): |
| 109 r'\n+' |
| 110 t.lexer.lineno += t.value.count("\n") |
| 111 |
| 112 def t_error(self, t): |
| 113 print("Illegal character '%s'" % t.value[0]) |
| 114 t.lexer.skip(1) |
| 115 |
| 116 |
| 117 class Parser(object): |
| 118 |
| 119 def __init__(self, lexer): |
| 120 self.tokens = lexer.tokens |
| 121 |
| 122 def p_module(self, p): |
| 123 """module : MODULE NAME LCURLY definitions RCURLY""" |
| 124 p[0] = ('MODULE', p[2], p[4]) |
| 125 |
| 126 def p_definitions(self, p): |
| 127 """definitions : definition definitions |
| 128 |""" |
| 129 if len(p) > 1: |
| 130 p[0] = ListFromConcat(p[1], p[2]) |
| 131 |
| 132 def p_definition(self, p): |
| 133 """definition : struct |
| 134 | interface""" |
| 135 p[0] = p[1] |
| 136 |
| 137 def p_attribute_section(self, p): |
| 138 """attribute_section : LBRACKET attributes RBRACKET |
| 139 | """ |
| 140 if len(p) > 3: |
| 141 p[0] = p[2] |
| 142 |
| 143 def p_attributes(self, p): |
| 144 """attributes : attribute |
| 145 | attribute COMMA attributes |
| 146 | """ |
| 147 if len(p) == 2: |
| 148 p[0] = ListFromConcat(p[1]) |
| 149 elif len(p) > 3: |
| 150 p[0] = ListFromConcat(p[1], p[3]) |
| 151 |
| 152 def p_attribute(self, p): |
| 153 """attribute : NAME EQUALS NUMBER""" |
| 154 p[0] = ('ATTRIBUTE', p[1], p[3]) |
| 155 |
| 156 def p_struct(self, p): |
| 157 """struct : attribute_section STRUCT NAME LCURLY fields RCURLY SEMICOLON""" |
| 158 p[0] = ('STRUCT', p[3], p[1], p[5]) |
| 159 |
| 160 def p_fields(self, p): |
| 161 """fields : field fields |
| 162 |""" |
| 163 if len(p) > 1: |
| 164 p[0] = ListFromConcat(p[1], p[2]) |
| 165 |
| 166 def p_field(self, p): |
| 167 """field : typename NAME ordinal SEMICOLON""" |
| 168 p[0] = ('FIELD', p[1], p[2], p[3]) |
| 169 |
| 170 def p_interface(self, p): |
| 171 """interface : INTERFACE NAME LCURLY methods RCURLY SEMICOLON""" |
| 172 p[0] = ('INTERFACE', p[2], p[4]) |
| 173 |
| 174 def p_methods(self, p): |
| 175 """methods : method methods |
| 176 | """ |
| 177 if len(p) > 1: |
| 178 p[0] = ListFromConcat(p[1], p[2]) |
| 179 |
| 180 def p_method(self, p): |
| 181 """method : VOID NAME LPAREN parameters RPAREN ordinal SEMICOLON""" |
| 182 p[0] = ('METHOD', p[2], p[4], p[6]) |
| 183 |
| 184 def p_parameters(self, p): |
| 185 """parameters : parameter |
| 186 | parameter COMMA parameters |
| 187 | """ |
| 188 if len(p) == 2: |
| 189 p[0] = p[1] |
| 190 elif len(p) > 3: |
| 191 p[0] = ListFromConcat(p[1], p[3]) |
| 192 |
| 193 def p_parameter(self, p): |
| 194 """parameter : typename NAME ordinal""" |
| 195 p[0] = ('PARAM', p[1], p[2], p[3]) |
| 196 |
| 197 def p_typename(self, p): |
| 198 """typename : NAME |
| 199 | ARRAY""" |
| 200 p[0] = p[1] |
| 201 |
| 202 def p_ordinal(self, p): |
| 203 """ordinal : ORDINAL |
| 204 | """ |
| 205 if len(p) > 1: |
| 206 p[0] = p[1] |
| 207 |
| 208 def p_error(self, e): |
| 209 print('error: %s'%e) |
| 210 |
| 211 |
| 212 def Parse(filename): |
| 213 lexer = Lexer() |
| 214 parser = Parser(lexer) |
| 215 |
| 216 lex.lex(object=lexer) |
| 217 yacc.yacc(module=parser, debug=0, write_tables=0) |
| 218 |
| 219 tree = yacc.parse(open(filename).read()) |
| 220 return tree |
| 221 |
| 222 |
| 223 def Main(): |
| 224 if len(sys.argv) < 2: |
| 225 print("usage: %s filename" % (sys.argv[0])) |
| 226 sys.exit(1) |
| 227 tree = Parse(filename=sys.argv[1]) |
| 228 print(tree) |
| 229 |
| 230 |
| 231 if __name__ == '__main__': |
| 232 Main() |
OLD | NEW |