573 lines
14 KiB
Python
573 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)
|