1#! /usr/bin/env python3 2# 3# ----------------------------------------------------------------------------- 4# Copyright (c) 2019-2021, Arm Limited. All rights reserved. 5# 6# SPDX-License-Identifier: BSD-3-Clause 7# 8# ----------------------------------------------------------------------------- 9 10 11import re 12import os 13 14# Match (((x) + (y))) mode and ((x) + (y)) mode. x, y can be HEX or DEC value. 15expression_re = re.compile(r"([(]?[(]?[(]?(([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*([\+\-]\s*([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*)*)[)]?\s*([\+\-])\s*[(]?(([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*([\+\-]\s*([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*)*)[)]?[)]?[)]?)|([(]?[(]?[(]?(([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*([\+\-]\s*([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*)*)[)]?[)]?[)]?)") 16 17# Simple parser that takes a string and evaluates an expression from it. 18# The expression might contain additions and subtractions amongst numbers that 19# are written in decimal or hexadecimal form. 20# The parses can process expressions in which the parentheses does not change 21# the sign of the following number or numbers in an expression. 22# Thus the parser can process the following expression: (x + y) 23# However it will not calculate the correct sum for the expression below: 24# (x - (y + z)) 25def parse_and_sum(text): 26 m = expression_re.match(text) 27 if m is None: 28 msg = "The script was probably invoked manually" 29 msg += " with having certain macros nested in flash_layouts.h.\n" 30 msg += "Please revisit the flash_layout.h file and hardcode values" 31 msg += " for the (NON-)SECURE_IMAGE_OFFSET and" 32 msg += " (NON-)SECURE_IMAGE_MAX_SIZE macros" 33 raise Exception(msg) 34 35 nums = re.findall(r'0x[A-Fa-f0-9]+|[\d]+', m.group(0)) 36 for i in range(len(nums)): 37 nums[i] = int(nums[i], 0) 38 ops = re.findall(r'\+|\-', m.group(0)) 39 sum = nums[0] 40 for i in range(len(ops)): 41 if ops[i] == '+': 42 sum += nums[i+1] 43 else: 44 sum -= nums[i+1] 45 return sum 46 47 48# Opens a file that contains the macro of interest, then finds the macro with 49# a regular expression, parses the expression that is defined for the given 50# macro. Lastly it evaluates the expression with the parse_and_sum function 51def evaluate_macro(file, regexp, matchGroupKey, matchGroupData, bracketless=False): 52 regexp_compiled = re.compile(regexp) 53 54 if os.path.isabs(file): 55 configFile = file 56 else: 57 scriptsDir = os.path.dirname(os.path.abspath(__file__)) 58 configFile = os.path.join(scriptsDir, file) 59 60 macroValue = {} 61 with open(configFile, 'r') as macros_preprocessed_file: 62 for line in macros_preprocessed_file: 63 if bracketless: 64 line=line.replace("(","") 65 line=line.replace(")","") 66 m = regexp_compiled.match(line) 67 if m is not None: 68 macroValue[m.group(matchGroupKey)] = \ 69 parse_and_sum(m.group(matchGroupData)) 70 71 if (matchGroupKey == 0 and not macroValue): 72 macroValue["None"] = None 73 74 return list(macroValue.values())[0] if (matchGroupKey == 0) else macroValue 75