get_arg_name support for negative arg_num, etc.
There are a number of changes in this commit:
- get_arg_name: Added support for arg_num of 0 (the name of the
function) and for negative arg_nums (the lvalues -n through -1).
- sprint_varx: Improvements to printing hex numbers.
- New functions:
- get_line_indent: For use by get_arg_name.
- digit_length_in_bits: Constant function.
- word_length_in_digits: Constant function.
- get_req_num_hex_digits: For use by sprint_varx in printing hex.
- dft_num_hex_digits: Constant function.
- get_stack_var: Search the call stack for a variable.
Change-Id: I8e771a28667a8e25dd3f03c57f157d87c14e5b0e
Signed-off-by: Michael Walsh <micwalsh@us.ibm.com>
diff --git a/lib/gen_print.py b/lib/gen_print.py
index 18aa896..0de4489 100755
--- a/lib/gen_print.py
+++ b/lib/gen_print.py
@@ -306,7 +306,12 @@
# pvar is an alias for print_var.
aliases.add(re.sub("print_var", "pvar", real_called_func_name))
- func_name_regex = "(" + '|'.join(aliases) + ")"
+ # The call to the function could be encased in a recast (e.g.
+ # int(func_name())).
+ recast_regex = "([^ ]+\([ ]*)?"
+ import_name_regex = "([a-zA-Z0-9_]+\.)?"
+ func_name_regex = recast_regex + import_name_regex + "(" +\
+ '|'.join(aliases) + ")"
pre_args_regex = ".*" + func_name_regex + "[ ]*\("
# Search backward through source lines looking for the calling function
@@ -354,20 +359,29 @@
# Insert one space after first "=" if there isn't one already.
composite_line = re.sub("=[ ]*([^ ])", "= \\1", composite_line, 1)
- lvalue_regex = "[ ]+=[ ]*" + func_name_regex + ".*"
+ lvalue_regex = "[ ]*=[ ]+" + func_name_regex + ".*"
lvalue_string = re.sub(lvalue_regex, "", composite_line)
- lvalues_list = map(str.strip, lvalue_string.split(","))
- lvalues = collections.OrderedDict()
+ if lvalue_string == composite_line:
+ # i.e. the regex did not match so there are no lvalues.
+ lvalue_string = ""
+ lvalues_list = filter(None, map(str.strip, lvalue_string.split(",")))
+ try:
+ lvalues = collections.OrderedDict()
+ except AttributeError:
+ # A non-ordered dict doesn't look as nice when printed but it will do.
+ lvalues = {}
ix = len(lvalues_list) * -1
for lvalue in lvalues_list:
lvalues[ix] = lvalue
ix += 1
- called_func_name = re.sub("(.*=)?[ ]+" + func_name_regex +
- "[ ]*\(.*", "\\2",
- composite_line)
+ lvalue_prefix_regex = "(.*=[ ]+)?"
+ called_func_name_regex = lvalue_prefix_regex + func_name_regex + "[ ]*\(.*"
+ called_func_name = re.sub(called_func_name_regex, "\\4", composite_line)
arg_list_etc = "(" + re.sub(pre_args_regex, "", composite_line)
if local_debug:
print_varx("aliases", aliases, 0, debug_indent)
+ print_varx("import_name_regex", import_name_regex, 0, debug_indent)
+ print_varx("func_name_regex", func_name_regex, 0, debug_indent)
print_varx("pre_args_regex", pre_args_regex, 0, debug_indent)
print_varx("start_line_ix", start_line_ix, 0, debug_indent)
print_varx("end_line_ix", end_line_ix, 0, debug_indent)
@@ -375,6 +389,8 @@
print_varx("lvalue_regex", lvalue_regex, 0, debug_indent)
print_varx("lvalue_string", lvalue_string, 0, debug_indent)
print_varx("lvalues", lvalues, 0, debug_indent)
+ print_varx("called_func_name_regex", called_func_name_regex, 0,
+ debug_indent)
print_varx("called_func_name", called_func_name, 0, debug_indent)
print_varx("arg_list_etc", arg_list_etc, 0, debug_indent)
@@ -552,6 +568,127 @@
return sprint_time() + "**ERROR** " + buffer
+# Implement "constants" with functions.
+def digit_length_in_bits():
+ r"""
+ Return the digit length in bits.
+ """
+
+ return 4
+
+
+def word_length_in_digits():
+ r"""
+ Return the word length in digits.
+ """
+
+ return 8
+
+
+def bit_length(number):
+ r"""
+ Return the bit length of the number.
+
+ Description of argument(s):
+ number The number to be analyzed.
+ """
+
+ if number < 0:
+ # Convert negative numbers to positive and subtract one. The
+ # following example illustrates the reason for this:
+ # Consider a single nibble whose signed values can range from -8 to 7
+ # (0x8 to 0x7). A value of 0x7 equals 0b0111. Therefore, its length
+ # in bits is 3. Since the negative bit (i.e. 0b1000) is not set, the
+ # value 7 clearly will fit in one nibble. With -8 = 0x8 = 0b1000, you
+ # have the smallest negative value that will fit. Note that it
+ # requires 3 bits of 0. So by converting a number value of -8 to a
+ # working_number of 7, this function can accurately calculate the
+ # number of bits and therefore nibbles required to represent the
+ # number in print.
+ working_number = abs(number) - 1
+ else:
+ working_number = number
+
+ # Handle the special case of the number 0.
+ if working_number == 0:
+ return 0
+
+ return len(bin(working_number)) - 2
+
+
+def get_req_num_hex_digits(number):
+ r"""
+ Return the required number of hex digits required to display the given
+ number.
+
+ The returned value will always be rounded up to the nearest multiple of 8.
+
+ Description of argument(s):
+ number The number to be analyzed.
+ """
+
+ if number < 0:
+ # Convert negative numbers to positive and subtract one. The
+ # following example illustrates the reason for this:
+ # Consider a single nibble whose signed values can range from -8 to 7
+ # (0x8 to 0x7). A value of 0x7 equals 0b0111. Therefore, its length
+ # in bits is 3. Since the negative bit (i.e. 0b1000) is not set, the
+ # value 7 clearly will fit in one nibble. With -8 = 0x8 = 0b1000, you
+ # have the smallest negative value that will fit. Note that it
+ # requires 3 bits of 0. So by converting a number value of -8 to a
+ # working_number of 7, this function can accurately calculate the
+ # number of bits and therefore nibbles required to represent the
+ # number in print.
+ working_number = abs(number) - 1
+ else:
+ working_number = number
+
+ # Handle the special case of the number 0.
+ if working_number == 0:
+ return word_length_in_digits()
+
+ num_length_in_bits = bit_length(working_number)
+ num_hex_digits, remainder = divmod(num_length_in_bits,
+ digit_length_in_bits())
+ if remainder > 0:
+ # Example: the number 7 requires 3 bits. The divmod above produces,
+ # 0 with remainder of 3. So because we have a remainder, we increment
+ # num_hex_digits from 0 to 1.
+ num_hex_digits += 1
+
+ # Check to see whether the negative bit is set. This is the left-most
+ # bit in the highest order digit.
+ negative_mask = 2 ** (num_hex_digits * 4 - 1)
+ if working_number & negative_mask:
+ # If a number that is intended to be positive has its negative bit
+ # on, an additional digit will be required to represent it correctly
+ # in print.
+ num_hex_digits += 1
+
+ num_words, remainder = divmod(num_hex_digits, word_length_in_digits())
+ if remainder > 0 or num_words == 0:
+ num_words += 1
+
+ # Round up to the next word length in digits.
+ return num_words * word_length_in_digits()
+
+
+def dft_num_hex_digits():
+ r"""
+ Return the default number of hex digits to be used to represent a hex
+ number in print.
+
+ The value returned is a function of sys.maxsize.
+ """
+
+ global _gen_print_dft_num_hex_digits_
+ try:
+ return _gen_print_dft_num_hex_digits_
+ except NameError:
+ _gen_print_dft_num_hex_digits_ = get_req_num_hex_digits(sys.maxsize)
+ return _gen_print_dft_num_hex_digits_
+
+
def sprint_varx(var_name,
var_value,
hex=0,
@@ -651,10 +788,14 @@
if var_value == "":
var_value = "<blank>"
else:
- if type(var_value) is long or var_value >= 0x100000000:
- value_format = "0x%16x"
- else:
- value_format = "0x%08x"
+ num_hex_digits = max(dft_num_hex_digits(),
+ get_req_num_hex_digits(var_value))
+ # Convert a negative number to its positive twos complement
+ # for proper printing. For example, instead of printing -1 as
+ # "0x-000000000000001" it will be printed as
+ # "0xffffffffffffffff".
+ var_value = var_value & (2 ** (num_hex_digits * 4) - 1)
+ value_format = "0x%0" + str(num_hex_digits) + "x"
else:
value_format = "%s"
format_string = "%" + str(loc_col1_indent) + "s%-" \