OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Generates a syntax tree from a Mojo IDL file.""" | 6 """Generates a syntax tree from a Mojo IDL file.""" |
7 | 7 |
8 | 8 |
9 import sys | 9 import sys |
10 import os.path | 10 import os.path |
11 | 11 |
| 12 |
12 # Try to load the ply module, if not, then assume it is in the third_party | 13 # Try to load the ply module, if not, then assume it is in the third_party |
13 # directory. | 14 # directory. |
14 try: | 15 try: |
15 # Disable lint check which fails to find the ply module. | 16 # Disable lint check which fails to find the ply module. |
16 # pylint: disable=F0401 | 17 # pylint: disable=F0401 |
17 from ply import lex | 18 from ply import lex |
18 from ply import yacc | 19 from ply import yacc |
19 except ImportError: | 20 except ImportError: |
20 module_path, module_name = os.path.split(__file__) | 21 module_path, module_name = os.path.split(__file__) |
21 third_party = os.path.join( | 22 third_party = os.path.join( |
22 module_path, os.pardir, os.pardir, os.pardir, os.pardir, 'third_party') | 23 module_path, os.pardir, os.pardir, os.pardir, os.pardir, 'third_party') |
23 sys.path.append(third_party) | 24 sys.path.append(third_party) |
24 # pylint: disable=F0401 | 25 # pylint: disable=F0401 |
25 from ply import lex | 26 from ply import lex |
26 from ply import yacc | 27 from ply import yacc |
27 | 28 |
28 from mojo_lexer import Lexer | |
29 | |
30 | 29 |
31 def ListFromConcat(*items): | 30 def ListFromConcat(*items): |
32 """Generate list by concatenating inputs""" | 31 """Generate list by concatenating inputs""" |
33 itemsout = [] | 32 itemsout = [] |
34 for item in items: | 33 for item in items: |
35 if item is None: | 34 if item is None: |
36 continue | 35 continue |
37 if type(item) is not type([]): | 36 if type(item) is not type([]): |
38 itemsout.append(item) | 37 itemsout.append(item) |
39 else: | 38 else: |
40 itemsout.extend(item) | 39 itemsout.extend(item) |
41 | 40 |
42 return itemsout | 41 return itemsout |
43 | 42 |
44 | 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 'ORDINAL', |
| 52 |
| 53 'HANDLE', |
| 54 'DATAPIPECONSUMER', |
| 55 'DATAPIPEPRODUCER', |
| 56 'MESSAGEPIPE', |
| 57 |
| 58 'MODULE', |
| 59 'STRUCT', |
| 60 'INTERFACE', |
| 61 'ENUM', |
| 62 'VOID', |
| 63 |
| 64 'LCURLY', |
| 65 'RCURLY', |
| 66 'LPAREN', |
| 67 'RPAREN', |
| 68 'LANGLE', |
| 69 'RANGLE', |
| 70 'LBRACKET', |
| 71 'RBRACKET', |
| 72 'COMMA', |
| 73 'SEMICOLON', |
| 74 'EQUALS', |
| 75 ) |
| 76 |
| 77 t_LCURLY = r'{' |
| 78 t_RCURLY = r'}' |
| 79 t_LPAREN = r'\(' |
| 80 t_RPAREN = r'\)' |
| 81 t_LANGLE = r'<' |
| 82 t_RANGLE = r'>' |
| 83 t_LBRACKET = r'\[' |
| 84 t_RBRACKET = r'\]' |
| 85 t_COMMA = r',' |
| 86 t_SEMICOLON = r';' |
| 87 t_EQUALS = r'=' |
| 88 t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' |
| 89 t_NUMBER = r'\d+' |
| 90 t_ORDINAL = r'@[0-9]*' |
| 91 |
| 92 def t_HANDLE(self, t): |
| 93 r'handle' |
| 94 return t |
| 95 |
| 96 def t_DATAPIPECONSUMER(self, t): |
| 97 r'data_pipe_consumer' |
| 98 return t |
| 99 |
| 100 def t_DATAPIPEPRODUCER(self, t): |
| 101 r'data_pipe_producer' |
| 102 return t |
| 103 |
| 104 def t_MESSAGEPIPE(self, t): |
| 105 r'message_pipe' |
| 106 return t |
| 107 |
| 108 def t_MODULE(self, t): |
| 109 r'module' |
| 110 return t |
| 111 |
| 112 def t_STRUCT(self, t): |
| 113 r'struct' |
| 114 return t |
| 115 |
| 116 def t_INTERFACE(self, t): |
| 117 r'interface' |
| 118 return t |
| 119 |
| 120 def t_ENUM(self, t): |
| 121 r'enum' |
| 122 return t |
| 123 |
| 124 def t_VOID(self, t): |
| 125 r'void' |
| 126 return t |
| 127 |
| 128 # Ignore C and C++ style comments |
| 129 def t_COMMENT(self, t): |
| 130 r'(/\*(.|\n)*?\*/)|(//.*(\n[ \t]*//.*)*)' |
| 131 pass |
| 132 |
| 133 # Ignored characters |
| 134 t_ignore = " \t" |
| 135 |
| 136 def t_newline(self, t): |
| 137 r'\n+' |
| 138 t.lexer.lineno += t.value.count("\n") |
| 139 |
| 140 def t_error(self, t): |
| 141 print("Illegal character '%s'" % t.value[0]) |
| 142 t.lexer.skip(1) |
| 143 |
| 144 |
45 class Parser(object): | 145 class Parser(object): |
46 | 146 |
47 def __init__(self, lexer): | 147 def __init__(self, lexer): |
48 self.tokens = lexer.tokens | 148 self.tokens = lexer.tokens |
49 | 149 |
50 def p_module(self, p): | 150 def p_module(self, p): |
51 """module : MODULE NAME LBRACE definitions RBRACE""" | 151 """module : MODULE NAME LCURLY definitions RCURLY""" |
52 p[0] = ('MODULE', p[2], p[4]) | 152 p[0] = ('MODULE', p[2], p[4]) |
53 | 153 |
54 def p_definitions(self, p): | 154 def p_definitions(self, p): |
55 """definitions : definition definitions | 155 """definitions : definition definitions |
56 |""" | 156 |""" |
57 if len(p) > 1: | 157 if len(p) > 1: |
58 p[0] = ListFromConcat(p[1], p[2]) | 158 p[0] = ListFromConcat(p[1], p[2]) |
59 | 159 |
60 def p_definition(self, p): | 160 def p_definition(self, p): |
61 """definition : struct | 161 """definition : struct |
(...skipping 10 matching lines...) Expand all Loading... |
72 def p_attributes(self, p): | 172 def p_attributes(self, p): |
73 """attributes : attribute | 173 """attributes : attribute |
74 | attribute COMMA attributes | 174 | attribute COMMA attributes |
75 | """ | 175 | """ |
76 if len(p) == 2: | 176 if len(p) == 2: |
77 p[0] = ListFromConcat(p[1]) | 177 p[0] = ListFromConcat(p[1]) |
78 elif len(p) > 3: | 178 elif len(p) > 3: |
79 p[0] = ListFromConcat(p[1], p[3]) | 179 p[0] = ListFromConcat(p[1], p[3]) |
80 | 180 |
81 def p_attribute(self, p): | 181 def p_attribute(self, p): |
82 """attribute : NAME EQUALS expression | 182 """attribute : NAME EQUALS NUMBER |
83 | NAME EQUALS NAME""" | 183 | NAME EQUALS NAME""" |
84 p[0] = ('ATTRIBUTE', p[1], p[3]) | 184 p[0] = ('ATTRIBUTE', p[1], p[3]) |
85 | 185 |
86 def p_struct(self, p): | 186 def p_struct(self, p): |
87 """struct : attribute_section STRUCT NAME LBRACE struct_body RBRACE SEMI""" | 187 """struct : attribute_section STRUCT NAME LCURLY struct_body RCURLY SEMICOLO
N""" |
88 p[0] = ('STRUCT', p[3], p[1], p[5]) | 188 p[0] = ('STRUCT', p[3], p[1], p[5]) |
89 | 189 |
90 def p_struct_body(self, p): | 190 def p_struct_body(self, p): |
91 """struct_body : field struct_body | 191 """struct_body : field struct_body |
92 | enum struct_body | 192 | enum struct_body |
93 |""" | 193 |""" |
94 if len(p) > 1: | 194 if len(p) > 1: |
95 p[0] = ListFromConcat(p[1], p[2]) | 195 p[0] = ListFromConcat(p[1], p[2]) |
96 | 196 |
97 def p_field(self, p): | 197 def p_field(self, p): |
98 """field : typename NAME ordinal SEMI""" | 198 """field : typename NAME ordinal SEMICOLON""" |
99 p[0] = ('FIELD', p[1], p[2], p[3]) | 199 p[0] = ('FIELD', p[1], p[2], p[3]) |
100 | 200 |
101 def p_interface(self, p): | 201 def p_interface(self, p): |
102 """interface : attribute_section INTERFACE NAME LBRACE interface_body RBRACE
SEMI""" | 202 """interface : attribute_section INTERFACE NAME LCURLY interface_body RCURLY
SEMICOLON""" |
103 p[0] = ('INTERFACE', p[3], p[1], p[5]) | 203 p[0] = ('INTERFACE', p[3], p[1], p[5]) |
104 | 204 |
105 def p_interface_body(self, p): | 205 def p_interface_body(self, p): |
106 """interface_body : method interface_body | 206 """interface_body : method interface_body |
107 | enum interface_body | 207 | enum interface_body |
108 | """ | 208 | """ |
109 if len(p) > 1: | 209 if len(p) > 1: |
110 p[0] = ListFromConcat(p[1], p[2]) | 210 p[0] = ListFromConcat(p[1], p[2]) |
111 | 211 |
112 def p_method(self, p): | 212 def p_method(self, p): |
113 """method : VOID NAME LPAREN parameters RPAREN ordinal SEMI""" | 213 """method : VOID NAME LPAREN parameters RPAREN ordinal SEMICOLON""" |
114 p[0] = ('METHOD', p[2], p[4], p[6]) | 214 p[0] = ('METHOD', p[2], p[4], p[6]) |
115 | 215 |
116 def p_parameters(self, p): | 216 def p_parameters(self, p): |
117 """parameters : parameter | 217 """parameters : parameter |
118 | parameter COMMA parameters | 218 | parameter COMMA parameters |
119 | """ | 219 | """ |
120 if len(p) == 1: | 220 if len(p) == 1: |
121 p[0] = [] | 221 p[0] = [] |
122 elif len(p) == 2: | 222 elif len(p) == 2: |
123 p[0] = ListFromConcat(p[1]) | 223 p[0] = ListFromConcat(p[1]) |
124 elif len(p) > 3: | 224 elif len(p) > 3: |
125 p[0] = ListFromConcat(p[1], p[3]) | 225 p[0] = ListFromConcat(p[1], p[3]) |
126 | 226 |
127 def p_parameter(self, p): | 227 def p_parameter(self, p): |
128 """parameter : typename NAME ordinal""" | 228 """parameter : typename NAME ordinal""" |
129 p[0] = ('PARAM', p[1], p[2], p[3]) | 229 p[0] = ('PARAM', p[1], p[2], p[3]) |
130 | 230 |
131 def p_typename(self, p): | 231 def p_typename(self, p): |
132 """typename : basictypename | 232 """typename : basictypename |
133 | array""" | 233 | array""" |
134 p[0] = p[1] | 234 p[0] = p[1] |
135 | 235 |
136 def p_basictypename(self, p): | 236 def p_basictypename(self, p): |
137 """basictypename : NAME | 237 """basictypename : NAME |
138 | HANDLE | 238 | HANDLE |
139 | specializedhandle""" | 239 | specializedhandle""" |
140 p[0] = p[1] | 240 p[0] = p[1] |
141 | 241 |
142 def p_specializedhandle(self, p): | 242 def p_specializedhandle(self, p): |
143 """specializedhandle : HANDLE LT specializedhandlename GT""" | 243 """specializedhandle : HANDLE LANGLE specializedhandlename RANGLE""" |
144 p[0] = "handle<" + p[3] + ">" | 244 p[0] = "handle<" + p[3] + ">" |
145 | 245 |
146 def p_specializedhandlename(self, p): | 246 def p_specializedhandlename(self, p): |
147 """specializedhandlename : DATA_PIPE_CONSUMER | 247 """specializedhandlename : DATAPIPECONSUMER |
148 | DATA_PIPE_PRODUCER | 248 | DATAPIPEPRODUCER |
149 | MESSAGE_PIPE""" | 249 | MESSAGEPIPE""" |
150 p[0] = p[1] | 250 p[0] = p[1] |
151 | 251 |
152 def p_array(self, p): | 252 def p_array(self, p): |
153 """array : basictypename LBRACKET RBRACKET""" | 253 """array : basictypename LBRACKET RBRACKET""" |
154 p[0] = p[1] + "[]" | 254 p[0] = p[1] + "[]" |
155 | 255 |
156 def p_ordinal(self, p): | 256 def p_ordinal(self, p): |
157 """ordinal : ORDINAL | 257 """ordinal : ORDINAL |
158 | """ | 258 | """ |
159 if len(p) > 1: | 259 if len(p) > 1: |
160 p[0] = p[1] | 260 p[0] = p[1] |
161 | 261 |
162 def p_enum(self, p): | 262 def p_enum(self, p): |
163 """enum : ENUM NAME LBRACE enum_fields RBRACE SEMI""" | 263 """enum : ENUM NAME LCURLY enum_fields RCURLY SEMICOLON""" |
164 p[0] = ('ENUM', p[2], p[4]) | 264 p[0] = ('ENUM', p[2], p[4]) |
165 | 265 |
166 def p_enum_fields(self, p): | 266 def p_enum_fields(self, p): |
167 """enum_fields : enum_field | 267 """enum_fields : enum_field |
168 | enum_field COMMA enum_fields | 268 | enum_field COMMA enum_fields |
169 |""" | 269 |""" |
170 if len(p) == 2: | 270 if len(p) == 2: |
171 p[0] = ListFromConcat(p[1]) | 271 p[0] = ListFromConcat(p[1]) |
172 elif len(p) > 3: | 272 elif len(p) > 3: |
173 p[0] = ListFromConcat(p[1], p[3]) | 273 p[0] = ListFromConcat(p[1], p[3]) |
174 | 274 |
175 def p_enum_field(self, p): | 275 def p_enum_field(self, p): |
176 """enum_field : NAME | 276 """enum_field : NAME |
177 | NAME EQUALS expression""" | 277 | NAME EQUALS NUMBER""" |
178 if len(p) == 2: | 278 if len(p) == 2: |
179 p[0] = ('ENUM_FIELD', p[1], None) | 279 p[0] = ('ENUM_FIELD', p[1], None) |
180 else: | 280 else: |
181 p[0] = ('ENUM_FIELD', p[1], p[3]) | 281 p[0] = ('ENUM_FIELD', p[1], p[3]) |
182 | 282 |
183 ### Expressions ### | |
184 | |
185 def p_expression(self, p): | |
186 """expression : conditional_expression""" | |
187 p[0] = p[1] | |
188 | |
189 def p_conditional_expression(self, p): | |
190 """conditional_expression : binary_expression | |
191 | binary_expression CONDOP expression COLON condit
ional_expression""" | |
192 # Just pass the arguments through. I don't think it's possible to preserve | |
193 # the spaces of the original, so just put a single space between them. | |
194 p[0] = ' '.join(p[1:]) | |
195 | |
196 # PLY lets us specify precedence of operators, but since we don't actually | |
197 # evaluate them, we don't need that here. | |
198 def p_binary_expression(self, p): | |
199 """binary_expression : unary_expression | |
200 | binary_expression binary_operator binary_expression""
" | |
201 p[0] = ' '.join(p[1:]) | |
202 | |
203 def p_binary_operator(self, p): | |
204 """binary_operator : TIMES | |
205 | DIVIDE | |
206 | MOD | |
207 | PLUS | |
208 | MINUS | |
209 | RSHIFT | |
210 | LSHIFT | |
211 | LT | |
212 | LE | |
213 | GE | |
214 | GT | |
215 | EQ | |
216 | NE | |
217 | AND | |
218 | OR | |
219 | XOR | |
220 | LAND | |
221 | LOR""" | |
222 p[0] = p[1] | |
223 | |
224 def p_unary_expression(self, p): | |
225 """unary_expression : primary_expression | |
226 | unary_operator expression""" | |
227 p[0] = ''.join(p[1:]) | |
228 | |
229 def p_unary_operator(self, p): | |
230 """unary_operator : TIMES | |
231 | PLUS | |
232 | MINUS | |
233 | NOT | |
234 | LNOT""" | |
235 p[0] = p[1] | |
236 | |
237 def p_primary_expression(self, p): | |
238 """primary_expression : constant | |
239 | NAME | |
240 | LPAREN expression RPAREN""" | |
241 p[0] = ''.join(p[1:]) | |
242 | |
243 def p_constant(self, p): | |
244 """constant : INT_CONST_DEC | |
245 | INT_CONST_OCT | |
246 | INT_CONST_HEX | |
247 | FLOAT_CONST | |
248 | HEX_FLOAT_CONST | |
249 | CHAR_CONST | |
250 | WCHAR_CONST | |
251 | STRING_LITERAL | |
252 | WSTRING_LITERAL""" | |
253 p[0] = ''.join(p[1:]) | |
254 | |
255 def p_error(self, e): | 283 def p_error(self, e): |
256 print('error: %s'%e) | 284 print('error: %s'%e) |
257 | 285 |
258 | 286 |
259 def Parse(filename): | 287 def Parse(filename): |
260 lexer = Lexer() | 288 lexer = Lexer() |
261 parser = Parser(lexer) | 289 parser = Parser(lexer) |
262 | 290 |
263 lex.lex(object=lexer) | 291 lex.lex(object=lexer) |
264 yacc.yacc(module=parser, debug=0, write_tables=0) | 292 yacc.yacc(module=parser, debug=0, write_tables=0) |
265 | 293 |
266 tree = yacc.parse(open(filename).read()) | 294 tree = yacc.parse(open(filename).read()) |
267 return tree | 295 return tree |
268 | 296 |
269 | 297 |
270 def Main(): | 298 def Main(): |
271 if len(sys.argv) < 2: | 299 if len(sys.argv) < 2: |
272 print("usage: %s filename" % (sys.argv[0])) | 300 print("usage: %s filename" % (sys.argv[0])) |
273 sys.exit(1) | 301 sys.exit(1) |
274 tree = Parse(filename=sys.argv[1]) | 302 tree = Parse(filename=sys.argv[1]) |
275 print(tree) | 303 print(tree) |
276 | 304 |
277 | 305 |
278 if __name__ == '__main__': | 306 if __name__ == '__main__': |
279 Main() | 307 Main() |
OLD | NEW |