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 | |
13 # Try to load the ply module, if not, then assume it is in the third_party | 12 # Try to load the ply module, if not, then assume it is in the third_party |
14 # directory. | 13 # directory. |
15 try: | 14 try: |
16 # Disable lint check which fails to find the ply module. | 15 # Disable lint check which fails to find the ply module. |
17 # pylint: disable=F0401 | 16 # pylint: disable=F0401 |
18 from ply import lex | 17 from ply import lex |
19 from ply import yacc | 18 from ply import yacc |
20 except ImportError: | 19 except ImportError: |
21 module_path, module_name = os.path.split(__file__) | 20 module_path, module_name = os.path.split(__file__) |
22 third_party = os.path.join( | 21 third_party = os.path.join( |
23 module_path, os.pardir, os.pardir, os.pardir, os.pardir, 'third_party') | 22 module_path, os.pardir, os.pardir, os.pardir, os.pardir, 'third_party') |
24 sys.path.append(third_party) | 23 sys.path.append(third_party) |
25 # pylint: disable=F0401 | 24 # pylint: disable=F0401 |
26 from ply import lex | 25 from ply import lex |
27 from ply import yacc | 26 from ply import yacc |
28 | 27 |
| 28 from mojo_lexer import Lexer |
| 29 |
29 | 30 |
30 def ListFromConcat(*items): | 31 def ListFromConcat(*items): |
31 """Generate list by concatenating inputs""" | 32 """Generate list by concatenating inputs""" |
32 itemsout = [] | 33 itemsout = [] |
33 for item in items: | 34 for item in items: |
34 if item is None: | 35 if item is None: |
35 continue | 36 continue |
36 if type(item) is not type([]): | 37 if type(item) is not type([]): |
37 itemsout.append(item) | 38 itemsout.append(item) |
38 else: | 39 else: |
39 itemsout.extend(item) | 40 itemsout.extend(item) |
40 | 41 |
41 return itemsout | 42 return itemsout |
42 | 43 |
43 | 44 |
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 | |
145 class Parser(object): | 45 class Parser(object): |
146 | 46 |
147 def __init__(self, lexer): | 47 def __init__(self, lexer): |
148 self.tokens = lexer.tokens | 48 self.tokens = lexer.tokens |
149 | 49 |
150 def p_module(self, p): | 50 def p_module(self, p): |
151 """module : MODULE NAME LCURLY definitions RCURLY""" | 51 """module : MODULE NAME LBRACE definitions RBRACE""" |
152 p[0] = ('MODULE', p[2], p[4]) | 52 p[0] = ('MODULE', p[2], p[4]) |
153 | 53 |
154 def p_definitions(self, p): | 54 def p_definitions(self, p): |
155 """definitions : definition definitions | 55 """definitions : definition definitions |
156 |""" | 56 |""" |
157 if len(p) > 1: | 57 if len(p) > 1: |
158 p[0] = ListFromConcat(p[1], p[2]) | 58 p[0] = ListFromConcat(p[1], p[2]) |
159 | 59 |
160 def p_definition(self, p): | 60 def p_definition(self, p): |
161 """definition : struct | 61 """definition : struct |
(...skipping 10 matching lines...) Expand all Loading... |
172 def p_attributes(self, p): | 72 def p_attributes(self, p): |
173 """attributes : attribute | 73 """attributes : attribute |
174 | attribute COMMA attributes | 74 | attribute COMMA attributes |
175 | """ | 75 | """ |
176 if len(p) == 2: | 76 if len(p) == 2: |
177 p[0] = ListFromConcat(p[1]) | 77 p[0] = ListFromConcat(p[1]) |
178 elif len(p) > 3: | 78 elif len(p) > 3: |
179 p[0] = ListFromConcat(p[1], p[3]) | 79 p[0] = ListFromConcat(p[1], p[3]) |
180 | 80 |
181 def p_attribute(self, p): | 81 def p_attribute(self, p): |
182 """attribute : NAME EQUALS NUMBER | 82 """attribute : NAME EQUALS expression |
183 | NAME EQUALS NAME""" | 83 | NAME EQUALS NAME""" |
184 p[0] = ('ATTRIBUTE', p[1], p[3]) | 84 p[0] = ('ATTRIBUTE', p[1], p[3]) |
185 | 85 |
186 def p_struct(self, p): | 86 def p_struct(self, p): |
187 """struct : attribute_section STRUCT NAME LCURLY struct_body RCURLY SEMICOLO
N""" | 87 """struct : attribute_section STRUCT NAME LBRACE struct_body RBRACE SEMI""" |
188 p[0] = ('STRUCT', p[3], p[1], p[5]) | 88 p[0] = ('STRUCT', p[3], p[1], p[5]) |
189 | 89 |
190 def p_struct_body(self, p): | 90 def p_struct_body(self, p): |
191 """struct_body : field struct_body | 91 """struct_body : field struct_body |
192 | enum struct_body | 92 | enum struct_body |
193 |""" | 93 |""" |
194 if len(p) > 1: | 94 if len(p) > 1: |
195 p[0] = ListFromConcat(p[1], p[2]) | 95 p[0] = ListFromConcat(p[1], p[2]) |
196 | 96 |
197 def p_field(self, p): | 97 def p_field(self, p): |
198 """field : typename NAME ordinal SEMICOLON""" | 98 """field : typename NAME ordinal SEMI""" |
199 p[0] = ('FIELD', p[1], p[2], p[3]) | 99 p[0] = ('FIELD', p[1], p[2], p[3]) |
200 | 100 |
201 def p_interface(self, p): | 101 def p_interface(self, p): |
202 """interface : attribute_section INTERFACE NAME LCURLY interface_body RCURLY
SEMICOLON""" | 102 """interface : attribute_section INTERFACE NAME LBRACE interface_body RBRACE
SEMI""" |
203 p[0] = ('INTERFACE', p[3], p[1], p[5]) | 103 p[0] = ('INTERFACE', p[3], p[1], p[5]) |
204 | 104 |
205 def p_interface_body(self, p): | 105 def p_interface_body(self, p): |
206 """interface_body : method interface_body | 106 """interface_body : method interface_body |
207 | enum interface_body | 107 | enum interface_body |
208 | """ | 108 | """ |
209 if len(p) > 1: | 109 if len(p) > 1: |
210 p[0] = ListFromConcat(p[1], p[2]) | 110 p[0] = ListFromConcat(p[1], p[2]) |
211 | 111 |
212 def p_method(self, p): | 112 def p_method(self, p): |
213 """method : VOID NAME LPAREN parameters RPAREN ordinal SEMICOLON""" | 113 """method : VOID NAME LPAREN parameters RPAREN ordinal SEMI""" |
214 p[0] = ('METHOD', p[2], p[4], p[6]) | 114 p[0] = ('METHOD', p[2], p[4], p[6]) |
215 | 115 |
216 def p_parameters(self, p): | 116 def p_parameters(self, p): |
217 """parameters : parameter | 117 """parameters : parameter |
218 | parameter COMMA parameters | 118 | parameter COMMA parameters |
219 | """ | 119 | """ |
220 if len(p) == 1: | 120 if len(p) == 1: |
221 p[0] = [] | 121 p[0] = [] |
222 elif len(p) == 2: | 122 elif len(p) == 2: |
223 p[0] = ListFromConcat(p[1]) | 123 p[0] = ListFromConcat(p[1]) |
224 elif len(p) > 3: | 124 elif len(p) > 3: |
225 p[0] = ListFromConcat(p[1], p[3]) | 125 p[0] = ListFromConcat(p[1], p[3]) |
226 | 126 |
227 def p_parameter(self, p): | 127 def p_parameter(self, p): |
228 """parameter : typename NAME ordinal""" | 128 """parameter : typename NAME ordinal""" |
229 p[0] = ('PARAM', p[1], p[2], p[3]) | 129 p[0] = ('PARAM', p[1], p[2], p[3]) |
230 | 130 |
231 def p_typename(self, p): | 131 def p_typename(self, p): |
232 """typename : basictypename | 132 """typename : basictypename |
233 | array""" | 133 | array""" |
234 p[0] = p[1] | 134 p[0] = p[1] |
235 | 135 |
236 def p_basictypename(self, p): | 136 def p_basictypename(self, p): |
237 """basictypename : NAME | 137 """basictypename : NAME |
238 | HANDLE | 138 | HANDLE |
239 | specializedhandle""" | 139 | specializedhandle""" |
240 p[0] = p[1] | 140 p[0] = p[1] |
241 | 141 |
242 def p_specializedhandle(self, p): | 142 def p_specializedhandle(self, p): |
243 """specializedhandle : HANDLE LANGLE specializedhandlename RANGLE""" | 143 """specializedhandle : HANDLE LT specializedhandlename GT""" |
244 p[0] = "handle<" + p[3] + ">" | 144 p[0] = "handle<" + p[3] + ">" |
245 | 145 |
246 def p_specializedhandlename(self, p): | 146 def p_specializedhandlename(self, p): |
247 """specializedhandlename : DATAPIPECONSUMER | 147 """specializedhandlename : DATA_PIPE_CONSUMER |
248 | DATAPIPEPRODUCER | 148 | DATA_PIPE_PRODUCER |
249 | MESSAGEPIPE""" | 149 | MESSAGE_PIPE""" |
250 p[0] = p[1] | 150 p[0] = p[1] |
251 | 151 |
252 def p_array(self, p): | 152 def p_array(self, p): |
253 """array : basictypename LBRACKET RBRACKET""" | 153 """array : basictypename LBRACKET RBRACKET""" |
254 p[0] = p[1] + "[]" | 154 p[0] = p[1] + "[]" |
255 | 155 |
256 def p_ordinal(self, p): | 156 def p_ordinal(self, p): |
257 """ordinal : ORDINAL | 157 """ordinal : ORDINAL |
258 | """ | 158 | """ |
259 if len(p) > 1: | 159 if len(p) > 1: |
260 p[0] = p[1] | 160 p[0] = p[1] |
261 | 161 |
262 def p_enum(self, p): | 162 def p_enum(self, p): |
263 """enum : ENUM NAME LCURLY enum_fields RCURLY SEMICOLON""" | 163 """enum : ENUM NAME LBRACE enum_fields RBRACE SEMI""" |
264 p[0] = ('ENUM', p[2], p[4]) | 164 p[0] = ('ENUM', p[2], p[4]) |
265 | 165 |
266 def p_enum_fields(self, p): | 166 def p_enum_fields(self, p): |
267 """enum_fields : enum_field | 167 """enum_fields : enum_field |
268 | enum_field COMMA enum_fields | 168 | enum_field COMMA enum_fields |
269 |""" | 169 |""" |
270 if len(p) == 2: | 170 if len(p) == 2: |
271 p[0] = ListFromConcat(p[1]) | 171 p[0] = ListFromConcat(p[1]) |
272 elif len(p) > 3: | 172 elif len(p) > 3: |
273 p[0] = ListFromConcat(p[1], p[3]) | 173 p[0] = ListFromConcat(p[1], p[3]) |
274 | 174 |
275 def p_enum_field(self, p): | 175 def p_enum_field(self, p): |
276 """enum_field : NAME | 176 """enum_field : NAME |
277 | NAME EQUALS NUMBER""" | 177 | NAME EQUALS expression""" |
278 if len(p) == 2: | 178 if len(p) == 2: |
279 p[0] = ('ENUM_FIELD', p[1], None) | 179 p[0] = ('ENUM_FIELD', p[1], None) |
280 else: | 180 else: |
281 p[0] = ('ENUM_FIELD', p[1], p[3]) | 181 p[0] = ('ENUM_FIELD', p[1], p[3]) |
282 | 182 |
| 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 |
283 def p_error(self, e): | 255 def p_error(self, e): |
284 print('error: %s'%e) | 256 print('error: %s'%e) |
285 | 257 |
286 | 258 |
287 def Parse(filename): | 259 def Parse(filename): |
288 lexer = Lexer() | 260 lexer = Lexer() |
289 parser = Parser(lexer) | 261 parser = Parser(lexer) |
290 | 262 |
291 lex.lex(object=lexer) | 263 lex.lex(object=lexer) |
292 yacc.yacc(module=parser, debug=0, write_tables=0) | 264 yacc.yacc(module=parser, debug=0, write_tables=0) |
293 | 265 |
294 tree = yacc.parse(open(filename).read()) | 266 tree = yacc.parse(open(filename).read()) |
295 return tree | 267 return tree |
296 | 268 |
297 | 269 |
298 def Main(): | 270 def Main(): |
299 if len(sys.argv) < 2: | 271 if len(sys.argv) < 2: |
300 print("usage: %s filename" % (sys.argv[0])) | 272 print("usage: %s filename" % (sys.argv[0])) |
301 sys.exit(1) | 273 sys.exit(1) |
302 tree = Parse(filename=sys.argv[1]) | 274 tree = Parse(filename=sys.argv[1]) |
303 print(tree) | 275 print(tree) |
304 | 276 |
305 | 277 |
306 if __name__ == '__main__': | 278 if __name__ == '__main__': |
307 Main() | 279 Main() |
OLD | NEW |