parser.py revision 6863:21fbf0412e0d
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
29import os.path
30import re
31import sys
32
33from m5.util.grammar import Grammar, TokenError, ParseError
34
35import slicc.ast as ast
36import slicc.util as util
37from slicc.symbols import SymbolTable
38
39def read_slicc(sources):
40    if not isinstance(sources, (list,tuple)):
41        sources = [ sources ]
42
43    for source in sources:
44        for sm_file in file(source, "r"):
45            sm_file = sm_file.strip()
46            if not sm_file:
47                continue
48            if sm_file.startswith("#"):
49                continue
50            yield sm_file
51
52class SLICC(Grammar):
53    def __init__(self, **kwargs):
54        super(SLICC, self).__init__(**kwargs)
55        self.decl_list_vec = []
56        self.current_file = None
57        self.symtab = SymbolTable()
58
59    def parse(self, filename):
60        self.current_file = filename
61        f = file(filename, 'r')
62        text = f.read()
63        try:
64            decl_list = super(SLICC, self).parse(text)
65        except (TokenError, ParseError), e:
66            sys.exit("%s: %s:%d" % (e, filename, e.token.lineno))
67        self.decl_list_vec.append(decl_list)
68        self.current_file = None
69
70    def _load(self, *filenames):
71        filenames = list(filenames)
72        while filenames:
73            f = filenames.pop(0)
74            if isinstance(f, (list, tuple)):
75                filenames[0:0] = list(f)
76                continue
77
78            yield f
79            if f.endswith(".slicc"):
80                dirname,basename = os.path.split(f)
81                filenames[0:0] = [ os.path.join(dirname, x) \
82                                   for x in read_slicc(f)]
83            else:
84                assert f.endswith(".sm")
85                self.parse(f)
86
87    def load(self, *filenames, **kwargs):
88        verbose = kwargs.pop("verbose", False)
89        if kwargs:
90            raise TypeError
91
92        gen = self._load(*filenames)
93        if verbose:
94            return gen
95        else:
96            # Run out the generator if we don't want the verbosity
97            for foo in gen:
98                pass
99
100    def findMachines(self):
101        for decl_list in self.decl_list_vec:
102            decl_list.findMachines()
103
104    def generate(self):
105        for decl_list in self.decl_list_vec:
106            decl_list.generate()
107
108    def writeCodeFiles(self, code_path):
109        util.makeDir(code_path)
110        self.symtab.writeCodeFiles(code_path)
111
112    def writeHTMLFiles(self, code_path):
113        util.makeDir(code_path)
114        self.symtab.writeHTMLFiles(code_path)
115
116    def files(self):
117        f = set([
118            'ControllerFactory.cc',
119            'ControllerFactory.hh',
120            'MachineType.cc',
121            'MachineType.hh',
122            'Types.hh' ])
123
124        for decl_list in self.decl_list_vec:
125            f |= decl_list.files()
126
127        return f
128
129    t_ignore = '\t '
130
131    # C or C++ comment (ignore)
132    def t_c_comment(self, t):
133        r'/\*(.|\n)*?\*/'
134        t.lexer.lineno += t.value.count('\n')
135
136    def t_cpp_comment(self, t):
137        r'//.*'
138
139    # Define a rule so we can track line numbers
140    def t_newline(self, t):
141        r'\n+'
142        t.lexer.lineno += len(t.value)
143
144    reserved = {
145        'global' : 'GLOBAL',
146        'machine' : 'MACHINE',
147        'in_port' : 'IN_PORT',
148        'out_port' : 'OUT_PORT',
149        'action' : 'ACTION',
150        'transition' : 'TRANS',
151        'structure' : 'STRUCT',
152        'external_type' : 'EXTERN_TYPE',
153        'enumeration' : 'ENUM',
154        'peek' : 'PEEK',
155        'enqueue' : 'ENQUEUE',
156        'copy_head' : 'COPY_HEAD',
157        'check_allocate' : 'CHECK_ALLOCATE',
158        'check_stop_slots' : 'CHECK_STOP_SLOTS',
159        'if' : 'IF',
160        'else' : 'ELSE',
161        'return' : 'RETURN',
162        'THIS' : 'THIS',
163        'CHIP' : 'CHIP',
164        'void' : 'VOID',
165        'new' : 'NEW',
166    }
167
168    literals = ':[]{}(),='
169
170    tokens = [ 'EQ', 'NE', 'LT', 'GT', 'LE', 'GE',
171               'LEFTSHIFT', 'RIGHTSHIFT',
172               'NOT', 'AND', 'OR',
173               'PLUS', 'DASH', 'STAR', 'SLASH',
174               'DOUBLE_COLON', 'SEMI',
175               'ASSIGN', 'DOT',
176               'IDENT', 'LIT_BOOL', 'FLOATNUMBER', 'NUMBER', 'STRING' ]
177    tokens += reserved.values()
178
179    t_EQ = r'=='
180    t_NE = r'!='
181    t_LT = r'<'
182    t_GT = r'>'
183    t_LE = r'<='
184    t_GE = r'>='
185    t_LEFTSHIFT = r'<<'
186    t_RIGHTSHIFT = r'>>'
187    t_NOT = r'!'
188    t_AND = r'&&'
189    t_OR = r'\|\|'
190    t_PLUS = r'\+'
191    t_DASH = r'-'
192    t_STAR = r'\*'
193    t_SLASH = r'/'
194    t_DOUBLE_COLON = r'::'
195    t_SEMI = r';'
196    t_ASSIGN = r':='
197    t_DOT = r'\.'
198
199    precedence = (
200        ('left', 'AND', 'OR'),
201        ('left', 'EQ', 'NE'),
202        ('left', 'LT', 'GT', 'LE', 'GE'),
203        ('left', 'RIGHTSHIFT', 'LEFTSHIFT'),
204        ('left', 'PLUS', 'DASH'),
205        ('left', 'STAR', 'SLASH'),
206        ('right', 'NOT', 'UMINUS'),
207    )
208
209    def t_IDENT(self, t):
210        r'[a-zA-Z_][a-zA-Z_0-9]*'
211        if t.value == 'true':
212            t.type = 'LIT_BOOL'
213            t.value = True
214            return t
215
216        if t.value == 'false':
217            t.type = 'LIT_BOOL'
218            t.value = False
219            return t
220
221        # Check for reserved words
222        t.type = self.reserved.get(t.value, 'IDENT')
223        return t
224
225    def t_FLOATNUMBER(self, t):
226        '[0-9]+[.][0-9]+'
227        try:
228            t.value = float(t.value)
229        except ValueError:
230            raise TokenError("Illegal float", t)
231        return t
232
233    def t_NUMBER(self, t):
234        r'[0-9]+'
235        try:
236            t.value = int(t.value)
237        except ValueError:
238            raise TokenError("Illegal number", t)
239        return t
240
241    def t_STRING1(self, t):
242        r'\"[^"\n]*\"'
243        t.type = 'STRING'
244        t.value = t.value[1:-1]
245        return t
246
247    def t_STRING2(self, t):
248        r"\'[^'\n]*\'"
249        t.type = 'STRING'
250        t.value = t.value[1:-1]
251        return t
252
253    def p_file(self, p):
254        "file : decls"
255        p[0] = p[1]
256
257    def p_empty(self, p):
258        "empty :"
259
260    def p_decls(self, p):
261        "decls : declsx"
262        p[0] = ast.DeclListAST(self, p[1])
263
264    def p_declsx__list(self, p):
265        "declsx : decl declsx"
266        p[0] = [ p[1] ] + p[2]
267
268    def p_declsx__none(self, p):
269        "declsx : empty"
270        p[0] = []
271
272    def p_decl__machine(self, p):
273        "decl : MACHINE '(' ident pairs ')' ':' params '{' decls '}'"
274        p[0] = ast.MachineAST(self, p[3], p[4], p[7], p[9])
275
276    def p_decl__action(self, p):
277        "decl : ACTION '(' ident pairs ')' statements"
278        p[0] = ast.ActionDeclAST(self, p[3], p[4], p[6])
279
280    def p_decl__in_port(self, p):
281        "decl : IN_PORT '(' ident ',' type ',' var pairs ')' statements"
282        p[0] = ast.InPortDeclAST(self, p[3], p[5], p[7], p[8], p[10])
283
284    def p_decl__out_port(self, p):
285        "decl : OUT_PORT '(' ident ',' type ',' var pairs ')' SEMI"
286        p[0] = ast.OutPortDeclAST(self, p[3], p[5], p[7], p[8])
287
288    def p_decl__trans0(self, p):
289        "decl : TRANS '(' idents ',' idents ',' ident pairs ')' idents"
290        p[0] = ast.TransitionDeclAST(self, p[3], p[5], p[7], p[8], p[10])
291
292    def p_decl__trans1(self, p):
293        "decl : TRANS '(' idents ',' idents           pairs ')' idents"
294        p[0] = ast.TransitionDeclAST(self, p[3], p[5], None, p[6], p[8])
295
296    def p_decl__extern0(self, p):
297        "decl : EXTERN_TYPE '(' type pairs ')' SEMI"
298        p[4]["external"] = "yes"
299        p[0] = ast.TypeDeclAST(self, p[3], p[4], [])
300
301    def p_decl__extern1(self, p):
302        "decl : EXTERN_TYPE '(' type pairs ')' '{' type_methods '}'"
303        p[4]["external"] = "yes"
304        p[0] = ast.TypeDeclAST(self, p[3], p[4], p[7])
305
306    def p_decl__global(self, p):
307        "decl : GLOBAL '(' type pairs ')' '{' type_members '}'"
308        p[4]["global"] = "yes"
309        p[0] = ast.TypeDeclAST(self, p[3], p[4], p[7])
310
311    def p_decl__struct(self, p):
312        "decl : STRUCT '(' type pairs ')' '{' type_members '}'"
313        p[0] = ast.TypeDeclAST(self, p[3], p[4], p[7])
314
315    def p_decl__enum(self, p):
316        "decl : ENUM '(' type pairs ')' '{' type_enums   '}'"
317        p[4]["enumeration"] = "yes"
318        p[0] = ast.EnumDeclAST(self, p[3], p[4], p[7])
319
320    def p_decl__object(self, p):
321        "decl : type ident pairs SEMI"
322        p[0] = ast.ObjDeclAST(self, p[1], p[2], p[3])
323
324    def p_decl__func_decl(self, p):
325        """decl : void ident '(' params ')' pairs SEMI
326                | type ident '(' params ')' pairs SEMI"""
327        p[0] = ast.FuncDeclAST(self, p[1], p[2], p[4], p[6], None)
328
329    def p_decl__func_def(self, p):
330        """decl : void ident '(' params ')' pairs statements
331                | type ident '(' params ')' pairs statements"""
332        p[0] = ast.FuncDeclAST(self, p[1], p[2], p[4], p[6], p[7])
333
334    # Type fields
335    def p_type_members__list(self, p):
336        "type_members : type_member type_members"
337        p[0] = [ p[1] ] + p[2]
338
339    def p_type_members__empty(self, p):
340        "type_members : empty"
341        p[0] = []
342
343    def p_type_member__1(self, p):
344        "type_member : type ident pairs SEMI"
345        p[0] = ast.TypeFieldMemberAST(self, p[1], p[2], p[3], None)
346
347    def p_type_member__2(self, p):
348        "type_member : type ident ASSIGN expr SEMI"
349        p[0] = ast.TypeFieldMemberAST(self, p[1], p[2],
350                                      ast.PairListAST(self), p[4])
351
352    # Methods
353    def p_type_methods__list(self, p):
354        "type_methods : type_method type_methods"
355        p[0] = [ p[1] ] + p[2]
356
357    def p_type_methods(self, p):
358        "type_methods : empty"
359        p[0] = []
360
361    def p_type_method(self, p):
362        "type_method : type_or_void ident '(' types ')' pairs SEMI"
363        p[0] = ast.TypeFieldMethodAST(self, p[1], p[2], p[4], p[6])
364
365    # Enum fields
366    def p_type_enums__list(self, p):
367        "type_enums : type_enum type_enums"
368        p[0] = [ p[1] ] + p[2]
369
370    def p_type_enums__empty(self, p):
371        "type_enums : empty"
372        p[0] = []
373
374    def p_type_enum(self, p):
375        "type_enum : ident pairs SEMI"
376        p[0] = ast.TypeFieldEnumAST(self, p[1], p[2])
377
378    # Type
379    def p_types__multiple(self, p):
380        "types : type ',' types"
381        p[0] = [ p[1] ] + p[3]
382
383    def p_types__one(self, p):
384        "types : type"
385        p[0] = [ p[1] ]
386
387    def p_types__empty(self, p):
388        "types : empty"
389        p[0] = []
390
391    def p_type(self, p):
392        "type : ident"
393        p[0] = ast.TypeAST(self, p[1])
394
395    def p_void(self, p):
396        "void : VOID"
397        p[0] = ast.TypeAST(self, p[1])
398
399    def p_type_or_void(self, p):
400        """type_or_void : type
401                        | void"""
402        p[0] = p[1]
403
404    # Formal Param
405    def p_params__many(self, p):
406        "params : param ',' params"
407        p[0] = [ p[1] ] + p[3]
408
409    def p_params__one(self, p):
410        "params : param"
411        p[0] = [ p[1] ]
412
413    def p_params__none(self, p):
414        "params : empty"
415        p[0] = []
416
417    def p_param(self, p):
418        "param : type ident"
419        p[0] = ast.FormalParamAST(self, p[1], p[2])
420
421    # Idents and lists
422    def p_idents__braced(self, p):
423        "idents : '{' identx '}'"
424        p[0] = p[2]
425
426    def p_idents__bare(self, p):
427        "idents : ident"
428        p[0] = [ p[1] ]
429
430    def p_identx__multiple_1(self, p):
431        """identx : ident SEMI identx
432                  | ident ',' identx"""
433        p[0] = [ p[1] ] + p[3]
434
435    def p_identx__multiple_2(self, p):
436        "identx : ident identx"
437        p[0] = [ p[1] ] + p[2]
438
439    def p_identx__single(self, p):
440        "identx : empty"
441        p[0] = [ ]
442
443    def p_ident(self, p):
444        "ident : IDENT"
445        p[0] = p[1]
446
447    # Pair and pair lists
448    def p_pairs__list(self, p):
449        "pairs : ',' pairsx"
450        p[0] = p[2]
451
452    def p_pairs__empty(self, p):
453        "pairs : empty"
454        p[0] = ast.PairListAST(self)
455
456    def p_pairsx__many(self, p):
457        "pairsx : pair ',' pairsx"
458        p[0] = p[3]
459        p[0].addPair(p[1])
460
461    def p_pairsx__one(self, p):
462        "pairsx : pair"
463        p[0] = ast.PairListAST(self)
464        p[0].addPair(p[1])
465
466    def p_pair__assign(self, p):
467        """pair : ident '=' STRING
468                | ident '=' ident"""
469        p[0] = ast.PairAST(self, p[1], p[3])
470
471    def p_pair__literal(self, p):
472        "pair : STRING"
473        p[0] = ast.PairAST(self, "short", p[1])
474
475    # Below are the rules for action descriptions
476    def p_statements__inner(self, p):
477        "statements : '{' statements_inner '}'"
478        p[0] = ast.StatementListAST(self, p[2])
479
480    def p_statements__none(self, p):
481        "statements : '{' '}'"
482        p[0] = ast.StatementListAST(self, [])
483
484    def p_statements_inner__many(self, p):
485        "statements_inner : statement statements_inner"
486        p[0] = [ p[1] ] + p[2]
487
488    def p_statements_inner__one(self, p):
489        "statements_inner : statement"
490        p[0] = [ p[1] ]
491
492    def p_exprs__multiple(self, p):
493        "exprs : expr ',' exprs"
494        p[0] = [ p[1] ] + p[3]
495
496    def p_exprs__one(self, p):
497        "exprs : expr"
498        p[0] = [ p[1] ]
499
500    def p_exprs__empty(self, p):
501        "exprs : empty"""
502        p[0] = []
503
504    def p_statement__expression(self, p):
505        "statement : expr SEMI"
506        p[0] = ast.ExprStatementAST(self, p[1])
507
508    def p_statement__assign(self, p):
509        "statement : expr ASSIGN expr SEMI"
510        p[0] = ast.AssignStatementAST(self, p[1], p[3])
511
512    def p_statement__enqueue(self, p):
513        "statement : ENQUEUE '(' var ',' type pairs ')' statements"
514        p[0] = ast.EnqueueStatementAST(self, p[3], p[5], p[6], p[8])
515
516    def p_statement__peek(self, p):
517        "statement : PEEK '(' var ',' type pairs ')' statements"
518        p[0] = ast.PeekStatementAST(self, p[3], p[5], p[6], p[8], "peek")
519
520    def p_statement__copy_head(self, p):
521        "statement : COPY_HEAD '(' var ',' var pairs ')' SEMI"
522        p[0] = ast.CopyHeadStatementAST(self, p[3], p[5], p[6])
523
524    def p_statement__check_allocate(self, p):
525        "statement : CHECK_ALLOCATE '(' var ')' SEMI"
526        p[0] = ast.CheckAllocateStatementAST(self, p[3])
527
528    def p_statement__check_stop(self, p):
529        "statement : CHECK_STOP_SLOTS '(' var ',' STRING ',' STRING ')' SEMI"
530        p[0] = ast.CheckStopStatementAST(self, p[3], p[5], p[7])
531
532    def p_statement__return(self, p):
533        "statement : RETURN expr SEMI"
534        p[0] = ast.ReturnStatementAST(self, p[2])
535
536    def p_statement__if(self, p):
537        "statement : if_statement"
538        p[0] = p[1]
539
540    def p_if_statement__if(self, p):
541        "if_statement : IF '(' expr ')' statements"
542        p[0] = ast.IfStatementAST(self, p[3], p[5], None)
543
544    def p_if_statement__if_else(self, p):
545        "if_statement : IF '(' expr ')' statements ELSE statements"
546        p[0] = ast.IfStatementAST(self, p[3], p[5], p[7])
547
548    def p_statement__if_else_if(self, p):
549        "if_statement : IF '(' expr ')' statements ELSE if_statement"
550        p[0] = ast.IfStatementAST(self, p[3], p[5],
551                                  ast.StatementListAST(self, p[7]))
552
553    def p_expr__var(self, p):
554        "aexpr : var"
555        p[0] = p[1]
556
557    def p_expr__literal(self, p):
558        "aexpr : literal"
559        p[0] = p[1]
560
561    def p_expr__enumeration(self, p):
562        "aexpr : enumeration"
563        p[0] = p[1]
564
565    def p_expr__func_call(self, p):
566        "aexpr : ident '(' exprs ')'"
567        p[0] = ast.FuncCallExprAST(self, p[1], p[3])
568
569    def p_expr__new(self, p):
570        "aexpr : NEW type"
571        p[0] = ast.NewExprAST(self, p[2])
572
573    # globally access a local chip component and call a method
574    def p_expr__local_chip_method(self, p):
575        "aexpr : THIS DOT var '[' expr ']' DOT var DOT ident '(' exprs ')'"
576        p[0] = ast.LocalChipMethodAST(self, p[3], p[5], p[8], p[10], p[12])
577
578    # globally access a local chip component and access a data member
579    def p_expr__local_chip_member(self, p):
580        "aexpr : THIS DOT var '[' expr ']' DOT var DOT field"
581        p[0] = ast.LocalChipMemberAST(self, p[3], p[5], p[8], p[10])
582
583    # globally access a specified chip component and call a method
584    def p_expr__specified_chip_method(self, p):
585        "aexpr : CHIP '[' expr ']' DOT var '[' expr ']' DOT var DOT ident '(' exprs ')'"
586        p[0] = ast.SpecifiedChipMethodAST(self, p[3], p[6], p[8], p[11], p[13],
587                                          p[15])
588
589    # globally access a specified chip component and access a data member
590    def p_expr__specified_chip_member(self, p):
591        "aexpr : CHIP '[' expr ']' DOT var '[' expr ']' DOT var DOT field"
592        p[0] = ast.SpecifiedChipMemberAST(self, p[3], p[6], p[8], p[11], p[13])
593
594    def p_expr__member(self, p):
595        "aexpr : aexpr DOT ident"
596        p[0] = ast.MemberExprAST(self, p[1], p[3])
597
598    def p_expr__member_method_call(self, p):
599        "aexpr : aexpr DOT ident '(' exprs ')'"
600        p[0] = ast.MemberMethodCallExprAST(self, p[1], p[3], p[5])
601
602    def p_expr__member_method_call_lookup(self, p):
603        "aexpr : aexpr '[' exprs ']'"
604        p[0] = ast.MemberMethodCallExprAST(self, p[1], "lookup", p[3])
605
606    def p_expr__class_method_call(self, p):
607        "aexpr : type DOUBLE_COLON ident '(' exprs ')'"
608        p[0] = ast.ClassMethodCallExprAST(self, p[1], p[3], p[5])
609
610    def p_expr__aexpr(self, p):
611        "expr : aexpr"
612        p[0] = p[1]
613
614    def p_expr__binary_op(self, p):
615        """expr : expr STAR  expr
616                | expr SLASH expr
617                | expr PLUS  expr
618                | expr DASH  expr
619                | expr LT    expr
620                | expr GT    expr
621                | expr LE    expr
622                | expr GE    expr
623                | expr EQ    expr
624                | expr NE    expr
625                | expr AND   expr
626                | expr OR    expr
627                | expr RIGHTSHIFT expr
628                | expr LEFTSHIFT  expr"""
629        p[0] = ast.InfixOperatorExprAST(self, p[1], p[2], p[3])
630
631    # FIXME - unary not
632    def p_expr__unary_op(self, p):
633        """expr : NOT expr
634                | DASH expr %prec UMINUS"""
635        p[0] = PrefixOperatorExpr(p[1], p[2])
636
637    def p_expr__parens(self, p):
638        "aexpr : '(' expr ')'"
639        p[0] = p[2]
640
641    def p_literal__string(self, p):
642        "literal : STRING"
643        p[0] = ast.LiteralExprAST(self, p[1], "string")
644
645    def p_literal__number(self, p):
646        "literal : NUMBER"
647        p[0] = ast.LiteralExprAST(self, p[1], "int")
648
649    def p_literal__float(self, p):
650        "literal : FLOATNUMBER"
651        p[0] = ast.LiteralExprAST(self, p[1], "int")
652
653    def p_literal__bool(self, p):
654        "literal : LIT_BOOL"
655        p[0] = ast.LiteralExprAST(self, p[1], "bool")
656
657    def p_enumeration(self, p):
658        "enumeration : ident ':' ident"
659        p[0] = ast.EnumExprAST(self, ast.TypeAST(self, p[1]), p[3])
660
661    def p_var(self, p):
662        "var : ident"
663        p[0] = ast.VarExprAST(self, p[1])
664
665    def p_field(self, p):
666        "field : ident"
667        p[0] = p[1]
668