xed/pysrc/actions.py
Mark Charney ffd94e705c initial commit
Change-Id: I32a6db1a17988d9df8ff69aa1672dbf08b108e8a
2016-12-16 16:09:38 -05:00

353 lines
12 KiB
Python
Executable File

#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
from verbosity import *
import re
import patterns
import genutil
import encutil
import mbuild
import copy
def msgb(s,b=''):
mbuild.msgb(s,b)
def gen_return_action(ret_val):
''' create new action with type return '''
#temporary creating it as dummy
action = action_t("nothing")
action.type = 'return'
action.value = str(ret_val)
return action
def dummy_emit(act_in,name):
''' creating new action based on the input action with
dummy emit type and name as the field name'''
action = copy.deepcopy(act_in)
action.emit_type = 'dummy'
action.field_name = name
return action
def gen_dummy_fb(fb):
''' create new fb action that sets the value to -1 '''
str = "%s=-1" % fb
action = action_t(str)
return action
def gen_null_fb():
''' create new fb with fake fb name:"null" and value 0
using this to represent null pointers'''
str = "null=0"
action = action_t(str)
return action
def gen_nt_action(nt):
''' create new action with type nt '''
str = "%s()" % nt
action = action_t(str)
return action
class action_t(object):
"""This is the right hand side of the rule_t. It can be a (1)
field binding (2) a byte encoding, (3) 'error' or (4) 'nothing'."""
def __init__(self, arg_action):
self.type = None # 'FB', 'emit', 'nt', 'error', 'nothing', return
self.field_name = None
self.value = None
self.nt = None
self.ntluf = None
self.int_value = None
self.emit_type = None # 'numeric', 'letters', 'reg'
self.nbits = 0
if vaction():
msgb("ARGACTION", arg_action)
if arg_action == 'nothing' or arg_action == "NOTHING":
self.type = 'nothing'
return
# in the inputs, "error" gets expanded to "ERROR=1" via the statebits.
if arg_action == 'error' or arg_action == "ERROR" or arg_action == 'ERROR=1':
self.type = 'error'
return
b = patterns.bit_expand_pattern.search(arg_action)
if b:
expanded = b.group('bitname') * int(b.group('count'))
action = patterns.bit_expand_pattern.sub(expanded,arg_action)
else:
action = arg_action
#msgerr("CHECKING: %s" % action)
a = patterns.equals_pattern.search(action)
if a:
# field binding
#msgerr("FIELD BINDING: %s" % action)
self.field_name = a.group('lhs')
rhs = a.group('rhs')
if patterns.decimal_pattern.match(rhs) or \
patterns.binary_pattern.match(rhs) or \
patterns.hex_pattern.match(rhs):
self.int_value = genutil.make_numeric(rhs)
self.value = str(self.int_value)
#msgb("SET RHS", "%s -> %s" % (rhs,self.value))
else:
self.value = rhs
self.type = 'FB'
return
nt = patterns.nt_name_pattern.match(action)
if nt:
# NTLUF or NT. Only shows up on decode-oriented rules
self.nt = nt.group('ntname')
self.type = 'nt'
return
ntluf = patterns.ntluf_name_pattern.match(action)
if ntluf:
# NTLUF or NT. Only shows up on decode-oriented rules
self.ntluf = ntluf.group('ntname')
self.type = 'ntluf'
return
cp = patterns.lhs_capture_pattern_end.match(action)
if cp:
self.type = 'emit'
self.value = cp.group('bits')
self.field_name = cp.group('name').lower()
#msgerr("EMIT ACTION %s" % action)
self.classify()
return
# simple byte encoding
self.type = 'emit'
self.field_name = None
#msgerr("EMIT ACTION %s" % action)
self.value = action
self.classify()
def classify(self):
if patterns.decimal_pattern.match(self.value):
self.emit_type = 'numeric'
self.int_value = int(self.value)
t = hex(self.int_value)
self.nbits = 4*len(t[2:])
if vclassify():
msgb("CLASSIFY", "%s as decimal values" % (self.value))
return
if patterns.hex_pattern.match(self.value):
self.emit_type = 'numeric'
self.int_value = int(self.value,16)
self.nbits = 4*(len(self.value)-2) # drop the 0x, convert nibbles to bits
if vclassify():
msgb("CLASSIFY", "%s as hex" % (self.value))
return
if patterns.letter_and_underscore_pattern.match(self.value):
self.emit_type = 'letters'
t = self.value
t = genutil.no_underscores(t)
self.nbits = len(t)
if vclassify():
msgb("CLASSIFY", "%s as letters" % (self.value))
return
b = patterns.binary_pattern.match(self.value) # leading "0b"
if b:
self.emit_type = 'numeric'
t = '0b' + b.group('bits') # pattern match strips out 0b
self.int_value = genutil.make_numeric(t)
bits_str = genutil.make_binary(t)
self.nbits = len(bits_str)
if vclassify():
msgb("CLASSIFY", "%s as explicit-binary -> int = %d nbits=%d [%s,%s]" % (self.value,self.int_value,self.nbits,t,bits_str))
return
if patterns.bits_and_letters_underscore_pattern.match(self.value):
self.emit_type = 'letters'
v = genutil.no_underscores(self.value)
self.nbits = len(v)
if vclassify():
msgb("CLASSIFY", "%s as mixed-letters" % (self.value))
return
if patterns.simple_number_pattern.match(self.value):
self.emit_type = 'numeric'
self.int_value = genutil.make_numeric(self.value)
t = hex(self.int_value)
self.nbits = 4*len(t[2:])
if vclassify():
msgb("CLASSIFY", "%s as simple-number" % (self.value))
return
genutil.die("unknown pattern")
def naked_bits(self):
''' returns True if the type is emit but there is no field name. '''
if self.type == 'emit' and self.field_name == None:
return True
return False
def is_nothing(self):
return self.type == 'nothing'
def is_error(self):
return self.type == 'error'
def is_return(self):
return self.type == 'return'
def is_nonterminal(self):
if self.nt:
return True
return False
def is_ntluf(self):
if self.ntluf:
return True
return False
def is_field_binding(self):
"""Return True if this action is a field binding."""
if self.type == 'FB':
return True
return False
def is_emit_action(self):
"""Return True if this action is an emit action."""
if self.type == 'emit':
return True
return False
def __str__(self):
s = []
s.append(str(self.type))
if self.nt:
s.append(" NT[%s]" % (self.nt))
if self.field_name:
s.append(" ")
s.extend([self.field_name,'=',self.value])
elif self.value != None:
s.append(" ")
s.append(self.value)
if self.emit_type:
s.append(" emit_type=%s" % self.emit_type)
if self.int_value != None:
s.append(" value=0x%x" % self.int_value)
if self.nbits != 0:
s.append(" nbits=%d" % self.nbits)
return ''.join(s)
def get_str_value(self):
if self.is_field_binding() or self.is_return():
return self.value
if self.is_nonterminal():
return self.nt
if self.is_ntluf():
return self.ntluf
err = "unsupported type: %s for function get_str_value" % self.type
genutil.die(err)
def emit_code(self, bind_or_emit):
if self.is_error():
#return [ ' return 0; /* error */' ]
# FIXME? bind ERROR=1?
return [ ' okay=0; /* error */' ]
elif self.is_nothing():
return [ ' return 1; /* nothing */' ]
elif self.is_field_binding():
return self._generate_code_for_field_binding(bind_or_emit)
elif self.is_emit_action():
return self._generate_code_for_emit_action(bind_or_emit)
elif self.is_nonterminal():
return self._emit_nonterminal_code(bind_or_emit)
else:
return [ '/* FIXME action code not done yet for ' + self.__str__() + '*/' ]
def _generate_code_for_field_binding(self, bind_or_emit):
if bind_or_emit == 'EMIT':
return []
# we are in BIND
if self.field_name == 'NO_RETURN':
return [ '/* no code required for NO_RETURN binding */']
operand_setter = "%s_set_%s" % (encutil.enc_strings['op_accessor'],
self.field_name.lower())
obj_name = encutil.enc_strings['obj_str']
s = ' %s(%s,%s);' % (operand_setter,
obj_name, self.value)
if self.field_name == 'ERROR':
return [ s, " return 0; /* error */" ]
else:
return [ s ]
def _generate_code_for_emit_action(self,bind_or_emit):
"""Emit code for emit action """
if bind_or_emit == 'BIND':
if self.emit_type == 'letters' or self.field_name == None:
return ''
elif self.emit_type == 'numeric':
op_accessor = encutil.enc_strings['op_accessor']
operand_setter = "%s_set_%s" % (op_accessor,
self.field_name.lower())
obj_name = encutil.enc_strings['obj_str']
hex_val = hex(self.int_value)
code = "%s(%s, %s);" % (operand_setter, obj_name, hex_val)
return [' ' + code]
else:
genutil.die("Unknown emit_type %s" % self.emit_type)
else:
emit_util_function = encutil.enc_strings['emit_util_function']
obj_name = encutil.enc_strings['obj_str']
nbits = self.nbits
code = ''
if self.field_name == None:
if self.emit_type == 'numeric':
hex_val = hex(self.int_value)
code = "%s(%s, %d, %s);" % (emit_util_function,obj_name,
nbits,hex_val)
else:
genutil.die("must have field name for letter action")
else:
op_accessor = encutil.enc_strings['op_accessor']
operand_getter = "%s_get_%s(%s)" % (op_accessor,
self.field_name.lower(),
obj_name)
code = "%s(%s, %d, %s);" % (emit_util_function,
obj_name,nbits,operand_getter)
return [' ' + code]
def _emit_nonterminal_code(self,bind_or_emit):
"""Emit code for calling a nonterminal in bind or emit modes"""
nt_prefix = "%s" % encutil.enc_strings['nt_prefix']
obj_name = encutil.enc_strings['obj_str']
if bind_or_emit =='BIND':
s = []
s.append(' if (okay)')
s.append(' okay = %s_%s_%s(%s);' %(nt_prefix,self.nt,
bind_or_emit,obj_name))
return s
else: #'EMIT'
code = '%s_%s_%s(%s);' %(nt_prefix, self.nt, bind_or_emit, obj_name)
return [' ' + code]