Merge with head.
[gem5.git] / src / mem / slicc / parser / parser.py
1 # Copyright (c) 2009 The Hewlett-Packard Development Company
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #
27 # Authors: Nathan Binkert
28
29 from ply import lex, yacc
30 import re
31
32 t_ignore = '\t '
33
34 # C or C++ comment (ignore)
35 def t_c_comment(t):
36 r'/\*(.|\n)*?\*/'
37 t.lexer.lineno += t.value.count('\n')
38
39 def t_cpp_comment(t):
40 r'//.*'
41 pass
42
43 # Define a rule so we can track line numbers
44 def t_newline(t):
45 r'\n+'
46 t.lexer.lineno += len(t.value)
47
48 reserved = {
49 'global' : 'GLOBAL',
50 'machine' : 'MACHINE',
51 'in_port' : 'IN_PORT',
52 'out_port' : 'OUT_PORT',
53 'action' : 'ACTION',
54 'transition' : 'TRANS',
55 'structure' : 'STRUCT',
56 'external_type' : 'EXTERN_TYPE',
57 'enumeration' : 'ENUM',
58 'peek' : 'PEEK',
59 'enqueue' : 'ENQUEUE',
60 'copy_head' : 'COPY_HEAD',
61 'check_allocate' : 'CHECK_ALLOCATE',
62 'check_stop_slots' : 'CHECK_STOP_SLOTS',
63 'if' : 'IF',
64 'else' : 'ELSE',
65 'return' : 'RETURN',
66 'THIS' : 'THIS',
67 'CHIP' : 'CHIP',
68 'void' : 'VOID',
69 'new' : 'NEW',
70 }
71
72 literals = ':[]{}(),='
73
74 tokens = [ 'EQ', 'NE', 'LT', 'GT', 'LE', 'GE',
75 'LEFTSHIFT', 'RIGHTSHIFT',
76 'NOT', 'AND', 'OR',
77 'PLUS', 'DASH', 'STAR', 'SLASH',
78 'DOUBLE_COLON', 'SEMICOLON',
79 'ASSIGN', 'DOT', 'LATENCY',
80 'IDENT', 'LIT_BOOL', 'FLOATNUMBER', 'NUMBER', 'STRING' ]
81 tokens += reserved.values()
82
83 t_EQ = r'=='
84 t_NE = r'!='
85 t_LT = r'<'
86 t_GT = r'>'
87 t_LE = r'<='
88 t_GE = r'>='
89 t_LEFTSHIFT = r'<<'
90 t_RIGHTSHIFT = r'>>'
91 t_NOT = r'!'
92 t_AND = r'&&'
93 t_OR = r'\|\|'
94 t_PLUS = r'\+'
95 t_DASH = r'-'
96 t_STAR = r'\*'
97 t_SLASH = r'/'
98 t_DOUBLE_COLON = r'::'
99 t_SEMICOLON = r';'
100 t_ASSIGN = r':='
101 t_DOT = r'\.'
102
103 class TokenError(Exception):
104 def __init__(self, msg, t):
105 super(TokenError, self).__init__(msg)
106 self.token = t
107
108 class ParseError(Exception):
109 def __init__(self, msg, t):
110 super(ParseError, self).__init__(msg)
111 self.token = t
112
113 def t_error(t):
114 raise TokenError("Illegal character", t)
115
116 def t_IDENT(t):
117 r'[a-zA-Z_][a-zA-Z_0-9]*'
118 if t.value == 'true':
119 t.type = 'LIT_BOOL'
120 t.value = True
121 return t
122
123 if t.value == 'false':
124 t.type = 'LIT_BOOL'
125 t.value = False
126 return t
127
128 if t.value.startswith('LATENCY_'):
129 t.type = 'LATENCY'
130 return t
131
132 t.type = reserved.get(t.value, 'IDENT') # Check for reserved words
133 return t
134
135 def t_FLOATNUMBER(t):
136 '[0-9]+[.][0-9]+'
137 try:
138 t.value = float(t.value)
139 except ValueError:
140 raise TokenError("Illegal float", t)
141 return t
142
143 def t_NUMBER(t):
144 r'[0-9]+'
145 try:
146 t.value = int(t.value)
147 except ValueError:
148 raise TokenError("Illegal number", t)
149 return t
150
151 def t_STRING1(t):
152 r'\"[^"\n]*\"'
153 t.type = 'STRING'
154 return t
155
156 def t_STRING2(t):
157 r"\'[^'\n]*\'"
158 t.type = 'STRING'
159 return t
160
161
162 def p_file(p):
163 "file : decl_l"
164 p[0] = [ x for x in p[1] if x is not None ]
165
166 def p_error(t):
167 raise ParseError("Syntax error", t)
168
169 def p_empty(p):
170 "empty :"
171 pass
172
173 def p_decl_l(p):
174 "decl_l : decls"
175 p[0] = p[1]
176
177 def p_decls(p):
178 """decls : decl decls
179 | empty"""
180 if len(p) == 3:
181 p[0] = [ p[1] ] + p[2]
182 elif len(p) == 2:
183 p[0] = []
184
185 def p_decl(p):
186 """decl : d_machine
187 | d_action
188 | d_in_port
189 | d_out_port
190 | t_trans
191 | d_extern
192 | d_global
193 | d_struct
194 | d_enum
195 | d_object
196 | d_func_decl
197 | d_func_def"""
198 p[0] = p[1]
199
200 def p_latency(p):
201 """latency : LATENCY"""
202 pass
203
204 def p_latencies(p):
205 """latencies : latency latencies
206 | empty"""
207 return []
208
209 def p_d_machine(p):
210 """d_machine : MACHINE '(' ident pair_l ')' '{' decl_l '}'
211 | MACHINE '(' ident pair_l ')' ':' type_members '{' decl_l '}'
212 | MACHINE '(' ident pair_l ')' ':' latencies '{' decl_l '}'"""
213
214 if len(p) == 9:
215 decl_l = p[7]
216 elif len(p) == 11:
217 decl_l = p[9]
218 decls = [ x for x in decl_l if x is not None ]
219 p[0] = Machine(p[3], decls)
220
221 def p_d_action(p):
222 "d_action : ACTION '(' ident pair_l ')' statement_l"
223 p[0] = Action(p[3])
224
225 def p_d_in_port(p):
226 "d_in_port : IN_PORT '(' ident ',' type ',' var pair_l ')' statement_l"
227 p[0] = InPort(p[3])
228
229 def p_d_out_port(p):
230 "d_out_port : OUT_PORT '(' ident ',' type ',' var pair_l ')' SEMICOLON"
231 p[0] = OutPort(p[3])
232
233 def p_t_trans(p):
234 """t_trans : TRANS '(' ident_l ',' ident_l ',' ident pair_l ')' ident_l
235 | TRANS '(' ident_l ',' ident_l pair_l ')' ident_l"""
236 p[0] = Transition("transition")
237
238 def p_d_extern(p):
239 """d_extern : EXTERN_TYPE '(' type pair_l ')' SEMICOLON
240 | EXTERN_TYPE '(' type pair_l ')' '{' type_methods '}'"""
241 p[0] = Extern(p[3])
242
243 def p_d_global(p):
244 "d_global : GLOBAL '(' type pair_l ')' '{' type_members '}'"
245 p[0] = Global(p[3])
246
247 def p_d_struct(p):
248 "d_struct : STRUCT '(' type pair_l ')' '{' type_members '}'"
249 p[0] = Struct(p[3])
250
251 def p_d_enum(p):
252 "d_enum : ENUM '(' type pair_l ')' '{' type_enums '}'"
253 p[0] = Enum(p[3])
254
255 def p_d_object(p):
256 "d_object : type ident pair_l SEMICOLON"
257 p[0] = Object(p[2])
258
259 def p_d_func_decl(p):
260 """d_func_decl : void ident '(' param_l ')' pair_l SEMICOLON
261 | type ident '(' param_l ')' pair_l SEMICOLON"""
262 pass
263
264 def p_d_func_def(p):
265 """d_func_def : void ident '(' param_l ')' pair_l statement_l
266 | type ident '(' param_l ')' pair_l statement_l"""
267 p[0] = Function(p[2])
268
269 # Type fields
270 def p_type_members(p):
271 """type_members : type_member type_members
272 | empty"""
273 pass
274
275 def p_type_member(p):
276 """type_member : type ident pair_l SEMICOLON
277 | type ident ASSIGN expr SEMICOLON"""
278 pass
279
280 # Methods
281 def p_type_methods(p):
282 """type_methods : type_method type_methods
283 | empty"""
284 pass
285
286 def p_type_method(p):
287 "type_method : type_or_void ident '(' type_l ')' pair_l SEMICOLON"
288 pass
289
290 # Enum fields
291 def p_type_enums(p):
292 """type_enums : type_enum type_enums
293 | empty"""
294 pass
295
296 def p_type_enum(p):
297 "type_enum : ident pair_l SEMICOLON"
298 pass
299
300 # Type
301 def p_type_l(p):
302 """type_l : types
303 | empty"""
304 pass
305
306 def p_types(p):
307 """types : type ',' types
308 | type"""
309 pass
310
311 def p_type(p):
312 "type : ident"
313 p[0] = p[1]
314
315 def p_void(p):
316 "void : VOID"
317 p[0] = None
318
319 def p_type_or_void(p):
320 """type_or_void : type
321 | void"""
322 p[0] = p[1]
323
324 # Formal Param
325 def p_param_l(p):
326 """param_l : params
327 | empty"""
328 pass
329
330 def p_params(p):
331 """params : param ',' params
332 | param"""
333 pass
334
335 def p_param(p):
336 "param : type ident"
337 pass
338
339 # Idents and lists
340 def p_ident(p):
341 "ident : IDENT"
342 p[0] = p[1]
343
344 def p_ident_l(p):
345 """ident_l : '{' idents '}'
346 | ident"""
347 p[0] = p[1]
348
349 def p_idents(p):
350 """idents : ident SEMICOLON idents
351 | ident ',' idents
352 | ident idents
353 | empty"""
354 pass
355
356 # Pair and pair lists
357 def p_pair_l(p):
358 """pair_l : ',' pairs
359 | empty"""
360 if len(p) == 3:
361 p[0] = p[2]
362 elif len(p) == 2:
363 p[0] = None
364
365 def p_pairs(p):
366 """pairs : pair ',' pairs
367 | pair"""
368 if len(p) == 4:
369 p[3].append(p[1])
370 p[0] = p[3]
371 elif len(p) == 2:
372 p[0] = [ p[1] ]
373
374 def p_pair(p):
375 """pair : ident '=' STRING
376 | ident '=' ident
377 | STRING"""
378 if len(p) == 4:
379 p[0] = p[1], p[3]
380 elif len(p) == 2:
381 p[0] = "short", p[1]
382
383 # Below are the rules for action descriptions
384 def p_statement_l(p):
385 "statement_l : '{' statements '}'"
386 pass
387
388 def p_statements(p):
389 """statements : statement statements
390 | empty"""
391 pass
392
393 def p_expr_l(p):
394 """expr_l : expr ',' expr_l
395 | expr
396 | empty"""
397 pass
398
399 def p_statement(p):
400 """statement : expr SEMICOLON
401 | expr ASSIGN expr SEMICOLON
402 | ENQUEUE '(' var ',' type pair_l ')' statement_l
403 | PEEK '(' var ',' type ')' statement_l
404 | COPY_HEAD '(' var ',' var pair_l ')' SEMICOLON
405 | CHECK_ALLOCATE '(' var ')' SEMICOLON
406 | CHECK_STOP_SLOTS '(' var ',' STRING ',' STRING ')' SEMICOLON
407 | if_statement
408 | RETURN expr SEMICOLON"""
409 pass
410
411 def p_if_statement(p):
412 """if_statement : IF '(' expr ')' statement_l ELSE statement_l
413 | IF '(' expr ')' statement_l
414 | IF '(' expr ')' statement_l ELSE if_statement"""
415 pass
416
417 def p_expr(p):
418 """expr : var
419 | literal
420 | enumeration
421 | ident '(' expr_l ')'
422 | NEW type
423 | THIS DOT var '[' expr ']' DOT var DOT ident '(' expr_l ')'
424 | THIS DOT var '[' expr ']' DOT var DOT ident
425 | CHIP '[' expr ']' DOT var '[' expr ']' DOT var DOT ident '(' expr_l ')'
426 | CHIP '[' expr ']' DOT var '[' expr ']' DOT var DOT ident
427 | expr DOT ident
428 | expr DOT ident '(' expr_l ')'
429 | type DOUBLE_COLON ident '(' expr_l ')'
430 | expr '[' expr_l ']'
431 | expr STAR expr
432 | expr SLASH expr
433 | expr PLUS expr
434 | expr DASH expr
435 | expr LT expr
436 | expr GT expr
437 | expr LE expr
438 | expr GE expr
439 | expr EQ expr
440 | expr NE expr
441 | expr AND expr
442 | expr OR expr
443 | NOT expr
444 | expr RIGHTSHIFT expr
445 | expr LEFTSHIFT expr
446 | '(' expr ')'"""
447 pass
448
449 def p_literal(p):
450 """literal : STRING
451 | NUMBER
452 | FLOATNUMBER
453 | LIT_BOOL"""
454 pass
455
456 def p_enumeration(p):
457 "enumeration : ident ':' ident"
458 pass
459
460 def p_var(p):
461 "var : ident"
462 pass
463
464 lex.lex()
465 yacc.yacc(write_tables=0)
466
467 slicc_generated_cc = set([
468 'ControllerFactory.cc',
469 'MachineType.cc'])
470
471 slicc_generated_hh = set([
472 'ControllerFactory.hh',
473 'MachineType.hh',
474 'Types.hh',
475 'protocol_name.hh' ])
476
477 class Machine(object):
478 def __init__(self, name, decls):
479 self.name = name
480 self.decls = decls
481
482 def add(self, hh, cc):
483 hh.add('%s_Controller.hh' % self.name)
484 hh.add('%s_Profiler.hh' % self.name)
485
486 cc.add('%s_Controller.cc' % self.name)
487 cc.add('%s_Profiler.cc' % self.name)
488 cc.add('%s_Transitions.cc' % self.name)
489 cc.add('%s_Wakeup.cc' % self.name)
490
491 for decl in self.decls:
492 decl.add(hh, cc, self.name)
493
494 class Declaration(object):
495 hh = False
496 cc = False
497 def __init__(self, name):
498 self.name = name
499
500 def add(self, hh, cc, name=None):
501 #print '>>>', type(self).__name__, self.name
502 if name:
503 name += '_'
504 else:
505 name = ""
506 if self.hh:
507 hh.add('%s%s.hh' % (name, self.name))
508 if self.cc:
509 cc.add('%s%s.cc' % (name, self.name))
510
511 class Action(Declaration): pass
512 class InPort(Declaration): pass
513 class OutPort(Declaration): pass
514 class Transition(Declaration): pass
515 class Extern(Declaration): pass
516 class Global(Declaration):
517 hh = True
518 cc = True
519 class Struct(Declaration):
520 hh = True
521 cc = True
522 class Enum(Declaration):
523 hh = True
524 cc = True
525 class Object(Declaration): pass
526 class Function(Declaration):
527 cc = True
528
529 def read_slicc(sources):
530 if not isinstance(sources, (list,tuple)):
531 sources = [ sources ]
532
533 sm_files = []
534 for source in sources:
535 for sm_file in file(source, "r"):
536 sm_file = sm_file.strip()
537 if not sm_file:
538 continue
539 if sm_file.startswith("#"):
540 continue
541 sm_files.append(sm_file)
542
543 return sm_files
544
545 def scan(filenames):
546 hh = slicc_generated_hh.copy()
547 cc = slicc_generated_cc.copy()
548
549 for filename in filenames:
550 lex.lexer.lineno = 1
551 try:
552 results = yacc.parse(file(filename, 'r').read())
553 except (TokenError, ParseError), e:
554 sys.exit("%s: %s:%d" % (e, filename, e.token.lineno))
555
556 for result in results:
557 result.add(hh, cc)
558
559 return list(hh), list(cc)
560
561 if __name__ == '__main__':
562 import sys
563
564 hh, cc = scan(read_slicc(sys.argv[1:]))
565 hh.sort()
566 cc.sort()
567 print 'Headers:'
568 for i in hh:
569 print ' %s' % i
570
571 print 'Sources:'
572 for i in cc:
573 print ' %s' % i