119ea8026Sopenharmony_ci#!/usr/bin/env python3 219ea8026Sopenharmony_ci# 319ea8026Sopenharmony_ci# Preprocessor that makes asserts easier to debug. 419ea8026Sopenharmony_ci# 519ea8026Sopenharmony_ci# Example: 619ea8026Sopenharmony_ci# ./scripts/prettyasserts.py -p LFS_ASSERT lfs.c -o lfs.a.c 719ea8026Sopenharmony_ci# 819ea8026Sopenharmony_ci# Copyright (c) 2022, The littlefs authors. 919ea8026Sopenharmony_ci# Copyright (c) 2020, Arm Limited. All rights reserved. 1019ea8026Sopenharmony_ci# SPDX-License-Identifier: BSD-3-Clause 1119ea8026Sopenharmony_ci# 1219ea8026Sopenharmony_ci 1319ea8026Sopenharmony_ciimport re 1419ea8026Sopenharmony_ciimport sys 1519ea8026Sopenharmony_ci 1619ea8026Sopenharmony_ci# NOTE the use of macros here helps keep a consistent stack depth which 1719ea8026Sopenharmony_ci# tools may rely on. 1819ea8026Sopenharmony_ci# 1919ea8026Sopenharmony_ci# If compilation errors are noisy consider using -ftrack-macro-expansion=0. 2019ea8026Sopenharmony_ci# 2119ea8026Sopenharmony_ci 2219ea8026Sopenharmony_ciLIMIT = 16 2319ea8026Sopenharmony_ci 2419ea8026Sopenharmony_ciCMP = { 2519ea8026Sopenharmony_ci '==': 'eq', 2619ea8026Sopenharmony_ci '!=': 'ne', 2719ea8026Sopenharmony_ci '<=': 'le', 2819ea8026Sopenharmony_ci '>=': 'ge', 2919ea8026Sopenharmony_ci '<': 'lt', 3019ea8026Sopenharmony_ci '>': 'gt', 3119ea8026Sopenharmony_ci} 3219ea8026Sopenharmony_ci 3319ea8026Sopenharmony_ciLEXEMES = { 3419ea8026Sopenharmony_ci 'ws': [r'(?:\s|\n|#.*?\n|//.*?\n|/\*.*?\*/)+'], 3519ea8026Sopenharmony_ci 'assert': ['assert'], 3619ea8026Sopenharmony_ci 'arrow': ['=>'], 3719ea8026Sopenharmony_ci 'string': [r'"(?:\\.|[^"])*"', r"'(?:\\.|[^'])\'"], 3819ea8026Sopenharmony_ci 'paren': ['\(', '\)'], 3919ea8026Sopenharmony_ci 'cmp': CMP.keys(), 4019ea8026Sopenharmony_ci 'logic': ['\&\&', '\|\|'], 4119ea8026Sopenharmony_ci 'sep': [':', ';', '\{', '\}', ','], 4219ea8026Sopenharmony_ci 'op': ['->'], # specifically ops that conflict with cmp 4319ea8026Sopenharmony_ci} 4419ea8026Sopenharmony_ci 4519ea8026Sopenharmony_ci 4619ea8026Sopenharmony_cidef openio(path, mode='r', buffering=-1): 4719ea8026Sopenharmony_ci # allow '-' for stdin/stdout 4819ea8026Sopenharmony_ci if path == '-': 4919ea8026Sopenharmony_ci if mode == 'r': 5019ea8026Sopenharmony_ci return os.fdopen(os.dup(sys.stdin.fileno()), mode, buffering) 5119ea8026Sopenharmony_ci else: 5219ea8026Sopenharmony_ci return os.fdopen(os.dup(sys.stdout.fileno()), mode, buffering) 5319ea8026Sopenharmony_ci else: 5419ea8026Sopenharmony_ci return open(path, mode, buffering) 5519ea8026Sopenharmony_ci 5619ea8026Sopenharmony_cidef write_header(f, limit=LIMIT): 5719ea8026Sopenharmony_ci f.writeln("// Generated by %s:" % sys.argv[0]) 5819ea8026Sopenharmony_ci f.writeln("//") 5919ea8026Sopenharmony_ci f.writeln("// %s" % ' '.join(sys.argv)) 6019ea8026Sopenharmony_ci f.writeln("//") 6119ea8026Sopenharmony_ci f.writeln() 6219ea8026Sopenharmony_ci 6319ea8026Sopenharmony_ci f.writeln("#include <stdbool.h>") 6419ea8026Sopenharmony_ci f.writeln("#include <stdint.h>") 6519ea8026Sopenharmony_ci f.writeln("#include <inttypes.h>") 6619ea8026Sopenharmony_ci f.writeln("#include <stdio.h>") 6719ea8026Sopenharmony_ci f.writeln("#include <string.h>") 6819ea8026Sopenharmony_ci f.writeln("#include <signal.h>") 6919ea8026Sopenharmony_ci # give source a chance to define feature macros 7019ea8026Sopenharmony_ci f.writeln("#undef _FEATURES_H") 7119ea8026Sopenharmony_ci f.writeln() 7219ea8026Sopenharmony_ci 7319ea8026Sopenharmony_ci # write print macros 7419ea8026Sopenharmony_ci f.writeln("__attribute__((unused))") 7519ea8026Sopenharmony_ci f.writeln("static void __pretty_assert_print_bool(") 7619ea8026Sopenharmony_ci f.writeln(" const void *v, size_t size) {") 7719ea8026Sopenharmony_ci f.writeln(" (void)size;") 7819ea8026Sopenharmony_ci f.writeln(" printf(\"%s\", *(const bool*)v ? \"true\" : \"false\");") 7919ea8026Sopenharmony_ci f.writeln("}") 8019ea8026Sopenharmony_ci f.writeln() 8119ea8026Sopenharmony_ci f.writeln("__attribute__((unused))") 8219ea8026Sopenharmony_ci f.writeln("static void __pretty_assert_print_int(") 8319ea8026Sopenharmony_ci f.writeln(" const void *v, size_t size) {") 8419ea8026Sopenharmony_ci f.writeln(" (void)size;") 8519ea8026Sopenharmony_ci f.writeln(" printf(\"%\"PRIiMAX, *(const intmax_t*)v);") 8619ea8026Sopenharmony_ci f.writeln("}") 8719ea8026Sopenharmony_ci f.writeln() 8819ea8026Sopenharmony_ci f.writeln("__attribute__((unused))") 8919ea8026Sopenharmony_ci f.writeln("static void __pretty_assert_print_mem(") 9019ea8026Sopenharmony_ci f.writeln(" const void *v, size_t size) {") 9119ea8026Sopenharmony_ci f.writeln(" const uint8_t *v_ = v;") 9219ea8026Sopenharmony_ci f.writeln(" printf(\"\\\"\");") 9319ea8026Sopenharmony_ci f.writeln(" for (size_t i = 0; i < size && i < %d; i++) {" % limit) 9419ea8026Sopenharmony_ci f.writeln(" if (v_[i] >= ' ' && v_[i] <= '~') {") 9519ea8026Sopenharmony_ci f.writeln(" printf(\"%c\", v_[i]);") 9619ea8026Sopenharmony_ci f.writeln(" } else {") 9719ea8026Sopenharmony_ci f.writeln(" printf(\"\\\\x%02x\", v_[i]);") 9819ea8026Sopenharmony_ci f.writeln(" }") 9919ea8026Sopenharmony_ci f.writeln(" }") 10019ea8026Sopenharmony_ci f.writeln(" if (size > %d) {" % limit) 10119ea8026Sopenharmony_ci f.writeln(" printf(\"...\");") 10219ea8026Sopenharmony_ci f.writeln(" }") 10319ea8026Sopenharmony_ci f.writeln(" printf(\"\\\"\");") 10419ea8026Sopenharmony_ci f.writeln("}") 10519ea8026Sopenharmony_ci f.writeln() 10619ea8026Sopenharmony_ci f.writeln("__attribute__((unused))") 10719ea8026Sopenharmony_ci f.writeln("static void __pretty_assert_print_str(") 10819ea8026Sopenharmony_ci f.writeln(" const void *v, size_t size) {") 10919ea8026Sopenharmony_ci f.writeln(" __pretty_assert_print_mem(v, size);") 11019ea8026Sopenharmony_ci f.writeln("}") 11119ea8026Sopenharmony_ci f.writeln() 11219ea8026Sopenharmony_ci f.writeln("__attribute__((unused, noinline))") 11319ea8026Sopenharmony_ci f.writeln("static void __pretty_assert_fail(") 11419ea8026Sopenharmony_ci f.writeln(" const char *file, int line,") 11519ea8026Sopenharmony_ci f.writeln(" void (*type_print_cb)(const void*, size_t),") 11619ea8026Sopenharmony_ci f.writeln(" const char *cmp,") 11719ea8026Sopenharmony_ci f.writeln(" const void *lh, size_t lsize,") 11819ea8026Sopenharmony_ci f.writeln(" const void *rh, size_t rsize) {") 11919ea8026Sopenharmony_ci f.writeln(" printf(\"%s:%d:assert: assert failed with \", file, line);") 12019ea8026Sopenharmony_ci f.writeln(" type_print_cb(lh, lsize);") 12119ea8026Sopenharmony_ci f.writeln(" printf(\", expected %s \", cmp);") 12219ea8026Sopenharmony_ci f.writeln(" type_print_cb(rh, rsize);") 12319ea8026Sopenharmony_ci f.writeln(" printf(\"\\n\");") 12419ea8026Sopenharmony_ci f.writeln(" fflush(NULL);") 12519ea8026Sopenharmony_ci f.writeln(" raise(SIGABRT);") 12619ea8026Sopenharmony_ci f.writeln("}") 12719ea8026Sopenharmony_ci f.writeln() 12819ea8026Sopenharmony_ci 12919ea8026Sopenharmony_ci # write assert macros 13019ea8026Sopenharmony_ci for op, cmp in sorted(CMP.items()): 13119ea8026Sopenharmony_ci f.writeln("#define __PRETTY_ASSERT_BOOL_%s(lh, rh) do { \\" 13219ea8026Sopenharmony_ci % cmp.upper()) 13319ea8026Sopenharmony_ci f.writeln(" bool _lh = !!(lh); \\") 13419ea8026Sopenharmony_ci f.writeln(" bool _rh = !!(rh); \\") 13519ea8026Sopenharmony_ci f.writeln(" if (!(_lh %s _rh)) { \\" % op) 13619ea8026Sopenharmony_ci f.writeln(" __pretty_assert_fail( \\") 13719ea8026Sopenharmony_ci f.writeln(" __FILE__, __LINE__, \\") 13819ea8026Sopenharmony_ci f.writeln(" __pretty_assert_print_bool, \"%s\", \\" 13919ea8026Sopenharmony_ci % cmp) 14019ea8026Sopenharmony_ci f.writeln(" &_lh, 0, \\") 14119ea8026Sopenharmony_ci f.writeln(" &_rh, 0); \\") 14219ea8026Sopenharmony_ci f.writeln(" } \\") 14319ea8026Sopenharmony_ci f.writeln("} while (0)") 14419ea8026Sopenharmony_ci for op, cmp in sorted(CMP.items()): 14519ea8026Sopenharmony_ci f.writeln("#define __PRETTY_ASSERT_INT_%s(lh, rh) do { \\" 14619ea8026Sopenharmony_ci % cmp.upper()) 14719ea8026Sopenharmony_ci f.writeln(" __typeof__(lh) _lh = lh; \\") 14819ea8026Sopenharmony_ci f.writeln(" __typeof__(lh) _rh = rh; \\") 14919ea8026Sopenharmony_ci f.writeln(" if (!(_lh %s _rh)) { \\" % op) 15019ea8026Sopenharmony_ci f.writeln(" __pretty_assert_fail( \\") 15119ea8026Sopenharmony_ci f.writeln(" __FILE__, __LINE__, \\") 15219ea8026Sopenharmony_ci f.writeln(" __pretty_assert_print_int, \"%s\", \\" 15319ea8026Sopenharmony_ci % cmp) 15419ea8026Sopenharmony_ci f.writeln(" &(intmax_t){_lh}, 0, \\") 15519ea8026Sopenharmony_ci f.writeln(" &(intmax_t){_rh}, 0); \\") 15619ea8026Sopenharmony_ci f.writeln(" } \\") 15719ea8026Sopenharmony_ci f.writeln("} while (0)") 15819ea8026Sopenharmony_ci for op, cmp in sorted(CMP.items()): 15919ea8026Sopenharmony_ci f.writeln("#define __PRETTY_ASSERT_MEM_%s(lh, rh, size) do { \\" 16019ea8026Sopenharmony_ci % cmp.upper()) 16119ea8026Sopenharmony_ci f.writeln(" const void *_lh = lh; \\") 16219ea8026Sopenharmony_ci f.writeln(" const void *_rh = rh; \\") 16319ea8026Sopenharmony_ci f.writeln(" if (!(memcmp(_lh, _rh, size) %s 0)) { \\" % op) 16419ea8026Sopenharmony_ci f.writeln(" __pretty_assert_fail( \\") 16519ea8026Sopenharmony_ci f.writeln(" __FILE__, __LINE__, \\") 16619ea8026Sopenharmony_ci f.writeln(" __pretty_assert_print_mem, \"%s\", \\" 16719ea8026Sopenharmony_ci % cmp) 16819ea8026Sopenharmony_ci f.writeln(" _lh, size, \\") 16919ea8026Sopenharmony_ci f.writeln(" _rh, size); \\") 17019ea8026Sopenharmony_ci f.writeln(" } \\") 17119ea8026Sopenharmony_ci f.writeln("} while (0)") 17219ea8026Sopenharmony_ci for op, cmp in sorted(CMP.items()): 17319ea8026Sopenharmony_ci f.writeln("#define __PRETTY_ASSERT_STR_%s(lh, rh) do { \\" 17419ea8026Sopenharmony_ci % cmp.upper()) 17519ea8026Sopenharmony_ci f.writeln(" const char *_lh = lh; \\") 17619ea8026Sopenharmony_ci f.writeln(" const char *_rh = rh; \\") 17719ea8026Sopenharmony_ci f.writeln(" if (!(strcmp(_lh, _rh) %s 0)) { \\" % op) 17819ea8026Sopenharmony_ci f.writeln(" __pretty_assert_fail( \\") 17919ea8026Sopenharmony_ci f.writeln(" __FILE__, __LINE__, \\") 18019ea8026Sopenharmony_ci f.writeln(" __pretty_assert_print_str, \"%s\", \\" 18119ea8026Sopenharmony_ci % cmp) 18219ea8026Sopenharmony_ci f.writeln(" _lh, strlen(_lh), \\") 18319ea8026Sopenharmony_ci f.writeln(" _rh, strlen(_rh)); \\") 18419ea8026Sopenharmony_ci f.writeln(" } \\") 18519ea8026Sopenharmony_ci f.writeln("} while (0)") 18619ea8026Sopenharmony_ci f.writeln() 18719ea8026Sopenharmony_ci f.writeln() 18819ea8026Sopenharmony_ci 18919ea8026Sopenharmony_cidef mkassert(type, cmp, lh, rh, size=None): 19019ea8026Sopenharmony_ci if size is not None: 19119ea8026Sopenharmony_ci return ("__PRETTY_ASSERT_%s_%s(%s, %s, %s)" 19219ea8026Sopenharmony_ci % (type.upper(), cmp.upper(), lh, rh, size)) 19319ea8026Sopenharmony_ci else: 19419ea8026Sopenharmony_ci return ("__PRETTY_ASSERT_%s_%s(%s, %s)" 19519ea8026Sopenharmony_ci % (type.upper(), cmp.upper(), lh, rh)) 19619ea8026Sopenharmony_ci 19719ea8026Sopenharmony_ci 19819ea8026Sopenharmony_ci# simple recursive descent parser 19919ea8026Sopenharmony_ciclass ParseFailure(Exception): 20019ea8026Sopenharmony_ci def __init__(self, expected, found): 20119ea8026Sopenharmony_ci self.expected = expected 20219ea8026Sopenharmony_ci self.found = found 20319ea8026Sopenharmony_ci 20419ea8026Sopenharmony_ci def __str__(self): 20519ea8026Sopenharmony_ci return "expected %r, found %s..." % ( 20619ea8026Sopenharmony_ci self.expected, repr(self.found)[:70]) 20719ea8026Sopenharmony_ci 20819ea8026Sopenharmony_ciclass Parser: 20919ea8026Sopenharmony_ci def __init__(self, in_f, lexemes=LEXEMES): 21019ea8026Sopenharmony_ci p = '|'.join('(?P<%s>%s)' % (n, '|'.join(l)) 21119ea8026Sopenharmony_ci for n, l in lexemes.items()) 21219ea8026Sopenharmony_ci p = re.compile(p, re.DOTALL) 21319ea8026Sopenharmony_ci data = in_f.read() 21419ea8026Sopenharmony_ci tokens = [] 21519ea8026Sopenharmony_ci line = 1 21619ea8026Sopenharmony_ci col = 0 21719ea8026Sopenharmony_ci while True: 21819ea8026Sopenharmony_ci m = p.search(data) 21919ea8026Sopenharmony_ci if m: 22019ea8026Sopenharmony_ci if m.start() > 0: 22119ea8026Sopenharmony_ci tokens.append((None, data[:m.start()], line, col)) 22219ea8026Sopenharmony_ci tokens.append((m.lastgroup, m.group(), line, col)) 22319ea8026Sopenharmony_ci data = data[m.end():] 22419ea8026Sopenharmony_ci else: 22519ea8026Sopenharmony_ci tokens.append((None, data, line, col)) 22619ea8026Sopenharmony_ci break 22719ea8026Sopenharmony_ci self.tokens = tokens 22819ea8026Sopenharmony_ci self.off = 0 22919ea8026Sopenharmony_ci 23019ea8026Sopenharmony_ci def lookahead(self, *pattern): 23119ea8026Sopenharmony_ci if self.off < len(self.tokens): 23219ea8026Sopenharmony_ci token = self.tokens[self.off] 23319ea8026Sopenharmony_ci if token[0] in pattern or token[1] in pattern: 23419ea8026Sopenharmony_ci self.m = token[1] 23519ea8026Sopenharmony_ci return self.m 23619ea8026Sopenharmony_ci self.m = None 23719ea8026Sopenharmony_ci return self.m 23819ea8026Sopenharmony_ci 23919ea8026Sopenharmony_ci def accept(self, *patterns): 24019ea8026Sopenharmony_ci m = self.lookahead(*patterns) 24119ea8026Sopenharmony_ci if m is not None: 24219ea8026Sopenharmony_ci self.off += 1 24319ea8026Sopenharmony_ci return m 24419ea8026Sopenharmony_ci 24519ea8026Sopenharmony_ci def expect(self, *patterns): 24619ea8026Sopenharmony_ci m = self.accept(*patterns) 24719ea8026Sopenharmony_ci if not m: 24819ea8026Sopenharmony_ci raise ParseFailure(patterns, self.tokens[self.off:]) 24919ea8026Sopenharmony_ci return m 25019ea8026Sopenharmony_ci 25119ea8026Sopenharmony_ci def push(self): 25219ea8026Sopenharmony_ci return self.off 25319ea8026Sopenharmony_ci 25419ea8026Sopenharmony_ci def pop(self, state): 25519ea8026Sopenharmony_ci self.off = state 25619ea8026Sopenharmony_ci 25719ea8026Sopenharmony_cidef p_assert(p): 25819ea8026Sopenharmony_ci state = p.push() 25919ea8026Sopenharmony_ci 26019ea8026Sopenharmony_ci # assert(memcmp(a,b,size) cmp 0)? 26119ea8026Sopenharmony_ci try: 26219ea8026Sopenharmony_ci p.expect('assert') ; p.accept('ws') 26319ea8026Sopenharmony_ci p.expect('(') ; p.accept('ws') 26419ea8026Sopenharmony_ci p.expect('memcmp') ; p.accept('ws') 26519ea8026Sopenharmony_ci p.expect('(') ; p.accept('ws') 26619ea8026Sopenharmony_ci lh = p_expr(p) ; p.accept('ws') 26719ea8026Sopenharmony_ci p.expect(',') ; p.accept('ws') 26819ea8026Sopenharmony_ci rh = p_expr(p) ; p.accept('ws') 26919ea8026Sopenharmony_ci p.expect(',') ; p.accept('ws') 27019ea8026Sopenharmony_ci size = p_expr(p) ; p.accept('ws') 27119ea8026Sopenharmony_ci p.expect(')') ; p.accept('ws') 27219ea8026Sopenharmony_ci cmp = p.expect('cmp') ; p.accept('ws') 27319ea8026Sopenharmony_ci p.expect('0') ; p.accept('ws') 27419ea8026Sopenharmony_ci p.expect(')') 27519ea8026Sopenharmony_ci return mkassert('mem', CMP[cmp], lh, rh, size) 27619ea8026Sopenharmony_ci except ParseFailure: 27719ea8026Sopenharmony_ci p.pop(state) 27819ea8026Sopenharmony_ci 27919ea8026Sopenharmony_ci # assert(strcmp(a,b) cmp 0)? 28019ea8026Sopenharmony_ci try: 28119ea8026Sopenharmony_ci p.expect('assert') ; p.accept('ws') 28219ea8026Sopenharmony_ci p.expect('(') ; p.accept('ws') 28319ea8026Sopenharmony_ci p.expect('strcmp') ; p.accept('ws') 28419ea8026Sopenharmony_ci p.expect('(') ; p.accept('ws') 28519ea8026Sopenharmony_ci lh = p_expr(p) ; p.accept('ws') 28619ea8026Sopenharmony_ci p.expect(',') ; p.accept('ws') 28719ea8026Sopenharmony_ci rh = p_expr(p) ; p.accept('ws') 28819ea8026Sopenharmony_ci p.expect(')') ; p.accept('ws') 28919ea8026Sopenharmony_ci cmp = p.expect('cmp') ; p.accept('ws') 29019ea8026Sopenharmony_ci p.expect('0') ; p.accept('ws') 29119ea8026Sopenharmony_ci p.expect(')') 29219ea8026Sopenharmony_ci return mkassert('str', CMP[cmp], lh, rh) 29319ea8026Sopenharmony_ci except ParseFailure: 29419ea8026Sopenharmony_ci p.pop(state) 29519ea8026Sopenharmony_ci 29619ea8026Sopenharmony_ci # assert(a cmp b)? 29719ea8026Sopenharmony_ci try: 29819ea8026Sopenharmony_ci p.expect('assert') ; p.accept('ws') 29919ea8026Sopenharmony_ci p.expect('(') ; p.accept('ws') 30019ea8026Sopenharmony_ci lh = p_expr(p) ; p.accept('ws') 30119ea8026Sopenharmony_ci cmp = p.expect('cmp') ; p.accept('ws') 30219ea8026Sopenharmony_ci rh = p_expr(p) ; p.accept('ws') 30319ea8026Sopenharmony_ci p.expect(')') 30419ea8026Sopenharmony_ci return mkassert('int', CMP[cmp], lh, rh) 30519ea8026Sopenharmony_ci except ParseFailure: 30619ea8026Sopenharmony_ci p.pop(state) 30719ea8026Sopenharmony_ci 30819ea8026Sopenharmony_ci # assert(a)? 30919ea8026Sopenharmony_ci p.expect('assert') ; p.accept('ws') 31019ea8026Sopenharmony_ci p.expect('(') ; p.accept('ws') 31119ea8026Sopenharmony_ci lh = p_exprs(p) ; p.accept('ws') 31219ea8026Sopenharmony_ci p.expect(')') 31319ea8026Sopenharmony_ci return mkassert('bool', 'eq', lh, 'true') 31419ea8026Sopenharmony_ci 31519ea8026Sopenharmony_cidef p_expr(p): 31619ea8026Sopenharmony_ci res = [] 31719ea8026Sopenharmony_ci while True: 31819ea8026Sopenharmony_ci if p.accept('('): 31919ea8026Sopenharmony_ci res.append(p.m) 32019ea8026Sopenharmony_ci while True: 32119ea8026Sopenharmony_ci res.append(p_exprs(p)) 32219ea8026Sopenharmony_ci if p.accept('sep'): 32319ea8026Sopenharmony_ci res.append(p.m) 32419ea8026Sopenharmony_ci else: 32519ea8026Sopenharmony_ci break 32619ea8026Sopenharmony_ci res.append(p.expect(')')) 32719ea8026Sopenharmony_ci elif p.lookahead('assert'): 32819ea8026Sopenharmony_ci state = p.push() 32919ea8026Sopenharmony_ci try: 33019ea8026Sopenharmony_ci res.append(p_assert(p)) 33119ea8026Sopenharmony_ci except ParseFailure: 33219ea8026Sopenharmony_ci p.pop(state) 33319ea8026Sopenharmony_ci res.append(p.expect('assert')) 33419ea8026Sopenharmony_ci elif p.accept('string', 'op', 'ws', None): 33519ea8026Sopenharmony_ci res.append(p.m) 33619ea8026Sopenharmony_ci else: 33719ea8026Sopenharmony_ci return ''.join(res) 33819ea8026Sopenharmony_ci 33919ea8026Sopenharmony_cidef p_exprs(p): 34019ea8026Sopenharmony_ci res = [] 34119ea8026Sopenharmony_ci while True: 34219ea8026Sopenharmony_ci res.append(p_expr(p)) 34319ea8026Sopenharmony_ci if p.accept('cmp', 'logic', ','): 34419ea8026Sopenharmony_ci res.append(p.m) 34519ea8026Sopenharmony_ci else: 34619ea8026Sopenharmony_ci return ''.join(res) 34719ea8026Sopenharmony_ci 34819ea8026Sopenharmony_cidef p_stmt(p): 34919ea8026Sopenharmony_ci ws = p.accept('ws') or '' 35019ea8026Sopenharmony_ci 35119ea8026Sopenharmony_ci # memcmp(lh,rh,size) => 0? 35219ea8026Sopenharmony_ci if p.lookahead('memcmp'): 35319ea8026Sopenharmony_ci state = p.push() 35419ea8026Sopenharmony_ci try: 35519ea8026Sopenharmony_ci p.expect('memcmp') ; p.accept('ws') 35619ea8026Sopenharmony_ci p.expect('(') ; p.accept('ws') 35719ea8026Sopenharmony_ci lh = p_expr(p) ; p.accept('ws') 35819ea8026Sopenharmony_ci p.expect(',') ; p.accept('ws') 35919ea8026Sopenharmony_ci rh = p_expr(p) ; p.accept('ws') 36019ea8026Sopenharmony_ci p.expect(',') ; p.accept('ws') 36119ea8026Sopenharmony_ci size = p_expr(p) ; p.accept('ws') 36219ea8026Sopenharmony_ci p.expect(')') ; p.accept('ws') 36319ea8026Sopenharmony_ci p.expect('=>') ; p.accept('ws') 36419ea8026Sopenharmony_ci p.expect('0') ; p.accept('ws') 36519ea8026Sopenharmony_ci return ws + mkassert('mem', 'eq', lh, rh, size) 36619ea8026Sopenharmony_ci except ParseFailure: 36719ea8026Sopenharmony_ci p.pop(state) 36819ea8026Sopenharmony_ci 36919ea8026Sopenharmony_ci # strcmp(lh,rh) => 0? 37019ea8026Sopenharmony_ci if p.lookahead('strcmp'): 37119ea8026Sopenharmony_ci state = p.push() 37219ea8026Sopenharmony_ci try: 37319ea8026Sopenharmony_ci p.expect('strcmp') ; p.accept('ws') ; p.expect('(') ; p.accept('ws') 37419ea8026Sopenharmony_ci lh = p_expr(p) ; p.accept('ws') 37519ea8026Sopenharmony_ci p.expect(',') ; p.accept('ws') 37619ea8026Sopenharmony_ci rh = p_expr(p) ; p.accept('ws') 37719ea8026Sopenharmony_ci p.expect(')') ; p.accept('ws') 37819ea8026Sopenharmony_ci p.expect('=>') ; p.accept('ws') 37919ea8026Sopenharmony_ci p.expect('0') ; p.accept('ws') 38019ea8026Sopenharmony_ci return ws + mkassert('str', 'eq', lh, rh) 38119ea8026Sopenharmony_ci except ParseFailure: 38219ea8026Sopenharmony_ci p.pop(state) 38319ea8026Sopenharmony_ci 38419ea8026Sopenharmony_ci # lh => rh? 38519ea8026Sopenharmony_ci lh = p_exprs(p) 38619ea8026Sopenharmony_ci if p.accept('=>'): 38719ea8026Sopenharmony_ci rh = p_exprs(p) 38819ea8026Sopenharmony_ci return ws + mkassert('int', 'eq', lh, rh) 38919ea8026Sopenharmony_ci else: 39019ea8026Sopenharmony_ci return ws + lh 39119ea8026Sopenharmony_ci 39219ea8026Sopenharmony_cidef main(input=None, output=None, pattern=[], limit=LIMIT): 39319ea8026Sopenharmony_ci with openio(input or '-', 'r') as in_f: 39419ea8026Sopenharmony_ci # create parser 39519ea8026Sopenharmony_ci lexemes = LEXEMES.copy() 39619ea8026Sopenharmony_ci lexemes['assert'] += pattern 39719ea8026Sopenharmony_ci p = Parser(in_f, lexemes) 39819ea8026Sopenharmony_ci 39919ea8026Sopenharmony_ci with openio(output or '-', 'w') as f: 40019ea8026Sopenharmony_ci def writeln(s=''): 40119ea8026Sopenharmony_ci f.write(s) 40219ea8026Sopenharmony_ci f.write('\n') 40319ea8026Sopenharmony_ci f.writeln = writeln 40419ea8026Sopenharmony_ci 40519ea8026Sopenharmony_ci # write extra verbose asserts 40619ea8026Sopenharmony_ci write_header(f, limit=limit) 40719ea8026Sopenharmony_ci if input is not None: 40819ea8026Sopenharmony_ci f.writeln("#line %d \"%s\"" % (1, input)) 40919ea8026Sopenharmony_ci 41019ea8026Sopenharmony_ci # parse and write out stmt at a time 41119ea8026Sopenharmony_ci try: 41219ea8026Sopenharmony_ci while True: 41319ea8026Sopenharmony_ci f.write(p_stmt(p)) 41419ea8026Sopenharmony_ci if p.accept('sep'): 41519ea8026Sopenharmony_ci f.write(p.m) 41619ea8026Sopenharmony_ci else: 41719ea8026Sopenharmony_ci break 41819ea8026Sopenharmony_ci except ParseFailure as e: 41919ea8026Sopenharmony_ci print('warning: %s' % e) 42019ea8026Sopenharmony_ci pass 42119ea8026Sopenharmony_ci 42219ea8026Sopenharmony_ci for i in range(p.off, len(p.tokens)): 42319ea8026Sopenharmony_ci f.write(p.tokens[i][1]) 42419ea8026Sopenharmony_ci 42519ea8026Sopenharmony_ci 42619ea8026Sopenharmony_ciif __name__ == "__main__": 42719ea8026Sopenharmony_ci import argparse 42819ea8026Sopenharmony_ci import sys 42919ea8026Sopenharmony_ci parser = argparse.ArgumentParser( 43019ea8026Sopenharmony_ci description="Preprocessor that makes asserts easier to debug.", 43119ea8026Sopenharmony_ci allow_abbrev=False) 43219ea8026Sopenharmony_ci parser.add_argument( 43319ea8026Sopenharmony_ci 'input', 43419ea8026Sopenharmony_ci help="Input C file.") 43519ea8026Sopenharmony_ci parser.add_argument( 43619ea8026Sopenharmony_ci '-o', '--output', 43719ea8026Sopenharmony_ci required=True, 43819ea8026Sopenharmony_ci help="Output C file.") 43919ea8026Sopenharmony_ci parser.add_argument( 44019ea8026Sopenharmony_ci '-p', '--pattern', 44119ea8026Sopenharmony_ci action='append', 44219ea8026Sopenharmony_ci help="Regex patterns to search for starting an assert statement. This" 44319ea8026Sopenharmony_ci " implicitly includes \"assert\" and \"=>\".") 44419ea8026Sopenharmony_ci parser.add_argument( 44519ea8026Sopenharmony_ci '-l', '--limit', 44619ea8026Sopenharmony_ci type=lambda x: int(x, 0), 44719ea8026Sopenharmony_ci default=LIMIT, 44819ea8026Sopenharmony_ci help="Maximum number of characters to display in strcmp and memcmp. " 44919ea8026Sopenharmony_ci "Defaults to %r." % LIMIT) 45019ea8026Sopenharmony_ci sys.exit(main(**{k: v 45119ea8026Sopenharmony_ci for k, v in vars(parser.parse_intermixed_args()).items() 45219ea8026Sopenharmony_ci if v is not None})) 453