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