diff options
Diffstat (limited to 'src/mem/slicc/parser/parser.py')
-rw-r--r-- | src/mem/slicc/parser/parser.py | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/src/mem/slicc/parser/parser.py b/src/mem/slicc/parser/parser.py new file mode 100644 index 000000000..ac2dd294a --- /dev/null +++ b/src/mem/slicc/parser/parser.py @@ -0,0 +1,572 @@ +# Copyright (c) 2009 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +from ply import lex, yacc +import re + +t_ignore = '\t ' + +# C or C++ comment (ignore) +def t_c_comment(t): + r'/\*(.|\n)*?\*/' + t.lexer.lineno += t.value.count('\n') + +def t_cpp_comment(t): + r'//.*' + pass + +# Define a rule so we can track line numbers +def t_newline(t): + r'\n+' + t.lexer.lineno += len(t.value) + +reserved = { + 'global' : 'GLOBAL', + 'machine' : 'MACHINE', + 'in_port' : 'IN_PORT', + 'out_port' : 'OUT_PORT', + 'action' : 'ACTION', + 'transition' : 'TRANS', + 'structure' : 'STRUCT', + 'external_type' : 'EXTERN_TYPE', + 'enumeration' : 'ENUM', + 'peek' : 'PEEK', + 'enqueue' : 'ENQUEUE', + 'copy_head' : 'COPY_HEAD', + 'check_allocate' : 'CHECK_ALLOCATE', + 'check_stop_slots' : 'CHECK_STOP_SLOTS', + 'if' : 'IF', + 'else' : 'ELSE', + 'return' : 'RETURN', + 'THIS' : 'THIS', + 'CHIP' : 'CHIP', + 'void' : 'VOID', +} + +literals = ':[]{}(),=' + +tokens = [ 'EQ', 'NE', 'LT', 'GT', 'LE', 'GE', + 'LEFTSHIFT', 'RIGHTSHIFT', + 'NOT', 'AND', 'OR', + 'PLUS', 'DASH', 'STAR', 'SLASH', + 'DOUBLE_COLON', 'SEMICOLON', + 'ASSIGN', 'DOT', + 'IDENT', 'LIT_BOOL', 'FLOATNUMBER', 'NUMBER', 'STRING' ] +tokens += reserved.values() + +t_EQ = r'==' +t_NE = r'!=' +t_LT = r'<' +t_GT = r'>' +t_LE = r'<=' +t_GE = r'>=' +t_LEFTSHIFT = r'<<' +t_RIGHTSHIFT = r'>>' +t_NOT = r'!' +t_AND = r'&&' +t_OR = r'\|\|' +t_PLUS = r'\+' +t_DASH = r'-' +t_STAR = r'\*' +t_SLASH = r'/' +t_DOUBLE_COLON = r'::' +t_SEMICOLON = r';' +t_ASSIGN = r':=' +t_DOT = r'\.' + +class TokenError(Exception): pass +class ParseError(Exception): pass + +def t_error(t): + raise TokenError("Illegal character", t) + +def t_IDENT(t): + r'[a-zA-Z_][a-zA-Z_0-9]*' + if t.value == 'true': + t.type = 'LIT_BOOL' + t.value = True + return t + + if t.value == 'false': + t.type = 'LIT_BOOL' + t.value = False + return t + + t.type = reserved.get(t.value, 'IDENT') # Check for reserved words + return t + +def t_FLOATNUMBER(t): + '[0-9]+[.][0-9]+' + try: + t.value = float(t.value) + except ValueError: + raise TokenError("Illegal float", t) + return t + +def t_NUMBER(t): + r'[0-9]+' + try: + t.value = int(t.value) + except ValueError: + raise TokenError("Illegal number", t) + return t + +def t_STRING1(t): + r'\"[^"\n]*\"' + t.type = 'STRING' + return t + +def t_STRING2(t): + r"\'[^'\n]*\'" + t.type = 'STRING' + return t + + +def p_file(p): + "file : decl_l" + p[0] = [ x for x in p[1] if x is not None ] + +def p_error(t): + raise ParseError(t) + +def p_empty(p): + "empty :" + pass + +def p_decl_l(p): + "decl_l : decls" + p[0] = p[1] + +def p_decls(p): + """decls : decl decls + | empty""" + if len(p) == 3: + p[0] = [ p[1] ] + p[2] + elif len(p) == 2: + p[0] = [] + +def p_decl(p): + """decl : d_machine + | d_action + | d_in_port + | d_out_port + | t_trans + | d_extern + | d_global + | d_struct + | d_enum + | d_object + | d_func_decl + | d_func_def""" + p[0] = p[1] + +def p_d_machine(p): + "d_machine : MACHINE '(' ident pair_l ')' '{' decl_l '}'" + decls = [ x for x in p[7] if x is not None ] + p[0] = Machine(p[3], decls) + +def p_d_action(p): + "d_action : ACTION '(' ident pair_l ')' statement_l" + p[0] = Action(p[3]) + +def p_d_in_port(p): + "d_in_port : IN_PORT '(' ident ',' type ',' var pair_l ')' statement_l" + p[0] = InPort(p[3]) + +def p_d_out_port(p): + "d_out_port : OUT_PORT '(' ident ',' type ',' var pair_l ')' SEMICOLON" + p[0] = OutPort(p[3]) + +def p_t_trans(p): + """t_trans : TRANS '(' ident_l ',' ident_l ',' ident pair_l ')' ident_l + | TRANS '(' ident_l ',' ident_l pair_l ')' ident_l""" + p[0] = Transition("transition") + +def p_d_extern(p): + """d_extern : EXTERN_TYPE '(' type pair_l ')' SEMICOLON + | EXTERN_TYPE '(' type pair_l ')' '{' type_methods '}'""" + p[0] = Extern(p[3]) + +def p_d_global(p): + "d_global : GLOBAL '(' type pair_l ')' '{' type_members '}'" + p[0] = Global(p[3]) + +def p_d_struct(p): + "d_struct : STRUCT '(' type pair_l ')' '{' type_members '}'" + p[0] = Struct(p[3]) + +def p_d_enum(p): + "d_enum : ENUM '(' type pair_l ')' '{' type_enums '}'" + p[0] = Enum(p[3]) + +def p_d_object(p): + "d_object : type ident pair_l SEMICOLON" + p[0] = Object(p[2]) + +def p_d_func_decl(p): + """d_func_decl : void ident '(' param_l ')' pair_l SEMICOLON + | type ident '(' param_l ')' pair_l SEMICOLON""" + pass + +def p_d_func_def(p): + """d_func_def : void ident '(' param_l ')' pair_l statement_l + | type ident '(' param_l ')' pair_l statement_l""" + p[0] = Function(p[2]) + +# Type fields +def p_type_members(p): + """type_members : type_member type_members + | empty""" + pass + +def p_type_member(p): + """type_member : type ident pair_l SEMICOLON + | type ident ASSIGN expr SEMICOLON""" + pass + +# Methods +def p_type_methods(p): + """type_methods : type_method type_methods + | empty""" + pass + +def p_type_method(p): + "type_method : type_or_void ident '(' type_l ')' pair_l SEMICOLON" + pass + +# Enum fields +def p_type_enums(p): + """type_enums : type_enum type_enums + | empty""" + pass + +def p_type_enum(p): + "type_enum : ident pair_l SEMICOLON" + pass + +# Type +def p_type_l(p): + """type_l : types + | empty""" + pass + +def p_types(p): + """types : type ',' types + | type""" + pass + +def p_type(p): + "type : ident" + p[0] = p[1] + +def p_void(p): + "void : VOID" + p[0] = None + +def p_type_or_void(p): + """type_or_void : type + | void""" + p[0] = p[1] + +# Formal Param +def p_param_l(p): + """param_l : params + | empty""" + pass + +def p_params(p): + """params : param ',' params + | param""" + pass + +def p_param(p): + "param : type ident" + pass + +# Idents and lists +def p_ident(p): + "ident : IDENT" + p[0] = p[1] + +def p_ident_l(p): + """ident_l : '{' idents '}' + | ident""" + p[0] = p[1] + +def p_idents(p): + """idents : ident SEMICOLON idents + | ident ',' idents + | ident idents + | empty""" + pass + +# Pair and pair lists +def p_pair_l(p): + """pair_l : ',' pairs + | empty""" + if len(p) == 3: + p[0] = p[2] + elif len(p) == 2: + p[0] = None + +def p_pairs(p): + """pairs : pair ',' pairs + | pair""" + if len(p) == 4: + p[3].append(p[1]) + p[0] = p[3] + elif len(p) == 2: + p[0] = [ p[1] ] + +def p_pair(p): + """pair : ident '=' STRING + | ident '=' ident + | STRING""" + if len(p) == 4: + p[0] = p[1], p[3] + elif len(p) == 2: + p[0] = "short", p[1] + +# Below are the rules for action descriptions +def p_statement_l(p): + "statement_l : '{' statements '}'" + pass + +def p_statements(p): + """statements : statement statements + | empty""" + pass + +def p_expr_l(p): + """expr_l : expr ',' expr_l + | expr + | empty""" + pass + +def p_statement(p): + """statement : expr SEMICOLON + | expr ASSIGN expr SEMICOLON + | ENQUEUE '(' var ',' type pair_l ')' statement_l + | PEEK '(' var ',' type ')' statement_l + | COPY_HEAD '(' var ',' var pair_l ')' SEMICOLON + | CHECK_ALLOCATE '(' var ')' SEMICOLON + | CHECK_STOP_SLOTS '(' var ',' STRING ',' STRING ')' SEMICOLON + | if_statement + | RETURN expr SEMICOLON""" + pass + +def p_if_statement(p): + """if_statement : IF '(' expr ')' statement_l ELSE statement_l + | IF '(' expr ')' statement_l + | IF '(' expr ')' statement_l ELSE if_statement""" + pass + +def p_expr(p): + """expr : var + | literal + | enumeration + | ident '(' expr_l ')' + | THIS DOT var '[' expr ']' DOT var DOT ident '(' expr_l ')' + | THIS DOT var '[' expr ']' DOT var DOT ident + | CHIP '[' expr ']' DOT var '[' expr ']' DOT var DOT ident '(' expr_l ')' + | CHIP '[' expr ']' DOT var '[' expr ']' DOT var DOT ident + | expr DOT ident + | expr DOT ident '(' expr_l ')' + | type DOUBLE_COLON ident '(' expr_l ')' + | expr '[' expr_l ']' + | expr STAR expr + | expr SLASH expr + | expr PLUS expr + | expr DASH expr + | expr LT expr + | expr GT expr + | expr LE expr + | expr GE expr + | expr EQ expr + | expr NE expr + | expr AND expr + | expr OR expr + | NOT expr + | expr RIGHTSHIFT expr + | expr LEFTSHIFT expr + | '(' expr ')'""" + pass + +def p_literal(p): + """literal : STRING + | NUMBER + | FLOATNUMBER + | LIT_BOOL""" + pass + +def p_enumeration(p): + "enumeration : ident ':' ident" + pass + +def p_var(p): + "var : ident" + pass + +lex.lex() +yacc.yacc(write_tables=0) + +slicc_generated_cc = set([ + 'AccessModeType.cc', + 'AccessPermission.cc', + 'AccessType.cc', + 'AllocationStrategy.cc', + 'CacheMsg.cc', + 'CacheRequestType.cc', + 'Chip.cc', + 'CoherenceRequestType.cc', + 'DetermGETXGeneratorStatus.cc', + 'DetermInvGeneratorStatus.cc', + 'DetermSeriesGETSGeneratorStatus.cc', + 'GenericMachineType.cc', + 'GenericRequestType.cc', + 'LinkType.cc', + 'LockStatus.cc', + 'MachineType.cc', + 'MaskPredictorIndex.cc', + 'MaskPredictorTraining.cc', + 'MaskPredictorType.cc', + 'MemoryMsg.cc', + 'MemoryRequestType.cc', + 'MessageSizeType.cc', + 'PrefetchBit.cc', + 'Protocol.cc', + 'RequestGeneratorStatus.cc', + 'SearchMechanism.cc', + 'SequencerStatus.cc', + 'SpecifiedGeneratorType.cc', + 'TesterStatus.cc', + 'TopologyType.cc', + 'TransientRequestType.cc', + 'TransitionResult.cc']) + +slicc_generated_hh = set([ + 'AccessType.hh', + 'AccessModeType.hh', + 'AccessPermission.hh', + 'AllocationStrategy.hh', + 'CacheMsg.hh', + 'CacheRequestType.hh', + 'Chip.hh', + 'CoherenceRequestType.hh', + 'DetermGETXGeneratorStatus.hh', + 'DetermInvGeneratorStatus.hh', + 'DetermSeriesGETSGeneratorStatus.hh', + 'GenericMachineType.hh', + 'GenericRequestType.hh', + 'LinkType.hh', + 'LockStatus.hh', + 'MachineType.hh', + 'MaskPredictorIndex.hh', + 'MaskPredictorTraining.hh', + 'MaskPredictorType.hh', + 'MemoryMsg.hh', + 'MemoryRequestType.hh', + 'MessageSizeType.hh', + 'PrefetchBit.hh', + 'Protocol.hh', + 'RequestGeneratorStatus.hh', + 'SearchMechanism.hh', + 'SequencerStatus.hh', + 'SpecifiedGeneratorType.hh', + 'TesterStatus.hh', + 'TopologyType.hh', + 'TransientRequestType.hh', + 'TransitionResult.hh', + 'Types.hh', + 'protocol_name.hh' ]) + +class Machine(object): + def __init__(self, name, decls): + self.name = name + self.decls = decls + + def add(self, hh, cc): + hh.add('%s_Controller.hh' % self.name) + hh.add('%s_Profiler.hh' % self.name) + + cc.add('%s_Controller.cc' % self.name) + cc.add('%s_Profiler.cc' % self.name) + cc.add('%s_Transitions.cc' % self.name) + cc.add('%s_Wakeup.cc' % self.name) + + for decl in self.decls: + decl.add(hh, cc, self.name) + +class Declaration(object): + hh = False + cc = False + def __init__(self, name): + self.name = name + + def add(self, hh, cc, name=None): + #print '>>>', type(self).__name__, self.name + if name: + name += '_' + else: + name = "" + if self.hh: + hh.add('%s%s.hh' % (name, self.name)) + if self.cc: + cc.add('%s%s.cc' % (name, self.name)) + +class Action(Declaration): pass +class InPort(Declaration): pass +class OutPort(Declaration): pass +class Transition(Declaration): pass +class Extern(Declaration): pass +class Global(Declaration): pass +class Struct(Declaration): + hh = True + cc = True +class Enum(Declaration): + hh = True + cc = True +class Object(Declaration): pass +class Function(Declaration): + cc = True + +def scan(filenames): + hh = slicc_generated_hh.copy() + cc = slicc_generated_cc.copy() + + for filename in filenames: + lex.lexer.lineno = 1 + try: + results = yacc.parse(file(filename, 'r').read()) + except (TokenError, ParseError), e: + raise type(e), tuple([filename] + [ i for i in e ]) + + for result in results: + result.add(hh, cc) + + return list(hh), list(cc) |