7311fd7182
Add the PROTOCOL sticky option sets the coherence protocol that slicc will parse and therefore ruby will use. This whole process was made difficult by the fact that the set of files that are output by slicc are not easily known ahead of time. The easiest thing wound up being to write a parser for slicc that would tell me. Incidentally this means we now have a slicc grammar written in python.
572 lines
14 KiB
Python
572 lines
14 KiB
Python
# 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)
|